@timardex/cluemart-shared 1.7.0 → 1.7.1

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 (145) hide show
  1. package/dist/ad-BUYzE6zx.d.ts +181 -0
  2. package/dist/ad-BhLoEul3.d.mts +181 -0
  3. package/dist/affiliate-BbtjeUP4.d.mts +73 -0
  4. package/dist/affiliate-C51nzKsw.d.ts +73 -0
  5. package/dist/apollo/index.cjs +1383 -0
  6. package/dist/apollo/index.cjs.map +1 -0
  7. package/dist/apollo/index.d.mts +323 -0
  8. package/dist/apollo/index.d.ts +323 -0
  9. package/dist/apollo/index.mjs +1295 -0
  10. package/dist/apollo/index.mjs.map +1 -0
  11. package/dist/auth/index.cjs +1727 -0
  12. package/dist/auth/index.cjs.map +1 -0
  13. package/dist/auth/index.d.mts +166 -0
  14. package/dist/auth/index.d.ts +166 -0
  15. package/dist/auth/index.mjs +380 -0
  16. package/dist/auth/index.mjs.map +1 -0
  17. package/dist/chunk-32MKHJTX.mjs +1207 -0
  18. package/dist/chunk-32MKHJTX.mjs.map +1 -0
  19. package/dist/{chunk-RKIRWZCH.mjs → chunk-AYO3E4DM.mjs} +39 -183
  20. package/dist/chunk-AYO3E4DM.mjs.map +1 -0
  21. package/dist/{chunk-ZZJSCYJK.mjs → chunk-BIJ5NDXW.mjs} +46 -42
  22. package/dist/chunk-BIJ5NDXW.mjs.map +1 -0
  23. package/dist/chunk-DQ7ZHIXW.mjs +26 -0
  24. package/dist/chunk-DQ7ZHIXW.mjs.map +1 -0
  25. package/dist/{chunk-MVQ3CFQR.mjs → chunk-ILILH7E2.mjs} +12 -23
  26. package/dist/chunk-ILILH7E2.mjs.map +1 -0
  27. package/dist/{chunk-TAECMXM4.mjs → chunk-LBEJECG3.mjs} +249 -219
  28. package/dist/{chunk-TAECMXM4.mjs.map → chunk-LBEJECG3.mjs.map} +1 -1
  29. package/dist/{chunk-HZMP7GXC.mjs → chunk-R6PCFOYO.mjs} +949 -2629
  30. package/dist/chunk-R6PCFOYO.mjs.map +1 -0
  31. package/dist/chunk-RAYUJODN.mjs +45 -0
  32. package/dist/chunk-RAYUJODN.mjs.map +1 -0
  33. package/dist/chunk-SD42WIMV.mjs +297 -0
  34. package/dist/chunk-SD42WIMV.mjs.map +1 -0
  35. package/dist/chunk-VPANTTZI.mjs +262 -0
  36. package/dist/chunk-VPANTTZI.mjs.map +1 -0
  37. package/dist/{chunk-KZTOISPA.mjs → chunk-X3OLM35T.mjs} +14 -8
  38. package/dist/chunk-X3OLM35T.mjs.map +1 -0
  39. package/dist/{contactUs-H7799pWe.d.ts → contactUs--NoohZBu.d.ts} +1 -1
  40. package/dist/{contactUs-DGrDzJaM.d.mts → contactUs-CBWzefUS.d.mts} +1 -1
  41. package/dist/enums/index.cjs +13 -7
  42. package/dist/enums/index.cjs.map +1 -1
  43. package/dist/enums/index.d.mts +15 -9
  44. package/dist/enums/index.d.ts +15 -9
  45. package/dist/enums/index.mjs +1 -1
  46. package/dist/formFields/index.cjs +136 -73
  47. package/dist/formFields/index.cjs.map +1 -1
  48. package/dist/formFields/index.d.mts +3 -2
  49. package/dist/formFields/index.d.ts +3 -2
  50. package/dist/formFields/index.mjs +9 -4
  51. package/dist/{global-fKbMmluy.d.ts → global-CUYYxpy2.d.ts} +12 -11
  52. package/dist/{global-BUUfmCo7.d.mts → global-DePDtOFt.d.mts} +12 -11
  53. package/dist/graphql/index.cjs +694 -1251
  54. package/dist/graphql/index.cjs.map +1 -1
  55. package/dist/graphql/index.d.mts +423 -173
  56. package/dist/graphql/index.d.ts +423 -173
  57. package/dist/graphql/index.mjs +33 -21
  58. package/dist/hooks/index.cjs +937 -307
  59. package/dist/hooks/index.cjs.map +1 -1
  60. package/dist/hooks/index.d.mts +10 -4
  61. package/dist/hooks/index.d.ts +10 -4
  62. package/dist/hooks/index.mjs +170 -58
  63. package/dist/hooks/index.mjs.map +1 -1
  64. package/dist/images/apple-maps-icon.webp.d.ts +8 -1
  65. package/dist/images/banner-horizontal.webp.d.ts +8 -1
  66. package/dist/images/banner-vertical.webp.d.ts +8 -1
  67. package/dist/images/cluiTui.webp.d.ts +8 -1
  68. package/dist/images/corporate.webp.d.ts +8 -1
  69. package/dist/images/facebook.webp.d.ts +8 -1
  70. package/dist/images/gazebo-top.webp.d.ts +8 -1
  71. package/dist/images/google-maps-icon.webp.d.ts +8 -1
  72. package/dist/images/googleMaps-logo-dark.webp.d.ts +8 -1
  73. package/dist/images/googleMaps-logo-light.webp.d.ts +8 -1
  74. package/dist/images/instagram.webp.d.ts +8 -1
  75. package/dist/images/logo-atr.webp.d.ts +8 -1
  76. package/dist/images/logo-dark.webp.d.ts +8 -1
  77. package/dist/images/logo.webp.d.ts +8 -1
  78. package/dist/images/meet.webp.d.ts +8 -1
  79. package/dist/images/mini-market1.webp.d.ts +8 -1
  80. package/dist/images/mini-market2.webp.d.ts +8 -1
  81. package/dist/images/mini-market3.webp.d.ts +8 -1
  82. package/dist/images/mini-market4.webp.d.ts +8 -1
  83. package/dist/images/mini-market5.webp.d.ts +8 -1
  84. package/dist/images/poll.webp.d.ts +8 -1
  85. package/dist/images/poster1.webp.d.ts +8 -1
  86. package/dist/images/poster2.webp.d.ts +8 -1
  87. package/dist/images/poster3.webp.d.ts +8 -1
  88. package/dist/images/poster4.webp.d.ts +8 -1
  89. package/dist/images/private.webp.d.ts +8 -1
  90. package/dist/images/qr-code.webp.d.ts +8 -1
  91. package/dist/images/school.webp.d.ts +8 -1
  92. package/dist/images/sima.webp.d.ts +8 -1
  93. package/dist/images/store-android.webp.d.ts +8 -1
  94. package/dist/images/store-ios.webp.d.ts +8 -1
  95. package/dist/images/tablas.webp.d.ts +8 -1
  96. package/dist/images/telefonos.webp.d.ts +8 -1
  97. package/dist/images/tiktok.webp.d.ts +8 -1
  98. package/dist/images/tip.webp.d.ts +8 -1
  99. package/dist/images/ugralos.webp.d.ts +8 -1
  100. package/dist/images/waze-maps-icon.webp.d.ts +8 -1
  101. package/dist/images/website.webp.d.ts +8 -1
  102. package/dist/images/youtube.webp.d.ts +8 -1
  103. package/dist/index.cjs +1655 -1705
  104. package/dist/index.cjs.map +1 -1
  105. package/dist/index.d.mts +654 -240
  106. package/dist/index.d.ts +654 -240
  107. package/dist/index.mjs +1617 -1704
  108. package/dist/index.mjs.map +1 -1
  109. package/dist/map/index.cjs +14 -9
  110. package/dist/map/index.cjs.map +1 -1
  111. package/dist/map/index.d.mts +16 -13
  112. package/dist/map/index.d.ts +16 -13
  113. package/dist/map/index.mjs +14 -9
  114. package/dist/map/index.mjs.map +1 -1
  115. package/dist/{resourceActivities-BL_12IAo.d.ts → resourceActivities-CMUcn2P7.d.ts} +9 -4
  116. package/dist/{resourceActivities-zczOntNk.d.mts → resourceActivities-CwbJFGIp.d.mts} +9 -4
  117. package/dist/sharing/index.cjs +39 -1252
  118. package/dist/sharing/index.cjs.map +1 -1
  119. package/dist/sharing/index.d.mts +17 -5
  120. package/dist/sharing/index.d.ts +17 -5
  121. package/dist/sharing/index.mjs +34 -30
  122. package/dist/subscription-BU8GvH2K.d.ts +12 -0
  123. package/dist/subscription-bmAdrnfi.d.mts +12 -0
  124. package/dist/types/index.cjs +15 -2
  125. package/dist/types/index.cjs.map +1 -1
  126. package/dist/types/index.d.mts +10 -23
  127. package/dist/types/index.d.ts +10 -23
  128. package/dist/types/index.mjs +9 -5
  129. package/dist/user-D47MLFyH.d.ts +134 -0
  130. package/dist/user-DE8edl3u.d.mts +134 -0
  131. package/dist/utils/index.cjs +355 -136
  132. package/dist/utils/index.cjs.map +1 -1
  133. package/dist/utils/index.d.mts +87 -35
  134. package/dist/utils/index.d.ts +87 -35
  135. package/dist/utils/index.mjs +42 -15
  136. package/package.json +31 -10
  137. package/dist/ad-CVkVX_z5.d.ts +0 -296
  138. package/dist/ad-DA9ECAhK.d.mts +0 -296
  139. package/dist/affiliate-1RtkLnLP.d.ts +0 -35
  140. package/dist/affiliate-Cos2Syz5.d.mts +0 -35
  141. package/dist/chunk-HZMP7GXC.mjs.map +0 -1
  142. package/dist/chunk-KZTOISPA.mjs.map +0 -1
  143. package/dist/chunk-MVQ3CFQR.mjs.map +0 -1
  144. package/dist/chunk-RKIRWZCH.mjs.map +0 -1
  145. package/dist/chunk-ZZJSCYJK.mjs.map +0 -1
