209 lines
6.4 KiB
TypeScript
209 lines
6.4 KiB
TypeScript
import type { DeliveryInquiryDetails, InquiryPreferredDate, PickupInquiryDetails } from '@/domain/cart/inquiry';
|
|
import { hasInquirySchedule, isInquiryBranchOnlineEnabled } from '@/domain/cart/inquiry';
|
|
import type { BookingDetails } from '@/domain/booking/entities';
|
|
import { isBookingComplete } from '@/domain/booking/validation';
|
|
import type { Language } from '@/domain/language/entities';
|
|
import { localizeOrderLineName } from '@/application/i18n/menu-localization';
|
|
import {
|
|
calculateOrderTotal,
|
|
formatOrderLinesForInquiry,
|
|
formatOrderLinesForMessage,
|
|
type OrderLine,
|
|
} from '@/domain/shared/order-line';
|
|
import { PICKUP_LEAD_TIME_MINUTES } from '@/domain/shared/constants';
|
|
|
|
export interface CartInquiryCopy {
|
|
pickupIntro: string;
|
|
deliveryIntro: string;
|
|
messageTotal: string;
|
|
messageName: string;
|
|
messageEmail: string;
|
|
messageBranch: string;
|
|
branchAskim: string;
|
|
branchBackaplan: string;
|
|
messageAddress: string;
|
|
messagePreferredDate: string;
|
|
messagePreferredTime: string;
|
|
scheduleDateToday: string;
|
|
scheduleDateTomorrow: string;
|
|
deliverySwishNote: string;
|
|
}
|
|
|
|
/** @deprecated Legacy cart copy — kept for any remaining references */
|
|
export interface CartDrawerCopy {
|
|
messageHello: string;
|
|
messageIntro: string;
|
|
messageAddress: string;
|
|
messageConfirm: string;
|
|
messageTotal: string;
|
|
messageThanks: string;
|
|
}
|
|
|
|
export interface BookingLocationCopy {
|
|
askim: string;
|
|
backaplan: string;
|
|
}
|
|
|
|
export interface BookingMessageCopy extends BookingLocationCopy {
|
|
modeTable: string;
|
|
modeEvent: string;
|
|
eventLine: string;
|
|
greeting: string;
|
|
labelName: string;
|
|
labelPhone: string;
|
|
labelEmail: string;
|
|
labelLocation: string;
|
|
labelDate: string;
|
|
labelTime: string;
|
|
labelGuests: string;
|
|
labelNotes: string;
|
|
labelPreOrder: string;
|
|
preOrderNone: string;
|
|
preOrderTotal: string;
|
|
confirmLine: string;
|
|
thanksLine: string;
|
|
}
|
|
|
|
export function getSuggestedPickupTime(language: Language, from: Date = new Date()): string {
|
|
const suggested = new Date(from.getTime() + PICKUP_LEAD_TIME_MINUTES * 60 * 1000);
|
|
const timeLocale =
|
|
language === 'sv' ? 'sv-SE' :
|
|
language === 'ar' ? 'ar-SA' :
|
|
language === 'tr' ? 'tr-TR' :
|
|
'en-GB';
|
|
return suggested.toLocaleTimeString(timeLocale, { hour: '2-digit', minute: '2-digit' });
|
|
}
|
|
|
|
function localizeInquiryLines(lang: Language, items: OrderLine[]): string {
|
|
return formatOrderLinesForInquiry(
|
|
items.map((item) => ({ ...item, name: localizeOrderLineName(lang, item) })),
|
|
);
|
|
}
|
|
|
|
function resolveInquiryBranchLabel(
|
|
branch: PickupInquiryDetails['branch'],
|
|
copy: CartInquiryCopy,
|
|
): string {
|
|
return branch === 'askim' ? copy.branchAskim : copy.branchBackaplan;
|
|
}
|
|
|
|
function resolveInquiryDateLabel(
|
|
date: InquiryPreferredDate,
|
|
copy: CartInquiryCopy,
|
|
): string {
|
|
return date === 'tomorrow' ? copy.scheduleDateTomorrow : copy.scheduleDateToday;
|
|
}
|
|
|
|
function formatInquiryScheduleLine(details: PickupInquiryDetails, copy: CartInquiryCopy): string {
|
|
if (!hasInquirySchedule(details)) return '';
|
|
|
|
return `${copy.messagePreferredDate}: ${resolveInquiryDateLabel(details.preferredDate, copy)}
|
|
${copy.messagePreferredTime}: ${details.preferredTime.trim()}`;
|
|
}
|
|
|
|
export function buildPickupInquiryMessage(
|
|
items: OrderLine[],
|
|
details: PickupInquiryDetails,
|
|
copy: CartInquiryCopy,
|
|
language: Language = 'sv',
|
|
): string | null {
|
|
if (items.length === 0 || !isInquiryBranchOnlineEnabled(details.branch)) return null;
|
|
|
|
const lines = localizeInquiryLines(language, items);
|
|
const total = calculateOrderTotal(items);
|
|
|
|
const scheduleLine = formatInquiryScheduleLine(details, copy);
|
|
|
|
return `${copy.pickupIntro}
|
|
${lines}
|
|
${copy.messageTotal}: ${total} kr
|
|
${copy.messageBranch}: ${resolveInquiryBranchLabel(details.branch, copy)}
|
|
${copy.messageName}: ${details.name.trim()}
|
|
${copy.messageEmail}: ${details.email.trim()}${scheduleLine ? `\n${scheduleLine}` : ''}`;
|
|
}
|
|
|
|
export function buildDeliveryInquiryMessage(
|
|
items: OrderLine[],
|
|
details: DeliveryInquiryDetails,
|
|
copy: CartInquiryCopy,
|
|
language: Language = 'sv',
|
|
): string | null {
|
|
if (items.length === 0 || !isInquiryBranchOnlineEnabled(details.branch)) return null;
|
|
|
|
const lines = localizeInquiryLines(language, items);
|
|
const total = calculateOrderTotal(items);
|
|
|
|
const scheduleLine = formatInquiryScheduleLine(details, copy);
|
|
const addressLine = details.address.trim()
|
|
? `${copy.messageAddress}: ${details.address.trim()}\n`
|
|
: '';
|
|
|
|
return `${copy.deliveryIntro}
|
|
${lines}
|
|
${copy.messageTotal}: ${total} kr
|
|
${copy.messageBranch}: ${resolveInquiryBranchLabel(details.branch, copy)}
|
|
${copy.messageName}: ${details.name.trim()}
|
|
${copy.messageEmail}: ${details.email.trim()}
|
|
${addressLine}${scheduleLine ? `${scheduleLine}\n` : ''}${copy.deliverySwishNote}`;
|
|
}
|
|
|
|
const PACKAGE_NAME_PLACEHOLDER = '{{package}}';
|
|
|
|
export function buildCateringPackagePricingMessage(
|
|
packageName: string,
|
|
template: string,
|
|
): string {
|
|
return template.split(PACKAGE_NAME_PLACEHOLDER).join(packageName);
|
|
}
|
|
|
|
function resolveBookingEventLabel(booking: BookingDetails, eventLabel: string): string {
|
|
if (booking.bookingMode !== 'event' || !booking.eventType) return '';
|
|
if (booking.eventType === 'other') {
|
|
return booking.eventTypeOther.trim() || eventLabel;
|
|
}
|
|
return eventLabel;
|
|
}
|
|
|
|
export function buildBookingWhatsAppMessage(
|
|
booking: BookingDetails,
|
|
preOrder: OrderLine[],
|
|
copy: BookingMessageCopy,
|
|
eventLabel = '',
|
|
language: Language = 'sv',
|
|
): string | null {
|
|
if (!isBookingComplete(booking)) return null;
|
|
|
|
const locationLabel =
|
|
booking.location === 'askim' ? copy.askim : copy.backaplan;
|
|
const bookingModeLabel =
|
|
booking.bookingMode === 'event' ? copy.modeEvent : copy.modeTable;
|
|
const occasionLine = resolveBookingEventLabel(booking, eventLabel);
|
|
const occasionText = occasionLine ? `\n${copy.eventLine}: ${occasionLine}` : '';
|
|
|
|
const itemsText =
|
|
preOrder.length > 0
|
|
? localizeInquiryLines(language, preOrder)
|
|
: copy.preOrderNone;
|
|
|
|
const totalText =
|
|
preOrder.length > 0 ? `\n${copy.preOrderTotal}: ${calculateOrderTotal(preOrder)} kr\n` : '';
|
|
|
|
return `${copy.greeting}
|
|
|
|
${bookingModeLabel}:
|
|
|
|
${copy.labelName}: ${booking.name}
|
|
${copy.labelPhone}: ${booking.phone}
|
|
${copy.labelEmail}: ${booking.email || 'N/A'}
|
|
${copy.labelLocation}: ${locationLabel}
|
|
${copy.labelDate}: ${booking.date}
|
|
${copy.labelTime}: ${booking.time}
|
|
${copy.labelGuests}: ${booking.guests}${occasionText}
|
|
${copy.labelNotes}: ${booking.notes || copy.preOrderNone}
|
|
|
|
${copy.labelPreOrder}:
|
|
${itemsText}${totalText}
|
|
${copy.confirmLine}
|
|
|
|
${copy.thanksLine}`;
|
|
} |