7eb6357b4a
Fresh installs can now shape the event-type catalog during the setup wizard — rename, delete or replace the seeded defaults while nothing references them. On existing installs system types stay protected. - New wizard step between features and config: edit name/URL prefix, remove, or add types; defaults shown as recommendations - setup_wizard_completed app setting (migration 161): seeded true when an admin already exists, false on fresh installs; POST /api/setup/ complete (adminAuth) flips it when the wizard finishes - deleteEventType: system types deletable only while the flag is unset; in-use check extended to quotes; per-type reminder template (event_reminder_<slug>) is deleted with the type - reminder-template self-heal no longer resurrects templates for slugs removed from the catalog - v1 API event creation validates event_type against the live catalog instead of a hardcoded whitelist (custom types were rejected; the never-seeded 'family' slug is no longer silently accepted) - contract→event conversion resolves the event type via crm_default_event_type / resolveDefaultEventType instead of hardcoding 'wedding' (resolveDefaultEventType moved from quoteService to eventTypeService for reuse)
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
import { api } from '../config/api';
|
|
|
|
export interface SetupStatus {
|
|
needsAdmin: boolean;
|
|
complete: boolean;
|
|
}
|
|
|
|
export interface SetupAdminUser {
|
|
id: number;
|
|
username: string;
|
|
email: string;
|
|
role: { name: string; displayName?: string };
|
|
}
|
|
|
|
export interface CreateInitialAdminInput {
|
|
token: string;
|
|
email: string;
|
|
password: string;
|
|
}
|
|
|
|
// First-run bootstrap. Public endpoints that self-close once an admin exists.
|
|
export const setupService = {
|
|
async getSetupStatus(): Promise<SetupStatus> {
|
|
const response = await api.get<SetupStatus>('/setup/status');
|
|
return response.data;
|
|
},
|
|
|
|
// Step-1 pre-flight: confirm the token is valid before advancing to the
|
|
// account step. Rejects (400, field: 'token') on a wrong token without
|
|
// burning it. Throws on non-2xx so the caller can branch on the status.
|
|
async verifyToken(token: string): Promise<{ valid: boolean }> {
|
|
const response = await api.post<{ valid: boolean }>('/setup/verify-token', { token });
|
|
return response.data;
|
|
},
|
|
|
|
async createInitialAdmin(input: CreateInitialAdminInput): Promise<{ user: SetupAdminUser }> {
|
|
// Admin JWT is returned as an HttpOnly cookie (mirrors login); body carries the user.
|
|
const response = await api.post<{ user: SetupAdminUser }>('/setup/admin', input);
|
|
return response.data;
|
|
},
|
|
|
|
// One-way wizard-finish marker (authenticated — runs after the admin
|
|
// exists). While unset, the wizard's event-types step may delete the
|
|
// seeded system types; afterwards they are permanently protected.
|
|
async completeSetup(): Promise<void> {
|
|
await api.post('/setup/complete');
|
|
},
|
|
};
|