@@ -0,0 +1,297 @@
1
+ import {
2
+ EnumEventDateStatus
3
+ } from "./chunk-X3OLM35T.mjs";
4
+
5
+ // src/utils/mapArrayToOptions.ts
6
+ var mapArrayToOptions = (items) => items.map((item) => ({
7
+ label: item,
8
+ value: item
9
+ }));
10
+
11
+ // src/utils/date.ts
12
+ import dayjs from "dayjs";
13
+ import customParseFormat from "dayjs/plugin/customParseFormat.js";
14
+ import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js";
15
+ import timezone from "dayjs/plugin/timezone.js";
16
+ import utc from "dayjs/plugin/utc.js";
17
+ var dateFormat = "DD-MM-YYYY";
18
+ var timeFormat = "HH:mm";
19
+ dayjs.extend(customParseFormat);
20
+ dayjs.extend(utc);
21
+ dayjs.extend(timezone);
22
+ dayjs.extend(isSameOrAfter);
23
+ var NZ_TZ = "Pacific/Auckland";
24
+ function toNZTime(date) {
25
+ return date ? dayjs(date).tz(NZ_TZ) : dayjs().tz(NZ_TZ);
26
+ }
27
+ function nzStartOfDay(input) {
28
+ if (input == null) {
29
+ return dayjs().tz(NZ_TZ).startOf("day");
30
+ }
31
+ return dayjs.tz(input, NZ_TZ).startOf("day");
32
+ }
33
+ var formatDate = (dateStr, display = "datetime", timeStr) => {
34
+ const dateTimeStr = timeStr ? `${dateStr} ${timeStr}` : dateStr;
35
+ const dateTime = timeStr ? dayjs(dateTimeStr, `${dateFormat} ${timeFormat}`) : dayjs(dateStr, dateFormat);
36
+ const formattedDate = dateTime.format("dddd, D MMMM, YYYY");
37
+ const formattedTime = dateTime.format("h:mm a");
38
+ switch (display) {
39
+ case "date":
40
+ return formattedDate;
41
+ case "time":
42
+ return formattedTime;
43
+ case "datetime":
44
+ return `${formattedDate} at ${formattedTime}`;
45
+ default:
46
+ return formattedDate;
47
+ }
48
+ };
49
+ var getCurrentAndFutureDates = (dates) => {
50
+ const now = dayjs();
51
+ return dates.filter((dateObj) => {
52
+ const dateTime = dayjs(
53
+ `${dateObj.startDate} ${dateObj.startTime}`,
54
+ `${dateFormat} ${timeFormat}`
55
+ );
56
+ return dateTime.isSameOrAfter(now);
57
+ });
58
+ };
59
+ var isFutureDatesBeforeThreshold = (date, minHoursFromNow) => {
60
+ const threshold = minHoursFromNow ? dayjs().add(minHoursFromNow, "hour") : dayjs().startOf("day");
61
+ const dateTime = dayjs(
62
+ `${date.startDate} ${date.startTime}`,
63
+ `${dateFormat} ${timeFormat}`
64
+ );
65
+ return dateTime.isSameOrAfter(threshold);
66
+ };
67
+ var formatTimestamp = (timestamp) => {
68
+ const formattedDate = toNZTime(timestamp).format(dateFormat);
69
+ return formatDate(formattedDate, "date");
70
+ };
71
+ var isIsoDateString = (value) => {
72
+ return typeof value === "string" && !Number.isNaN(Date.parse(value));
73
+ };
74
+ function sortDatesChronologically(dates) {
75
+ if (!dates?.length) {
76
+ return [];
77
+ }
78
+ return [...dates].sort((a, b) => {
79
+ const dateTimeFormat = `${dateFormat} ${timeFormat}`;
80
+ const dateA = dayjs(`${a.startDate} ${a.startTime}`, dateTimeFormat);
81
+ const dateB = dayjs(`${b.startDate} ${b.startTime}`, dateTimeFormat);
82
+ return dateA.valueOf() - dateB.valueOf();
83
+ });
84
+ }
85
+ var futureTimePeriods = mapArrayToOptions(
86
+ Object.values(EnumEventDateStatus)
87
+ ).filter(
88
+ (period) => period.value !== "Starting_Soon" /* STARTING_SOON */ && period.value !== "Canceled" /* CANCELED */ && period.value !== "Rescheduled" /* RE_SCHEDULED */ && period.value !== "Started" /* STARTED */ && period.value !== "Ended" /* ENDED */ && period.value !== "Invalid" /* INVALID */
89
+ ).map((period) => ({
90
+ label: period.value.replaceAll("_", " "),
91
+ value: period.value
92
+ }));
93
+
94
+ // src/sharing/relationShareTypes.ts
95
+ var RELATION_SHARE_INVITATION = "invitation";
96
+ var RELATION_SHARE_APPLICATION = "application";
97
+ var RELATION_OVERLAY_LAYOUT_VERSION = 43;
98
+ var RELATION_SHARE_RESOURCE_TYPES = [
99
+ RELATION_SHARE_INVITATION,
100
+ RELATION_SHARE_APPLICATION
101
+ ];
102
+ function isRelationShareResourceType(resourceType) {
103
+ return RELATION_SHARE_RESOURCE_TYPES.includes(
104
+ resourceType
105
+ );
106
+ }
107
+
108
+ // src/sharing/constants.ts
109
+ var SOCIAL_IMAGE_WIDTH = 1200;
110
+ var SOCIAL_IMAGE_HEIGHT = 630;
111
+ var SHARE_SITE_URL = "https://cluemart.co.nz";
112
+ var SHARE_CALENDAR_ICON = "\u{1F4C5}";
113
+ var SHARE_MARKET_DATES_SECTION_HEADING = `${SHARE_CALENDAR_ICON} Market dates:`;
114
+ var SHARE_CHECKMARK_ICON = "\u2705";
115
+ var SHARE_REQUIREMENTS_SECTION_HEADING = `${SHARE_CHECKMARK_ICON} Requirements:`;
116
+ var SHARE_INFO_ICON = "\u2139\uFE0F";
117
+ var SHARE_TAGS_SECTION_HEADING = `${SHARE_INFO_ICON} Tags:`;
118
+ var SHARE_RAIN_OR_SHINE_LINE = "Rain or Shine";
119
+ var SHARE_FOOD_TRUCK_LINE = "Food Truck";
120
+ var SHARE_COMPLIANCE_PREFIX = `${SHARE_CHECKMARK_ICON} Compliance:`;
121
+ var SHARE_CATEGORY_ICON = "\u{1F3F7}\uFE0F";
122
+ var SHARE_CATEGORIES_SECTION_HEADING = `${SHARE_CATEGORY_ICON} Categories:`;
123
+ var SHARE_RULER_ICON = "\u{1F4CF}";
124
+ var SHARE_STALL_SIZE_PREFIX = `${SHARE_RULER_ICON} Stall size:`;
125
+ var SHARE_DOLLAR_ICON = "$";
126
+ var SHARE_PRICE_RANGE_PREFIX = `${SHARE_DOLLAR_ICON} Price range:`;
127
+ var SHARE_CLOCK_ICON = "\u23F0";
128
+ var SHARE_APPLICATION_DEADLINE_PREFIX = `${SHARE_CLOCK_ICON} Application deadline:`;
129
+ var SHARE_MORE_INFO_LINE = "Shared from ClueMart";
130
+ var DEFAULT_SHARE_OG_IMAGE = `${SHARE_SITE_URL}/assets/logo.webp`;
131
+ var RESOURCE_SHARE_TYPES = [
132
+ "market",
133
+ "stallholder",
134
+ "partner",
135
+ "affiliate",
136
+ "school"
137
+ ];
138
+ var POST_SHARE_RESOURCE_TYPES = [
139
+ "market_faces",
140
+ "clue_bites",
141
+ "play_and_win"
142
+ ];
143
+ var SHARE_RESOURCE_LABEL = {
144
+ [RELATION_SHARE_APPLICATION]: "Application",
145
+ [RELATION_SHARE_INVITATION]: "Invitation",
146
+ clue_bites: "Clue Bites",
147
+ market_faces: "Market Faces",
148
+ play_and_win: "Play & Win",
149
+ market: "Market",
150
+ partner: "Partner",
151
+ stallholder: "Stallholder",
152
+ affiliate: "Affiliate",
153
+ school: "School"
154
+ };
155
+ function isPostShareResourceType(resourceType) {
156
+ return POST_SHARE_RESOURCE_TYPES.includes(
157
+ resourceType
158
+ );
159
+ }
160
+
161
+ // src/sharing/joinShareDescriptionSections.ts
162
+ var SHARE_DESCRIPTION_SECTION_BREAK = "\n\n";
163
+ var OG_DESCRIPTION_LINE_BREAK = "
";
164
+ function joinShareOgDescriptionSections(sections) {
165
+ return sections.map((section) => typeof section === "string" ? section.trim() : "").filter((section) => section.length > 0).map((section) => section.replace(/\n/g, OG_DESCRIPTION_LINE_BREAK)).join(OG_DESCRIPTION_LINE_BREAK);
166
+ }
167
+ function joinShareDescriptionSections(sections) {
168
+ return sections.filter((section) => Boolean(section)).join(SHARE_DESCRIPTION_SECTION_BREAK);
169
+ }
170
+ function appendShareMoreInfoLine(description) {
171
+ const trimmed = description.trim();
172
+ if (trimmed.startsWith(SHARE_MORE_INFO_LINE)) {
173
+ return trimmed;
174
+ }
175
+ if (trimmed.length === 0) {
176
+ return SHARE_MORE_INFO_LINE;
177
+ }
178
+ return joinShareDescriptionSections([SHARE_MORE_INFO_LINE, trimmed]);
179
+ }
180
+
181
+ // src/sharing/normalizeShareDescription.ts
182
+ var LEADING_WHITESPACE = /^[ \t]*/;
183
+ function normalizeShareText(value) {
184
+ if (value == null) {
185
+ return "";
186
+ }
187
+ return value.trim().split("\n").map((line) => {
188
+ const leading = LEADING_WHITESPACE.exec(line)?.[0] ?? "";
189
+ const rest = line.slice(leading.length).trim().replace(/[ \t]{2,}/g, " ");
190
+ return leading + rest;
191
+ }).join("\n").replace(/\n{3,}/g, "\n\n");
192
+ }
193
+ function shareMessageFooterPlacementForType(_shareType) {
194
+ return "before-body";
195
+ }
196
+ function buildShareMessageSections(input) {
197
+ const title = normalizeShareText(input.title);
198
+ const description = normalizeShareText(input.description);
199
+ return [SHARE_MORE_INFO_LINE, title, description].filter(
200
+ (section) => section.length > 0
201
+ );
202
+ }
203
+ function splitShareDescriptionSections(value) {
204
+ const trimmed = normalizeShareText(value);
205
+ if (!trimmed) {
206
+ return [];
207
+ }
208
+ if (/\n\n/.test(trimmed)) {
209
+ return trimmed.split(/\n\n+/).map((section) => normalizeShareText(section)).filter((section) => section.length > 0);
210
+ }
211
+ if (/\n/.test(trimmed)) {
212
+ return trimmed.split(/\n+/).map((section) => normalizeShareText(section)).filter((section) => section.length > 0);
213
+ }
214
+ return [trimmed];
215
+ }
216
+ function normalizeShareOgDescription(value) {
217
+ return joinShareOgDescriptionSections(splitShareDescriptionSections(value));
218
+ }
219
+ function buildFacebookShareQuote(title, description, shareType) {
220
+ const sections = buildShareMessageSections({ description, shareType, title });
221
+ const quote = sections.join(SHARE_DESCRIPTION_SECTION_BREAK).trim();
222
+ return quote.length > 0 ? quote : void 0;
223
+ }
224
+ function buildShareOgDescriptionFromSections(sections) {
225
+ return joinShareOgDescriptionSections(sections);
226
+ }
227
+ function buildShareOgDescription(_title, description) {
228
+ return joinShareOgDescriptionSections(
229
+ splitShareDescriptionSections(description)
230
+ );
231
+ }
232
+ function stripOverlaySubtitleSpecialChars(text) {
233
+ const regex = /[^\p{L}\p{M}\p{N}\s.,!?'"&\-():;/]/gu;
234
+ const result = text.replace(/\p{Extended_Pictographic}/gu, "").replace(regex, "");
235
+ return result.trim();
236
+ }
237
+
238
+ export {
239
+ mapArrayToOptions,
240
+ dateFormat,
241
+ timeFormat,
242
+ toNZTime,
243
+ nzStartOfDay,
244
+ formatDate,
245
+ getCurrentAndFutureDates,
246
+ isFutureDatesBeforeThreshold,
247
+ formatTimestamp,
248
+ isIsoDateString,
249
+ sortDatesChronologically,
250
+ futureTimePeriods,
251
+ RELATION_SHARE_INVITATION,
252
+ RELATION_SHARE_APPLICATION,
253
+ RELATION_OVERLAY_LAYOUT_VERSION,
254
+ RELATION_SHARE_RESOURCE_TYPES,
255
+ isRelationShareResourceType,
256
+ SOCIAL_IMAGE_WIDTH,
257
+ SOCIAL_IMAGE_HEIGHT,
258
+ SHARE_SITE_URL,
259
+ SHARE_CALENDAR_ICON,
260
+ SHARE_MARKET_DATES_SECTION_HEADING,
261
+ SHARE_CHECKMARK_ICON,
262
+ SHARE_REQUIREMENTS_SECTION_HEADING,
263
+ SHARE_INFO_ICON,
264
+ SHARE_TAGS_SECTION_HEADING,
265
+ SHARE_RAIN_OR_SHINE_LINE,
266
+ SHARE_FOOD_TRUCK_LINE,
267
+ SHARE_COMPLIANCE_PREFIX,
268
+ SHARE_CATEGORY_ICON,
269
+ SHARE_CATEGORIES_SECTION_HEADING,
270
+ SHARE_RULER_ICON,
271
+ SHARE_STALL_SIZE_PREFIX,
272
+ SHARE_DOLLAR_ICON,
273
+ SHARE_PRICE_RANGE_PREFIX,
274
+ SHARE_CLOCK_ICON,
275
+ SHARE_APPLICATION_DEADLINE_PREFIX,
276
+ SHARE_MORE_INFO_LINE,
277
+ DEFAULT_SHARE_OG_IMAGE,
278
+ RESOURCE_SHARE_TYPES,
279
+ POST_SHARE_RESOURCE_TYPES,
280
+ SHARE_RESOURCE_LABEL,
281
+ isPostShareResourceType,
282
+ SHARE_DESCRIPTION_SECTION_BREAK,
283
+ OG_DESCRIPTION_LINE_BREAK,
284
+ joinShareOgDescriptionSections,
285
+ joinShareDescriptionSections,
286
+ appendShareMoreInfoLine,
287
+ normalizeShareText,
288
+ shareMessageFooterPlacementForType,
289
+ buildShareMessageSections,
290
+ splitShareDescriptionSections,
291
+ normalizeShareOgDescription,
292
+ buildFacebookShareQuote,
293
+ buildShareOgDescriptionFromSections,
294
+ buildShareOgDescription,
295
+ stripOverlaySubtitleSpecialChars
296
+ };
297
+ //# sourceMappingURL=chunk-SD42WIMV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/mapArrayToOptions.ts","../src/utils/date.ts","../src/sharing/relationShareTypes.ts","../src/sharing/constants.ts","../src/sharing/joinShareDescriptionSections.ts","../src/sharing/normalizeShareDescription.ts"],"sourcesContent":["import { OptionItem } from \"src/types\";\n\n/**\n * Convert an array of strings to an array of objects with label and value properties.\n */\nexport const mapArrayToOptions = (items: string[]): OptionItem[] =>\n items.map((item) => ({\n label: item,\n value: item,\n }));\n","import dayjs from \"dayjs\";\nimport customParseFormat from \"dayjs/plugin/customParseFormat.js\";\nimport isSameOrAfter from \"dayjs/plugin/isSameOrAfter.js\";\nimport timezone from \"dayjs/plugin/timezone.js\";\nimport utc from \"dayjs/plugin/utc.js\";\n\nimport { EnumEventDateStatus } from \"src/enums\";\n\nimport { mapArrayToOptions } from \"./mapArrayToOptions\";\n\nexport const dateFormat = \"DD-MM-YYYY\";\nexport const timeFormat = \"HH:mm\";\n\n// Enable custom format parsing\ndayjs.extend(customParseFormat);\ndayjs.extend(utc);\ndayjs.extend(timezone);\ndayjs.extend(isSameOrAfter);\n\nconst NZ_TZ = \"Pacific/Auckland\";\n\nexport function toNZTime(date?: Date | string) {\n return date ? dayjs(date).tz(NZ_TZ) : dayjs().tz(NZ_TZ);\n}\n\n/** Start of the calendar day in Pacific/Auckland (daily games, streaks, etc.). */\nexport function nzStartOfDay(\n input?: Date | string | number | null,\n): dayjs.Dayjs {\n if (input == null) {\n return dayjs().tz(NZ_TZ).startOf(\"day\");\n }\n return dayjs.tz(input, NZ_TZ).startOf(\"day\");\n}\n\ntype DateFormat = \"date\" | \"time\" | \"datetime\";\n\n/**\n * Format a date string to a more readable format.\n * @param dateStr - the date string\n * @param timeStr - optional time string\n * @param display - 'date' | 'time' | 'datetime'\n * @returns formatted string based on display option\n */\nexport const formatDate = (\n dateStr: string,\n display: DateFormat = \"datetime\",\n timeStr?: string,\n) => {\n // Combine date and time into a single string if time is provided\n const dateTimeStr = timeStr ? `${dateStr} ${timeStr}` : dateStr;\n\n // Parse with formats\n const dateTime = timeStr\n ? dayjs(dateTimeStr, `${dateFormat} ${timeFormat}`)\n : dayjs(dateStr, dateFormat);\n\n // Format parts\n const formattedDate = dateTime.format(\"dddd, D MMMM, YYYY\");\n const formattedTime = dateTime.format(\"h:mm a\");\n\n // Return based on display option\n switch (display) {\n case \"date\":\n return formattedDate;\n case \"time\":\n return formattedTime;\n case \"datetime\":\n return `${formattedDate} at ${formattedTime}`;\n default:\n return formattedDate;\n }\n};\n\nexport const getCurrentAndFutureDates = <\n T extends { startDate: string; startTime: string },\n>(\n dates: T[],\n): T[] => {\n const now = dayjs(); // current date and time\n\n return dates.filter((dateObj) => {\n const dateTime = dayjs(\n `${dateObj.startDate} ${dateObj.startTime}`,\n `${dateFormat} ${timeFormat}`,\n );\n return dateTime.isSameOrAfter(now);\n });\n};\n\nexport const isFutureDatesBeforeThreshold = (\n date: {\n startDate: string;\n startTime: string;\n },\n minHoursFromNow: number,\n): boolean => {\n const threshold = minHoursFromNow\n ? dayjs().add(minHoursFromNow, \"hour\")\n : dayjs().startOf(\"day\");\n\n const dateTime = dayjs(\n `${date.startDate} ${date.startTime}`,\n `${dateFormat} ${timeFormat}`,\n );\n\n return dateTime.isSameOrAfter(threshold);\n};\n\nexport const formatTimestamp = (timestamp: string) => {\n const formattedDate = toNZTime(timestamp).format(dateFormat);\n\n return formatDate(formattedDate, \"date\");\n};\n\nexport const isIsoDateString = (value: unknown): value is string => {\n return typeof value === \"string\" && !Number.isNaN(Date.parse(value));\n};\n\n/**\n * Sort an array of date strings by their proximity to the current date.\n * @param dates - The array of date strings to sort.\n * @returns - The sorted array of date strings.\n */\nexport function sortDatesChronologically<\n T extends { startDate: string; startTime: string },\n>(dates: T[]): T[] {\n if (!dates?.length) {\n return [];\n }\n\n return [...dates].sort((a, b) => {\n const dateTimeFormat = `${dateFormat} ${timeFormat}`;\n const dateA = dayjs(`${a.startDate} ${a.startTime}`, dateTimeFormat);\n const dateB = dayjs(`${b.startDate} ${b.startTime}`, dateTimeFormat);\n return dateA.valueOf() - dateB.valueOf(); // chronological order\n });\n}\n\nexport const futureTimePeriods = mapArrayToOptions(\n Object.values(EnumEventDateStatus),\n)\n .filter(\n (period) =>\n period.value !== EnumEventDateStatus.STARTING_SOON &&\n period.value !== EnumEventDateStatus.CANCELED &&\n period.value !== EnumEventDateStatus.RE_SCHEDULED &&\n period.value !== EnumEventDateStatus.STARTED &&\n period.value !== EnumEventDateStatus.ENDED &&\n period.value !== EnumEventDateStatus.INVALID,\n )\n .map((period) => ({\n label: period.value.replaceAll(\"_\", \" \"),\n value: period.value,\n }));\n","/** Path segments for relation share URLs — must match mobile `RelationTitle` values. */\nexport const RELATION_SHARE_INVITATION = \"invitation\" as const;\nexport const RELATION_SHARE_APPLICATION = \"application\" as const;\n\n/**\n * Bump when relation overlay SVG/layout changes so og:image URLs and API ETags\n * invalidate after deploy. Facebook caches preview JPEGs by exact URL — changing\n * this value forces crawlers to fetch a fresh image after server deploy.\n */\nexport const RELATION_OVERLAY_LAYOUT_VERSION = 43;\n\nexport const RELATION_SHARE_RESOURCE_TYPES = [\n RELATION_SHARE_INVITATION,\n RELATION_SHARE_APPLICATION,\n] as const;\n\nexport type RelationShareResourceType =\n (typeof RELATION_SHARE_RESOURCE_TYPES)[number];\n\nexport function isRelationShareResourceType(\n resourceType: string,\n): resourceType is RelationShareResourceType {\n return (RELATION_SHARE_RESOURCE_TYPES as readonly string[]).includes(\n resourceType,\n );\n}\n","import {\n RELATION_SHARE_APPLICATION,\n RELATION_SHARE_INVITATION,\n type RelationShareResourceType,\n} from \"./relationShareTypes\";\n\nexport {\n RELATION_SHARE_APPLICATION,\n RELATION_SHARE_INVITATION,\n RELATION_OVERLAY_LAYOUT_VERSION,\n RELATION_SHARE_RESOURCE_TYPES,\n isRelationShareResourceType,\n type RelationShareResourceType,\n} from \"./relationShareTypes\";\n\n/** Open Graph recommended preview size (must match admin `SHARE_OG_IMAGE_*`). */\nexport const SOCIAL_IMAGE_WIDTH = 1200;\n\n/** Open Graph recommended preview size (must match admin `SHARE_OG_IMAGE_*`). */\nexport const SOCIAL_IMAGE_HEIGHT = 630;\n\n/** Keep in sync with `CLUEMART_MAIN_DOMAIN_URL` in utils (avoid utils↔sharing import cycle). */\nexport const SHARE_SITE_URL = \"https://cluemart.co.nz\";\n\n/** Calendar marker for invitation market-dates share copy (U+1F4C5 📅). */\nexport const SHARE_CALENDAR_ICON = \"\\u{1F4C5}\";\n\nexport const SHARE_MARKET_DATES_SECTION_HEADING = `${SHARE_CALENDAR_ICON} Market dates:`;\n\n/** Check mark for invitation requirements share copy (U+2705 ✅). */\nexport const SHARE_CHECKMARK_ICON = \"\\u{2705}\";\n\nexport const SHARE_REQUIREMENTS_SECTION_HEADING = `${SHARE_CHECKMARK_ICON} Requirements:`;\n\n/** Information marker for tags share copy (U+2139 ℹ️). */\nexport const SHARE_INFO_ICON = \"\\u{2139}\\u{FE0F}\";\n\nexport const SHARE_TAGS_SECTION_HEADING = `${SHARE_INFO_ICON} Tags:`;\n\n/** Standalone line when `rainOrShine` is true (invitation share + OG section parsing). */\nexport const SHARE_RAIN_OR_SHINE_LINE = \"Rain or Shine\";\n\n/** Standalone line when `foodTruck` is true (application share + OG section parsing). */\nexport const SHARE_FOOD_TRUCK_LINE = \"Food Truck\";\n\n/** Prefix for application compliance line (share text + OG section parsing). */\nexport const SHARE_COMPLIANCE_PREFIX = `${SHARE_CHECKMARK_ICON} Compliance:`;\n\n/** Label tag for application categories share copy (U+1F3F7 🏷️). */\nexport const SHARE_CATEGORY_ICON = \"\\u{1F3F7}\\u{FE0F}\";\n\nexport const SHARE_CATEGORIES_SECTION_HEADING = `${SHARE_CATEGORY_ICON} Categories:`;\n\n/** Straight ruler for application stall-size share copy (U+1F4CF 📏). */\nexport const SHARE_RULER_ICON = \"\\u{1F4CF}\";\n\n/** Prefix for application stall-size line (share text + OG section parsing). */\nexport const SHARE_STALL_SIZE_PREFIX = `${SHARE_RULER_ICON} Stall size:`;\n\n/** Dollar marker for price-range share copy (U+0024 $ — text, not emoji, so it stays black). */\nexport const SHARE_DOLLAR_ICON = \"$\";\n\n/** Prefix for application price-range line (share text + OG section parsing). */\nexport const SHARE_PRICE_RANGE_PREFIX = `${SHARE_DOLLAR_ICON} Price range:`;\n\n/** Alarm clock for invitation application-deadline share copy (U+23F0 ⏰). */\nexport const SHARE_CLOCK_ICON = \"\\u{23F0}\";\n\n/** Prefix for the invitation application-deadline sentence (share text + OG section parsing). */\nexport const SHARE_APPLICATION_DEADLINE_PREFIX = `${SHARE_CLOCK_ICON} Application deadline:`;\n\n/** First line on share sheet messages, Facebook SDK quote, and `og:description`. */\nexport const SHARE_MORE_INFO_LINE = \"Shared from ClueMart\";\n\nexport const DEFAULT_SHARE_OG_IMAGE = `${SHARE_SITE_URL}/assets/logo.webp`;\n\nexport const RESOURCE_SHARE_TYPES = [\n \"market\",\n \"stallholder\",\n \"partner\",\n \"affiliate\",\n \"school\",\n] as const;\n\nexport type ResourceShareType = (typeof RESOURCE_SHARE_TYPES)[number];\n\nexport const POST_SHARE_RESOURCE_TYPES = [\n \"market_faces\",\n \"clue_bites\",\n \"play_and_win\",\n] as const;\n\nexport type PostShareResourceType = (typeof POST_SHARE_RESOURCE_TYPES)[number];\n\nexport type ShareResourceType =\n | ResourceShareType\n | PostShareResourceType\n | RelationShareResourceType;\n\nexport const SHARE_RESOURCE_LABEL: Record<ShareResourceType, string> = {\n [RELATION_SHARE_APPLICATION]: \"Application\",\n [RELATION_SHARE_INVITATION]: \"Invitation\",\n clue_bites: \"Clue Bites\",\n market_faces: \"Market Faces\",\n play_and_win: \"Play & Win\",\n market: \"Market\",\n partner: \"Partner\",\n stallholder: \"Stallholder\",\n affiliate: \"Affiliate\",\n school: \"School\",\n};\n\nexport function isPostShareResourceType(\n resourceType: ShareResourceType,\n): resourceType is PostShareResourceType {\n return (POST_SHARE_RESOURCE_TYPES as readonly string[]).includes(\n resourceType,\n );\n}\n","import { SHARE_MORE_INFO_LINE } from \"./constants\";\n\n/** Blank line between share sections — title, address, dates, URL, etc. */\nexport const SHARE_DESCRIPTION_SECTION_BREAK = \"\\n\\n\";\n\n/**\n * Line break for `og:description` meta content. Use instead of `\\n` — Next.js\n * HTML serialisation collapses literal newlines to spaces; Facebook reads `&#10;`.\n */\nexport const OG_DESCRIPTION_LINE_BREAK = \"&#10;\";\n\n/** Joins OG description sections for Facebook link cards (and Twitter). */\nexport function joinShareOgDescriptionSections(\n sections: ReadonlyArray<string | false | null | undefined>,\n): string {\n return sections\n .map((section) => (typeof section === \"string\" ? section.trim() : \"\"))\n .filter((section): section is string => section.length > 0)\n .map((section) => section.replace(/\\n/g, OG_DESCRIPTION_LINE_BREAK))\n .join(OG_DESCRIPTION_LINE_BREAK);\n}\n\nexport function joinShareDescriptionSections(\n sections: ReadonlyArray<string | false | null | undefined>,\n): string {\n return sections\n .filter((section): section is string => Boolean(section))\n .join(SHARE_DESCRIPTION_SECTION_BREAK);\n}\n\n/** Prepends the standard share branding line when assembling display text. */\nexport function appendShareMoreInfoLine(description: string): string {\n const trimmed = description.trim();\n if (trimmed.startsWith(SHARE_MORE_INFO_LINE)) {\n return trimmed;\n }\n if (trimmed.length === 0) {\n return SHARE_MORE_INFO_LINE;\n }\n return joinShareDescriptionSections([SHARE_MORE_INFO_LINE, trimmed]);\n}\n","import { SHARE_MORE_INFO_LINE, type ShareResourceType } from \"./constants\";\nimport {\n joinShareOgDescriptionSections,\n SHARE_DESCRIPTION_SECTION_BREAK,\n} from \"./joinShareDescriptionSections\";\n\nexport {\n joinShareOgDescriptionSections,\n OG_DESCRIPTION_LINE_BREAK,\n SHARE_DESCRIPTION_SECTION_BREAK,\n} from \"./joinShareDescriptionSections\";\n\n/** Trims share text and collapses spaces per line; preserves `\\n\\n` section breaks. */\nconst LEADING_WHITESPACE = /^[ \\t]*/;\n\nexport function normalizeShareText(value: string | null | undefined): string {\n if (value == null) {\n return \"\";\n }\n return value\n .trim()\n .split(\"\\n\")\n .map((line) => {\n const leading = LEADING_WHITESPACE.exec(line)?.[0] ?? \"\";\n const rest = line\n .slice(leading.length)\n .trim()\n .replace(/[ \\t]{2,}/g, \" \");\n return leading + rest;\n })\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\");\n}\n\n/** Branding line placement — first so Facebook truncation does not drop it. */\nexport type ShareMessageFooterPlacement = \"before-body\";\n\nexport function shareMessageFooterPlacementForType(\n _shareType?: ShareResourceType,\n): ShareMessageFooterPlacement {\n return \"before-body\";\n}\n\n/**\n * Ordered sections for share-sheet / Facebook SDK quote text:\n * {@link SHARE_MORE_INFO_LINE} → title → description (full body or post caption).\n */\nexport function buildShareMessageSections(input: {\n title?: string | null;\n description?: string | null;\n shareType?: ShareResourceType;\n}): string[] {\n const title = normalizeShareText(input.title);\n const description = normalizeShareText(input.description);\n\n return [SHARE_MORE_INFO_LINE, title, description].filter(\n (section) => section.length > 0,\n );\n}\n\nexport function splitShareDescriptionSections(value: string): string[] {\n const trimmed = normalizeShareText(value);\n if (!trimmed) {\n return [];\n }\n\n if (/\\n\\n/.test(trimmed)) {\n return trimmed\n .split(/\\n\\n+/)\n .map((section) => normalizeShareText(section))\n .filter((section) => section.length > 0);\n }\n\n if (/\\n/.test(trimmed)) {\n return trimmed\n .split(/\\n+/)\n .map((section) => normalizeShareText(section))\n .filter((section) => section.length > 0);\n }\n\n return [trimmed];\n}\n\n/**\n * Formats share descriptions for Open Graph / Twitter meta tags.\n * Sections are joined with {@link OG_DESCRIPTION_LINE_BREAK} (`&#10;`).\n */\nexport function normalizeShareOgDescription(value: string): string {\n return joinShareOgDescriptionSections(splitShareDescriptionSections(value));\n}\n\n/**\n * Quote text for Facebook ShareDialog on iOS (`ShareLinkContent.quote`).\n *\n * Title + blank lines + body sections. URL is omitted — `contentUrl` supplies\n * the link card (OG on resource landing pages controls card title/image).\n */\nexport function buildFacebookShareQuote(\n title: string,\n description: string,\n shareType?: ShareResourceType,\n): string | undefined {\n const sections = buildShareMessageSections({ description, shareType, title });\n const quote = sections.join(SHARE_DESCRIPTION_SECTION_BREAK).trim();\n return quote.length > 0 ? quote : undefined;\n}\n\n/**\n * Open Graph / Twitter description from pre-built section strings.\n * Prefer {@link joinShareOgDescriptionSections} when sections are already known.\n */\nexport function buildShareOgDescriptionFromSections(\n sections: ReadonlyArray<string | false | null | undefined>,\n): string {\n return joinShareOgDescriptionSections(sections);\n}\n\n/** Open Graph / Twitter description — body sections only (`og:title` is separate). */\nexport function buildShareOgDescription(\n _title: string,\n description: string,\n): string {\n return joinShareOgDescriptionSections(\n splitShareDescriptionSections(description),\n );\n}\n\n/**\n * Strips emoji and symbols that do not render reliably in overlay SVG fonts.\n * Keeps letters, numbers, whitespace, and common sentence punctuation.\n */\nexport function stripOverlaySubtitleSpecialChars(text: string): string {\n const regex = /[^\\p{L}\\p{M}\\p{N}\\s.,!?'\"&\\-():;/]/gu;\n const result = text\n .replace(/\\p{Extended_Pictographic}/gu, \"\")\n .replace(regex, \"\");\n return result.trim();\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,262 @@
1
+ // src/auth/permissions/permissions.ts
2
+ var PERMISSIONS = [
3
+ "*",
4
+ // Dashboards
5
+ "dashboard.admin",
6
+ "dashboard.affiliate",
7
+ "dashboard.customer",
8
+ "dashboard.event",
9
+ "dashboard.partner",
10
+ "dashboard.school",
11
+ "dashboard.vendor",
12
+ // Admin: users
13
+ "users.delete",
14
+ "users.read",
15
+ "users.update",
16
+ // Admin: events
17
+ "events.create",
18
+ "events.delete",
19
+ "events.read",
20
+ "events.update",
21
+ // Admin: vendors
22
+ "vendors.create",
23
+ "vendors.delete",
24
+ "vendors.read",
25
+ "vendors.update",
26
+ // Admin: partners
27
+ "partners.create",
28
+ "partners.delete",
29
+ "partners.read",
30
+ "partners.update",
31
+ // Admin: schools
32
+ "schools.create",
33
+ "schools.delete",
34
+ "schools.read",
35
+ "schools.update",
36
+ // Admin: affiliates
37
+ "affiliates.create",
38
+ "affiliates.delete",
39
+ "affiliates.read",
40
+ "affiliates.update",
41
+ // Admin: ads / posts / settings
42
+ "ads.create",
43
+ "ads.delete",
44
+ "ads.read",
45
+ "ads.update",
46
+ "posts.create",
47
+ "posts.delete",
48
+ "posts.read",
49
+ "posts.update",
50
+ "settings.read",
51
+ "settings.update",
52
+ // Product: own-resource management
53
+ "affiliates.manage_own",
54
+ "events.manage_own",
55
+ "partners.manage_own",
56
+ "schools.manage_own",
57
+ "vendors.manage_own"
58
+ ];
59
+ var WILDCARD_PERMISSION = "*";
60
+
61
+ // src/auth/permissions/rolePermissions.ts
62
+ var ADMIN_PERMISSIONS = [
63
+ "dashboard.admin",
64
+ "events.read",
65
+ "events.create",
66
+ "events.update",
67
+ "events.delete",
68
+ "vendors.read",
69
+ "vendors.create",
70
+ "vendors.update",
71
+ "vendors.delete",
72
+ "partners.read",
73
+ "partners.create",
74
+ "partners.update",
75
+ "partners.delete",
76
+ "schools.read",
77
+ "schools.create",
78
+ "schools.update",
79
+ "schools.delete",
80
+ "affiliates.read",
81
+ "affiliates.create",
82
+ "affiliates.update",
83
+ "affiliates.delete",
84
+ "ads.read",
85
+ "ads.create",
86
+ "ads.update",
87
+ "ads.delete",
88
+ "posts.read",
89
+ "posts.create",
90
+ "posts.update",
91
+ "posts.delete"
92
+ ];
93
+ var ROLE_PERMISSIONS = {
94
+ ["super_admin" /* SUPER_ADMIN */]: ["*"],
95
+ ["admin" /* ADMIN */]: ADMIN_PERMISSIONS,
96
+ ["customer" /* CUSTOMER */]: ["dashboard.customer"],
97
+ ["event" /* EVENT */]: ["dashboard.event", "events.manage_own"],
98
+ ["vendor" /* VENDOR */]: ["dashboard.vendor", "vendors.manage_own"],
99
+ ["partner" /* PARTNER */]: ["dashboard.partner", "partners.manage_own"],
100
+ ["school" /* SCHOOL */]: ["dashboard.school", "schools.manage_own"],
101
+ ["affiliate" /* AFFILIATE */]: ["dashboard.affiliate", "affiliates.manage_own"]
102
+ };
103
+
104
+ // src/auth/permissions/helpers.ts
105
+ function normalizeRoles(roles) {
106
+ if (!roles?.length) return [];
107
+ return roles;
108
+ }
109
+ function getPermissionsForRoles(roles) {
110
+ const seen = /* @__PURE__ */ new Set();
111
+ const result = [];
112
+ for (const role of normalizeRoles(roles)) {
113
+ const perms = ROLE_PERMISSIONS[role] ?? [];
114
+ for (const perm of perms) {
115
+ if (!seen.has(perm)) {
116
+ seen.add(perm);
117
+ result.push(perm);
118
+ }
119
+ }
120
+ }
121
+ return result;
122
+ }
123
+ function permissionListIncludes(permissions, permission) {
124
+ if (!permissions?.length) return false;
125
+ const set = new Set(permissions);
126
+ if (set.has(WILDCARD_PERMISSION)) return true;
127
+ return set.has(permission);
128
+ }
129
+ function hasPermission(roles, permission) {
130
+ return permissionListIncludes(getPermissionsForRoles(roles), permission);
131
+ }
132
+ function hasAnyPermission(roles, permissions) {
133
+ if (permissions.length === 0) return false;
134
+ const granted = getPermissionsForRoles(roles);
135
+ return permissions.some((p) => permissionListIncludes(granted, p));
136
+ }
137
+ function hasAllPermissions(roles, permissions) {
138
+ if (permissions.length === 0) return true;
139
+ const granted = getPermissionsForRoles(roles);
140
+ return permissions.every((p) => permissionListIncludes(granted, p));
141
+ }
142
+ function hasRole(roles, role) {
143
+ return normalizeRoles(roles).includes(role);
144
+ }
145
+ function hasAnyRole(roles, checkRoles) {
146
+ if (checkRoles.length === 0) return false;
147
+ const set = new Set(normalizeRoles(roles));
148
+ return checkRoles.some((r) => set.has(r));
149
+ }
150
+
151
+ // src/auth/permissions/adminAppAccess.ts
152
+ var ADMIN_APP_ROLES = [
153
+ "super_admin" /* SUPER_ADMIN */,
154
+ "admin" /* ADMIN */,
155
+ "event" /* EVENT */,
156
+ "vendor" /* VENDOR */,
157
+ "partner" /* PARTNER */,
158
+ "school" /* SCHOOL */,
159
+ "affiliate" /* AFFILIATE */
160
+ ];
161
+ var ADMIN_DASHBOARD_CONTEXTS = [
162
+ {
163
+ context: "staff",
164
+ home: "/dashboard",
165
+ label: "Staff",
166
+ pathPrefixes: ["/dashboard"],
167
+ roles: ["super_admin" /* SUPER_ADMIN */, "admin" /* ADMIN */]
168
+ },
169
+ {
170
+ context: "event",
171
+ home: "/event/dashboard",
172
+ label: "Events",
173
+ pathPrefixes: ["/event"],
174
+ roles: ["event" /* EVENT */]
175
+ },
176
+ {
177
+ context: "vendor",
178
+ home: "/vendor/dashboard",
179
+ label: "Stallholders",
180
+ pathPrefixes: ["/vendor"],
181
+ roles: ["vendor" /* VENDOR */]
182
+ },
183
+ {
184
+ context: "partner",
185
+ home: "/partner/dashboard",
186
+ label: "Partners",
187
+ pathPrefixes: ["/partner"],
188
+ roles: ["partner" /* PARTNER */]
189
+ },
190
+ {
191
+ context: "school",
192
+ home: "/school/dashboard",
193
+ label: "Schools",
194
+ pathPrefixes: ["/school"],
195
+ roles: ["school" /* SCHOOL */]
196
+ },
197
+ {
198
+ context: "affiliate",
199
+ home: "/affiliate/dashboard",
200
+ label: "Affiliate",
201
+ pathPrefixes: ["/affiliate"],
202
+ roles: ["affiliate" /* AFFILIATE */]
203
+ }
204
+ ];
205
+ function canAccessAdminApp(roles) {
206
+ return hasAnyRole(roles, ADMIN_APP_ROLES);
207
+ }
208
+ function getUsableAdminContexts(roles) {
209
+ return ADMIN_DASHBOARD_CONTEXTS.filter((ctx) => hasAnyRole(roles, ctx.roles));
210
+ }
211
+ function getDefaultAdminHome(roles, preferredContext) {
212
+ const usable = getUsableAdminContexts(roles);
213
+ if (usable.length === 0) {
214
+ return "/login";
215
+ }
216
+ if (preferredContext) {
217
+ const preferred = usable.find((ctx) => ctx.context === preferredContext);
218
+ if (preferred) return preferred.home;
219
+ }
220
+ return usable[0].home;
221
+ }
222
+ function resolveAdminContextFromPath(pathname) {
223
+ for (const ctx of ADMIN_DASHBOARD_CONTEXTS) {
224
+ if (ctx.pathPrefixes.some(
225
+ (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`)
226
+ )) {
227
+ return ctx.context;
228
+ }
229
+ }
230
+ return null;
231
+ }
232
+ function canAccessAdminPath(roles, pathname) {
233
+ if (!canAccessAdminApp(roles)) return false;
234
+ const context = resolveAdminContextFromPath(pathname);
235
+ if (!context) {
236
+ return true;
237
+ }
238
+ const info = ADMIN_DASHBOARD_CONTEXTS.find((ctx) => ctx.context === context);
239
+ if (!info) return false;
240
+ return hasAnyRole(roles, info.roles);
241
+ }
242
+
243
+ export {
244
+ PERMISSIONS,
245
+ WILDCARD_PERMISSION,
246
+ ROLE_PERMISSIONS,
247
+ getPermissionsForRoles,
248
+ permissionListIncludes,
249
+ hasPermission,
250
+ hasAnyPermission,
251
+ hasAllPermissions,
252
+ hasRole,
253
+ hasAnyRole,
254
+ ADMIN_APP_ROLES,
255
+ ADMIN_DASHBOARD_CONTEXTS,
256
+ canAccessAdminApp,
257
+ getUsableAdminContexts,
258
+ getDefaultAdminHome,
259
+ resolveAdminContextFromPath,
260
+ canAccessAdminPath
261
+ };
262
+ //# sourceMappingURL=chunk-VPANTTZI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/permissions/permissions.ts","../src/auth/permissions/rolePermissions.ts","../src/auth/permissions/helpers.ts","../src/auth/permissions/adminAppAccess.ts"],"sourcesContent":["/**\n * Canonical permission IDs. Add new permissions here first, then map them in\n * ROLE_PERMISSIONS. Prefer resource.action names (e.g. users.read).\n */\nexport const PERMISSIONS = [\n \"*\",\n // Dashboards\n \"dashboard.admin\",\n \"dashboard.affiliate\",\n \"dashboard.customer\",\n \"dashboard.event\",\n \"dashboard.partner\",\n \"dashboard.school\",\n \"dashboard.vendor\",\n // Admin: users\n \"users.delete\",\n \"users.read\",\n \"users.update\",\n // Admin: events\n \"events.create\",\n \"events.delete\",\n \"events.read\",\n \"events.update\",\n // Admin: vendors\n \"vendors.create\",\n \"vendors.delete\",\n \"vendors.read\",\n \"vendors.update\",\n // Admin: partners\n \"partners.create\",\n \"partners.delete\",\n \"partners.read\",\n \"partners.update\",\n // Admin: schools\n \"schools.create\",\n \"schools.delete\",\n \"schools.read\",\n \"schools.update\",\n // Admin: affiliates\n \"affiliates.create\",\n \"affiliates.delete\",\n \"affiliates.read\",\n \"affiliates.update\",\n // Admin: ads / posts / settings\n \"ads.create\",\n \"ads.delete\",\n \"ads.read\",\n \"ads.update\",\n \"posts.create\",\n \"posts.delete\",\n \"posts.read\",\n \"posts.update\",\n \"settings.read\",\n \"settings.update\",\n // Product: own-resource management\n \"affiliates.manage_own\",\n \"events.manage_own\",\n \"partners.manage_own\",\n \"schools.manage_own\",\n \"vendors.manage_own\",\n] as const;\n\nexport type Permission = (typeof PERMISSIONS)[number];\n\nexport const WILDCARD_PERMISSION: Permission = \"*\";\n","import { EnumUserRole } from \"../../enums\";\n\nimport type { Permission } from \"./permissions\";\n\nconst ADMIN_PERMISSIONS: readonly Permission[] = [\n \"dashboard.admin\",\n \"events.read\",\n \"events.create\",\n \"events.update\",\n \"events.delete\",\n \"vendors.read\",\n \"vendors.create\",\n \"vendors.update\",\n \"vendors.delete\",\n \"partners.read\",\n \"partners.create\",\n \"partners.update\",\n \"partners.delete\",\n \"schools.read\",\n \"schools.create\",\n \"schools.update\",\n \"schools.delete\",\n \"affiliates.read\",\n \"affiliates.create\",\n \"affiliates.update\",\n \"affiliates.delete\",\n \"ads.read\",\n \"ads.create\",\n \"ads.update\",\n \"ads.delete\",\n \"posts.read\",\n \"posts.create\",\n \"posts.update\",\n \"posts.delete\",\n];\n\n/**\n * Static role → permissions map. Source of truth for access.\n * Permissions for a user = union of all their roles' lists.\n */\nexport const ROLE_PERMISSIONS: Record<EnumUserRole, readonly Permission[]> = {\n [EnumUserRole.SUPER_ADMIN]: [\"*\"],\n [EnumUserRole.ADMIN]: ADMIN_PERMISSIONS,\n [EnumUserRole.CUSTOMER]: [\"dashboard.customer\"],\n [EnumUserRole.EVENT]: [\"dashboard.event\", \"events.manage_own\"],\n [EnumUserRole.VENDOR]: [\"dashboard.vendor\", \"vendors.manage_own\"],\n [EnumUserRole.PARTNER]: [\"dashboard.partner\", \"partners.manage_own\"],\n [EnumUserRole.SCHOOL]: [\"dashboard.school\", \"schools.manage_own\"],\n [EnumUserRole.AFFILIATE]: [\"dashboard.affiliate\", \"affiliates.manage_own\"],\n};\n","import { EnumUserRole } from \"../../enums\";\n\nimport type { Permission } from \"./permissions\";\nimport { WILDCARD_PERMISSION } from \"./permissions\";\nimport { ROLE_PERMISSIONS } from \"./rolePermissions\";\n\nfunction normalizeRoles(\n roles: EnumUserRole[] | null | undefined,\n): EnumUserRole[] {\n if (!roles?.length) return [];\n return roles;\n}\n\n/**\n * Union of permissions for the given roles (deduped, stable order).\n */\nexport function getPermissionsForRoles(\n roles: EnumUserRole[] | null | undefined,\n): Permission[] {\n const seen = new Set<Permission>();\n const result: Permission[] = [];\n\n for (const role of normalizeRoles(roles)) {\n const perms = ROLE_PERMISSIONS[role] ?? [];\n for (const perm of perms) {\n if (!seen.has(perm)) {\n seen.add(perm);\n result.push(perm);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Check a concrete permission list (e.g. authUser.permissions) for a grant.\n * Honours the \"*\" wildcard.\n */\nexport function permissionListIncludes(\n permissions: readonly Permission[] | null | undefined,\n permission: Permission,\n): boolean {\n if (!permissions?.length) return false;\n const set = new Set(permissions);\n if (set.has(WILDCARD_PERMISSION)) return true;\n return set.has(permission);\n}\n\nexport function hasPermission(\n roles: EnumUserRole[] | null | undefined,\n permission: Permission,\n): boolean {\n return permissionListIncludes(getPermissionsForRoles(roles), permission);\n}\n\nexport function hasAnyPermission(\n roles: EnumUserRole[] | null | undefined,\n permissions: readonly Permission[],\n): boolean {\n if (permissions.length === 0) return false;\n const granted = getPermissionsForRoles(roles);\n return permissions.some((p) => permissionListIncludes(granted, p));\n}\n\nexport function hasAllPermissions(\n roles: EnumUserRole[] | null | undefined,\n permissions: readonly Permission[],\n): boolean {\n if (permissions.length === 0) return true;\n const granted = getPermissionsForRoles(roles);\n return permissions.every((p) => permissionListIncludes(granted, p));\n}\n\nexport function hasRole(\n roles: EnumUserRole[] | null | undefined,\n role: EnumUserRole,\n): boolean {\n return normalizeRoles(roles).includes(role);\n}\n\nexport function hasAnyRole(\n roles: EnumUserRole[] | null | undefined,\n checkRoles: readonly EnumUserRole[],\n): boolean {\n if (checkRoles.length === 0) return false;\n const set = new Set(normalizeRoles(roles));\n return checkRoles.some((r) => set.has(r));\n}\n","import { EnumUserRole } from \"../../enums\";\n\nimport { hasAnyRole } from \"./helpers\";\n\n/** Roles allowed to sign into the admin web app (CUSTOMER-only is denied). */\nexport const ADMIN_APP_ROLES = [\n EnumUserRole.SUPER_ADMIN,\n EnumUserRole.ADMIN,\n EnumUserRole.EVENT,\n EnumUserRole.VENDOR,\n EnumUserRole.PARTNER,\n EnumUserRole.SCHOOL,\n EnumUserRole.AFFILIATE,\n] as const;\n\nexport type AdminAppRole = (typeof ADMIN_APP_ROLES)[number];\n\nexport type AdminDashboardContext =\n | \"staff\"\n | \"event\"\n | \"vendor\"\n | \"partner\"\n | \"school\"\n | \"affiliate\";\n\nexport type AdminDashboardContextInfo = {\n context: AdminDashboardContext;\n home: string;\n label: string;\n /** Path prefixes that belong to this context (including home). */\n pathPrefixes: readonly string[];\n roles: readonly EnumUserRole[];\n};\n\n/**\n * Priority order for default home + role switcher.\n * Staff first, then product roles.\n */\nexport const ADMIN_DASHBOARD_CONTEXTS: readonly AdminDashboardContextInfo[] = [\n {\n context: \"staff\",\n home: \"/dashboard\",\n label: \"Staff\",\n pathPrefixes: [\"/dashboard\"],\n roles: [EnumUserRole.SUPER_ADMIN, EnumUserRole.ADMIN],\n },\n {\n context: \"event\",\n home: \"/event/dashboard\",\n label: \"Events\",\n pathPrefixes: [\"/event\"],\n roles: [EnumUserRole.EVENT],\n },\n {\n context: \"vendor\",\n home: \"/vendor/dashboard\",\n label: \"Stallholders\",\n pathPrefixes: [\"/vendor\"],\n roles: [EnumUserRole.VENDOR],\n },\n {\n context: \"partner\",\n home: \"/partner/dashboard\",\n label: \"Partners\",\n pathPrefixes: [\"/partner\"],\n roles: [EnumUserRole.PARTNER],\n },\n {\n context: \"school\",\n home: \"/school/dashboard\",\n label: \"Schools\",\n pathPrefixes: [\"/school\"],\n roles: [EnumUserRole.SCHOOL],\n },\n {\n context: \"affiliate\",\n home: \"/affiliate/dashboard\",\n label: \"Affiliate\",\n pathPrefixes: [\"/affiliate\"],\n roles: [EnumUserRole.AFFILIATE],\n },\n] as const;\n\nexport function canAccessAdminApp(\n roles: EnumUserRole[] | null | undefined,\n): boolean {\n return hasAnyRole(roles, ADMIN_APP_ROLES);\n}\n\nexport function getUsableAdminContexts(\n roles: EnumUserRole[] | null | undefined,\n): AdminDashboardContextInfo[] {\n return ADMIN_DASHBOARD_CONTEXTS.filter((ctx) => hasAnyRole(roles, ctx.roles));\n}\n\nexport function getDefaultAdminHome(\n roles: EnumUserRole[] | null | undefined,\n preferredContext?: AdminDashboardContext | null,\n): string {\n const usable = getUsableAdminContexts(roles);\n if (usable.length === 0) {\n return \"/login\";\n }\n\n if (preferredContext) {\n const preferred = usable.find((ctx) => ctx.context === preferredContext);\n if (preferred) return preferred.home;\n }\n\n return usable[0].home;\n}\n\nexport function resolveAdminContextFromPath(\n pathname: string,\n): AdminDashboardContext | null {\n for (const ctx of ADMIN_DASHBOARD_CONTEXTS) {\n if (\n ctx.pathPrefixes.some(\n (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`),\n )\n ) {\n return ctx.context;\n }\n }\n return null;\n}\n\nexport function canAccessAdminPath(\n roles: EnumUserRole[] | null | undefined,\n pathname: string,\n): boolean {\n if (!canAccessAdminApp(roles)) return false;\n\n const context = resolveAdminContextFromPath(pathname);\n if (!context) {\n // Authenticated admin-app users may hit non-dashboard admin routes later;\n // unknown paths are allowed only if they have any admin-app role.\n return true;\n }\n\n const info = ADMIN_DASHBOARD_CONTEXTS.find((ctx) => ctx.context === context);\n if (!info) return false;\n return hasAnyRole(roles, info.roles);\n}\n"],"mappings":"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","names":[]}