feat: update alert timestamps to use Minsk timezone for accurate display and input handling
This commit is contained in:
@@ -380,16 +380,16 @@ function AlertCard({ alert, index, onEdit, onDelete }) {
|
|||||||
<div className="text-xs text-gray-500">
|
<div className="text-xs text-gray-500">
|
||||||
{alert.start_time && (
|
{alert.start_time && (
|
||||||
<div>
|
<div>
|
||||||
Начало: {new Date(alert.start_time).toLocaleString('ru-RU')}
|
Начало: {new Date(alert.start_time).toLocaleString('ru-RU', { timeZone: MINSK_TIME_ZONE })}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{alert.end_time && (
|
{alert.end_time && (
|
||||||
<div>
|
<div>
|
||||||
Конец: {new Date(alert.end_time).toLocaleString('ru-RU')}
|
Конец: {new Date(alert.end_time).toLocaleString('ru-RU', { timeZone: MINSK_TIME_ZONE })}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{status === 'scheduled' && <div className="mt-1 text-blue-700">Push будет отправлен в момент начала</div>}
|
{status === 'scheduled' && <div className="mt-1 text-blue-700">Push будет отправлен в момент начала</div>}
|
||||||
{alert.notification_sent_at && <div className="mt-1 text-green-700">Push отправлен: {new Date(alert.notification_sent_at).toLocaleString('ru-RU')}</div>}
|
{alert.notification_sent_at && <div className="mt-1 text-green-700">Push отправлен: {new Date(alert.notification_sent_at).toLocaleString('ru-RU', { timeZone: MINSK_TIME_ZONE })}</div>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
@@ -416,11 +416,30 @@ function createAlertIdempotencyKey() {
|
|||||||
return `alert-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
return `alert-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MINSK_TIME_ZONE = 'Europe/Minsk';
|
||||||
|
const MINSK_OFFSET = '+03:00';
|
||||||
|
|
||||||
function toDateTimeInput(value = new Date()) {
|
function toDateTimeInput(value = new Date()) {
|
||||||
const date = new Date(value);
|
const date = new Date(value);
|
||||||
if (Number.isNaN(date.getTime())) return '';
|
if (Number.isNaN(date.getTime())) return '';
|
||||||
const local = new Date(date.getTime() - date.getTimezoneOffset() * 60_000);
|
const parts = new Intl.DateTimeFormat('en-CA', {
|
||||||
return local.toISOString().slice(0, 16);
|
timeZone: MINSK_TIME_ZONE,
|
||||||
|
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||||
|
hour: '2-digit', minute: '2-digit', hourCycle: 'h23'
|
||||||
|
}).formatToParts(date).reduce((result, part) => ({ ...result, [part.type]: part.value }), {});
|
||||||
|
return `${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostgreSQL currently stores alert timestamps without a timezone. Keep UTC
|
||||||
|
// values there, while the operator always sees and enters Polotsk time.
|
||||||
|
function toApiDateTime(value) {
|
||||||
|
if (!value) return null;
|
||||||
|
const date = new Date(`${value}:00${MINSK_OFFSET}`);
|
||||||
|
return Number.isNaN(date.getTime()) ? value : date.toISOString().slice(0, 19);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMinskDate(value) {
|
||||||
|
return new Date(`${value}:00${MINSK_OFFSET}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AlertForm({ alert, routes, templates, onSubmit, onCancel }) {
|
function AlertForm({ alert, routes, templates, onSubmit, onCancel }) {
|
||||||
@@ -443,7 +462,8 @@ function AlertForm({ alert, routes, templates, onSubmit, onCancel }) {
|
|||||||
const data = {
|
const data = {
|
||||||
...formData,
|
...formData,
|
||||||
route_id: formData.route_id || null,
|
route_id: formData.route_id || null,
|
||||||
end_time: formData.end_time || null
|
start_time: toApiDateTime(formData.start_time),
|
||||||
|
end_time: toApiDateTime(formData.end_time)
|
||||||
};
|
};
|
||||||
|
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
@@ -472,7 +492,7 @@ function AlertForm({ alert, routes, templates, onSubmit, onCancel }) {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const startDate = new Date(formData.start_time);
|
const startDate = toMinskDate(formData.start_time);
|
||||||
const isScheduled = formData.is_active && !Number.isNaN(startDate.getTime()) && startDate > new Date();
|
const isScheduled = formData.is_active && !Number.isNaN(startDate.getTime()) && startDate > new Date();
|
||||||
const saveLabel = alert ? 'Сохранить' : !formData.is_active ? 'Сохранить черновик' : isScheduled ? 'Запланировать' : 'Опубликовать';
|
const saveLabel = alert ? 'Сохранить' : !formData.is_active ? 'Сохранить черновик' : isScheduled ? 'Запланировать' : 'Опубликовать';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user