@bash-app/bash-common 30.374.0 → 30.377.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.
Files changed (42) hide show
  1. package/dist/definitions.d.ts +7 -0
  2. package/dist/definitions.d.ts.map +1 -1
  3. package/dist/definitions.js.map +1 -1
  4. package/dist/extendedSchemas.d.ts +57 -1
  5. package/dist/extendedSchemas.d.ts.map +1 -1
  6. package/dist/extendedSchemas.js +10 -0
  7. package/dist/extendedSchemas.js.map +1 -1
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/utils/__tests__/ticketPrintPostageUtils.test.d.ts +2 -0
  13. package/dist/utils/__tests__/ticketPrintPostageUtils.test.d.ts.map +1 -0
  14. package/dist/utils/__tests__/ticketPrintPostageUtils.test.js +70 -0
  15. package/dist/utils/__tests__/ticketPrintPostageUtils.test.js.map +1 -0
  16. package/dist/utils/lobFlyerUtils.d.ts +2 -0
  17. package/dist/utils/lobFlyerUtils.d.ts.map +1 -1
  18. package/dist/utils/lobFlyerUtils.js +8 -0
  19. package/dist/utils/lobFlyerUtils.js.map +1 -1
  20. package/dist/utils/qrCodeUtils.d.ts +17 -0
  21. package/dist/utils/qrCodeUtils.d.ts.map +1 -1
  22. package/dist/utils/qrCodeUtils.js +20 -0
  23. package/dist/utils/qrCodeUtils.js.map +1 -1
  24. package/dist/utils/service/__tests__/apiServiceBookingApiUtils.test.js +4 -0
  25. package/dist/utils/service/__tests__/apiServiceBookingApiUtils.test.js.map +1 -1
  26. package/dist/utils/service/apiServiceBookingApiUtils.js +2 -2
  27. package/dist/utils/service/apiServiceBookingApiUtils.js.map +1 -1
  28. package/dist/utils/ticketPrintPostageUtils.d.ts +27 -0
  29. package/dist/utils/ticketPrintPostageUtils.d.ts.map +1 -0
  30. package/dist/utils/ticketPrintPostageUtils.js +65 -0
  31. package/dist/utils/ticketPrintPostageUtils.js.map +1 -0
  32. package/package.json +1 -1
  33. package/prisma/schema.prisma +94 -0
  34. package/src/definitions.ts +8 -0
  35. package/src/extendedSchemas.ts +64 -0
  36. package/src/index.ts +1 -0
  37. package/src/utils/__tests__/ticketPrintPostageUtils.test.ts +95 -0
  38. package/src/utils/lobFlyerUtils.ts +7 -0
  39. package/src/utils/qrCodeUtils.ts +26 -0
  40. package/src/utils/service/__tests__/apiServiceBookingApiUtils.test.ts +6 -0
  41. package/src/utils/service/apiServiceBookingApiUtils.ts +2 -2
  42. package/src/utils/ticketPrintPostageUtils.ts +81 -0
