payload-reserve 1.0.2 → 1.1.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 (81) hide show
  1. package/README.md +61 -1141
  2. package/dist/collections/Customers.d.ts +3 -0
  3. package/dist/collections/Customers.js +58 -0
  4. package/dist/collections/Customers.js.map +1 -0
  5. package/dist/collections/Reservations.js +129 -35
  6. package/dist/collections/Reservations.js.map +1 -1
  7. package/dist/collections/Resources.js +70 -2
  8. package/dist/collections/Resources.js.map +1 -1
  9. package/dist/collections/Schedules.js +4 -1
  10. package/dist/collections/Schedules.js.map +1 -1
  11. package/dist/collections/Services.js +59 -2
  12. package/dist/collections/Services.js.map +1 -1
  13. package/dist/components/AvailabilityOverview/AvailabilityOverview.module.css +31 -0
  14. package/dist/components/AvailabilityOverview/index.js +59 -8
  15. package/dist/components/AvailabilityOverview/index.js.map +1 -1
  16. package/dist/components/CalendarView/CalendarView.module.css +171 -0
  17. package/dist/components/CalendarView/index.js +547 -38
  18. package/dist/components/CalendarView/index.js.map +1 -1
  19. package/dist/components/CustomerField/index.js +24 -10
  20. package/dist/components/CustomerField/index.js.map +1 -1
  21. package/dist/components/DashboardWidget/DashboardWidgetServer.js +21 -11
  22. package/dist/components/DashboardWidget/DashboardWidgetServer.js.map +1 -1
  23. package/dist/defaults.d.ts +1 -2
  24. package/dist/defaults.js +22 -4
  25. package/dist/defaults.js.map +1 -1
  26. package/dist/endpoints/cancelBooking.d.ts +3 -0
  27. package/dist/endpoints/cancelBooking.js +37 -0
  28. package/dist/endpoints/cancelBooking.js.map +1 -0
  29. package/dist/endpoints/checkAvailability.d.ts +3 -0
  30. package/dist/endpoints/checkAvailability.js +37 -0
  31. package/dist/endpoints/checkAvailability.js.map +1 -0
  32. package/dist/endpoints/createBooking.d.ts +3 -0
  33. package/dist/endpoints/createBooking.js +32 -0
  34. package/dist/endpoints/createBooking.js.map +1 -0
  35. package/dist/endpoints/customerSearch.js +76 -58
  36. package/dist/endpoints/customerSearch.js.map +1 -1
  37. package/dist/endpoints/getSlots.d.ts +3 -0
  38. package/dist/endpoints/getSlots.js +51 -0
  39. package/dist/endpoints/getSlots.js.map +1 -0
  40. package/dist/hooks/index.d.ts +2 -0
  41. package/dist/hooks/index.js +2 -0
  42. package/dist/hooks/index.js.map +1 -1
  43. package/dist/hooks/reservations/calculateEndTime.js +75 -9
  44. package/dist/hooks/reservations/calculateEndTime.js.map +1 -1
  45. package/dist/hooks/reservations/checkIdempotency.d.ts +3 -0
  46. package/dist/hooks/reservations/checkIdempotency.js +32 -0
  47. package/dist/hooks/reservations/checkIdempotency.js.map +1 -0
  48. package/dist/hooks/reservations/onStatusChange.d.ts +3 -0
  49. package/dist/hooks/reservations/onStatusChange.js +41 -0
  50. package/dist/hooks/reservations/onStatusChange.js.map +1 -0
  51. package/dist/hooks/reservations/validateCancellation.js +1 -1
  52. package/dist/hooks/reservations/validateCancellation.js.map +1 -1
  53. package/dist/hooks/reservations/validateConflicts.js +34 -56
  54. package/dist/hooks/reservations/validateConflicts.js.map +1 -1
  55. package/dist/hooks/reservations/validateStatusTransition.d.ts +2 -1
  56. package/dist/hooks/reservations/validateStatusTransition.js +29 -6
  57. package/dist/hooks/reservations/validateStatusTransition.js.map +1 -1
  58. package/dist/index.d.ts +5 -1
  59. package/dist/index.js +3 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/plugin.js +49 -54
  62. package/dist/plugin.js.map +1 -1
  63. package/dist/services/AvailabilityService.d.ts +57 -0
  64. package/dist/services/AvailabilityService.js +232 -0
  65. package/dist/services/AvailabilityService.js.map +1 -0
  66. package/dist/services/index.d.ts +1 -0
  67. package/dist/services/index.js +3 -0
  68. package/dist/services/index.js.map +1 -0
  69. package/dist/translations/en.json +33 -1
  70. package/dist/translations/index.d.ts +5 -0
  71. package/dist/translations/index.js.map +1 -1
  72. package/dist/types.d.ts +84 -6
  73. package/dist/types.js +29 -9
  74. package/dist/types.js.map +1 -1
  75. package/dist/utilities/ownerAccess.d.ts +24 -0
  76. package/dist/utilities/ownerAccess.js +128 -0
  77. package/dist/utilities/ownerAccess.js.map +1 -0
  78. package/dist/utilities/resolveReservationItems.d.ts +18 -0
  79. package/dist/utilities/resolveReservationItems.js +45 -0
  80. package/dist/utilities/resolveReservationItems.js.map +1 -0
  81. package/package.json +12 -9
