@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
@@ -53,6 +53,8 @@ export declare const EventCustomizationSection: {
53
53
  readonly RSVP: "rsvp";
54
54
  readonly MUSIC: "music";
55
55
  readonly DRESS_CODE: "dress_code";
56
+ readonly ATTENDANCE: "attendance";
57
+ readonly VIDEO: "video";
56
58
  };
57
59
  export type EventCustomizationSectionKey = (typeof EventCustomizationSection)[keyof typeof EventCustomizationSection];
58
60
  export declare const EventCustomizationSectionOptions: {
@@ -62,7 +64,23 @@ export declare const EventCustomizationSectionOptions: {
62
64
  ar: string;
63
65
  };
64
66
  }[];
67
+ /** Invitation video (customization.cover_video): one per event, checked in the app before upload */
68
+ export declare const EVENT_COVER_VIDEO_MAX_SECONDS = 60;
69
+ export declare const EVENT_COVER_VIDEO_MAX_BYTES: number;
70
+ export declare const EVENT_COVER_VIDEO_TYPES: readonly ["video/mp4", "video/quicktime", "video/webm", "video/x-m4v"];
65
71
  export declare const EVENT_CUSTOMIZATION_TEXT_MAX = 160;
72
+ /** Children / food line on the invitation: defaults, owner text limit and ready phrases */
73
+ export declare const EVENT_ATTENDANCE_TEXT_MAX = 60;
74
+ export declare const EventAttendanceTexts: {
75
+ readonly children: {
76
+ readonly default: "جنة الأطفال منازلهم";
77
+ readonly suggestions: readonly ["جنة الأطفال منازلهم", "نعتذر عن اصطحاب الأطفال", "الحفل للكبار فقط", "نتمنى لأطفالكم ليلة هانئة في البيت"];
78
+ };
79
+ readonly food: {
80
+ readonly default: "عشاكم بيحلا معنا";
81
+ readonly suggestions: readonly ["عشاكم بيحلا معنا", "يسعدنا أن تشاركونا العشاء", "بوفيه مفتوح بعد الحفل", "ضيافة وعشاء"];
82
+ };
83
+ };
66
84
  /** How the invitation opens for a guest; no value keeps the template's own opening */
