supersam/supabase/functions/_shared/delivery-invitations.ts

111 lines
3.7 KiB
TypeScript

export type DeliveryInvitationAction =
| "create_delivery_invitation"
| "send_delivery_offer"
| "send_delivery_reminder"
| "request_new_link"
| "confirm_delivery_choice"
| "transfer_to_logistics"
| "mark_paid_storage"
| "mark_delivered";
export type DeliveryInvitationPublicState =
| "awaiting_choice"
| "opened"
| "reminder_sent"
| "transferred_to_logistics"
| "paid_storage"
| "delivered"
| "agreed"
| "default";
export const DEFAULT_AVAILABLE_SLOTS = ["Первая половина дня", "Вторая половина дня"];
export const getOrderUpdateForDeliveryInvitationAction = (action: DeliveryInvitationAction) => {
switch (action) {
case "create_delivery_invitation":
case "send_delivery_offer":
case "send_delivery_reminder":
case "request_new_link":
return {
status: "Ожидает ответа клиента",
deliveryAgreementStatus: "Отправлено клиенту",
};
case "confirm_delivery_choice":
return {
status: "Доставка согласована",
deliveryAgreementStatus: "Подтверждено клиентом",
};
case "transfer_to_logistics":
return {
status: "Передан логисту",
deliveryAgreementStatus: "Нет ответа",
};
case "mark_paid_storage":
return {
status: "Платное хранение",
deliveryAgreementStatus: "Нет ответа",
};
case "mark_delivered":
return {
status: "Доставлен",
deliveryAgreementStatus: "Подтверждено клиентом",
};
default:
return null;
}
};
export const getClientInvitationStateFromOrderStatus = (
status: string,
): DeliveryInvitationPublicState => {
switch (status) {
case "Ожидает ответа клиента":
return "awaiting_choice";
case "Ожидает согласования доставки":
return "opened";
case "Напоминание отправлено":
case "Переход отправлен":
return "reminder_sent";
case "Передан логисту":
return "transferred_to_logistics";
case "Платное хранение":
return "paid_storage";
case "Доставлен":
return "delivered";
case "Доставка согласована":
return "agreed";
default:
return "default";
}
};
export const isActiveInvitationState = (state: DeliveryInvitationPublicState) =>
state === "awaiting_choice" || state === "opened" || state === "reminder_sent";
export const generateInvitationToken = () => crypto.randomUUID().replaceAll("-", "");
export const hashInvitationToken = async (token: string) => {
const bytes = new TextEncoder().encode(token);
const digest = await crypto.subtle.digest("SHA-256", bytes);
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
};
export const normalizeAvailableSlots = (availableSlots?: string[] | null) => {
const slots = availableSlots?.map((slot) => slot.trim()).filter(Boolean) || [];
return slots.length > 0 ? Array.from(new Set(slots)) : [...DEFAULT_AVAILABLE_SLOTS];
};
export const resolvePublicAppUrl = (
request: Request,
fallbackEnv?: string,
) => {
const origin = request.headers.get("origin") || request.headers.get("referer") || "";
const envValue =
fallbackEnv ||
(typeof Deno !== "undefined" ? Deno.env.get("PUBLIC_APP_URL") || Deno.env.get("APP_PUBLIC_URL") : "");
return (envValue || origin || "").replace(/\/$/, "");
};
export const buildInvitationUrl = (baseUrl: string, token: string) =>
`${baseUrl.replace(/\/$/, "")}/delivery/${token}`;