@fayz-ai/plugin-agenda 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/components/AgendaMobileList.d.ts +10 -0
  2. package/dist/components/AgendaMobileList.d.ts.map +1 -0
  3. package/dist/components/AppointmentModal.d.ts +4 -2
  4. package/dist/components/AppointmentModal.d.ts.map +1 -1
  5. package/dist/components/AppointmentPopover.d.ts.map +1 -1
  6. package/dist/components/EventContextMenu.d.ts.map +1 -1
  7. package/dist/config.d.ts +62 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/data/index.d.ts +1 -0
  10. package/dist/data/index.d.ts.map +1 -1
  11. package/dist/data/mock.d.ts +15 -1
  12. package/dist/data/mock.d.ts.map +1 -1
  13. package/dist/data/supabase.d.ts.map +1 -1
  14. package/dist/index.cjs +614 -308
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +452 -147
  19. package/dist/index.js.map +1 -1
  20. package/dist/locales/en.d.ts.map +1 -1
  21. package/dist/locales/pt-BR.d.ts.map +1 -1
  22. package/dist/store.d.ts +3 -0
  23. package/dist/store.d.ts.map +1 -1
  24. package/dist/types.d.ts +8 -0
  25. package/dist/types.d.ts.map +1 -1
  26. package/dist/views/CalendarView.d.ts.map +1 -1
  27. package/package.json +5 -8
  28. package/src/components/AgendaMobileList.tsx +103 -0
  29. package/src/components/AppointmentModal.tsx +86 -9
  30. package/src/components/AppointmentPopover.tsx +20 -10
  31. package/src/components/EventContextMenu.tsx +3 -0
  32. package/src/config.ts +104 -5
  33. package/src/data/index.ts +1 -0
  34. package/src/data/mock.ts +22 -5
  35. package/src/data/supabase.ts +13 -2
  36. package/src/index.ts +8 -3
  37. package/src/locales/en.ts +12 -0
  38. package/src/locales/pt-BR.ts +12 -0
  39. package/src/store.ts +4 -2
  40. package/src/types.ts +8 -0
  41. package/src/views/CalendarView.tsx +220 -54
