@fayz-ai/plugin-agenda 0.9.0 → 0.10.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 (196) hide show
  1. package/README.md +3 -3
  2. package/dist/bridges/create-financial-bridge.d.ts +1 -1
  3. package/dist/bridges/create-financial-bridge.d.ts.map +1 -1
  4. package/dist/bridges/financial-bridge.d.ts.map +1 -0
  5. package/dist/{chunk-Q2PAWBPR.js → chunk-ISLJXP7O.js} +7 -2
  6. package/dist/chunk-ISLJXP7O.js.map +1 -0
  7. package/dist/components/AppointmentModal.d.ts.map +1 -1
  8. package/dist/components/PaymentStatusBadge.d.ts +1 -1
  9. package/dist/components/PaymentStatusBadge.d.ts.map +1 -1
  10. package/dist/config.d.ts +2 -2
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/{AgendaContext.d.ts → context.d.ts} +1 -1
  13. package/dist/context.d.ts.map +1 -0
  14. package/dist/data/mock.d.ts.map +1 -1
  15. package/dist/data/realtime.test.d.ts +2 -0
  16. package/dist/data/realtime.test.d.ts.map +1 -0
  17. package/dist/data/registries.d.ts.map +1 -0
  18. package/dist/data/supabase.d.ts.map +1 -1
  19. package/dist/data/types.d.ts +7 -0
  20. package/dist/data/types.d.ts.map +1 -1
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2515 -187
  24. package/dist/index.js.map +1 -1
  25. package/dist/integrations/google-calendar/conflict.d.ts +25 -0
  26. package/dist/integrations/google-calendar/conflict.d.ts.map +1 -0
  27. package/dist/integrations/google-calendar/connectorDef.d.ts +12 -0
  28. package/dist/integrations/google-calendar/connectorDef.d.ts.map +1 -1
  29. package/dist/integrations/google-calendar/credentials.d.ts +27 -0
  30. package/dist/integrations/google-calendar/credentials.d.ts.map +1 -0
  31. package/dist/integrations/google-calendar/data/supabase.d.ts +10 -2
  32. package/dist/integrations/google-calendar/data/supabase.d.ts.map +1 -1
  33. package/dist/integrations/google-calendar/data/tables.d.ts +2 -0
  34. package/dist/integrations/google-calendar/data/tables.d.ts.map +1 -1
  35. package/dist/integrations/google-calendar/health.d.ts +23 -0
  36. package/dist/integrations/google-calendar/health.d.ts.map +1 -0
  37. package/dist/integrations/google-calendar/health.test.d.ts +2 -0
  38. package/dist/integrations/google-calendar/health.test.d.ts.map +1 -0
  39. package/dist/integrations/google-calendar/index.d.ts +6 -0
  40. package/dist/integrations/google-calendar/index.d.ts.map +1 -1
  41. package/dist/integrations/google-calendar/migrations/index.d.ts +12 -0
  42. package/dist/integrations/google-calendar/migrations/index.d.ts.map +1 -0
  43. package/dist/integrations/google-calendar/panel-data.d.ts +26 -0
  44. package/dist/integrations/google-calendar/panel-data.d.ts.map +1 -0
  45. package/dist/integrations/google-calendar/panel-data.test.d.ts +2 -0
  46. package/dist/integrations/google-calendar/panel-data.test.d.ts.map +1 -0
  47. package/dist/integrations/google-calendar/types.d.ts +17 -0
  48. package/dist/integrations/google-calendar/types.d.ts.map +1 -1
  49. package/dist/lib/booking-events.d.ts +5 -0
  50. package/dist/lib/booking-events.d.ts.map +1 -0
  51. package/dist/lib/calendar-events.d.ts +8 -0
  52. package/dist/lib/calendar-events.d.ts.map +1 -0
  53. package/dist/lib/calendar-events.test.d.ts +2 -0
  54. package/dist/lib/calendar-events.test.d.ts.map +1 -0
  55. package/dist/lib/message-events.d.ts +12 -0
  56. package/dist/lib/message-events.d.ts.map +1 -0
  57. package/dist/locales/en.d.ts.map +1 -1
  58. package/dist/locales/pt-BR.d.ts.map +1 -1
  59. package/dist/public/{data.d.ts → data/index.d.ts} +4 -4
  60. package/dist/public/data/index.d.ts.map +1 -0
  61. package/dist/public/{data.supabase.d.ts → data/supabase.d.ts} +2 -2
  62. package/dist/public/data/supabase.d.ts.map +1 -0
  63. package/dist/public/{hooks.d.ts → hooks/index.d.ts} +4 -4
  64. package/dist/public/hooks/index.d.ts.map +1 -0
  65. package/dist/public/index.d.ts +4 -4
  66. package/dist/public/index.d.ts.map +1 -1
  67. package/dist/public/index.js +3 -3
  68. package/dist/public/index.js.map +1 -1
  69. package/dist/public/{format.d.ts → lib/format.d.ts} +1 -1
  70. package/dist/public/lib/format.d.ts.map +1 -0
  71. package/dist/public/views/BookingWidget.d.ts.map +1 -0
  72. package/dist/public/{steps → views/steps}/ContactStep.d.ts +1 -1
  73. package/dist/public/views/steps/ContactStep.d.ts.map +1 -0
  74. package/dist/public/{steps → views/steps}/DateTimeStep.d.ts +3 -3
  75. package/dist/public/views/steps/DateTimeStep.d.ts.map +1 -0
  76. package/dist/public/{steps → views/steps}/OverviewStep.d.ts +1 -1
  77. package/dist/public/views/steps/OverviewStep.d.ts.map +1 -0
  78. package/dist/public/{steps → views/steps}/PaymentStep.d.ts +1 -1
  79. package/dist/public/views/steps/PaymentStep.d.ts.map +1 -0
  80. package/dist/store.d.ts +1 -1
  81. package/dist/store.d.ts.map +1 -1
  82. package/dist/styles/calendar-styles.d.ts.map +1 -0
  83. package/dist/types.d.ts +1 -1
  84. package/dist/types.d.ts.map +1 -1
  85. package/dist/{AgendaPage.d.ts → views/AgendaPage.d.ts} +3 -3
  86. package/dist/views/AgendaPage.d.ts.map +1 -0
  87. package/dist/views/CalendarView.d.ts.map +1 -1
  88. package/package.json +9 -11
  89. package/dist/AgendaContext.d.ts.map +0 -1
  90. package/dist/AgendaPage.d.ts.map +0 -1
  91. package/dist/calendar-styles.d.ts.map +0 -1
  92. package/dist/chunk-Q2PAWBPR.js.map +0 -1
  93. package/dist/financial-bridge.d.ts.map +0 -1
  94. package/dist/integrations/google-calendar/GoogleCalendarSettings.d.ts +0 -3
  95. package/dist/integrations/google-calendar/GoogleCalendarSettings.d.ts.map +0 -1
  96. package/dist/public/BookingWidget.d.ts.map +0 -1
  97. package/dist/public/data.d.ts.map +0 -1
  98. package/dist/public/data.supabase.d.ts.map +0 -1
  99. package/dist/public/format.d.ts.map +0 -1
  100. package/dist/public/hooks.d.ts.map +0 -1
  101. package/dist/public/steps/ContactStep.d.ts.map +0 -1
  102. package/dist/public/steps/DateTimeStep.d.ts.map +0 -1
  103. package/dist/public/steps/OverviewStep.d.ts.map +0 -1
  104. package/dist/public/steps/PaymentStep.d.ts.map +0 -1
  105. package/dist/registries.d.ts.map +0 -1
  106. package/src/AgendaContext.tsx +0 -11
  107. package/src/AgendaPage.tsx +0 -33
  108. package/src/bridges/create-financial-bridge.ts +0 -296
  109. package/src/calendar-styles.css +0 -245
  110. package/src/calendar-styles.ts +0 -285
  111. package/src/components/AgendaGeneralSettings.tsx +0 -86
  112. package/src/components/AgendaMobileList.tsx +0 -103
  113. package/src/components/AppointmentModal.tsx +0 -1050
  114. package/src/components/AppointmentPopover.tsx +0 -231
  115. package/src/components/BookingPaymentPanel.tsx +0 -394
  116. package/src/components/CalendarSidebar.tsx +0 -119
  117. package/src/components/CalendarToolbar.tsx +0 -86
  118. package/src/components/EventContextMenu.tsx +0 -125
  119. package/src/components/FloatingPanel.tsx +0 -123
  120. package/src/components/MiniCalendar.tsx +0 -120
  121. package/src/components/PaymentStatusBadge.tsx +0 -62
  122. package/src/components/StatusBadge.tsx +0 -23
  123. package/src/config.ts +0 -368
  124. package/src/data/index.ts +0 -4
  125. package/src/data/mock.ts +0 -344
  126. package/src/data/supabase.ts +0 -636
  127. package/src/data/types.ts +0 -37
  128. package/src/financial-bridge.ts +0 -96
  129. package/src/hooks/useAgendaSettings.ts +0 -17
  130. package/src/index.ts +0 -297
  131. package/src/integrations/google-calendar/GoogleCalendarSettings.tsx +0 -136
  132. package/src/integrations/google-calendar/components/CalendarColorDot.tsx +0 -23
  133. package/src/integrations/google-calendar/components/ChannelMappingList.tsx +0 -329
  134. package/src/integrations/google-calendar/components/ImportEventsWizard.tsx +0 -215
  135. package/src/integrations/google-calendar/components/useAgendaLookups.ts +0 -100
  136. package/src/integrations/google-calendar/connector.ts +0 -20
  137. package/src/integrations/google-calendar/connectorDef.tsx +0 -185
  138. package/src/integrations/google-calendar/data/supabase.ts +0 -170
  139. package/src/integrations/google-calendar/data/tables.ts +0 -12
  140. package/src/integrations/google-calendar/index.ts +0 -45
  141. package/src/integrations/google-calendar/integration.test.ts +0 -199
  142. package/src/integrations/google-calendar/mapping.ts +0 -183
  143. package/src/integrations/google-calendar/migrations/001_google_calendar.sql +0 -97
  144. package/src/integrations/google-calendar/migrations/002_smart_sync.sql +0 -517
  145. package/src/integrations/google-calendar/migrations/003_plg_rename.sql +0 -273
  146. package/src/integrations/google-calendar/types.ts +0 -142
  147. package/src/lib/tenant.ts +0 -3
  148. package/src/locales/en.ts +0 -220
  149. package/src/locales/index.ts +0 -7
  150. package/src/locales/pt-BR.ts +0 -220
  151. package/src/migrations/000b_v_bookings_rename.sql +0 -21
  152. package/src/migrations/000c_dedupe_customer_phones.sql +0 -43
  153. package/src/migrations/001_public_booking.sql +0 -296
  154. package/src/migrations/002_v_bookings_compat.sql +0 -14
  155. package/src/migrations/003_public_client_kind.sql +0 -175
  156. package/src/migrations/004_public_booking_assignee.sql +0 -176
  157. package/src/migrations/005_agent_rpcs.sql +0 -168
  158. package/src/migrations/006_agent_rpc_localtime.sql +0 -181
  159. package/src/migrations/007_schedule_exception_precedence.sql +0 -290
  160. package/src/migrations/008_agent_rpc_exception_precedence.sql +0 -172
  161. package/src/migrations/009_public_booking_location.sql +0 -162
  162. package/src/migrations/010_public_service_curation.sql +0 -31
  163. package/src/migrations/011_default_assignee.sql +0 -167
  164. package/src/migrations/012_drop_legacy_booking_overload.sql +0 -29
  165. package/src/migrations/013_normalize_v_appointments.sql +0 -199
  166. package/src/migrations/014_agent_rpc_update_appointment.sql +0 -199
  167. package/src/migrations/index.ts +0 -2377
  168. package/src/public/BookingWidget.tsx +0 -324
  169. package/src/public/components/BrandHeader.tsx +0 -27
  170. package/src/public/components/ServiceCard.tsx +0 -39
  171. package/src/public/components/SidebarExtras.tsx +0 -30
  172. package/src/public/components/StepRailItem.tsx +0 -27
  173. package/src/public/components/SuccessPanel.tsx +0 -27
  174. package/src/public/components/SummaryRail.tsx +0 -90
  175. package/src/public/components/defaults.ts +0 -14
  176. package/src/public/context.tsx +0 -103
  177. package/src/public/createPublicBookingPlugin.ts +0 -281
  178. package/src/public/data.supabase.ts +0 -97
  179. package/src/public/data.ts +0 -105
  180. package/src/public/format.ts +0 -96
  181. package/src/public/hooks.ts +0 -110
  182. package/src/public/index.ts +0 -69
  183. package/src/public/steps/ContactStep.tsx +0 -184
  184. package/src/public/steps/DateTimeStep.tsx +0 -138
  185. package/src/public/steps/OverviewStep.tsx +0 -81
  186. package/src/public/steps/PaymentStep.tsx +0 -180
  187. package/src/public/types.ts +0 -250
  188. package/src/registries.ts +0 -35
  189. package/src/store.ts +0 -311
  190. package/src/types.ts +0 -273
  191. package/src/views/CalendarView.tsx +0 -1112
  192. package/src/views/ConfirmationsView.tsx +0 -155
  193. /package/dist/{financial-bridge.d.ts → bridges/financial-bridge.d.ts} +0 -0
  194. /package/dist/{registries.d.ts → data/registries.d.ts} +0 -0
  195. /package/dist/public/{BookingWidget.d.ts → views/BookingWidget.d.ts} +0 -0
  196. /package/dist/{calendar-styles.d.ts → styles/calendar-styles.d.ts} +0 -0
