chore: seminarhof customer project

This commit is contained in:
e2e
2026-06-22 09:44:35 +02:00
commit c3035e16ec
161 changed files with 18517 additions and 0 deletions

24
apps/app/src/lib/auth.ts Normal file
View File

@@ -0,0 +1,24 @@
import { createAuthClient } from 'better-auth/client'
function apiUrl(): string {
if (typeof window !== 'undefined' && (window as any).__E2E_API_URL) {
return (window as any).__E2E_API_URL as string
}
return import.meta.env.VITE_API_URL ?? '/api'
}
// Better Auth mounts at /api/auth (default basePath); the client appends the
// endpoint verbatim to baseURL, so the base must include /auth — otherwise it
// emits /api/sign-in/email and 404s on both sandbox and deploy.
export const authClient = createAuthClient({
baseURL: `${apiUrl()}/auth`,
})
export async function signIn(email: string, password: string): Promise<void> {
const { error } = await authClient.signIn.email({ email, password })
if (error) throw new Error('Invalid credentials')
}
export async function signOut(): Promise<void> {
await authClient.signOut()
}

24
apps/app/src/lib/dates.ts Normal file
View File

@@ -0,0 +1,24 @@
// Placeholder shown for missing dates (an enquiry may not have dates yet).
const NO_DATE = '—'
export function fmtDate(d: Date | null | undefined, locale: string): string {
if (!d) return NO_DATE
return d.toLocaleDateString(locale.startsWith('de') ? 'de-DE' : 'en-GB', {
day: 'numeric',
month: 'short',
year: 'numeric',
})
}
export function fmtDateShort(d: Date | null | undefined, locale: string): string {
if (!d) return NO_DATE
return d.toLocaleDateString(locale.startsWith('de') ? 'de-DE' : 'en-GB', {
day: 'numeric',
month: 'short',
})
}
export function toDateInputStr(d: Date | null | undefined): string {
if (!d) return ''
return d.toISOString().slice(0, 10)
}

View File

@@ -0,0 +1,35 @@
// Brand-aligned status palettes. Single source of truth for booking, invoice
// and room state colours. Each entry: bg (badge background), fg (text colour)
// and dot (8 px leading dot). Hex codes are checked for ≥4.5:1 on bg.
export type BookingStatus =
| 'enquiry'
| 'reserved'
| 'confirmed'
| 'ended'
| 'cancelled'
export const BOOKING_STATUS: Record<BookingStatus, { bg: string; fg: string; dot: string }> = {
enquiry: { bg: '#F7EEF5', fg: '#583651', dot: '#BC7AA6' },
reserved: { bg: '#FFEDDC', fg: '#8A4A1A', dot: '#FFBC7D' },
confirmed: { bg: '#E9D4E2', fg: '#4E3149', dot: '#88557F' },
ended: { bg: '#EDEDED', fg: '#4A4A4A', dot: '#989499' },
cancelled: { bg: '#F2F2F2', fg: '#6B6B6B', dot: '#B5B5B5' },
}
/** Valid transitions per status (client-side, for CTA buttons). Enforced server-side too. */
export const BOOKING_TRANSITIONS: Record<BookingStatus, BookingStatus[]> = {
enquiry: ['reserved', 'cancelled'],
reserved: ['confirmed', 'cancelled'],
confirmed: ['ended', 'cancelled'],
ended: [],
cancelled: [],
}
export type InvoiceStatus = 'outstanding' | 'paid' | 'cancelled'
export const INVOICE_STATUS: Record<InvoiceStatus, { bg: string; fg: string; dot: string }> = {
outstanding: { bg: '#FFF8E0', fg: '#806600', dot: '#FFCE00' },
paid: { bg: '#E9D4E2', fg: '#4E3149', dot: '#88557F' },
cancelled: { bg: '#F2F2F2', fg: '#6B6B6B', dot: '#B5B5B5' },
}