@@ -1 +1 @@
1
- {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/locales/en.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6MrC,CAAA"}
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/locales/en.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyNrC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"pt-BR.d.ts","sourceRoot":"","sources":["../../src/locales/pt-BR.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6MvC,CAAA"}
1
+ {"version":3,"file":"pt-BR.d.ts","sourceRoot":"","sources":["../../src/locales/pt-BR.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyNvC,CAAA"}
package/dist/store.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type StoreApi } from 'zustand/vanilla';
2
2
  import type { AgendaDataProvider } from './data/types';
3
3
  import type { AgendaFinancialBridge } from './financial-bridge';
4
+ import type { ExternalBookingSource } from './config';
4
5
  import type { CalendarBooking, Professional, Schedule, CreateBookingInput, UpdateBookingInput } from './types';
5
6
  export interface AgendaUIState {
6
7
  bookings: CalendarBooking[];
@@ -32,6 +33,7 @@ export interface AgendaUIState {
32
33
  endsAt?: string;
33
34
  };
34
35
  initialTab?: string;
36
+ externalSource?: ExternalBookingSource;
35
37
  };
36
38
  fetchBookings(range: {
37
39
  start: string;
@@ -59,6 +61,7 @@ export interface AgendaUIState {
59
61
  endsAt?: string;
60
62
  };
61
63
  initialTab?: string;
64
+ externalSource?: ExternalBookingSource;
62
65
  }): void;
63
66
  closeAppointmentModal(): void;
64
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -11,6 +11,9 @@ export interface BookingTypeConfig {
11
11
  icon: string;
12
12
  color: string;
13
13
  fields: {
14
+ /** Free-text event title (maps to the booking's display name). Used by
15
+ * simple / Google-Calendar-style events that have no client party. */
16
+ title?: boolean;
14
17
  client: boolean;
15
18
  professional: boolean;
16
19
  services: boolean;
@@ -148,6 +151,9 @@ export interface CreateBookingInput {
148
151
  locationId?: string;
149
152
  startsAt: string;
150
153
  notes?: string;
154
+ /** Free-text event title for simple events (no client party). Maps to the
155
+ * booking's display name (clientName in the read model). */
156
+ title?: string;
151
157
  services: CreateBookingServiceInput[];
152
158
  }
153
159
  export interface CreateBookingServiceInput {
@@ -165,6 +171,8 @@ export interface UpdateBookingInput {
165
171
  endsAt?: string;
166
172
  status?: BookingStatus;
167
173
  notes?: string;
174
+ /** Free-text event title for simple events (no client party). */
175
+ title?: string;
168
176
  services?: CreateBookingServiceInput[];
169
177
  }
170
178
  export interface SaveScheduleInput {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CalendarView.d.ts","sourceRoot":"","sources":["../../src/views/CalendarView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAA;AA4OhF,wBAAgB,YAAY,sBA2pB3B"}
1
+ {"version":3,"file":"CalendarView.d.ts","sourceRoot":"","sources":["../../src/views/CalendarView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAA;AAwRhF,wBAAgB,YAAY,sBAqxB3B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fayz-ai/plugin-agenda",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "description": "Fayz SDK — plugin-agenda plugin",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -33,10 +33,10 @@
33
33
  "@tanstack/react-table": "^8.20.0",
34
34
  "@fullcalendar/resource-timegrid": "^6.1.0",
35
35
  "@fullcalendar/list": "^6.1.0",
36
- "@fayz-ai/core": "^0.6.0",
37
- "@fayz-ai/ui": "^0.6.0",
38
- "@fayz-ai/saas": "^0.6.0",
39
- "@fayz-ai/plugin-financial": "^0.1.7"
36
+ "@fayz-ai/core": "^0.6.6",
37
+ "@fayz-ai/ui": "^0.6.6",
38
+ "@fayz-ai/saas": "^0.6.6",
39
+ "@fayz-ai/plugin-financial": "^0.2.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/react": "^18.3.0",
@@ -53,9 +53,6 @@
53
53
  "fayz-plugin",
54
54
  "fayz-sdk"
55
55
  ],
56
- "publishConfig": {
57
- "access": "public"
58
- },
59
56
  "scripts": {
60
57
  "build": "tsup && tsc --emitDeclarationOnly --declaration --declarationMap --noEmit false",
61
58
  "dev": "tsup --watch",
@@ -0,0 +1,103 @@
1
+ import React, { useMemo } from 'react'
2
+ import { formatCurrency, useTranslation, getCurrentLocale } from '@fayz-ai/core'
3
+ import type { CalendarBooking } from '../types'
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Mobile agenda list — a thumb-friendly, date-grouped list of upcoming items.
7
+ // Rendered on <md viewports instead of the FullCalendar grid. Each row shows a
8
+ // category/status dot, the title, the time, and (for finance-style events) the
9
+ // amount. Fed straight from the store bookings so it works for any seeded app.
10
+ // ---------------------------------------------------------------------------
11
+
12
+ function startOfDay(d: Date): Date {
13
+ const x = new Date(d)
14
+ x.setHours(0, 0, 0, 0)
15
+ return x
16
+ }
17
+
18
+ function timeLabel(iso: string): string {
19
+ const d = new Date(iso)
20
+ return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
21
+ }
22
+
23
+ export interface AgendaMobileListProps {
24
+ bookings: CalendarBooking[]
25
+ statusColors: Record<string, string>
26
+ currencyCode: string
27
+ onSelect: (booking: CalendarBooking) => void
28
+ }
29
+
30
+ export function AgendaMobileList({ bookings, statusColors, currencyCode, onSelect }: AgendaMobileListProps) {
31
+ const t = useTranslation()
32
+ const locale = getCurrentLocale() === 'pt-BR' ? 'pt-BR' : 'en'
33
+
34
+ const groups = useMemo(() => {
35
+ const todayStart = startOfDay(new Date()).getTime()
36
+ const sorted = bookings
37
+ .filter((b) => !!b.startsAt)
38
+ .slice()
39
+ .sort((a, b) => (a.startsAt < b.startsAt ? -1 : a.startsAt > b.startsAt ? 1 : 0))
40
+ const map = new Map<string, CalendarBooking[]>()
41
+ for (const b of sorted) {
42
+ const day = startOfDay(new Date(b.startsAt))
43
+ if (day.getTime() < todayStart) continue // upcoming only
44
+ const key = day.toISOString().slice(0, 10)
45
+ const list = map.get(key) ?? []
46
+ list.push(b)
47
+ map.set(key, list)
48
+ }
49
+ return Array.from(map.entries()).map(([key, items]) => ({ key, date: new Date(key + 'T00:00:00'), items }))
50
+ }, [bookings])
51
+
52
+ function dayLabel(date: Date): string {
53
+ const today = startOfDay(new Date())
54
+ const diff = Math.round((startOfDay(date).getTime() - today.getTime()) / 86400000)
55
+ if (diff === 0) return t('agenda.list.today')
56
+ if (diff === 1) return t('agenda.list.tomorrow')
57
+ return date.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long' })
58
+ }
59
+
60
+ if (groups.length === 0) {
61
+ return (
62
+ <div className="flex-1 flex flex-col items-center justify-center px-6 py-16 text-center text-muted-foreground">
63
+ <p className="text-sm">{t('agenda.list.empty')}</p>
64
+ </div>
65
+ )
66
+ }
67
+
68
+ return (
69
+ <div className="flex-1 overflow-y-auto px-3 py-3 space-y-5">
70
+ {groups.map((g) => (
71
+ <div key={g.key}>
72
+ <h3 className="px-1 pb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
73
+ {dayLabel(g.date)}
74
+ </h3>
75
+ <div className="space-y-1.5">
76
+ {g.items.map((b) => {
77
+ const color = statusColors[b.status] ?? '#6b7280'
78
+ const hasAmount = typeof b.orderTotal === 'number' && b.orderTotal > 0
79
+ return (
80
+ <button
81
+ key={b.id}
82
+ onClick={() => onSelect(b)}
83
+ className="flex w-full items-center gap-3 rounded-lg border bg-card px-3 py-2.5 text-left shadow-sm transition-colors active:bg-muted/50"
84
+ >
85
+ <span className="h-2.5 w-2.5 shrink-0 rounded-full" style={{ backgroundColor: color }} />
86
+ <div className="min-w-0 flex-1">
87
+ <p className="truncate text-sm font-medium text-foreground">{b.clientName ?? '—'}</p>
88
+ <p className="text-xs text-muted-foreground">{timeLabel(b.startsAt)}</p>
89
+ </div>
90
+ {hasAmount && (
91
+ <span className="shrink-0 text-sm font-semibold tabular-nums text-foreground">
92
+ {formatCurrency(b.orderTotal, currencyCode)}
93
+ </span>
94
+ )}
95
+ </button>
96
+ )
97
+ })}
98
+ </div>
99
+ </div>
100
+ ))}
101
+ </div>
102
+ )
103
+ }
@@ -21,6 +21,7 @@ import { useTranslation } from '@fayz-ai/core'
21
21
  import { getCurrentLocale } from '@fayz-ai/core'
22
22
  import { isStatusAvailable } from '../types'
23
23
  import type { CreateBookingInput, BookingTypeId } from '../types'
24
+ import type { ExternalBookingSource } from '../config'
24
25
 
25
26
  // ---------------------------------------------------------------------------
26
27
  // Helpers
@@ -38,6 +39,7 @@ function formatCompactDate(dateStr: string, locale: string): string {
38
39
  }
39
40
 
40
41
  interface ServiceItem { serviceId: string; name: string; durationMinutes: number; price: number }
42
+ interface CancellationReasonItem { id: string; label: string; requiresNotes?: boolean }
41
43
 
42
44
  // ---------------------------------------------------------------------------
43
45
  // Inline editable number — allows clearing, commits on blur/enter
@@ -266,11 +268,12 @@ interface Props {
266
268
  bookingId?: string
267
269
  prefill?: Partial<CreateBookingInput> & { endsAt?: string }
268
270
  initialTab?: string
271
+ externalSource?: ExternalBookingSource
269
272
  onClose: () => void
270
- onCreated?: (bookingId: string) => void
273
+ onCreated?: (bookingId: string, source?: ExternalBookingSource) => void
271
274
  }
272
275
 
273
- export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose, onCreated }: Props) {
276
+ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, externalSource, onClose, onCreated }: Props) {
274
277
  const t = useTranslation()
275
278
  const locale = getCurrentLocale()
276
279
  const config = useAgendaConfig()
@@ -285,8 +288,12 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
285
288
  const storeLocations = useAgendaStore((s) => s.locations)
286
289
 
287
290
  // --- State ---
291
+ // Default to the first configured booking type (e.g. 'event' in simple mode,
292
+ // 'appointment' otherwise) so single-type agendas resolve their type cleanly.
293
+ const defaultBookingType = (config.bookingTypes[0]?.id ?? 'appointment') as BookingTypeId
288
294
  const [loading, setLoading] = useState(mode === 'edit')
289
- const [bookingType, setBookingType] = useState<BookingTypeId>(prefill?.kind ?? 'appointment')
295
+ const [bookingType, setBookingType] = useState<BookingTypeId>(prefill?.kind ?? defaultBookingType)
296
+ const [title, setTitle] = useState('')
290
297
  const [clientId, setClientId] = useState(prefill?.clientId ?? '')
291
298
  const [clientSearch, setClientSearch] = useState('')
292
299
  const [clientPhone, setClientPhone] = useState('')
@@ -331,6 +338,10 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
331
338
  const [clientData, setClientData] = useState<Record<string, any> | null>(null)
332
339
  const [clientDataLoading, setClientDataLoading] = useState(false)
333
340
  const [clientEditing, setClientEditing] = useState(false)
341
+ const [cancellationReasons, setCancellationReasons] = useState<CancellationReasonItem[]>([])
342
+ const [cancellationReasonId, setCancellationReasonId] = useState('')
343
+ const [cancellationNotes, setCancellationNotes] = useState('')
344
+ const [cancellationReasonsLoading, setCancellationReasonsLoading] = useState(false)
334
345
 
335
346
  // Active booking type config
336
347
  const activeType = config.bookingTypes.find((bt) => bt.id === bookingType) ?? config.bookingTypes[0]
@@ -343,10 +354,11 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
343
354
  setServiceSearch(''); setNotes(''); setStatus('scheduled'); setShowNotes(false)
344
355
  setConflict(false); setLoading(mode === 'edit')
345
356
  setQuickCreate(false); setNewClientName(''); setNewClientPhone(''); setNewClientEmail(''); setCreatingClient(false)
346
- setBookingType(prefill?.kind ?? 'appointment')
357
+ setBookingType(prefill?.kind ?? defaultBookingType); setTitle('')
347
358
  setEditingDate(false); setEditingTime(false); setConfirmingDelete(false); setDeleting(false)
348
359
  setEditOrderId(null); setEditOrderTotal(0); setEditPaymentStatus('none'); setPaymentStatusLoading(false)
349
360
  setClientData(null); setClientDataLoading(false); setClientEditing(false)
361
+ setCancellationReasonId(''); setCancellationNotes(''); setCancellationReasonsLoading(false)
350
362
  setModalTab((initialTab as 'appointment' | 'client' | 'financial') || 'appointment')
351
363
  if (!prefill?.professionalId && professionals.length === 1) setProfessionalId(professionals[0].id)
352
364
  setDate(() => {
@@ -368,7 +380,8 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
368
380
  setLoading(true)
369
381
  provider.getBookingById(bookingId).then((b) => {
370
382
  if (!b) { setLoading(false); return }
371
- setBookingType((b.kind as BookingTypeId) ?? 'appointment')
383
+ setBookingType((b.kind as BookingTypeId) ?? defaultBookingType)
384
+ setTitle(b.clientName ?? '')
372
385
  setClientId(b.clientId ?? ''); setClientSearch(b.clientName ?? '')
373
386
  setProfessionalId(b.professionalId ?? ''); setLocationId(b.locationId ?? '')
374
387
  setDate(b.startsAt.slice(0, 10))
@@ -385,10 +398,11 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
385
398
  // Save initial snapshot for dirty check
386
399
  const svcSnap = b.services ? b.services.map((s: any) => ({ id: s.serviceId ?? '', dur: s.durationMinutes, price: s.price })) : []
387
400
  initialSnapshot.current = JSON.stringify({
401
+ title: b.clientName ?? '',
388
402
  clientId: b.clientId ?? '', professionalId: b.professionalId ?? '', locationId: b.locationId ?? '',
389
403
  date: b.startsAt.slice(0, 10),
390
404
  startTime: `${String(new Date(b.startsAt).getHours()).padStart(2, '0')}:${String(new Date(b.startsAt).getMinutes()).padStart(2, '0')}`,
391
- status: b.status, notes: b.notes ?? '', services: svcSnap,
405
+ status: b.status, notes: b.notes ?? '', cancellationReasonId: '', cancellationNotes: '', services: svcSnap,
392
406
  })
393
407
  setLoading(false)
394
408
  // Resolve payment status from bridge if available
@@ -415,6 +429,15 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
415
429
  }).catch(() => setClientDataLoading(false))
416
430
  }, [modalTab, clientId])
417
431
 
432
+ useEffect(() => {
433
+ if (!open || status !== 'cancelled' || !config.cancellationDetails || cancellationReasons.length > 0) return
434
+ setCancellationReasonsLoading(true)
435
+ config.cancellationDetails.listReasons()
436
+ .then((reasons) => setCancellationReasons(reasons))
437
+ .catch(() => setCancellationReasons([]))
438
+ .finally(() => setCancellationReasonsLoading(false))
439
+ }, [open, status, config.cancellationDetails, cancellationReasons.length])
440
+
418
441
  // Fetch initial service list when modal opens
419
442
  useEffect(() => {
420
443
  if (!open || !config.serviceLookup) return
@@ -497,14 +520,24 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
497
520
  const startsAt = new Date(`${date}T${startTime}:00`).toISOString()
498
521
  if (mode === 'create') {
499
522
  const newBooking = await createBooking({ kind: bookingType, clientId, professionalId, locationId: locationId || undefined, startsAt, notes: notes || undefined,
523
+ title: activeType.fields.title ? title.trim() : undefined,
500
524
  services: services.map((s: any) => ({ serviceId: s.serviceId, name: s.name, durationMinutes: s.durationMinutes, price: s.price })) })
501
525
  onClose()
502
- onCreated?.(newBooking.id)
526
+ onCreated?.(newBooking.id, externalSource)
503
527
  } else if (bookingId) {
504
528
  await updateBooking(bookingId, {
505
529
  clientId, professionalId, locationId: locationId || undefined, startsAt, notes: notes || undefined, status: status as any,
530
+ title: activeType.fields.title ? title.trim() : undefined,
506
531
  services: services.map((s: any) => ({ serviceId: s.serviceId, name: s.name, durationMinutes: s.durationMinutes, price: s.price })),
507
532
  })
533
+ if (status === 'cancelled' && config.cancellationDetails && cancellationReasonId) {
534
+ await config.cancellationDetails.saveCancellationDetails({
535
+ bookingId,
536
+ reasonId: cancellationReasonId,
537
+ notes: cancellationNotes.trim() || undefined,
538
+ cancelledAt: new Date().toISOString(),
539
+ })
540
+ }
508
541
  onClose()
509
542
  }
510
543
  } catch { /* toast */ }
@@ -519,18 +552,24 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
519
552
  }
520
553
 
521
554
  const isPaidBooking = editPaymentStatus === 'paid'
555
+ const selectedCancellationReason = cancellationReasons.find((reason) => reason.id === cancellationReasonId)
556
+ const needsCancellationReason = mode === 'edit' && status === 'cancelled' && !!config.cancellationDetails
557
+ const needsCancellationNotes = needsCancellationReason && !!selectedCancellationReason?.requiresNotes
522
558
 
523
559
  // Dirty check — only enable Update when something changed
524
560
  const formSnapshot = useMemo(() =>
525
- JSON.stringify({ clientId, professionalId, locationId, date, startTime, status, notes, services: services.map((s: any) => ({ id: s.serviceId, dur: s.durationMinutes, price: s.price })) }),
526
- [clientId, professionalId, locationId, date, startTime, status, notes, services]
561
+ JSON.stringify({ title, clientId, professionalId, locationId, date, startTime, status, notes, cancellationReasonId, cancellationNotes, services: services.map((s: any) => ({ id: s.serviceId, dur: s.durationMinutes, price: s.price })) }),
562
+ [title, clientId, professionalId, locationId, date, startTime, status, notes, cancellationReasonId, cancellationNotes, services]
527
563
  )
528
564
  const isDirty = mode === 'create' || formSnapshot !== initialSnapshot.current
529
565
 
530
566
  const canSubmit = (
567
+ (!activeType.fields.title || title.trim()) &&
531
568
  (!activeType.requiresClient || clientId) &&
532
569
  (!activeType.fields.professional || professionalId) &&
533
570
  (!activeType.requiresServices || services.length > 0) &&
571
+ (!needsCancellationReason || !!cancellationReasonId) &&
572
+ (!needsCancellationNotes || !!cancellationNotes.trim()) &&
534
573
  !conflict && !saving
535
574
  )
536
575
 
@@ -748,6 +787,16 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
748
787
 
749
788
  {!loading && <>
750
789
 
790
+ {/* Title — free-text event name (simple / Google-Calendar-style events) */}
791
+ {activeType.fields.title && (
792
+ <div className="flex items-center gap-3 py-1">
793
+ <Calendar className="h-4 w-4 text-muted-foreground shrink-0" />
794
+ <input type="text" value={title} onChange={(e) => setTitle(e.target.value)}
795
+ placeholder={t('agenda.appointment.addTitle')} autoFocus={mode === 'create'}
796
+ className="w-full flex-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-ring" />
797
+ </div>
798
+ )}
799
+
751
800
  {/* Client */}
752
801
  {activeType.fields.client && (
753
802
  <div className="flex items-center gap-3 py-1">
@@ -927,6 +976,34 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, o
927
976
  </div>
928
977
  )}
929
978
 
979
+ {needsCancellationReason && (
980
+ <div className="flex items-start gap-3 py-1">
981
+ <Ban className="h-4 w-4 mt-2 text-muted-foreground shrink-0" />
982
+ <div className="flex-1 space-y-2">
983
+ <select
984
+ value={cancellationReasonId}
985
+ onChange={(event) => setCancellationReasonId(event.target.value)}
986
+ disabled={cancellationReasonsLoading}
987
+ className="w-full rounded-input border border-input bg-card px-2.5 py-1.5 text-sm shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring"
988
+ >
989
+ <option value="">{cancellationReasonsLoading ? t('agenda.cancellation.loadingReasons') : t('agenda.cancellation.selectReason')}</option>
990
+ {cancellationReasons.map((reason) => (
991
+ <option key={reason.id} value={reason.id}>
992
+ {reason.label}{reason.requiresNotes ? ' *' : ''}
993
+ </option>
994
+ ))}
995
+ </select>
996
+ <textarea
997
+ value={cancellationNotes}
998
+ onChange={(event) => setCancellationNotes(event.target.value)}
999
+ placeholder={needsCancellationNotes ? t('agenda.cancellation.notesRequired') : t('agenda.cancellation.notesOptional')}
1000
+ rows={2}
1001
+ className="w-full rounded-input border border-input bg-card px-2.5 py-1.5 text-sm resize-none shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring"
1002
+ />
1003
+ </div>
1004
+ </div>
1005
+ )}
1006
+
930
1007
  {/* Notes — progressive disclosure */}
931
1008
  {!showNotes ? (
932
1009
  <div className="flex items-center gap-3 py-1">
@@ -126,7 +126,14 @@ export function AppointmentPopover({ booking, position, onClose, onEdit }: Props
126
126
  <div className="flex items-start gap-3">
127
127
  <span className="mt-1.5 h-3 w-3 rounded shrink-0" style={{ backgroundColor: color }} />
128
128
  <div className="min-w-0">
129
- <PersonLink personId={booking.clientId} name={booking.clientName ?? 'Unknown'} className="text-base" />
129
+ {/* Client agendas link to the person; simple events (no client
130
+ capability) render the free-text title as a plain heading —
131
+ booking.clientName carries the event title in that model. */}
132
+ {config.capabilities.client ? (
133
+ <PersonLink personId={booking.clientId} name={booking.clientName ?? 'Unknown'} className="text-base" />
134
+ ) : (
135
+ <p className="text-base font-medium truncate">{booking.clientName || t('agenda.appointment.untitled')}</p>
136
+ )}
130
137
  <p className="text-sm text-muted-foreground mt-0.5">{fmtDate(booking.startsAt)} &middot; {timeRange}</p>
131
138
  </div>
132
139
  </div>
@@ -142,7 +149,7 @@ export function AppointmentPopover({ booking, position, onClose, onEdit }: Props
142
149
  </div>
143
150
  )}
144
151
 
145
- {booking.professionalName && (
152
+ {config.capabilities.professional && booking.professionalName && (
146
153
  <div className="flex items-center gap-3">
147
154
  <User className="h-4 w-4 text-muted-foreground shrink-0" />
148
155
  <span className="text-sm">{booking.professionalName}</span>
@@ -204,14 +211,17 @@ export function AppointmentPopover({ booking, position, onClose, onEdit }: Props
204
211
  )
205
212
  })()}
206
213
 
207
- <div className="pt-2 border-t fayz-glass-divider">
208
- <PopoverStatusSelect
209
- value={booking.status}
210
- statuses={config.statuses}
211
- bookingStartsAt={booking.startsAt}
212
- onChange={(v) => { updateStatus(booking.id, v); onClose() }}
213
- />
214
- </div>
214
+ {/* Status workflow — hidden for simple events (no status capability). */}
215
+ {config.capabilities.status && (
216
+ <div className="pt-2 border-t fayz-glass-divider">
217
+ <PopoverStatusSelect
218
+ value={booking.status}
219
+ statuses={config.statuses}
220
+ bookingStartsAt={booking.startsAt}
221
+ onChange={(v) => { updateStatus(booking.id, v); onClose() }}
222
+ />
223
+ </div>
224
+ )}
215
225
  </div>
216
226
  </>
217
227
  )}
@@ -101,6 +101,8 @@ export function EventContextMenu({ booking, position, onClose, onEdit }: Props)
101
101
  )}
102
102
  </div>
103
103
 
104
+ {/* Status workflow — hidden for simple events (no status capability). */}
105
+ {config.capabilities.status && (
104
106
  <div className="border-t px-4 py-3">
105
107
  <p className="text-[11px] font-medium text-muted-foreground mb-2">{t('agenda.contextMenu.changeStatus')}</p>
106
108
  <div className="flex items-center gap-1.5">
@@ -115,6 +117,7 @@ export function EventContextMenu({ booking, position, onClose, onEdit }: Props)
115
117
  })}
116
118
  </div>
117
119
  </div>
120
+ )}
118
121
  </>
119
122
  )}
120
123
  </FloatingPanel>