#26 - Loading animation + success message fix
This commit was merged in pull request #31.
This commit is contained in:
@@ -74,6 +74,13 @@ class RsvFormReservationElementHandler implements RsvFormElementHandler {
|
||||
$price_per_block = (float) $def->getAttr('price_per_block', 0);
|
||||
$result->setValue($name . '_price', $price_per_block * count($payload['timetable_reservations']));
|
||||
|
||||
$slots = array_map(fn($t) => [
|
||||
'start_utc' => (new DateTime($t))->format(DateTime::ATOM),
|
||||
'end_utc' => $this->end_from_start(new DateTime($t), $timetable->block_size)->format(DateTime::ATOM),
|
||||
'price' => $price_per_block,
|
||||
], $payload['timetable_reservations']);
|
||||
$result->setValue('slots', array_merge($result->getValue('slots') ?? [], $slots));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+15
-2
@@ -16,13 +16,26 @@ final class RsvFormCalculatedValues {
|
||||
$price_before_discount += (float) $element_calculator($element, $data->getValue($element->getName()));
|
||||
}
|
||||
|
||||
$discount_pct = (new RsvMembershipService())->discount_for($definition, $data);
|
||||
$discount_detail = (new RsvMembershipService())->discount_detail_for($definition, $data);
|
||||
$discount_pct = $discount_detail['percent'];
|
||||
$final_price = $calculator->calculate($definition, $data);
|
||||
$subtotal = $price_before_discount;
|
||||
$discount_amount = $subtotal - $final_price;
|
||||
|
||||
return [
|
||||
'price' => $final_price,
|
||||
'price_before_discount' => $price_before_discount,
|
||||
'discount_percent' => $discount_pct,
|
||||
'pricing' => [
|
||||
'currency' => 'CZK',
|
||||
'subtotal' => $subtotal,
|
||||
'discount' => $discount_pct > 0.0 ? [
|
||||
'percent' => $discount_pct,
|
||||
'amount' => round($discount_amount, 2),
|
||||
'reason' => $discount_detail['reason'],
|
||||
] : null,
|
||||
'total' => $final_price,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -31,6 +44,6 @@ final class RsvFormCalculatedValues {
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function names(): array {
|
||||
return ['price', 'price_before_discount', 'discount_percent'];
|
||||
return ['price', 'price_before_discount', 'discount_percent', 'pricing'];
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Reservair\Templating\RsvTemplateEngine;
|
||||
|
||||
class RsvFormHtmlRenderer {
|
||||
public function draw(RsvFormDefinition $form): bool {
|
||||
if (!$form->hasElements()) {
|
||||
@@ -21,37 +19,12 @@ class RsvFormHtmlRenderer {
|
||||
<?php endforeach; ?>
|
||||
|
||||
</form>
|
||||
<?php $this->draw_success_template($form); ?>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the admin-configured success message as an inert <template> that the
|
||||
* client clones once the form is submitted. A <reservation-summary> element
|
||||
* expands to a placeholder div that RsvFormSender fills with the visitor's
|
||||
* selected slots.
|
||||
*/
|
||||
private function draw_success_template(RsvFormDefinition $form): void {
|
||||
$message = trim($form->getSuccessMessage());
|
||||
if ($message === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
global $rsv_template_registry;
|
||||
$engine = new RsvTemplateEngine(registry: $rsv_template_registry);
|
||||
|
||||
// Sanitize admin HTML before rendering, allowing the registered template
|
||||
// custom elements through so the engine can expand them.
|
||||
$allowed = $rsv_template_registry->kses_allowed(wp_kses_allowed_html('post'));
|
||||
$html = $engine->render(wp_kses($message, $allowed));
|
||||
?>
|
||||
<template class="rsv-form-success"><?= $html ?></template>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function draw_element(RsvFormElementDefinition $data): void {
|
||||
global $rsv_form_registry;
|
||||
|
||||
|
||||
@@ -35,7 +35,24 @@ class RsvFormSubmission {
|
||||
return ['success' => false, 'errors' => $result->getErrors()];
|
||||
}
|
||||
|
||||
return ['success' => true, 'submit_id' => $submit_id, 'values' => $result->getValues()];
|
||||
global $rsv_template_registry;
|
||||
$message = trim($definition->getSuccessMessage());
|
||||
if ($message !== '') {
|
||||
$allowed = $rsv_template_registry->kses_allowed(wp_kses_allowed_html('post'));
|
||||
$template = wp_kses($message, $allowed);
|
||||
} else {
|
||||
$template = '';
|
||||
}
|
||||
|
||||
$data = array_merge($result->getValues(), (new RsvFormCalculatedValues())->for($definition, $form_data));
|
||||
|
||||
try {
|
||||
$submit_repo->set_computed($submit_id, $data);
|
||||
} catch (\Throwable $e) {
|
||||
Logger::error($e);
|
||||
}
|
||||
|
||||
return ['success' => true, 'submit_id' => $submit_id, 'template' => $template, 'data' => $data];
|
||||
}
|
||||
|
||||
/** Remove a submission whose run failed. */
|
||||
|
||||
@@ -2,18 +2,9 @@
|
||||
|
||||
class RsvMembershipService {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Total membership discount for a submission.
|
||||
*
|
||||
* Each binding names a form field whose submitted value must match a key
|
||||
* in the bound program. Matching bindings' discounts are combined per the
|
||||
* definition's combine mode: the best single discount, or all summed and
|
||||
* capped at 100%.
|
||||
*/
|
||||
public function discount_for(RsvFormDefinition $def, RsvFormData $data): float {
|
||||
public function discount_detail_for(RsvFormDefinition $def, RsvFormData $data): array {
|
||||
$repo = new RsvMembershipProgramRepository();
|
||||
$matched_programs = [];
|
||||
$matched_discounts = [];
|
||||
|
||||
foreach ($def->getMembershipBindings() as $binding) {
|
||||
@@ -33,18 +24,37 @@ class RsvMembershipService {
|
||||
}
|
||||
|
||||
if ($repo->key_exists($program_id, $value)) {
|
||||
$program = $repo->get($program_id);
|
||||
if ($program) {
|
||||
$matched_programs[] = $program['name'];
|
||||
}
|
||||
$matched_discounts[] = $discount;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($matched_discounts)) {
|
||||
return 0.0;
|
||||
return ['percent' => 0.0, 'reason' => ''];
|
||||
}
|
||||
|
||||
if ($def->getMembershipCombine() === 'sum') {
|
||||
return min(100.0, array_sum($matched_discounts));
|
||||
$reason = implode(', ', $matched_programs);
|
||||
return ['percent' => min(100.0, array_sum($matched_discounts)), 'reason' => $reason];
|
||||
}
|
||||
|
||||
return max($matched_discounts);
|
||||
$max_idx = array_search(max($matched_discounts), $matched_discounts, true);
|
||||
$reason = $matched_programs[$max_idx] ?? '';
|
||||
return ['percent' => max($matched_discounts), 'reason' => $reason];
|
||||
}
|
||||
|
||||
/**
|
||||
* Total membership discount for a submission.
|
||||
*
|
||||
* Each binding names a form field whose submitted value must match a key
|
||||
* in the bound program. Matching bindings' discounts are combined per the
|
||||
* definition's combine mode: the best single discount, or all summed and
|
||||
* capped at 100%.
|
||||
*/
|
||||
public function discount_for(RsvFormDefinition $def, RsvFormData $data): float {
|
||||
return $this->discount_detail_for($def, $data)['percent'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ class RsvReservationService {
|
||||
// (maintainer emails, calendar sync) observe the new reservation.
|
||||
foreach($reservation->timetable_reservations as $timetable_reservation) {
|
||||
if($timetable_reservation->is_confirmed === null) {
|
||||
error_log('timetable_reservation->is_confirmed is null: ' . $timetable_reservation->id);
|
||||
$maintainer_email = (new RsvTimetableRepository())->get_maintainer_email($timetable_reservation->timetable_id);
|
||||
RsvEventDispatcher::dispatch(new RsvTimetableReservationPendingEvent(
|
||||
$reservation_id,
|
||||
|
||||
@@ -115,18 +115,18 @@ class RsvTimetableReservationService {
|
||||
return $this->repo->has_pending_confirmation($reservation_id);
|
||||
}
|
||||
|
||||
public function get_confirmation_code(int $reservation_id): ?string {
|
||||
$code = $this->repo->get_confirmation_code($reservation_id);
|
||||
public function get_confirmation_code(int $timetable_reservation_id): ?string {
|
||||
$code = $this->repo->get_confirmation_code($timetable_reservation_id);
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
public function accept_by_reservation_id(int $reservation_id): void {
|
||||
$this->set_confirmed_state($this->get_confirmation_code($reservation_id), true);
|
||||
public function accept_by_id(int $timetable_reservation_id): void {
|
||||
$this->set_confirmed_state($this->get_confirmation_code($timetable_reservation_id), true);
|
||||
}
|
||||
|
||||
public function refuse_by_reservation_id(int $reservation_id): void {
|
||||
$this->set_confirmed_state($this->get_confirmation_code($reservation_id), false);
|
||||
public function refuse_by_id(int $timetable_reservation_id): void {
|
||||
$this->set_confirmed_state($this->get_confirmation_code($timetable_reservation_id), false);
|
||||
}
|
||||
|
||||
// TODO: Add requires_confirmation parameter
|
||||
|
||||
Reference in New Issue
Block a user