@@ -0,0 +1,3 @@
1
+ import type { CollectionConfig } from 'payload';
2
+ import type { ResolvedReservationPluginConfig } from '../types.js';
3
+ export declare function createCustomersCollection(config: ResolvedReservationPluginConfig): CollectionConfig;
@@ -0,0 +1,58 @@
1
+ export function createCustomersCollection(config) {
2
+ return {
3
+ slug: config.slugs.customers,
4
+ access: {
5
+ admin: ()=>false,
6
+ ...config.access.customers
7
+ },
8
+ admin: {
9
+ group: config.adminGroup,
10
+ listSearchableFields: [
11
+ 'firstName',
12
+ 'lastName',
13
+ 'phone',
14
+ 'email'
15
+ ],
16
+ useAsTitle: 'firstName'
17
+ },
18
+ auth: true,
19
+ fields: [
20
+ {
21
+ name: 'firstName',
22
+ type: 'text',
23
+ label: ({ t })=>t('reservation:fieldFirstName'),
24
+ maxLength: 200,
25
+ required: true
26
+ },
27
+ {
28
+ name: 'lastName',
29
+ type: 'text',
30
+ label: ({ t })=>t('reservation:fieldLastName'),
31
+ maxLength: 200,
32
+ required: true
33
+ },
34
+ {
35
+ name: 'phone',
36
+ type: 'text',
37
+ maxLength: 50
38
+ },
39
+ {
40
+ name: 'notes',
41
+ type: 'textarea',
42
+ label: ({ t })=>t('reservation:fieldNotes')
43
+ },
44
+ {
45
+ name: 'bookings',
46
+ type: 'join',
47
+ collection: config.slugs.reservations,
48
+ on: 'customer'
49
+ }
50
+ ],
51
+ labels: {
52
+ plural: ({ t })=>t('reservation:collectionCustomers'),
53
+ singular: ({ t })=>t('reservation:collectionCustomer')
54
+ }
55
+ };
56
+ }
57
+
58
+ //# sourceMappingURL=Customers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/collections/Customers.ts"],"sourcesContent":["import type { CollectionConfig, CollectionSlug } from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nexport function createCustomersCollection(\n config: ResolvedReservationPluginConfig,\n): CollectionConfig {\n return {\n slug: config.slugs.customers,\n access: {\n admin: () => false,\n ...config.access.customers,\n },\n admin: {\n group: config.adminGroup,\n listSearchableFields: ['firstName', 'lastName', 'phone', 'email'],\n useAsTitle: 'firstName',\n },\n auth: true,\n fields: [\n {\n name: 'firstName',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldFirstName'),\n maxLength: 200,\n required: true,\n },\n {\n name: 'lastName',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldLastName'),\n maxLength: 200,\n required: true,\n },\n {\n name: 'phone',\n type: 'text',\n maxLength: 50,\n },\n {\n name: 'notes',\n type: 'textarea',\n label: ({ t }) => (t as PluginT)('reservation:fieldNotes'),\n },\n {\n name: 'bookings',\n type: 'join',\n collection: config.slugs.reservations as unknown as CollectionSlug,\n on: 'customer',\n },\n ],\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionCustomers'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionCustomer'),\n },\n }\n}\n"],"names":["createCustomersCollection","config","slug","slugs","customers","access","admin","group","adminGroup","listSearchableFields","useAsTitle","auth","fields","name","type","label","t","maxLength","required","collection","reservations","on","labels","plural","singular"],"mappings":"AAKA,OAAO,SAASA,0BACdC,MAAuC;IAEvC,OAAO;QACLC,MAAMD,OAAOE,KAAK,CAACC,SAAS;QAC5BC,QAAQ;YACNC,OAAO,IAAM;YACb,GAAGL,OAAOI,MAAM,CAACD,SAAS;QAC5B;QACAE,OAAO;YACLC,OAAON,OAAOO,UAAU;YACxBC,sBAAsB;gBAAC;gBAAa;gBAAY;gBAAS;aAAQ;YACjEC,YAAY;QACd;QACAC,MAAM;QACNC,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjCC,WAAW;gBACXC,UAAU;YACZ;YACA;gBACEL,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjCC,WAAW;gBACXC,UAAU;YACZ;YACA;gBACEL,MAAM;gBACNC,MAAM;gBACNG,WAAW;YACb;YACA;gBACEJ,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;YACnC;YACA;gBACEH,MAAM;gBACNC,MAAM;gBACNK,YAAYlB,OAAOE,KAAK,CAACiB,YAAY;gBACrCC,IAAI;YACN;SACD;QACDC,QAAQ;YACNC,QAAQ,CAAC,EAAEP,CAAC,EAAE,GAAK,AAACA,EAAc;YAClCQ,UAAU,CAAC,EAAER,CAAC,EAAE,GAAK,AAACA,EAAc;QACtC;IACF;AACF"}
@@ -1,11 +1,52 @@
1
1
  import { calculateEndTime } from '../hooks/reservations/calculateEndTime.js';
2
+ import { checkIdempotency } from '../hooks/reservations/checkIdempotency.js';
3
+ import { onStatusChange } from '../hooks/reservations/onStatusChange.js';
2
4
  import { validateCancellation } from '../hooks/reservations/validateCancellation.js';
3
5
  import { validateConflicts } from '../hooks/reservations/validateConflicts.js';
4
6
  import { validateStatusTransition } from '../hooks/reservations/validateStatusTransition.js';
