Add per-event finance, event team permissions and public door sales state.
Event finance - Finance tab on the event page: P&L summary with a revenue-to-result waterfall, costs and other income in one ledger, and the partner split with payouts. Lifecycle stepper (Selling, Adding costs, Ready to close, Finalized) with what is left to do; closing the books goes through a checklist dialog that freezes the numbers. - Expense modal shows only the fields each calculation type needs, a live preview with the event's real counts, and a category suggested from the description. Date inputs follow the UI language. - Global Finance page: profit per event with outliers clipped and labelled, and a "Ready to close" list of past events whose books are still open. - Calculation service (integer PYG, basis points) with pinned regression scenarios; PYG formatting centralised in lib/money with locale-aware separators. Event team permissions - Per-event members with role presets and requireEventPermission; the header stat "Confirmed" is relabelled "Not checked in yet", which is what it counts. Public sales state - One sales state (online, door, sold out, ended, external, cancelled) for the event page, listings and JSON-LD, with the door price and tenders shown only while people can still pay at the door. Frontend unit tests run with vitest (npm test in frontend/). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b51c1360e2
commit
e203fb6c74
@@ -3,7 +3,9 @@ import type { EmailTemplate, EmailVariable, EmailLog, EmailStats, Pagination } f
|
||||
|
||||
export const emailsApi = {
|
||||
// Templates
|
||||
getTemplates: () => fetchApi<{ templates: EmailTemplate[] }>('/api/emails/templates'),
|
||||
// Team members (non-admin) pass the event they email for, so the server can check their permission there.
|
||||
getTemplates: (eventId?: string) =>
|
||||
fetchApi<{ templates: EmailTemplate[] }>(`/api/emails/templates${eventId ? `?eventId=${encodeURIComponent(eventId)}` : ''}`),
|
||||
|
||||
getTemplate: (id: string) => fetchApi<{ template: EmailTemplate }>(`/api/emails/templates/${id}`),
|
||||
|
||||
@@ -56,8 +58,8 @@ export const emailsApi = {
|
||||
templateSlug: string;
|
||||
variables?: Record<string, any>;
|
||||
locale?: string;
|
||||
}) =>
|
||||
fetchApi<{ subject: string; bodyHtml: string }>('/api/emails/preview', {
|
||||
}, eventId?: string) =>
|
||||
fetchApi<{ subject: string; bodyHtml: string }>(`/api/emails/preview${eventId ? `?eventId=${encodeURIComponent(eventId)}` : ''}`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user