@open-mercato/ui 0.6.2-develop.3461.1.605f31c2c9 → 0.6.2

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 (86) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/ai/AiChat.js +130 -22
  3. package/dist/ai/AiChat.js.map +2 -2
  4. package/dist/ai/AiChatSessions.js +73 -3
  5. package/dist/ai/AiChatSessions.js.map +2 -2
  6. package/dist/ai/conversation-store.js +149 -0
  7. package/dist/ai/conversation-store.js.map +7 -0
  8. package/dist/ai/parts/MutationPreviewCard.js +4 -3
  9. package/dist/ai/parts/MutationPreviewCard.js.map +2 -2
  10. package/dist/ai/parts/MutationResultCard.js +9 -16
  11. package/dist/ai/parts/MutationResultCard.js.map +2 -2
  12. package/dist/ai/useAiChat.js +80 -4
  13. package/dist/ai/useAiChat.js.map +2 -2
  14. package/dist/backend/AuthSessionGuard.js +99 -0
  15. package/dist/backend/AuthSessionGuard.js.map +7 -0
  16. package/dist/backend/CrudForm.js +2 -1
  17. package/dist/backend/CrudForm.js.map +2 -2
  18. package/dist/backend/FilterOverlay.js +1 -1
  19. package/dist/backend/FilterOverlay.js.map +1 -1
  20. package/dist/backend/dashboard/widgetRegistry.js +2 -1
  21. package/dist/backend/dashboard/widgetRegistry.js.map +2 -2
  22. package/dist/backend/date-range/dateRanges.js +16 -18
  23. package/dist/backend/date-range/dateRanges.js.map +2 -2
  24. package/dist/backend/detail/AttachmentMetadataDialog.js +3 -1
  25. package/dist/backend/detail/AttachmentMetadataDialog.js.map +2 -2
  26. package/dist/backend/detail/InlineEditors.js +1 -1
  27. package/dist/backend/detail/InlineEditors.js.map +1 -1
  28. package/dist/backend/injection/useAppEvent.js +2 -7
  29. package/dist/backend/injection/useAppEvent.js.map +2 -2
  30. package/dist/backend/injection/widgetRegistry.js +2 -1
  31. package/dist/backend/injection/widgetRegistry.js.map +2 -2
  32. package/dist/backend/messages/useMessageCompose.js +62 -5
  33. package/dist/backend/messages/useMessageCompose.js.map +2 -2
  34. package/dist/backend/messages/useMessageComposeOperations.js +64 -5
  35. package/dist/backend/messages/useMessageComposeOperations.js.map +2 -2
  36. package/dist/backend/schedule/ScheduleCalendar.js +11 -1
  37. package/dist/backend/schedule/ScheduleCalendar.js.map +2 -2
  38. package/dist/backend/schedule/ScheduleToolbar.js +11 -1
  39. package/dist/backend/schedule/ScheduleToolbar.js.map +2 -2
  40. package/dist/primitives/calendar.js +1 -1
  41. package/dist/primitives/calendar.js.map +1 -1
  42. package/dist/primitives/date-format.js +1 -1
  43. package/dist/primitives/date-format.js.map +1 -1
  44. package/dist/primitives/date-picker-helpers.js +7 -9
  45. package/dist/primitives/date-picker-helpers.js.map +2 -2
  46. package/dist/primitives/date-picker.js +1 -1
  47. package/dist/primitives/date-picker.js.map +2 -2
  48. package/dist/primitives/date-range-picker.js +1 -1
  49. package/dist/primitives/date-range-picker.js.map +2 -2
  50. package/jest.config.cjs +4 -1
  51. package/package.json +6 -7
  52. package/src/ai/AiChat.tsx +138 -22
  53. package/src/ai/AiChatSessions.tsx +89 -9
  54. package/src/ai/__tests__/AiAssistantLauncher.test.tsx +1 -1
  55. package/src/ai/__tests__/AiChat.conversation.test.tsx +86 -0
  56. package/src/ai/__tests__/AiChat.test.tsx +17 -2
  57. package/src/ai/__tests__/conversation-store.test.ts +29 -0
  58. package/src/ai/conversation-store.ts +246 -0
  59. package/src/ai/parts/MutationPreviewCard.tsx +25 -20
  60. package/src/ai/parts/MutationResultCard.tsx +15 -27
  61. package/src/ai/parts/__tests__/MutationPreviewCard.test.tsx +26 -1
  62. package/src/ai/parts/__tests__/MutationResultCard.test.tsx +16 -1
  63. package/src/ai/useAiChat.ts +97 -8
  64. package/src/backend/AuthSessionGuard.tsx +114 -0
  65. package/src/backend/CrudForm.tsx +3 -2
  66. package/src/backend/FilterOverlay.tsx +1 -1
  67. package/src/backend/__tests__/AppShell.test.tsx +1 -1
  68. package/src/backend/__tests__/AuthSessionGuard.test.tsx +150 -0
  69. package/src/backend/__tests__/SidebarCustomizationEditor.test.tsx +8 -1
  70. package/src/backend/dashboard/widgetRegistry.ts +2 -1
  71. package/src/backend/date-range/dateRanges.ts +16 -18
  72. package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
  73. package/src/backend/detail/InlineEditors.tsx +1 -1
  74. package/src/backend/injection/__tests__/useAppEvent.test.ts +16 -0
  75. package/src/backend/injection/useAppEvent.ts +2 -9
  76. package/src/backend/injection/widgetRegistry.ts +2 -1
  77. package/src/backend/messages/__tests__/MessageComposer.test.tsx +77 -0
  78. package/src/backend/messages/useMessageCompose.ts +64 -5
  79. package/src/backend/messages/useMessageComposeOperations.ts +70 -4
  80. package/src/backend/schedule/ScheduleCalendar.tsx +11 -1
  81. package/src/backend/schedule/ScheduleToolbar.tsx +11 -1
  82. package/src/primitives/calendar.tsx +2 -2
  83. package/src/primitives/date-format.ts +2 -2
  84. package/src/primitives/date-picker-helpers.ts +7 -9
  85. package/src/primitives/date-picker.tsx +2 -2
  86. package/src/primitives/date-range-picker.tsx +2 -2
