Add mock order status timeline
This commit is contained in:
213
app/composables/useOrderStatusPresentation.ts
Normal file
213
app/composables/useOrderStatusPresentation.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
type OrderStatusCode =
|
||||
| 'NEW'
|
||||
| 'MANAGER_PROCESSING'
|
||||
| 'WAITING_DOUBLE_CONFIRM'
|
||||
| 'CLIENT_REJECTED'
|
||||
| 'MANAGER_REJECTED'
|
||||
| 'MANAGER_BLOCKED'
|
||||
| 'CONFIRMED'
|
||||
| 'IN_PROGRESS'
|
||||
| 'COMPLETED';
|
||||
|
||||
type TimelineStage = {
|
||||
code: string;
|
||||
label: string;
|
||||
note: string;
|
||||
dateLabel: string;
|
||||
state: 'done' | 'current' | 'upcoming';
|
||||
};
|
||||
|
||||
type StatusPresentation = {
|
||||
title: string;
|
||||
summary: string;
|
||||
stages: TimelineStage[];
|
||||
};
|
||||
|
||||
const STAGE_ORDER: OrderStatusCode[] = [
|
||||
'NEW',
|
||||
'MANAGER_PROCESSING',
|
||||
'WAITING_DOUBLE_CONFIRM',
|
||||
'CONFIRMED',
|
||||
'IN_PROGRESS',
|
||||
'COMPLETED',
|
||||
];
|
||||
|
||||
const DAY_FORMATTER = new Intl.DateTimeFormat('ru-RU', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
});
|
||||
|
||||
function addDays(date: Date, days: number) {
|
||||
const next = new Date(date);
|
||||
next.setDate(next.getDate() + days);
|
||||
return next;
|
||||
}
|
||||
|
||||
function formatDay(date: Date) {
|
||||
return DAY_FORMATTER.format(date);
|
||||
}
|
||||
|
||||
function stageIndex(status: string) {
|
||||
const index = STAGE_ORDER.indexOf(status as OrderStatusCode);
|
||||
return index >= 0 ? index : 0;
|
||||
}
|
||||
|
||||
function buildDates(createdAt: string | Date) {
|
||||
const base = new Date(createdAt);
|
||||
|
||||
return {
|
||||
created: base,
|
||||
offer: addDays(base, 1),
|
||||
approval: addDays(base, 2),
|
||||
production: addDays(base, 4),
|
||||
shipment: addDays(base, 6),
|
||||
delivered: addDays(base, 8),
|
||||
};
|
||||
}
|
||||
|
||||
export function getOrderStatusPresentation(status: string, createdAt: string | Date): StatusPresentation {
|
||||
const dates = buildDates(createdAt);
|
||||
|
||||
if (status === 'CLIENT_REJECTED') {
|
||||
return {
|
||||
title: 'Заказ остановлен клиентом',
|
||||
summary: 'Согласование остановлено. Если нужно, заказ можно собрать заново с новыми условиями.',
|
||||
stages: [
|
||||
{
|
||||
code: 'NEW',
|
||||
label: 'Заявка принята',
|
||||
note: 'Заказ попал в обработку.',
|
||||
dateLabel: formatDay(dates.created),
|
||||
state: 'done',
|
||||
},
|
||||
{
|
||||
code: 'CLIENT_REJECTED',
|
||||
label: 'Клиент отказался от продолжения',
|
||||
note: 'Текущий заказ закрыт без запуска в работу.',
|
||||
dateLabel: formatDay(dates.approval),
|
||||
state: 'current',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
if (status === 'MANAGER_REJECTED' || status === 'MANAGER_BLOCKED') {
|
||||
return {
|
||||
title: status === 'MANAGER_BLOCKED' ? 'Заказ ждёт уточнения' : 'Заказ остановлен менеджером',
|
||||
summary: status === 'MANAGER_BLOCKED'
|
||||
? 'Сейчас ждём уточнение параметров, после него заказ вернётся в работу.'
|
||||
: 'Менеджер остановил обработку. При необходимости можно собрать новый заказ.',
|
||||
stages: [
|
||||
{
|
||||
code: 'NEW',
|
||||
label: 'Заявка принята',
|
||||
note: 'Заказ попал в обработку.',
|
||||
dateLabel: formatDay(dates.created),
|
||||
state: 'done',
|
||||
},
|
||||
{
|
||||
code: status,
|
||||
label: status === 'MANAGER_BLOCKED' ? 'Нужно уточнение по заказу' : 'Обработка остановлена',
|
||||
note: status === 'MANAGER_BLOCKED'
|
||||
? 'Менеджер запросил уточнение перед продолжением.'
|
||||
: 'Текущий заказ завершён без запуска в производство.',
|
||||
dateLabel: formatDay(dates.approval),
|
||||
state: 'current',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const currentIndex = stageIndex(status);
|
||||
|
||||
const stages: TimelineStage[] = [
|
||||
{
|
||||
code: 'NEW',
|
||||
label: 'Заявка принята',
|
||||
note: 'Получили состав заказа и начали обработку.',
|
||||
dateLabel: formatDay(dates.created),
|
||||
state: currentIndex > 0 ? 'done' : 'current',
|
||||
},
|
||||
{
|
||||
code: 'MANAGER_PROCESSING',
|
||||
label: 'Готовим предложение',
|
||||
note: 'Уточняем цену, сроки и условия доставки.',
|
||||
dateLabel: formatDay(dates.offer),
|
||||
state: currentIndex > 1 ? 'done' : currentIndex === 1 ? 'current' : 'upcoming',
|
||||
},
|
||||
{
|
||||
code: 'WAITING_DOUBLE_CONFIRM',
|
||||
label: 'Ждём подтверждение',
|
||||
note: 'Показываем согласованные условия и ждём финальное подтверждение.',
|
||||
dateLabel: formatDay(dates.approval),
|
||||
state: currentIndex > 2 ? 'done' : currentIndex === 2 ? 'current' : 'upcoming',
|
||||
},
|
||||
{
|
||||
code: 'CONFIRMED',
|
||||
label: 'Заказ подтверждён',
|
||||
note: `Планируем передать в производство и ориентируемся на выпуск ${formatDay(dates.production)}.`,
|
||||
dateLabel: formatDay(dates.production),
|
||||
state: currentIndex > 3 ? 'done' : currentIndex === 3 ? 'current' : 'upcoming',
|
||||
},
|
||||
{
|
||||
code: 'IN_PROGRESS',
|
||||
label: 'Заказ в работе',
|
||||
note: `Сейчас идёт исполнение. Следующее ожидаемое обновление около ${formatDay(dates.shipment)}.`,
|
||||
dateLabel: formatDay(dates.shipment),
|
||||
state: currentIndex > 4 ? 'done' : currentIndex === 4 ? 'current' : 'upcoming',
|
||||
},
|
||||
{
|
||||
code: 'COMPLETED',
|
||||
label: 'Заказ завершён',
|
||||
note: 'Исполнение закрыто, заказ готов к выдаче или уже доставлен.',
|
||||
dateLabel: formatDay(dates.delivered),
|
||||
state: currentIndex === 5 ? 'current' : currentIndex > 5 ? 'done' : 'upcoming',
|
||||
},
|
||||
];
|
||||
|
||||
if (status === 'NEW') {
|
||||
return {
|
||||
title: 'Собираем предложение по заказу',
|
||||
summary: `Сейчас уточняем стоимость и комплектацию. Следующее обновление ориентировочно ${formatDay(dates.offer)}.`,
|
||||
stages,
|
||||
};
|
||||
}
|
||||
|
||||
if (status === 'MANAGER_PROCESSING') {
|
||||
return {
|
||||
title: 'Готовим условия по заказу',
|
||||
summary: `Менеджер собирает финальные условия. Ориентир по следующему апдейту ${formatDay(dates.approval)}.`,
|
||||
stages,
|
||||
};
|
||||
}
|
||||
|
||||
if (status === 'WAITING_DOUBLE_CONFIRM') {
|
||||
return {
|
||||
title: 'Ожидаем подтверждение условий',
|
||||
summary: 'Нужно подтвердить текущие условия, после этого сразу двинем заказ дальше.',
|
||||
stages,
|
||||
};
|
||||
}
|
||||
|
||||
if (status === 'CONFIRMED') {
|
||||
return {
|
||||
title: 'Заказ подтверждён',
|
||||
summary: `Ожидаем выпуск с производства ориентировочно ${formatDay(dates.production)}.`,
|
||||
stages,
|
||||
};
|
||||
}
|
||||
|
||||
if (status === 'IN_PROGRESS') {
|
||||
return {
|
||||
title: 'Заказ в работе',
|
||||
summary: `Сейчас заказ исполняется. Следующее ожидаемое обновление около ${formatDay(dates.shipment)}.`,
|
||||
stages,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: 'Заказ завершён',
|
||||
summary: 'Работы по заказу завершены, история этапов сохранена ниже.',
|
||||
stages,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user