7
+ import { makeReservationOwnerAccess } from '../utilities/ownerAccess.js';
8
+ function createPluginHooksBeforeCreate(hooks) {
9
+ return async ({ context, data, operation, req })=>{
10
+ if (context?.skipReservationHooks) {
11
+ return data;
12
+ }
13
+ if (operation === 'create' && hooks.beforeBookingCreate) {
14
+ let mutatedData = data;
15
+ for (const hook of hooks.beforeBookingCreate){
16
+ const result = await hook({
17
+ data: mutatedData,
18
+ req
19
+ });
20
+ if (result) {
21
+ mutatedData = result;
22
+ }
23
+ }
24
+ return mutatedData;
25
+ }
26
+ return data;
27
+ };
28
+ }
29
+ function createPluginHooksAfterCreate(hooks) {
30
+ return async ({ doc, operation, req })=>{
31
+ if (operation === 'create' && hooks.afterBookingCreate) {
32
+ const docRecord = doc;
33
+ for (const hook of hooks.afterBookingCreate){
34
+ await hook({
35
+ doc: docRecord,
36
+ req
37
+ });
38
+ }
39
+ }
40
+ return doc;
41
+ };
42
+ }
5
43
  export function createReservationsCollection(config) {
44
+ const { statusMachine } = config;
45
+ const rom = config.resourceOwnerMode;
46
+ const access = config.access.reservations ?? (rom ? makeReservationOwnerAccess(rom) : {});
6
47
  return {
7
48
  slug: config.slugs.reservations,
8
- access: config.access.reservations ?? {},
49
+ access,
9
50
  admin: {
10
51
  components: {
11
52
  views: {
@@ -38,23 +79,16 @@ export function createReservationsCollection(config) {
38
79
  {
39
80
  name: 'customer',
40
81
  type: 'relationship',
41
- label: ({ t })=>t('reservation:fieldCustomer'),
42
- relationTo: config.userCollection,
43
- required: true,
44
- ...config.customerRole ? {
45
- filterOptions: ()=>({
46
- role: {
47
- equals: config.customerRole
48
- }
49
- })
50
- } : {},
51
82
  admin: {
52
83
  allowCreate: true,
53
84
  allowEdit: true,
54
85
  components: {
55
86
  Field: 'payload-reserve/client#CustomerField'
56
87
  }
57
- }
88
+ },
89
+ label: ({ t })=>t('reservation:fieldCustomer'),
90
+ relationTo: config.slugs.customers,
91
+ required: true
58
92
  },
59
93
  {
60
94
  name: 'startTime',
@@ -81,50 +115,110 @@ export function createReservationsCollection(config) {
81
115
  {
82
116
  name: 'status',
83
117
  type: 'select',
84
- defaultValue: 'pending',
118
+ defaultValue: statusMachine.defaultStatus,
85
119
  label: ({ t })=>t('reservation:fieldStatus'),
86
- options: [
120
+ options: statusMachine.statuses.map((s)=>({
121
+ label: ({ t })=>{
122
+ const key = `reservation:status${s.charAt(0).toUpperCase() + s.slice(1)}`;
123
+ const translated = t(key);
124
+ return translated !== key ? translated : s.charAt(0).toUpperCase() + s.slice(1);
125
+ },
126
+ value: s
127
+ }))
128
+ },
129
+ {
130
+ name: 'cancellationReason',
131
+ type: 'textarea',
132
+ admin: {
133
+ condition: (_, siblingData)=>siblingData?.status === 'cancelled'
134
+ },
135
+ label: ({ t })=>t('reservation:fieldCancellationReason')
136
+ },
137
+ {
138
+ name: 'guestCount',
139
+ type: 'number',
140
+ defaultValue: 1,
141
+ label: ({ t })=>t('reservation:fieldGuestCount'),
142
+ min: 1
143
+ },
144
+ {
145
+ name: 'notes',
146
+ type: 'textarea',
147
+ label: ({ t })=>t('reservation:fieldNotes')
148
+ },
149
+ {
150
+ name: 'items',
151
+ type: 'array',
152
+ admin: {
153
+ description: 'Resources included in this booking. Leave empty for single-resource bookings.'
154
+ },
155
+ fields: [
87
156
  {
88
- label: ({ t })=>t('reservation:statusPending'),
89
- value: 'pending'
157
+ name: 'resource',
158
+ type: 'relationship',
159
+ label: ({ t })=>t('reservation:fieldResource'),
160
+ relationTo: config.slugs.resources,
161
+ required: true
90
162
  },
91
163
  {
92
- label: ({ t })=>t('reservation:statusConfirmed'),
93
- value: 'confirmed'
164
+ name: 'service',
165
+ type: 'relationship',
166
+ label: ({ t })=>t('reservation:fieldService'),
167
+ relationTo: config.slugs.services
94
168
  },
95
169
  {
96
- label: ({ t })=>t('reservation:statusCompleted'),
97
- value: 'completed'
170
+ name: 'startTime',
171
+ type: 'date',
172
+ admin: {
173
+ date: {
174
+ pickerAppearance: 'dayAndTime'
175
+ }
176
+ },
177
+ label: ({ t })=>t('reservation:fieldStartTime')
98
178
  },
99
179
  {
100
- label: ({ t })=>t('reservation:statusCancelled'),
101
- value: 'cancelled'
180
+ name: 'endTime',
181
+ type: 'date',
182
+ admin: {
183
+ date: {
184
+ pickerAppearance: 'dayAndTime'
185
+ },
186
+ readOnly: false
187
+ },
188
+ label: ({ t })=>t('reservation:fieldEndTime')
102
189
  },
103
190
  {
104
- label: ({ t })=>t('reservation:statusNoShow'),
105
- value: 'no-show'
191
+ name: 'guestCount',
192
+ type: 'number',
193
+ label: ({ t })=>t('reservation:fieldGuestCount'),
194
+ min: 1
106
195
  }
107
- ]
196
+ ],
197
+ label: ({ t })=>t('reservation:fieldItems')
108
198
  },
109
199
  {
110
- name: 'cancellationReason',
111
- type: 'textarea',
200
+ name: 'idempotencyKey',
201
+ type: 'text',
112
202
  admin: {
113
- condition: (_, siblingData)=>siblingData?.status === 'cancelled'
203
+ position: 'sidebar',
204
+ readOnly: true
114
205
  },
115
- label: ({ t })=>t('reservation:fieldCancellationReason')
206
+ index: true,
207
+ unique: true
116
208
  },
117
- {
118
- name: 'notes',
119
- type: 'textarea',
120
- label: ({ t })=>t('reservation:fieldNotes')
121
- }
209
+ ...config.extraReservationFields
122
210
  ],
123
211
  hooks: {
212
+ afterChange: [
213
+ createPluginHooksAfterCreate(config.hooks),
214
+ onStatusChange(config)
215
+ ],
124
216
  beforeChange: [
217
+ createPluginHooksBeforeCreate(config.hooks),
218
+ checkIdempotency(config),
125
219
  calculateEndTime(config),
126
220
  validateConflicts(config),
127
- validateStatusTransition(),
221
+ validateStatusTransition(config),
128
222
  validateCancellation(config)
129
223
  ]
130
224
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/collections/Reservations.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nimport { calculateEndTime } from '../hooks/reservations/calculateEndTime.js'\nimport { validateCancellation } from '../hooks/reservations/validateCancellation.js'\nimport { validateConflicts } from '../hooks/reservations/validateConflicts.js'\nimport { validateStatusTransition } from '../hooks/reservations/validateStatusTransition.js'\n\nexport function createReservationsCollection(\n config: ResolvedReservationPluginConfig,\n): CollectionConfig {\n return {\n slug: config.slugs.reservations,\n access: config.access.reservations ?? {},\n admin: {\n components: {\n views: {\n list: {\n Component: 'payload-reserve/client#CalendarView',\n },\n },\n },\n group: config.adminGroup,\n listSearchableFields: ['status'],\n useAsTitle: 'startTime',\n },\n fields: [\n {\n name: 'service',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldService'),\n relationTo: config.slugs.services,\n required: true,\n },\n {\n name: 'resource',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldResource'),\n relationTo: config.slugs.resources,\n required: true,\n },\n {\n name: 'customer',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldCustomer'),\n relationTo: config.userCollection,\n required: true,\n ...(config.customerRole\n ? { filterOptions: () => ({ role: { equals: config.customerRole } }) }\n : {}),\n admin: {\n allowCreate: true,\n allowEdit: true,\n components: {\n Field: 'payload-reserve/client#CustomerField',\n },\n },\n },\n {\n name: 'startTime',\n type: 'date',\n admin: {\n date: {\n pickerAppearance: 'dayAndTime',\n },\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldStartTime'),\n required: true,\n },\n {\n name: 'endTime',\n type: 'date',\n admin: {\n date: {\n pickerAppearance: 'dayAndTime',\n },\n readOnly: true,\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldEndTime'),\n },\n {\n name: 'status',\n type: 'select',\n defaultValue: 'pending',\n label: ({ t }) => (t as PluginT)('reservation:fieldStatus'),\n options: [\n { label: ({ t }) => (t as PluginT)('reservation:statusPending'), value: 'pending' },\n { label: ({ t }) => (t as PluginT)('reservation:statusConfirmed'), value: 'confirmed' },\n { label: ({ t }) => (t as PluginT)('reservation:statusCompleted'), value: 'completed' },\n { label: ({ t }) => (t as PluginT)('reservation:statusCancelled'), value: 'cancelled' },\n { label: ({ t }) => (t as PluginT)('reservation:statusNoShow'), value: 'no-show' },\n ],\n },\n {\n name: 'cancellationReason',\n type: 'textarea',\n admin: {\n condition: (_, siblingData) => siblingData?.status === 'cancelled',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldCancellationReason'),\n },\n {\n name: 'notes',\n type: 'textarea',\n label: ({ t }) => (t as PluginT)('reservation:fieldNotes'),\n },\n ],\n hooks: {\n beforeChange: [\n calculateEndTime(config),\n validateConflicts(config),\n validateStatusTransition(),\n validateCancellation(config),\n ],\n },\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionReservations'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionReservations'),\n },\n }\n}\n"],"names":["calculateEndTime","validateCancellation","validateConflicts","validateStatusTransition","createReservationsCollection","config","slug","slugs","reservations","access","admin","components","views","list","Component","group","adminGroup","listSearchableFields","useAsTitle","fields","name","type","label","t","relationTo","services","required","resources","userCollection","customerRole","filterOptions","role","equals","allowCreate","allowEdit","Field","date","pickerAppearance","readOnly","defaultValue","options","value","condition","_","siblingData","status","hooks","beforeChange","labels","plural","singular"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/collections/Reservations.ts"],"sourcesContent":["import type {\n CollectionAfterChangeHook,\n CollectionBeforeChangeHook,\n CollectionConfig,\n CollectionSlug,\n} from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ReservationPluginHooks, ResolvedReservationPluginConfig } from '../types.js'\n\nimport { calculateEndTime } from '../hooks/reservations/calculateEndTime.js'\nimport { checkIdempotency } from '../hooks/reservations/checkIdempotency.js'\nimport { onStatusChange } from '../hooks/reservations/onStatusChange.js'\nimport { validateCancellation } from '../hooks/reservations/validateCancellation.js'\nimport { validateConflicts } from '../hooks/reservations/validateConflicts.js'\nimport { validateStatusTransition } from '../hooks/reservations/validateStatusTransition.js'\nimport { makeReservationOwnerAccess } from '../utilities/ownerAccess.js'\n\nfunction createPluginHooksBeforeCreate(\n hooks: ReservationPluginHooks,\n): CollectionBeforeChangeHook {\n return async ({ context, data, operation, req }) => {\n if (context?.skipReservationHooks) {return data}\n\n if (operation === 'create' && hooks.beforeBookingCreate) {\n let mutatedData = data\n for (const hook of hooks.beforeBookingCreate) {\n const result = await hook({ data: mutatedData, req })\n if (result) {mutatedData = result}\n }\n return mutatedData\n }\n\n return data\n }\n}\n\nfunction createPluginHooksAfterCreate(\n hooks: ReservationPluginHooks,\n): CollectionAfterChangeHook {\n return async ({ doc, operation, req }) => {\n if (operation === 'create' && hooks.afterBookingCreate) {\n const docRecord = doc as Record<string, unknown>\n for (const hook of hooks.afterBookingCreate) {\n await hook({ doc: docRecord, req })\n }\n }\n return doc\n }\n}\n\nexport function createReservationsCollection(\n config: ResolvedReservationPluginConfig,\n): CollectionConfig {\n const { statusMachine } = config\n const rom = config.resourceOwnerMode\n const access =\n config.access.reservations ?? (rom ? makeReservationOwnerAccess(rom) : {})\n\n return {\n slug: config.slugs.reservations,\n access,\n admin: {\n components: {\n views: {\n list: {\n Component: 'payload-reserve/client#CalendarView',\n },\n },\n },\n group: config.adminGroup,\n listSearchableFields: ['status'],\n useAsTitle: 'startTime',\n },\n fields: [\n {\n name: 'service',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldService'),\n relationTo: config.slugs.services as unknown as CollectionSlug,\n required: true,\n },\n {\n name: 'resource',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldResource'),\n relationTo: config.slugs.resources as unknown as CollectionSlug,\n required: true,\n },\n {\n name: 'customer',\n type: 'relationship',\n admin: {\n allowCreate: true,\n allowEdit: true,\n components: {\n Field: 'payload-reserve/client#CustomerField',\n },\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldCustomer'),\n relationTo: config.slugs.customers as unknown as CollectionSlug,\n required: true,\n },\n {\n name: 'startTime',\n type: 'date',\n admin: {\n date: {\n pickerAppearance: 'dayAndTime',\n },\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldStartTime'),\n required: true,\n },\n {\n name: 'endTime',\n type: 'date',\n admin: {\n date: {\n pickerAppearance: 'dayAndTime',\n },\n readOnly: true,\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldEndTime'),\n },\n {\n name: 'status',\n type: 'select',\n defaultValue: statusMachine.defaultStatus,\n label: ({ t }) => (t as PluginT)('reservation:fieldStatus'),\n options: statusMachine.statuses.map((s) => ({\n label: ({ t }) => {\n const key = `reservation:status${s.charAt(0).toUpperCase() + s.slice(1)}`\n const translated = (t as PluginT)(key)\n return translated !== key ? translated : s.charAt(0).toUpperCase() + s.slice(1)\n },\n value: s,\n })),\n },\n {\n name: 'cancellationReason',\n type: 'textarea',\n admin: {\n condition: (_, siblingData) => siblingData?.status === 'cancelled',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldCancellationReason'),\n },\n {\n name: 'guestCount',\n type: 'number',\n defaultValue: 1,\n label: ({ t }) => (t as PluginT)('reservation:fieldGuestCount'),\n min: 1,\n },\n {\n name: 'notes',\n type: 'textarea',\n label: ({ t }) => (t as PluginT)('reservation:fieldNotes'),\n },\n {\n name: 'items',\n type: 'array',\n admin: {\n description: 'Resources included in this booking. Leave empty for single-resource bookings.',\n },\n fields: [\n {\n name: 'resource',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldResource'),\n relationTo: config.slugs.resources as unknown as CollectionSlug,\n required: true,\n },\n {\n name: 'service',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldService'),\n relationTo: config.slugs.services as unknown as CollectionSlug,\n },\n {\n name: 'startTime',\n type: 'date',\n admin: { date: { pickerAppearance: 'dayAndTime' } },\n label: ({ t }) => (t as PluginT)('reservation:fieldStartTime'),\n },\n {\n name: 'endTime',\n type: 'date',\n admin: { date: { pickerAppearance: 'dayAndTime' }, readOnly: false },\n label: ({ t }) => (t as PluginT)('reservation:fieldEndTime'),\n },\n {\n name: 'guestCount',\n type: 'number',\n label: ({ t }) => (t as PluginT)('reservation:fieldGuestCount'),\n min: 1,\n },\n ],\n label: ({ t }) => (t as PluginT)('reservation:fieldItems'),\n },\n {\n name: 'idempotencyKey',\n type: 'text',\n admin: { position: 'sidebar', readOnly: true },\n index: true,\n unique: true,\n },\n ...config.extraReservationFields,\n ],\n hooks: {\n afterChange: [\n createPluginHooksAfterCreate(config.hooks),\n onStatusChange(config),\n ],\n beforeChange: [\n createPluginHooksBeforeCreate(config.hooks),\n checkIdempotency(config),\n calculateEndTime(config),\n validateConflicts(config),\n validateStatusTransition(config),\n validateCancellation(config),\n ],\n },\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionReservations'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionReservations'),\n },\n }\n}\n"],"names":["calculateEndTime","checkIdempotency","onStatusChange","validateCancellation","validateConflicts","validateStatusTransition","makeReservationOwnerAccess","createPluginHooksBeforeCreate","hooks","context","data","operation","req","skipReservationHooks","beforeBookingCreate","mutatedData","hook","result","createPluginHooksAfterCreate","doc","afterBookingCreate","docRecord","createReservationsCollection","config","statusMachine","rom","resourceOwnerMode","access","reservations","slug","slugs","admin","components","views","list","Component","group","adminGroup","listSearchableFields","useAsTitle","fields","name","type","label","t","relationTo","services","required","resources","allowCreate","allowEdit","Field","customers","date","pickerAppearance","readOnly","defaultValue","defaultStatus","options","statuses","map","s","key","charAt","toUpperCase","slice","translated","value","condition","_","siblingData","status","min","description","position","index","unique","extraReservationFields","afterChange","beforeChange","labels","plural","singular"],"mappings":"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"}
@@ -1,7 +1,33 @@
1
+ import { makeResourceOwnerAccess } from '../utilities/ownerAccess.js';
1
2
  export function createResourcesCollection(config) {
3
+ const rom = config.resourceOwnerMode;
4
+ const ownerField = rom?.ownerField ?? 'owner';
5
+ // Build the owner field when resourceOwnerMode is enabled
6
+ const ownerFieldDef = rom ? {
7
+ name: ownerField,
8
+ type: 'relationship',
9
+ admin: {
10
+ position: 'sidebar'
11
+ },
12
+ hooks: {
13
+ beforeChange: [
14
+ ({ operation, req, value })=>{
15
+ if (operation === 'create' && req.user) {
16
+ return req.user.id;
17
+ }
18
+ return value;
19
+ }
20
+ ]
21
+ },
22
+ label: 'Owner',
23
+ relationTo: config.slugs.customers,
24
+ required: true
25
+ } : null;
26
+ // Determine access: app override → owner-mode auto-wired → unrestricted
27
+ const access = config.access.resources ?? (rom ? makeResourceOwnerAccess(rom) : {});
2
28
  return {
3
29
  slug: config.slugs.resources,
4
- access: config.access.resources ?? {},
30
+ access,
5
31
  admin: {
6
32
  group: config.adminGroup,
7
33
  useAsTitle: 'name'
@@ -47,7 +73,49 @@ export function createResourcesCollection(config) {
47
73
  },
48
74
  defaultValue: true,
49
75
  label: ({ t })=>t('reservation:fieldActive')
50
- }
76
+ },
77
+ {
78
+ name: 'quantity',
79
+ type: 'number',
80
+ admin: {
81
+ position: 'sidebar'
82
+ },
83
+ defaultValue: 1,
84
+ label: ({ t })=>t('reservation:fieldQuantity'),
85
+ min: 1,
86
+ required: true
87
+ },
88
+ {
89
+ name: 'capacityMode',
90
+ type: 'select',
91
+ admin: {
92
+ condition: (data)=>(data?.quantity ?? 1) > 1,
93
+ position: 'sidebar'
94
+ },
95
+ defaultValue: 'per-reservation',
96
+ label: ({ t })=>t('reservation:fieldCapacityMode'),
97
+ options: [
98
+ {
99
+ label: ({ t })=>t('reservation:capacityPerReservation'),
100
+ value: 'per-reservation'
101
+ },
102
+ {
103
+ label: ({ t })=>t('reservation:capacityPerGuest'),
104
+ value: 'per-guest'
105
+ }
106
+ ]
107
+ },
108
+ {
109
+ name: 'timezone',
110
+ type: 'text',
111
+ admin: {
112
+ position: 'sidebar'
113
+ },
114
+ label: ({ t })=>t('reservation:fieldTimezone')
115
+ },
116
+ ...ownerFieldDef ? [
117
+ ownerFieldDef
118
+ ] : []
51
119
  ],
52
120
  labels: {
53
121
  plural: ({ t })=>t('reservation:collectionResources'),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/collections/Resources.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nexport function createResourcesCollection(\n config: ResolvedReservationPluginConfig,\n): CollectionConfig {\n return {\n slug: config.slugs.resources,\n access: config.access.resources ?? {},\n admin: {\n group: config.adminGroup,\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldName'),\n ...(config.localized ? { localized: true } : {}),\n maxLength: 200,\n required: true,\n },\n {\n name: 'image',\n type: 'upload',\n label: ({ t }) => (t as PluginT)('reservation:fieldImage'),\n relationTo: config.slugs.media,\n },\n {\n name: 'description',\n type: 'textarea',\n label: ({ t }) => (t as PluginT)('reservation:fieldDescription'),\n ...(config.localized ? { localized: true } : {}),\n },\n {\n name: 'services',\n type: 'relationship',\n hasMany: true,\n label: ({ t }) => (t as PluginT)('reservation:fieldServices'),\n relationTo: config.slugs.services,\n required: true,\n },\n {\n name: 'active',\n type: 'checkbox',\n admin: {\n position: 'sidebar',\n },\n defaultValue: true,\n label: ({ t }) => (t as PluginT)('reservation:fieldActive'),\n },\n ],\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionResources'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionResources'),\n },\n }\n}\n"],"names":["createResourcesCollection","config","slug","slugs","resources","access","admin","group","adminGroup","useAsTitle","fields","name","type","label","t","localized","maxLength","required","relationTo","media","hasMany","services","position","defaultValue","labels","plural","singular"],"mappings":"AAKA,OAAO,SAASA,0BACdC,MAAuC;IAEvC,OAAO;QACLC,MAAMD,OAAOE,KAAK,CAACC,SAAS;QAC5BC,QAAQJ,OAAOI,MAAM,CAACD,SAAS,IAAI,CAAC;QACpCE,OAAO;YACLC,OAAON,OAAOO,UAAU;YACxBC,YAAY;QACd;QACAC,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjC,GAAIb,OAAOc,SAAS,GAAG;oBAAEA,WAAW;gBAAK,IAAI,CAAC,CAAC;gBAC/CC,WAAW;gBACXC,UAAU;YACZ;YACA;gBACEN,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjCI,YAAYjB,OAAOE,KAAK,CAACgB,KAAK;YAChC;YACA;gBACER,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjC,GAAIb,OAAOc,SAAS,GAAG;oBAAEA,WAAW;gBAAK,IAAI,CAAC,CAAC;YACjD;YACA;gBACEJ,MAAM;gBACNC,MAAM;gBACNQ,SAAS;gBACTP,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjCI,YAAYjB,OAAOE,KAAK,CAACkB,QAAQ;gBACjCJ,UAAU;YACZ;YACA;gBACEN,MAAM;gBACNC,MAAM;gBACNN,OAAO;oBACLgB,UAAU;gBACZ;gBACAC,cAAc;gBACdV,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;YACnC;SACD;QACDU,QAAQ;YACNC,QAAQ,CAAC,EAAEX,CAAC,EAAE,GAAK,AAACA,EAAc;YAClCY,UAAU,CAAC,EAAEZ,CAAC,EAAE,GAAK,AAACA,EAAc;QACtC;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/collections/Resources.ts"],"sourcesContent":["import type { CollectionConfig, CollectionSlug, Field } from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nimport { makeResourceOwnerAccess } from '../utilities/ownerAccess.js'\n\nexport function createResourcesCollection(\n config: ResolvedReservationPluginConfig,\n): CollectionConfig {\n const rom = config.resourceOwnerMode\n const ownerField = rom?.ownerField ?? 'owner'\n\n // Build the owner field when resourceOwnerMode is enabled\n const ownerFieldDef: Field | null = rom\n ? {\n name: ownerField,\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n hooks: {\n beforeChange: [\n ({ operation, req, value }) => {\n if (operation === 'create' && req.user) {return req.user.id}\n return value\n },\n ],\n },\n label: 'Owner',\n relationTo: config.slugs.customers as unknown as CollectionSlug,\n required: true,\n }\n : null\n\n // Determine access: app override → owner-mode auto-wired → unrestricted\n const access =\n config.access.resources ?? (rom ? makeResourceOwnerAccess(rom) : {})\n\n return {\n slug: config.slugs.resources,\n access,\n admin: {\n group: config.adminGroup,\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldName'),\n ...(config.localized ? { localized: true } : {}),\n maxLength: 200,\n required: true,\n },\n {\n name: 'image',\n type: 'upload',\n label: ({ t }) => (t as PluginT)('reservation:fieldImage'),\n relationTo: config.slugs.media as unknown as CollectionSlug,\n },\n {\n name: 'description',\n type: 'textarea',\n label: ({ t }) => (t as PluginT)('reservation:fieldDescription'),\n ...(config.localized ? { localized: true } : {}),\n },\n {\n name: 'services',\n type: 'relationship',\n hasMany: true,\n label: ({ t }) => (t as PluginT)('reservation:fieldServices'),\n relationTo: config.slugs.services as unknown as CollectionSlug,\n required: true,\n },\n {\n name: 'active',\n type: 'checkbox',\n admin: {\n position: 'sidebar',\n },\n defaultValue: true,\n label: ({ t }) => (t as PluginT)('reservation:fieldActive'),\n },\n {\n name: 'quantity',\n type: 'number',\n admin: {\n position: 'sidebar',\n },\n defaultValue: 1,\n label: ({ t }) => (t as PluginT)('reservation:fieldQuantity'),\n min: 1,\n required: true,\n },\n {\n name: 'capacityMode',\n type: 'select',\n admin: {\n condition: (data) => (data?.quantity ?? 1) > 1,\n position: 'sidebar',\n },\n defaultValue: 'per-reservation',\n label: ({ t }) => (t as PluginT)('reservation:fieldCapacityMode'),\n options: [\n {\n label: ({ t }) => (t as PluginT)('reservation:capacityPerReservation'),\n value: 'per-reservation',\n },\n {\n label: ({ t }) => (t as PluginT)('reservation:capacityPerGuest'),\n value: 'per-guest',\n },\n ],\n },\n {\n name: 'timezone',\n type: 'text',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldTimezone'),\n },\n ...(ownerFieldDef ? [ownerFieldDef] : []),\n ],\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionResources'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionResources'),\n },\n }\n}\n"],"names":["makeResourceOwnerAccess","createResourcesCollection","config","rom","resourceOwnerMode","ownerField","ownerFieldDef","name","type","admin","position","hooks","beforeChange","operation","req","value","user","id","label","relationTo","slugs","customers","required","access","resources","slug","group","adminGroup","useAsTitle","fields","t","localized","maxLength","media","hasMany","services","defaultValue","min","condition","data","quantity","options","labels","plural","singular"],"mappings":"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"}
@@ -1,7 +1,10 @@
1
+ import { makeScheduleOwnerAccess } from '../utilities/ownerAccess.js';
1
2
  export function createSchedulesCollection(config) {
3
+ const rom = config.resourceOwnerMode;
4
+ const access = config.access.schedules ?? (rom ? makeScheduleOwnerAccess(rom) : {});
2
5
  return {
3
6
  slug: config.slugs.schedules,
4
- access: config.access.schedules ?? {},
7
+ access,
5
8
  admin: {
6
9
  group: config.adminGroup,
7
10
  useAsTitle: 'name'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/collections/Schedules.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nexport function createSchedulesCollection(\n config: ResolvedReservationPluginConfig,\n): CollectionConfig {\n return {\n slug: config.slugs.schedules,\n access: config.access.schedules ?? {},\n admin: {\n group: config.adminGroup,\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldName'),\n required: true,\n },\n {\n name: 'resource',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldResource'),\n relationTo: config.slugs.resources,\n required: true,\n },\n {\n name: 'scheduleType',\n type: 'select',\n defaultValue: 'recurring',\n label: ({ t }) => (t as PluginT)('reservation:fieldScheduleType'),\n options: [\n {\n label: ({ t }) => (t as PluginT)('reservation:scheduleTypeRecurring'),\n value: 'recurring',\n },\n {\n label: ({ t }) => (t as PluginT)('reservation:scheduleTypeManual'),\n value: 'manual',\n },\n ],\n },\n {\n name: 'recurringSlots',\n type: 'array',\n admin: {\n condition: (_, siblingData) => siblingData?.scheduleType === 'recurring',\n },\n fields: [\n {\n name: 'day',\n type: 'select',\n label: ({ t }) => (t as PluginT)('reservation:fieldDay'),\n options: [\n { label: ({ t }) => (t as PluginT)('reservation:dayMonday'), value: 'mon' },\n { label: ({ t }) => (t as PluginT)('reservation:dayTuesday'), value: 'tue' },\n { label: ({ t }) => (t as PluginT)('reservation:dayWednesday'), value: 'wed' },\n { label: ({ t }) => (t as PluginT)('reservation:dayThursday'), value: 'thu' },\n { label: ({ t }) => (t as PluginT)('reservation:dayFriday'), value: 'fri' },\n { label: ({ t }) => (t as PluginT)('reservation:daySaturday'), value: 'sat' },\n { label: ({ t }) => (t as PluginT)('reservation:daySunday'), value: 'sun' },\n ],\n required: true,\n },\n {\n name: 'startTime',\n type: 'text',\n admin: {\n placeholder: '09:00',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldStartTimeHHmm'),\n required: true,\n },\n {\n name: 'endTime',\n type: 'text',\n admin: {\n placeholder: '17:00',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldEndTimeHHmm'),\n required: true,\n },\n ],\n label: ({ t }) => (t as PluginT)('reservation:fieldRecurringSlots'),\n },\n {\n name: 'manualSlots',\n type: 'array',\n admin: {\n condition: (_, siblingData) => siblingData?.scheduleType === 'manual',\n },\n fields: [\n {\n name: 'date',\n type: 'date',\n admin: {\n date: {\n pickerAppearance: 'dayOnly',\n },\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldDate'),\n required: true,\n },\n {\n name: 'startTime',\n type: 'text',\n admin: {\n placeholder: '09:00',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldStartTimeHHmm'),\n required: true,\n },\n {\n name: 'endTime',\n type: 'text',\n admin: {\n placeholder: '17:00',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldEndTimeHHmm'),\n required: true,\n },\n ],\n label: ({ t }) => (t as PluginT)('reservation:fieldManualSlots'),\n },\n {\n name: 'exceptions',\n type: 'array',\n fields: [\n {\n name: 'date',\n type: 'date',\n admin: {\n date: {\n pickerAppearance: 'dayOnly',\n },\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldDate'),\n required: true,\n },\n {\n name: 'reason',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldReason'),\n },\n ],\n label: ({ t }) => (t as PluginT)('reservation:fieldExceptions'),\n },\n {\n name: 'active',\n type: 'checkbox',\n admin: {\n position: 'sidebar',\n },\n defaultValue: true,\n label: ({ t }) => (t as PluginT)('reservation:fieldActive'),\n },\n ],\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionSchedules'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionSchedules'),\n },\n }\n}\n"],"names":["createSchedulesCollection","config","slug","slugs","schedules","access","admin","group","adminGroup","useAsTitle","fields","name","type","label","t","required","relationTo","resources","defaultValue","options","value","condition","_","siblingData","scheduleType","placeholder","date","pickerAppearance","position","labels","plural","singular"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/collections/Schedules.ts"],"sourcesContent":["import type { CollectionConfig, CollectionSlug } from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nimport { makeScheduleOwnerAccess } from '../utilities/ownerAccess.js'\n\nexport function createSchedulesCollection(\n config: ResolvedReservationPluginConfig,\n): CollectionConfig {\n const rom = config.resourceOwnerMode\n const access =\n config.access.schedules ?? (rom ? makeScheduleOwnerAccess(rom) : {})\n\n return {\n slug: config.slugs.schedules,\n access,\n admin: {\n group: config.adminGroup,\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldName'),\n required: true,\n },\n {\n name: 'resource',\n type: 'relationship',\n label: ({ t }) => (t as PluginT)('reservation:fieldResource'),\n relationTo: config.slugs.resources as unknown as CollectionSlug,\n required: true,\n },\n {\n name: 'scheduleType',\n type: 'select',\n defaultValue: 'recurring',\n label: ({ t }) => (t as PluginT)('reservation:fieldScheduleType'),\n options: [\n {\n label: ({ t }) => (t as PluginT)('reservation:scheduleTypeRecurring'),\n value: 'recurring',\n },\n {\n label: ({ t }) => (t as PluginT)('reservation:scheduleTypeManual'),\n value: 'manual',\n },\n ],\n },\n {\n name: 'recurringSlots',\n type: 'array',\n admin: {\n condition: (_, siblingData) => siblingData?.scheduleType === 'recurring',\n },\n fields: [\n {\n name: 'day',\n type: 'select',\n label: ({ t }) => (t as PluginT)('reservation:fieldDay'),\n options: [\n { label: ({ t }) => (t as PluginT)('reservation:dayMonday'), value: 'mon' },\n { label: ({ t }) => (t as PluginT)('reservation:dayTuesday'), value: 'tue' },\n { label: ({ t }) => (t as PluginT)('reservation:dayWednesday'), value: 'wed' },\n { label: ({ t }) => (t as PluginT)('reservation:dayThursday'), value: 'thu' },\n { label: ({ t }) => (t as PluginT)('reservation:dayFriday'), value: 'fri' },\n { label: ({ t }) => (t as PluginT)('reservation:daySaturday'), value: 'sat' },\n { label: ({ t }) => (t as PluginT)('reservation:daySunday'), value: 'sun' },\n ],\n required: true,\n },\n {\n name: 'startTime',\n type: 'text',\n admin: {\n placeholder: '09:00',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldStartTimeHHmm'),\n required: true,\n },\n {\n name: 'endTime',\n type: 'text',\n admin: {\n placeholder: '17:00',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldEndTimeHHmm'),\n required: true,\n },\n ],\n label: ({ t }) => (t as PluginT)('reservation:fieldRecurringSlots'),\n },\n {\n name: 'manualSlots',\n type: 'array',\n admin: {\n condition: (_, siblingData) => siblingData?.scheduleType === 'manual',\n },\n fields: [\n {\n name: 'date',\n type: 'date',\n admin: {\n date: {\n pickerAppearance: 'dayOnly',\n },\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldDate'),\n required: true,\n },\n {\n name: 'startTime',\n type: 'text',\n admin: {\n placeholder: '09:00',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldStartTimeHHmm'),\n required: true,\n },\n {\n name: 'endTime',\n type: 'text',\n admin: {\n placeholder: '17:00',\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldEndTimeHHmm'),\n required: true,\n },\n ],\n label: ({ t }) => (t as PluginT)('reservation:fieldManualSlots'),\n },\n {\n name: 'exceptions',\n type: 'array',\n fields: [\n {\n name: 'date',\n type: 'date',\n admin: {\n date: {\n pickerAppearance: 'dayOnly',\n },\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldDate'),\n required: true,\n },\n {\n name: 'reason',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldReason'),\n },\n ],\n label: ({ t }) => (t as PluginT)('reservation:fieldExceptions'),\n },\n {\n name: 'active',\n type: 'checkbox',\n admin: {\n position: 'sidebar',\n },\n defaultValue: true,\n label: ({ t }) => (t as PluginT)('reservation:fieldActive'),\n },\n ],\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionSchedules'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionSchedules'),\n },\n }\n}\n"],"names":["makeScheduleOwnerAccess","createSchedulesCollection","config","rom","resourceOwnerMode","access","schedules","slug","slugs","admin","group","adminGroup","useAsTitle","fields","name","type","label","t","required","relationTo","resources","defaultValue","options","value","condition","_","siblingData","scheduleType","placeholder","date","pickerAppearance","position","labels","plural","singular"],"mappings":"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"}
@@ -1,7 +1,34 @@
1
+ import { makeServiceOwnerAccess } from '../utilities/ownerAccess.js';
1
2
  export function createServicesCollection(config) {
3
+ const rom = config.resourceOwnerMode;
4
+ const ownedServices = rom?.ownedServices ?? false;
5
+ const ownerField = rom?.ownerField ?? 'owner';
6
+ // Owner field on Services (only when ownedServices: true)
7
+ const ownerFieldDef = rom && ownedServices ? {
8
+ name: ownerField,
9
+ type: 'relationship',
10
+ admin: {
11
+ position: 'sidebar'
12
+ },
13
+ hooks: {
14
+ beforeChange: [
15
+ ({ operation, req, value })=>{
16
+ if (operation === 'create' && req.user) {
17
+ return req.user.id;
18
+ }
19
+ return value;
20
+ }
21
+ ]
22
+ },
23
+ label: 'Owner',
24
+ relationTo: config.slugs.customers,
25
+ required: true
26
+ } : null;
27
+ // Determine access: app override → owner-mode auto-wired → unrestricted
28
+ const access = config.access.services ?? (rom && ownedServices ? makeServiceOwnerAccess(rom, ownerField) : {});
2
29
  return {
3
30
  slug: config.slugs.services,
4
- access: config.access.services ?? {},
31
+ access,
5
32
  admin: {
6
33
  group: config.adminGroup,
7
34
  useAsTitle: 'name'
@@ -17,6 +44,12 @@ export function createServicesCollection(config) {
17
44
  maxLength: 200,
18
45
  required: true
19
46
  },
47
+ {
48
+ name: 'image',
49
+ type: 'upload',
50
+ label: ({ t })=>t('reservation:fieldImage'),
51
+ relationTo: config.slugs.media
52
+ },
20
53
  {
21
54
  name: 'description',
22
55
  type: 'textarea',
@@ -32,6 +65,27 @@ export function createServicesCollection(config) {
32
65
  min: 1,
33
66
  required: true
34
67
  },
68
+ {
69
+ name: 'durationType',
70
+ type: 'select',
71
+ defaultValue: 'fixed',
72
+ label: ({ t })=>t('reservation:fieldDurationType'),
73
+ options: [
74
+ {
75
+ label: ({ t })=>t('reservation:durationFixed'),
76
+ value: 'fixed'
77
+ },
78
+ {
79
+ label: ({ t })=>t('reservation:durationFlexible'),
80
+ value: 'flexible'
81
+ },
82
+ {
83
+ label: ({ t })=>t('reservation:durationFullDay'),
84
+ value: 'full-day'
85
+ }
86
+ ],
87
+ required: true
88
+ },
35
89
  {
36
90
  name: 'price',
37
91
  type: 'number',
@@ -63,7 +117,10 @@ export function createServicesCollection(config) {
63
117
  },
64
118
  defaultValue: true,
65
119
  label: ({ t })=>t('reservation:fieldActive')
66
- }
120
+ },
121
+ ...ownerFieldDef ? [
122
+ ownerFieldDef
123
+ ] : []
67
124
  ],
68
125
  labels: {
69
126
  plural: ({ t })=>t('reservation:collectionServices'),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/collections/Services.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nexport function createServicesCollection(config: ResolvedReservationPluginConfig): CollectionConfig {\n return {\n slug: config.slugs.services,\n access: config.access.services ?? {},\n admin: {\n group: config.adminGroup,\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldName'),\n ...(config.localized ? { localized: true } : {}),\n maxLength: 200,\n required: true,\n },\n {\n name: 'description',\n type: 'textarea',\n label: ({ t }) => (t as PluginT)('reservation:fieldDescription'),\n ...(config.localized ? { localized: true } : {}),\n },\n {\n name: 'duration',\n type: 'number',\n label: ({ t }) => (t as PluginT)('reservation:fieldDurationMinutes'),\n min: 1,\n required: true,\n },\n {\n name: 'price',\n type: 'number',\n admin: {\n step: 0.01,\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldPrice'),\n min: 0,\n },\n {\n name: 'bufferTimeBefore',\n type: 'number',\n defaultValue: 0,\n label: ({ t }) => (t as PluginT)('reservation:fieldBufferTimeBefore'),\n min: 0,\n },\n {\n name: 'bufferTimeAfter',\n type: 'number',\n defaultValue: 0,\n label: ({ t }) => (t as PluginT)('reservation:fieldBufferTimeAfter'),\n min: 0,\n },\n {\n name: 'active',\n type: 'checkbox',\n admin: {\n position: 'sidebar',\n },\n defaultValue: true,\n label: ({ t }) => (t as PluginT)('reservation:fieldActive'),\n },\n ],\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionServices'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionServices'),\n },\n }\n}\n"],"names":["createServicesCollection","config","slug","slugs","services","access","admin","group","adminGroup","useAsTitle","fields","name","type","label","t","localized","maxLength","required","min","step","defaultValue","position","labels","plural","singular"],"mappings":"AAKA,OAAO,SAASA,yBAAyBC,MAAuC;IAC9E,OAAO;QACLC,MAAMD,OAAOE,KAAK,CAACC,QAAQ;QAC3BC,QAAQJ,OAAOI,MAAM,CAACD,QAAQ,IAAI,CAAC;QACnCE,OAAO;YACLC,OAAON,OAAOO,UAAU;YACxBC,YAAY;QACd;QACAC,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjC,GAAIb,OAAOc,SAAS,GAAG;oBAAEA,WAAW;gBAAK,IAAI,CAAC,CAAC;gBAC/CC,WAAW;gBACXC,UAAU;YACZ;YACA;gBACEN,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjC,GAAIb,OAAOc,SAAS,GAAG;oBAAEA,WAAW;gBAAK,IAAI,CAAC,CAAC;YACjD;YACA;gBACEJ,MAAM;gBACNC,MAAM;gBACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjCI,KAAK;gBACLD,UAAU;YACZ;YACA;gBACEN,MAAM;gBACNC,MAAM;gBACNN,OAAO;oBACLa,MAAM;gBACR;gBACAN,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjCI,KAAK;YACP;YACA;gBACEP,MAAM;gBACNC,MAAM;gBACNQ,cAAc;gBACdP,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjCI,KAAK;YACP;YACA;gBACEP,MAAM;gBACNC,MAAM;gBACNQ,cAAc;gBACdP,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;gBACjCI,KAAK;YACP;YACA;gBACEP,MAAM;gBACNC,MAAM;gBACNN,OAAO;oBACLe,UAAU;gBACZ;gBACAD,cAAc;gBACdP,OAAO,CAAC,EAAEC,CAAC,EAAE,GAAK,AAACA,EAAc;YACnC;SACD;QACDQ,QAAQ;YACNC,QAAQ,CAAC,EAAET,CAAC,EAAE,GAAK,AAACA,EAAc;YAClCU,UAAU,CAAC,EAAEV,CAAC,EAAE,GAAK,AAACA,EAAc;QACtC;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/collections/Services.ts"],"sourcesContent":["import type { CollectionConfig, CollectionSlug, Field } from 'payload'\n\nimport type { PluginT } from '../translations/index.js'\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nimport { makeServiceOwnerAccess } from '../utilities/ownerAccess.js'\n\nexport function createServicesCollection(config: ResolvedReservationPluginConfig): CollectionConfig {\n const rom = config.resourceOwnerMode\n const ownedServices = rom?.ownedServices ?? false\n const ownerField = rom?.ownerField ?? 'owner'\n\n // Owner field on Services (only when ownedServices: true)\n const ownerFieldDef: Field | null =\n rom && ownedServices\n ? {\n name: ownerField,\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n hooks: {\n beforeChange: [\n ({ operation, req, value }) => {\n if (operation === 'create' && req.user) {return req.user.id}\n return value\n },\n ],\n },\n label: 'Owner',\n relationTo: config.slugs.customers as unknown as CollectionSlug,\n required: true,\n }\n : null\n\n // Determine access: app override → owner-mode auto-wired → unrestricted\n const access =\n config.access.services ??\n (rom && ownedServices ? makeServiceOwnerAccess(rom, ownerField) : {})\n\n return {\n slug: config.slugs.services,\n access,\n admin: {\n group: config.adminGroup,\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n label: ({ t }) => (t as PluginT)('reservation:fieldName'),\n ...(config.localized ? { localized: true } : {}),\n maxLength: 200,\n required: true,\n },\n {\n name: 'image',\n type: 'upload',\n label: ({ t }) => (t as PluginT)('reservation:fieldImage'),\n relationTo: config.slugs.media as unknown as CollectionSlug,\n },\n {\n name: 'description',\n type: 'textarea',\n label: ({ t }) => (t as PluginT)('reservation:fieldDescription'),\n ...(config.localized ? { localized: true } : {}),\n },\n {\n name: 'duration',\n type: 'number',\n label: ({ t }) => (t as PluginT)('reservation:fieldDurationMinutes'),\n min: 1,\n required: true,\n },\n {\n name: 'durationType',\n type: 'select',\n defaultValue: 'fixed',\n label: ({ t }) => (t as PluginT)('reservation:fieldDurationType'),\n options: [\n {\n label: ({ t }) => (t as PluginT)('reservation:durationFixed'),\n value: 'fixed',\n },\n {\n label: ({ t }) => (t as PluginT)('reservation:durationFlexible'),\n value: 'flexible',\n },\n {\n label: ({ t }) => (t as PluginT)('reservation:durationFullDay'),\n value: 'full-day',\n },\n ],\n required: true,\n },\n {\n name: 'price',\n type: 'number',\n admin: {\n step: 0.01,\n },\n label: ({ t }) => (t as PluginT)('reservation:fieldPrice'),\n min: 0,\n },\n {\n name: 'bufferTimeBefore',\n type: 'number',\n defaultValue: 0,\n label: ({ t }) => (t as PluginT)('reservation:fieldBufferTimeBefore'),\n min: 0,\n },\n {\n name: 'bufferTimeAfter',\n type: 'number',\n defaultValue: 0,\n label: ({ t }) => (t as PluginT)('reservation:fieldBufferTimeAfter'),\n min: 0,\n },\n {\n name: 'active',\n type: 'checkbox',\n admin: {\n position: 'sidebar',\n },\n defaultValue: true,\n label: ({ t }) => (t as PluginT)('reservation:fieldActive'),\n },\n ...(ownerFieldDef ? [ownerFieldDef] : []),\n ],\n labels: {\n plural: ({ t }) => (t as PluginT)('reservation:collectionServices'),\n singular: ({ t }) => (t as PluginT)('reservation:collectionServices'),\n },\n }\n}\n"],"names":["makeServiceOwnerAccess","createServicesCollection","config","rom","resourceOwnerMode","ownedServices","ownerField","ownerFieldDef","name","type","admin","position","hooks","beforeChange","operation","req","value","user","id","label","relationTo","slugs","customers","required","access","services","slug","group","adminGroup","useAsTitle","fields","t","localized","maxLength","media","min","defaultValue","options","step","labels","plural","singular"],"mappings":"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"}