@deallony/shared 1.2.80 → 1.2.82

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 (117) hide show
  1. package/dist/cjs/constants/events/EventBirthday.d.ts +2 -0
  2. package/dist/cjs/constants/events/EventBirthday.js +12 -0
  3. package/dist/cjs/constants/events/EventCustomization.d.ts +21 -0
  4. package/dist/cjs/constants/events/EventCustomization.js +23 -2
  5. package/dist/cjs/constants/events/EventDressCode.d.ts +65 -0
  6. package/dist/cjs/constants/events/EventDressCode.js +56 -0
  7. package/dist/cjs/constants/events/EventGuests.d.ts +3 -0
  8. package/dist/cjs/constants/events/EventGuests.js +6 -0
  9. package/dist/cjs/constants/events/EventHost.d.ts +79 -0
  10. package/dist/cjs/constants/events/EventHost.js +155 -0
  11. package/dist/cjs/constants/events/EventOccasion.d.ts +63 -0
  12. package/dist/cjs/constants/events/EventOccasion.js +242 -0
  13. package/dist/cjs/constants/events/EventPreview.d.ts +3 -0
  14. package/dist/cjs/constants/events/EventPreview.js +9 -1
  15. package/dist/cjs/constants/events/EventTemplate.d.ts +518 -10
  16. package/dist/cjs/constants/events/EventTemplate.js +81 -11
  17. package/dist/cjs/constants/events/EventTextPolicy.d.ts +7 -0
  18. package/dist/cjs/constants/events/EventTextPolicy.js +66 -0
  19. package/dist/cjs/constants/events/EventType.d.ts +273 -8
  20. package/dist/cjs/constants/events/EventType.js +38 -2
  21. package/dist/cjs/constants/events/EventVisibility.d.ts +19 -0
  22. package/dist/cjs/constants/events/EventVisibility.js +18 -0
  23. package/dist/cjs/constants/events/EventWedding.js +3 -0
  24. package/dist/cjs/constants/events/EventWeddingReligion.d.ts +72 -0
  25. package/dist/cjs/constants/events/EventWeddingReligion.js +126 -0
  26. package/dist/cjs/constants/events/index.d.ts +8 -0
  27. package/dist/cjs/constants/events/index.js +8 -0
  28. package/dist/cjs/constants/routes/app.d.ts +49 -0
  29. package/dist/cjs/constants/routes/app.js +16 -0
  30. package/dist/cjs/dto/events/EventBirthday.dto.d.ts +3 -0
  31. package/dist/cjs/dto/events/EventBirthday.dto.js +2 -0
  32. package/dist/cjs/dto/events/EventHost.dto.d.ts +7 -0
  33. package/dist/cjs/dto/events/EventHost.dto.js +2 -0
  34. package/dist/cjs/dto/events/EventOccasion.dto.d.ts +3 -0
  35. package/dist/cjs/dto/events/EventOccasion.dto.js +2 -0
  36. package/dist/cjs/dto/events/index.d.ts +3 -0
  37. package/dist/cjs/dto/events/index.js +3 -0
  38. package/dist/cjs/schema/communication/ai-conversation.schema.d.ts +55 -3
  39. package/dist/cjs/schema/communication/ai-conversation.schema.js +28 -3
  40. package/dist/cjs/schema/communication/offer.schema.d.ts +3 -3
  41. package/dist/cjs/schema/communication/support-ticket.schema.d.ts +136 -0
  42. package/dist/cjs/schema/communication/support-ticket.schema.js +47 -2
  43. package/dist/cjs/schema/events/Event.schema.d.ts +326 -0
  44. package/dist/cjs/schema/events/Event.schema.js +55 -1
  45. package/dist/cjs/schema/events/EventBirthday.schema.d.ts +19 -0
  46. package/dist/cjs/schema/events/EventBirthday.schema.js +17 -0
  47. package/dist/cjs/schema/events/EventHost.schema.d.ts +36 -0
  48. package/dist/cjs/schema/events/EventHost.schema.js +44 -0
  49. package/dist/cjs/schema/events/EventOccasion.schema.d.ts +22 -0
  50. package/dist/cjs/schema/events/EventOccasion.schema.js +31 -0
  51. package/dist/cjs/schema/events/EventRsvp.schema.d.ts +4 -0
  52. package/dist/cjs/schema/events/EventRsvp.schema.js +1 -0
  53. package/dist/cjs/schema/events/EventTimeline.schema.d.ts +5 -0
  54. package/dist/cjs/schema/events/EventTimeline.schema.js +14 -1
  55. package/dist/cjs/schema/events/EventWedding.schema.d.ts +32 -0
  56. package/dist/cjs/schema/events/EventWedding.schema.js +11 -0
  57. package/dist/cjs/schema/events/index.d.ts +3 -0
  58. package/dist/cjs/schema/events/index.js +3 -0
  59. package/dist/cjs/types/communication/Notification.d.ts +21 -2
  60. package/dist/cjs/types/communication/Notification.js +17 -0
  61. package/dist/cjs/types/events/Event.d.ts +38 -1
  62. package/dist/cjs/types/events/EventBirthday.d.ts +17 -0
  63. package/dist/cjs/types/events/EventBirthday.js +2 -0
  64. package/dist/cjs/types/events/EventCustomization.d.ts +4 -0
  65. package/dist/cjs/types/events/EventDressCode.d.ts +13 -0
  66. package/dist/cjs/types/events/EventDressCode.js +2 -0
  67. package/dist/cjs/types/events/EventHost.d.ts +29 -0
  68. package/dist/cjs/types/events/EventHost.js +2 -0
  69. package/dist/cjs/types/events/EventOccasion.d.ts +24 -0
  70. package/dist/cjs/types/events/EventOccasion.js +2 -0
  71. package/dist/cjs/types/events/EventRsvp.d.ts +2 -0
  72. package/dist/cjs/types/events/EventTimeline.d.ts +2 -0
  73. package/dist/cjs/types/events/EventWedding.d.ts +7 -0
  74. package/dist/cjs/types/events/index.d.ts +4 -0
  75. package/dist/cjs/types/events/index.js +4 -0
  76. package/dist/cjs/types/index.d.ts +4 -0
  77. package/dist/cjs/types/index.js +6 -2
  78. package/dist/cjs/types/user/SavedSearch.d.ts +38 -0
  79. package/dist/cjs/types/user/SavedSearch.js +11 -0
  80. package/dist/esm/constants/events/EventBirthday.js +9 -0
  81. package/dist/esm/constants/events/EventCustomization.js +21 -1
  82. package/dist/esm/constants/events/EventDressCode.js +49 -0
  83. package/dist/esm/constants/events/EventGuests.js +3 -0
  84. package/dist/esm/constants/events/EventHost.js +147 -0
  85. package/dist/esm/constants/events/EventOccasion.js +235 -0
  86. package/dist/esm/constants/events/EventPreview.js +7 -0
  87. package/dist/esm/constants/events/EventTemplate.js +78 -10
  88. package/dist/esm/constants/events/EventTextPolicy.js +61 -0
  89. package/dist/esm/constants/events/EventType.js +34 -1
  90. package/dist/esm/constants/events/EventVisibility.js +15 -0
  91. package/dist/esm/constants/events/EventWedding.js +3 -0
  92. package/dist/esm/constants/events/EventWeddingReligion.js +118 -0
  93. package/dist/esm/constants/events/index.js +8 -0
  94. package/dist/esm/constants/routes/app.js +16 -0
  95. package/dist/esm/dto/events/EventBirthday.dto.js +1 -0
  96. package/dist/esm/dto/events/EventHost.dto.js +1 -0
  97. package/dist/esm/dto/events/EventOccasion.dto.js +1 -0
  98. package/dist/esm/dto/events/index.js +3 -0
  99. package/dist/esm/schema/communication/ai-conversation.schema.js +27 -2
  100. package/dist/esm/schema/communication/support-ticket.schema.js +46 -1
  101. package/dist/esm/schema/events/Event.schema.js +55 -1
  102. package/dist/esm/schema/events/EventBirthday.schema.js +14 -0
  103. package/dist/esm/schema/events/EventHost.schema.js +41 -0
  104. package/dist/esm/schema/events/EventOccasion.schema.js +28 -0
  105. package/dist/esm/schema/events/EventRsvp.schema.js +1 -0
  106. package/dist/esm/schema/events/EventTimeline.schema.js +14 -1
  107. package/dist/esm/schema/events/EventWedding.schema.js +11 -0
  108. package/dist/esm/schema/events/index.js +3 -0
  109. package/dist/esm/types/communication/Notification.js +17 -0
  110. package/dist/esm/types/events/EventBirthday.js +1 -0
  111. package/dist/esm/types/events/EventDressCode.js +1 -0
  112. package/dist/esm/types/events/EventHost.js +1 -0
  113. package/dist/esm/types/events/EventOccasion.js +1 -0
  114. package/dist/esm/types/events/index.js +4 -0
  115. package/dist/esm/types/index.js +4 -0
  116. package/dist/esm/types/user/SavedSearch.js +8 -0
  117. package/package.json +1 -1
