Files
shiftcraft/app/utils/constraintDisplay.ts
Clanker 36e0946ee4 feat: complete ShiftCraft — AI-powered shift scheduling SaaS
Complete implementation including:
- Landing page with hero, features, how-it-works, pricing
- Employee management (CRUD with soft delete)
- AI constraint parser (Anthropic Claude API)
- German labor law templates (ArbZG §3, §5, §9)
- HiGHS ILP solver for optimal fair schedules
- Schedule calendar result view (employee × date grid)
- Shift framework configuration (periods + shifts)
- Subscription tiers: Free / Pro / Business
- PocketBase setup script with collection creation + seed data
- .env.example with all required variables documented

Pages: employees, constraints (list/new/templates), schedules (list/new/[id]),
       settings (organization/shifts/billing), dashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 07:47:31 +02:00

32 lines
1.5 KiB
TypeScript

import type { ConstraintJSON } from '~/shared/types/constraint'
export function constraintToHuman(constraint: ConstraintJSON): string {
return constraint.natural_language_summary || formatConstraintFallback(constraint)
}
function formatConstraintFallback(c: ConstraintJSON): string {
const params = c.params as Record<string, unknown>
switch (c.type) {
case 'max_hours_per_day':
return `Maximal ${params.max_hours} Stunden pro Tag`
case 'max_hours_per_week':
return `Maximal ${params.max_hours} Stunden pro Woche`
case 'min_rest_between_shifts':
return `Mindestens ${params.min_hours} Stunden Ruhezeit zwischen Schichten`
case 'max_consecutive_shifts':
return `Maximal ${params.max_count} Schichten am Stück`
case 'max_consecutive_shift_type':
return `Maximal ${params.max_count} ${params.period_id}-Schichten am Stück`
case 'forbidden_shift_sequence':
return `${params.first_period_id}-Schicht darf nicht direkt auf ${params.second_period_id}-Schicht folgen`
case 'employee_avoids_period':
return `Mitarbeiter bevorzugt keine ${params.period_id}-Schichten`
case 'employee_prefers_period':
return `Mitarbeiter bevorzugt ${params.period_id}-Schichten`
case 'fair_distribution':
return `Faire Verteilung der ${params.metric === 'night_shifts' ? 'Nachtschichten' : 'Schichten'} (max. ${params.max_deviation_percent}% Abweichung)`
default:
return c.type.replace(/_/g, ' ')
}
}