@@ -1181,6 +1181,8 @@ model BashEvent {
1181
1181
  merchOrders BashEventMerchOrder[]
1182
1182
  coatCheckEntitlements CoatCheckEntitlement[]
1183
1183
  experienceOpportunities ExperienceOpportunity[]
1184
+ ticketPrintOrders TicketPrintOrder[]
1185
+ ticketDeliverySettings TicketDeliverySettings?
1184
1186
 
1185
1187
  /// Latest AI moderator verdict
1186
1188
  /// Null = never reviewed by AI. Recomputed each time the bash transitions to Pending
@@ -3316,6 +3318,9 @@ model TicketTier {
3316
3318
  tierReleaseReminders TierReleaseReminder[]
3317
3319
  entryCompetition Competition? @relation("CompetitionEntryTicketTier")
3318
3320
 
3321
+ /// Host opt-in: buyers of this tier may choose mailed or venue will-call physical delivery (see TicketPrintOrder).
3322
+ allowsPhysicalDelivery Boolean @default(false)
3323
+
3319
3324
  @@unique([bashEventId, title])
3320
3325
  @@index([availableAt])
3321
3326
  }
@@ -3464,6 +3469,7 @@ model Ticket {
3464
3469
  eventReferral EventReferral? // When this ticket was purchased via a referral link
3465
3470
  flyerConversions FlyerConversion[]
3466
3471
  coatCheckEntitlements CoatCheckEntitlement[]
3472
+ printOrder TicketPrintOrder?
3467
3473
 
3468
3474
  @@index([bashEventId])
3469
3475
  @@index([bashEventId, seatId])
@@ -3556,6 +3562,94 @@ model TicketMetadata {
3556
3562
  @@index([ticketId])
3557
3563
  }
3558
3564
 
3565
+ enum TicketDeliveryMethod {
3566
+ Digital
3567
+ PhysicalMail
3568
+ VenueWillCall
3569
+ }
3570
+
3571
+ enum TicketPrintOrderStatus {
3572
+ Queued
3573
+ Submitted
3574
+ Printed
3575
+ InTransit
3576
+ Delivered
3577
+ Failed
3578
+ CancelledBeforeSubmit
3579
+ CancelledAfterSubmit
3580
+ }
3581
+
3582
+ /// One row per physical ticket piece mailed or held for venue will-call via Lob.
3583
+ /// Mirrors FlyerCampaign's Lob usage and CoatCheckEntitlement's per-unit purchase/status pattern.
3584
+ model TicketPrintOrder {
3585
+ id String @id @default(cuid())
3586
+ ticketId String @unique
3587
+ bashEventId String
3588
+
3589
+ deliveryMethod TicketDeliveryMethod
3590
+ status TicketPrintOrderStatus @default(Queued)
3591
+
3592
+ /// Ship-to snapshot: buyer address (PhysicalMail, from Stripe shipping_details) or
3593
+ /// venue will-call address (VenueWillCall, from TicketDeliverySettings) at submit time.
3594
+ shipToName String?
3595
+ shipToLine1 String?
3596
+ shipToLine2 String?
3597
+ shipToCity String?
3598
+ shipToState String?
3599
+ shipToZip String?
3600
+
3601
+ lobPostcardSize LobPostcardSize @default(LOB_4X6)
3602
+ lobPostcardId String?
3603
+ vendorStatus String?
3604
+ /// Groups will-call pieces submitted together for host tracking ("Batch #3 — 42 pieces").
3605
+ willCallBatchId String?
3606
+
3607
+ surchargeCents Int @default(0)
3608
+ stripeCheckoutSessionId String?
3609
+ checkoutId String?
3610
+
3611
+ submittedAt DateTime?
3612
+ printedAt DateTime?
3613
+ shippedAt DateTime?
3614
+ deliveredAt DateTime?
3615
+ cancelledAt DateTime?
3616
+
3617
+ lastVendorStatusSyncAt DateTime?
3618
+ lastLobWebhookId String?
3619
+
3620
+ createdAt DateTime @default(now())
3621
+ updatedAt DateTime @updatedAt
3622
+
3623
+ ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
3624
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
3625
+
3626
+ @@index([bashEventId, deliveryMethod, status])
3627
+ @@index([willCallBatchId])
3628
+ }
3629
+
3630
+ /// Per-event opt-in + venue will-call address for physical ticket delivery; kept separate
3631
+ /// from BashEvent (already very large) — one row per event, created on first opt-in.
3632
+ model TicketDeliverySettings {
3633
+ id String @id @default(cuid())
3634
+ bashEventId String @unique
3635
+
3636
+ physicalMailEnabled Boolean @default(false)
3637
+ willCallEnabled Boolean @default(false)
3638
+ lobPostcardSize LobPostcardSize @default(LOB_4X6)
3639
+
3640
+ willCallAddressName String?
3641
+ willCallAddressLine1 String?
3642
+ willCallAddressLine2 String?
3643
+ willCallAddressCity String?
3644
+ willCallAddressState String?
3645
+ willCallAddressZip String?
3646
+
3647
+ createdAt DateTime @default(now())
3648
+ updatedAt DateTime @updatedAt
3649
+
3650
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
3651
+ }
3652
+
3559
3653
  /// Stripe donation to an event (Checkout session or PaymentIntent); includes optional UTM attribution.
3560
3654
  model BashEventDonation {
3561
3655
  id String @id @default(cuid())
@@ -1101,6 +1101,14 @@ export interface StripeCreateBashEventTicketsCheckoutSessionArgs extends UtmFiel
1101
1101
  coatCheckOversized?: boolean;
1102
1102
  /** Optional tip cents for coat check (when host enables tips). */
1103
1103
  coatCheckTipCents?: number;
1104
+
1105
+ /**
1106
+ * Physical ticket delivery via Lob (mail-to-buyer or venue will-call).
1107
+ * Undefined = digital ticket only (existing flow, unchanged). Server
1108
+ * validates against the event's `TicketDeliverySettings` + each tier's
1109
+ * `allowsPhysicalDelivery` before charging the surcharge.
1110
+ */
1111
+ ticketDeliveryMethod?: "PhysicalMail" | "VenueWillCall";
1104
1112
  }
1105
1113
 
1106
1114
  export interface StripeCreateBashEventDonationCheckoutSessionArgs extends UtmFields {
@@ -78,6 +78,10 @@ import {
78
78
  TicketTier,
79
79
  TicketTransfer,
80
80
  TicketTransferInvite,
81
+ TicketDeliverySettings,
82
+ TicketDeliveryMethod,
83
+ TicketPrintOrder,
84
+ TicketPrintOrderStatus,
81
85
  User,
82
86
  UserPreferences,
83
87
  UserStats,
@@ -1729,6 +1733,8 @@ export type TicketFlexible = Ticket & {
1729
1733
  transfers?: TicketTransfer[];
1730
1734
  metadata?: TicketMetadata[];
1731
1735
  transferInvite?: TicketTransferInviteTeaser | null;
1736
+ /** Physical delivery (mail / venue will-call) status, when the ticket opted in at checkout. */
1737
+ printOrder?: TicketPrintOrder | null;
1732
1738
  };
1733
1739
 
1734
1740
  /**
@@ -2114,6 +2120,64 @@ export interface FlyerAnalyticsSummary {
2114
2120
 
2115
2121
  export type PostalCarrierRouteExt = PostalCarrierRoute;
2116
2122
 
2123
+ // --- Physical ticket delivery (mail / venue will-call via Lob) ---
2124
+
2125
+ /** Delivery method a buyer picks at checkout when the tier allows physical delivery. */
2126
+ export interface TicketDeliverySelection {
2127
+ deliveryMethod: TicketDeliveryMethod;
2128
+ }
2129
+
2130
+ export const TICKET_PRINT_ORDER_WITH_TICKET_INCLUDE = {
2131
+ ticket: {
2132
+ select: {
2133
+ id: true,
2134
+ fullName: true,
2135
+ email: true,
2136
+ ticketTier: { select: { id: true, title: true } },
2137
+ },
2138
+ },
2139
+ } satisfies Prisma.TicketPrintOrderInclude;
2140
+
2141
+ export type TicketPrintOrderExt = Prisma.TicketPrintOrderGetPayload<{
2142
+ include: typeof TICKET_PRINT_ORDER_WITH_TICKET_INCLUDE;
2143
+ }>;
2144
+
2145
+ /** Host-facing form for enabling/configuring physical delivery on an event. */
2146
+ export interface TicketDeliverySettingsFormData {
2147
+ physicalMailEnabled: boolean;
2148
+ willCallEnabled: boolean;
2149
+ lobPostcardSize: TicketDeliverySettings["lobPostcardSize"];
2150
+ willCallAddressName?: string;
2151
+ willCallAddressLine1?: string;
2152
+ willCallAddressLine2?: string;
2153
+ willCallAddressCity?: string;
2154
+ willCallAddressState?: string;
2155
+ willCallAddressZip?: string;
2156
+ }
2157
+
2158
+ /** Response from the host "send queued will-call tickets to venue" action. */
2159
+ export interface WillCallBatchSubmitResult {
2160
+ willCallBatchId: string;
2161
+ submittedCount: number;
2162
+ failedCount: number;
2163
+ }
2164
+
2165
+ /** Summary counts for the host Tickets tab "Print & Mail" panel. */
2166
+ export interface TicketPrintOrderSummary {
2167
+ deliveryMethod: TicketDeliveryMethod;
2168
+ status: TicketPrintOrderStatus;
2169
+ count: number;
2170
+ }
2171
+
2172
+ /** Public-safe checkout-time read of an event's physical delivery settings. */
2173
+ export interface TicketDeliveryAvailability {
2174
+ physicalMailEnabled: boolean;
2175
+ willCallEnabled: boolean;
2176
+ lobPostcardSize: TicketDeliverySettings["lobPostcardSize"];
2177
+ /** Buyer-facing surcharge (integer cents) for one physical ticket piece. */
2178
+ surchargeCentsPerTicket: number;
2179
+ }
2180
+
2117
2181
  // === Talent Agency selects/types ============================================
2118
2182
 
2119
2183
  /// Public-safe roster entry for an agency's artist (agency detail page + cards).
package/src/index.ts CHANGED
@@ -416,6 +416,7 @@ export * from "./utils/ticketCheckInDisplay.js";
416
416
  export * from "./utils/coatCheckUtils.js";
417
417
  export * from "./utils/ticketTierSchedule.js";
418
418
  export * from "./utils/lobFlyerUtils.js";
419
+ export * from "./utils/ticketPrintPostageUtils.js";
419
420
  export * from "./utils/generalDateTimeUtils.js";
420
421
  export * from "./utils/locationVisibility.js";
421
422
  export * from "./utils/luxonUtils.js";
@@ -0,0 +1,95 @@
1
+ import { describe, expect, it } from "@jest/globals";
2
+ import { TicketDeliveryMethod, TicketPrintOrderStatus } from "@prisma/client";
3
+
4
+ import {
5
+ ticketDeliveryStatusLabel,
6
+ ticketPrintSurchargeCentsForQuantity,
7
+ ticketPrintSurchargeCentsPerPiece,
8
+ } from "../ticketPrintPostageUtils.js";
9
+
10
+ describe("ticketPrintPostageUtils", () => {
11
+ describe("ticketPrintSurchargeCentsPerPiece", () => {
12
+ it("matches the per-piece quote for quantity 1", () => {
13
+ expect(ticketPrintSurchargeCentsPerPiece("LOB_4X6")).toBe(
14
+ ticketPrintSurchargeCentsForQuantity("LOB_4X6", 1)
15
+ );
16
+ });
17
+ });
18
+
19
+ describe("ticketPrintSurchargeCentsForQuantity", () => {
20
+ it("is zero for quantity < 1", () => {
21
+ expect(ticketPrintSurchargeCentsForQuantity("LOB_4X6", 0)).toBe(0);
22
+ expect(ticketPrintSurchargeCentsForQuantity("LOB_4X6", -1)).toBe(0);
23
+ });
24
+
25
+ it("scales with quantity", () => {
26
+ const one = ticketPrintSurchargeCentsForQuantity("LOB_6X9", 1);
27
+ const five = ticketPrintSurchargeCentsForQuantity("LOB_6X9", 5);
28
+ expect(five).toBeGreaterThan(one);
29
+ });
30
+ });
31
+
32
+ describe("ticketDeliveryStatusLabel", () => {
33
+ it("returns null for Digital (no print order)", () => {
34
+ expect(ticketDeliveryStatusLabel(null)).toBeNull();
35
+ expect(ticketDeliveryStatusLabel(undefined)).toBeNull();
36
+ });
37
+
38
+ it("returns a cancelled label regardless of delivery method (before submit)", () => {
39
+ expect(
40
+ ticketDeliveryStatusLabel({
41
+ deliveryMethod: TicketDeliveryMethod.PhysicalMail,
42
+ status: TicketPrintOrderStatus.CancelledBeforeSubmit,
43
+ })
44
+ ).toBe("Physical ticket cancelled");
45
+ });
46
+
47
+ it("returns a cancelled label (after submit)", () => {
48
+ expect(
49
+ ticketDeliveryStatusLabel({
50
+ deliveryMethod: TicketDeliveryMethod.VenueWillCall,
51
+ status: TicketPrintOrderStatus.CancelledAfterSubmit,
52
+ })
53
+ ).toBe("Physical ticket cancelled");
54
+ });
55
+
56
+ it("returns a failure label", () => {
57
+ expect(
58
+ ticketDeliveryStatusLabel({
59
+ deliveryMethod: TicketDeliveryMethod.PhysicalMail,
60
+ status: TicketPrintOrderStatus.Failed,
61
+ })
62
+ ).toBe("Physical ticket delivery failed — contact the host");
63
+ });
64
+
65
+ it.each([
66
+ [TicketPrintOrderStatus.Queued, "Pick up at venue: will-call (printing soon)"],
67
+ [TicketPrintOrderStatus.Submitted, "Pick up at venue: will-call"],
68
+ [TicketPrintOrderStatus.Printed, "Pick up at venue: will-call"],
69
+ [TicketPrintOrderStatus.InTransit, "Pick up at venue: will-call"],
70
+ [TicketPrintOrderStatus.Delivered, "Pick up at venue: will-call (ready)"],
71
+ ])("VenueWillCall %s -> %s", (status, expected) => {
72
+ expect(
73
+ ticketDeliveryStatusLabel({
74
+ deliveryMethod: TicketDeliveryMethod.VenueWillCall,
75
+ status,
76
+ })
77
+ ).toBe(expected);
78
+ });
79
+
80
+ it.each([
81
+ [TicketPrintOrderStatus.Queued, "Mailed ticket: printing"],
82
+ [TicketPrintOrderStatus.Submitted, "Mailed ticket: printing"],
83
+ [TicketPrintOrderStatus.Printed, "Mailed ticket: printed"],
84
+ [TicketPrintOrderStatus.InTransit, "Mailed ticket: in transit"],
85
+ [TicketPrintOrderStatus.Delivered, "Mailed ticket: delivered"],
86
+ ])("PhysicalMail %s -> %s", (status, expected) => {
87
+ expect(
88
+ ticketDeliveryStatusLabel({
89
+ deliveryMethod: TicketDeliveryMethod.PhysicalMail,
90
+ status,
91
+ })
92
+ ).toBe(expected);
93
+ });
94
+ });
95
+ });
@@ -13,6 +13,13 @@
13
13
 
14
14
  export type LobPostcardSizeKey = "LOB_4X6" | "LOB_6X9" | "LOB_6X11";
15
15
 
16
+ /** Narrows the Prisma `LobPostcardSize` enum value to the string-literal key used by these utils. */
17
+ export function lobPostcardSizeEnumToKey(size: LobPostcardSizeKey | string): LobPostcardSizeKey {
18
+ if (size === "LOB_6X9") return "LOB_6X9";
19
+ if (size === "LOB_6X11") return "LOB_6X11";
20
+ return "LOB_4X6";
21
+ }
22
+
16
23
  /** Trim width × height in inches (portrait), matching Lob postcard products. */
17
24
  export const LOB_POSTCARD_TRIM_IN: Record<
18
25
  LobPostcardSizeKey,
@@ -24,3 +24,29 @@ export async function createQrCodeImage(qrData: string): Promise<string> {
24
24
  errorCorrectionLevel: 'high',
25
25
  });
26
26
  }
27
+
28
+ /**
29
+ * Door-scan admission QR payload for a ticket — the same shape the buyer's
30
+ * "show at door" QR encodes (bash-app `MyTicketInlineQr.tsx`, built inline as
31
+ * `checkInData` for `encodeTicketQrPayload`) and what the API's door-verify
32
+ * parser reads (`parseTicketQrScanPayload` in `ticketApi.ts`, which requires
33
+ * string `eventId`/`ticketId` and reads an optional `qrToken`).
34
+ *
35
+ * Server-side callers (e.g. printed ticket artwork) MUST use this so a
36
+ * physical ticket's QR scans identically to the in-app one — no new
37
+ * verification path, no schema changes to `qrToken` handling.
38
+ */
39
+ export function encodeTicketDoorQrPayload(args: {
40
+ eventId: string;
41
+ ticketId: string;
42
+ ownerUserId?: string | null;
43
+ qrToken?: string | null;
44
+ }): string {
45
+ return JSON.stringify({
46
+ eventId: args.eventId,
47
+ userId: args.ownerUserId ?? "",
48
+ ticketId: args.ticketId,
49
+ qrToken: args.qrToken ?? undefined,
50
+ timestamp: new Date().toISOString(),
51
+ });
52
+ }
@@ -148,6 +148,12 @@ describe("servicePriceToBookToApiPackages", () => {
148
148
  expect(servicePriceToBookToApiPackages(priceToBook)).toEqual([]);
149
149
  });
150
150
 
151
+ it("returns empty array when priceToBook.packages is undefined", () => {
152
+ const priceToBook = {} as unknown as FrontendServiceGetPriceToBookResult;
153
+
154
+ expect(servicePriceToBookToApiPackages(priceToBook)).toEqual([]);
155
+ });
156
+
151
157
  it("maps priceToBook packages to ApiServicePackageParams", () => {
152
158
  const priceToBook = {
153
159
  packages: [
@@ -270,7 +270,7 @@ export function servicePriceToBookToApiDays(
270
270
  export function servicePriceToBookToApiPackages(
271
271
  priceToBook: FrontendServiceGetPriceToBookResult
272
272
  ): ApiServicePackageParams[] {
273
- return priceToBook.packages.map(
273
+ return (priceToBook.packages ?? []).map(
274
274
  (pkg): ApiServicePackageParams => ({
275
275
  packageId: pkg.packageId,
276
276
  chosenQuantity: pkg.chosenQuantity,
@@ -304,7 +304,7 @@ export function servicePriceToBookToApiBookingBase({
304
304
  costPQCents: addOn.costPQCents,
305
305
  })
306
306
  );
307
- const packages = priceToBook.packages.map(
307
+ const packages = (priceToBook.packages ?? []).map(
308
308
  (pkg): Partial<ServiceBookingPackageExt> => ({
309
309
  packageId: pkg.packageId,
310
310
  package: pkg.package,
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Buyer-facing surcharge for physical ticket delivery (mail-to-buyer or venue
3
+ * will-call), both fulfilled as individually-addressed Lob postcards — one
4
+ * ticket = one piece, same product used by Flyer Blast's addressed mail path.
5
+ *
6
+ * Reuses the Lob per-piece cost table from `lobFlyerUtils.ts` rather than
7
+ * duplicating pricing — same "verify before production" caveat applies here.
8
+ */
9
+
10
+ import { TicketDeliveryMethod, TicketPrintOrderStatus } from "@prisma/client";
11
+
12
+ import {
13
+ quoteLobAddressedPostageCents,
14
+ type LobPostcardSizeKey,
15
+ } from "./lobFlyerUtils.js";
16
+
17
+ /** Surcharge for a single printed/mailed ticket piece (integer cents). */
18
+ export function ticketPrintSurchargeCentsPerPiece(size: LobPostcardSizeKey): number {
19
+ return quoteLobAddressedPostageCents(size, 1);
20
+ }
21
+
22
+ /**
23
+ * Total buyer-facing surcharge (integer cents) for `quantity` physical ticket
24
+ * pieces of the given size — used as the Stripe checkout line item amount.
25
+ */
26
+ export function ticketPrintSurchargeCentsForQuantity(
27
+ size: LobPostcardSizeKey,
28
+ quantity: number
29
+ ): number {
30
+ if (quantity < 1) return 0;
31
+ return quoteLobAddressedPostageCents(size, quantity);
32
+ }
33
+
34
+ /**
35
+ * Buyer-facing badge copy for a ticket's physical delivery status — shared by
36
+ * My Tickets and the ticket details view so both surfaces stay in sync.
37
+ * `null`/`undefined` (Digital) means no badge should render.
38
+ */
39
+ export function ticketDeliveryStatusLabel(
40
+ printOrder:
41
+ | { deliveryMethod: TicketDeliveryMethod; status: TicketPrintOrderStatus }
42
+ | null
43
+ | undefined
44
+ ): string | null {
45
+ if (!printOrder) return null;
46
+ const { deliveryMethod, status } = printOrder;
47
+
48
+ if (
49
+ status === TicketPrintOrderStatus.CancelledBeforeSubmit ||
50
+ status === TicketPrintOrderStatus.CancelledAfterSubmit
51
+ ) {
52
+ return "Physical ticket cancelled";
53
+ }
54
+ if (status === TicketPrintOrderStatus.Failed) {
55
+ return "Physical ticket delivery failed — contact the host";
56
+ }
57
+ if (deliveryMethod === TicketDeliveryMethod.VenueWillCall) {
58
+ switch (status) {
59
+ case TicketPrintOrderStatus.Queued:
60
+ return "Pick up at venue: will-call (printing soon)";
61
+ case TicketPrintOrderStatus.Delivered:
62
+ return "Pick up at venue: will-call (ready)";
63
+ default:
64
+ return "Pick up at venue: will-call";
65
+ }
66
+ }
67
+ // PhysicalMail
68
+ switch (status) {
69
+ case TicketPrintOrderStatus.Queued:
70
+ case TicketPrintOrderStatus.Submitted:
71
+ return "Mailed ticket: printing";
72
+ case TicketPrintOrderStatus.Printed:
73
+ return "Mailed ticket: printed";
74
+ case TicketPrintOrderStatus.InTransit:
75
+ return "Mailed ticket: in transit";
76
+ case TicketPrintOrderStatus.Delivered:
77
+ return "Mailed ticket: delivered";
78
+ default:
79
+ return "Mailed ticket";
80
+ }
81
+ }