feat: complete production backend integration

This commit is contained in:
Marek Miklewicz
2026-06-02 20:51:57 +02:00
parent d3f2fd69db
commit 4b531a4c24
20 changed files with 853 additions and 40 deletions
+56 -15
View File
@@ -41,10 +41,22 @@ function normalize_rule_post(array $post): array
return $post;
}
/** @param array<string,mixed> $rule @return array<string,mixed> */
function attach_rule_scope(AppContext $ctx, array $rule): array
{
if (empty($rule['dynamic_scope'])) {
$rule['mailbox_snapshot'] = (new MailboxDirectory())->mailboxesForUser($ctx->daUser->username());
}
return $rule;
}
function render_calendar_picker(AppContext $ctx, string $name, string $title, string $value): string
{
$mode = $ctx->settings->scheduleMode();
$selectedDate = substr($value, 0, 10);
if (!preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $selectedDate)) {
$selectedDate = date('Y-m-d');
}
$selectedTime = '09:00';
$selectedPeriod = 'morning';
if ($mode === 'exact_hour' && preg_match('/T([0-9]{2}:[0-9]{2})$/', $value, $m)) {
@@ -52,33 +64,62 @@ function render_calendar_picker(AppContext $ctx, string $name, string $title, st
} elseif ($mode === 'directadmin_period' && preg_match('/\|(morning|afternoon|evening)$/', $value, $m)) {
$selectedPeriod = $m[1];
}
$days = '';
for ($week = 0, $day = 1; $week < 4; $week++) {
$days .= '<tr>';
for ($i = 0; $i < 7; $i++, $day++) {
$date = sprintf('2026-06-%02d', $day);
$class = $date === $selectedDate ? ' is-selected' : '';
$days .= '<td><button type="button" class="br-cal-day' . $class . '" data-date-target="' . AppContext::e($name . '_date') . '" data-date-label="' . AppContext::e($name . '_label') . '" data-date-value="' . AppContext::e($date) . '">' . $day . '</button></td>';
}
$days .= '</tr>';
}
$selectedDt = DateTimeImmutable::createFromFormat('!Y-m-d', $selectedDate) ?: new DateTimeImmutable('today');
$monthStart = $selectedDt->modify('first day of this month');
$days = render_calendar_days($name, $selectedDate, $monthStart);
$visibleMonth = $monthStart->format('Y-m');
$monthLabel = calendar_month_label($ctx, $monthStart);
if ($mode === 'exact_hour') {
$timeControl = '<label>' . AppContext::e($ctx->t('Time')) . '</label><input type="time" name="' . AppContext::e($name . '_time') . '" value="' . AppContext::e($selectedTime) . '" step="60">';
$timeControl = '<label>' . AppContext::e($ctx->t('Time')) . '</label><input type="time" name="' . AppContext::e($name . '_time') . '" value="' . AppContext::e($selectedTime) . '" step="60" data-time-for="' . AppContext::e($name) . '">';
} else {
$timeControl = '<label>' . AppContext::e($ctx->t('Time of day')) . '</label><select name="' . AppContext::e($name . '_period') . '">' .
$timeControl = '<label>' . AppContext::e($ctx->t('Time of day')) . '</label><select name="' . AppContext::e($name . '_period') . '" data-period-for="' . AppContext::e($name) . '">' .
'<option value="morning"' . ($selectedPeriod === 'morning' ? ' selected' : '') . '>' . AppContext::e($ctx->t('Morning')) . '</option>' .
'<option value="afternoon"' . ($selectedPeriod === 'afternoon' ? ' selected' : '') . '>' . AppContext::e($ctx->t('Afternoon')) . '</option>' .
'<option value="evening"' . ($selectedPeriod === 'evening' ? ' selected' : '') . '>' . AppContext::e($ctx->t('Evening')) . '</option>' .
'</select>';
}
return '<div class="panel"><h3>' . AppContext::e($title) . '</h3><div class="br-restore-layout"><div class="br-restore-calendar"><h4>' . AppContext::e($title) . '</h4><div class="br-month-nav"><button type="button" class="br-month-btn">&lsaquo;</button><span class="br-month-label">Czerwiec 2026</span><button type="button" class="br-month-btn">&rsaquo;</button></div>' .
'<table class="br-calendar-grid"><thead><tr><th>Pn</th><th>Wt</th><th>Śr</th><th>Cz</th><th>Pt</th><th>Sb</th><th>Nd</th></tr></thead><tbody>' . $days . '</tbody></table>' .
return '<div class="panel"><h3>' . AppContext::e($title) . '</h3><div class="br-restore-layout"><div class="br-restore-calendar" data-calendar-picker data-schedule-mode="' . AppContext::e($mode) . '" data-calendar-name="' . AppContext::e($name) . '" data-visible-month="' . AppContext::e($visibleMonth) . '" data-selected-date="' . AppContext::e($selectedDate) . '"><h4>' . AppContext::e($title) . '</h4><div class="br-month-nav"><button type="button" class="br-month-btn" data-calendar-prev>&lsaquo;</button><span class="br-month-label" data-calendar-month-label>' . AppContext::e($monthLabel) . '</span><button type="button" class="br-month-btn" data-calendar-next>&rsaquo;</button></div>' .
'<table class="br-calendar-grid"><thead><tr><th>Pn</th><th>Wt</th><th>Śr</th><th>Cz</th><th>Pt</th><th>Sb</th><th>Nd</th></tr></thead><tbody data-calendar-days>' . $days . '</tbody></table>' .
'<div class="br-date-label" id="' . AppContext::e($name . '_label') . '">Wybrano: ' . AppContext::e($selectedDate) . '</div><input type="hidden" id="' . AppContext::e($name . '_date') . '" name="' . AppContext::e($name . '_date') . '" value="' . AppContext::e($selectedDate) . '"></div>' .
'<div class="br-restore-calendar"><h4>' . AppContext::e($ctx->t('Time')) . '</h4>' . $timeControl . '</div></div>' .
'<input type="hidden" name="' . AppContext::e($name) . '" value="' . AppContext::e($value) . '"></div>';
'<input type="hidden" id="' . AppContext::e($name) . '" name="' . AppContext::e($name) . '" value="' . AppContext::e($value) . '" data-canonical-value="' . AppContext::e($name) . '"></div>';
}
function render_preview_box(array $rule): string
{
return '<div class="preview-box"><div><strong>Temat:</strong> ' . AppContext::e((string)$rule['subject']) . '</div><br><div>' . nl2br(AppContext::e((string)$rule['body'])) . '</div></div>';
}
function render_calendar_days(string $name, string $selectedDate, DateTimeImmutable $monthStart): string
{
$offset = ((int)$monthStart->format('N')) - 1;
$daysInMonth = (int)$monthStart->format('t');
$html = '';
$day = 1;
for ($week = 0; $week < 6; $week++) {
$html .= '<tr>';
for ($i = 0; $i < 7; $i++) {
if (($week === 0 && $i < $offset) || $day > $daysInMonth) {
$html .= '<td class="br-cal-empty"></td>';
continue;
}
$date = $monthStart->setDate((int)$monthStart->format('Y'), (int)$monthStart->format('m'), $day)->format('Y-m-d');
$class = $date === $selectedDate ? ' is-selected' : '';
$html .= '<td><button type="button" class="br-cal-day' . $class . '" data-date-target="' . AppContext::e($name . '_date') . '" data-date-label="' . AppContext::e($name . '_label') . '" data-date-value="' . AppContext::e($date) . '">' . $day . '</button></td>';
$day++;
}
$html .= '</tr>';
if ($day > $daysInMonth) {
break;
}
}
return $html;
}
function calendar_month_label(AppContext $ctx, DateTimeImmutable $monthStart): string
{
$pl = ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'];
$en = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
$months = $ctx->lang->code() === 'pl' ? $pl : $en;
return $months[((int)$monthStart->format('n')) - 1] . ' ' . $monthStart->format('Y');
}