67
85
  export declare const EventCustomizationOpening: {
68
86
  readonly NONE: "none";
@@ -4,7 +4,7 @@
4
4
  * Every field is optional: an empty value keeps the chosen template's own look.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.findEventCustomizationTrack = exports.eventCustomizationTracksFor = exports.findEventCustomizationFont = exports.findEventCustomizationPalette = exports.EventCustomizationOpeningValues = exports.EventCustomizationSectionValues = exports.EventCustomizationTrackValues = exports.EventCustomizationFontValues = exports.EventCustomizationPaletteValues = exports.EventCustomizationOpeningOptions = exports.EventCustomizationOpening = exports.EVENT_CUSTOMIZATION_TEXT_MAX = exports.EventCustomizationSectionOptions = exports.EventCustomizationSection = exports.EventCustomizationTracks = exports.EventCustomizationFonts = exports.EventCustomizationPalettes = void 0;
7
+ exports.findEventCustomizationTrack = exports.eventCustomizationTracksFor = exports.findEventCustomizationFont = exports.findEventCustomizationPalette = exports.EventCustomizationOpeningValues = exports.EventCustomizationSectionValues = exports.EventCustomizationTrackValues = exports.EventCustomizationFontValues = exports.EventCustomizationPaletteValues = exports.EventCustomizationOpeningOptions = exports.EventCustomizationOpening = exports.EventAttendanceTexts = exports.EVENT_ATTENDANCE_TEXT_MAX = exports.EVENT_CUSTOMIZATION_TEXT_MAX = exports.EVENT_COVER_VIDEO_TYPES = exports.EVENT_COVER_VIDEO_MAX_BYTES = exports.EVENT_COVER_VIDEO_MAX_SECONDS = exports.EventCustomizationSectionOptions = exports.EventCustomizationSection = exports.EventCustomizationTracks = exports.EventCustomizationFonts = exports.EventCustomizationPalettes = void 0;
8
8
  exports.EventCustomizationPalettes = [
9
9
  { value: "night", name: { en: "Night", ar: "ليلي" }, background: "#0f0c18", surface: "#1b1628", text: "#efe8f6", accent: "#d6b36a", is_dark: true },
10
10
  { value: "ivory", name: { en: "Ivory", ar: "عاجي" }, background: "#fbf6ee", surface: "#ffffff", text: "#2a2118", accent: "#9c6b3c", is_dark: false },
@@ -32,6 +32,8 @@ exports.EventCustomizationSection = {
32
32
  RSVP: "rsvp",
33
33
  MUSIC: "music",
34
34
  DRESS_CODE: "dress_code",
35
+ ATTENDANCE: "attendance",
36
+ VIDEO: "video",
35
37
  };
36
38
  exports.EventCustomizationSectionOptions = [
37
39
  { value: "countdown", name: { en: "Countdown", ar: "العد التنازلي" } },
@@ -41,8 +43,26 @@ exports.EventCustomizationSectionOptions = [
41
43
  { value: "rsvp", name: { en: "RSVP", ar: "تأكيد الحضور" } },
42
44
  { value: "music", name: { en: "Music", ar: "الموسيقى" } },
43
45
  { value: "dress_code", name: { en: "Dress code", ar: "اللباس المطلوب" } },
46
+ { value: "attendance", name: { en: "Attendance details", ar: "تفاصيل الحضور" } },
47
+ { value: "video", name: { en: "Video", ar: "الفيديو" } },
44
48
  ];
49
+ /** Invitation video (customization.cover_video): one per event, checked in the app before upload */
50
+ exports.EVENT_COVER_VIDEO_MAX_SECONDS = 60;
51
+ exports.EVENT_COVER_VIDEO_MAX_BYTES = 100 * 1024 * 1024;
52
+ exports.EVENT_COVER_VIDEO_TYPES = ["video/mp4", "video/quicktime", "video/webm", "video/x-m4v"];
45
53
  exports.EVENT_CUSTOMIZATION_TEXT_MAX = 160;
54
+ /** Children / food line on the invitation: defaults, owner text limit and ready phrases */
55
+ exports.EVENT_ATTENDANCE_TEXT_MAX = 60;
56
+ exports.EventAttendanceTexts = {
57
+ children: {
58
+ default: "جنة الأطفال منازلهم",
59
+ suggestions: ["جنة الأطفال منازلهم", "نعتذر عن اصطحاب الأطفال", "الحفل للكبار فقط", "نتمنى لأطفالكم ليلة هانئة في البيت"],
60
+ },
61
+ food: {
62
+ default: "عشاكم بيحلا معنا",
63
+ suggestions: ["عشاكم بيحلا معنا", "يسعدنا أن تشاركونا العشاء", "بوفيه مفتوح بعد الحفل", "ضيافة وعشاء"],
64
+ },
65
+ };
46
66
  /** How the invitation opens for a guest; no value keeps the template's own opening */
47
67
  exports.EventCustomizationOpening = {
48
68
  NONE: "none",
@@ -0,0 +1,3 @@
1
+ /** Limits of the expected guest count asked when creating an event */
2
+ export declare const EVENT_EXPECTED_GUESTS_MIN = 1;
3
+ export declare const EVENT_EXPECTED_GUESTS_MAX = 100000;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EVENT_EXPECTED_GUESTS_MAX = exports.EVENT_EXPECTED_GUESTS_MIN = void 0;
4
+ /** Limits of the expected guest count asked when creating an event */
5
+ exports.EVENT_EXPECTED_GUESTS_MIN = 1;
6
+ exports.EVENT_EXPECTED_GUESTS_MAX = 100000;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * People of an event other than its creator: who they are (a slot of the event type),
3
+ * what they may do (role) and the permission map shared by the backend check and the app.
4
+ */
5
+ type Text = {
6
+ en: string;
7
+ ar: string;
8
+ };
9
+ /** organiser: full control like the owner; guests: the event's guests only */
10
+ export declare const EventHostRoleValues: readonly ["organiser", "guests"];
11
+ export type EventHostRole = (typeof EventHostRoleValues)[number];
12
+ export declare const EventHostRole: {
13
+ readonly ORGANISER: "organiser";
14
+ readonly GUESTS: "guests";
15
+ };
16
+ export declare const EventHostRoleNames: Record<EventHostRole, Text>;
17
+ export declare const EventHostRoleHints: Record<EventHostRole, Text>;
18
+ export declare const EventHostRoleOptions: {
19
+ value: "organiser" | "guests";
20
+ name: Text;
21
+ hint: Text;
22
+ }[];
23
+ /** pending: waiting for the person to sign in and accept; active: accepted */
24
+ export declare const EventHostStatusValues: readonly ["pending", "active", "declined", "left", "removed"];
25
+ export type EventHostStatus = (typeof EventHostStatusValues)[number];
26
+ export declare const EventHostStatus: {
27
+ readonly PENDING: "pending";
28
+ readonly ACTIVE: "active";
29
+ readonly DECLINED: "declined";
30
+ readonly LEFT: "left";
31
+ readonly REMOVED: "removed";
32
+ };
33
+ export declare const EventHostStatusNames: Record<EventHostStatus, Text>;
34
+ /** Statuses that still hold the number on the event (one row per number) */
35
+ export declare const EventHostOpenStatusValues: EventHostStatus[];
36
+ /** What the signed-in user is on an event */
37
+ export declare const EventAccessRoleValues: readonly ["owner", "organiser", "guests"];
38
+ export type EventAccessRole = (typeof EventAccessRoleValues)[number];
39
+ export declare const EventPermissionValues: readonly ["event.view", "event.edit", "event.publish", "event.delete", "guests.manage", "hosts.manage"];
40
+ export type EventPermission = (typeof EventPermissionValues)[number];
41
+ export declare const EventRolePermissions: Record<EventAccessRole, readonly EventPermission[]>;
42
+ export declare const hasEventPermission: (role: EventAccessRole | null | undefined, permission: EventPermission) => boolean;
43
+ export declare const EventAccessRoleNames: Record<EventAccessRole, Text>;
44
+ /** Old single-number fields a slot is kept in sync with */
45
+ export type EventPeopleSlotMirror = "wedding.bride_phone" | "wedding.groom_phone" | "occasion.phone";
46
+ /** A suggested person of an event type: one optional phone field in the form */
47
+ export type EventPeopleSlot = {
48
+ key: string;
49
+ label: Text;
50
+ /** Role they get unless the owner changes it */
51
+ role: EventHostRole;
52
+ /** The existing form field that already holds this number */
53
+ mirrors?: EventPeopleSlotMirror;
54
+ /** Hidden from them until the event ends when the type's details.surprise is "yes" */
55
+ surprise_when_details_surprise?: boolean;
56
+ };
57
+ /**
58
+ * Suggested people of each event type. The person the event is for manages guests;
59
+ * whoever organises or invites gets full control. Anyone else is added by hand.
60
+ */
61
+ export declare const EventPeopleSlots: Record<string, EventPeopleSlot[]>;
62
+ /** Suggested people of a type (a type without its own list gets the organiser only) */
63
+ export declare const findEventPeopleSlots: (eventType: string | null | undefined) => EventPeopleSlot[];
64
+ export declare const findEventPeopleSlot: (eventType: string | null | undefined, key: string | null | undefined) => EventPeopleSlot | undefined;
65
+ /** Answers to «من أنت في هذه المناسبة؟» besides the type's slots */
66
+ export declare const EventCreatorRoleExtra: {
67
+ readonly COMPANY: "company";
68
+ readonly OTHER: "other";
69
+ };
70
+ export declare const EventCreatorRoleExtraNames: Record<(typeof EventCreatorRoleExtra)[keyof typeof EventCreatorRoleExtra], Text>;
71
+ /** Label of the person a host row (or the creator) is: slot label, or the free text */
72
+ export declare const eventPersonLabel: (eventType: string | null | undefined, slotKey: string | null | undefined, fallback?: string | null) => Text | null;
73
+ export declare const EVENT_HOST_LABEL_MAX = 60;
74
+ /**
75
+ * One spelling for a phone number so numbers typed differently still match:
76
+ * digits only with a leading +, 00 → +, and no 0 right after a known country code.
77
+ */
78
+ export declare const normalizeEventPhone: (value: string | null | undefined) => string | null;
79
+ export {};
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeEventPhone = exports.EVENT_HOST_LABEL_MAX = exports.eventPersonLabel = exports.EventCreatorRoleExtraNames = exports.EventCreatorRoleExtra = exports.findEventPeopleSlot = exports.findEventPeopleSlots = exports.EventPeopleSlots = exports.EventAccessRoleNames = exports.hasEventPermission = exports.EventRolePermissions = exports.EventPermissionValues = exports.EventAccessRoleValues = exports.EventHostOpenStatusValues = exports.EventHostStatusNames = exports.EventHostStatus = exports.EventHostStatusValues = exports.EventHostRoleOptions = exports.EventHostRoleHints = exports.EventHostRoleNames = exports.EventHostRole = exports.EventHostRoleValues = void 0;
4
+ /** organiser: full control like the owner; guests: the event's guests only */
5
+ exports.EventHostRoleValues = ["organiser", "guests"];
6
+ exports.EventHostRole = {
7
+ ORGANISER: "organiser",
8
+ GUESTS: "guests",
9
+ };
10
+ exports.EventHostRoleNames = {
11
+ organiser: { ar: "منظم", en: "Organiser" },
12
+ guests: { ar: "إدارة المدعوين", en: "Manages guests" },
13
+ };
14
+ exports.EventHostRoleHints = {
15
+ organiser: { ar: "يدير المناسبة كاملة", en: "Manages the whole event" },
16
+ guests: { ar: "يدير المدعوين ويرسل الدعوات ويتابع الردود", en: "Manages guests, sends invitations and follows replies" },
17
+ };
18
+ exports.EventHostRoleOptions = exports.EventHostRoleValues.map((value) => ({
19
+ value,
20
+ name: exports.EventHostRoleNames[value],
21
+ hint: exports.EventHostRoleHints[value],
22
+ }));
23
+ /** pending: waiting for the person to sign in and accept; active: accepted */
24
+ exports.EventHostStatusValues = ["pending", "active", "declined", "left", "removed"];
25
+ exports.EventHostStatus = {
26
+ PENDING: "pending",
27
+ ACTIVE: "active",
28
+ DECLINED: "declined",
29
+ LEFT: "left",
30
+ REMOVED: "removed",
31
+ };
32
+ exports.EventHostStatusNames = {
33
+ pending: { ar: "بانتظار القبول", en: "Waiting to accept" },
34
+ active: { ar: "انضم", en: "Joined" },
35
+ declined: { ar: "رفض", en: "Declined" },
36
+ left: { ar: "غادر", en: "Left" },
37
+ removed: { ar: "أزيل", en: "Removed" },
38
+ };
39
+ /** Statuses that still hold the number on the event (one row per number) */
40
+ exports.EventHostOpenStatusValues = ["pending", "active"];
41
+ /** What the signed-in user is on an event */
42
+ exports.EventAccessRoleValues = ["owner", "organiser", "guests"];
43
+ exports.EventPermissionValues = [
44
+ /** See the event (drafts included) and its invitation link */
45
+ "event.view",
46
+ /** Details, names, date, timeline, dress code, design, photos, visibility, preview */
47
+ "event.edit",
48
+ /** Publish (pay), unpublish */
49
+ "event.publish",
50
+ "event.delete",
51
+ /** Guests: add, edit, remove, send links, read status, replies, check-in, guest reports */
52
+ "guests.manage",
53
+ /** Add/remove people of the event and change their role */
54
+ "hosts.manage",
55
+ ];
56
+ exports.EventRolePermissions = {
57
+ owner: exports.EventPermissionValues,
58
+ organiser: exports.EventPermissionValues,
59
+ guests: ["event.view", "guests.manage"],
60
+ };
61
+ const hasEventPermission = (role, permission) => !!role && exports.EventRolePermissions[role].includes(permission);
62
+ exports.hasEventPermission = hasEventPermission;
63
+ exports.EventAccessRoleNames = {
64
+ owner: { ar: "المالك", en: "Owner" },
65
+ organiser: exports.EventHostRoleNames.organiser,
66
+ guests: exports.EventHostRoleNames.guests,
67
+ };
68
+ const slot = (key, ar, en, role, extra = {}) => ({ key, label: { ar, en }, role, ...extra });
69
+ const organiser = (ar = "المنظم", en = "Organiser") => slot("organiser", ar, en, "organiser", { mirrors: "occasion.phone" });
70
+ const weddingPeople = [
71
+ slot("bride", "العروس", "Bride", "guests", { mirrors: "wedding.bride_phone" }),
72
+ slot("groom", "العريس", "Groom", "guests", { mirrors: "wedding.groom_phone" }),
73
+ slot("organiser", "المنظم", "Organiser", "organiser"),
74
+ ];
75
+ /**
76
+ * Suggested people of each event type. The person the event is for manages guests;
77
+ * whoever organises or invites gets full control. Anyone else is added by hand.
78
+ */
79
+ exports.EventPeopleSlots = {
80
+ wedding: weddingPeople,
81
+ engagement: weddingPeople,
82
+ marriage: weddingPeople,
83
+ proposal: [
84
+ slot("proposer", "من سيطلب", "Who is proposing", "organiser"),
85
+ slot("partner", "الشريك", "Partner", "guests", { surprise_when_details_surprise: true }),
86
+ organiser(),
87
+ ],
88
+ bachelor: [slot("celebrant", "العروس أو العريس", "Bride or groom", "guests"), organiser()],
89
+ birthday: [slot("celebrant", "صاحب عيد الميلاد", "Birthday person", "guests"), organiser("من يدعو", "Who is inviting")],
90
+ newborn: [slot("mother", "الأم", "Mother", "organiser", { mirrors: "occasion.phone" }), slot("father", "الأب", "Father", "organiser")],
91
+ gender_reveal: [slot("mother", "الأم", "Mother", "organiser", { mirrors: "occasion.phone" }), slot("father", "الأب", "Father", "organiser")],
92
+ circumcision: [slot("mother", "الأم", "Mother", "organiser", { mirrors: "occasion.phone" }), slot("father", "الأب", "Father", "organiser")],
93
+ graduation: [slot("graduate", "الخريج", "Graduate", "guests"), organiser("من يدعو", "Who is inviting")],
94
+ hajj: [
95
+ slot("pilgrim", "الحاج أو الحاجة", "Pilgrim", "guests"),
96
+ slot("pilgrim2", "الحاج الثاني", "Second pilgrim", "guests"),
97
+ organiser("من يدعو", "Who is inviting"),
98
+ ],
99
+ mothers_day: [slot("mother", "الأم", "Mother", "guests"), organiser("من يدعو", "Who is inviting")],
100
+ valentine: [
101
+ slot("first", "الشخص الأول", "First person", "guests"),
102
+ slot("second", "الشخص الثاني", "Second person", "guests"),
103
+ organiser("من يدعو", "Who is inviting"),
104
+ ],
105
+ opening: [slot("shop_owner", "صاحب المحل", "Business owner", "organiser", { mirrors: "occasion.phone" })],
106
+ general: [organiser()],
107
+ };
108
+ const DEFAULT_PEOPLE = [organiser()];
109
+ /** Suggested people of a type (a type without its own list gets the organiser only) */
110
+ const findEventPeopleSlots = (eventType) => (eventType && exports.EventPeopleSlots[eventType]) || DEFAULT_PEOPLE;
111
+ exports.findEventPeopleSlots = findEventPeopleSlots;
112
+ const findEventPeopleSlot = (eventType, key) => key ? (0, exports.findEventPeopleSlots)(eventType).find((s) => s.key === key) : undefined;
113
+ exports.findEventPeopleSlot = findEventPeopleSlot;
114
+ /** Answers to «من أنت في هذه المناسبة؟» besides the type's slots */
115
+ exports.EventCreatorRoleExtra = {
116
+ COMPANY: "company",
117
+ OTHER: "other",
118
+ };
119
+ exports.EventCreatorRoleExtraNames = {
120
+ company: { ar: "شركة", en: "A company" },
121
+ other: { ar: "شخص آخر", en: "Someone else" },
122
+ };
123
+ /** Label of the person a host row (or the creator) is: slot label, or the free text */
124
+ const eventPersonLabel = (eventType, slotKey, fallback) => {
125
+ const s = (0, exports.findEventPeopleSlot)(eventType, slotKey);
126
+ if (s)
127
+ return s.label;
128
+ if (slotKey === "company" || slotKey === "other")
129
+ return exports.EventCreatorRoleExtraNames[slotKey];
130
+ return fallback ? { ar: fallback, en: fallback } : null;
131
+ };
132
+ exports.eventPersonLabel = eventPersonLabel;
133
+ exports.EVENT_HOST_LABEL_MAX = 60;
134
+ /**
135
+ * One spelling for a phone number so numbers typed differently still match:
136
+ * digits only with a leading +, 00 → +, and no 0 right after a known country code.
137
+ */
138
+ const normalizeEventPhone = (value) => {
139
+ if (!value)
140
+ return null;
141
+ let digits = String(value).trim().replace(/[^\d+]/g, "");
142
+ if (digits.startsWith("00"))
143
+ digits = "+" + digits.slice(2);
144
+ if (!digits.startsWith("+"))
145
+ digits = "+" + digits.replace(/\+/g, "");
146
+ digits = "+" + digits.slice(1).replace(/\+/g, "");
147
+ for (const code of ["+963", "+971", "+965", "+961", "+90", "+966", "+962", "+974"]) {
148
+ if (digits.startsWith(code + "0")) {
149
+ digits = code + digits.slice(code.length + 1);
150
+ break;
151
+ }
152
+ }
153
+ return digits.length > 4 ? digits : null;
154
+ };
155
+ exports.normalizeEventPhone = normalizeEventPhone;
@@ -25,9 +25,9 @@ exports.EventTemplate = {
25
25
  ENGAGEMENT_ROSE_ARCH: { value: 'engagement-rose-arch', name: { en: 'Rose arch', ar: 'قوس الورد' }, event_types: ['engagement'], photos: 1 },
26
26
  ENGAGEMENT_FULL_MOMENT: { value: 'engagement-full-moment', name: { en: 'Full moment', ar: 'لحظة كاملة' }, event_types: ['engagement'], photos: 1 },
27
27
  ENGAGEMENT_SEALED_LETTER: { value: 'engagement-sealed-letter', name: { en: 'Sealed letter', ar: 'رسالة مختومة' }, event_types: ['engagement'], photos: 1 },
28
- MARRIAGE_CONTRACT: { value: 'marriage-contract', name: { en: 'The contract', ar: 'وثيقة العقد' }, event_types: ['marriage'], photos: 1 },
29
- MARRIAGE_STAR_MEDALLION: { value: 'marriage-star-medallion', name: { en: 'Star medallion', ar: 'ميدالية النجمة' }, event_types: ['marriage'], photos: 1 },
30
- MARRIAGE_MASHRABIYA: { value: 'marriage-mashrabiya', name: { en: 'Mashrabiya', ar: 'نافذة المشربية' }, event_types: ['marriage'], photos: 1 },
28
+ MARRIAGE_CONTRACT: { value: 'marriage-contract', name: { en: 'The contract', ar: 'وثيقة العقد' }, event_types: ['wedding', 'marriage'], photos: 1 },
29
+ MARRIAGE_STAR_MEDALLION: { value: 'marriage-star-medallion', name: { en: 'Star medallion', ar: 'ميدالية النجمة' }, event_types: ['wedding', 'marriage'], photos: 1 },
30
+ MARRIAGE_MASHRABIYA: { value: 'marriage-mashrabiya', name: { en: 'Mashrabiya', ar: 'نافذة المشربية' }, event_types: ['wedding', 'marriage'], photos: 1 },
31
31
  PROPOSAL_ONE_QUESTION: { value: 'proposal-one-question', name: { en: 'One question', ar: 'سؤال واحد' }, event_types: ['proposal'], photos: 1 },
32
32
  PROPOSAL_WITNESS_TICKET: { value: 'proposal-witness-ticket', name: { en: 'Witness ticket', ar: 'تذكرة شاهد' }, event_types: ['proposal'], photos: 1 },
33
33
  PROPOSAL_CANDLELIGHT: { value: 'proposal-candlelight', name: { en: 'Candlelight', ar: 'ضوء الشموع' }, event_types: ['proposal'], photos: 1 },
@@ -53,6 +53,7 @@ export declare const EventTypes: {
53
53
  readonly group: "celebrations";
54
54
  readonly details: "wedding";
55
55
  };
56
+ /** Folded into the wedding (2026-11): no longer offered, kept so saved events still open */
56
57
  readonly MARRIAGE: {
57
58
  readonly value: "marriage";
58
59
  readonly name: {
@@ -61,6 +62,7 @@ export declare const EventTypes: {
61
62
  };
62
63
  readonly group: "celebrations";
63
64
  readonly details: "wedding";
65
+ readonly hidden: true;
64
66
  };
65
67
  readonly PROPOSAL: {
66
68
  readonly value: "proposal";
@@ -174,106 +176,35 @@ export declare const EventTypes: {
174
176
  export type EventTypeValue = (typeof EventTypes)[keyof typeof EventTypes]['value'];
175
177
  export declare const EventTypeValues: [EventTypeValue, ...EventTypeValue[]];
176
178
  export declare const EventTypeOptions: {
177
- value: "general" | "wedding" | "engagement" | "marriage" | "proposal" | "valentine" | "birthday" | "bachelor" | "newborn" | "gender_reveal" | "circumcision" | "graduation" | "hajj" | "mothers_day" | "opening";
179
+ value: EventTypeValue;
178
180
  name: {
179
- readonly en: "Wedding";
180
- readonly ar: "زفاف";
181
- } | {
182
- readonly en: "Engagement";
183
- readonly ar: "حفلة خطبة";
184
- } | {
185
- readonly en: "Marriage contract";
186
- readonly ar: "حفل زواج";
187
- } | {
188
- readonly en: "Proposal";
189
- readonly ar: "حفل Proposal";
190
- } | {
191
- readonly en: "Bachelor party";
192
- readonly ar: "حفل توديع عزوبية";
193
- } | {
194
- readonly en: "Birthday";
195
- readonly ar: "عيد ميلاد";
196
- } | {
197
- readonly en: "New baby";
198
- readonly ar: "مباركة مولود";
199
- } | {
200
- readonly en: "Gender reveal";
201
- readonly ar: "احتفال جنس المولود";
202
- } | {
203
- readonly en: "Circumcision";
204
- readonly ar: "حفل طهور";
205
- } | {
206
- readonly en: "Graduation";
207
- readonly ar: "حفل تخرج";
208
- } | {
209
- readonly en: "Hajj return";
210
- readonly ar: "حفلة حج";
211
- } | {
212
- readonly en: "Mother's Day";
213
- readonly ar: "حفل عيد الأم";
214
- } | {
215
- readonly en: "Valentine's Day";
216
- readonly ar: "حفل لعيد الحب";
217
- } | {
218
- readonly en: "Business opening";
219
- readonly ar: "افتتاح عمل تجاري";
220
- } | {
221
- readonly en: "General party";
222
- readonly ar: "حفلة عامة";
181
+ en: string;
182
+ ar: string;
223
183
  };
224
184
  group: EventTypeGroup;
225
185
  details: "wedding" | "occasion";
186
+ hidden: boolean;
187
+ }[];
188
+ /** Types offered when creating an invitation (hidden ones are left out) */
189
+ export declare const EventTypeOfferedOptions: {
190
+ value: EventTypeValue;
191
+ name: {
192
+ en: string;
193
+ ar: string;
194
+ };
195
+ group: EventTypeGroup;
196
+ details: "wedding" | "occasion";
197
+ hidden: boolean;
226
198
  }[];
227
199
  export declare const findEventType: (value: string | null | undefined) => {
228
- value: "general" | "wedding" | "engagement" | "marriage" | "proposal" | "valentine" | "birthday" | "bachelor" | "newborn" | "gender_reveal" | "circumcision" | "graduation" | "hajj" | "mothers_day" | "opening";
200
+ value: EventTypeValue;
229
201
  name: {
230
- readonly en: "Wedding";
231
- readonly ar: "زفاف";
232
- } | {
233
- readonly en: "Engagement";
234
- readonly ar: "حفلة خطبة";
235
- } | {
236
- readonly en: "Marriage contract";
237
- readonly ar: "حفل زواج";
238
- } | {
239
- readonly en: "Proposal";
240
- readonly ar: "حفل Proposal";
241
- } | {
242
- readonly en: "Bachelor party";
243
- readonly ar: "حفل توديع عزوبية";
244
- } | {
245
- readonly en: "Birthday";
246
- readonly ar: "عيد ميلاد";
247
- } | {
248
- readonly en: "New baby";
249
- readonly ar: "مباركة مولود";
250
- } | {
251
- readonly en: "Gender reveal";
252
- readonly ar: "احتفال جنس المولود";
253
- } | {
254
- readonly en: "Circumcision";
255
- readonly ar: "حفل طهور";
256
- } | {
257
- readonly en: "Graduation";
258
- readonly ar: "حفل تخرج";
259
- } | {
260
- readonly en: "Hajj return";
261
- readonly ar: "حفلة حج";
262
- } | {
263
- readonly en: "Mother's Day";
264
- readonly ar: "حفل عيد الأم";
265
- } | {
266
- readonly en: "Valentine's Day";
267
- readonly ar: "حفل لعيد الحب";
268
- } | {
269
- readonly en: "Business opening";
270
- readonly ar: "افتتاح عمل تجاري";
271
- } | {
272
- readonly en: "General party";
273
- readonly ar: "حفلة عامة";
202
+ en: string;
203
+ ar: string;
274
204
  };
275
205
  group: EventTypeGroup;
276
206
  details: "wedding" | "occasion";
207
+ hidden: boolean;
277
208
  } | null;
278
209
  /** Types whose details are a couple stored in event.wedding (events without a type are weddings) */
279
210
  export declare const isCoupleEventType: (value: string | null | undefined) => boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isOccasionEventType = exports.isCoupleEventType = exports.findEventType = exports.EventTypeOptions = exports.EventTypeValues = exports.EventTypes = exports.EventTypeGroups = void 0;
3
+ exports.isOccasionEventType = exports.isCoupleEventType = exports.findEventType = exports.EventTypeOfferedOptions = exports.EventTypeOptions = exports.EventTypeValues = exports.EventTypes = exports.EventTypeGroups = void 0;
4
4
  /** Groups on the «ما نوع المناسبة؟» step */
5
5
  exports.EventTypeGroups = {
6
6
  CELEBRATIONS: { value: 'celebrations', name: { en: 'Weddings & engagements', ar: 'أفراح' } },
@@ -15,7 +15,8 @@ exports.EventTypeGroups = {
15
15
  exports.EventTypes = {
16
16
  WEDDING: { value: 'wedding', name: { en: 'Wedding', ar: 'زفاف' }, group: 'celebrations', details: 'wedding' },
17
17
  ENGAGEMENT: { value: 'engagement', name: { en: 'Engagement', ar: 'حفلة خطبة' }, group: 'celebrations', details: 'wedding' },
18
- MARRIAGE: { value: 'marriage', name: { en: 'Marriage contract', ar: 'حفل زواج' }, group: 'celebrations', details: 'wedding' },
18
+ /** Folded into the wedding (2026-11): no longer offered, kept so saved events still open */
19
+ MARRIAGE: { value: 'marriage', name: { en: 'Marriage contract', ar: 'حفل زواج' }, group: 'celebrations', details: 'wedding', hidden: true },
19
20
  PROPOSAL: { value: 'proposal', name: { en: 'Proposal', ar: 'حفل Proposal' }, group: 'celebrations', details: 'occasion' },
20
21
  BACHELOR: { value: 'bachelor', name: { en: 'Bachelor party', ar: 'حفل توديع عزوبية' }, group: 'celebrations', details: 'occasion' },
21
22
  BIRTHDAY: { value: 'birthday', name: { en: 'Birthday', ar: 'عيد ميلاد' }, group: 'family', details: 'occasion' },
@@ -30,12 +31,18 @@ exports.EventTypes = {
30
31
  GENERAL: { value: 'general', name: { en: 'General party', ar: 'حفلة عامة' }, group: 'business', details: 'occasion' },
31
32
  };
32
33
  exports.EventTypeValues = Object.values(exports.EventTypes).map((t) => t.value);
33
- exports.EventTypeOptions = Object.values(exports.EventTypes).map((type) => ({
34
- value: type.value,
35
- name: type.name,
36
- group: type.group,
37
- details: type.details,
38
- }));
34
+ exports.EventTypeOptions = Object.values(exports.EventTypes).map((type) => {
35
+ var _a;
36
+ return ({
37
+ value: type.value,
38
+ name: type.name,
39
+ group: type.group,
40
+ details: type.details,
41
+ hidden: (_a = type.hidden) !== null && _a !== void 0 ? _a : false,
42
+ });
43
+ });
44
+ /** Types offered when creating an invitation (hidden ones are left out) */
45
+ exports.EventTypeOfferedOptions = exports.EventTypeOptions.filter((t) => !t.hidden);
39
46
  const findEventType = (value) => { var _a; return (_a = exports.EventTypeOptions.find((t) => t.value === (value || 'wedding'))) !== null && _a !== void 0 ? _a : null; };
40
47
  exports.findEventType = findEventType;
41
48
  /** Types whose details are a couple stored in event.wedding (events without a type are weddings) */
@@ -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
@@ -44,6 +44,11 @@ export declare const EventWeddingVerses: EventWeddingVerse[];
44
44
  /** General style only: the owner writes the couple's words by hand (event.wedding.custom_verse) */
45
45
  export declare const EVENT_WEDDING_CUSTOM_VERSE = "custom";
46
46
  export declare const EVENT_WEDDING_CUSTOM_VERSE_MAX = 160;
47
+ /**
48
+ * Quran excerpt keys from before 2026-11-08. Still accepted so older apps can save,
49
+ * but the backend drops them and no invitation shows them any more.
50
+ */
51
+ export declare const EVENT_WEDDING_LEGACY_VERSE_KEYS: readonly ["rum-21", "furqan-74", "rum-mawadda"];
47
52
  export declare const EventWeddingVerseValues: [string, ...string[]];
48
53
  /** The hand-written text applies only to the general style */
49
54
  export declare const eventWeddingCustomVerse: (verseKey: string | null | undefined, religion: string | null | undefined, customVerse: string | null | undefined) => string | null;
@@ -51,8 +56,8 @@ export declare const eventWeddingCustomVerse: (verseKey: string | null | undefin
51
56
  export type EventWeddingReligionTexts = {
52
57
  /** Line above everything (bismillah); null = nothing */
53
58
  opening: string | null;
54
- /** Heading over the verse / phrase */
55
- verse_title: string;
59
+ /** Heading over the opening phrase; null = the style shows no phrase (muslim) */
60
+ verse_title: string | null;
56
61
  /** Closing wish for the couple */
57
62
  blessing: string;
58
63
  /** Title of the short wish card */
@@ -67,6 +72,6 @@ export declare const EventWeddingReligionTextsMap: Record<EventWeddingReligion,
67
72
  export declare const EVENT_WEDDING_CEREMONY_TIMELINE_TITLE = "\u0645\u0631\u0627\u0633\u0645 \u0627\u0644\u0632\u0648\u0627\u062C";
68
73
  export declare const normalizeEventWeddingReligion: (value: string | null | undefined) => EventWeddingReligion;
69
74
  export declare const eventWeddingVersesFor: (religion: string | null | undefined) => EventWeddingVerse[];
70
- /** The saved verse when it belongs to the style, otherwise the style's first one */
71
- export declare const findEventWeddingVerse: (value: string | null | undefined, religion: string | null | undefined) => EventWeddingVerse;
75
+ /** The saved phrase when it belongs to the style, otherwise the style's first one (undefined for muslim) */
76
+ export declare const findEventWeddingVerse: (value: string | null | undefined, religion: string | null | undefined) => EventWeddingVerse | undefined;
72
77
  export declare const eventWeddingReligionTexts: (religion: string | null | undefined) => EventWeddingReligionTexts;