@deallony/shared 1.2.81 → 1.2.83

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 (69) hide show
  1. package/dist/cjs/constants/events/EventCustomization.d.ts +18 -0
  2. package/dist/cjs/constants/events/EventCustomization.js +21 -1
  3. package/dist/cjs/constants/events/EventGuests.d.ts +3 -0
  4. package/dist/cjs/constants/events/EventGuests.js +6 -0
  5. package/dist/cjs/constants/events/EventHost.d.ts +79 -0
  6. package/dist/cjs/constants/events/EventHost.js +155 -0
  7. package/dist/cjs/constants/events/EventTemplate.js +3 -3
  8. package/dist/cjs/constants/events/EventType.d.ts +21 -90
  9. package/dist/cjs/constants/events/EventType.js +15 -8
  10. package/dist/cjs/constants/events/EventWeddingReligion.d.ts +10 -5
  11. package/dist/cjs/constants/events/EventWeddingReligion.js +12 -27
  12. package/dist/cjs/constants/events/index.d.ts +2 -0
  13. package/dist/cjs/constants/events/index.js +2 -0
  14. package/dist/cjs/constants/routes/app.d.ts +21 -0
  15. package/dist/cjs/constants/routes/app.js +6 -0
  16. package/dist/cjs/dto/events/EventHost.dto.d.ts +7 -0
  17. package/dist/cjs/dto/events/EventHost.dto.js +2 -0
  18. package/dist/cjs/dto/events/index.d.ts +1 -0
  19. package/dist/cjs/dto/events/index.js +1 -0
  20. package/dist/cjs/schema/communication/ai-conversation.schema.d.ts +4 -2
  21. package/dist/cjs/schema/communication/offer.schema.d.ts +3 -3
  22. package/dist/cjs/schema/events/Event.schema.d.ts +70 -0
  23. package/dist/cjs/schema/events/Event.schema.js +34 -0
  24. package/dist/cjs/schema/events/EventHost.schema.d.ts +36 -0
  25. package/dist/cjs/schema/events/EventHost.schema.js +44 -0
  26. package/dist/cjs/schema/events/index.d.ts +1 -0
  27. package/dist/cjs/schema/events/index.js +1 -0
  28. package/dist/cjs/types/ad/Ad.d.ts +2 -0
  29. package/dist/cjs/types/communication/Notification.d.ts +12 -0
  30. package/dist/cjs/types/communication/Notification.js +15 -0
  31. package/dist/cjs/types/events/Event.d.ts +28 -0
  32. package/dist/cjs/types/events/EventCustomization.d.ts +11 -0
  33. package/dist/cjs/types/events/EventDay.d.ts +89 -0
  34. package/dist/cjs/types/events/EventDay.js +2 -0
  35. package/dist/cjs/types/events/EventHost.d.ts +29 -0
  36. package/dist/cjs/types/events/EventHost.js +2 -0
  37. package/dist/cjs/types/events/EventInvited.d.ts +25 -0
  38. package/dist/cjs/types/events/EventInvited.js +2 -0
  39. package/dist/cjs/types/events/EventRsvp.d.ts +12 -1
  40. package/dist/cjs/types/events/index.d.ts +3 -0
  41. package/dist/cjs/types/events/index.js +3 -0
  42. package/dist/cjs/types/index.d.ts +3 -0
  43. package/dist/cjs/types/index.js +5 -2
  44. package/dist/cjs/utils/adSeoTitle.d.ts +35 -0
  45. package/dist/cjs/utils/adSeoTitle.js +26 -0
  46. package/dist/cjs/utils/index.d.ts +1 -0
  47. package/dist/cjs/utils/index.js +1 -0
  48. package/dist/esm/constants/events/EventCustomization.js +20 -0
  49. package/dist/esm/constants/events/EventGuests.js +3 -0
  50. package/dist/esm/constants/events/EventHost.js +147 -0
  51. package/dist/esm/constants/events/EventTemplate.js +3 -3
  52. package/dist/esm/constants/events/EventType.js +14 -7
  53. package/dist/esm/constants/events/EventWeddingReligion.js +11 -26
  54. package/dist/esm/constants/events/index.js +2 -0
  55. package/dist/esm/constants/routes/app.js +6 -0
  56. package/dist/esm/dto/events/EventHost.dto.js +1 -0
  57. package/dist/esm/dto/events/index.js +1 -0
  58. package/dist/esm/schema/events/Event.schema.js +35 -1
  59. package/dist/esm/schema/events/EventHost.schema.js +41 -0
  60. package/dist/esm/schema/events/index.js +1 -0
  61. package/dist/esm/types/communication/Notification.js +15 -0
  62. package/dist/esm/types/events/EventDay.js +1 -0
  63. package/dist/esm/types/events/EventHost.js +1 -0
  64. package/dist/esm/types/events/EventInvited.js +1 -0
  65. package/dist/esm/types/events/index.js +3 -0
  66. package/dist/esm/types/index.js +3 -0
  67. package/dist/esm/utils/adSeoTitle.js +23 -0
  68. package/dist/esm/utils/index.js +1 -0
  69. package/package.json +1 -1
