@bash-app/bash-common 30.246.0 → 30.253.0
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/README.md +4 -0
- package/dist/__tests__/bashSectionTitleForBashType.test.js +32 -1
- package/dist/__tests__/bashSectionTitleForBashType.test.js.map +1 -1
- package/dist/__tests__/definitionsHelpers.test.d.ts +2 -0
- package/dist/__tests__/definitionsHelpers.test.d.ts.map +1 -0
- package/dist/__tests__/definitionsHelpers.test.js +85 -0
- package/dist/__tests__/definitionsHelpers.test.js.map +1 -0
- package/dist/__tests__/extendedSchemas.test.d.ts +2 -0
- package/dist/__tests__/extendedSchemas.test.d.ts.map +1 -0
- package/dist/__tests__/extendedSchemas.test.js +40 -0
- package/dist/__tests__/extendedSchemas.test.js.map +1 -0
- package/dist/__tests__/membershipDefinitions.test.d.ts +2 -0
- package/dist/__tests__/membershipDefinitions.test.d.ts.map +1 -0
- package/dist/__tests__/membershipDefinitions.test.js +95 -0
- package/dist/__tests__/membershipDefinitions.test.js.map +1 -0
- package/dist/__tests__/ticketAdmission.test.d.ts +5 -0
- package/dist/__tests__/ticketAdmission.test.d.ts.map +1 -0
- package/dist/__tests__/ticketAdmission.test.js +42 -0
- package/dist/__tests__/ticketAdmission.test.js.map +1 -0
- package/dist/__tests__/utmAttribution.test.d.ts +2 -0
- package/dist/__tests__/utmAttribution.test.d.ts.map +1 -0
- package/dist/__tests__/utmAttribution.test.js +92 -0
- package/dist/__tests__/utmAttribution.test.js.map +1 -0
- package/dist/definitions.d.ts +18 -5
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +84 -22
- package/dist/definitions.js.map +1 -1
- package/dist/extendedSchemas.d.ts +41 -1
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +27 -0
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/sms/smsTemplates.d.ts +27 -0
- package/dist/sms/smsTemplates.d.ts.map +1 -0
- package/dist/sms/smsTemplates.js +11 -0
- package/dist/sms/smsTemplates.js.map +1 -0
- package/dist/utils/__tests__/addressUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/addressUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/addressUtils.test.js +138 -0
- package/dist/utils/__tests__/addressUtils.test.js.map +1 -0
- package/dist/utils/__tests__/apiUtils.test.d.ts +5 -0
- package/dist/utils/__tests__/apiUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/apiUtils.test.js +161 -0
- package/dist/utils/__tests__/apiUtils.test.js.map +1 -0
- package/dist/utils/__tests__/arrayUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/arrayUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/arrayUtils.test.js +23 -0
- package/dist/utils/__tests__/arrayUtils.test.js.map +1 -0
- package/dist/utils/__tests__/blogUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/blogUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/blogUtils.test.js +102 -0
- package/dist/utils/__tests__/blogUtils.test.js.map +1 -0
- package/dist/utils/__tests__/dateTimeUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/dateTimeUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/dateTimeUtils.test.js +180 -0
- package/dist/utils/__tests__/dateTimeUtils.test.js.map +1 -0
- package/dist/utils/__tests__/discountEngine/discountCalculator.test.d.ts +2 -0
- package/dist/utils/__tests__/discountEngine/discountCalculator.test.d.ts.map +1 -0
- package/dist/utils/__tests__/discountEngine/discountCalculator.test.js +356 -0
- package/dist/utils/__tests__/discountEngine/discountCalculator.test.js.map +1 -0
- package/dist/utils/__tests__/generalDateTimeUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/generalDateTimeUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/generalDateTimeUtils.test.js +26 -0
- package/dist/utils/__tests__/generalDateTimeUtils.test.js.map +1 -0
- package/dist/utils/__tests__/luxonUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/luxonUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/luxonUtils.test.js +139 -0
- package/dist/utils/__tests__/luxonUtils.test.js.map +1 -0
- package/dist/utils/__tests__/mathUtils.test.d.ts +5 -0
- package/dist/utils/__tests__/mathUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/mathUtils.test.js +26 -0
- package/dist/utils/__tests__/mathUtils.test.js.map +1 -0
- package/dist/utils/__tests__/objUtils.test.d.ts +5 -0
- package/dist/utils/__tests__/objUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/objUtils.test.js +41 -0
- package/dist/utils/__tests__/objUtils.test.js.map +1 -0
- package/dist/utils/__tests__/paymentUtils.test.js +48 -1
- package/dist/utils/__tests__/paymentUtils.test.js.map +1 -1
- package/dist/utils/__tests__/qrCodeUtils.test.js +16 -1
- package/dist/utils/__tests__/qrCodeUtils.test.js.map +1 -1
- package/dist/utils/__tests__/reviewUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/reviewUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/reviewUtils.test.js +49 -0
- package/dist/utils/__tests__/reviewUtils.test.js.map +1 -0
- package/dist/utils/__tests__/slugUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/slugUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/slugUtils.test.js +103 -0
- package/dist/utils/__tests__/slugUtils.test.js.map +1 -0
- package/dist/utils/__tests__/sortUtils.test.d.ts +5 -0
- package/dist/utils/__tests__/sortUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/sortUtils.test.js +28 -0
- package/dist/utils/__tests__/sortUtils.test.js.map +1 -0
- package/dist/utils/__tests__/stringUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/stringUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/stringUtils.test.js +27 -0
- package/dist/utils/__tests__/stringUtils.test.js.map +1 -0
- package/dist/utils/__tests__/ticketListUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/ticketListUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/ticketListUtils.test.js +41 -0
- package/dist/utils/__tests__/ticketListUtils.test.js.map +1 -0
- package/dist/utils/__tests__/typeUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/typeUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/typeUtils.test.js +11 -0
- package/dist/utils/__tests__/typeUtils.test.js.map +1 -0
- package/dist/utils/__tests__/userSubscriptionUtils.test.d.ts +5 -0
- package/dist/utils/__tests__/userSubscriptionUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/userSubscriptionUtils.test.js +66 -0
- package/dist/utils/__tests__/userSubscriptionUtils.test.js.map +1 -0
- package/dist/utils/__tests__/userUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/userUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/userUtils.test.js +34 -0
- package/dist/utils/__tests__/userUtils.test.js.map +1 -0
- package/dist/utils/__tests__/venueTypeFormatter.test.d.ts +2 -0
- package/dist/utils/__tests__/venueTypeFormatter.test.d.ts.map +1 -0
- package/dist/utils/__tests__/venueTypeFormatter.test.js +25 -0
- package/dist/utils/__tests__/venueTypeFormatter.test.js.map +1 -0
- package/dist/utils/service/__tests__/regexUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/regexUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/regexUtils.test.js +51 -0
- package/dist/utils/service/__tests__/regexUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/serviceDBUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/serviceDBUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/serviceDBUtils.test.js +17 -0
- package/dist/utils/service/__tests__/serviceDBUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/serviceFeaturedSortUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/serviceFeaturedSortUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/serviceFeaturedSortUtils.test.js +60 -0
- package/dist/utils/service/__tests__/serviceFeaturedSortUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/serviceUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/serviceUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/serviceUtils.test.js +135 -0
- package/dist/utils/service/__tests__/serviceUtils.test.js.map +1 -0
- package/dist/utils/service/serviceFeaturedSortUtils.d.ts.map +1 -1
- package/dist/utils/service/serviceFeaturedSortUtils.js +5 -1
- package/dist/utils/service/serviceFeaturedSortUtils.js.map +1 -1
- package/dist/utils/ticketListUtils.d.ts.map +1 -1
- package/dist/utils/ticketListUtils.js +11 -7
- package/dist/utils/ticketListUtils.js.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +47 -0
- package/src/__tests__/bashSectionTitleForBashType.test.ts +48 -1
- package/src/__tests__/definitionsHelpers.test.ts +136 -0
- package/src/__tests__/extendedSchemas.test.ts +50 -0
- package/src/__tests__/membershipDefinitions.test.ts +144 -0
- package/src/__tests__/ticketAdmission.test.ts +73 -0
- package/src/__tests__/utmAttribution.test.ts +118 -0
- package/src/definitions.ts +86 -23
- package/src/extendedSchemas.ts +35 -1
- package/src/index.ts +1 -0
- package/src/sms/smsTemplates.ts +20 -0
- package/src/utils/__tests__/addressUtils.test.ts +176 -0
- package/src/utils/__tests__/apiUtils.test.ts +219 -0
- package/src/utils/__tests__/arrayUtils.test.ts +26 -0
- package/src/utils/__tests__/blogUtils.test.ts +145 -0
- package/src/utils/__tests__/dateTimeUtils.test.ts +233 -0
- package/src/utils/__tests__/discountEngine/discountCalculator.test.ts +410 -0
- package/src/utils/__tests__/generalDateTimeUtils.test.ts +34 -0
- package/src/utils/__tests__/luxonUtils.test.ts +171 -0
- package/src/utils/__tests__/mathUtils.test.ts +30 -0
- package/src/utils/__tests__/objUtils.test.ts +48 -0
- package/src/utils/__tests__/paymentUtils.test.ts +59 -0
- package/src/utils/__tests__/qrCodeUtils.test.ts +28 -1
- package/src/utils/__tests__/reviewUtils.test.ts +65 -0
- package/src/utils/__tests__/slugUtils.test.ts +143 -0
- package/src/utils/__tests__/sortUtils.test.ts +33 -0
- package/src/utils/__tests__/stringUtils.test.ts +37 -0
- package/src/utils/__tests__/ticketListUtils.test.ts +47 -0
- package/src/utils/__tests__/typeUtils.test.ts +12 -0
- package/src/utils/__tests__/userSubscriptionUtils.test.ts +87 -0
- package/src/utils/__tests__/userUtils.test.ts +41 -0
- package/src/utils/__tests__/venueTypeFormatter.test.ts +31 -0
- package/src/utils/service/__tests__/regexUtils.test.ts +66 -0
- package/src/utils/service/__tests__/serviceDBUtils.test.ts +19 -0
- package/src/utils/service/__tests__/serviceFeaturedSortUtils.test.ts +67 -0
- package/src/utils/service/__tests__/serviceUtils.test.ts +190 -0
- package/src/utils/service/serviceFeaturedSortUtils.ts +5 -1
- package/src/utils/ticketListUtils.ts +13 -6
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import {
|
|
3
|
+
isPositiveInt,
|
|
4
|
+
isPositiveFloat,
|
|
5
|
+
isPrice,
|
|
6
|
+
isUrlInputtingProtocol,
|
|
7
|
+
isUrl,
|
|
8
|
+
} from "../regexUtils.js";
|
|
9
|
+
|
|
10
|
+
describe("regexUtils", () => {
|
|
11
|
+
describe("isPositiveInt", () => {
|
|
12
|
+
test("accepts digits and empty string", () => {
|
|
13
|
+
expect(isPositiveInt("123")).toBe(true);
|
|
14
|
+
expect(isPositiveInt("")).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("rejects non-digit characters", () => {
|
|
18
|
+
expect(isPositiveInt("12a")).toBe(false);
|
|
19
|
+
expect(isPositiveInt("-1")).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("isPositiveFloat", () => {
|
|
24
|
+
test("accepts decimal numbers", () => {
|
|
25
|
+
expect(isPositiveFloat("12.5")).toBe(true);
|
|
26
|
+
expect(isPositiveFloat("0.")).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("rejects letters", () => {
|
|
30
|
+
expect(isPositiveFloat("1.2.3")).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("isPrice", () => {
|
|
35
|
+
test("allows up to two decimal places", () => {
|
|
36
|
+
expect(isPrice("19.99")).toBe(true);
|
|
37
|
+
expect(isPrice("100")).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("rejects more than two decimal places", () => {
|
|
41
|
+
expect(isPrice("1.999")).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe("isUrlInputtingProtocol", () => {
|
|
46
|
+
test("matches partial protocol typing", () => {
|
|
47
|
+
expect(isUrlInputtingProtocol("https://")).toBe(true);
|
|
48
|
+
expect(isUrlInputtingProtocol("htt")).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("rejects random text", () => {
|
|
52
|
+
expect(isUrlInputtingProtocol("example.com")).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("isUrl", () => {
|
|
57
|
+
test("accepts http(s) URLs and bare domains", () => {
|
|
58
|
+
expect(isUrl("https://bash.events")).toBe(true);
|
|
59
|
+
expect(isUrl("bash.events")).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("rejects strings with spaces", () => {
|
|
63
|
+
expect(isUrl("not a url")).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import { serviceFromDb, serviceToDb } from "../serviceDBUtils.js";
|
|
3
|
+
|
|
4
|
+
describe("serviceDBUtils", () => {
|
|
5
|
+
test("serviceFromDb returns the same reference (identity transform)", () => {
|
|
6
|
+
const service = { id: "svc-1", serviceName: "Test" } as any;
|
|
7
|
+
expect(serviceFromDb(service)).toBe(service);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("serviceFromDb passes through null and undefined", () => {
|
|
11
|
+
expect(serviceFromDb(null)).toBeNull();
|
|
12
|
+
expect(serviceFromDb(undefined)).toBeUndefined();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("serviceToDb returns the same partial payload", () => {
|
|
16
|
+
const partial = { tagline: "Hello" };
|
|
17
|
+
expect(serviceToDb(partial)).toBe(partial);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import {
|
|
3
|
+
compareFeaturedServices,
|
|
4
|
+
MIN_FEATURED_SERVICES_FOR_SECTION,
|
|
5
|
+
} from "../serviceFeaturedSortUtils.js";
|
|
6
|
+
|
|
7
|
+
describe("serviceFeaturedSortUtils", () => {
|
|
8
|
+
const now = new Date("2024-06-15T12:00:00Z");
|
|
9
|
+
const cmp = compareFeaturedServices(now);
|
|
10
|
+
|
|
11
|
+
test("ranks paid features above auto-featured and unfeatured", () => {
|
|
12
|
+
const paid = {
|
|
13
|
+
isFeaturedService: true,
|
|
14
|
+
featuredServiceUntil: new Date("2025-01-01"),
|
|
15
|
+
featuredAt: new Date("2024-01-01"),
|
|
16
|
+
featuredReason: "Paid" as const,
|
|
17
|
+
createdAt: new Date("2023-01-01"),
|
|
18
|
+
};
|
|
19
|
+
const auto = {
|
|
20
|
+
isFeaturedService: true,
|
|
21
|
+
featuredServiceUntil: new Date("2025-01-01"),
|
|
22
|
+
featuredAt: new Date("2024-02-01"),
|
|
23
|
+
featuredReason: "AutoNewService" as const,
|
|
24
|
+
createdAt: new Date("2024-05-01"),
|
|
25
|
+
};
|
|
26
|
+
const plain = {
|
|
27
|
+
isFeaturedService: false,
|
|
28
|
+
createdAt: new Date("2024-06-01"),
|
|
29
|
+
};
|
|
30
|
+
expect(cmp(paid, auto)).toBeLessThan(0);
|
|
31
|
+
expect(cmp(auto, plain)).toBeLessThan(0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("sorts paid tier FIFO by featuredAt ascending", () => {
|
|
35
|
+
const earlier = {
|
|
36
|
+
isFeaturedService: true,
|
|
37
|
+
featuredServiceUntil: new Date("2025-01-01"),
|
|
38
|
+
featuredAt: new Date("2024-01-01"),
|
|
39
|
+
featuredReason: "Admin" as const,
|
|
40
|
+
createdAt: new Date("2023-01-01"),
|
|
41
|
+
};
|
|
42
|
+
const later = {
|
|
43
|
+
...earlier,
|
|
44
|
+
featuredAt: new Date("2024-03-01"),
|
|
45
|
+
};
|
|
46
|
+
expect(cmp(earlier, later)).toBeLessThan(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("treats expired featuredUntil as unfeatured tier", () => {
|
|
50
|
+
const expired = {
|
|
51
|
+
isFeaturedService: true,
|
|
52
|
+
featuredServiceUntil: new Date("2024-01-01"),
|
|
53
|
+
featuredAt: new Date("2023-01-01"),
|
|
54
|
+
featuredReason: "Paid" as const,
|
|
55
|
+
createdAt: new Date("2024-06-01"),
|
|
56
|
+
};
|
|
57
|
+
const active = {
|
|
58
|
+
isFeaturedService: false,
|
|
59
|
+
createdAt: new Date("2024-05-01"),
|
|
60
|
+
};
|
|
61
|
+
expect(cmp(expired, active)).toBeGreaterThan(0);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("exports homepage carousel floor constant", () => {
|
|
65
|
+
expect(MIN_FEATURED_SERVICES_FOR_SECTION).toBe(3);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import { ServiceSubscriptionStatus, ServiceTypes } from "@prisma/client";
|
|
3
|
+
import {
|
|
4
|
+
serviceSubscriptionIsActive,
|
|
5
|
+
serviceGetSpecificType,
|
|
6
|
+
serviceDetailUrl,
|
|
7
|
+
serviceWizardUrl,
|
|
8
|
+
partnerServiceProfileWizardPaymentMethodUrl,
|
|
9
|
+
venueWizardLoyaltyBuilderUrl,
|
|
10
|
+
serviceCheckoutUrl,
|
|
11
|
+
serviceTypeToField,
|
|
12
|
+
aiServiceInfoToInfoString,
|
|
13
|
+
aiServiceInfoToExampleString,
|
|
14
|
+
buildAIFieldsString,
|
|
15
|
+
serviceRelevantData,
|
|
16
|
+
serviceExcludeIds,
|
|
17
|
+
serviceExcludeOwners,
|
|
18
|
+
serviceGetInfoAI,
|
|
19
|
+
getVendorSalesLabel,
|
|
20
|
+
SERVICE_CANCELLATION_POLICY_DATA,
|
|
21
|
+
PARTNER_SERVICE_PROFILE_WIZARD_PAYMENT_METHOD_MAJOR_STEP,
|
|
22
|
+
VENUE_WIZARD_LOYALTY_MAJOR_STEP,
|
|
23
|
+
} from "../serviceUtils.js";
|
|
24
|
+
|
|
25
|
+
describe("serviceUtils", () => {
|
|
26
|
+
describe("serviceSubscriptionIsActive", () => {
|
|
27
|
+
test("returns true for Normal and Trialing", () => {
|
|
28
|
+
expect(serviceSubscriptionIsActive(ServiceSubscriptionStatus.Normal)).toBe(true);
|
|
29
|
+
expect(serviceSubscriptionIsActive(ServiceSubscriptionStatus.Trialing)).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("returns false for canceled statuses", () => {
|
|
33
|
+
expect(serviceSubscriptionIsActive(ServiceSubscriptionStatus.None)).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("serviceGetSpecificType", () => {
|
|
38
|
+
test("maps venue service to venueId", () => {
|
|
39
|
+
expect(
|
|
40
|
+
serviceGetSpecificType({
|
|
41
|
+
id: "svc-1",
|
|
42
|
+
serviceType: ServiceTypes.Venues,
|
|
43
|
+
venueId: "venue-99",
|
|
44
|
+
} as any)
|
|
45
|
+
).toEqual({
|
|
46
|
+
serviceId: "svc-1",
|
|
47
|
+
serviceType: ServiceTypes.Venues,
|
|
48
|
+
specificFieldName: "venue",
|
|
49
|
+
specificId: "venue-99",
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("returns null when serviceType is missing", () => {
|
|
54
|
+
expect(serviceGetSpecificType({ id: "svc-1" } as any)).toBeNull();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("URL builders", () => {
|
|
59
|
+
test("serviceDetailUrl", () => {
|
|
60
|
+
expect(serviceDetailUrl("s1", "Venues", "v1")).toBe("/services/s1/Venues/v1");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("serviceWizardUrl includes step indices", () => {
|
|
64
|
+
expect(serviceWizardUrl("s1", "Vendors", "v1", 2, 1)).toBe(
|
|
65
|
+
"/wz/services/s1/Vendors/v1/2/1"
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("partnerServiceProfileWizardPaymentMethodUrl uses payment step constants", () => {
|
|
70
|
+
expect(partnerServiceProfileWizardPaymentMethodUrl("s1", "Vendors", "v1")).toBe(
|
|
71
|
+
`/wz/services/s1/Vendors/v1/${PARTNER_SERVICE_PROFILE_WIZARD_PAYMENT_METHOD_MAJOR_STEP}/3`
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("venueWizardLoyaltyBuilderUrl uses loyalty major step", () => {
|
|
76
|
+
expect(venueWizardLoyaltyBuilderUrl("s1", "Venues", "v1")).toBe(
|
|
77
|
+
`/wz/services/s1/Venues/v1/${VENUE_WIZARD_LOYALTY_MAJOR_STEP}/0`
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("serviceCheckoutUrl", () => {
|
|
82
|
+
expect(serviceCheckoutUrl("s1", "Venues", "v1")).toBe("/checkout/services/s1/Venues/v1");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe("serviceTypeToField", () => {
|
|
87
|
+
test("maps enum to specific relation key", () => {
|
|
88
|
+
expect(serviceTypeToField(ServiceTypes.Vendors)).toBe("vendor");
|
|
89
|
+
expect(serviceTypeToField(ServiceTypes.EntertainmentServices)).toBe("entertainmentService");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("AI string helpers", () => {
|
|
94
|
+
const info = {
|
|
95
|
+
description: "Venue name",
|
|
96
|
+
example: "The Loft",
|
|
97
|
+
type: "string" as const,
|
|
98
|
+
isArray: false,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
test("aiServiceInfoToInfoString", () => {
|
|
102
|
+
expect(aiServiceInfoToInfoString("serviceName", info)).toBe(
|
|
103
|
+
"serviceName: Venue name - string"
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("aiServiceInfoToExampleString marks arrays", () => {
|
|
108
|
+
expect(
|
|
109
|
+
aiServiceInfoToExampleString("tags", { ...info, isArray: true, example: '["A"]' })
|
|
110
|
+
).toBe('tags: ["A"] - string[]');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("buildAIFieldsString formats values and missing keys", () => {
|
|
114
|
+
const out = buildAIFieldsString(
|
|
115
|
+
{ capacity: 150, vibe: null },
|
|
116
|
+
{
|
|
117
|
+
capacity: { description: "cap", example: "100", type: "integer", isArray: false },
|
|
118
|
+
vibe: { description: "vibe", example: "Chill", type: "string", isArray: false },
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
expect(out).toContain("capacity: 150");
|
|
122
|
+
expect(out).toContain("vibe: No vibe provided");
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe("serviceRelevantData", () => {
|
|
127
|
+
test("strips ids, owners, rates, dates, and misc fields", () => {
|
|
128
|
+
const result = serviceRelevantData({
|
|
129
|
+
id: "svc-1",
|
|
130
|
+
ownerId: "u1",
|
|
131
|
+
creatorId: "u2",
|
|
132
|
+
serviceName: "Hidden",
|
|
133
|
+
serviceType: ServiceTypes.Venues,
|
|
134
|
+
createdAt: new Date(),
|
|
135
|
+
owner: { id: "u1" },
|
|
136
|
+
tagline: "Keep me",
|
|
137
|
+
} as any);
|
|
138
|
+
expect(result).toEqual({ tagline: "Keep me" });
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe("serviceExclude helpers", () => {
|
|
143
|
+
test("serviceExcludeIds removes foreign keys and ids", () => {
|
|
144
|
+
const result = serviceExcludeIds({
|
|
145
|
+
id: "svc-1",
|
|
146
|
+
venueId: "v1",
|
|
147
|
+
tagline: "Stay",
|
|
148
|
+
} as any);
|
|
149
|
+
expect(result).toEqual({ tagline: "Stay" });
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("serviceExcludeOwners removes nested owner/creator", () => {
|
|
153
|
+
const result = serviceExcludeOwners({
|
|
154
|
+
owner: { id: "u1" },
|
|
155
|
+
creator: { id: "u2" },
|
|
156
|
+
description: "Keep",
|
|
157
|
+
} as any);
|
|
158
|
+
expect(result).toEqual({ description: "Keep" });
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("serviceGetInfoAI", () => {
|
|
163
|
+
test("returns field metadata for venue services", () => {
|
|
164
|
+
const info = serviceGetInfoAI(ServiceTypes.Venues);
|
|
165
|
+
expect(info).toBeDefined();
|
|
166
|
+
expect(Object.keys(info).length).toBeGreaterThan(0);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe("getVendorSalesLabel", () => {
|
|
171
|
+
test("returns Products for vendors and Merch for others", () => {
|
|
172
|
+
expect(getVendorSalesLabel(ServiceTypes.Vendors)).toBe("Products");
|
|
173
|
+
expect(getVendorSalesLabel(ServiceTypes.EntertainmentServices)).toBe("Merch");
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe("SERVICE_CANCELLATION_POLICY_DATA", () => {
|
|
178
|
+
test("generates guest-facing copy for Flexible policy", () => {
|
|
179
|
+
const policy = SERVICE_CANCELLATION_POLICY_DATA.Flexible;
|
|
180
|
+
expect(policy.description).toContain("Guests may cancel");
|
|
181
|
+
expect(policy.refundPolicy).toHaveLength(2);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("generates vendor copy for VendorFlexible", () => {
|
|
185
|
+
const policy = SERVICE_CANCELLATION_POLICY_DATA.VendorFlexible;
|
|
186
|
+
expect(policy.description).toContain("the vendor");
|
|
187
|
+
expect(policy.description).toContain("verified booking");
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
});
|
|
@@ -39,7 +39,11 @@ function isActiveFeatured(s: FeaturedServiceSortable, now: Date): boolean {
|
|
|
39
39
|
* and are treated as "legacy featured" sitting just below auto-features).
|
|
40
40
|
*/
|
|
41
41
|
function featuredTier(s: FeaturedServiceSortable, now: Date): number {
|
|
42
|
-
if (!isActiveFeatured(s, now))
|
|
42
|
+
if (!isActiveFeatured(s, now)) {
|
|
43
|
+
// Expired paid feature still has isFeaturedService set; rank below never-featured.
|
|
44
|
+
if (s.isFeaturedService) return 4;
|
|
45
|
+
return 3;
|
|
46
|
+
}
|
|
43
47
|
if (s.featuredReason && PAID_TIER_REASONS.has(s.featuredReason)) return 0;
|
|
44
48
|
if (s.featuredReason === "AutoNewService") return 1;
|
|
45
49
|
return 2;
|
|
@@ -110,14 +110,21 @@ export function ticketListStrToTicketList(
|
|
|
110
110
|
): Map<string, NumberOfTicketsForDate[]> {
|
|
111
111
|
const ticketList: Map<string, NumberOfTicketsForDate[]> = new Map();
|
|
112
112
|
|
|
113
|
-
//
|
|
113
|
+
// Legacy plain strings use tier delimiters; encoded payloads are base64-only.
|
|
114
114
|
let decodedStr: string;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
if (
|
|
116
|
+
ticketListStr.includes(
|
|
117
|
+
URL_PARAMS_TICKET_TIER_ID_NUMBER_OF_TICKETS_DATE_DELIM
|
|
118
|
+
)
|
|
119
|
+
) {
|
|
120
120
|
decodedStr = ticketListStr;
|
|
121
|
+
} else {
|
|
122
|
+
try {
|
|
123
|
+
decodedStr = decodeBase64UrlSafe(ticketListStr);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error("Failed to decode ticketListStr:", error);
|
|
126
|
+
decodedStr = ticketListStr;
|
|
127
|
+
}
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
// [ticketTierId]__~~[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~...,...
|