@@ -533,7 +533,7 @@ export function AttachmentMetadataDialog({ open, onOpenChange, item, availableTa
533
533
  {item.fileName}
534
534
  </div>
535
535
  <div className="text-xs text-muted-foreground">
536
- {formatFileSize(item.fileSize)} \u2022 {item.partitionTitle ?? item.partitionCode}
536
+ {formatFileSize(item.fileSize)} {'\u2022'} {item.partitionTitle ?? item.partitionCode}
537
537
  </div>
538
538
  </div>
539
539
  {downloadUrl ? (
@@ -17,7 +17,7 @@ import { Textarea } from '@open-mercato/ui/primitives/textarea'
17
17
  import { DatePicker } from '@open-mercato/ui/primitives/date-picker'
18
18
  import { useT } from '@open-mercato/shared/lib/i18n/context'
19
19
  import { cn } from '@open-mercato/shared/lib/utils'
20
- import { format } from 'date-fns'
20
+ import { format } from 'date-fns/format'
21
21
  import { LoadingMessage } from './LoadingMessage'
22
22
  import { mapCrudServerErrorToFormErrors } from '../utils/serverErrors'
23
23
  import { MarkdownPreview } from '../markdown'
@@ -0,0 +1,16 @@
1
+ import { matchesPattern } from '../useAppEvent'
2
+
3
+ describe('matchesPattern', () => {
4
+ it('matches DOM event wildcard patterns without regex execution', () => {
5
+ expect(matchesPattern('*', 'customers.person.created')).toBe(true)
6
+ expect(matchesPattern('customers.person.*', 'customers.person.created')).toBe(true)
7
+ expect(matchesPattern('customers.*.created', 'customers.person.created')).toBe(true)
8
+ expect(matchesPattern('sales.*', 'customers.person.created')).toBe(false)
9
+ })
10
+
11
+ it('treats regex metacharacters as literal event characters', () => {
12
+ expect(matchesPattern('customers.(person).*', 'customers.(person).created')).toBe(true)
13
+ expect(matchesPattern('customers.+.*', 'customers.person.created')).toBe(false)
14
+ })
15
+ })
16
+
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
  import { useEffect, useRef } from 'react'
3
3
  import type { AppEventPayload } from '@open-mercato/shared/modules/widgets/injection'
4
+ import { matchWildcardPattern } from '@open-mercato/shared/lib/patterns/wildcard'
4
5
 
5
6
  /**
6
7
  * DOM Event Bridge event name.
@@ -23,15 +24,7 @@ export const APP_EVENT_DOM_NAME = 'om:event'
23
24
  * matchesPattern('*', 'anything.here') // true
24
25
  */
25
26
  export function matchesPattern(pattern: string, eventId: string): boolean {
26
- if (pattern === '*') return true
27
- if (!pattern.includes('*')) return pattern === eventId
28
- const escapedPattern = pattern
29
- .replace(/[|\\{}()[\]^$+?.]/g, '\\$&')
30
- .replace(/\*/g, '.*')
31
- const regex = new RegExp(
32
- '^' + escapedPattern + '$',
33
- )
34
- return regex.test(eventId)
27
+ return matchWildcardPattern(eventId, pattern)
35
28
  }
36
29
 
37
30
  /**
@@ -1,5 +1,6 @@
1
1
  import type { ModuleInjectionWidgetEntry } from '@open-mercato/shared/modules/registry'
2
2
  import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'
3
+ import { applyInjectionWidgetOverridesToEntries } from '@open-mercato/shared/modules/overrides'
3
4
 
4
5
  type Entry = ModuleInjectionWidgetEntry
5
6
 
@@ -10,7 +11,7 @@ export function registerInjectionWidgets(entries: Entry[]) {
10
11
  if (_injectionWidgetEntries !== null && process.env.NODE_ENV === 'development') {
11
12
  console.debug('[Bootstrap] Injection widgets re-registered (this may occur during HMR)')
12
13
  }
13
- _injectionWidgetEntries = entries
14
+ _injectionWidgetEntries = applyInjectionWidgetOverridesToEntries(entries)
14
15
  }
15
16
 
16
17
  export function getInjectionWidgets(): Entry[] {
@@ -121,6 +121,78 @@ describe('MessageComposer draft flow', () => {
121
121
  expect(flash).toHaveBeenCalledWith('Draft saved.', 'success')
122
122
  })
123
123
 
124
+ it('sends an existing draft via PATCH with isDraft=false', async () => {
125
+ renderWithProviders(
126
+ <MessageComposer
127
+ inline
128
+ variant="compose"
129
+ messageId="draft-1"
130
+ defaultValues={{
131
+ recipients: ['11111111-1111-4111-8111-111111111111'],
132
+ subject: 'Existing draft',
133
+ body: 'Existing draft body',
134
+ }}
135
+ />,
136
+ { dict: {} },
137
+ )
138
+
139
+ fireEvent.click(await screen.findByRole('button', { name: 'Send' }))
140
+
141
+ await waitFor(() => {
142
+ expect(apiCall).toHaveBeenCalledWith(
143
+ '/api/messages/draft-1',
144
+ expect.objectContaining({
145
+ method: 'PATCH',
146
+ }),
147
+ )
148
+ })
149
+
150
+ const updateRequest = (apiCall as jest.Mock).mock.calls.find(
151
+ (call) => call[0] === '/api/messages/draft-1' && call[1]?.method === 'PATCH',
152
+ )
153
+ const payload = JSON.parse(updateRequest?.[1]?.body ?? '{}') as Record<string, unknown>
154
+ expect(payload.isDraft).toBe(false)
155
+ expect(payload.recipients).toEqual([{ userId: '11111111-1111-4111-8111-111111111111', type: 'to' }])
156
+ expect(flash).toHaveBeenCalledWith('Message sent.', 'success')
157
+ })
158
+
159
+ it('saves an existing draft via PATCH without a draft transition flag', async () => {
160
+ renderWithProviders(
161
+ <MessageComposer
162
+ inline
163
+ variant="compose"
164
+ messageId="draft-1"
165
+ defaultValues={{
166
+ subject: 'Existing draft',
167
+ body: 'Existing draft body',
168
+ }}
169
+ />,
170
+ { dict: {} },
171
+ )
172
+
173
+ fireEvent.click(await screen.findByRole('button', { name: 'Save draft' }))
174
+
175
+ await waitFor(() => {
176
+ expect(apiCall).toHaveBeenCalledWith(
177
+ '/api/messages/draft-1',
178
+ expect.objectContaining({
179
+ method: 'PATCH',
180
+ }),
181
+ )
182
+ })
183
+
184
+ const updateRequest = (apiCall as jest.Mock).mock.calls.find(
185
+ (call) => call[0] === '/api/messages/draft-1' && call[1]?.method === 'PATCH',
186
+ )
187
+ const payload = JSON.parse(updateRequest?.[1]?.body ?? '{}') as Record<string, unknown>
188
+ expect(payload).not.toHaveProperty('isDraft')
189
+ expect(payload).toEqual(expect.objectContaining({
190
+ subject: 'Existing draft',
191
+ body: 'Existing draft body',
192
+ }))
193
+ expect(flash).toHaveBeenCalledWith('Draft saved.', 'success')
194
+ })
195
+
124
196
  it('keeps the send action disabled after a successful compose submit until the composer resets', async () => {
125
197
  let resolveMessagePost!: (value: {
126
198
  ok: boolean
@@ -342,6 +414,11 @@ describe('MessageComposer draft flow', () => {
342
414
  await waitFor(() => {
343
415
  expect(apiCall).toHaveBeenCalledWith(
344
416
  expect.stringMatching(/^\/api\/auth\/users\?/),
417
+ expect.objectContaining({
418
+ headers: expect.objectContaining({
419
+ 'x-om-forbidden-redirect': '0',
420
+ }),
421
+ }),
345
422
  )
346
423
  })
347
424
  })
@@ -16,6 +16,8 @@ import {
16
16
  useComposeSendOperation,
17
17
  useForwardSubmitOperation,
18
18
  useReplySubmitOperation,
19
+ useSendDraftOperation,
20
+ useUpdateDraftOperation,
19
21
  } from './useMessageComposeOperations'
20
22
 
21
23
  function toErrorMessage(payload: unknown): string | null {
@@ -410,7 +412,17 @@ export function useMessageCompose({
410
412
  params.set('pageSize', '100')
411
413
  // Recipient lookup is filtered in TagsInput because incremental auth user search is unreliable.
412
414
 
413
- const call = await apiCall<{ items?: UserListItem[] }>(`/api/auth/users?${params.toString()}`)
415
+ const call = await apiCall<{ items?: UserListItem[] }>(
416
+ `/api/auth/users?${params.toString()}`,
417
+ {
418
+ headers: {
419
+ 'x-om-forbidden-redirect': '0',
420
+ },
421
+ },
422
+ ).catch(() => null)
423
+ if (!call) {
424
+ return []
425
+ }
414
426
  if (!call.ok) {
415
427
  return []
416
428
  }
@@ -477,6 +489,7 @@ export function useMessageCompose({
477
489
 
478
490
  const composeDraftOperation = useComposeDraftOperation({
479
491
  t,
492
+ messageId,
480
493
  messageType,
481
494
  priority,
482
495
  visibility,
@@ -514,16 +527,59 @@ export function useMessageCompose({
514
527
  sendViaEmail,
515
528
  })
516
529
 
530
+ const sendDraftOperation = useSendDraftOperation({
531
+ t,
532
+ messageId: messageId ?? '',
533
+ messageType,
534
+ priority,
535
+ visibility,
536
+ externalEmail,
537
+ recipientIds,
538
+ subject,
539
+ body,
540
+ bodyFormat,
541
+ sendViaEmail,
542
+ contextObject,
543
+ defaultValues,
544
+ contextActionOptions,
545
+ normalizedRequiredActionMode,
546
+ shouldShowContextActions,
547
+ contextActionRequired,
548
+ contextActionType,
549
+ })
550
+
551
+ const updateDraftOperation = useUpdateDraftOperation({
552
+ t,
553
+ messageId: messageId ?? '',
554
+ messageType,
555
+ priority,
556
+ visibility,
557
+ externalEmail,
558
+ recipientIds,
559
+ subject,
560
+ body,
561
+ bodyFormat,
562
+ sendViaEmail,
563
+ contextObject,
564
+ defaultValues,
565
+ contextActionOptions,
566
+ normalizedRequiredActionMode,
567
+ shouldShowContextActions,
568
+ contextActionRequired,
569
+ contextActionType,
570
+ })
571
+
517
572
  const handleSubmit = React.useCallback(async ({ saveAsDraft = false }: { saveAsDraft?: boolean } = {}) => {
518
573
  if (submitting) return false
519
574
 
520
575
  setSubmitError(null)
521
576
 
577
+ const isEditingExistingDraft = variant === 'compose' && Boolean(messageId)
522
578
  const isComposeDraftSubmit = saveAsDraft && variant === 'compose'
523
579
  const operation = isComposeDraftSubmit
524
- ? composeDraftOperation
580
+ ? (isEditingExistingDraft ? updateDraftOperation : composeDraftOperation)
525
581
  : variant === 'compose'
526
- ? composeSendOperation
582
+ ? (isEditingExistingDraft ? sendDraftOperation : composeSendOperation)
527
583
  : variant === 'reply'
528
584
  ? replyOperation
529
585
  : forwardOperation
@@ -556,10 +612,10 @@ export function useMessageCompose({
556
612
  }
557
613
 
558
614
  if (!shouldReturnFalse) {
559
- const { endpoint, payload } = operation.buildRequest({ attachmentIds: nextAttachmentIds })
615
+ const { endpoint, method, payload } = operation.buildRequest({ attachmentIds: nextAttachmentIds })
560
616
 
561
617
  const call = await apiCall<{ id?: string }>(endpoint, {
562
- method: 'POST',
618
+ method,
563
619
  headers: { 'Content-Type': 'application/json' },
564
620
  body: JSON.stringify(payload),
565
621
  })
@@ -612,11 +668,14 @@ export function useMessageCompose({
612
668
  forwardOperation,
613
669
  inline,
614
670
  loadAttachmentIds,
671
+ messageId,
615
672
  onOpenChange,
616
673
  onSuccess,
617
674
  replyOperation,
675
+ sendDraftOperation,
618
676
  submitting,
619
677
  t,
678
+ updateDraftOperation,
620
679
  variant,
621
680
  ])
622
681
 
@@ -16,6 +16,7 @@ type MessageRecipient = {
16
16
 
17
17
  type SubmitRequest = {
18
18
  endpoint: string
19
+ method: 'POST' | 'PATCH'
19
20
  payload: Record<string, unknown>
20
21
  }
21
22
 
@@ -67,6 +68,7 @@ type ForwardOperationParams = {
67
68
  }
68
69
 
69
70
  type DraftOperationParams = Omit<ComposeOperationParams, 'createableMessageTypes'>
71
+ & { messageId?: string }
70
72
 
71
73
  function isValidEmailAddress(value: string): boolean {
72
74
  const email = value.trim()
@@ -182,6 +184,7 @@ export function useComposeSendOperation(params: ComposeOperationParams): BaseOpe
182
184
  },
183
185
  buildRequest: ({ attachmentIds }) => ({
184
186
  endpoint: '/api/messages',
187
+ method: 'POST',
185
188
  payload: buildComposePayload(params, { attachmentIds, isDraft: false }),
186
189
  }),
187
190
  successMessage: params.t('messages.flash.sentSuccess', 'Message sent.'),
@@ -192,10 +195,24 @@ export function useComposeSendOperation(params: ComposeOperationParams): BaseOpe
192
195
  export function useComposeDraftOperation(params: DraftOperationParams): BaseOperation {
193
196
  return React.useMemo(() => ({
194
197
  validate: () => null,
195
- buildRequest: ({ attachmentIds }) => ({
196
- endpoint: '/api/messages',
197
- payload: buildComposePayload(params, { attachmentIds, isDraft: true }),
198
- }),
198
+ buildRequest: ({ attachmentIds }) => {
199
+ const payload = buildComposePayload(params, { attachmentIds, isDraft: true })
200
+ if (!params.messageId) {
201
+ return {
202
+ endpoint: '/api/messages',
203
+ method: 'POST',
204
+ payload,
205
+ }
206
+ }
207
+
208
+ const draftUpdatePayload = { ...payload }
209
+ delete draftUpdatePayload.isDraft
210
+ return {
211
+ endpoint: `/api/messages/${encodeURIComponent(params.messageId)}`,
212
+ method: 'PATCH',
213
+ payload: draftUpdatePayload,
214
+ }
215
+ },
199
216
  successMessage: params.t('messages.flash.draftSaved', 'Draft saved.'),
200
217
  requiresAttachmentRefresh: true,
201
218
  }), [params])
@@ -214,6 +231,7 @@ export function useReplySubmitOperation(params: ReplyOperationParams): BaseOpera
214
231
  },
215
232
  buildRequest: ({ attachmentIds }) => ({
216
233
  endpoint: `/api/messages/${encodeURIComponent(params.messageId ?? '')}/reply`,
234
+ method: 'POST',
217
235
  payload: {
218
236
  body: params.body,
219
237
  bodyFormat: params.bodyFormat,
@@ -244,6 +262,7 @@ export function useForwardSubmitOperation(params: ForwardOperationParams): BaseO
244
262
  },
245
263
  buildRequest: () => ({
246
264
  endpoint: `/api/messages/${encodeURIComponent(params.messageId ?? '')}/forward`,
265
+ method: 'POST',
247
266
  payload: {
248
267
  recipients: mapRecipients(params.recipientIds),
249
268
  body: params.body,
@@ -256,4 +275,51 @@ export function useForwardSubmitOperation(params: ForwardOperationParams): BaseO
256
275
  }), [params])
257
276
  }
258
277
 
278
+ type SendDraftOperationParams = DraftOperationParams & { messageId: string }
279
+
280
+ export function useSendDraftOperation(params: SendDraftOperationParams): BaseOperation {
281
+ return React.useMemo(() => ({
282
+ validate: () => {
283
+ if (params.visibility !== 'public' && params.recipientIds.length === 0) {
284
+ return params.t('messages.errors.noRecipients', 'Please add at least one recipient.')
285
+ }
286
+ if (params.visibility === 'public' && !isValidEmailAddress(params.externalEmail.trim())) {
287
+ return params.t('messages.errors.noExternalEmail', 'Please enter a valid external email.')
288
+ }
289
+ if (!params.subject.trim()) {
290
+ return params.t('messages.errors.noSubject', 'Please enter a subject.')
291
+ }
292
+ if (!params.body.trim()) {
293
+ return params.t('messages.errors.noBody', 'Please enter a message.')
294
+ }
295
+ return null
296
+ },
297
+ buildRequest: ({ attachmentIds }) => ({
298
+ endpoint: `/api/messages/${encodeURIComponent(params.messageId)}`,
299
+ method: 'PATCH' as const,
300
+ payload: buildComposePayload(params, { attachmentIds, isDraft: false }),
301
+ }),
302
+ successMessage: params.t('messages.flash.sentSuccess', 'Message sent.'),
303
+ requiresAttachmentRefresh: true,
304
+ }), [params])
305
+ }
306
+
307
+ type UpdateDraftOperationParams = DraftOperationParams & { messageId: string }
308
+
309
+ export function useUpdateDraftOperation(params: UpdateDraftOperationParams): BaseOperation {
310
+ return React.useMemo(() => ({
311
+ validate: () => null,
312
+ buildRequest: ({ attachmentIds }) => {
313
+ const { isDraft: _omit, ...payload } = buildComposePayload(params, { attachmentIds, isDraft: true })
314
+ return {
315
+ endpoint: `/api/messages/${encodeURIComponent(params.messageId)}`,
316
+ method: 'PATCH' as const,
317
+ payload,
318
+ }
319
+ },
320
+ successMessage: params.t('messages.flash.draftSaved', 'Draft saved.'),
321
+ requiresAttachmentRefresh: true,
322
+ }), [params])
323
+ }
324
+
259
325
  export type MessageComposeSubmitOperation = BaseOperation
@@ -2,7 +2,17 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { Calendar, dateFnsLocalizer, type View, type SlotInfo } from 'react-big-calendar'
5
- import { addDays, differenceInCalendarDays, endOfDay, endOfMonth, endOfWeek, format, getDay, parse, startOfDay, startOfMonth, startOfWeek } from 'date-fns'
5
+ import { addDays } from 'date-fns/addDays'
6
+ import { differenceInCalendarDays } from 'date-fns/differenceInCalendarDays'
7
+ import { endOfDay } from 'date-fns/endOfDay'
8
+ import { endOfMonth } from 'date-fns/endOfMonth'
9
+ import { endOfWeek } from 'date-fns/endOfWeek'
10
+ import { format } from 'date-fns/format'
11
+ import { getDay } from 'date-fns/getDay'
12
+ import { parse } from 'date-fns/parse'
13
+ import { startOfDay } from 'date-fns/startOfDay'
14
+ import { startOfMonth } from 'date-fns/startOfMonth'
15
+ import { startOfWeek } from 'date-fns/startOfWeek'
6
16
  import { enUS } from 'date-fns/locale/en-US'
7
17
  import type { ScheduleItem, ScheduleRange, ScheduleSlot, ScheduleViewMode } from './types'
8
18
  import { Button } from '../../primitives/button'
@@ -6,7 +6,17 @@ import { Input } from '../../primitives/input'
6
6
  import type { ScheduleRange, ScheduleViewMode } from './types'
7
7
  import { cn } from '@open-mercato/shared/lib/utils'
8
8
  import { useT } from '@open-mercato/shared/lib/i18n/context'
9
- import { addDays, addMonths, addWeeks, differenceInCalendarDays, endOfDay, endOfMonth, endOfWeek, format, startOfDay, startOfMonth, startOfWeek } from 'date-fns'
9
+ import { addDays } from 'date-fns/addDays'
10
+ import { addMonths } from 'date-fns/addMonths'
11
+ import { addWeeks } from 'date-fns/addWeeks'
12
+ import { differenceInCalendarDays } from 'date-fns/differenceInCalendarDays'
13
+ import { endOfDay } from 'date-fns/endOfDay'
14
+ import { endOfMonth } from 'date-fns/endOfMonth'
15
+ import { endOfWeek } from 'date-fns/endOfWeek'
16
+ import { format } from 'date-fns/format'
17
+ import { startOfDay } from 'date-fns/startOfDay'
18
+ import { startOfMonth } from 'date-fns/startOfMonth'
19
+ import { startOfWeek } from 'date-fns/startOfWeek'
10
20
  import { enUS } from 'date-fns/locale/en-US'
11
21
  import { ChevronLeft, ChevronRight } from 'lucide-react'
12
22
 
@@ -4,8 +4,8 @@ import * as React from 'react'
4
4
  import { DayPicker, useDayPicker } from 'react-day-picker'
5
5
  import type { DayPickerProps, CalendarMonth } from 'react-day-picker'
6
6
  import { ChevronLeft, ChevronRight } from 'lucide-react'
7
- import { format } from 'date-fns'
8
- import type { Locale } from 'date-fns'
7
+ import { format } from 'date-fns/format'
8
+ import type { Locale } from 'date-fns/locale'
9
9
  import { cn } from '@open-mercato/shared/lib/utils'
10
10
 
11
11
  export type CalendarProps = DayPickerProps
@@ -1,5 +1,5 @@
1
- import { format as formatDateFns } from 'date-fns'
2
- import type { Locale } from 'date-fns'
1
+ import { format as formatDateFns } from 'date-fns/format'
2
+ import type { Locale } from 'date-fns/locale'
3
3
 
4
4
  type LocaleLike = Locale | string | null | undefined
5
5
 
@@ -1,12 +1,10 @@
1
- import {
2
- startOfDay,
3
- endOfDay,
4
- startOfMonth,
5
- startOfYear,
6
- subDays,
7
- subMonths,
8
- subYears,
9
- } from 'date-fns'
1
+ import { endOfDay } from 'date-fns/endOfDay'
2
+ import { startOfDay } from 'date-fns/startOfDay'
3
+ import { startOfMonth } from 'date-fns/startOfMonth'
4
+ import { startOfYear } from 'date-fns/startOfYear'
5
+ import { subDays } from 'date-fns/subDays'
6
+ import { subMonths } from 'date-fns/subMonths'
7
+ import { subYears } from 'date-fns/subYears'
10
8
  import type { DateRange } from '../backend/date-range/dateRanges'
11
9
 
12
10
  export type DateRangePresetItem = {
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
- import type { Locale } from 'date-fns'
4
+ import type { Locale } from 'date-fns/locale'
5
5
  import { CalendarIcon } from 'lucide-react'
6
6
  import { cn } from '@open-mercato/shared/lib/utils'
7
7
  import { useT } from '@open-mercato/shared/lib/i18n/context'
@@ -233,7 +233,7 @@ export function DatePicker({
233
233
  onSelect={handleDaySelect}
234
234
  locale={locale}
235
235
  disabled={disabledMatcher}
236
- initialFocus
236
+ autoFocus
237
237
  />
238
238
  {withTime && (
239
239
  <div className="flex items-center gap-2 border-t px-3 py-2">
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
- import type { Locale } from 'date-fns'
4
+ import type { Locale } from 'date-fns/locale'
5
5
  import { CalendarIcon } from 'lucide-react'
6
6
  import { cn } from '@open-mercato/shared/lib/utils'
7
7
  import { useT } from '@open-mercato/shared/lib/i18n/context'
@@ -244,7 +244,7 @@ export function DateRangePicker({
244
244
  locale={locale}
245
245
  disabled={disabledMatcher}
246
246
  numberOfMonths={numberOfMonths}
247
- initialFocus
247
+ autoFocus
248
248
  />
249
249
  </div>
250
250
  </div>