@@ -22,9 +22,9 @@ export const EventTemplate = {
22
22
  ENGAGEMENT_ROSE_ARCH: { value: 'engagement-rose-arch', name: { en: 'Rose arch', ar: 'قوس الورد' }, event_types: ['engagement'], photos: 1 },
23
23
  ENGAGEMENT_FULL_MOMENT: { value: 'engagement-full-moment', name: { en: 'Full moment', ar: 'لحظة كاملة' }, event_types: ['engagement'], photos: 1 },
24
24
  ENGAGEMENT_SEALED_LETTER: { value: 'engagement-sealed-letter', name: { en: 'Sealed letter', ar: 'رسالة مختومة' }, event_types: ['engagement'], photos: 1 },
25
- MARRIAGE_CONTRACT: { value: 'marriage-contract', name: { en: 'The contract', ar: 'وثيقة العقد' }, event_types: ['marriage'], photos: 1 },
26
- MARRIAGE_STAR_MEDALLION: { value: 'marriage-star-medallion', name: { en: 'Star medallion', ar: 'ميدالية النجمة' }, event_types: ['marriage'], photos: 1 },
27
- MARRIAGE_MASHRABIYA: { value: 'marriage-mashrabiya', name: { en: 'Mashrabiya', ar: 'نافذة المشربية' }, event_types: ['marriage'], photos: 1 },
25
+ MARRIAGE_CONTRACT: { value: 'marriage-contract', name: { en: 'The contract', ar: 'وثيقة العقد' }, event_types: ['wedding', 'marriage'], photos: 1 },
26
+ MARRIAGE_STAR_MEDALLION: { value: 'marriage-star-medallion', name: { en: 'Star medallion', ar: 'ميدالية النجمة' }, event_types: ['wedding', 'marriage'], photos: 1 },
27
+ MARRIAGE_MASHRABIYA: { value: 'marriage-mashrabiya', name: { en: 'Mashrabiya', ar: 'نافذة المشربية' }, event_types: ['wedding', 'marriage'], photos: 1 },
28
28
  PROPOSAL_ONE_QUESTION: { value: 'proposal-one-question', name: { en: 'One question', ar: 'سؤال واحد' }, event_types: ['proposal'], photos: 1 },
29
29
  PROPOSAL_WITNESS_TICKET: { value: 'proposal-witness-ticket', name: { en: 'Witness ticket', ar: 'تذكرة شاهد' }, event_types: ['proposal'], photos: 1 },
30
30
  PROPOSAL_CANDLELIGHT: { value: 'proposal-candlelight', name: { en: 'Candlelight', ar: 'ضوء الشموع' }, event_types: ['proposal'], photos: 1 },
@@ -12,7 +12,8 @@ export const EventTypeGroups = {
12
12
  export const EventTypes = {
13
13
  WEDDING: { value: 'wedding', name: { en: 'Wedding', ar: 'زفاف' }, group: 'celebrations', details: 'wedding' },
14
14
  ENGAGEMENT: { value: 'engagement', name: { en: 'Engagement', ar: 'حفلة خطبة' }, group: 'celebrations', details: 'wedding' },
15
- MARRIAGE: { value: 'marriage', name: { en: 'Marriage contract', ar: 'حفل زواج' }, group: 'celebrations', details: 'wedding' },
15
+ /** Folded into the wedding (2026-11): no longer offered, kept so saved events still open */
16
+ MARRIAGE: { value: 'marriage', name: { en: 'Marriage contract', ar: 'حفل زواج' }, group: 'celebrations', details: 'wedding', hidden: true },
16
17
  PROPOSAL: { value: 'proposal', name: { en: 'Proposal', ar: 'حفل Proposal' }, group: 'celebrations', details: 'occasion' },
17
18
  BACHELOR: { value: 'bachelor', name: { en: 'Bachelor party', ar: 'حفل توديع عزوبية' }, group: 'celebrations', details: 'occasion' },
18
19
  BIRTHDAY: { value: 'birthday', name: { en: 'Birthday', ar: 'عيد ميلاد' }, group: 'family', details: 'occasion' },
@@ -27,12 +28,18 @@ export const EventTypes = {
27
28
  GENERAL: { value: 'general', name: { en: 'General party', ar: 'حفلة عامة' }, group: 'business', details: 'occasion' },
28
29
  };
29
30
  export const EventTypeValues = Object.values(EventTypes).map((t) => t.value);
30
- export const EventTypeOptions = Object.values(EventTypes).map((type) => ({
31
- value: type.value,
32
- name: type.name,
33
- group: type.group,
34
- details: type.details,
35
- }));
31
+ export const EventTypeOptions = Object.values(EventTypes).map((type) => {
32
+ var _a;
33
+ return ({
34
+ value: type.value,
35
+ name: type.name,
36
+ group: type.group,
37
+ details: type.details,
38
+ hidden: (_a = type.hidden) !== null && _a !== void 0 ? _a : false,
39
+ });
40
+ });
41
+ /** Types offered when creating an invitation (hidden ones are left out) */
42
+ export const EventTypeOfferedOptions = EventTypeOptions.filter((t) => !t.hidden);
36
43
  export const findEventType = (value) => { var _a; return (_a = EventTypeOptions.find((t) => t.value === (value || 'wedding'))) !== null && _a !== void 0 ? _a : null; };
37
44
  /** Types whose details are a couple stored in event.wedding (events without a type are weddings) */
38
45
  export const isCoupleEventType = (value) => { var _a, _b; return ((_b = (_a = findEventType(value)) === null || _a === void 0 ? void 0 : _a.details) !== null && _b !== void 0 ? _b : 'wedding') === 'wedding'; };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Invitation style of a wedding (also used by engagement and marriage, which share event.wedding).
3
- * muslim = the Islamic opening, Quran verse and dua (the original templates).
3
+ * muslim = the Islamic opening (bismillah) and dua. No Quran excerpt (removed 2026-11-08 by owner request).
4
4
  * general = social congratulations only: names, place, date, program. Suits Christian weddings.
5
5
  *
6
6
  * Content rule (owner decision 2026-11-04): no Christian religious symbols, creeds, Bible verses or rites
@@ -16,8 +16,8 @@ export const EventWeddingReligionNames = {
16
16
  muslim: {
17
17
  en: "Islamic",
18
18
  ar: "إسلامي",
19
- hint_en: "Bismillah, a Quran verse and a dua.",
20
- hint_ar: "البسملة وآية قرآنية ودعاء للعروسين.",
19
+ hint_en: "Bismillah and a dua for the couple.",
20
+ hint_ar: "البسملة ودعاء للعروسين.",
21
21
  },
22
22
  general: {
23
23
  en: "General",
@@ -31,27 +31,6 @@ export const EventWeddingReligionOptions = EventWeddingReligionValues.map((value
31
31
  name: EventWeddingReligionNames[value],
32
32
  }));
33
33
  export const EventWeddingVerses = [
34
- {
35
- value: "rum-21",
36
- religion: "muslim",
37
- text: "﴿ وَمِنْ آيَاتِهِ أَنْ خَلَقَ لَكُمْ مِنْ أَنْفُسِكُمْ أَزْوَاجًا لِتَسْكُنُوا إِلَيْهَا وَجَعَلَ بَيْنَكُمْ مَوَدَّةً وَرَحْمَةً ﴾",
38
- reference: "سورة الروم - آية ٢١",
39
- label: { en: "Ar-Rum 21", ar: "سورة الروم - آية ٢١" },
40
- },
41
- {
42
- value: "furqan-74",
43
- religion: "muslim",
44
- text: "﴿ رَبَّنَا هَبْ لَنَا مِنْ أَزْوَاجِنَا وَذُرِّيَّاتِنَا قُرَّةَ أَعْيُنٍ وَاجْعَلْنَا لِلْمُتَّقِينَ إِمَامًا ﴾",
45
- reference: "سورة الفرقان - آية ٧٤",
46
- label: { en: "Al-Furqan 74", ar: "سورة الفرقان - آية ٧٤" },
47
- },
48
- {
49
- value: "rum-mawadda",
50
- religion: "muslim",
51
- text: "﴿ وَجَعَلَ بَيْنَكُم مَّوَدَّةً وَرَحْمَةً ﴾",
52
- reference: "سورة الروم",
53
- label: { en: "Mawadda wa rahma", ar: "وجعل بينكم مودة ورحمة" },
54
- },
55
34
  {
56
35
  value: "together",
57
36
  religion: "general",
@@ -77,9 +56,15 @@ export const EventWeddingVerses = [
77
56
  /** General style only: the owner writes the couple's words by hand (event.wedding.custom_verse) */
78
57
  export const EVENT_WEDDING_CUSTOM_VERSE = "custom";
79
58
  export const EVENT_WEDDING_CUSTOM_VERSE_MAX = 160;
59
+ /**
60
+ * Quran excerpt keys from before 2026-11-08. Still accepted so older apps can save,
61
+ * but the backend drops them and no invitation shows them any more.
62
+ */
63
+ export const EVENT_WEDDING_LEGACY_VERSE_KEYS = ["rum-21", "furqan-74", "rum-mawadda"];
80
64
  export const EventWeddingVerseValues = [
81
65
  EVENT_WEDDING_CUSTOM_VERSE,
82
66
  ...EventWeddingVerses.map((v) => v.value),
67
+ ...EVENT_WEDDING_LEGACY_VERSE_KEYS,
83
68
  ];
84
69
  /** The hand-written text applies only to the general style */
85
70
  export const eventWeddingCustomVerse = (verseKey, religion, customVerse) => verseKey === EVENT_WEDDING_CUSTOM_VERSE && normalizeEventWeddingReligion(religion) === "general"
@@ -88,7 +73,7 @@ export const eventWeddingCustomVerse = (verseKey, religion, customVerse) => vers
88
73
  export const EventWeddingReligionTextsMap = {
89
74
  muslim: {
90
75
  opening: "بسم الله الرحمن الرحيم",
91
- verse_title: "مقتطف قرآني مبارك",
76
+ verse_title: null,
92
77
  blessing: "اللهم بارك لهما وبارك عليهما واجمع بينهما في خير، واجعل أيامهما مودة ورحمة وسكينة.",
93
78
  blessing_title: "دعاء",
94
79
  symbol: "۞",
@@ -109,7 +94,7 @@ export const normalizeEventWeddingReligion = (value) => EventWeddingReligionValu
109
94
  ? value
110
95
  : DEFAULT_EVENT_WEDDING_RELIGION;
111
96
  export const eventWeddingVersesFor = (religion) => EventWeddingVerses.filter((v) => v.religion === normalizeEventWeddingReligion(religion));
112
- /** The saved verse when it belongs to the style, otherwise the style's first one */
97
+ /** The saved phrase when it belongs to the style, otherwise the style's first one (undefined for muslim) */
113
98
  export const findEventWeddingVerse = (value, religion) => {
114
99
  var _a;
115
100
  const list = eventWeddingVersesFor(religion);
@@ -13,3 +13,5 @@ export * from "./EventVisibility.js";
13
13
  export * from "./EventWeddingReligion.js";
14
14
  export * from "./EventTextPolicy.js";
15
15
  export * from "./EventDressCode.js";
16
+ export * from "./EventHost.js";
17
+ export * from "./EventGuests.js";
@@ -203,10 +203,16 @@ export const APP_ROUTES = {
203
203
  newOfType: (eventType) => ({ pathname: "/event/new", params: { personal: "1", event_type: eventType } }),
204
204
  start: () => ({ pathname: "/event/start" }),
205
205
  mine: () => ({ pathname: "/event/mine" }),
206
+ /** «دعواتي»: the events the user was invited to, as a chip of «مناسباتي» */
207
+ invitations: () => ({ pathname: "/event/mine", params: { tab: "invited" } }),
208
+ /** One event the user was invited to, as a guest sees it */
209
+ invited: (eventId) => ({ pathname: "/event/invited/[id]", params: { id: eventId } }),
206
210
  /** Upcoming public events (optionally of one venue) */
207
211
  upcoming: (venueId) => venueId ? { pathname: "/event/upcoming", params: { venue_id: venueId } } : { pathname: "/event/upcoming" },
208
212
  publish: (id) => ({ pathname: "/event/publish/[id]", params: { id } }),
209
213
  edit: (id) => ({ pathname: "/event/new", params: { id } }),
210
214
  details: (id) => ({ pathname: "/event/details/[id]", params: { id } }),
215
+ /** People of the event (owner, organisers, guest managers) */
216
+ hosts: (id) => ({ pathname: "/event/hosts/[id]", params: { id } }),
211
217
  },
212
218
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -5,3 +5,4 @@ export * from './EventWedding.dto.js';
5
5
  export * from './EventBirthday.dto.js';
6
6
  export * from './EventOccasion.dto.js';
7
7
  export * from './EventVenue.dto.js';
8
+ export * from './EventHost.dto.js';
@@ -3,7 +3,8 @@ import { saveEventTimelineSchema } from "./EventTimeline.schema.js";
3
3
  import { saveEventWeddingSchema } from "./EventWedding.schema.js";
4
4
  import { saveEventBirthdaySchema } from "./EventBirthday.schema.js";
5
5
  import { saveEventOccasionSchema } from "./EventOccasion.schema.js";
6
- import { EVENT_CUSTOMIZATION_TEXT_MAX, EVENT_DRESS_CODE_NOTE_MAX, EventDressCodeColorModeValues, EventDressCodeColorValues, EventDressCodeStyleValues, EventCustomizationFontValues, EventCustomizationOpeningValues, EventCustomizationPaletteValues, EventCustomizationSectionValues, EventCustomizationTrackValues, EventInvitationScanTypeValues, EventPublishPaymentMethodValues, EventVisibilityValues, } from "../../constants/events/index.js";
6
+ import { eventPersonInputSchema } from "./EventHost.schema.js";
7
+ import { EVENT_CUSTOMIZATION_TEXT_MAX, EVENT_ATTENDANCE_TEXT_MAX, EVENT_COVER_VIDEO_MAX_BYTES, EVENT_COVER_VIDEO_MAX_SECONDS, 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";
7
8
  import { BLOCKED_RELIGIOUS_TEXT_MESSAGE, hasBlockedReligiousText } from "../../constants/events/EventTextPolicy.js";
8
9
  const customizationText = z
9
10
  .string()
@@ -13,6 +14,15 @@ const customizationText = z
13
14
  .transform((v) => (v.length ? v : null))
14
15
  .nullable()
15
16
  .optional();
17
+ /** Owner's own wording for the children / food line on the invitation; empty keeps the default */
18
+ const attendanceText = z
19
+ .string()
20
+ .trim()
21
+ .max(EVENT_ATTENDANCE_TEXT_MAX)
22
+ .refine((v) => !hasBlockedReligiousText(v), { message: BLOCKED_RELIGIOUS_TEXT_MESSAGE.ar })
23
+ .transform((v) => (v.length ? v : null))
24
+ .nullable()
25
+ .optional();
16
26
  export const eventCustomizationSchema = z.object({
17
27
  palette: z.enum(EventCustomizationPaletteValues).nullable().optional(),
18
28
  font: z.enum(EventCustomizationFontValues).nullable().optional(),
@@ -22,9 +32,23 @@ export const eventCustomizationSchema = z.object({
22
32
  .optional(),
23
33
  welcome_message: customizationText,
24
34
  rsvp_message: customizationText,
35
+ children_message: attendanceText,
36
+ food_message: attendanceText,
25
37
  music: z.enum(EventCustomizationTrackValues).nullable().optional(),
26
38
  opening: z.enum(EventCustomizationOpeningValues).nullable().optional(),
27
39
  auto_scroll: z.boolean().nullable().optional(),
40
+ cover_video: z
41
+ .record(z.string(), z.any())
42
+ .refine((v) => typeof v.url === "string" && v.url.length > 0, { message: "Video URL is missing" })
43
+ .refine((v) => !(Number(v.size) > EVENT_COVER_VIDEO_MAX_BYTES), {
44
+ message: "حجم الفيديو أكبر من 100 ميغابايت",
45
+ })
46
+ .refine((v) => !(Number(v.durationSeconds) > EVENT_COVER_VIDEO_MAX_SECONDS + 1), {
47
+ message: "الفيديو أطول من 60 ثانية",
48
+ })
49
+ .nullable()
50
+ .optional(),
51
+ cover_video_muted: z.boolean().nullable().optional(),
28
52
  });
29
53
  export const eventDressCodeSchema = z.object({
30
54
  style: z.enum(EventDressCodeStyleValues).nullable().optional(),
@@ -68,10 +92,20 @@ export const eventBaseSchema = z.object({
68
92
  venue_id: z.coerce.number().int().positive().nullable().optional(),
69
93
  venue_name: z.string().trim().max(255).nullable().optional(),
70
94
  location_label: z.string().trim().nullable().optional(),
95
+ /** Expected number of guests; the app asks for it on every new event (old events may have none) */
96
+ expected_guests: z.coerce.number().int().min(EVENT_EXPECTED_GUESTS_MIN).max(EVENT_EXPECTED_GUESTS_MAX).nullable().optional(),
71
97
  invitation_scan_type: z.enum(EventInvitationScanTypeValues).optional(),
72
98
  customization: eventCustomizationSchema.nullable().optional(),
73
99
  dress_code: eventDressCodeSchema.nullable().optional(),
100
+ /** Children may come; null for events created before it was asked */
101
+ children_allowed: z.boolean().nullable().optional(),
102
+ /** Food is served; null for events created before it was asked */
103
+ food_included: z.boolean().nullable().optional(),
74
104
  visibility: z.enum(EventVisibilityValues).optional(),
105
+ /** «من أنت في هذه المناسبة؟»: a slot key of the type, "company" or "other" */
106
+ creator_role: z.string().trim().max(40).nullable().optional(),
107
+ /** Suggested people of the type (CONSTANTS.EVENTS.EventPeopleSlots) without their own field */
108
+ people: z.array(eventPersonInputSchema).max(20).optional(),
75
109
  });
76
110
  export const createEventSchema = eventBaseSchema;
77
111
  export const updateEventSchema = eventBaseSchema.extend({
@@ -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
+ });
@@ -6,3 +6,4 @@ export * from "./EventBirthday.schema.js";
6
6
  export * from "./EventOccasion.schema.js";
7
7
  export * from "./EventVenue.schema.js";
8
8
  export { internationalPhoneSchema } from "../common/Phone.schema.js";
9
+ export * from "./EventHost.schema.js";
@@ -17,6 +17,16 @@ export var NotificationTypeEnum;
17
17
  NotificationTypeEnum["DEALLONY_NEWS"] = "deallony_news";
18
18
  /** A guest opened their personal invitation or replied to it */
19
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
+ /** The user is on an event's guest list («دعواتي») */
27
+ NotificationTypeEnum["EVENT_INVITED"] = "event_invited";
28
+ /** A guest's invitation is tomorrow or today («دعواتي») */
29
+ NotificationTypeEnum["EVENT_REMINDER"] = "event_reminder";
20
30
  /** New ads match one of the user's saved searches */
21
31
  NotificationTypeEnum["SAVED_SEARCH"] = "saved_search";
22
32
  })(NotificationTypeEnum || (NotificationTypeEnum = {}));
@@ -41,5 +51,10 @@ export const NOTIFICATION_CATEGORY = {
41
51
  [NotificationTypeEnum.POINTS_EARNED]: NotificationCategoryEnum.POINTS,
42
52
  [NotificationTypeEnum.DEALLONY_NEWS]: NotificationCategoryEnum.DEALLONY,
43
53
  [NotificationTypeEnum.EVENT_GUESTS]: NotificationCategoryEnum.EVENTS,
54
+ [NotificationTypeEnum.EVENT_HOST_ADDED]: NotificationCategoryEnum.EVENTS,
55
+ [NotificationTypeEnum.EVENT_HOST_JOINED]: NotificationCategoryEnum.EVENTS,
56
+ [NotificationTypeEnum.EVENT_HOST_REMOVED]: NotificationCategoryEnum.EVENTS,
57
+ [NotificationTypeEnum.EVENT_INVITED]: NotificationCategoryEnum.EVENTS,
58
+ [NotificationTypeEnum.EVENT_REMINDER]: NotificationCategoryEnum.EVENTS,
44
59
  [NotificationTypeEnum.SAVED_SEARCH]: NotificationCategoryEnum.SAVED_SEARCHES,
45
60
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -6,3 +6,6 @@ export * from './EventBirthday.js';
6
6
  export * from './EventOccasion.js';
7
7
  export * from './EventCustomization.js';
8
8
  export * from "./EventDressCode.js";
9
+ export * from './EventHost.js';
10
+ export * from './EventDay.js';
11
+ export * from './EventInvited.js';
@@ -53,6 +53,9 @@ export * as EventWedding from './events/EventWedding.js';
53
53
  export * as EventBirthday from './events/EventBirthday.js';
54
54
  export * as EventOccasion from './events/EventOccasion.js';
55
55
  export * as EventVenue from './events/EventVenue.js';
56
+ export * as EventHost from './events/EventHost.js';
57
+ export * as EventDay from './events/EventDay.js';
58
+ export * as EventInvited from './events/EventInvited.js';
56
59
  // user
57
60
  export * as User from "./user/User.js";
58
61
  export * as Role from "./user/Role.js";
@@ -0,0 +1,23 @@
1
+ const rtl = (text) => `⁧${text}⁩`;
2
+ const ltr = (text) => `⁦${text}⁩`;
3
+ export function buildAdSeoTitle(ad) {
4
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
5
+ if (!ad)
6
+ return "Deallony";
7
+ const categoryName = (_b = (_a = ad.category) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : undefined;
8
+ let title = ((_c = ad.title) === null || _c === void 0 ? void 0 : _c.trim()) || categoryName;
9
+ if (ad.subject_type === "properties") {
10
+ const offer = (_f = (_e = (_d = ad.property) === null || _d === void 0 ? void 0 : _d.offerType) === null || _e === void 0 ? void 0 : _e.name) === null || _f === void 0 ? void 0 : _f.ar;
11
+ if (offer && categoryName) {
12
+ title = offer + " " + categoryName + " في " + ((_g = ad.adminBoundary) === null || _g === void 0 ? void 0 : _g.name);
13
+ }
14
+ }
15
+ if (ad.subject_type === "motors") {
16
+ const offer = (_k = (_j = (_h = ad.motor) === null || _h === void 0 ? void 0 : _h.offerType) === null || _j === void 0 ? void 0 : _j.name) === null || _k === void 0 ? void 0 : _k.ar;
17
+ if (offer && categoryName) {
18
+ const arabicMain = rtl(`${offer} سيارة في ${(_l = ad.adminBoundary) === null || _l === void 0 ? void 0 : _l.name}`);
19
+ title = `${ltr(categoryName)} | ${arabicMain}`;
20
+ }
21
+ }
22
+ return title || "Deallony";
23
+ }
@@ -3,3 +3,4 @@ export * from './routes.js';
3
3
  export * from './adMedia.js';
4
4
  export * from './analysis.js';
5
5
  export * from './rentPrices.js';
6
+ export * from './adSeoTitle.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deallony/shared",
3
- "version": "1.2.81",
3
+ "version": "1.2.83",
4
4
  "private": false,
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",