@@ -7,6 +7,12 @@ export const APP_ROUTES = {
7
7
  list: () => ({ pathname: "/notifications" }),
8
8
  settings: () => ({ pathname: "/notifications/settings" }),
9
9
  },
10
+ savedSearches: {
11
+ /** The user's saved ad searches ("بحثي المحفوظ") */
12
+ list: () => ({ pathname: "/saved-searches" }),
13
+ /** Opens a saved search's results with its new ads marked, and marks them seen */
14
+ open: (id) => ({ pathname: "/saved-searches/[id]", params: { id: String(id) } }),
15
+ },
10
16
  favorites: {
11
17
  compare: (ad_ids) => ({
12
18
  pathname: "/favorites/compare",
@@ -181,6 +187,10 @@ export const APP_ROUTES = {
181
187
  details: (id) => ({ pathname: "/company/details/[id]", params: { id } }),
182
188
  /** Public profile with the company's ads */
183
189
  profile: (id) => ({ pathname: "/company/profile/[id]", params: { id } }),
190
+ /** Every ad published under the company, for its members */
191
+ ads: (id) => ({ pathname: "/company/ads/[id]", params: { id } }),
192
+ /** This week's most active companies (opened from the home strip) */
193
+ ranking: () => ({ pathname: "/company/ranking" }),
184
194
  },
185
195
  venue: {
186
196
  new: (companyId) => ({ pathname: "/venue/new", params: { company_id: companyId } }),
@@ -189,10 +199,16 @@ export const APP_ROUTES = {
189
199
  },
190
200
  event: {
191
201
  new: (venueId) => venueId ? { pathname: "/event/new", params: { venue_id: venueId } } : { pathname: "/event/new", params: { personal: "1" } },
202
+ /** A new personal event of one type (wedding, birthday), chosen on the start page */
203
+ newOfType: (eventType) => ({ pathname: "/event/new", params: { personal: "1", event_type: eventType } }),
192
204
  start: () => ({ pathname: "/event/start" }),
193
205
  mine: () => ({ pathname: "/event/mine" }),
206
+ /** Upcoming public events (optionally of one venue) */
207
+ upcoming: (venueId) => venueId ? { pathname: "/event/upcoming", params: { venue_id: venueId } } : { pathname: "/event/upcoming" },
194
208
  publish: (id) => ({ pathname: "/event/publish/[id]", params: { id } }),
195
209
  edit: (id) => ({ pathname: "/event/new", params: { id } }),
196
210
  details: (id) => ({ pathname: "/event/details/[id]", params: { id } }),
211
+ /** People of the event (owner, organisers, guest managers) */
212
+ hosts: (id) => ({ pathname: "/event/hosts/[id]", params: { id } }),
197
213
  },
198
214
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -2,4 +2,7 @@ export * from './Event.dto.js';
2
2
  export * from './EventRsvp.dto.js';
3
3
  export * from './EventTimeline.dto.js';
4
4
  export * from './EventWedding.dto.js';
5
+ export * from './EventBirthday.dto.js';
6
+ export * from './EventOccasion.dto.js';
5
7
  export * from './EventVenue.dto.js';
8
+ export * from './EventHost.dto.js';
@@ -40,6 +40,8 @@ export const AiConversationStatusSchema = z.enum([
40
40
  'starting',
41
41
  /** The opening is written and waits for an admin to approve it */
42
42
  'awaiting_approval',
43
+ /** Waits for the sending hours to open: the opening, an approved draft or the AI's reply goes out then */
44
+ 'scheduled',
43
45
  'waiting_for_reply',
44
46
  'chatting',
45
47
  'interested',
@@ -55,6 +57,7 @@ export const AiConversationPurposeSchema = z.enum(['marketing', 'support']);
55
57
  export const AI_CONVERSATION_ACTIVE_STATUSES = [
56
58
  'starting',
57
59
  'awaiting_approval',
60
+ 'scheduled',
58
61
  'waiting_for_reply',
59
62
  'chatting',
60
63
  'interested',
@@ -74,10 +77,11 @@ export const AiApprovalSettingsSchema = z.object({
74
77
  enabled: z.boolean(),
75
78
  });
76
79
  /**
77
- * pending: waiting for an admin. sent: approved and sent. rejected: thrown away by an admin.
80
+ * pending: waiting for an admin. scheduled: ready, goes out when the sending hours open (send_after).
81
+ * sent: approved and sent. rejected: thrown away by an admin.
78
82
  * outdated: the customer wrote again, so a newer draft replaced it. failed: approved but WhatsApp refused it.
79
83
  */
80
- export const AiDraftStatusSchema = z.enum(['pending', 'sent', 'rejected', 'outdated', 'failed']);
84
+ export const AiDraftStatusSchema = z.enum(['pending', 'scheduled', 'sent', 'rejected', 'outdated', 'failed']);
81
85
  /** opening: first messages of a new chat. reply: answer to the customer. opt_out: goodbye after a stop request */
82
86
  export const AiDraftKindSchema = z.enum(['opening', 'reply', 'opt_out']);
83
87
  export const AiDraftListSchema = z.object({
@@ -92,7 +96,28 @@ export const AiDraftDecisionSchema = z.object({
92
96
  /** Edited messages to send instead of the AI's; only with approve */
93
97
  replies: z.array(z.string().trim().min(1).max(4000)).min(1).max(4).optional(),
94
98
  });
99
+ /** Sends a scheduled draft right away, ignoring the sending hours */
100
+ export const AiDraftSendNowSchema = z.object({
101
+ draft_id: z.coerce.number().int().positive(),
102
+ });
95
103
  export const AiDraftApproveAllSchema = z.object({
96
104
  /** Approve only these drafts; all pending drafts when left out */
97
105
  draft_ids: z.array(z.coerce.number().int().positive()).max(100).optional(),
98
106
  });
107
+ /* ---------- Sending hours: AI marketing messages go out only between start and end ---------- */
108
+ const ClockTimeSchema = z
109
+ .string()
110
+ .trim()
111
+ .regex(/^([01]\d|2[0-3]):[0-5]\d$/, 'Use HH:MM, 24-hour clock');
112
+ /**
113
+ * One setting for all AI marketing conversations. Times are on each customer's own clock,
114
+ * picked from the phone code (+963 Syria, +971 UAE); other numbers use default_timezone.
115
+ * end before start means the hours cross midnight (for example 20:00 to 02:00).
116
+ */
117
+ export const AiSendWindowSettingsSchema = z.object({
118
+ enabled: z.boolean(),
119
+ start: ClockTimeSchema,
120
+ end: ClockTimeSchema,
121
+ /** IANA time zone, for example Asia/Damascus */
122
+ default_timezone: z.string().trim().min(1).max(60),
123
+ });
@@ -1,7 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  export const SupportTicketStatusSchema = z.enum(['open', 'assigned', 'in_progress', 'waiting_customer', 'resolved', 'closed', 'reopened']);
3
3
  export const SupportTicketPrioritySchema = z.enum(['low', 'normal', 'high', 'urgent']);
4
- export const SupportTicketCategorySchema = z.enum(['technical_issue', 'account', 'advertisement', 'payment', 'complaint', 'other']);
4
+ export const SupportTicketCategorySchema = z.enum(['technical_issue', 'account', 'advertisement', 'payment', 'complaint', 'kyc', 'event', 'login', 'other']);
5
+ export const SupportTicketSourceSchema = z.enum(['admin', 'ai', 'app', 'guest', 'report']);
5
6
  export const SupportTicketCreateSchema = z.object({
6
7
  title: z.string().trim().min(4).max(180),
7
8
  description: z.string().trim().min(5).max(5000),
@@ -26,7 +27,51 @@ export const SupportTicketListSchema = z.object({
26
27
  status: SupportTicketStatusSchema.optional(),
27
28
  priority: SupportTicketPrioritySchema.optional(),
28
29
  search: z.string().trim().max(100).optional(),
30
+ source: SupportTicketSourceSchema.optional(),
31
+ screen: z.string().trim().max(40).optional(),
29
32
  });
30
33
  export const SupportTicketStatusUpdateSchema = SupportTicketIdSchema.extend({ status: SupportTicketStatusSchema });
31
34
  export const SupportTicketAssignmentSchema = SupportTicketIdSchema.extend({ assigned_to: z.number().int().positive() });
32
35
  export const SupportTicketReplySchema = SupportTicketIdSchema.extend({ message: z.string().trim().min(1).max(4000) });
36
+ // In-app "report a problem" button (create event, create ad, KYC, login)
37
+ export const SupportReportScreenSchema = z.enum(['event.new', 'ad.new', 'kyc', 'auth.login']);
38
+ export const SupportReportReasonSchema = z.enum(['blocked', 'error_message', 'slow', 'other']);
39
+ export const SupportReportAttachmentSchema = z.object({
40
+ url: z.string().trim().url().max(500),
41
+ id: z.number().int().positive().nullable().optional(),
42
+ mimetype: z.string().max(80).nullable().optional(),
43
+ width: z.number().nonnegative().nullable().optional(),
44
+ height: z.number().nonnegative().nullable().optional(),
45
+ });
46
+ export const SupportReportRequestLogSchema = z.object({
47
+ at: z.string(),
48
+ method: z.string().max(10),
49
+ path: z.string().max(300),
50
+ status: z.number().int().nullable(),
51
+ ms: z.number().nullable().optional(),
52
+ message: z.string().max(300).nullable().optional(),
53
+ });
54
+ export const SupportReportErrorLogSchema = z.object({
55
+ at: z.string(),
56
+ source: z.string().max(40),
57
+ message: z.string().max(500),
58
+ });
59
+ export const SupportReportContextSchema = z.object({
60
+ screen: z.object({ route: z.string().max(200), step: z.union([z.string(), z.number()]).nullable().optional(), ids: z.record(z.string(), z.union([z.string(), z.number(), z.null()])).optional(), error_fields: z.array(z.string()).optional() }).optional(),
61
+ device: z.record(z.string(), z.any()).optional(),
62
+ app: z.record(z.string(), z.any()).optional(),
63
+ requests: z.array(SupportReportRequestLogSchema).max(50).optional(),
64
+ errors: z.array(SupportReportErrorLogSchema).max(50).optional(),
65
+ }).passthrough();
66
+ export const SupportReportCreateSchema = z.object({
67
+ description: z.string().trim().min(5).max(5000),
68
+ screen: SupportReportScreenSchema,
69
+ reason: SupportReportReasonSchema.default('other'),
70
+ phone: z.string().trim().min(8).max(30).nullable().optional(),
71
+ device_id: z.string().trim().max(80).nullable().optional(),
72
+ platform: z.string().trim().max(20).nullable().optional(),
73
+ app_version: z.string().trim().max(60).nullable().optional(),
74
+ ad_id: z.number().int().positive().nullable().optional(),
75
+ context: SupportReportContextSchema.nullable().optional(),
76
+ attachments: z.array(SupportReportAttachmentSchema).max(3).optional(),
77
+ });
@@ -1,11 +1,16 @@
1
1
  import { z } from "zod";
2
2
  import { saveEventTimelineSchema } from "./EventTimeline.schema.js";
3
3
  import { saveEventWeddingSchema } from "./EventWedding.schema.js";
4
- import { EVENT_CUSTOMIZATION_TEXT_MAX, EventCustomizationFontValues, EventCustomizationPaletteValues, EventCustomizationSectionValues, EventCustomizationTrackValues, EventInvitationScanTypeValues, EventPublishPaymentMethodValues, } from "../../constants/events/index.js";
4
+ import { saveEventBirthdaySchema } from "./EventBirthday.schema.js";
5
+ import { saveEventOccasionSchema } from "./EventOccasion.schema.js";
6
+ import { eventPersonInputSchema } from "./EventHost.schema.js";
7
+ import { EVENT_CUSTOMIZATION_TEXT_MAX, EVENT_DRESS_CODE_NOTE_MAX, EVENT_EXPECTED_GUESTS_MAX, EVENT_EXPECTED_GUESTS_MIN, EventDressCodeColorModeValues, EventDressCodeColorValues, EventDressCodeStyleValues, EventCustomizationFontValues, EventCustomizationOpeningValues, EventCustomizationPaletteValues, EventCustomizationSectionValues, EventCustomizationTrackValues, EventInvitationScanTypeValues, EventPublishPaymentMethodValues, EventVisibilityValues, } from "../../constants/events/index.js";
8
+ import { BLOCKED_RELIGIOUS_TEXT_MESSAGE, hasBlockedReligiousText } from "../../constants/events/EventTextPolicy.js";
5
9
  const customizationText = z
6
10
  .string()
7
11
  .trim()
8
12
  .max(EVENT_CUSTOMIZATION_TEXT_MAX)
13
+ .refine((v) => !hasBlockedReligiousText(v), { message: BLOCKED_RELIGIOUS_TEXT_MESSAGE.ar })
9
14
  .transform((v) => (v.length ? v : null))
10
15
  .nullable()
11
16
  .optional();
@@ -19,6 +24,32 @@ export const eventCustomizationSchema = z.object({
19
24
  welcome_message: customizationText,
20
25
  rsvp_message: customizationText,
21
26
  music: z.enum(EventCustomizationTrackValues).nullable().optional(),
27
+ opening: z.enum(EventCustomizationOpeningValues).nullable().optional(),
28
+ auto_scroll: z.boolean().nullable().optional(),
29
+ });
30
+ export const eventDressCodeSchema = z.object({
31
+ style: z.enum(EventDressCodeStyleValues).nullable().optional(),
32
+ /** Colours guests are asked to wear (any number) */
33
+ colors: z
34
+ .array(z.enum(EventDressCodeColorValues))
35
+ .transform((v) => Array.from(new Set(v)))
36
+ .nullable()
37
+ .optional(),
38
+ /** Colours guests should not wear (any number) */
39
+ avoid_colors: z
40
+ .array(z.enum(EventDressCodeColorValues))
41
+ .transform((v) => Array.from(new Set(v)))
42
+ .nullable()
43
+ .optional(),
44
+ color_mode: z.enum(EventDressCodeColorModeValues).nullable().optional(),
45
+ note: z
46
+ .string()
47
+ .trim()
48
+ .max(EVENT_DRESS_CODE_NOTE_MAX)
49
+ .refine((v) => !hasBlockedReligiousText(v), { message: BLOCKED_RELIGIOUS_TEXT_MESSAGE.ar })
50
+ .transform((v) => (v.length ? v : null))
51
+ .nullable()
52
+ .optional(),
22
53
  });
23
54
  export const eventBaseSchema = z.object({
24
55
  lat: z.coerce.number().optional().nullable(),
@@ -28,14 +59,26 @@ export const eventBaseSchema = z.object({
28
59
  is_published: z.boolean().optional(),
29
60
  slug: z.string().trim().min(1).max(255),
30
61
  wedding: saveEventWeddingSchema,
62
+ /** @deprecated birthdays are saved in `occasion` since 2026-11 */
63
+ birthday: saveEventBirthdaySchema.nullable().optional(),
64
+ /** Details of occasion types (birthday, graduation, newborn, ...) */
65
+ occasion: saveEventOccasionSchema.nullable().optional(),
31
66
  timeline: saveEventTimelineSchema,
32
67
  event_type: z.string().trim().max(255).nullable().optional(),
33
68
  event_template: z.string().trim().max(255).nullable().optional(),
34
69
  venue_id: z.coerce.number().int().positive().nullable().optional(),
35
70
  venue_name: z.string().trim().max(255).nullable().optional(),
36
71
  location_label: z.string().trim().nullable().optional(),
72
+ /** Expected number of guests; the app asks for it on every new event (old events may have none) */
73
+ expected_guests: z.coerce.number().int().min(EVENT_EXPECTED_GUESTS_MIN).max(EVENT_EXPECTED_GUESTS_MAX).nullable().optional(),
37
74
  invitation_scan_type: z.enum(EventInvitationScanTypeValues).optional(),
38
75
  customization: eventCustomizationSchema.nullable().optional(),
76
+ dress_code: eventDressCodeSchema.nullable().optional(),
77
+ visibility: z.enum(EventVisibilityValues).optional(),
78
+ /** «من أنت في هذه المناسبة؟»: a slot key of the type, "company" or "other" */
79
+ creator_role: z.string().trim().max(40).nullable().optional(),
80
+ /** Suggested people of the type (CONSTANTS.EVENTS.EventPeopleSlots) without their own field */
81
+ people: z.array(eventPersonInputSchema).max(20).optional(),
39
82
  });
40
83
  export const createEventSchema = eventBaseSchema;
41
84
  export const updateEventSchema = eventBaseSchema.extend({
@@ -54,7 +97,18 @@ export const eventIdSchema = z.object({
54
97
  });
55
98
  export const getEventsFilterSchema = z.object({
56
99
  is_published: z.boolean().optional(),
100
+ visibility: z.enum(EventVisibilityValues).optional(),
57
101
  search: z.string().trim().optional(),
58
102
  page: z.coerce.number().int().positive().optional(),
59
103
  limit: z.coerce.number().int().positive().max(100).optional(),
60
104
  });
105
+ export const setEventVisibilitySchema = z.object({
106
+ id: z.coerce.number().int().positive(),
107
+ visibility: z.enum(EventVisibilityValues),
108
+ });
109
+ export const publicEventsFilterSchema = z.object({
110
+ venue_id: z.coerce.number().int().positive().optional(),
111
+ company_id: z.coerce.number().int().positive().optional(),
112
+ page: z.coerce.number().int().positive().optional(),
113
+ limit: z.coerce.number().int().positive().max(50).optional(),
114
+ });
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ import { internationalPhoneSchema } from "../common/Phone.schema.js";
3
+ export const EVENT_BIRTHDAY_AGE_MAX = 120;
4
+ export const eventBirthdayBaseSchema = z.object({
5
+ event_id: z.coerce.number().int().positive().optional(),
6
+ cover: z.record(z.string(), z.any()).nullable().optional(),
7
+ celebrant_name: z.string().trim().max(255).nullable().optional(),
8
+ age: z.coerce.number().int().min(1).max(EVENT_BIRTHDAY_AGE_MAX).nullable().optional(),
9
+ host_name: z.string().trim().max(255).nullable().optional(),
10
+ phone: internationalPhoneSchema.nullable().optional(),
11
+ });
12
+ export const saveEventBirthdaySchema = eventBirthdayBaseSchema.extend({
13
+ id: z.coerce.number().int().positive().optional(),
14
+ });
@@ -0,0 +1,41 @@
1
+ import { z } from "zod";
2
+ import { internationalPhoneSchema } from "../common/Phone.schema.js";
3
+ import { EVENT_HOST_LABEL_MAX, EventHostRoleValues } from "../../constants/events/EventHost.js";
4
+ const hostName = z
5
+ .string()
6
+ .trim()
7
+ .max(EVENT_HOST_LABEL_MAX)
8
+ .transform((v) => (v.length ? v : null))
9
+ .nullable()
10
+ .optional();
11
+ /** One suggested person in the create/edit form; an empty phone removes them */
12
+ export const eventPersonInputSchema = z.object({
13
+ slot: z.string().trim().min(1).max(40),
14
+ phone: internationalPhoneSchema.nullable().optional(),
15
+ name: hostName,
16
+ /** Don't tell them or give access before the event ends */
17
+ surprise: z.boolean().optional(),
18
+ });
19
+ /** Add someone to an event by hand */
20
+ export const addEventHostSchema = z.object({
21
+ event_id: z.coerce.number().int().positive(),
22
+ phone: internationalPhoneSchema,
23
+ role: z.enum(EventHostRoleValues),
24
+ /** e.g. «أم العروس» */
25
+ label: hostName,
26
+ name: hostName,
27
+ surprise: z.boolean().optional(),
28
+ });
29
+ export const updateEventHostSchema = z.object({
30
+ host_id: z.coerce.number().int().positive(),
31
+ role: z.enum(EventHostRoleValues).optional(),
32
+ label: hostName,
33
+ name: hostName,
34
+ surprise: z.boolean().optional(),
35
+ });
36
+ export const eventHostIdSchema = z.object({
37
+ host_id: z.coerce.number().int().positive(),
38
+ });
39
+ export const eventHostsListSchema = z.object({
40
+ event_id: z.coerce.number().int().positive(),
41
+ });
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ import { internationalPhoneSchema } from "../common/Phone.schema.js";
3
+ import { EVENT_OCCASION_LONG_TEXT_MAX, EVENT_OCCASION_TEXT_MAX } from "../../constants/events/EventOccasion.js";
4
+ import { EVENT_TEMPLATE_MAX_PHOTOS } from "../../constants/events/EventTemplate.js";
5
+ import { BLOCKED_RELIGIOUS_TEXT_MESSAGE, hasBlockedReligiousText } from "../../constants/events/EventTextPolicy.js";
6
+ const allowedText = (max) => z.string().trim().max(max).refine((v) => !hasBlockedReligiousText(v), { message: BLOCKED_RELIGIOUS_TEXT_MESSAGE.ar });
7
+ const detailValue = z.union([
8
+ allowedText(EVENT_OCCASION_LONG_TEXT_MAX),
9
+ z.number(),
10
+ z.boolean(),
11
+ z.null(),
12
+ ]);
13
+ export const eventOccasionBaseSchema = z.object({
14
+ event_id: z.coerce.number().int().positive().optional(),
15
+ primary_name: z.string().trim().max(EVENT_OCCASION_TEXT_MAX).nullable().optional(),
16
+ secondary_name: z.string().trim().max(EVENT_OCCASION_TEXT_MAX).nullable().optional(),
17
+ host_name: z.string().trim().max(EVENT_OCCASION_TEXT_MAX).nullable().optional(),
18
+ phone: internationalPhoneSchema.nullable().optional(),
19
+ cover: z.record(z.string(), z.any()).nullable().optional(),
20
+ /** Extra pictures after the cover, for designs with several photos */
21
+ /** By slot: an empty slot is null so the next pictures keep their place */
22
+ photos: z.array(z.record(z.string(), z.any()).nullable()).max(EVENT_TEMPLATE_MAX_PHOTOS - 1).nullable().optional(),
23
+ /** Keys come from the type's config; the API keeps only known keys */
24
+ details: z.record(z.string().max(64), detailValue).nullable().optional(),
25
+ });
26
+ export const saveEventOccasionSchema = eventOccasionBaseSchema.extend({
27
+ id: z.coerce.number().int().positive().optional(),
28
+ });
@@ -12,6 +12,7 @@ export const eventRsvpBaseSchema = z.object({
12
12
  attendance_status: z.enum(attendanceStatusValues),
13
13
  guest_count: z.coerce.number().int().positive().max(100).default(1),
14
14
  message: z.string().trim().max(5000).nullable().optional(),
15
+ answers: z.record(z.string().max(64), z.union([z.string().max(100), z.number(), z.boolean()])).nullable().optional(),
15
16
  responded_at: z.iso.datetime().optional(),
16
17
  });
17
18
  export const createEventRsvpSchema = eventRsvpBaseSchema;
@@ -1,7 +1,20 @@
1
1
  import { z } from 'zod';
2
+ import { BLOCKED_RELIGIOUS_TEXT_MESSAGE, hasBlockedReligiousText } from '../../constants/events/EventTextPolicy.js';
2
3
  export const timelinePayloadSchema = z.object({
3
- title: z.string().trim().min(1).max(255),
4
+ title: z
5
+ .string()
6
+ .trim()
7
+ .min(1)
8
+ .max(255)
9
+ .refine((v) => !hasBlockedReligiousText(v), { message: BLOCKED_RELIGIOUS_TEXT_MESSAGE.ar }),
4
10
  start_time: z.string().trim().regex(/^([01]\d|2[0-3]):([0-5]\d)$/),
11
+ place: z
12
+ .string()
13
+ .trim()
14
+ .max(255)
15
+ .refine((v) => !hasBlockedReligiousText(v), { message: BLOCKED_RELIGIOUS_TEXT_MESSAGE.ar })
16
+ .nullable()
17
+ .optional(),
5
18
  });
6
19
  export const eventTimelineBaseSchema = z.object({
7
20
  event_id: z.coerce.number().int().positive().optional(),
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { internationalPhoneSchema } from "../common/Phone.schema.js";
3
+ import { EVENT_WEDDING_CUSTOM_VERSE_MAX, EventWeddingReligionValues, EventWeddingVerseValues, } from "../../constants/events/EventWeddingReligion.js";
4
+ import { BLOCKED_RELIGIOUS_TEXT_MESSAGE, hasBlockedReligiousText } from "../../constants/events/EventTextPolicy.js";
3
5
  export const eventWeddingBaseSchema = z.object({
4
6
  event_id: z.coerce.number().int().positive().optional(),
5
7
  cover: z.record(z.string(), z.any()).nullable().optional(),
@@ -9,6 +11,15 @@ export const eventWeddingBaseSchema = z.object({
9
11
  last_groom_name: z.string().trim().max(255).nullable().optional(),
10
12
  bride_phone: internationalPhoneSchema.nullable().optional(),
11
13
  groom_phone: internationalPhoneSchema.nullable().optional(),
14
+ religion: z.enum(EventWeddingReligionValues).nullable().optional(),
15
+ verse_key: z.enum(EventWeddingVerseValues).nullable().optional(),
16
+ custom_verse: z
17
+ .string()
18
+ .trim()
19
+ .max(EVENT_WEDDING_CUSTOM_VERSE_MAX)
20
+ .refine((v) => !hasBlockedReligiousText(v), { message: BLOCKED_RELIGIOUS_TEXT_MESSAGE.ar })
21
+ .nullable()
22
+ .optional(),
12
23
  });
13
24
  export const createEventWeddingSchema = eventWeddingBaseSchema;
14
25
  export const updateEventWeddingSchema = eventWeddingBaseSchema.extend({
@@ -2,5 +2,8 @@ export * from "./Event.schema.js";
2
2
  export * from "./EventRsvp.schema.js";
3
3
  export * from "./EventTimeline.schema.js";
4
4
  export * from "./EventWedding.schema.js";
5
+ export * from "./EventBirthday.schema.js";
6
+ export * from "./EventOccasion.schema.js";
5
7
  export * from "./EventVenue.schema.js";
6
8
  export { internationalPhoneSchema } from "../common/Phone.schema.js";
9
+ export * from "./EventHost.schema.js";
@@ -15,6 +15,16 @@ export var NotificationTypeEnum;
15
15
  NotificationTypeEnum["POINTS_EARNED"] = "points_earned";
16
16
  /** Sent by Deallony from the dashboard */
17
17
  NotificationTypeEnum["DEALLONY_NEWS"] = "deallony_news";
18
+ /** A guest opened their personal invitation or replied to it */
19
+ NotificationTypeEnum["EVENT_GUESTS"] = "event_guests";
20
+ /** Someone added the user to an event (to accept) */
21
+ NotificationTypeEnum["EVENT_HOST_ADDED"] = "event_host_added";
22
+ /** A person the owner added accepted and joined */
23
+ NotificationTypeEnum["EVENT_HOST_JOINED"] = "event_host_joined";
24
+ /** The user no longer has access to an event */
25
+ NotificationTypeEnum["EVENT_HOST_REMOVED"] = "event_host_removed";
26
+ /** New ads match one of the user's saved searches */
27
+ NotificationTypeEnum["SAVED_SEARCH"] = "saved_search";
18
28
  })(NotificationTypeEnum || (NotificationTypeEnum = {}));
19
29
  /** How the centre groups types for its filter chips and settings */
20
30
  export var NotificationCategoryEnum;
@@ -23,6 +33,8 @@ export var NotificationCategoryEnum;
23
33
  NotificationCategoryEnum["MY_ADS"] = "my_ads";
24
34
  NotificationCategoryEnum["POINTS"] = "points";
25
35
  NotificationCategoryEnum["DEALLONY"] = "deallony";
36
+ NotificationCategoryEnum["EVENTS"] = "events";
37
+ NotificationCategoryEnum["SAVED_SEARCHES"] = "saved_searches";
26
38
  })(NotificationCategoryEnum || (NotificationCategoryEnum = {}));
27
39
  export const NOTIFICATION_CATEGORY = {
28
40
  [NotificationTypeEnum.FAVORITE_PRICE_DROP]: NotificationCategoryEnum.FAVORITES,
@@ -34,4 +46,9 @@ export const NOTIFICATION_CATEGORY = {
34
46
  [NotificationTypeEnum.AD_SAVED]: NotificationCategoryEnum.MY_ADS,
35
47
  [NotificationTypeEnum.POINTS_EARNED]: NotificationCategoryEnum.POINTS,
36
48
  [NotificationTypeEnum.DEALLONY_NEWS]: NotificationCategoryEnum.DEALLONY,
49
+ [NotificationTypeEnum.EVENT_GUESTS]: NotificationCategoryEnum.EVENTS,
50
+ [NotificationTypeEnum.EVENT_HOST_ADDED]: NotificationCategoryEnum.EVENTS,
51
+ [NotificationTypeEnum.EVENT_HOST_JOINED]: NotificationCategoryEnum.EVENTS,
52
+ [NotificationTypeEnum.EVENT_HOST_REMOVED]: NotificationCategoryEnum.EVENTS,
53
+ [NotificationTypeEnum.SAVED_SEARCH]: NotificationCategoryEnum.SAVED_SEARCHES,
37
54
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -2,4 +2,8 @@ export * from './Event.js';
2
2
  export * from './EventRsvp.js';
3
3
  export * from './EventTimeline.js';
4
4
  export * from './EventWedding.js';
5
+ export * from './EventBirthday.js';
6
+ export * from './EventOccasion.js';
5
7
  export * from './EventCustomization.js';
8
+ export * from "./EventDressCode.js";
9
+ export * from './EventHost.js';
@@ -50,13 +50,17 @@ export * as Event from './events/Event.js';
50
50
  export * as EventRsvp from './events/EventRsvp.js';
51
51
  export * as EventTimeline from './events/EventTimeline.js';
52
52
  export * as EventWedding from './events/EventWedding.js';
53
+ export * as EventBirthday from './events/EventBirthday.js';
54
+ export * as EventOccasion from './events/EventOccasion.js';
53
55
  export * as EventVenue from './events/EventVenue.js';
56
+ export * as EventHost from './events/EventHost.js';
54
57
  // user
55
58
  export * as User from "./user/User.js";
56
59
  export * as Role from "./user/Role.js";
57
60
  export * as Permission from "./user/Permission.js";
58
61
  export * as Wallet from "./user/Wallet.js";
59
62
  export * as Favorite from "./user/Favorite.js";
63
+ export * as SavedSearch from "./user/SavedSearch.js";
60
64
  export * as Loyalty from "./user/Loyalty.js";
61
65
  export * as PotentialUser from "./user/PotentialUser.js";
62
66
  export * as Company from './company/Company.js';
@@ -0,0 +1,8 @@
1
+ /** How often a saved search alerts: as new ads come in, or one summary each morning */
2
+ export var SavedSearchFrequency;
3
+ (function (SavedSearchFrequency) {
4
+ SavedSearchFrequency["INSTANT"] = "instant";
5
+ SavedSearchFrequency["DAILY"] = "daily";
6
+ })(SavedSearchFrequency || (SavedSearchFrequency = {}));
7
+ /** Most saved searches one user can keep */
8
+ export const SAVED_SEARCH_LIMIT = 20;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deallony/shared",
3
- "version": "1.2.80",
3
+ "version": "1.2.82",
4
4
  "private": false,
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",