Make templates editable for existing orders and add {date:iso}/{date:at} formats
Build and Push Lunchtime Images (Kaniko) / build-and-push (push) Successful in 1m48s
Build and Push Lunchtime Images (Kaniko) / build-and-push (push) Successful in 1m48s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
23fcc9774e
commit
d15fe97584
3 files changed
+39
-3
No files matched your search
@@ -62,6 +62,7 @@ export default function ReadOnlyOrderOverviewCard({
|
|||||||
notifications,
|
notifications,
|
||||||
allowExport = false,
|
allowExport = false,
|
||||||
onSavePayment,
|
onSavePayment,
|
||||||
|
onSaveTemplates,
|
||||||
extraTabs = [],
|
extraTabs = [],
|
||||||
activeTabKey,
|
activeTabKey,
|
||||||
onTabChange,
|
onTabChange,
|
||||||
@@ -80,6 +81,8 @@ export default function ReadOnlyOrderOverviewCard({
|
|||||||
allowExport?: boolean;
|
allowExport?: boolean;
|
||||||
/** Makes the payment tab editable (order admin only); without it the tab is read-only. */
|
/** Makes the payment tab editable (order admin only); without it the tab is read-only. */
|
||||||
onSavePayment?: (payment: OrderPaymentDetails) => Promise<void>;
|
onSavePayment?: (payment: OrderPaymentDetails) => Promise<void>;
|
||||||
|
/** Makes the templates tab editable (order admin only); without it the tab is read-only. */
|
||||||
|
onSaveTemplates?: (templates: OrderTemplates) => Promise<void>;
|
||||||
extraTabs?: NonNullable<TabsProps["items"]>;
|
extraTabs?: NonNullable<TabsProps["items"]>;
|
||||||
activeTabKey?: string;
|
activeTabKey?: string;
|
||||||
onTabChange?: (key: string) => void;
|
onTabChange?: (key: string) => void;
|
||||||
@@ -207,7 +210,8 @@ export default function ReadOnlyOrderOverviewCard({
|
|||||||
templates={templates}
|
templates={templates}
|
||||||
config={currentConfig}
|
config={currentConfig}
|
||||||
previewContext={templatePreviewContext}
|
previewContext={templatePreviewContext}
|
||||||
readOnly
|
readOnly={!onSaveTemplates}
|
||||||
|
onSave={onSaveTemplates}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -115,7 +115,9 @@ export const BODY_PLACEHOLDERS = [
|
|||||||
{ key: "{creator}", description: "Order creator email" },
|
{ key: "{creator}", description: "Order creator email" },
|
||||||
{ key: "{participants}", description: "Participant emails (comma separated)" },
|
{ key: "{participants}", description: "Participant emails (comma separated)" },
|
||||||
{ key: "{link}", description: "Participant page link" },
|
{ key: "{link}", description: "Participant page link" },
|
||||||
{ key: "{date}", description: "Today's date" },
|
{ key: "{date}", description: "Today's date in the browser's culture" },
|
||||||
|
{ key: "{date:iso}", description: "Today's date as ISO 8601, e.g. 2026-11-04" },
|
||||||
|
{ key: "{date:at}", description: "Today's date in Austrian format, e.g. 04.11.2026" },
|
||||||
{ key: "{tally:Label}", description: "Count per item of a category, e.g. \"3x Fries\"" },
|
{ key: "{tally:Label}", description: "Count per item of a category, e.g. \"3x Fries\"" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -240,6 +242,23 @@ function decodeSeparator(separator: string): string {
|
|||||||
return separator.replace(/\\n/g, "\n").replace(/\\t/g, "\t");
|
return separator.replace(/\\n/g, "\n").replace(/\\t/g, "\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pad2(value: number): string {
|
||||||
|
return String(value).padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Culture-independent formats; without (or with an unknown) format the current culture is used.
|
||||||
|
function formatDate(date: Date, format: string | undefined): string {
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = pad2(date.getMonth() + 1);
|
||||||
|
const day = pad2(date.getDate());
|
||||||
|
|
||||||
|
switch (format?.trim().toLowerCase()) {
|
||||||
|
case "iso": return `${year}-${month}-${day}`;
|
||||||
|
case "at": return `${day}.${month}.${year}`;
|
||||||
|
default: return date.toLocaleDateString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function formatAmount(value: number | null): string {
|
function formatAmount(value: number | null): string {
|
||||||
return value === null ? "" : `€${value.toFixed(2)}`;
|
return value === null ? "" : `€${value.toFixed(2)}`;
|
||||||
}
|
}
|
||||||
@@ -578,7 +597,7 @@ export function renderTemplateText(
|
|||||||
case "creator": return context.creatorEmail || "";
|
case "creator": return context.creatorEmail || "";
|
||||||
case "participants": return getParticipantEmails(context).join(", ");
|
case "participants": return getParticipantEmails(context).join(", ");
|
||||||
case "link": return context.participantUrl;
|
case "link": return context.participantUrl;
|
||||||
case "date": return new Date().toLocaleDateString();
|
case "date": return formatDate(new Date(), arg);
|
||||||
case "tally": return arg ? renderTally(arg, context) : undefined;
|
case "tally": return arg ? renderTally(arg, context) : undefined;
|
||||||
default: return undefined;
|
default: return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,6 +233,18 @@ export default function AdminView({ orderId }: { orderId: string }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const saveTemplates = async (templates: OrderTemplates) => {
|
||||||
|
try {
|
||||||
|
const saved = await apiService.orders.updateTemplates(orderId, templates);
|
||||||
|
setData((previous: AdminViewData | null) =>
|
||||||
|
previous ? { ...previous, templates: normalizeOrderTemplates(saved) } : previous,
|
||||||
|
);
|
||||||
|
message.success("Templates saved");
|
||||||
|
} catch (error: any) {
|
||||||
|
message.error(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const saveNotifications = async (notifications: OrderNotifications) => {
|
const saveNotifications = async (notifications: OrderNotifications) => {
|
||||||
try {
|
try {
|
||||||
const saved = await apiService.orders.updateNotifications(orderId, notifications);
|
const saved = await apiService.orders.updateNotifications(orderId, notifications);
|
||||||
@@ -410,6 +422,7 @@ export default function AdminView({ orderId }: { orderId: string }) {
|
|||||||
notifications={data?.notifications}
|
notifications={data?.notifications}
|
||||||
allowExport
|
allowExport
|
||||||
onSavePayment={savePayment}
|
onSavePayment={savePayment}
|
||||||
|
onSaveTemplates={saveTemplates}
|
||||||
extraTabs={[
|
extraTabs={[
|
||||||
{
|
{
|
||||||
key: "notifications",
|
key: "notifications",
|
||||||
|
|||||||
Reference in new issue
Block a user