package/src/store.ts DELETED
@@ -1,311 +0,0 @@
1
- import { createStore, type StoreApi } from 'zustand/vanilla'
2
- import { emitDataChanged } from '@fayz-ai/core'
3
- import { dedup } from '@fayz-ai/saas'
4
- import { toast } from '@fayz-ai/ui'
5
- import { getScheduleBlockConfig, setScheduleBlockConfig } from '@fayz-ai/saas'
6
- import type { AgendaDataProvider } from './data/types'
7
- import type { AgendaFinancialBridge } from './financial-bridge'
8
- import type { ExternalBookingSource } from './config'
9
- import type {
10
- CalendarBooking, Professional, Schedule,
11
- CreateBookingInput, UpdateBookingInput, BookingQuery,
12
- } from './types'
13
-
14
- // ---------------------------------------------------------------------------
15
- // Store state
16
- // ---------------------------------------------------------------------------
17
-
18
- export interface AgendaUIState {
19
- // Calendar data
20
- bookings: CalendarBooking[]
21
- bookingsLoading: boolean
22
- dateRange: { start: string; end: string }
23
- currentView: string
24
- selectedDate: string
25
-
26
- // Resources
27
- professionals: Professional[]
28
- professionalsLoading: boolean
29
-
30
- // Filters
31
- selectedProfessionalIds: string[]
32
- selectedLocationId: string | null
33
- selectedStatuses: string[]
34
-
35
- // Locations
36
- locations: Array<{ id: string; name: string }>
37
-
38
- // Schedules
39
- schedules: Schedule[]
40
- schedulesLoading: boolean
41
-
42
- // Confirmations
43
- pendingConfirmations: CalendarBooking[]
44
- confirmationsLoading: boolean
45
-
46
- // Modal state
47
- appointmentModal: {
48
- open: boolean
49
- mode: 'create' | 'edit'
50
- bookingId?: string
51
- prefill?: Partial<CreateBookingInput> & { endsAt?: string }
52
- initialTab?: string
53
- externalSource?: ExternalBookingSource
54
- }
55
-
56
- // Actions
57
- fetchBookings(range: { start: string; end: string }): Promise<void>
58
- fetchProfessionals(): Promise<void>
59
- fetchLocations(): Promise<void>
60
- fetchSchedules(professionalId?: string): Promise<void>
61
- fetchConfirmations(): Promise<void>
62
- createBooking(input: CreateBookingInput): Promise<CalendarBooking>
63
- updateBooking(id: string, data: UpdateBookingInput): Promise<CalendarBooking>
64
- deleteBooking(id: string): Promise<void>
65
- updateBookingStatus(id: string, status: string): Promise<void>
66
- rescheduleBooking(id: string, newStart: string, newEnd: string, newProfessionalId?: string): Promise<void>
67
- setFilters(filters: Partial<{ professionalIds: string[]; locationId: string | null; statuses: string[] }>): void
68
- setView(view: string): void
69
- setSelectedDate(date: string): void
70
- openAppointmentModal(mode: 'create' | 'edit', options?: { bookingId?: string; prefill?: Partial<CreateBookingInput> & { endsAt?: string }; initialTab?: string; externalSource?: ExternalBookingSource }): void
71
- closeAppointmentModal(): void
72
- }
73
-
74
- // ---------------------------------------------------------------------------
75
- // Store factory
76
- // ---------------------------------------------------------------------------
77
-
78
- function getCurrentBookingQuery(state: AgendaUIState, dateRange = state.dateRange): BookingQuery {
79
- return {
80
- dateRange,
81
- professionalIds: state.selectedProfessionalIds.length ? state.selectedProfessionalIds : undefined,
82
- locationId: state.selectedLocationId ?? undefined,
83
- statuses: state.selectedStatuses.length ? state.selectedStatuses : undefined,
84
- }
85
- }
86
-
87
- export function createAgendaStore(provider: AgendaDataProvider, financialBridge?: AgendaFinancialBridge): StoreApi<AgendaUIState> {
88
- return createStore<AgendaUIState>((set, get) => ({
89
- bookings: [],
90
- bookingsLoading: false,
91
- dateRange: { start: '', end: '' },
92
- currentView: 'resourceTimeGridDay',
93
- selectedDate: new Date().toISOString().slice(0, 10),
94
-
95
- professionals: [],
96
- professionalsLoading: false,
97
-
98
- selectedProfessionalIds: [],
99
- selectedLocationId: null,
100
- selectedStatuses: ['scheduled', 'confirmed', 'in_progress', 'completed'],
101
-
102
- locations: [],
103
-
104
- schedules: [],
105
- schedulesLoading: false,
106
-
107
- pendingConfirmations: [],
108
- confirmationsLoading: false,
109
-
110
- appointmentModal: { open: false, mode: 'create' },
111
-
112
- async fetchBookings(range) {
113
- const key = `agenda:bookings:${range.start}:${range.end}`
114
- return dedup(key, async () => {
115
- set({ bookingsLoading: true, dateRange: range })
116
- const state = get()
117
- const query = getCurrentBookingQuery(state, range)
118
- let bookings = await provider.getBookings(query)
119
-
120
- // Enrich with payment status if financial bridge is available
121
- if (financialBridge) {
122
- const orderIds = bookings.map((b) => b.orderId).filter((id): id is string => !!id)
123
- if (orderIds.length > 0) {
124
- try {
125
- const statuses = await financialBridge.resolvePaymentStatuses(orderIds)
126
- bookings = bookings.map((b) => {
127
- if (!b.orderId) return b
128
- const summary = statuses.get(b.orderId)
129
- return summary ? { ...b, paymentStatus: summary.status } : b
130
- })
131
- } catch { /* non-blocking */ }
132
- }
133
- }
134
-
135
- set({ bookings, bookingsLoading: false })
136
- })
137
- },
138
-
139
- async fetchProfessionals() {
140
- return dedup('agenda:professionals', async () => {
141
- set({ professionalsLoading: true })
142
- const professionals = await provider.getProfessionals()
143
- set({ professionals, professionalsLoading: false })
144
- })
145
- },
146
-
147
- async fetchLocations() {
148
- return dedup('agenda:locations', async () => {
149
- if (!provider.getLocations) return
150
- const locations = await provider.getLocations()
151
- set({ locations })
152
- // Update global schedule block config so ScheduleEditor picks up locations
153
- const current = getScheduleBlockConfig()
154
- if (current) {
155
- setScheduleBlockConfig({ ...current, locations })
156
- }
157
- })
158
- },
159
-
160
- async fetchSchedules(professionalId) {
161
- return dedup('agenda:schedules:' + (professionalId ?? 'all'), async () => {
162
- set({ schedulesLoading: true })
163
- const schedules = await provider.getSchedules(professionalId)
164
- set({ schedules, schedulesLoading: false })
165
- })
166
- },
167
-
168
- async fetchConfirmations() {
169
- return dedup('agenda:confirmations', async () => {
170
- set({ confirmationsLoading: true })
171
- const pendingConfirmations = await provider.getConfirmationsPending()
172
- set({ pendingConfirmations, confirmationsLoading: false })
173
- })
174
- },
175
-
176
- async createBooking(input) {
177
- try {
178
- const booking = await provider.createBooking(input)
179
- // Refresh bookings for current range
180
- const state = get()
181
- if (state.dateRange.start && state.dateRange.end) {
182
- const bookings = await provider.getBookings(getCurrentBookingQuery(state))
183
- set({ bookings })
184
- }
185
- emitDataChanged({ table: 'appointments', op: 'create', id: booking.id, source: 'ui' })
186
- toast.success('Appointment created')
187
- return booking
188
- } catch (err: any) {
189
- toast.error('Failed to create appointment', { description: err?.message })
190
- throw err
191
- }
192
- },
193
-
194
- async updateBooking(id, data) {
195
- try {
196
- const booking = await provider.updateBooking(id, data)
197
- const state = get()
198
- if (state.dateRange.start && state.dateRange.end) {
199
- const bookings = await provider.getBookings(getCurrentBookingQuery(state))
200
- set({ bookings })
201
- }
202
- emitDataChanged({ table: 'appointments', op: 'update', id, source: 'ui' })
203
- toast.success('Appointment updated')
204
- return booking
205
- } catch (err: any) {
206
- toast.error('Failed to update appointment', { description: err?.message })
207
- throw err
208
- }
209
- },
210
-
211
- async deleteBooking(id) {
212
- try {
213
- await provider.deleteBooking(id)
214
- const state = get()
215
- if (state.dateRange.start && state.dateRange.end) {
216
- const bookings = await provider.getBookings(getCurrentBookingQuery(state))
217
- set({ bookings })
218
- }
219
- emitDataChanged({ table: 'appointments', op: 'delete', id, source: 'ui' })
220
- toast.success('Appointment deleted')
221
- } catch (err: any) {
222
- toast.error('Failed to delete appointment', { description: err?.message })
223
- throw err
224
- }
225
- },
226
-
227
- async updateBookingStatus(id, status) {
228
- // Optimistic update — change color immediately
229
- const prev = get().bookings
230
- set({ bookings: prev.map((b) => b.id === id ? { ...b, status: status as any } : b) })
231
- try {
232
- await provider.updateBookingStatus(id, status)
233
- // Refresh from server to get full data
234
- const state = get()
235
- if (state.dateRange.start && state.dateRange.end) {
236
- const bookings = await provider.getBookings(getCurrentBookingQuery(state))
237
- set({ bookings })
238
- }
239
- emitDataChanged({ table: 'appointments', op: 'update', id, source: 'ui' })
240
- toast.success('Status updated')
241
- } catch (err: any) {
242
- // Rollback on failure
243
- set({ bookings: prev })
244
- toast.error('Failed to update status', { description: err?.message })
245
- throw err
246
- }
247
- },
248
-
249
- async rescheduleBooking(id, newStart, newEnd, newProfessionalId) {
250
- try {
251
- // Check for conflicts
252
- const existing = get().bookings.find((b) => b.id === id)
253
- const assigneeId = newProfessionalId ?? existing?.professionalId
254
- if (assigneeId) {
255
- const hasConflict = await provider.checkConflict({
256
- assigneeId,
257
- startsAt: newStart,
258
- endsAt: newEnd,
259
- excludeBookingId: id,
260
- })
261
- if (hasConflict) {
262
- toast.error('Time conflict detected', { description: 'This professional already has an appointment at this time.' })
263
- throw new Error('Time conflict')
264
- }
265
- }
266
- await provider.updateBooking(id, {
267
- startsAt: newStart,
268
- endsAt: newEnd,
269
- ...(newProfessionalId && { professionalId: newProfessionalId }),
270
- })
271
- const state = get()
272
- if (state.dateRange.start && state.dateRange.end) {
273
- const bookings = await provider.getBookings(getCurrentBookingQuery(state))
274
- set({ bookings })
275
- }
276
- toast.success('Appointment rescheduled')
277
- } catch (err: any) {
278
- if (err?.message !== 'Time conflict') {
279
- toast.error('Failed to reschedule', { description: err?.message })
280
- }
281
- throw err
282
- }
283
- },
284
-
285
- setFilters(filters) {
286
- set({
287
- ...(filters.professionalIds !== undefined && { selectedProfessionalIds: filters.professionalIds }),
288
- ...(filters.locationId !== undefined && { selectedLocationId: filters.locationId }),
289
- ...(filters.statuses !== undefined && { selectedStatuses: filters.statuses }),
290
- })
291
- // Re-fetch with new filters
292
- const { dateRange } = get()
293
- if (dateRange.start && dateRange.end) {
294
- get().fetchBookings(dateRange)
295
- }
296
- },
297
-
298
- setView(view) { set({ currentView: view }) },
299
- setSelectedDate(date) { set({ selectedDate: date }) },
300
-
301
- openAppointmentModal(mode, options) {
302
- set({ appointmentModal: { open: true, mode, bookingId: options?.bookingId, prefill: options?.prefill, initialTab: options?.initialTab, externalSource: options?.externalSource } })
303
- },
304
-
305
- closeAppointmentModal() {
306
- // Only toggle open — keep mode/bookingId/prefill intact so layout
307
- // doesn't shift during the close animation
308
- set((state) => ({ appointmentModal: { ...state.appointmentModal, open: false } }))
309
- },
310
- }))
311
- }
package/src/types.ts DELETED
@@ -1,273 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Agenda Plugin — Pure TypeScript types
3
- // Zero dependencies. Maps to public archetype tables.
4
- // ---------------------------------------------------------------------------
5
-
6
- // ============================================================
7
- // ENUMS / LITERALS
8
- // ============================================================
9
-
10
- /** Booking status lifecycle */
11
- export type BookingStatus =
12
- | 'scheduled'
13
- | 'confirmed'
14
- | 'in_progress'
15
- | 'completed'
16
- | 'cancelled'
17
- | 'no_show'
18
-
19
- /** Confirmation outreach status */
20
- export type ConfirmationStatus = 'pending' | 'sent' | 'confirmed' | 'declined'
21
-
22
- /** Booking type identifier — extensible via string literal union */
23
- export type BookingTypeId = 'appointment' | 'task' | 'out_of_office' | 'block' | (string & {})
24
-
25
- /** Configuration for a booking type (event type) */
26
- export interface BookingTypeConfig {
27
- id: BookingTypeId
28
- label: string
29
- icon: string
30
- color: string
31
- fields: {
32
- /** Free-text event title (maps to the booking's display name). Used by
33
- * simple / Google-Calendar-style events that have no client party. */
34
- title?: boolean
35
- client: boolean
36
- professional: boolean
37
- services: boolean
38
- location: boolean
39
- status: boolean
40
- }
41
- requiresServices: boolean
42
- requiresClient: boolean
43
- }
44
-
45
- // ============================================================
46
- // CORE ENTITIES
47
- // ============================================================
48
-
49
- /** A booking service line item (from public.appointment_items) */
50
- export interface BookingService {
51
- id: string
52
- serviceId: string | null
53
- name: string
54
- durationMinutes: number
55
- price: number
56
- assigneeId: string | null
57
- }
58
-
59
- /** Calendar booking — the main entity rendered on the calendar (from v_appointments view on orders) */
60
- export interface CalendarBooking {
61
- id: string
62
- tenantId: string
63
- kind: string
64
- /** Lifecycle stage: booked, invoiced, paid, etc. */
65
- stage?: string
66
- /** Financial direction: credit, debit, null */
67
- direction?: string | null
68
- startsAt: string
69
- endsAt: string | null
70
- status: BookingStatus
71
- notes: string | null
72
- /** In unified model, orderId === id (the booking IS the order) */
73
- orderId: string | null
74
- locationId: string | null
75
- metadata: Record<string, unknown>
76
-
77
- // Client (party)
78
- clientId: string | null
79
- clientName: string | null
80
- clientPhone: string | null
81
- clientEmail: string | null
82
- clientAvatarUrl: string | null
83
-
84
- // Professional (assignee)
85
- professionalId: string | null
86
- professionalName: string | null
87
- professionalAvatarUrl: string | null
88
-
89
- // Location
90
- locationName: string | null
91
-
92
- // Order totals
93
- orderTotal: number | null
94
- orderStatus: string | null
95
- /** Payment status from financial bridge (enriched at runtime) */
96
- paymentStatus?: import('./financial-bridge').BookingPaymentStatus
97
-
98
- // Aggregated services
99
- services: BookingService[] | null
100
- totalDurationMinutes: number | null
101
-
102
- createdAt: string
103
- updatedAt: string
104
- }
105
-
106
- /** Professional / staff resource for the calendar */
107
- export interface Professional {
108
- id: string
109
- name: string
110
- avatarUrl: string | null
111
- locationId: string | null
112
- locationName: string | null
113
- isActive: boolean
114
- }
115
-
116
- /** Working hours schedule (from public.schedules) */
117
- export interface Schedule {
118
- id: string
119
- tenantId: string
120
- kind: string
121
- assigneeId: string | null
122
- locationId: string | null
123
- dayOfWeek: number | null
124
- specificDate: string | null
125
- startsAt: string
126
- endsAt: string
127
- isActive: boolean
128
- metadata: Record<string, unknown>
129
- }
130
-
131
- /** Available time slot */
132
- export interface TimeSlot {
133
- start: string
134
- end: string
135
- }
136
-
137
- /** Confirmation record stored in booking metadata */
138
- export interface ConfirmationRecord {
139
- channel: string
140
- sentAt: string
141
- status: ConfirmationStatus
142
- confirmedAt?: string
143
- }
144
-
145
- // ============================================================
146
- // STATUS CONFIGURATION
147
- // ============================================================
148
-
149
- /**
150
- * When a status is available for selection relative to the booking date.
151
- * - 'always' — any date (e.g. scheduled, confirmed, cancelled)
152
- * - 'today_or_past' — booking is today or earlier (e.g. completed, no_show)
153
- * - 'today_only' — booking is today (e.g. in_progress)
154
- */
155
- export type StatusAvailability = 'always' | 'today_or_past' | 'today_only'
156
-
157
- export interface StatusConfig {
158
- value: string
159
- label: string
160
- color: string
161
- /** When this status can be selected (default: 'always') */
162
- availableWhen?: StatusAvailability
163
- }
164
-
165
- /** Check if a status is available for a given booking date */
166
- export function isStatusAvailable(status: StatusConfig, bookingStartsAt: string): boolean {
167
- const when = status.availableWhen ?? 'always'
168
- if (when === 'always') return true
169
- const bookingDate = bookingStartsAt.slice(0, 10)
170
- const today = new Date().toISOString().slice(0, 10)
171
- if (when === 'today_or_past') return bookingDate <= today
172
- if (when === 'today_only') return bookingDate === today
173
- return true
174
- }
175
-
176
- // ============================================================
177
- // MODAL TAB EXTENSION
178
- // ============================================================
179
-
180
- /** Props passed to every booking modal tab component */
181
- export interface BookingModalTabProps {
182
- bookingId?: string
183
- clientId: string
184
- orderId: string | null
185
- services: Array<{ name: string; price: number; durationMinutes: number }>
186
- formatCurrency: (amount: number) => string
187
- onDataChange?: () => void
188
- }
189
-
190
- /** A tab registered in the booking edit modal */
191
- export interface BookingModalTab {
192
- id: string
193
- label: string
194
- icon: string
195
- order: number
196
- component: React.ComponentType<BookingModalTabProps>
197
- visible?: (ctx: { mode: 'create' | 'edit'; clientId?: string; orderId?: string }) => boolean
198
- }
199
-
200
- // ============================================================
201
- // INPUT TYPES (create / mutate)
202
- // ============================================================
203
-
204
- export interface CreateBookingInput {
205
- kind?: BookingTypeId
206
- clientId: string
207
- professionalId: string
208
- locationId?: string
209
- startsAt: string
210
- notes?: string
211
- /** Free-text event title for simple events (no client party). Maps to the
212
- * booking's display name (clientName in the read model). */
213
- title?: string
214
- services: CreateBookingServiceInput[]
215
- }
216
-
217
- export interface CreateBookingServiceInput {
218
- serviceId: string
219
- name: string
220
- durationMinutes: number
221
- price: number
222
- assigneeId?: string
223
- }
224
-
225
- export interface UpdateBookingInput {
226
- clientId?: string
227
- professionalId?: string
228
- locationId?: string
229
- startsAt?: string
230
- endsAt?: string
231
- status?: BookingStatus
232
- notes?: string
233
- /** Free-text event title for simple events (no client party). */
234
- title?: string
235
- services?: CreateBookingServiceInput[]
236
- }
237
-
238
- export interface SaveScheduleInput {
239
- assigneeId: string
240
- locationId?: string
241
- dayOfWeek?: number
242
- specificDate?: string
243
- startsAt: string
244
- endsAt: string
245
- isActive?: boolean
246
- metadata?: Record<string, unknown>
247
- }
248
-
249
- // ============================================================
250
- // QUERY / FILTER TYPES
251
- // ============================================================
252
-
253
- export interface BookingQuery {
254
- dateRange: { start: string; end: string }
255
- professionalIds?: string[]
256
- locationId?: string
257
- statuses?: string[]
258
- kind?: string
259
- }
260
-
261
- export interface ConflictCheckParams {
262
- assigneeId: string
263
- startsAt: string
264
- endsAt: string
265
- excludeBookingId?: string
266
- }
267
-
268
- export interface AvailableSlotsParams {
269
- assigneeId: string
270
- date: string
271
- durationMinutes: number
272
- slotInterval?: number
273
- }