@timardex/cluemart-shared 1.5.599 → 1.5.600
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.
- package/dist/{chunk-YV2JDG4R.mjs → chunk-3VUHAHP7.mjs} +5 -86
- package/dist/chunk-3VUHAHP7.mjs.map +1 -0
- package/dist/{chunk-HBVPPRHO.mjs → chunk-GSOSJNID.mjs} +22 -21
- package/dist/chunk-GSOSJNID.mjs.map +1 -0
- package/dist/chunk-X4VPNOHX.mjs +88 -0
- package/dist/chunk-X4VPNOHX.mjs.map +1 -0
- package/dist/{chunk-2NQUR2AV.mjs → chunk-ZDDWPO5Y.mjs} +2 -2
- package/dist/formFields/index.mjs +3 -2
- package/dist/hooks/index.mjs +8 -6
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.cjs +22 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +20 -6
- package/dist/index.d.ts +20 -6
- package/dist/index.mjs +17 -20
- package/dist/index.mjs.map +1 -1
- package/dist/sharing/index.cjs +63 -22
- package/dist/sharing/index.cjs.map +1 -1
- package/dist/sharing/index.d.mts +20 -6
- package/dist/sharing/index.d.ts +20 -6
- package/dist/sharing/index.mjs +14 -3
- package/dist/utils/index.mjs +13 -11
- package/package.json +1 -1
- package/dist/chunk-HBVPPRHO.mjs.map +0 -1
- package/dist/chunk-YV2JDG4R.mjs.map +0 -1
- /package/dist/{chunk-2NQUR2AV.mjs.map → chunk-ZDDWPO5Y.mjs.map} +0 -0
package/dist/sharing/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,12 +17,21 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/sharing/index.ts
|
|
21
31
|
var sharing_exports = {};
|
|
22
32
|
__export(sharing_exports, {
|
|
23
33
|
DEFAULT_SHARE_OG_IMAGE: () => DEFAULT_SHARE_OG_IMAGE,
|
|
34
|
+
OG_DESCRIPTION_LINE_BREAK: () => OG_DESCRIPTION_LINE_BREAK,
|
|
24
35
|
POST_SHARE_RESOURCE_TYPES: () => POST_SHARE_RESOURCE_TYPES,
|
|
25
36
|
PUBLIC_SHARE_PATH_TYPES: () => PUBLIC_SHARE_PATH_TYPES,
|
|
26
37
|
RELATION_SHARE_APPLICATION: () => RELATION_SHARE_APPLICATION,
|
|
@@ -37,20 +48,53 @@ __export(sharing_exports, {
|
|
|
37
48
|
buildFacebookShareQuote: () => buildFacebookShareQuote,
|
|
38
49
|
buildInvitationShareDescription: () => buildInvitationShareDescription,
|
|
39
50
|
buildShareOgDescription: () => buildShareOgDescription,
|
|
51
|
+
buildShareOgDescriptionFromSections: () => buildShareOgDescriptionFromSections,
|
|
40
52
|
buildSharePagePath: () => buildSharePagePath,
|
|
41
53
|
buildShareUrl: () => buildShareUrl,
|
|
42
54
|
formatCategoryLabel: () => formatCategoryLabel,
|
|
55
|
+
formatShareMarketDate: () => formatShareMarketDate,
|
|
43
56
|
formatShareSectionsForCompactDisplay: () => formatShareSectionsForCompactDisplay,
|
|
44
57
|
formatShareSectionsForMultilineDisplay: () => formatShareSectionsForMultilineDisplay,
|
|
45
58
|
formatStallCapacityLabel: () => formatStallCapacityLabel,
|
|
46
59
|
isPostShareResourceType: () => isPostShareResourceType,
|
|
47
60
|
isRelationShareResourceType: () => isRelationShareResourceType,
|
|
48
61
|
joinShareDescriptionSections: () => joinShareDescriptionSections,
|
|
62
|
+
joinShareOgDescriptionSections: () => joinShareOgDescriptionSections,
|
|
49
63
|
normalizeShareOgDescription: () => normalizeShareOgDescription,
|
|
50
|
-
normalizeShareRouteId: () => normalizeShareRouteId
|
|
64
|
+
normalizeShareRouteId: () => normalizeShareRouteId,
|
|
65
|
+
splitShareDescriptionSections: () => splitShareDescriptionSections
|
|
51
66
|
});
|
|
52
67
|
module.exports = __toCommonJS(sharing_exports);
|
|
53
68
|
|
|
69
|
+
// src/utils/date.ts
|
|
70
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
71
|
+
var import_customParseFormat = __toESM(require("dayjs/plugin/customParseFormat.js"));
|
|
72
|
+
var import_isSameOrAfter = __toESM(require("dayjs/plugin/isSameOrAfter.js"));
|
|
73
|
+
var import_timezone = __toESM(require("dayjs/plugin/timezone.js"));
|
|
74
|
+
var import_utc = __toESM(require("dayjs/plugin/utc.js"));
|
|
75
|
+
var dateFormat = "DD-MM-YYYY";
|
|
76
|
+
var timeFormat = "HH:mm";
|
|
77
|
+
import_dayjs.default.extend(import_customParseFormat.default);
|
|
78
|
+
import_dayjs.default.extend(import_utc.default);
|
|
79
|
+
import_dayjs.default.extend(import_timezone.default);
|
|
80
|
+
import_dayjs.default.extend(import_isSameOrAfter.default);
|
|
81
|
+
var formatDate = (dateStr, display = "datetime", timeStr) => {
|
|
82
|
+
const dateTimeStr = timeStr ? `${dateStr} ${timeStr}` : dateStr;
|
|
83
|
+
const dateTime = timeStr ? (0, import_dayjs.default)(dateTimeStr, `${dateFormat} ${timeFormat}`) : (0, import_dayjs.default)(dateStr, dateFormat);
|
|
84
|
+
const formattedDate = dateTime.format("dddd, D MMMM, YYYY");
|
|
85
|
+
const formattedTime = dateTime.format("h:mm a");
|
|
86
|
+
switch (display) {
|
|
87
|
+
case "date":
|
|
88
|
+
return formattedDate;
|
|
89
|
+
case "time":
|
|
90
|
+
return formattedTime;
|
|
91
|
+
case "datetime":
|
|
92
|
+
return `${formattedDate} at ${formattedTime}`;
|
|
93
|
+
default:
|
|
94
|
+
return formattedDate;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
54
98
|
// src/sharing/formatCategoryLabel.ts
|
|
55
99
|
function formatCategoryLabel(category) {
|
|
56
100
|
const subcategoryNames = category.subcategories.map((subcategory) => subcategory.name).filter(Boolean);
|
|
@@ -63,21 +107,17 @@ function formatCategoryLabel(category) {
|
|
|
63
107
|
// src/sharing/joinShareDescriptionSections.ts
|
|
64
108
|
var SHARE_DESCRIPTION_SECTION_SEPARATOR = " \xB7 ";
|
|
65
109
|
var SHARE_DESCRIPTION_SECTION_BREAK = "\n\n";
|
|
110
|
+
var OG_DESCRIPTION_LINE_BREAK = " ";
|
|
111
|
+
function joinShareOgDescriptionSections(sections) {
|
|
112
|
+
return sections.map((section) => typeof section === "string" ? section.trim() : "").filter((section) => section.length > 0).join(OG_DESCRIPTION_LINE_BREAK);
|
|
113
|
+
}
|
|
66
114
|
function joinShareDescriptionSections(sections) {
|
|
67
115
|
return sections.filter((section) => Boolean(section)).join(SHARE_DESCRIPTION_SECTION_BREAK);
|
|
68
116
|
}
|
|
69
117
|
|
|
70
118
|
// src/sharing/buildRelationShareDescription.ts
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
return new Intl.DateTimeFormat("en-NZ", {
|
|
74
|
-
day: "numeric",
|
|
75
|
-
month: "short",
|
|
76
|
-
year: "numeric"
|
|
77
|
-
}).format(new Date(isoDate));
|
|
78
|
-
} catch {
|
|
79
|
-
return isoDate;
|
|
80
|
-
}
|
|
119
|
+
function formatShareMarketDate(dateStr) {
|
|
120
|
+
return formatDate(dateStr, "date");
|
|
81
121
|
}
|
|
82
122
|
function formatStallCapacityLabel(stallCapacity) {
|
|
83
123
|
return stallCapacity > 0 ? ` (${stallCapacity} spaces available)` : " - Full";
|
|
@@ -91,7 +131,7 @@ function buildInvitationShareDescription(event, eventInfo) {
|
|
|
91
131
|
const sections = [
|
|
92
132
|
event.location.fullAddress,
|
|
93
133
|
...event.dateTime.map((date) => {
|
|
94
|
-
const start =
|
|
134
|
+
const start = formatShareMarketDate(date.startDate);
|
|
95
135
|
return `Market date: ${start}`;
|
|
96
136
|
}),
|
|
97
137
|
`Application deadline: vendors must apply at least ${eventInfo.applicationDeadlineHours} hours before each market date.`,
|
|
@@ -223,14 +263,7 @@ function formatShareSectionsForCompactDisplay(value) {
|
|
|
223
263
|
);
|
|
224
264
|
}
|
|
225
265
|
function normalizeShareOgDescription(value) {
|
|
226
|
-
|
|
227
|
-
if (!trimmed) {
|
|
228
|
-
return "";
|
|
229
|
-
}
|
|
230
|
-
if (/\n\n/.test(trimmed) || trimmed.includes(SHARE_DESCRIPTION_SECTION_SEPARATOR)) {
|
|
231
|
-
return formatShareSectionsForCompactDisplay(trimmed);
|
|
232
|
-
}
|
|
233
|
-
return trimmed.replace(/\s+/g, " ").trim();
|
|
266
|
+
return joinShareOgDescriptionSections(splitShareDescriptionSections(value));
|
|
234
267
|
}
|
|
235
268
|
function buildFacebookShareQuote(title, description) {
|
|
236
269
|
const titleSection = normalizeShareSection(title);
|
|
@@ -241,8 +274,11 @@ function buildFacebookShareQuote(title, description) {
|
|
|
241
274
|
const quote = sections.join(SHARE_DESCRIPTION_SECTION_BREAK).trim();
|
|
242
275
|
return quote.length > 0 ? quote : void 0;
|
|
243
276
|
}
|
|
277
|
+
function buildShareOgDescriptionFromSections(sections) {
|
|
278
|
+
return joinShareOgDescriptionSections(sections);
|
|
279
|
+
}
|
|
244
280
|
function buildShareOgDescription(_title, description) {
|
|
245
|
-
return
|
|
281
|
+
return joinShareOgDescriptionSections(splitShareDescriptionSections(description));
|
|
246
282
|
}
|
|
247
283
|
|
|
248
284
|
// src/sharing/normalizeShareRouteId.ts
|
|
@@ -259,6 +295,7 @@ function buildSharePagePath(resourceType, rawId) {
|
|
|
259
295
|
// Annotate the CommonJS export names for ESM import in node:
|
|
260
296
|
0 && (module.exports = {
|
|
261
297
|
DEFAULT_SHARE_OG_IMAGE,
|
|
298
|
+
OG_DESCRIPTION_LINE_BREAK,
|
|
262
299
|
POST_SHARE_RESOURCE_TYPES,
|
|
263
300
|
PUBLIC_SHARE_PATH_TYPES,
|
|
264
301
|
RELATION_SHARE_APPLICATION,
|
|
@@ -275,16 +312,20 @@ function buildSharePagePath(resourceType, rawId) {
|
|
|
275
312
|
buildFacebookShareQuote,
|
|
276
313
|
buildInvitationShareDescription,
|
|
277
314
|
buildShareOgDescription,
|
|
315
|
+
buildShareOgDescriptionFromSections,
|
|
278
316
|
buildSharePagePath,
|
|
279
317
|
buildShareUrl,
|
|
280
318
|
formatCategoryLabel,
|
|
319
|
+
formatShareMarketDate,
|
|
281
320
|
formatShareSectionsForCompactDisplay,
|
|
282
321
|
formatShareSectionsForMultilineDisplay,
|
|
283
322
|
formatStallCapacityLabel,
|
|
284
323
|
isPostShareResourceType,
|
|
285
324
|
isRelationShareResourceType,
|
|
286
325
|
joinShareDescriptionSections,
|
|
326
|
+
joinShareOgDescriptionSections,
|
|
287
327
|
normalizeShareOgDescription,
|
|
288
|
-
normalizeShareRouteId
|
|
328
|
+
normalizeShareRouteId,
|
|
329
|
+
splitShareDescriptionSections
|
|
289
330
|
});
|
|
290
331
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/sharing/index.ts","../../src/sharing/formatCategoryLabel.ts","../../src/sharing/joinShareDescriptionSections.ts","../../src/sharing/buildRelationShareDescription.ts","../../src/sharing/relationShareTypes.ts","../../src/sharing/constants.ts","../../src/sharing/buildShareUrl.ts","../../src/sharing/normalizeShareDescription.ts","../../src/sharing/normalizeShareRouteId.ts"],"sourcesContent":["export * from \"./buildRelationShareDescription\";\nexport * from \"./shareRelationTypes\";\nexport * from \"./buildShareUrl\";\nexport * from \"./constants\";\nexport * from \"./formatCategoryLabel\";\nexport * from \"./joinShareDescriptionSections\";\nexport * from \"./normalizeShareDescription\";\nexport * from \"./normalizeShareRouteId\";\nexport * from \"./relationShareTypes\";\n","import type { ShareVendorCategory } from \"./shareRelationTypes\";\n\nexport function formatCategoryLabel(category: ShareVendorCategory): string {\n const subcategoryNames = category.subcategories\n .map((subcategory) => subcategory.name)\n .filter(Boolean);\n\n if (subcategoryNames.length === 0) {\n return category.name;\n }\n\n return `${category.name} (${subcategoryNames.join(\", \")})`;\n}\n","/** Visible separator for multi-block share text when line breaks are stripped (legacy OG). */\nexport const SHARE_DESCRIPTION_SECTION_SEPARATOR = \" · \";\n\n/** Blank line between share sections — title, address, dates, URL, etc. */\nexport const SHARE_DESCRIPTION_SECTION_BREAK = \"\\n\\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","import { formatCategoryLabel } from \"./formatCategoryLabel\";\nimport { joinShareDescriptionSections } from \"./joinShareDescriptionSections\";\nimport type {\n ShareEventForInvitation,\n ShareEventInfoForInvitation,\n ShareVendorForApplication,\n ShareVendorInfoForApplication,\n} from \"./shareRelationTypes\";\n\nexport type {\n ShareEventDateTime,\n ShareEventForInvitation,\n ShareEventInfoForInvitation,\n ShareStallType,\n ShareVendorCategory,\n ShareVendorForApplication,\n ShareVendorInfoForApplication,\n} from \"./shareRelationTypes\";\n\nfunction formatShareDate(isoDate: string): string {\n try {\n return new Intl.DateTimeFormat(\"en-NZ\", {\n day: \"numeric\",\n month: \"short\",\n year: \"numeric\",\n }).format(new Date(isoDate));\n } catch {\n return isoDate;\n }\n}\n\nexport function formatStallCapacityLabel(stallCapacity: number): string {\n return stallCapacity > 0 ? ` (${stallCapacity} spaces available)` : \" - Full\";\n}\n\nexport function buildInvitationShareDescription(\n event: ShareEventForInvitation,\n eventInfo: ShareEventInfoForInvitation | null | undefined,\n): string {\n const stallTypes =\n eventInfo?.dateTime?.flatMap((date) => date.stallTypes) ?? [];\n\n if (!eventInfo || stallTypes.length === 0) {\n return event.description?.trim() || \"\";\n }\n\n const requirementLabels = (eventInfo.requirements ?? [])\n .filter((item) => item.value)\n .map((item) => item.label);\n\n const sections = [\n event.location.fullAddress,\n ...event.dateTime.map((date) => {\n const start = formatShareDate(date.startDate);\n // DO NOT share end date for now, we will add it later if needed\n return `Market date: ${start}`;\n }),\n `Application deadline: vendors must apply at least ${eventInfo.applicationDeadlineHours} hours before each market date.`,\n ...stallTypes.map(\n (stall) =>\n `Stall: ${stall.label} — $${stall.price}${formatStallCapacityLabel(stall.stallCapacity)}`,\n ),\n requirementLabels.length > 0 &&\n `Requirements: ${requirementLabels.join(\", \")}`,\n ];\n\n return joinShareDescriptionSections(sections);\n}\n\nexport function buildApplicationShareDescription(\n vendor: ShareVendorForApplication,\n vendorInfo: ShareVendorInfoForApplication | null | undefined,\n): string {\n const categoryLabels = vendor.categories.map((category) =>\n formatCategoryLabel(category),\n );\n\n if (!vendorInfo) {\n return vendor.description?.trim() || \"\";\n }\n\n const compliance = vendorInfo.compliance;\n const complianceLabels = [\n compliance?.liabilityInsurance && \"Liability insurance\",\n compliance?.foodBeverageLicense && \"Food & beverage licence\",\n ].filter(Boolean);\n\n const profileDescription = vendor.description?.trim();\n\n const sections = [\n categoryLabels.length > 0 && `Categories: ${categoryLabels.join(\", \")}`,\n `Stall size: ${vendorInfo.stallInfo.size.width}m × ${vendorInfo.stallInfo.size.depth}m`,\n `Compliance: ${complianceLabels.length > 0 ? complianceLabels.join(\", \") : \"Not specified\"}`,\n `Price range: $${vendorInfo.product.priceRange.min} – $${vendorInfo.product.priceRange.max}`,\n profileDescription,\n ];\n\n return joinShareDescriptionSections(sections);\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\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_SHARE_RESOURCE_TYPES,\n isRelationShareResourceType,\n type RelationShareResourceType,\n} from \"./relationShareTypes\";\n\nexport const SHARE_SITE_URL = \"https://cluemart.co.nz\";\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] as const;\n\nexport type ResourceShareType = (typeof RESOURCE_SHARE_TYPES)[number];\n\nexport const POST_SHARE_RESOURCE_TYPES = [\n \"daily_meets\",\n \"daily_tips\",\n \"daily_games\",\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 daily_games: \"Daily Game\",\n daily_meets: \"Daily Meet\",\n daily_tips: \"Daily Tip\",\n market: \"Market\",\n partner: \"Partner\",\n stallholder: \"Stallholder\",\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 {\n POST_SHARE_RESOURCE_TYPES,\n RESOURCE_SHARE_TYPES,\n SHARE_SITE_URL,\n} from \"./constants\";\nimport {\n RELATION_SHARE_APPLICATION,\n RELATION_SHARE_INVITATION,\n} from \"./relationShareTypes\";\n\n/** Path segments for public resource share URLs (markets, posts, etc.). */\nexport const PUBLIC_SHARE_PATH_TYPES = [\n ...RESOURCE_SHARE_TYPES,\n ...POST_SHARE_RESOURCE_TYPES,\n] as const;\n\nexport type PublicSharePathType = (typeof PUBLIC_SHARE_PATH_TYPES)[number];\n\n/** @deprecated Use {@link PUBLIC_SHARE_PATH_TYPES} — kept for mobile deep-link helpers. */\nexport const RESOURCE_SHARE_TYPES_FOR_URL = PUBLIC_SHARE_PATH_TYPES;\n\nexport type RelationSharePathType =\n | typeof RELATION_SHARE_INVITATION\n | typeof RELATION_SHARE_APPLICATION;\n\nexport type ShareType = PublicSharePathType | RelationSharePathType;\n\n/** Alternation for deep-link regexes — keep in sync with {@link ShareType}. */\nexport const SHARE_TYPE_PATH_REGEX = [\n ...PUBLIC_SHARE_PATH_TYPES,\n RELATION_SHARE_APPLICATION,\n RELATION_SHARE_INVITATION,\n].join(\"|\");\n\nexport function buildShareUrl(type: ShareType, id: string): string {\n return `${SHARE_SITE_URL}/share/${type}/${encodeURIComponent(id)}`;\n}\n","import {\n SHARE_DESCRIPTION_SECTION_BREAK,\n SHARE_DESCRIPTION_SECTION_SEPARATOR,\n} from \"./joinShareDescriptionSections\";\n\nconst LEGACY_BULLET_PREFIX = \"• \";\n\n/** Trims a share section and collapses spaces per line; preserves line breaks. */\nfunction normalizeShareSection(value: string | null | undefined): string {\n if (value == null) {\n return \"\";\n }\n return value\n .trim()\n .split(\"\\n\")\n .map((line) => line.trim().replace(/[ \\t]+/g, \" \"))\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\");\n}\n\nfunction stripLegacyBulletPrefix(section: string): string {\n return section.startsWith(LEGACY_BULLET_PREFIX)\n ? section.slice(LEGACY_BULLET_PREFIX.length)\n : section;\n}\n\nfunction splitShareDescriptionSections(value: string): string[] {\n const trimmed = value.trim();\n if (!trimmed) {\n return [];\n }\n\n if (trimmed.includes(SHARE_DESCRIPTION_SECTION_SEPARATOR)) {\n return trimmed\n .split(SHARE_DESCRIPTION_SECTION_SEPARATOR)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n if (/\\n\\n/.test(trimmed)) {\n return trimmed\n .split(/\\n\\n+/)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n if (/\\n/.test(trimmed)) {\n return trimmed\n .split(/\\n+/)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n return [stripLegacyBulletPrefix(normalizeShareSection(trimmed))];\n}\n\nfunction collapseExcessiveBlankLines(value: string): string {\n return value.replace(/\\n{4,}/g, \"\\n\\n\\n\").trim();\n}\n\n/**\n * Share copy with a blank line between each section (share sheet message, previews).\n */\nexport function formatShareSectionsForMultilineDisplay(value: string): string {\n return collapseExcessiveBlankLines(\n splitShareDescriptionSections(value).join(SHARE_DESCRIPTION_SECTION_BREAK),\n );\n}\n\n/**\n * Formats multiline share copy for UIs that strip line breaks (legacy OG one-liners).\n */\nexport function formatShareSectionsForCompactDisplay(value: string): string {\n return splitShareDescriptionSections(value).join(\n SHARE_DESCRIPTION_SECTION_SEPARATOR,\n );\n}\n\n/**\n * Formats share descriptions for Open Graph / Twitter meta tags when crawlers\n * collapse line breaks.\n */\nexport function normalizeShareOgDescription(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"\";\n }\n\n if (\n /\\n\\n/.test(trimmed) ||\n trimmed.includes(SHARE_DESCRIPTION_SECTION_SEPARATOR)\n ) {\n return formatShareSectionsForCompactDisplay(trimmed);\n }\n\n return trimmed.replace(/\\s+/g, \" \").trim();\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 `/share/*` controls card title/image).\n */\nexport function buildFacebookShareQuote(\n title: string,\n description: string,\n): string | undefined {\n const titleSection = normalizeShareSection(title);\n const body = formatShareSectionsForMultilineDisplay(\n normalizeShareSection(description),\n );\n const sections = [titleSection, body].filter((section) => section.length > 0);\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 — single line, no repeated `og:title`.\n *\n * Facebook's link card does not render `\\n`; sections are joined with ` · `.\n */\nexport function buildShareOgDescription(\n _title: string,\n description: string,\n): string {\n return normalizeShareOgDescription(description);\n}\n","import type { ShareResourceType } from \"./constants\";\n\nexport function normalizeShareRouteId(id: string): string {\n try {\n return decodeURIComponent(id);\n } catch {\n return id;\n }\n}\n\nexport function buildSharePagePath(\n resourceType: ShareResourceType,\n rawId: string,\n): string {\n return `/share/${resourceType}/${encodeURIComponent(normalizeShareRouteId(rawId))}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/sharing/index.ts","../../src/utils/date.ts","../../src/sharing/formatCategoryLabel.ts","../../src/sharing/joinShareDescriptionSections.ts","../../src/sharing/buildRelationShareDescription.ts","../../src/sharing/relationShareTypes.ts","../../src/sharing/constants.ts","../../src/sharing/buildShareUrl.ts","../../src/sharing/normalizeShareDescription.ts","../../src/sharing/normalizeShareRouteId.ts"],"sourcesContent":["export * from \"./buildRelationShareDescription\";\nexport * from \"./shareRelationTypes\";\nexport * from \"./buildShareUrl\";\nexport * from \"./constants\";\nexport * from \"./formatCategoryLabel\";\nexport * from \"./joinShareDescriptionSections\";\nexport * from \"./normalizeShareDescription\";\nexport * from \"./normalizeShareRouteId\";\nexport * from \"./relationShareTypes\";\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\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\" && !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 || !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","import type { ShareVendorCategory } from \"./shareRelationTypes\";\n\nexport function formatCategoryLabel(category: ShareVendorCategory): string {\n const subcategoryNames = category.subcategories\n .map((subcategory) => subcategory.name)\n .filter(Boolean);\n\n if (subcategoryNames.length === 0) {\n return category.name;\n }\n\n return `${category.name} (${subcategoryNames.join(\", \")})`;\n}\n","/** Visible separator for multi-block share text when line breaks are stripped (legacy OG). */\nexport const SHARE_DESCRIPTION_SECTION_SEPARATOR = \" · \";\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 ` `.\n */\nexport const OG_DESCRIPTION_LINE_BREAK = \" \";\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 .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","import { formatDate } from \"../utils/date\";\n\nimport { formatCategoryLabel } from \"./formatCategoryLabel\";\nimport { joinShareDescriptionSections } from \"./joinShareDescriptionSections\";\nimport type {\n ShareEventForInvitation,\n ShareEventInfoForInvitation,\n ShareVendorForApplication,\n ShareVendorInfoForApplication,\n} from \"./shareRelationTypes\";\n\nexport type {\n ShareEventDateTime,\n ShareEventForInvitation,\n ShareEventInfoForInvitation,\n ShareStallType,\n ShareVendorCategory,\n ShareVendorForApplication,\n ShareVendorInfoForApplication,\n} from \"./shareRelationTypes\";\n\n/** Formats event `startDate` (`DD-MM-YYYY`) for share copy — same as share preview UI. */\nexport function formatShareMarketDate(dateStr: string): string {\n return formatDate(dateStr, \"date\");\n}\n\nexport function formatStallCapacityLabel(stallCapacity: number): string {\n return stallCapacity > 0 ? ` (${stallCapacity} spaces available)` : \" - Full\";\n}\n\nexport function buildInvitationShareDescription(\n event: ShareEventForInvitation,\n eventInfo: ShareEventInfoForInvitation | null | undefined,\n): string {\n const stallTypes =\n eventInfo?.dateTime?.flatMap((date) => date.stallTypes) ?? [];\n\n if (!eventInfo || stallTypes.length === 0) {\n return event.description?.trim() || \"\";\n }\n\n const requirementLabels = (eventInfo.requirements ?? [])\n .filter((item) => item.value)\n .map((item) => item.label);\n\n const sections = [\n event.location.fullAddress,\n ...event.dateTime.map((date) => {\n const start = formatShareMarketDate(date.startDate);\n // DO NOT share end date for now, we will add it later if needed\n return `Market date: ${start}`;\n }),\n `Application deadline: vendors must apply at least ${eventInfo.applicationDeadlineHours} hours before each market date.`,\n ...stallTypes.map(\n (stall) =>\n `Stall: ${stall.label} — $${stall.price}${formatStallCapacityLabel(stall.stallCapacity)}`,\n ),\n requirementLabels.length > 0 &&\n `Requirements: ${requirementLabels.join(\", \")}`,\n ];\n\n return joinShareDescriptionSections(sections);\n}\n\nexport function buildApplicationShareDescription(\n vendor: ShareVendorForApplication,\n vendorInfo: ShareVendorInfoForApplication | null | undefined,\n): string {\n const categoryLabels = vendor.categories.map((category) =>\n formatCategoryLabel(category),\n );\n\n if (!vendorInfo) {\n return vendor.description?.trim() || \"\";\n }\n\n const compliance = vendorInfo.compliance;\n const complianceLabels = [\n compliance?.liabilityInsurance && \"Liability insurance\",\n compliance?.foodBeverageLicense && \"Food & beverage licence\",\n ].filter(Boolean);\n\n const profileDescription = vendor.description?.trim();\n\n const sections = [\n categoryLabels.length > 0 && `Categories: ${categoryLabels.join(\", \")}`,\n `Stall size: ${vendorInfo.stallInfo.size.width}m × ${vendorInfo.stallInfo.size.depth}m`,\n `Compliance: ${complianceLabels.length > 0 ? complianceLabels.join(\", \") : \"Not specified\"}`,\n `Price range: $${vendorInfo.product.priceRange.min} – $${vendorInfo.product.priceRange.max}`,\n profileDescription,\n ];\n\n return joinShareDescriptionSections(sections);\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\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_SHARE_RESOURCE_TYPES,\n isRelationShareResourceType,\n type RelationShareResourceType,\n} from \"./relationShareTypes\";\n\nexport const SHARE_SITE_URL = \"https://cluemart.co.nz\";\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] as const;\n\nexport type ResourceShareType = (typeof RESOURCE_SHARE_TYPES)[number];\n\nexport const POST_SHARE_RESOURCE_TYPES = [\n \"daily_meets\",\n \"daily_tips\",\n \"daily_games\",\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 daily_games: \"Daily Game\",\n daily_meets: \"Daily Meet\",\n daily_tips: \"Daily Tip\",\n market: \"Market\",\n partner: \"Partner\",\n stallholder: \"Stallholder\",\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 {\n POST_SHARE_RESOURCE_TYPES,\n RESOURCE_SHARE_TYPES,\n SHARE_SITE_URL,\n} from \"./constants\";\nimport {\n RELATION_SHARE_APPLICATION,\n RELATION_SHARE_INVITATION,\n} from \"./relationShareTypes\";\n\n/** Path segments for public resource share URLs (markets, posts, etc.). */\nexport const PUBLIC_SHARE_PATH_TYPES = [\n ...RESOURCE_SHARE_TYPES,\n ...POST_SHARE_RESOURCE_TYPES,\n] as const;\n\nexport type PublicSharePathType = (typeof PUBLIC_SHARE_PATH_TYPES)[number];\n\n/** @deprecated Use {@link PUBLIC_SHARE_PATH_TYPES} — kept for mobile deep-link helpers. */\nexport const RESOURCE_SHARE_TYPES_FOR_URL = PUBLIC_SHARE_PATH_TYPES;\n\nexport type RelationSharePathType =\n | typeof RELATION_SHARE_INVITATION\n | typeof RELATION_SHARE_APPLICATION;\n\nexport type ShareType = PublicSharePathType | RelationSharePathType;\n\n/** Alternation for deep-link regexes — keep in sync with {@link ShareType}. */\nexport const SHARE_TYPE_PATH_REGEX = [\n ...PUBLIC_SHARE_PATH_TYPES,\n RELATION_SHARE_APPLICATION,\n RELATION_SHARE_INVITATION,\n].join(\"|\");\n\nexport function buildShareUrl(type: ShareType, id: string): string {\n return `${SHARE_SITE_URL}/share/${type}/${encodeURIComponent(id)}`;\n}\n","import {\n joinShareOgDescriptionSections,\n OG_DESCRIPTION_LINE_BREAK,\n SHARE_DESCRIPTION_SECTION_BREAK,\n SHARE_DESCRIPTION_SECTION_SEPARATOR,\n} from \"./joinShareDescriptionSections\";\n\nexport {\n joinShareOgDescriptionSections,\n OG_DESCRIPTION_LINE_BREAK,\n SHARE_DESCRIPTION_SECTION_BREAK,\n SHARE_DESCRIPTION_SECTION_SEPARATOR,\n};\n\nconst LEGACY_BULLET_PREFIX = \"• \";\n\n/** Trims a share section and collapses spaces per line; preserves line breaks. */\nfunction normalizeShareSection(value: string | null | undefined): string {\n if (value == null) {\n return \"\";\n }\n return value\n .trim()\n .split(\"\\n\")\n .map((line) => line.trim().replace(/[ \\t]+/g, \" \"))\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\");\n}\n\nfunction stripLegacyBulletPrefix(section: string): string {\n return section.startsWith(LEGACY_BULLET_PREFIX)\n ? section.slice(LEGACY_BULLET_PREFIX.length)\n : section;\n}\n\nexport function splitShareDescriptionSections(value: string): string[] {\n const trimmed = value.trim();\n if (!trimmed) {\n return [];\n }\n\n if (trimmed.includes(SHARE_DESCRIPTION_SECTION_SEPARATOR)) {\n return trimmed\n .split(SHARE_DESCRIPTION_SECTION_SEPARATOR)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n if (/\\n\\n/.test(trimmed)) {\n return trimmed\n .split(/\\n\\n+/)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n if (/\\n/.test(trimmed)) {\n return trimmed\n .split(/\\n+/)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n return [stripLegacyBulletPrefix(normalizeShareSection(trimmed))];\n}\n\nfunction collapseExcessiveBlankLines(value: string): string {\n return value.replace(/\\n{4,}/g, \"\\n\\n\\n\").trim();\n}\n\n/**\n * Share copy with a blank line between each section (share sheet message, previews).\n */\nexport function formatShareSectionsForMultilineDisplay(value: string): string {\n return collapseExcessiveBlankLines(\n splitShareDescriptionSections(value).join(SHARE_DESCRIPTION_SECTION_BREAK),\n );\n}\n\n/**\n * Formats multiline share copy for UIs that strip line breaks (legacy OG one-liners).\n */\nexport function formatShareSectionsForCompactDisplay(value: string): string {\n return splitShareDescriptionSections(value).join(\n SHARE_DESCRIPTION_SECTION_SEPARATOR,\n );\n}\n\n/**\n * Formats share descriptions for Open Graph / Twitter meta tags.\n * Sections are joined with {@link OG_DESCRIPTION_LINE_BREAK} (` `).\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 `/share/*` controls card title/image).\n */\nexport function buildFacebookShareQuote(\n title: string,\n description: string,\n): string | undefined {\n const titleSection = normalizeShareSection(title);\n const body = formatShareSectionsForMultilineDisplay(\n normalizeShareSection(description),\n );\n const sections = [titleSection, body].filter((section) => section.length > 0);\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/**\n * Open Graph / Twitter description — body sections only (`og:title` is separate).\n * Multiline / legacy ` · ` input is split into sections, then joined with ` `.\n */\nexport function buildShareOgDescription(\n _title: string,\n description: string,\n): string {\n return joinShareOgDescriptionSections(splitShareDescriptionSections(description));\n}\n","import type { ShareResourceType } from \"./constants\";\n\nexport function normalizeShareRouteId(id: string): string {\n try {\n return decodeURIComponent(id);\n } catch {\n return id;\n }\n}\n\nexport function buildSharePagePath(\n resourceType: ShareResourceType,\n rawId: string,\n): string {\n return `/share/${resourceType}/${encodeURIComponent(normalizeShareRouteId(rawId))}`;\n}\n"],"mappings":"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","names":["dayjs","customParseFormat","utc","timezone","isSameOrAfter","dayjs"]}
|
package/dist/sharing/index.d.mts
CHANGED
|
@@ -57,6 +57,8 @@ type ShareVendorInfoForApplication = {
|
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
/** Formats event `startDate` (`DD-MM-YYYY`) for share copy — same as share preview UI. */
|
|
61
|
+
declare function formatShareMarketDate(dateStr: string): string;
|
|
60
62
|
declare function formatStallCapacityLabel(stallCapacity: number): string;
|
|
61
63
|
declare function buildInvitationShareDescription(event: ShareEventForInvitation, eventInfo: ShareEventInfoForInvitation | null | undefined): string;
|
|
62
64
|
declare function buildApplicationShareDescription(vendor: ShareVendorForApplication, vendorInfo: ShareVendorInfoForApplication | null | undefined): string;
|
|
@@ -95,8 +97,16 @@ declare function formatCategoryLabel(category: ShareVendorCategory): string;
|
|
|
95
97
|
declare const SHARE_DESCRIPTION_SECTION_SEPARATOR = " \u00B7 ";
|
|
96
98
|
/** Blank line between share sections — title, address, dates, URL, etc. */
|
|
97
99
|
declare const SHARE_DESCRIPTION_SECTION_BREAK = "\n\n";
|
|
100
|
+
/**
|
|
101
|
+
* Line break for `og:description` meta content. Use instead of `\n` — Next.js
|
|
102
|
+
* HTML serialisation collapses literal newlines to spaces; Facebook reads ` `.
|
|
103
|
+
*/
|
|
104
|
+
declare const OG_DESCRIPTION_LINE_BREAK = " ";
|
|
105
|
+
/** Joins OG description sections for Facebook link cards (and Twitter). */
|
|
106
|
+
declare function joinShareOgDescriptionSections(sections: ReadonlyArray<string | false | null | undefined>): string;
|
|
98
107
|
declare function joinShareDescriptionSections(sections: ReadonlyArray<string | false | null | undefined>): string;
|
|
99
108
|
|
|
109
|
+
declare function splitShareDescriptionSections(value: string): string[];
|
|
100
110
|
/**
|
|
101
111
|
* Share copy with a blank line between each section (share sheet message, previews).
|
|
102
112
|
*/
|
|
@@ -106,8 +116,8 @@ declare function formatShareSectionsForMultilineDisplay(value: string): string;
|
|
|
106
116
|
*/
|
|
107
117
|
declare function formatShareSectionsForCompactDisplay(value: string): string;
|
|
108
118
|
/**
|
|
109
|
-
* Formats share descriptions for Open Graph / Twitter meta tags
|
|
110
|
-
*
|
|
119
|
+
* Formats share descriptions for Open Graph / Twitter meta tags.
|
|
120
|
+
* Sections are joined with {@link OG_DESCRIPTION_LINE_BREAK} (` `).
|
|
111
121
|
*/
|
|
112
122
|
declare function normalizeShareOgDescription(value: string): string;
|
|
113
123
|
/**
|
|
@@ -118,13 +128,17 @@ declare function normalizeShareOgDescription(value: string): string;
|
|
|
118
128
|
*/
|
|
119
129
|
declare function buildFacebookShareQuote(title: string, description: string): string | undefined;
|
|
120
130
|
/**
|
|
121
|
-
* Open Graph / Twitter description
|
|
122
|
-
*
|
|
123
|
-
|
|
131
|
+
* Open Graph / Twitter description from pre-built section strings.
|
|
132
|
+
* Prefer {@link joinShareOgDescriptionSections} when sections are already known.
|
|
133
|
+
*/
|
|
134
|
+
declare function buildShareOgDescriptionFromSections(sections: ReadonlyArray<string | false | null | undefined>): string;
|
|
135
|
+
/**
|
|
136
|
+
* Open Graph / Twitter description — body sections only (`og:title` is separate).
|
|
137
|
+
* Multiline / legacy ` · ` input is split into sections, then joined with ` `.
|
|
124
138
|
*/
|
|
125
139
|
declare function buildShareOgDescription(_title: string, description: string): string;
|
|
126
140
|
|
|
127
141
|
declare function normalizeShareRouteId(id: string): string;
|
|
128
142
|
declare function buildSharePagePath(resourceType: ShareResourceType, rawId: string): string;
|
|
129
143
|
|
|
130
|
-
export { DEFAULT_SHARE_OG_IMAGE, POST_SHARE_RESOURCE_TYPES, PUBLIC_SHARE_PATH_TYPES, type PostShareResourceType, type PublicSharePathType, RELATION_SHARE_APPLICATION, RELATION_SHARE_INVITATION, RELATION_SHARE_RESOURCE_TYPES, RESOURCE_SHARE_TYPES, RESOURCE_SHARE_TYPES_FOR_URL, type RelationSharePathType, type RelationShareResourceType, type ResourceShareType, SHARE_DESCRIPTION_SECTION_BREAK, SHARE_DESCRIPTION_SECTION_SEPARATOR, SHARE_RESOURCE_LABEL, SHARE_SITE_URL, SHARE_TYPE_PATH_REGEX, type ShareEventDateTime, type ShareEventForInvitation, type ShareEventInfoForInvitation, type ShareResourceType, type ShareStallType, type ShareType, type ShareVendorCategory, type ShareVendorForApplication, type ShareVendorInfoForApplication, buildApplicationShareDescription, buildFacebookShareQuote, buildInvitationShareDescription, buildShareOgDescription, buildSharePagePath, buildShareUrl, formatCategoryLabel, formatShareSectionsForCompactDisplay, formatShareSectionsForMultilineDisplay, formatStallCapacityLabel, isPostShareResourceType, isRelationShareResourceType, joinShareDescriptionSections, normalizeShareOgDescription, normalizeShareRouteId };
|
|
144
|
+
export { DEFAULT_SHARE_OG_IMAGE, OG_DESCRIPTION_LINE_BREAK, POST_SHARE_RESOURCE_TYPES, PUBLIC_SHARE_PATH_TYPES, type PostShareResourceType, type PublicSharePathType, RELATION_SHARE_APPLICATION, RELATION_SHARE_INVITATION, RELATION_SHARE_RESOURCE_TYPES, RESOURCE_SHARE_TYPES, RESOURCE_SHARE_TYPES_FOR_URL, type RelationSharePathType, type RelationShareResourceType, type ResourceShareType, SHARE_DESCRIPTION_SECTION_BREAK, SHARE_DESCRIPTION_SECTION_SEPARATOR, SHARE_RESOURCE_LABEL, SHARE_SITE_URL, SHARE_TYPE_PATH_REGEX, type ShareEventDateTime, type ShareEventForInvitation, type ShareEventInfoForInvitation, type ShareResourceType, type ShareStallType, type ShareType, type ShareVendorCategory, type ShareVendorForApplication, type ShareVendorInfoForApplication, buildApplicationShareDescription, buildFacebookShareQuote, buildInvitationShareDescription, buildShareOgDescription, buildShareOgDescriptionFromSections, buildSharePagePath, buildShareUrl, formatCategoryLabel, formatShareMarketDate, formatShareSectionsForCompactDisplay, formatShareSectionsForMultilineDisplay, formatStallCapacityLabel, isPostShareResourceType, isRelationShareResourceType, joinShareDescriptionSections, joinShareOgDescriptionSections, normalizeShareOgDescription, normalizeShareRouteId, splitShareDescriptionSections };
|
package/dist/sharing/index.d.ts
CHANGED
|
@@ -57,6 +57,8 @@ type ShareVendorInfoForApplication = {
|
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
/** Formats event `startDate` (`DD-MM-YYYY`) for share copy — same as share preview UI. */
|
|
61
|
+
declare function formatShareMarketDate(dateStr: string): string;
|
|
60
62
|
declare function formatStallCapacityLabel(stallCapacity: number): string;
|
|
61
63
|
declare function buildInvitationShareDescription(event: ShareEventForInvitation, eventInfo: ShareEventInfoForInvitation | null | undefined): string;
|
|
62
64
|
declare function buildApplicationShareDescription(vendor: ShareVendorForApplication, vendorInfo: ShareVendorInfoForApplication | null | undefined): string;
|
|
@@ -95,8 +97,16 @@ declare function formatCategoryLabel(category: ShareVendorCategory): string;
|
|
|
95
97
|
declare const SHARE_DESCRIPTION_SECTION_SEPARATOR = " \u00B7 ";
|
|
96
98
|
/** Blank line between share sections — title, address, dates, URL, etc. */
|
|
97
99
|
declare const SHARE_DESCRIPTION_SECTION_BREAK = "\n\n";
|
|
100
|
+
/**
|
|
101
|
+
* Line break for `og:description` meta content. Use instead of `\n` — Next.js
|
|
102
|
+
* HTML serialisation collapses literal newlines to spaces; Facebook reads ` `.
|
|
103
|
+
*/
|
|
104
|
+
declare const OG_DESCRIPTION_LINE_BREAK = " ";
|
|
105
|
+
/** Joins OG description sections for Facebook link cards (and Twitter). */
|
|
106
|
+
declare function joinShareOgDescriptionSections(sections: ReadonlyArray<string | false | null | undefined>): string;
|
|
98
107
|
declare function joinShareDescriptionSections(sections: ReadonlyArray<string | false | null | undefined>): string;
|
|
99
108
|
|
|
109
|
+
declare function splitShareDescriptionSections(value: string): string[];
|
|
100
110
|
/**
|
|
101
111
|
* Share copy with a blank line between each section (share sheet message, previews).
|
|
102
112
|
*/
|
|
@@ -106,8 +116,8 @@ declare function formatShareSectionsForMultilineDisplay(value: string): string;
|
|
|
106
116
|
*/
|
|
107
117
|
declare function formatShareSectionsForCompactDisplay(value: string): string;
|
|
108
118
|
/**
|
|
109
|
-
* Formats share descriptions for Open Graph / Twitter meta tags
|
|
110
|
-
*
|
|
119
|
+
* Formats share descriptions for Open Graph / Twitter meta tags.
|
|
120
|
+
* Sections are joined with {@link OG_DESCRIPTION_LINE_BREAK} (` `).
|
|
111
121
|
*/
|
|
112
122
|
declare function normalizeShareOgDescription(value: string): string;
|
|
113
123
|
/**
|
|
@@ -118,13 +128,17 @@ declare function normalizeShareOgDescription(value: string): string;
|
|
|
118
128
|
*/
|
|
119
129
|
declare function buildFacebookShareQuote(title: string, description: string): string | undefined;
|
|
120
130
|
/**
|
|
121
|
-
* Open Graph / Twitter description
|
|
122
|
-
*
|
|
123
|
-
|
|
131
|
+
* Open Graph / Twitter description from pre-built section strings.
|
|
132
|
+
* Prefer {@link joinShareOgDescriptionSections} when sections are already known.
|
|
133
|
+
*/
|
|
134
|
+
declare function buildShareOgDescriptionFromSections(sections: ReadonlyArray<string | false | null | undefined>): string;
|
|
135
|
+
/**
|
|
136
|
+
* Open Graph / Twitter description — body sections only (`og:title` is separate).
|
|
137
|
+
* Multiline / legacy ` · ` input is split into sections, then joined with ` `.
|
|
124
138
|
*/
|
|
125
139
|
declare function buildShareOgDescription(_title: string, description: string): string;
|
|
126
140
|
|
|
127
141
|
declare function normalizeShareRouteId(id: string): string;
|
|
128
142
|
declare function buildSharePagePath(resourceType: ShareResourceType, rawId: string): string;
|
|
129
143
|
|
|
130
|
-
export { DEFAULT_SHARE_OG_IMAGE, POST_SHARE_RESOURCE_TYPES, PUBLIC_SHARE_PATH_TYPES, type PostShareResourceType, type PublicSharePathType, RELATION_SHARE_APPLICATION, RELATION_SHARE_INVITATION, RELATION_SHARE_RESOURCE_TYPES, RESOURCE_SHARE_TYPES, RESOURCE_SHARE_TYPES_FOR_URL, type RelationSharePathType, type RelationShareResourceType, type ResourceShareType, SHARE_DESCRIPTION_SECTION_BREAK, SHARE_DESCRIPTION_SECTION_SEPARATOR, SHARE_RESOURCE_LABEL, SHARE_SITE_URL, SHARE_TYPE_PATH_REGEX, type ShareEventDateTime, type ShareEventForInvitation, type ShareEventInfoForInvitation, type ShareResourceType, type ShareStallType, type ShareType, type ShareVendorCategory, type ShareVendorForApplication, type ShareVendorInfoForApplication, buildApplicationShareDescription, buildFacebookShareQuote, buildInvitationShareDescription, buildShareOgDescription, buildSharePagePath, buildShareUrl, formatCategoryLabel, formatShareSectionsForCompactDisplay, formatShareSectionsForMultilineDisplay, formatStallCapacityLabel, isPostShareResourceType, isRelationShareResourceType, joinShareDescriptionSections, normalizeShareOgDescription, normalizeShareRouteId };
|
|
144
|
+
export { DEFAULT_SHARE_OG_IMAGE, OG_DESCRIPTION_LINE_BREAK, POST_SHARE_RESOURCE_TYPES, PUBLIC_SHARE_PATH_TYPES, type PostShareResourceType, type PublicSharePathType, RELATION_SHARE_APPLICATION, RELATION_SHARE_INVITATION, RELATION_SHARE_RESOURCE_TYPES, RESOURCE_SHARE_TYPES, RESOURCE_SHARE_TYPES_FOR_URL, type RelationSharePathType, type RelationShareResourceType, type ResourceShareType, SHARE_DESCRIPTION_SECTION_BREAK, SHARE_DESCRIPTION_SECTION_SEPARATOR, SHARE_RESOURCE_LABEL, SHARE_SITE_URL, SHARE_TYPE_PATH_REGEX, type ShareEventDateTime, type ShareEventForInvitation, type ShareEventInfoForInvitation, type ShareResourceType, type ShareStallType, type ShareType, type ShareVendorCategory, type ShareVendorForApplication, type ShareVendorInfoForApplication, buildApplicationShareDescription, buildFacebookShareQuote, buildInvitationShareDescription, buildShareOgDescription, buildShareOgDescriptionFromSections, buildSharePagePath, buildShareUrl, formatCategoryLabel, formatShareMarketDate, formatShareSectionsForCompactDisplay, formatShareSectionsForMultilineDisplay, formatStallCapacityLabel, isPostShareResourceType, isRelationShareResourceType, joinShareDescriptionSections, joinShareOgDescriptionSections, normalizeShareOgDescription, normalizeShareRouteId, splitShareDescriptionSections };
|
package/dist/sharing/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_SHARE_OG_IMAGE,
|
|
3
|
+
OG_DESCRIPTION_LINE_BREAK,
|
|
3
4
|
POST_SHARE_RESOURCE_TYPES,
|
|
4
5
|
PUBLIC_SHARE_PATH_TYPES,
|
|
5
6
|
RELATION_SHARE_APPLICATION,
|
|
@@ -16,20 +17,26 @@ import {
|
|
|
16
17
|
buildFacebookShareQuote,
|
|
17
18
|
buildInvitationShareDescription,
|
|
18
19
|
buildShareOgDescription,
|
|
20
|
+
buildShareOgDescriptionFromSections,
|
|
19
21
|
buildSharePagePath,
|
|
20
22
|
buildShareUrl,
|
|
21
23
|
formatCategoryLabel,
|
|
24
|
+
formatShareMarketDate,
|
|
22
25
|
formatShareSectionsForCompactDisplay,
|
|
23
26
|
formatShareSectionsForMultilineDisplay,
|
|
24
27
|
formatStallCapacityLabel,
|
|
25
28
|
isPostShareResourceType,
|
|
26
29
|
isRelationShareResourceType,
|
|
27
30
|
joinShareDescriptionSections,
|
|
31
|
+
joinShareOgDescriptionSections,
|
|
28
32
|
normalizeShareOgDescription,
|
|
29
|
-
normalizeShareRouteId
|
|
30
|
-
|
|
33
|
+
normalizeShareRouteId,
|
|
34
|
+
splitShareDescriptionSections
|
|
35
|
+
} from "../chunk-GSOSJNID.mjs";
|
|
36
|
+
import "../chunk-X4VPNOHX.mjs";
|
|
31
37
|
export {
|
|
32
38
|
DEFAULT_SHARE_OG_IMAGE,
|
|
39
|
+
OG_DESCRIPTION_LINE_BREAK,
|
|
33
40
|
POST_SHARE_RESOURCE_TYPES,
|
|
34
41
|
PUBLIC_SHARE_PATH_TYPES,
|
|
35
42
|
RELATION_SHARE_APPLICATION,
|
|
@@ -46,16 +53,20 @@ export {
|
|
|
46
53
|
buildFacebookShareQuote,
|
|
47
54
|
buildInvitationShareDescription,
|
|
48
55
|
buildShareOgDescription,
|
|
56
|
+
buildShareOgDescriptionFromSections,
|
|
49
57
|
buildSharePagePath,
|
|
50
58
|
buildShareUrl,
|
|
51
59
|
formatCategoryLabel,
|
|
60
|
+
formatShareMarketDate,
|
|
52
61
|
formatShareSectionsForCompactDisplay,
|
|
53
62
|
formatShareSectionsForMultilineDisplay,
|
|
54
63
|
formatStallCapacityLabel,
|
|
55
64
|
isPostShareResourceType,
|
|
56
65
|
isRelationShareResourceType,
|
|
57
66
|
joinShareDescriptionSections,
|
|
67
|
+
joinShareOgDescriptionSections,
|
|
58
68
|
normalizeShareOgDescription,
|
|
59
|
-
normalizeShareRouteId
|
|
69
|
+
normalizeShareRouteId,
|
|
70
|
+
splitShareDescriptionSections
|
|
60
71
|
};
|
|
61
72
|
//# sourceMappingURL=index.mjs.map
|
package/dist/utils/index.mjs
CHANGED
|
@@ -8,27 +8,29 @@ import {
|
|
|
8
8
|
capitalizeFirstLetter,
|
|
9
9
|
cluemartSocialMedia,
|
|
10
10
|
computeDailyClueState,
|
|
11
|
-
dateFormat,
|
|
12
|
-
formatDate,
|
|
13
|
-
formatTimestamp,
|
|
14
|
-
getCurrentAndFutureDates,
|
|
15
|
-
isFutureDatesBeforeThreshold,
|
|
16
|
-
isIsoDateString,
|
|
17
11
|
licenseNiceNames,
|
|
18
12
|
mapArrayToOptions,
|
|
19
13
|
normalizeUrl,
|
|
20
|
-
nzStartOfDay,
|
|
21
14
|
paymentMethodOptions,
|
|
22
15
|
removeTypename,
|
|
23
16
|
seededShuffle,
|
|
24
|
-
sortDatesChronologically,
|
|
25
17
|
statusOptions,
|
|
26
|
-
timeFormat,
|
|
27
|
-
toNZTime,
|
|
28
18
|
truncateText
|
|
29
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-3VUHAHP7.mjs";
|
|
30
20
|
import "../chunk-SBY5HTAP.mjs";
|
|
31
21
|
import "../chunk-ZR4TGWTS.mjs";
|
|
22
|
+
import {
|
|
23
|
+
dateFormat,
|
|
24
|
+
formatDate,
|
|
25
|
+
formatTimestamp,
|
|
26
|
+
getCurrentAndFutureDates,
|
|
27
|
+
isFutureDatesBeforeThreshold,
|
|
28
|
+
isIsoDateString,
|
|
29
|
+
nzStartOfDay,
|
|
30
|
+
sortDatesChronologically,
|
|
31
|
+
timeFormat,
|
|
32
|
+
toNZTime
|
|
33
|
+
} from "../chunk-X4VPNOHX.mjs";
|
|
32
34
|
export {
|
|
33
35
|
ANDROID_URL,
|
|
34
36
|
IOS_URL,
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sharing/formatCategoryLabel.ts","../src/sharing/joinShareDescriptionSections.ts","../src/sharing/buildRelationShareDescription.ts","../src/sharing/relationShareTypes.ts","../src/sharing/constants.ts","../src/sharing/buildShareUrl.ts","../src/sharing/normalizeShareDescription.ts","../src/sharing/normalizeShareRouteId.ts"],"sourcesContent":["import type { ShareVendorCategory } from \"./shareRelationTypes\";\n\nexport function formatCategoryLabel(category: ShareVendorCategory): string {\n const subcategoryNames = category.subcategories\n .map((subcategory) => subcategory.name)\n .filter(Boolean);\n\n if (subcategoryNames.length === 0) {\n return category.name;\n }\n\n return `${category.name} (${subcategoryNames.join(\", \")})`;\n}\n","/** Visible separator for multi-block share text when line breaks are stripped (legacy OG). */\nexport const SHARE_DESCRIPTION_SECTION_SEPARATOR = \" · \";\n\n/** Blank line between share sections — title, address, dates, URL, etc. */\nexport const SHARE_DESCRIPTION_SECTION_BREAK = \"\\n\\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","import { formatCategoryLabel } from \"./formatCategoryLabel\";\nimport { joinShareDescriptionSections } from \"./joinShareDescriptionSections\";\nimport type {\n ShareEventForInvitation,\n ShareEventInfoForInvitation,\n ShareVendorForApplication,\n ShareVendorInfoForApplication,\n} from \"./shareRelationTypes\";\n\nexport type {\n ShareEventDateTime,\n ShareEventForInvitation,\n ShareEventInfoForInvitation,\n ShareStallType,\n ShareVendorCategory,\n ShareVendorForApplication,\n ShareVendorInfoForApplication,\n} from \"./shareRelationTypes\";\n\nfunction formatShareDate(isoDate: string): string {\n try {\n return new Intl.DateTimeFormat(\"en-NZ\", {\n day: \"numeric\",\n month: \"short\",\n year: \"numeric\",\n }).format(new Date(isoDate));\n } catch {\n return isoDate;\n }\n}\n\nexport function formatStallCapacityLabel(stallCapacity: number): string {\n return stallCapacity > 0 ? ` (${stallCapacity} spaces available)` : \" - Full\";\n}\n\nexport function buildInvitationShareDescription(\n event: ShareEventForInvitation,\n eventInfo: ShareEventInfoForInvitation | null | undefined,\n): string {\n const stallTypes =\n eventInfo?.dateTime?.flatMap((date) => date.stallTypes) ?? [];\n\n if (!eventInfo || stallTypes.length === 0) {\n return event.description?.trim() || \"\";\n }\n\n const requirementLabels = (eventInfo.requirements ?? [])\n .filter((item) => item.value)\n .map((item) => item.label);\n\n const sections = [\n event.location.fullAddress,\n ...event.dateTime.map((date) => {\n const start = formatShareDate(date.startDate);\n // DO NOT share end date for now, we will add it later if needed\n return `Market date: ${start}`;\n }),\n `Application deadline: vendors must apply at least ${eventInfo.applicationDeadlineHours} hours before each market date.`,\n ...stallTypes.map(\n (stall) =>\n `Stall: ${stall.label} — $${stall.price}${formatStallCapacityLabel(stall.stallCapacity)}`,\n ),\n requirementLabels.length > 0 &&\n `Requirements: ${requirementLabels.join(\", \")}`,\n ];\n\n return joinShareDescriptionSections(sections);\n}\n\nexport function buildApplicationShareDescription(\n vendor: ShareVendorForApplication,\n vendorInfo: ShareVendorInfoForApplication | null | undefined,\n): string {\n const categoryLabels = vendor.categories.map((category) =>\n formatCategoryLabel(category),\n );\n\n if (!vendorInfo) {\n return vendor.description?.trim() || \"\";\n }\n\n const compliance = vendorInfo.compliance;\n const complianceLabels = [\n compliance?.liabilityInsurance && \"Liability insurance\",\n compliance?.foodBeverageLicense && \"Food & beverage licence\",\n ].filter(Boolean);\n\n const profileDescription = vendor.description?.trim();\n\n const sections = [\n categoryLabels.length > 0 && `Categories: ${categoryLabels.join(\", \")}`,\n `Stall size: ${vendorInfo.stallInfo.size.width}m × ${vendorInfo.stallInfo.size.depth}m`,\n `Compliance: ${complianceLabels.length > 0 ? complianceLabels.join(\", \") : \"Not specified\"}`,\n `Price range: $${vendorInfo.product.priceRange.min} – $${vendorInfo.product.priceRange.max}`,\n profileDescription,\n ];\n\n return joinShareDescriptionSections(sections);\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\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_SHARE_RESOURCE_TYPES,\n isRelationShareResourceType,\n type RelationShareResourceType,\n} from \"./relationShareTypes\";\n\nexport const SHARE_SITE_URL = \"https://cluemart.co.nz\";\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] as const;\n\nexport type ResourceShareType = (typeof RESOURCE_SHARE_TYPES)[number];\n\nexport const POST_SHARE_RESOURCE_TYPES = [\n \"daily_meets\",\n \"daily_tips\",\n \"daily_games\",\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 daily_games: \"Daily Game\",\n daily_meets: \"Daily Meet\",\n daily_tips: \"Daily Tip\",\n market: \"Market\",\n partner: \"Partner\",\n stallholder: \"Stallholder\",\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 {\n POST_SHARE_RESOURCE_TYPES,\n RESOURCE_SHARE_TYPES,\n SHARE_SITE_URL,\n} from \"./constants\";\nimport {\n RELATION_SHARE_APPLICATION,\n RELATION_SHARE_INVITATION,\n} from \"./relationShareTypes\";\n\n/** Path segments for public resource share URLs (markets, posts, etc.). */\nexport const PUBLIC_SHARE_PATH_TYPES = [\n ...RESOURCE_SHARE_TYPES,\n ...POST_SHARE_RESOURCE_TYPES,\n] as const;\n\nexport type PublicSharePathType = (typeof PUBLIC_SHARE_PATH_TYPES)[number];\n\n/** @deprecated Use {@link PUBLIC_SHARE_PATH_TYPES} — kept for mobile deep-link helpers. */\nexport const RESOURCE_SHARE_TYPES_FOR_URL = PUBLIC_SHARE_PATH_TYPES;\n\nexport type RelationSharePathType =\n | typeof RELATION_SHARE_INVITATION\n | typeof RELATION_SHARE_APPLICATION;\n\nexport type ShareType = PublicSharePathType | RelationSharePathType;\n\n/** Alternation for deep-link regexes — keep in sync with {@link ShareType}. */\nexport const SHARE_TYPE_PATH_REGEX = [\n ...PUBLIC_SHARE_PATH_TYPES,\n RELATION_SHARE_APPLICATION,\n RELATION_SHARE_INVITATION,\n].join(\"|\");\n\nexport function buildShareUrl(type: ShareType, id: string): string {\n return `${SHARE_SITE_URL}/share/${type}/${encodeURIComponent(id)}`;\n}\n","import {\n SHARE_DESCRIPTION_SECTION_BREAK,\n SHARE_DESCRIPTION_SECTION_SEPARATOR,\n} from \"./joinShareDescriptionSections\";\n\nconst LEGACY_BULLET_PREFIX = \"• \";\n\n/** Trims a share section and collapses spaces per line; preserves line breaks. */\nfunction normalizeShareSection(value: string | null | undefined): string {\n if (value == null) {\n return \"\";\n }\n return value\n .trim()\n .split(\"\\n\")\n .map((line) => line.trim().replace(/[ \\t]+/g, \" \"))\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\");\n}\n\nfunction stripLegacyBulletPrefix(section: string): string {\n return section.startsWith(LEGACY_BULLET_PREFIX)\n ? section.slice(LEGACY_BULLET_PREFIX.length)\n : section;\n}\n\nfunction splitShareDescriptionSections(value: string): string[] {\n const trimmed = value.trim();\n if (!trimmed) {\n return [];\n }\n\n if (trimmed.includes(SHARE_DESCRIPTION_SECTION_SEPARATOR)) {\n return trimmed\n .split(SHARE_DESCRIPTION_SECTION_SEPARATOR)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n if (/\\n\\n/.test(trimmed)) {\n return trimmed\n .split(/\\n\\n+/)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n if (/\\n/.test(trimmed)) {\n return trimmed\n .split(/\\n+/)\n .map((section) => stripLegacyBulletPrefix(normalizeShareSection(section)))\n .filter((section) => section.length > 0);\n }\n\n return [stripLegacyBulletPrefix(normalizeShareSection(trimmed))];\n}\n\nfunction collapseExcessiveBlankLines(value: string): string {\n return value.replace(/\\n{4,}/g, \"\\n\\n\\n\").trim();\n}\n\n/**\n * Share copy with a blank line between each section (share sheet message, previews).\n */\nexport function formatShareSectionsForMultilineDisplay(value: string): string {\n return collapseExcessiveBlankLines(\n splitShareDescriptionSections(value).join(SHARE_DESCRIPTION_SECTION_BREAK),\n );\n}\n\n/**\n * Formats multiline share copy for UIs that strip line breaks (legacy OG one-liners).\n */\nexport function formatShareSectionsForCompactDisplay(value: string): string {\n return splitShareDescriptionSections(value).join(\n SHARE_DESCRIPTION_SECTION_SEPARATOR,\n );\n}\n\n/**\n * Formats share descriptions for Open Graph / Twitter meta tags when crawlers\n * collapse line breaks.\n */\nexport function normalizeShareOgDescription(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"\";\n }\n\n if (\n /\\n\\n/.test(trimmed) ||\n trimmed.includes(SHARE_DESCRIPTION_SECTION_SEPARATOR)\n ) {\n return formatShareSectionsForCompactDisplay(trimmed);\n }\n\n return trimmed.replace(/\\s+/g, \" \").trim();\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 `/share/*` controls card title/image).\n */\nexport function buildFacebookShareQuote(\n title: string,\n description: string,\n): string | undefined {\n const titleSection = normalizeShareSection(title);\n const body = formatShareSectionsForMultilineDisplay(\n normalizeShareSection(description),\n );\n const sections = [titleSection, body].filter((section) => section.length > 0);\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 — single line, no repeated `og:title`.\n *\n * Facebook's link card does not render `\\n`; sections are joined with ` · `.\n */\nexport function buildShareOgDescription(\n _title: string,\n description: string,\n): string {\n return normalizeShareOgDescription(description);\n}\n","import type { ShareResourceType } from \"./constants\";\n\nexport function normalizeShareRouteId(id: string): string {\n try {\n return decodeURIComponent(id);\n } catch {\n return id;\n }\n}\n\nexport function buildSharePagePath(\n resourceType: ShareResourceType,\n rawId: string,\n): string {\n return `/share/${resourceType}/${encodeURIComponent(normalizeShareRouteId(rawId))}`;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/date.ts","../src/utils/dailyClueGame.ts","../src/utils/utils.ts","../src/utils/school.ts"],"sourcesContent":["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\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\" && !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 || !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","import type { Dayjs } from \"dayjs\";\n\nimport {\n DailyClueGameData,\n GamePlacement,\n GamePlacementClue,\n gameScreenIdentifierList,\n} from \"../types/game/dailyClue\";\n\nimport { nzStartOfDay } from \"./date\";\n\nfunction createSeededRng(seed: number) {\n let t = seed >>> 0;\n\n return function random() {\n t += 0x6d2b79f5;\n let x = t;\n\n x = Math.imul(x ^ (x >>> 15), x | 1);\n x ^= x + Math.imul(x ^ (x >>> 7), x | 61);\n\n return ((x ^ (x >>> 14)) >>> 0) / 4294967296;\n };\n}\n\nfunction hashStringToNumber(seed: string): number {\n let hash = 2166136261;\n\n for (let i = 0; i < seed.length; i++) {\n hash ^= seed.codePointAt(i) ?? 0;\n hash = Math.imul(hash, 16777619);\n }\n\n return hash >>> 0;\n}\n\n/** Seeded shuffle so all players see the same letter order / placements for a game. */\nexport function seededShuffle<T>(array: readonly T[], seed: string): T[] {\n const rng = createSeededRng(hashStringToNumber(seed));\n const result = [...array];\n\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(rng() * (i + 1));\n [result[i], result[j]] = [result[j], result[i]];\n }\n\n return result;\n}\n\nfunction getDayIndex(start: Dayjs, today: Dayjs): number {\n return today.diff(start, \"day\");\n}\n\nexport function computeDailyClueState(dailyClue: DailyClueGameData): {\n todaysClue: GamePlacementClue | null;\n todaysLetter: string | null;\n todaysPlacement: GamePlacement | null;\n} | null {\n const { startDate, endDate } = dailyClue.gameFields.gameDate;\n const { solutionShuffled, collected } = dailyClue.letterInfo;\n\n const today = nzStartOfDay();\n const start = nzStartOfDay(startDate);\n const end = nzStartOfDay(endDate);\n\n // Before game starts\n if (today.isBefore(start)) {\n return null;\n }\n\n const shuffledPlacements = seededShuffle(\n gameScreenIdentifierList,\n start.toISOString(),\n );\n\n const index = getDayIndex(start, today);\n\n // After game ends\n if (today.isAfter(end)) {\n return {\n todaysClue: null,\n todaysLetter: null,\n todaysPlacement: null,\n };\n }\n\n // Safety: index must exist in BOTH arrays\n if (\n index < 0 ||\n index >= solutionShuffled.length ||\n index >= shuffledPlacements.length\n ) {\n return null;\n }\n\n const letterToday = solutionShuffled[index];\n const placement = shuffledPlacements[index];\n\n if (!letterToday || !placement) return null;\n\n const alreadyCollectedToday = (collected ?? []).includes(letterToday);\n\n // Already completed today\n if (alreadyCollectedToday) {\n return {\n todaysClue: null,\n todaysLetter: null,\n todaysPlacement: null,\n };\n }\n\n // Active state\n return {\n todaysClue: placement.clue,\n todaysLetter: letterToday,\n todaysPlacement: placement.id,\n };\n}\n","import {\n EnumInviteStatus,\n EnumPaymentMethod,\n EnumRegions,\n EnumSocialMedia,\n EnumUserLicence,\n} from \"src/enums\";\nimport { OptionItem, SocialMediaType } from \"src/types\";\n\nimport { isIsoDateString } from \"./date\";\n\nexport const removeTypename = (obj: any): any => {\n // Preserve Date objects\n if (obj instanceof Date) {\n return obj;\n }\n\n // Preserve File objects (for apollo-upload-client)\n if (obj instanceof File) {\n return obj;\n }\n\n // Preserve ISO date strings\n if (isIsoDateString(obj)) {\n return obj;\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return obj.map(removeTypename);\n }\n\n // Handle plain objects only\n if (obj !== null && typeof obj === \"object\") {\n const { __typename, ...cleanedObj } = obj;\n\n return Object.keys(cleanedObj).reduce((acc: any, key) => {\n acc[key] = removeTypename(cleanedObj[key]);\n return acc;\n }, {});\n }\n\n // Primitives\n return obj;\n};\n\n/**\n * Truncate text to a specified length and append ellipsis if necessary.\n * @param text\n * @param maxLength\n * @returns\n */\nexport const truncateText = (text: string, maxLength: number = 30): string => {\n return text.length > maxLength ? text.substring(0, maxLength) + \"...\" : text;\n};\n\n/**\n * Convert an array of strings to an array of objects with label and value properties.\n * @param items - The array of strings to convert.\n * @returns - The converted array of objects.\n */\nexport const mapArrayToOptions = (items: string[]): OptionItem[] =>\n items.map((item) => ({\n label: item,\n value: item,\n }));\n\nexport const capitalizeFirstLetter = (str: string): string => {\n return str\n .split(\" \")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\" \");\n};\n\nexport const statusOptions = [\n ...Object.values(EnumInviteStatus)\n .map((status) => ({\n label: status,\n value: status,\n }))\n .sort((a, b) => a.label.localeCompare(b.label)), // Sort the options alphabetically\n];\n\nexport const availableRegionTypes = Object.values(EnumRegions);\nexport const availableRegionOptions: OptionItem[] =\n mapArrayToOptions(availableRegionTypes);\n\nexport const paymentMethodOptions: OptionItem[] = mapArrayToOptions(\n Object.values(EnumPaymentMethod),\n);\n\nexport function normalizeUrl(url: string): string {\n if (!url.startsWith(\"http://\") && !url.startsWith(\"https://\")) {\n return `https://${url}`;\n }\n return url;\n}\n\nexport const licenseNiceNames: Record<EnumUserLicence, string> = {\n [EnumUserLicence.PRO_EVENT]: \"Pro Event\",\n [EnumUserLicence.PRO_VENDOR]: \"Pro Stallholder\",\n [EnumUserLicence.STANDARD_EVENT]: \"Standard Event\",\n [EnumUserLicence.STANDARD_VENDOR]: \"Standard Stallholder\",\n [EnumUserLicence.PRO_PLUS_EVENT]: \"Pro+Ads Event\",\n [EnumUserLicence.PRO_PLUS_VENDOR]: \"Pro+Ads Stallholder\",\n [EnumUserLicence.STANDARD_PARTNER]: \"Partner\",\n};\n\nexport const cluemartSocialMedia: SocialMediaType[] = [\n {\n link: \"https://www.facebook.com/ClueMartApp\",\n name: EnumSocialMedia.FACEBOOK,\n },\n {\n link: \"https://www.instagram.com/cluemart_app\",\n name: EnumSocialMedia.INSTAGRAM,\n },\n {\n link: \"https://www.tiktok.com/@cluemart\",\n name: EnumSocialMedia.TIKTOK,\n },\n {\n link: \"https://www.youtube.com/@ClueMart-App-NZ\",\n name: EnumSocialMedia.YOUTUBE,\n },\n];\n\nexport const IOS_URL = \"https://apps.apple.com/nz/app/cluemart/id6747251008\";\nexport const ANDROID_URL =\n \"https://play.google.com/store/apps/details?id=com.timardex.cluemart\";\n","export const SCHOOL_MIN_STUDENT_COUNT = 300;\nexport const SCHOOL_MAX_STUDENT_COUNT = 0;\n"],"mappings":"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","names":[]}
|
|
File without changes
|