@getmicdrop/venue-calendar 4.0.68 → 4.0.70
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/{CarouselView.legacy-DtlaKenI.js → CarouselView.legacy-CAtJAiSb.js} +3 -3
- package/dist/{CarouselView.legacy-DtlaKenI.js.map → CarouselView.legacy-CAtJAiSb.js.map} +1 -1
- package/dist/{CartView-xAVJT3Wf.js → CartView-CpA__vH7.js} +53 -53
- package/dist/{CartView-xAVJT3Wf.js.map → CartView-CpA__vH7.js.map} +1 -1
- package/dist/{Checkout-C8E5Q9nl.js → Checkout-Bm3yGYYr.js} +278 -273
- package/dist/Checkout-Bm3yGYYr.js.map +1 -0
- package/dist/{Checkout-WYIEsOZ0.js → Checkout-CRBwRTOc.js} +114 -114
- package/dist/{Checkout-WYIEsOZ0.js.map → Checkout-CRBwRTOc.js.map} +1 -1
- package/dist/{Checkout.legacy-Bjj390J_.js → Checkout.legacy-CpgxTxZl.js} +5 -5
- package/dist/{Checkout.legacy-Bjj390J_.js.map → Checkout.legacy-CpgxTxZl.js.map} +1 -1
- package/dist/{CheckoutTimer-DlnXHs-c.js → CheckoutTimer-SMZRnL_T.js} +2 -2
- package/dist/{CheckoutTimer-DlnXHs-c.js.map → CheckoutTimer-SMZRnL_T.js.map} +1 -1
- package/dist/{CollectionView-89AFwGuE.js → CollectionView-DgVzimMX.js} +5 -5
- package/dist/{CollectionView-89AFwGuE.js.map → CollectionView-DgVzimMX.js.map} +1 -1
- package/dist/{CollectionView.legacy-Czq6UrTZ.js → CollectionView.legacy-BTAS-mTd.js} +31 -31
- package/dist/{CollectionView.legacy-Czq6UrTZ.js.map → CollectionView.legacy-BTAS-mTd.js.map} +1 -1
- package/dist/{Event-DhvEjKVz.js → Event-BNVO_E6j.js} +145 -145
- package/dist/{Event-DhvEjKVz.js.map → Event-BNVO_E6j.js.map} +1 -1
- package/dist/{EventDetailsView-4f1xNl1a.js → EventDetailsView-CXvl9xwe.js} +140 -140
- package/dist/EventDetailsView-CXvl9xwe.js.map +1 -0
- package/dist/{EventPage-D75bt8XZ.js → EventPage-Dc4CtBeS.js} +5 -5
- package/dist/{EventPage-D75bt8XZ.js.map → EventPage-Dc4CtBeS.js.map} +1 -1
- package/dist/{EventPage.legacy-DU0ZcZg9.js → EventPage.legacy-D-9svuzb.js} +49 -49
- package/dist/{EventPage.legacy-DU0ZcZg9.js.map → EventPage.legacy-D-9svuzb.js.map} +1 -1
- package/dist/{FeaturedView.legacy-BgZu-R0y.js → FeaturedView.legacy-BKF3u2sH.js} +19 -19
- package/dist/{FeaturedView.legacy-BgZu-R0y.js.map → FeaturedView.legacy-BKF3u2sH.js.map} +1 -1
- package/dist/{GalleryCard-DdHqVAXD.js → GalleryCard-lNx3CEtB.js} +9 -9
- package/dist/{GalleryCard-DdHqVAXD.js.map → GalleryCard-lNx3CEtB.js.map} +1 -1
- package/dist/{GalleryView.legacy-F46Bwi9x.js → GalleryView.legacy-CMjIfp2b.js} +3 -3
- package/dist/{GalleryView.legacy-F46Bwi9x.js.map → GalleryView.legacy-CMjIfp2b.js.map} +1 -1
- package/dist/{GroupedListView.legacy-CLnOs7Ls.js → GroupedListView.legacy-BybmHzIV.js} +23 -23
- package/dist/{GroupedListView.legacy-CLnOs7Ls.js.map → GroupedListView.legacy-BybmHzIV.js.map} +1 -1
- package/dist/{OrderSummary-BYSCmf9h.js → OrderSummary-B1GhsUnc.js} +7 -7
- package/dist/{OrderSummary-BYSCmf9h.js.map → OrderSummary-B1GhsUnc.js.map} +1 -1
- package/dist/{PromoCodeInput-B8agz1bc.js → PromoCodeInput-CrXBD0oq.js} +30 -30
- package/dist/{PromoCodeInput-B8agz1bc.js.map → PromoCodeInput-CrXBD0oq.js.map} +1 -1
- package/dist/{SeriesPage-CH8STWTA.js → SeriesPage-DEDSbKuu.js} +5 -5
- package/dist/{SeriesPage-CH8STWTA.js.map → SeriesPage-DEDSbKuu.js.map} +1 -1
- package/dist/{SeriesPage.legacy-Cg5j7_1m.js → SeriesPage.legacy-BlqTBr4n.js} +38 -38
- package/dist/{SeriesPage.legacy-Cg5j7_1m.js.map → SeriesPage.legacy-BlqTBr4n.js.map} +1 -1
- package/dist/{Success-DMGAgbh-.js → Success-CD4K7aRv.js} +24 -24
- package/dist/{Success-DMGAgbh-.js.map → Success-CD4K7aRv.js.map} +1 -1
- package/dist/{Success.legacy-CY33Nix8.js → Success.legacy-B1Jvy8N0.js} +2 -2
- package/dist/{Success.legacy-CY33Nix8.js.map → Success.legacy-B1Jvy8N0.js.map} +1 -1
- package/dist/{VenueCalendar-H0gMPiFX.js → VenueCalendar-BoSdP7xI.js} +1472 -1457
- package/dist/{VenueCalendar-H0gMPiFX.js.map → VenueCalendar-BoSdP7xI.js.map} +1 -1
- package/dist/{ViewTicketsEmbed-DiGhZiyP.js → ViewTicketsEmbed-D1nD9zJY.js} +42 -42
- package/dist/{ViewTicketsEmbed-DiGhZiyP.js.map → ViewTicketsEmbed-D1nD9zJY.js.map} +1 -1
- package/dist/{WaitlistModal-CA8-Rcff.js → WaitlistModal-DWcbQmfW.js} +35 -35
- package/dist/{WaitlistModal-CA8-Rcff.js.map → WaitlistModal-DWcbQmfW.js.map} +1 -1
- package/dist/api/api.cjs +1 -1
- package/dist/api/api.cjs.map +1 -1
- package/dist/api/api.mjs +160 -157
- package/dist/api/api.mjs.map +1 -1
- package/dist/{api-IWcZsS94.js → api-CCKXC9Qs.js} +2 -2
- package/dist/{api-IWcZsS94.js.map → api-CCKXC9Qs.js.map} +1 -1
- package/dist/{data-toggle-store.svelte-D6pqR0Zt.js → data-toggle-store.svelte-CB6WLZEE.js} +2 -2
- package/dist/{data-toggle-store.svelte-D6pqR0Zt.js.map → data-toggle-store.svelte-CB6WLZEE.js.map} +1 -1
- package/dist/{transform-BPCR9pPY.js → transform-BrlBxayh.js} +6 -3
- package/dist/transform-BrlBxayh.js.map +1 -0
- package/dist/venue-calendar.es.js +1 -1
- package/dist/venue-calendar.iife.js +32 -32
- package/dist/venue-calendar.iife.js.map +1 -1
- package/dist/venue-calendar.umd.js +30 -30
- package/dist/venue-calendar.umd.js.map +1 -1
- package/package.json +1 -1
- package/dist/Checkout-C8E5Q9nl.js.map +0 -1
- package/dist/EventDetailsView-4f1xNl1a.js.map +0 -1
- package/dist/transform-BPCR9pPY.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrderSummary-BYSCmf9h.js","sources":["../src/lib/api/cta.ts","../src/lib/public-calendar-flow/defaults.ts","../src/lib/public-calendar-flow/OrderSummary.svelte"],"sourcesContent":["/**\r\n * CTA state computation.\r\n *\r\n * Pure function (no I/O) — derives the buy-button state from an event and\r\n * its ticket list. Lives in `api/` because it is the canonical, single\r\n * source of truth that replaces the duplicate implementations previously\r\n * scattered across utils/api.js, core/api-client.js, and a few components.\r\n */\r\n\r\n// Import from the specific subpath (not the bare entry) so the api/\r\n// bundle doesn't pull in the entire SC component graph (Accordion etc.)\r\n// and break `npm run build:api`.\r\nimport {\r\n formatDateRaw,\r\n formatTime,\r\n} from '@getmicdrop/svelte-components/utils/formatters';\r\n\r\nexport interface CtaStateOptions {\r\n cancelled?: boolean;\r\n isRegistration?: boolean;\r\n waitlistEnabled?: boolean;\r\n}\r\n\r\nexport interface CtaState {\r\n text: string;\r\n disabled: boolean;\r\n reason:\r\n | 'cancelled'\r\n | 'event_past'\r\n | 'no_tickets'\r\n | 'available'\r\n | 'coming_soon'\r\n | 'sold_out_waitlist'\r\n | 'sold_out'\r\n | 'sales_ended'\r\n | 'hidden_only';\r\n}\r\n\r\ninterface CtaEvent {\r\n startDateTime?: string | null;\r\n endDateTime?: string | null;\r\n hasPurchasableHiddenTickets?: boolean;\r\n}\r\n\r\ninterface CtaTicket {\r\n salesChannel?: number;\r\n salesBegin?: string | null;\r\n salesStart?: string | null;\r\n saleBegin?: string | null;\r\n onSaleStart?: string | null;\r\n salesEnd?: string | null;\r\n saleEnd?: string | null;\r\n onSaleEnd?: string | null;\r\n remainingCapacity?: number | null;\r\n quantityRemaining?: number | null;\r\n quantity?: number | null;\r\n soldOut?: boolean;\r\n isHidden?: boolean;\r\n visibility?: number;\r\n}\r\n\r\n// A hidden ticket (visibility>=2 or isHidden) that's still on sale drives the\r\n// \"Sales ended\" / \"Sold out\" / \"No tickets\" → \"Get tickets\" override. The user\r\n// just needs the promo code to see it.\r\nexport function isHiddenTicketPurchasable(ticket: CtaTicket): boolean {\r\n if (!ticket) return false;\r\n const isHidden =\r\n ticket.isHidden === true ||\r\n (typeof ticket.visibility === 'number' && ticket.visibility >= 2);\r\n if (!isHidden) return false;\r\n if (ticket.salesChannel === 2) return false;\r\n\r\n const now = new Date();\r\n const salesBegin =\r\n ticket.salesBegin ||\r\n ticket.salesStart ||\r\n ticket.saleBegin ||\r\n ticket.onSaleStart;\r\n const salesEnd = ticket.salesEnd || ticket.saleEnd || ticket.onSaleEnd;\r\n if (salesBegin && new Date(salesBegin) > now) return false;\r\n if (salesEnd && new Date(salesEnd) < now) return false;\r\n\r\n const remaining =\r\n ticket.remainingCapacity ?? ticket.quantityRemaining ?? ticket.quantity;\r\n const isSoldOut =\r\n ticket.soldOut ||\r\n (remaining !== null && remaining !== undefined && remaining <= 0);\r\n if (isSoldOut) return false;\r\n\r\n return true;\r\n}\r\n\r\nexport function computeCtaState(\r\n event: CtaEvent,\r\n tickets: CtaTicket[] | undefined,\r\n options: CtaStateOptions = {}\r\n): CtaState {\r\n const {\r\n cancelled = false,\r\n isRegistration = false,\r\n waitlistEnabled = false,\r\n } = options;\r\n const now = new Date();\r\n\r\n if (cancelled)\r\n return { text: 'Cancelled', disabled: true, reason: 'cancelled' };\r\n\r\n const eventEnd = event.endDateTime || event.startDateTime;\r\n if (eventEnd && new Date(eventEnd) < now) {\r\n return { text: 'Sales ended', disabled: true, reason: 'event_past' };\r\n }\r\n\r\n const hiddenAvailable =\r\n event?.hasPurchasableHiddenTickets === true ||\r\n (Array.isArray(tickets) && tickets.some(isHiddenTicketPurchasable));\r\n\r\n const publicTickets = (tickets || []).filter(\r\n t =>\r\n t.salesChannel !== 2 &&\r\n !t.isHidden &&\r\n !(typeof t.visibility === 'number' && t.visibility >= 2)\r\n );\r\n if (publicTickets.length === 0) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n return {\r\n text: 'No tickets available',\r\n disabled: true,\r\n reason: 'no_tickets',\r\n };\r\n }\r\n\r\n let hasPurchasable = false;\r\n let allSoldOut = true;\r\n let allComingSoon = true;\r\n let earliestSalesStart: Date | null = null;\r\n\r\n for (const ticket of publicTickets) {\r\n const salesBegin =\r\n ticket.salesBegin ||\r\n ticket.salesStart ||\r\n ticket.saleBegin ||\r\n ticket.onSaleStart;\r\n const salesEnd = ticket.salesEnd || ticket.saleEnd || ticket.onSaleEnd;\r\n const remaining =\r\n ticket.remainingCapacity ?? ticket.quantityRemaining ?? ticket.quantity;\r\n const isSoldOut =\r\n ticket.soldOut ||\r\n (remaining !== null && remaining !== undefined && remaining <= 0);\r\n\r\n const isScheduled = salesBegin ? new Date(salesBegin) > now : false;\r\n const hasSalesEnded = salesEnd ? new Date(salesEnd) < now : false;\r\n const isPurchasable = !isSoldOut && !isScheduled && !hasSalesEnded;\r\n\r\n if (isPurchasable) hasPurchasable = true;\r\n if (!isSoldOut) allSoldOut = false;\r\n if (!isScheduled) allComingSoon = false;\r\n\r\n if (isScheduled && salesBegin && !isSoldOut && !hasSalesEnded) {\r\n const startDate = new Date(salesBegin);\r\n if (!earliestSalesStart || startDate < earliestSalesStart) {\r\n earliestSalesStart = startDate;\r\n }\r\n }\r\n }\r\n\r\n if (hasPurchasable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'available',\r\n };\r\n }\r\n\r\n if (allComingSoon && earliestSalesStart) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n const diffMs = earliestSalesStart.getTime() - now.getTime();\r\n const diffHours = diffMs / (1000 * 60 * 60);\r\n const diffDays = diffMs / (1000 * 60 * 60 * 24);\r\n let dateText: string;\r\n if (diffHours < 24) {\r\n dateText = formatTime(earliestSalesStart, { hour12: true }, 'en-US');\r\n } else if (diffDays <= 7) {\r\n dateText = formatDateRaw(\r\n earliestSalesStart,\r\n { weekday: 'short', hour: 'numeric', minute: '2-digit', hour12: true },\r\n 'en-US'\r\n );\r\n } else {\r\n const d = formatDateRaw(\r\n earliestSalesStart,\r\n { month: 'short', day: 'numeric' },\r\n 'en-US'\r\n );\r\n const t = formatTime(earliestSalesStart, { hour12: true }, 'en-US');\r\n dateText = `${d} ${t}`;\r\n }\r\n return {\r\n text: `On sale ${dateText}`,\r\n disabled: true,\r\n reason: 'coming_soon',\r\n };\r\n }\r\n\r\n if (allSoldOut) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n if (waitlistEnabled) {\r\n return {\r\n text: 'Join Waitlist',\r\n disabled: false,\r\n reason: 'sold_out_waitlist',\r\n };\r\n }\r\n return { text: 'Sold out', disabled: true, reason: 'sold_out' };\r\n }\r\n\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n\r\n return { text: 'Sales ended', disabled: true, reason: 'sales_ended' };\r\n}\r\n","// @currency-escape: feeCents / 100 in calculateServiceFee is arithmetic,\r\n// not display. Produces a dollar-magnitude number used in the fee formula\r\n// `price * (feePercentage / 100) + feeCents / 100`. Per Atlas\r\n// utility-currency convergence record; the no-handrolled-currency\r\n// ESLint rule's divideByHundred detector treats variable-name `Cents`\r\n// as drift but here it's real math.\r\n\r\n// Premium Ticket Experience — Constants & Defaults\r\n// Used by all design variants. DO NOT MODIFY per-variant.\r\n\r\n// @raw-intl-datetimeformat-escape: formatSmartSalesDate is a date-formatter\r\n// implementation (smart relative-date thresholds → \"on Friday at 8 PM\" / \"on Mar 15\").\r\n// The weekday-long (\"Friday\") and month-short+day (\"Mar 15\") fragments are interpolated\r\n// into smart-threshold strings; SC formatDate/DATE_FORMATS has no preset that emits a\r\n// bare weekday or a bare month+day, so it cannot reproduce these byte-identical fragments.\r\n// This file is the canonical formatter module for public-calendar-flow (it wraps + re-exports\r\n// scFormatDate/scFormatTime), not a call site.\r\n\r\nimport type {\r\n EventData,\r\n TicketTypeData,\r\n ScarcityLevel,\r\n CtaConfig,\r\n PromoCodeState,\r\n} from './types';\r\nimport { computeCtaState } from '$lib/api';\r\nimport type { Cents } from '@getmicdrop/svelte-components';\r\nimport {\r\n formatDate as scFormatDate,\r\n formatTime as scFormatTime,\r\n roundCurrency,\r\n} from '@getmicdrop/svelte-components';\r\nimport {\r\n formatFullDate,\r\n formatFullDateCompact,\r\n formatEventTime,\r\n formatTimeRange,\r\n formatDoorsTime,\r\n formatSalesDate,\r\n formatBrowseDate,\r\n formatEventDate,\r\n formatCleanTimeRange,\r\n getDateParts,\r\n} from '$lib/utils/datetime.js';\r\n\r\n// --- Re-export production date/time formatters (timezone-aware) ---\r\nexport {\r\n formatFullDate,\r\n formatFullDateCompact,\r\n formatEventTime,\r\n formatTimeRange,\r\n formatDoorsTime,\r\n formatSalesDate,\r\n formatBrowseDate,\r\n formatEventDate,\r\n formatCleanTimeRange,\r\n getDateParts,\r\n};\r\n\r\n// --- Scarcity Badge Rules ---\r\nexport const SCARCITY_THRESHOLDS = {\r\n SOLD_OUT: 0,\r\n URGENT: 0.1, // ≤10% remaining → urgent (\"Only X left\")\r\n LOW: 0.2, // ≤20% remaining (80%+ sold) → \"Selling fast\"\r\n MAX_EXACT_COUNT: 20, // Don't show exact count above 20\r\n} as const;\r\n\r\nexport function getScarcityLevel(\r\n remaining: number,\r\n total: number\r\n): ScarcityLevel {\r\n if (total === 0) return 'none';\r\n if (remaining <= 0) return 'sold_out';\r\n const pct = remaining / total;\r\n if (pct <= SCARCITY_THRESHOLDS.URGENT) return 'urgent';\r\n if (pct <= SCARCITY_THRESHOLDS.LOW) return 'low';\r\n return 'none';\r\n}\r\n\r\nexport function getScarcityText(\r\n level: ScarcityLevel,\r\n remaining: number,\r\n context: 'browse' | 'event' | 'ticket',\r\n options?: { isFree?: boolean }\r\n): string | null {\r\n if (level === 'none') return null;\r\n if (level === 'sold_out') return 'Sold out';\r\n // No scarcity badges on free events/tickets — nothing to lose = no urgency\r\n if (options?.isFree) return null;\r\n if (\r\n level === 'urgent' &&\r\n context !== 'browse' &&\r\n remaining <= SCARCITY_THRESHOLDS.MAX_EXACT_COUNT\r\n ) {\r\n return `Only ${remaining} left`;\r\n }\r\n if (level === 'low' || level === 'urgent') return 'Selling fast';\r\n return null;\r\n}\r\n\r\n// --- CTA Rules ---\r\n// Delegates to production computeCtaState() but adapts our EventData shape.\r\n// Components keep calling getCtaConfig(event) — internal logic is production-aligned.\r\nexport function getCtaConfig(event: EventData): CtaConfig {\r\n // Map our EventData tickets to the shape computeCtaState expects.\r\n // `isHidden` flows through so computeCtaState can apply the hidden-only\r\n // \"Sales ended\" → \"Get tickets\" override (MIC-1039).\r\n const apiTickets = event.tickets.map(t => ({\r\n salesBegin: t.salesStartDate,\r\n salesEnd: t.salesEndDate,\r\n remainingCapacity: t.quantityAvailable,\r\n totalCapacity: t.quantityTotal,\r\n soldOut: t.status === 'sold_out',\r\n salesChannel: 1, // All our tickets are online (not \"at the door only\")\r\n isHidden: t.isHidden,\r\n }));\r\n\r\n // Handle statuses that computeCtaState doesn't compute from tickets\r\n if (event.status === 'cancelled') {\r\n return {\r\n text: 'Cancelled',\r\n disabled: true,\r\n reason: 'This event has been cancelled',\r\n };\r\n }\r\n if (event.status === 'past') {\r\n return {\r\n text: 'Event ended',\r\n disabled: true,\r\n reason: 'This event has ended',\r\n };\r\n }\r\n\r\n const result = computeCtaState(\r\n { startDateTime: event.startDateTime, endDateTime: event.endDateTime },\r\n apiTickets,\r\n {\r\n cancelled: false,\r\n isRegistration: event.isRegistrationEvent,\r\n waitlistEnabled: false,\r\n }\r\n );\r\n\r\n return {\r\n text: result.text,\r\n disabled: result.disabled,\r\n reason: result.disabled ? toFriendlyReason(result.reason) : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * computeCtaState() returns machine-enum reasons ('event_past', 'sold_out',\r\n * 'coming_soon', etc) intended for branching, not display. The BookingWidget\r\n * and MobileCta render `reason` directly as supplementary copy below the\r\n * button text — which leaks raw enum strings to users.\r\n *\r\n * Map each enum to a friendly sentence, OR return undefined when the button\r\n * `text` already says everything (\"Sales ended\" / \"Sold out\" — no need for\r\n * a second line repeating it).\r\n */\r\nfunction toFriendlyReason(reason: string | undefined): string | undefined {\r\n if (!reason) return undefined;\r\n switch (reason) {\r\n case 'cancelled':\r\n return 'This event has been cancelled.';\r\n case 'event_past':\r\n return 'This event has already happened.';\r\n case 'no_tickets':\r\n return 'There are no tickets configured for this event.';\r\n case 'coming_soon':\r\n return undefined; // text already shows \"On sale <date>\"\r\n case 'sold_out':\r\n return undefined; // text already shows \"Sold out\"\r\n case 'sold_out_waitlist':\r\n return 'All tickets are claimed. Join the waitlist to be notified.';\r\n case 'sales_ended':\r\n return undefined; // text already shows \"Sales ended\"\r\n default:\r\n return undefined; // unknown enum — never leak it\r\n }\r\n}\r\n\r\n// --- Price Display Rules (from DECISIONS.md #1) ---\r\nexport function getPriceDisplay(event: EventData): string | null {\r\n const visibleTickets = event.tickets.filter(\r\n t => t.status === 'on_sale' && !t.isHidden\r\n );\r\n if (visibleTickets.length === 0) return null;\r\n\r\n const hasDonation = visibleTickets.some(\r\n t => t.isDonation || t.ticketType === 2\r\n );\r\n const paidTickets = visibleTickets.filter(\r\n t => !t.isDonation && t.ticketType !== 2\r\n );\r\n const hasFree = paidTickets.some(t => t.price === 0);\r\n const pricedTickets = paidTickets.filter(t => t.price > 0);\r\n\r\n // Only donation tickets → \"Donation\"\r\n if (pricedTickets.length === 0 && !hasFree && hasDonation) return 'Donation';\r\n\r\n // Only free tickets (no paid, no donation) → null (BookingWidget shows \"Free\" via isFreeEvent)\r\n if (pricedTickets.length === 0 && hasFree) return null;\r\n\r\n const minPrice = Math.min(...pricedTickets.map(t => t.price));\r\n\r\n // Free + paid → \"Free\" (free dominates the display)\r\n if (hasFree) return null;\r\n\r\n // Donation + paid → \"From $X\" (donation is an alternative option)\r\n if (hasDonation) return `From $${minPrice}`;\r\n\r\n // Single paid ticket type → \"$X\"\r\n if (pricedTickets.length === 1) return `$${minPrice}`;\r\n\r\n // Multiple paid ticket types → \"From $X\"\r\n return `From $${minPrice}`;\r\n}\r\n\r\n// --- Fee Calculation ---\r\nexport function calculateFee(\r\n price: number,\r\n feePercentage: number,\r\n feeCents: Cents\r\n): number {\r\n return roundCurrency(price * (feePercentage / 100) + feeCents / 100);\r\n}\r\n\r\nexport function calculateTax(amount: number, taxPercentage: number): number {\r\n return roundCurrency(amount * (taxPercentage / 100));\r\n}\r\n\r\n// --- Date Formatting ---\r\n// PREFERRED: Use the timezone-aware production formatters re-exported above:\r\n// formatBrowseDate(iso, tz) → \"Fri, Feb 20\"\r\n// formatFullDateCompact(iso, tz) → \"Friday, February 20\"\r\n// formatEventTime(iso, tz) → \"8:00 PM\"\r\n// formatTimeRange(start, end, tz) → \"8:00 PM - 10:00 PM\"\r\n// formatDoorsTime(doors, tz) → \"7:00 PM\"\r\n//\r\n// DEPRECATED: The functions below are backward-compatible wrappers for variants\r\n// not yet migrated to timezone-aware formatters. They use browser-local timezone.\r\n// Migrate to the production formatters above when updating each variant.\r\n\r\n/** @deprecated Use formatBrowseDate(dateStr, timezone) instead */\r\nexport function formatDate(dateStr: string): string {\r\n return scFormatDate(dateStr, { weekday: 'short', year: undefined });\r\n}\r\n\r\n/** @deprecated Use formatEventTime(dateStr, timezone) instead */\r\nexport function formatTime(dateStr: string): string {\r\n return scFormatTime(dateStr);\r\n}\r\n\r\n/** @deprecated Use formatBrowseDate + formatTimeRange instead */\r\nexport function formatDateRange(start: string, end: string): string {\r\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;\r\n return `${formatBrowseDate(start, tz)} · ${formatTimeRange(start, end, tz)}`;\r\n}\r\n\r\n// --- Animation Durations ---\r\nexport const DURATION = {\r\n instant: 100,\r\n micro: 150,\r\n fast: 200,\r\n normal: 300,\r\n slow: 400,\r\n elaborate: 600,\r\n} as const;\r\n\r\n// --- Smart Sales Date Formatting ---\r\n// Ported from production TicketBlock.svelte — smart thresholds for human-readable dates\r\nexport function formatSmartSalesDate(dateStr: string): string {\r\n if (!dateStr) return '';\r\n const date = new Date(dateStr);\r\n const now = new Date();\r\n const diffMs = date.getTime() - now.getTime();\r\n const diffMinutes = Math.round(diffMs / (1000 * 60));\r\n const diffHours = diffMs / (1000 * 60 * 60);\r\n\r\n // < 1 hour: \"in X minutes\"\r\n if (diffMinutes > 0 && diffMinutes < 60) {\r\n const mins = Math.max(1, diffMinutes);\r\n return `in ${mins} minute${mins !== 1 ? 's' : ''}`;\r\n }\r\n\r\n // 1-24 hours: \"in X hours\"\r\n if (diffHours > 0 && diffHours < 24) {\r\n const hours = Math.max(1, Math.round(diffHours));\r\n return `in ${hours} hour${hours !== 1 ? 's' : ''}`;\r\n }\r\n\r\n // Tomorrow: \"tomorrow at X PM\"\r\n const tomorrow = new Date(now);\r\n tomorrow.setDate(tomorrow.getDate() + 1);\r\n if (date.toDateString() === tomorrow.toDateString()) {\r\n const timeStr = scFormatTime(\r\n date,\r\n { hour: 'numeric', minute: '2-digit' },\r\n 'en-US'\r\n );\r\n return `tomorrow at ${timeStr}`;\r\n }\r\n\r\n // 2-7 days: \"on Friday at X PM\"\r\n const diffDays = diffMs / (1000 * 60 * 60 * 24);\r\n if (diffDays > 0 && diffDays <= 7) {\r\n const dayName = new Intl.DateTimeFormat('en-US', {\r\n weekday: 'long',\r\n }).format(date);\r\n const timeStr = scFormatTime(\r\n date,\r\n { hour: 'numeric', minute: '2-digit' },\r\n 'en-US'\r\n );\r\n return `on ${dayName} at ${timeStr}`;\r\n }\r\n\r\n // > 7 days: \"on Mar 15\"\r\n const dateFormatted = new Intl.DateTimeFormat('en-US', {\r\n month: 'short',\r\n day: 'numeric',\r\n }).format(date);\r\n return `on ${dateFormatted}`;\r\n}\r\n\r\n// --- Promo Code State Factory ---\r\nexport function createDefaultPromoState(): PromoCodeState {\r\n return {\r\n code: '',\r\n isApplied: false,\r\n isValidating: false,\r\n error: '',\r\n hint: '',\r\n discountAmount: 0,\r\n discountType: '',\r\n discountTicketIds: [],\r\n revealHiddenTickets: false,\r\n revealTicketIds: [],\r\n };\r\n}\r\n\r\n// --- Ticket helpers ---\r\nexport function getAvailableTickets(\r\n tickets: TicketTypeData[]\r\n): TicketTypeData[] {\r\n return tickets.filter(t => !t.isHidden && t.status === 'on_sale');\r\n}\r\n","<script lang=\"ts\">\r\n\timport type { USD } from '@getmicdrop/svelte-components';\r\n\timport { Text, formatCurrency } from '@getmicdrop/svelte-components';\r\n\timport type { OrderTotals } from '$lib/public-calendar-flow/types';\r\n\timport { DURATION } from '$lib/public-calendar-flow/defaults';\r\n\r\n\tinterface Props {\r\n\t\torderTotals: OrderTotals;\r\n\t\tlabels?: Record<string, string>;\r\n\t\t/**\r\n\t\t * Which section to render.\r\n\t\t * - `full` (default): ticket lines + totals stacked together.\r\n\t\t * - `lines` : ticket-line items only. Use when the parent scrolls\r\n\t\t * this section in a flex column.\r\n\t\t * - `totals` : subtotal/fees/taxes/promo/total only. Use in a fixed\r\n\t\t * footer alongside the action button.\r\n\t\t *\r\n\t\t * Splitting via `lines` / `totals` lets the sticky sidebars scroll\r\n\t\t * just the variable-length ticket list while keeping the summary\r\n\t\t * block and CTA always visible.\r\n\t\t */\r\n\t\tmode?: 'full' | 'lines' | 'totals';\r\n\t}\r\n\r\n\tlet { orderTotals, labels = {}, mode = 'full' }: Props = $props();\r\n</script>\r\n\r\n<div\r\n\tclass=\"space-y-2\"\r\n\tstyle=\"transition-duration: {DURATION.normal}ms;\"\r\n>\r\n\t{#if mode !== 'totals'}\r\n\t\t<!-- Line items -->\r\n\t\t{#each orderTotals.lines as line (line.ticketId)}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\">{line.quantity}x {line.ticketName}</Text>\r\n\t\t\t\t<Text size=\"sm\">{formatCurrency(line.subtotal as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/each}\r\n\t{/if}\r\n\r\n\t{#if mode !== 'lines'}\r\n\t\t<!-- Subtotal. In `totals` mode the parent supplies the separator above\r\n\t\t this block (BookingWidget wraps the totals block in border-t); a\r\n\t\t second internal border would render as a double line. Only show\r\n\t\t the internal border-t in `full` mode where lines + totals stack\r\n\t\t in one container with no external separator. -->\r\n\t\t{#if mode === 'full' && orderTotals.lines.length > 1}\r\n\t\t\t<div class=\"flex justify-between pt-1 border-t border-default\">\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{labels.subtotal || 'Subtotal'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{formatCurrency(orderTotals.subtotal as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{:else if orderTotals.lines.length > 1}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{labels.subtotal || 'Subtotal'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{formatCurrency(orderTotals.subtotal as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Fees -->\r\n\t\t{#if orderTotals.fees > 0}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{labels.serviceFees || 'Service fees'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{formatCurrency(orderTotals.fees as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Taxes -->\r\n\t\t{#if orderTotals.taxes > 0}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{labels.taxes || 'Taxes'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{formatCurrency(orderTotals.taxes as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Promo discount -->\r\n\t\t{#if orderTotals.promoDiscount > 0}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"success\">{labels.promoDiscount || 'Promo discount'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"success\">-{formatCurrency(orderTotals.promoDiscount as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Gift card — deduction from the amount due; `total` already reflects it -->\r\n\t\t{#if orderTotals.giftCardAmount > 0}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"success\">{labels.giftCard || 'Gift card'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"success\">-{formatCurrency(orderTotals.giftCardAmount as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Total -->\r\n\t\t<div class=\"flex justify-between pt-2 border-t border-default\">\r\n\t\t\t<Text size=\"base\" class=\"font-semibold\">{labels.total || 'Total'}</Text>\r\n\t\t\t<Text size=\"base\" class=\"font-semibold\">{formatCurrency(orderTotals.total as USD)}</Text>\r\n\t\t</div>\r\n\t{/if}\r\n</div>\r\n"],"names":["isHiddenTicketPurchasable","ticket","now","salesBegin","salesEnd","remaining","computeCtaState","event","tickets","options","cancelled","isRegistration","waitlistEnabled","eventEnd","hiddenAvailable","publicTickets","t","hasPurchasable","allSoldOut","allComingSoon","earliestSalesStart","isSoldOut","isScheduled","hasSalesEnded","startDate","diffMs","diffHours","diffDays","dateText","formatTime","formatDateRaw","d","SCARCITY_THRESHOLDS","getScarcityLevel","total","pct","getScarcityText","level","context","getCtaConfig","apiTickets","result","toFriendlyReason","reason","getPriceDisplay","visibleTickets","hasDonation","paidTickets","hasFree","pricedTickets","minPrice","calculateTax","amount","taxPercentage","roundCurrency","DURATION","formatSmartSalesDate","dateStr","date","diffMinutes","mins","hours","tomorrow","scFormatTime","dayName","timeStr","createDefaultPromoState","labels","$","$$props","mode","div","root","node_1","line","div_1","root_2","Text","node_2","text","node_3","formatCurrency","$$render","consequent","div_2","root_6","node_6","node_7","$0","text_3","div_3","root_9","node_8","node_9","text_5","consequent_1","consequent_2","div_4","root_12","node_11","node_12","text_7","consequent_3","div_5","root_15","node_14","node_15","text_9","consequent_4","div_6","root_18","node_17","node_18","text_11","consequent_5","div_7","root_21","node_20","node_21","text_13","consequent_6","div_8","node_19","node_22","node_23","text_15","consequent_7"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OrderSummary-B1GhsUnc.js","sources":["../src/lib/api/cta.ts","../src/lib/public-calendar-flow/defaults.ts","../src/lib/public-calendar-flow/OrderSummary.svelte"],"sourcesContent":["/**\r\n * CTA state computation.\r\n *\r\n * Pure function (no I/O) — derives the buy-button state from an event and\r\n * its ticket list. Lives in `api/` because it is the canonical, single\r\n * source of truth that replaces the duplicate implementations previously\r\n * scattered across utils/api.js, core/api-client.js, and a few components.\r\n */\r\n\r\n// Import from the specific subpath (not the bare entry) so the api/\r\n// bundle doesn't pull in the entire SC component graph (Accordion etc.)\r\n// and break `npm run build:api`.\r\nimport {\r\n formatDateRaw,\r\n formatTime,\r\n} from '@getmicdrop/svelte-components/utils/formatters';\r\n\r\nexport interface CtaStateOptions {\r\n cancelled?: boolean;\r\n isRegistration?: boolean;\r\n waitlistEnabled?: boolean;\r\n}\r\n\r\nexport interface CtaState {\r\n text: string;\r\n disabled: boolean;\r\n reason:\r\n | 'cancelled'\r\n | 'event_past'\r\n | 'no_tickets'\r\n | 'available'\r\n | 'coming_soon'\r\n | 'sold_out_waitlist'\r\n | 'sold_out'\r\n | 'sales_ended'\r\n | 'hidden_only';\r\n}\r\n\r\ninterface CtaEvent {\r\n startDateTime?: string | null;\r\n endDateTime?: string | null;\r\n hasPurchasableHiddenTickets?: boolean;\r\n}\r\n\r\ninterface CtaTicket {\r\n salesChannel?: number;\r\n salesBegin?: string | null;\r\n salesStart?: string | null;\r\n saleBegin?: string | null;\r\n onSaleStart?: string | null;\r\n salesEnd?: string | null;\r\n saleEnd?: string | null;\r\n onSaleEnd?: string | null;\r\n remainingCapacity?: number | null;\r\n quantityRemaining?: number | null;\r\n quantity?: number | null;\r\n soldOut?: boolean;\r\n isHidden?: boolean;\r\n visibility?: number;\r\n}\r\n\r\n// A hidden ticket (visibility>=2 or isHidden) that's still on sale drives the\r\n// \"Sales ended\" / \"Sold out\" / \"No tickets\" → \"Get tickets\" override. The user\r\n// just needs the promo code to see it.\r\nexport function isHiddenTicketPurchasable(ticket: CtaTicket): boolean {\r\n if (!ticket) return false;\r\n const isHidden =\r\n ticket.isHidden === true ||\r\n (typeof ticket.visibility === 'number' && ticket.visibility >= 2);\r\n if (!isHidden) return false;\r\n if (ticket.salesChannel === 2) return false;\r\n\r\n const now = new Date();\r\n const salesBegin =\r\n ticket.salesBegin ||\r\n ticket.salesStart ||\r\n ticket.saleBegin ||\r\n ticket.onSaleStart;\r\n const salesEnd = ticket.salesEnd || ticket.saleEnd || ticket.onSaleEnd;\r\n if (salesBegin && new Date(salesBegin) > now) return false;\r\n if (salesEnd && new Date(salesEnd) < now) return false;\r\n\r\n const remaining =\r\n ticket.remainingCapacity ?? ticket.quantityRemaining ?? ticket.quantity;\r\n const isSoldOut =\r\n ticket.soldOut ||\r\n (remaining !== null && remaining !== undefined && remaining <= 0);\r\n if (isSoldOut) return false;\r\n\r\n return true;\r\n}\r\n\r\nexport function computeCtaState(\r\n event: CtaEvent,\r\n tickets: CtaTicket[] | undefined,\r\n options: CtaStateOptions = {}\r\n): CtaState {\r\n const {\r\n cancelled = false,\r\n isRegistration = false,\r\n waitlistEnabled = false,\r\n } = options;\r\n const now = new Date();\r\n\r\n if (cancelled)\r\n return { text: 'Cancelled', disabled: true, reason: 'cancelled' };\r\n\r\n const eventEnd = event.endDateTime || event.startDateTime;\r\n if (eventEnd && new Date(eventEnd) < now) {\r\n return { text: 'Sales ended', disabled: true, reason: 'event_past' };\r\n }\r\n\r\n const hiddenAvailable =\r\n event?.hasPurchasableHiddenTickets === true ||\r\n (Array.isArray(tickets) && tickets.some(isHiddenTicketPurchasable));\r\n\r\n const publicTickets = (tickets || []).filter(\r\n t =>\r\n t.salesChannel !== 2 &&\r\n !t.isHidden &&\r\n !(typeof t.visibility === 'number' && t.visibility >= 2)\r\n );\r\n if (publicTickets.length === 0) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n return {\r\n text: 'No tickets available',\r\n disabled: true,\r\n reason: 'no_tickets',\r\n };\r\n }\r\n\r\n let hasPurchasable = false;\r\n let allSoldOut = true;\r\n let allComingSoon = true;\r\n let earliestSalesStart: Date | null = null;\r\n\r\n for (const ticket of publicTickets) {\r\n const salesBegin =\r\n ticket.salesBegin ||\r\n ticket.salesStart ||\r\n ticket.saleBegin ||\r\n ticket.onSaleStart;\r\n const salesEnd = ticket.salesEnd || ticket.saleEnd || ticket.onSaleEnd;\r\n const remaining =\r\n ticket.remainingCapacity ?? ticket.quantityRemaining ?? ticket.quantity;\r\n const isSoldOut =\r\n ticket.soldOut ||\r\n (remaining !== null && remaining !== undefined && remaining <= 0);\r\n\r\n const isScheduled = salesBegin ? new Date(salesBegin) > now : false;\r\n const hasSalesEnded = salesEnd ? new Date(salesEnd) < now : false;\r\n const isPurchasable = !isSoldOut && !isScheduled && !hasSalesEnded;\r\n\r\n if (isPurchasable) hasPurchasable = true;\r\n if (!isSoldOut) allSoldOut = false;\r\n if (!isScheduled) allComingSoon = false;\r\n\r\n if (isScheduled && salesBegin && !isSoldOut && !hasSalesEnded) {\r\n const startDate = new Date(salesBegin);\r\n if (!earliestSalesStart || startDate < earliestSalesStart) {\r\n earliestSalesStart = startDate;\r\n }\r\n }\r\n }\r\n\r\n if (hasPurchasable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'available',\r\n };\r\n }\r\n\r\n if (allComingSoon && earliestSalesStart) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n const diffMs = earliestSalesStart.getTime() - now.getTime();\r\n const diffHours = diffMs / (1000 * 60 * 60);\r\n const diffDays = diffMs / (1000 * 60 * 60 * 24);\r\n let dateText: string;\r\n if (diffHours < 24) {\r\n dateText = formatTime(earliestSalesStart, { hour12: true }, 'en-US');\r\n } else if (diffDays <= 7) {\r\n dateText = formatDateRaw(\r\n earliestSalesStart,\r\n { weekday: 'short', hour: 'numeric', minute: '2-digit', hour12: true },\r\n 'en-US'\r\n );\r\n } else {\r\n const d = formatDateRaw(\r\n earliestSalesStart,\r\n { month: 'short', day: 'numeric' },\r\n 'en-US'\r\n );\r\n const t = formatTime(earliestSalesStart, { hour12: true }, 'en-US');\r\n dateText = `${d} ${t}`;\r\n }\r\n return {\r\n text: `On sale ${dateText}`,\r\n disabled: true,\r\n reason: 'coming_soon',\r\n };\r\n }\r\n\r\n if (allSoldOut) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n if (waitlistEnabled) {\r\n return {\r\n text: 'Join Waitlist',\r\n disabled: false,\r\n reason: 'sold_out_waitlist',\r\n };\r\n }\r\n return { text: 'Sold out', disabled: true, reason: 'sold_out' };\r\n }\r\n\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n\r\n return { text: 'Sales ended', disabled: true, reason: 'sales_ended' };\r\n}\r\n","// @currency-escape: feeCents / 100 in calculateServiceFee is arithmetic,\r\n// not display. Produces a dollar-magnitude number used in the fee formula\r\n// `price * (feePercentage / 100) + feeCents / 100`. Per Atlas\r\n// utility-currency convergence record; the no-handrolled-currency\r\n// ESLint rule's divideByHundred detector treats variable-name `Cents`\r\n// as drift but here it's real math.\r\n\r\n// Premium Ticket Experience — Constants & Defaults\r\n// Used by all design variants. DO NOT MODIFY per-variant.\r\n\r\n// @raw-intl-datetimeformat-escape: formatSmartSalesDate is a date-formatter\r\n// implementation (smart relative-date thresholds → \"on Friday at 8 PM\" / \"on Mar 15\").\r\n// The weekday-long (\"Friday\") and month-short+day (\"Mar 15\") fragments are interpolated\r\n// into smart-threshold strings; SC formatDate/DATE_FORMATS has no preset that emits a\r\n// bare weekday or a bare month+day, so it cannot reproduce these byte-identical fragments.\r\n// This file is the canonical formatter module for public-calendar-flow (it wraps + re-exports\r\n// scFormatDate/scFormatTime), not a call site.\r\n\r\nimport type {\r\n EventData,\r\n TicketTypeData,\r\n ScarcityLevel,\r\n CtaConfig,\r\n PromoCodeState,\r\n} from './types';\r\nimport { computeCtaState } from '$lib/api';\r\nimport type { Cents } from '@getmicdrop/svelte-components';\r\nimport {\r\n formatDate as scFormatDate,\r\n formatTime as scFormatTime,\r\n roundCurrency,\r\n} from '@getmicdrop/svelte-components';\r\nimport {\r\n formatFullDate,\r\n formatFullDateCompact,\r\n formatEventTime,\r\n formatTimeRange,\r\n formatDoorsTime,\r\n formatSalesDate,\r\n formatBrowseDate,\r\n formatEventDate,\r\n formatCleanTimeRange,\r\n getDateParts,\r\n} from '$lib/utils/datetime.js';\r\n\r\n// --- Re-export production date/time formatters (timezone-aware) ---\r\nexport {\r\n formatFullDate,\r\n formatFullDateCompact,\r\n formatEventTime,\r\n formatTimeRange,\r\n formatDoorsTime,\r\n formatSalesDate,\r\n formatBrowseDate,\r\n formatEventDate,\r\n formatCleanTimeRange,\r\n getDateParts,\r\n};\r\n\r\n// --- Scarcity Badge Rules ---\r\nexport const SCARCITY_THRESHOLDS = {\r\n SOLD_OUT: 0,\r\n URGENT: 0.1, // ≤10% remaining → urgent (\"Only X left\")\r\n LOW: 0.2, // ≤20% remaining (80%+ sold) → \"Selling fast\"\r\n MAX_EXACT_COUNT: 20, // Don't show exact count above 20\r\n} as const;\r\n\r\nexport function getScarcityLevel(\r\n remaining: number,\r\n total: number\r\n): ScarcityLevel {\r\n if (total === 0) return 'none';\r\n if (remaining <= 0) return 'sold_out';\r\n const pct = remaining / total;\r\n if (pct <= SCARCITY_THRESHOLDS.URGENT) return 'urgent';\r\n if (pct <= SCARCITY_THRESHOLDS.LOW) return 'low';\r\n return 'none';\r\n}\r\n\r\nexport function getScarcityText(\r\n level: ScarcityLevel,\r\n remaining: number,\r\n context: 'browse' | 'event' | 'ticket',\r\n options?: { isFree?: boolean }\r\n): string | null {\r\n if (level === 'none') return null;\r\n if (level === 'sold_out') return 'Sold out';\r\n // No scarcity badges on free events/tickets — nothing to lose = no urgency\r\n if (options?.isFree) return null;\r\n if (\r\n level === 'urgent' &&\r\n context !== 'browse' &&\r\n remaining <= SCARCITY_THRESHOLDS.MAX_EXACT_COUNT\r\n ) {\r\n return `Only ${remaining} left`;\r\n }\r\n if (level === 'low' || level === 'urgent') return 'Selling fast';\r\n return null;\r\n}\r\n\r\n// --- CTA Rules ---\r\n// Delegates to production computeCtaState() but adapts our EventData shape.\r\n// Components keep calling getCtaConfig(event) — internal logic is production-aligned.\r\nexport function getCtaConfig(event: EventData): CtaConfig {\r\n // Map our EventData tickets to the shape computeCtaState expects.\r\n // `isHidden` flows through so computeCtaState can apply the hidden-only\r\n // \"Sales ended\" → \"Get tickets\" override (MIC-1039).\r\n const apiTickets = event.tickets.map(t => ({\r\n salesBegin: t.salesStartDate,\r\n salesEnd: t.salesEndDate,\r\n remainingCapacity: t.quantityAvailable,\r\n totalCapacity: t.quantityTotal,\r\n soldOut: t.status === 'sold_out',\r\n salesChannel: 1, // All our tickets are online (not \"at the door only\")\r\n isHidden: t.isHidden,\r\n }));\r\n\r\n // Handle statuses that computeCtaState doesn't compute from tickets\r\n if (event.status === 'cancelled') {\r\n return {\r\n text: 'Cancelled',\r\n disabled: true,\r\n reason: 'This event has been cancelled',\r\n };\r\n }\r\n if (event.status === 'past') {\r\n return {\r\n text: 'Event ended',\r\n disabled: true,\r\n reason: 'This event has ended',\r\n };\r\n }\r\n\r\n const result = computeCtaState(\r\n { startDateTime: event.startDateTime, endDateTime: event.endDateTime },\r\n apiTickets,\r\n {\r\n cancelled: false,\r\n isRegistration: event.isRegistrationEvent,\r\n waitlistEnabled: false,\r\n }\r\n );\r\n\r\n return {\r\n text: result.text,\r\n disabled: result.disabled,\r\n reason: result.disabled ? toFriendlyReason(result.reason) : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * computeCtaState() returns machine-enum reasons ('event_past', 'sold_out',\r\n * 'coming_soon', etc) intended for branching, not display. The BookingWidget\r\n * and MobileCta render `reason` directly as supplementary copy below the\r\n * button text — which leaks raw enum strings to users.\r\n *\r\n * Map each enum to a friendly sentence, OR return undefined when the button\r\n * `text` already says everything (\"Sales ended\" / \"Sold out\" — no need for\r\n * a second line repeating it).\r\n */\r\nfunction toFriendlyReason(reason: string | undefined): string | undefined {\r\n if (!reason) return undefined;\r\n switch (reason) {\r\n case 'cancelled':\r\n return 'This event has been cancelled.';\r\n case 'event_past':\r\n return 'This event has already happened.';\r\n case 'no_tickets':\r\n return 'There are no tickets configured for this event.';\r\n case 'coming_soon':\r\n return undefined; // text already shows \"On sale <date>\"\r\n case 'sold_out':\r\n return undefined; // text already shows \"Sold out\"\r\n case 'sold_out_waitlist':\r\n return 'All tickets are claimed. Join the waitlist to be notified.';\r\n case 'sales_ended':\r\n return undefined; // text already shows \"Sales ended\"\r\n default:\r\n return undefined; // unknown enum — never leak it\r\n }\r\n}\r\n\r\n// --- Price Display Rules (from DECISIONS.md #1) ---\r\nexport function getPriceDisplay(event: EventData): string | null {\r\n const visibleTickets = event.tickets.filter(\r\n t => t.status === 'on_sale' && !t.isHidden\r\n );\r\n if (visibleTickets.length === 0) return null;\r\n\r\n const hasDonation = visibleTickets.some(\r\n t => t.isDonation || t.ticketType === 2\r\n );\r\n const paidTickets = visibleTickets.filter(\r\n t => !t.isDonation && t.ticketType !== 2\r\n );\r\n const hasFree = paidTickets.some(t => t.price === 0);\r\n const pricedTickets = paidTickets.filter(t => t.price > 0);\r\n\r\n // Only donation tickets → \"Donation\"\r\n if (pricedTickets.length === 0 && !hasFree && hasDonation) return 'Donation';\r\n\r\n // Only free tickets (no paid, no donation) → null (BookingWidget shows \"Free\" via isFreeEvent)\r\n if (pricedTickets.length === 0 && hasFree) return null;\r\n\r\n const minPrice = Math.min(...pricedTickets.map(t => t.price));\r\n\r\n // Free + paid → \"Free\" (free dominates the display)\r\n if (hasFree) return null;\r\n\r\n // Donation + paid → \"From $X\" (donation is an alternative option)\r\n if (hasDonation) return `From $${minPrice}`;\r\n\r\n // Single paid ticket type → \"$X\"\r\n if (pricedTickets.length === 1) return `$${minPrice}`;\r\n\r\n // Multiple paid ticket types → \"From $X\"\r\n return `From $${minPrice}`;\r\n}\r\n\r\n// --- Fee Calculation ---\r\nexport function calculateFee(\r\n price: number,\r\n feePercentage: number,\r\n feeCents: Cents\r\n): number {\r\n return roundCurrency(price * (feePercentage / 100) + feeCents / 100);\r\n}\r\n\r\nexport function calculateTax(amount: number, taxPercentage: number): number {\r\n return roundCurrency(amount * (taxPercentage / 100));\r\n}\r\n\r\n// --- Date Formatting ---\r\n// PREFERRED: Use the timezone-aware production formatters re-exported above:\r\n// formatBrowseDate(iso, tz) → \"Fri, Feb 20\"\r\n// formatFullDateCompact(iso, tz) → \"Friday, February 20\"\r\n// formatEventTime(iso, tz) → \"8:00 PM\"\r\n// formatTimeRange(start, end, tz) → \"8:00 PM - 10:00 PM\"\r\n// formatDoorsTime(doors, tz) → \"7:00 PM\"\r\n//\r\n// DEPRECATED: The functions below are backward-compatible wrappers for variants\r\n// not yet migrated to timezone-aware formatters. They use browser-local timezone.\r\n// Migrate to the production formatters above when updating each variant.\r\n\r\n/** @deprecated Use formatBrowseDate(dateStr, timezone) instead */\r\nexport function formatDate(dateStr: string): string {\r\n return scFormatDate(dateStr, { weekday: 'short', year: undefined });\r\n}\r\n\r\n/** @deprecated Use formatEventTime(dateStr, timezone) instead */\r\nexport function formatTime(dateStr: string): string {\r\n return scFormatTime(dateStr);\r\n}\r\n\r\n/** @deprecated Use formatBrowseDate + formatTimeRange instead */\r\nexport function formatDateRange(start: string, end: string): string {\r\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;\r\n return `${formatBrowseDate(start, tz)} · ${formatTimeRange(start, end, tz)}`;\r\n}\r\n\r\n// --- Animation Durations ---\r\nexport const DURATION = {\r\n instant: 100,\r\n micro: 150,\r\n fast: 200,\r\n normal: 300,\r\n slow: 400,\r\n elaborate: 600,\r\n} as const;\r\n\r\n// --- Smart Sales Date Formatting ---\r\n// Ported from production TicketBlock.svelte — smart thresholds for human-readable dates\r\nexport function formatSmartSalesDate(dateStr: string): string {\r\n if (!dateStr) return '';\r\n const date = new Date(dateStr);\r\n const now = new Date();\r\n const diffMs = date.getTime() - now.getTime();\r\n const diffMinutes = Math.round(diffMs / (1000 * 60));\r\n const diffHours = diffMs / (1000 * 60 * 60);\r\n\r\n // < 1 hour: \"in X minutes\"\r\n if (diffMinutes > 0 && diffMinutes < 60) {\r\n const mins = Math.max(1, diffMinutes);\r\n return `in ${mins} minute${mins !== 1 ? 's' : ''}`;\r\n }\r\n\r\n // 1-24 hours: \"in X hours\"\r\n if (diffHours > 0 && diffHours < 24) {\r\n const hours = Math.max(1, Math.round(diffHours));\r\n return `in ${hours} hour${hours !== 1 ? 's' : ''}`;\r\n }\r\n\r\n // Tomorrow: \"tomorrow at X PM\"\r\n const tomorrow = new Date(now);\r\n tomorrow.setDate(tomorrow.getDate() + 1);\r\n if (date.toDateString() === tomorrow.toDateString()) {\r\n const timeStr = scFormatTime(\r\n date,\r\n { hour: 'numeric', minute: '2-digit' },\r\n 'en-US'\r\n );\r\n return `tomorrow at ${timeStr}`;\r\n }\r\n\r\n // 2-7 days: \"on Friday at X PM\"\r\n const diffDays = diffMs / (1000 * 60 * 60 * 24);\r\n if (diffDays > 0 && diffDays <= 7) {\r\n const dayName = new Intl.DateTimeFormat('en-US', {\r\n weekday: 'long',\r\n }).format(date);\r\n const timeStr = scFormatTime(\r\n date,\r\n { hour: 'numeric', minute: '2-digit' },\r\n 'en-US'\r\n );\r\n return `on ${dayName} at ${timeStr}`;\r\n }\r\n\r\n // > 7 days: \"on Mar 15\"\r\n const dateFormatted = new Intl.DateTimeFormat('en-US', {\r\n month: 'short',\r\n day: 'numeric',\r\n }).format(date);\r\n return `on ${dateFormatted}`;\r\n}\r\n\r\n// --- Promo Code State Factory ---\r\nexport function createDefaultPromoState(): PromoCodeState {\r\n return {\r\n code: '',\r\n isApplied: false,\r\n isValidating: false,\r\n error: '',\r\n hint: '',\r\n discountAmount: 0,\r\n discountType: '',\r\n discountTicketIds: [],\r\n revealHiddenTickets: false,\r\n revealTicketIds: [],\r\n };\r\n}\r\n\r\n// --- Ticket helpers ---\r\nexport function getAvailableTickets(\r\n tickets: TicketTypeData[]\r\n): TicketTypeData[] {\r\n return tickets.filter(t => !t.isHidden && t.status === 'on_sale');\r\n}\r\n","<script lang=\"ts\">\r\n\timport type { USD } from '@getmicdrop/svelte-components';\r\n\timport { Text, formatCurrency } from '@getmicdrop/svelte-components';\r\n\timport type { OrderTotals } from '$lib/public-calendar-flow/types';\r\n\timport { DURATION } from '$lib/public-calendar-flow/defaults';\r\n\r\n\tinterface Props {\r\n\t\torderTotals: OrderTotals;\r\n\t\tlabels?: Record<string, string>;\r\n\t\t/**\r\n\t\t * Which section to render.\r\n\t\t * - `full` (default): ticket lines + totals stacked together.\r\n\t\t * - `lines` : ticket-line items only. Use when the parent scrolls\r\n\t\t * this section in a flex column.\r\n\t\t * - `totals` : subtotal/fees/taxes/promo/total only. Use in a fixed\r\n\t\t * footer alongside the action button.\r\n\t\t *\r\n\t\t * Splitting via `lines` / `totals` lets the sticky sidebars scroll\r\n\t\t * just the variable-length ticket list while keeping the summary\r\n\t\t * block and CTA always visible.\r\n\t\t */\r\n\t\tmode?: 'full' | 'lines' | 'totals';\r\n\t}\r\n\r\n\tlet { orderTotals, labels = {}, mode = 'full' }: Props = $props();\r\n</script>\r\n\r\n<div\r\n\tclass=\"space-y-2\"\r\n\tstyle=\"transition-duration: {DURATION.normal}ms;\"\r\n>\r\n\t{#if mode !== 'totals'}\r\n\t\t<!-- Line items -->\r\n\t\t{#each orderTotals.lines as line (line.ticketId)}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\">{line.quantity}x {line.ticketName}</Text>\r\n\t\t\t\t<Text size=\"sm\">{formatCurrency(line.subtotal as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/each}\r\n\t{/if}\r\n\r\n\t{#if mode !== 'lines'}\r\n\t\t<!-- Subtotal. In `totals` mode the parent supplies the separator above\r\n\t\t this block (BookingWidget wraps the totals block in border-t); a\r\n\t\t second internal border would render as a double line. Only show\r\n\t\t the internal border-t in `full` mode where lines + totals stack\r\n\t\t in one container with no external separator. -->\r\n\t\t{#if mode === 'full' && orderTotals.lines.length > 1}\r\n\t\t\t<div class=\"flex justify-between pt-1 border-t border-default\">\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{labels.subtotal || 'Subtotal'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{formatCurrency(orderTotals.subtotal as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{:else if orderTotals.lines.length > 1}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{labels.subtotal || 'Subtotal'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{formatCurrency(orderTotals.subtotal as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Fees -->\r\n\t\t{#if orderTotals.fees > 0}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{labels.serviceFees || 'Service fees'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{formatCurrency(orderTotals.fees as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Taxes -->\r\n\t\t{#if orderTotals.taxes > 0}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{labels.taxes || 'Taxes'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"muted\">{formatCurrency(orderTotals.taxes as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Promo discount -->\r\n\t\t{#if orderTotals.promoDiscount > 0}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"success\">{labels.promoDiscount || 'Promo discount'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"success\">-{formatCurrency(orderTotals.promoDiscount as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Gift card — deduction from the amount due; `total` already reflects it -->\r\n\t\t{#if orderTotals.giftCardAmount > 0}\r\n\t\t\t<div class=\"flex justify-between\">\r\n\t\t\t\t<Text size=\"sm\" color=\"success\">{labels.giftCard || 'Gift card'}</Text>\r\n\t\t\t\t<Text size=\"sm\" color=\"success\">-{formatCurrency(orderTotals.giftCardAmount as USD)}</Text>\r\n\t\t\t</div>\r\n\t\t{/if}\r\n\r\n\t\t<!-- Total -->\r\n\t\t<div class=\"flex justify-between pt-2 border-t border-default\">\r\n\t\t\t<Text size=\"base\" class=\"font-semibold\">{labels.total || 'Total'}</Text>\r\n\t\t\t<Text size=\"base\" class=\"font-semibold\">{formatCurrency(orderTotals.total as USD)}</Text>\r\n\t\t</div>\r\n\t{/if}\r\n</div>\r\n"],"names":["isHiddenTicketPurchasable","ticket","now","salesBegin","salesEnd","remaining","computeCtaState","event","tickets","options","cancelled","isRegistration","waitlistEnabled","eventEnd","hiddenAvailable","publicTickets","t","hasPurchasable","allSoldOut","allComingSoon","earliestSalesStart","isSoldOut","isScheduled","hasSalesEnded","startDate","diffMs","diffHours","diffDays","dateText","formatTime","formatDateRaw","d","SCARCITY_THRESHOLDS","getScarcityLevel","total","pct","getScarcityText","level","context","getCtaConfig","apiTickets","result","toFriendlyReason","reason","getPriceDisplay","visibleTickets","hasDonation","paidTickets","hasFree","pricedTickets","minPrice","calculateTax","amount","taxPercentage","roundCurrency","DURATION","formatSmartSalesDate","dateStr","date","diffMinutes","mins","hours","tomorrow","scFormatTime","dayName","timeStr","createDefaultPromoState","labels","$","$$props","mode","div","root","node_1","line","div_1","root_2","Text","node_2","text","node_3","formatCurrency","$$render","consequent","div_2","root_6","node_6","node_7","$0","text_3","div_3","root_9","node_8","node_9","text_5","consequent_1","consequent_2","div_4","root_12","node_11","node_12","text_7","consequent_3","div_5","root_15","node_14","node_15","text_9","consequent_4","div_6","root_18","node_17","node_18","text_11","consequent_5","div_7","root_21","node_20","node_21","text_13","consequent_6","div_8","node_19","node_22","node_23","text_15","consequent_7"],"mappings":"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"}
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
import "svelte/internal/disclose-version";
|
|
2
2
|
import * as e from "svelte/internal/client";
|
|
3
|
-
import { g as Q,
|
|
3
|
+
import { g as Q, aK as j, ae as ke, ad as te, B as R, ab as ye, ac as be, h as J } from "./VenueCalendar-BoSdP7xI.js";
|
|
4
4
|
import { H as Pe } from "./Heading-AFd3o0xt.js";
|
|
5
5
|
import { T as $ } from "./Text-CXR2fhx6.js";
|
|
6
6
|
import "svelte/transition";
|
|
7
7
|
import "svelte/easing";
|
|
8
|
-
import { g as Se, b as qe, f as De, D as ae } from "./OrderSummary-
|
|
8
|
+
import { g as Se, b as qe, f as De, D as ae } from "./OrderSummary-B1GhsUnc.js";
|
|
9
9
|
function ee(w = "light") {
|
|
10
10
|
if (typeof window > "u" || typeof navigator > "u" || !navigator.vibrate) return;
|
|
11
11
|
const t = w === "light" ? 8 : w === "medium" ? 18 : 32;
|
|
12
12
|
navigator.vibrate(t);
|
|
13
13
|
}
|
|
14
14
|
var Ce = e.from_html('<div class="donation-input-wrapper svelte-1rkcli3"><!></div>'), Ae = e.from_html('<span class="price-fee"> </span>'), we = e.from_html('<span class="price-strikethrough"> </span> <span class="price-discounted svelte-1rkcli3"> </span> <!>', 1), Te = e.from_html('<span class="price-lg text-color-muted"> </span>'), ze = e.from_html('<span class="price-fee"> </span>'), Be = e.from_html('<span class="price-lg text-color-primary"> </span> <!>', 1), Ie = e.from_html('<!> <span class="qty-display svelte-1rkcli3" aria-live="polite"> </span> <!>', 1), Ve = e.from_html('<article><div class="vc-flex-between-start gap-4"><div class="flex-1 min-w-0"><div class="flex-row-2 flex-wrap"><!> <!></div> <!> <div class="flex-row-2 mt-2"><!></div> <!></div> <div class="flex items-center quantity-selector svelte-1rkcli3"><!></div></div></article>');
|
|
15
|
-
function
|
|
15
|
+
function Me(w, t) {
|
|
16
16
|
e.push(t, !0);
|
|
17
17
|
let n = e.prop(t, "donationAmount", 3, ""), B = e.prop(t, "isRevealedByPromo", 3, !1), h = e.prop(t, "isDiscountedByPromo", 3, !1), T = e.prop(t, "discountedPrice", 3, null), u = e.prop(t, "labels", 19, () => ({})), k = e.derived(() => t.ticket.isDonation || t.ticket.ticketType === 2), I = e.derived(() => t.ticket.status === "sold_out" || t.ticket.quantityAvailable === 0), g = e.derived(() => t.ticket.status === "coming_soon"), V = e.derived(() => t.ticket.status === "sales_ended"), z = e.derived(() => e.get(I) || e.get(g) || e.get(V)), H = e.derived(() => Se(t.ticket.quantityAvailable, t.ticket.quantityTotal)), s = e.derived(() => qe(e.get(H), t.ticket.quantityAvailable, "ticket")), m = e.derived(() => parseFloat(n()) || 0), y = e.derived(() => e.get(k) && n() !== "" && e.get(m) < 1 ? "Minimum $1.00" : ""), b = e.derived(() => !e.get(k) || n() !== "" && e.get(m) >= 1), E = e.derived(() => t.quantity > 0), O = e.derived(() => !e.get(z) && t.quantity < t.ticket.maxPerOrder && t.quantity < t.ticket.quantityAvailable && e.get(b));
|
|
18
18
|
function F() {
|
|
19
19
|
if (e.get(E)) {
|
|
20
20
|
const a = t.quantity - 1;
|
|
21
|
-
t.onQuantityChange(
|
|
21
|
+
t.onQuantityChange(J(t.ticket.id), a < t.ticket.minPerOrder ? 0 : a), ee("light");
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
function
|
|
24
|
+
function K() {
|
|
25
25
|
if (e.get(O)) {
|
|
26
26
|
const a = t.quantity === 0 ? t.ticket.minPerOrder : t.quantity + 1;
|
|
27
|
-
t.onQuantityChange(
|
|
27
|
+
t.onQuantityChange(J(t.ticket.id), a), ee("light");
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
let P = e.state(e.proxy(n()));
|
|
31
31
|
e.user_effect(() => {
|
|
32
32
|
e.set(P, n());
|
|
33
33
|
});
|
|
34
|
-
function
|
|
35
|
-
e.get(P) !== n() && t.onDonationChange?.(
|
|
34
|
+
function L() {
|
|
35
|
+
e.get(P) !== n() && t.onDonationChange?.(J(t.ticket.id), e.get(P));
|
|
36
36
|
}
|
|
37
37
|
let d = e.derived(() => e.get(k) ? 0 : t.ticket.price + (t.ticket.price === 0 ? 0 : t.ticket.fee)), o = e.derived(() => e.get(k) ? "" : t.ticket.price === 0 ? u().free || "Free" : Q(e.get(d))), c = e.derived(() => !e.get(k) && t.ticket.fee > 0 && t.ticket.price > 0 ? `incl. ${Q(t.ticket.fee)} ${u().fee || "fee"}` : ""), S = e.derived(() => e.get(g) && t.ticket.salesStartDate ? `Sales start ${De(t.ticket.salesStartDate)}` : e.get(g) ? "Coming soon" : "");
|
|
38
38
|
var v = Ve();
|
|
39
39
|
let q;
|
|
40
|
-
var W = e.child(v),
|
|
40
|
+
var W = e.child(v), U = e.child(W), M = e.child(U), X = e.child(M);
|
|
41
41
|
Pe(X, {
|
|
42
42
|
level: 4,
|
|
43
43
|
size: "sm",
|
|
@@ -106,8 +106,8 @@ function Ke(w, t) {
|
|
|
106
106
|
e.get(I) ? a(re) : e.get(V) ? a(le, 1) : B() ? a(ne, 2) : h() ? a(de, 3) : e.get(s) && !e.get(g) && a(se, 4);
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
|
-
e.reset(
|
|
110
|
-
var Y = e.sibling(
|
|
109
|
+
e.reset(M);
|
|
110
|
+
var Y = e.sibling(M, 2);
|
|
111
111
|
{
|
|
112
112
|
var oe = (a) => {
|
|
113
113
|
$(a, {
|
|
@@ -126,7 +126,7 @@ function Ke(w, t) {
|
|
|
126
126
|
t.ticket.description && a(oe);
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
|
-
var
|
|
129
|
+
var N = e.sibling(Y, 2), ce = e.child(N);
|
|
130
130
|
{
|
|
131
131
|
var ve = (a) => {
|
|
132
132
|
var i = Ce(), l = e.child(i);
|
|
@@ -154,7 +154,7 @@ function Ke(w, t) {
|
|
|
154
154
|
}
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
|
-
e.reset(i), e.delegated("input", i,
|
|
157
|
+
e.reset(i), e.delegated("input", i, L), e.append(a, i);
|
|
158
158
|
}, ue = (a) => {
|
|
159
159
|
const i = e.derived(() => T() + (T() === 0 ? 0 : t.ticket.fee));
|
|
160
160
|
var l = we(), r = e.first_child(l), D = e.child(r, !0);
|
|
@@ -164,8 +164,8 @@ function Ke(w, t) {
|
|
|
164
164
|
var _ = e.sibling(C, 2);
|
|
165
165
|
{
|
|
166
166
|
var A = (p) => {
|
|
167
|
-
var x = Ae(),
|
|
168
|
-
e.reset(x), e.template_effect(() => e.set_text(
|
|
167
|
+
var x = Ae(), G = e.child(x, !0);
|
|
168
|
+
e.reset(x), e.template_effect(() => e.set_text(G, e.get(c))), e.append(p, x);
|
|
169
169
|
};
|
|
170
170
|
e.if(_, (p) => {
|
|
171
171
|
e.get(c) && p(A);
|
|
@@ -202,8 +202,8 @@ function Ke(w, t) {
|
|
|
202
202
|
e.get(k) ? a(ve) : h() && T() !== null ? a(ue, 1) : e.get(g) ? a(ge, 2) : a(me, !1);
|
|
203
203
|
});
|
|
204
204
|
}
|
|
205
|
-
e.reset(
|
|
206
|
-
var fe = e.sibling(
|
|
205
|
+
e.reset(N);
|
|
206
|
+
var fe = e.sibling(N, 2);
|
|
207
207
|
{
|
|
208
208
|
var _e = (a) => {
|
|
209
209
|
$(a, {
|
|
@@ -222,8 +222,8 @@ function Ke(w, t) {
|
|
|
222
222
|
e.get(S) && a(_e);
|
|
223
223
|
});
|
|
224
224
|
}
|
|
225
|
-
e.reset(
|
|
226
|
-
var Z = e.sibling(
|
|
225
|
+
e.reset(U);
|
|
226
|
+
var Z = e.sibling(U, 2), pe = e.child(Z);
|
|
227
227
|
{
|
|
228
228
|
var xe = (a) => {
|
|
229
229
|
}, he = (a) => {
|
|
@@ -240,7 +240,7 @@ function Ke(w, t) {
|
|
|
240
240
|
get "aria-label"() {
|
|
241
241
|
return `${e.get(_) ?? ""} ${e.get(A) ?? ""} ${e.get(p) ?? ""}`;
|
|
242
242
|
},
|
|
243
|
-
children: (x,
|
|
243
|
+
children: (x, G) => {
|
|
244
244
|
ye(x, { size: 16 });
|
|
245
245
|
},
|
|
246
246
|
$$slots: { default: !0 }
|
|
@@ -254,14 +254,14 @@ function Ke(w, t) {
|
|
|
254
254
|
R(C, {
|
|
255
255
|
variant: "alternative",
|
|
256
256
|
size: "icon-lg",
|
|
257
|
-
onclick:
|
|
257
|
+
onclick: K,
|
|
258
258
|
get disabled() {
|
|
259
259
|
return e.get(f);
|
|
260
260
|
},
|
|
261
261
|
get "aria-label"() {
|
|
262
262
|
return `${e.get(_) ?? ""} ${e.get(A) ?? ""} ${e.get(p) ?? ""}`;
|
|
263
263
|
},
|
|
264
|
-
children: (x,
|
|
264
|
+
children: (x, G) => {
|
|
265
265
|
be(x, { size: 16 });
|
|
266
266
|
},
|
|
267
267
|
$$slots: { default: !0 }
|
|
@@ -284,7 +284,7 @@ function Ke(w, t) {
|
|
|
284
284
|
}
|
|
285
285
|
e.delegate(["input"]);
|
|
286
286
|
var Re = e.from_html('<p class="promo-message success body-sm svelte-1uooa2j" role="status" aria-live="polite"> </p>'), Ee = e.from_html('<div class="space-y-2"><div class="promo-input-wrapper svelte-1uooa2j"><div class="flex-1"><!></div> <!></div> <!></div>'), Oe = e.from_html('<div class="promo-section svelte-1uooa2j" role="group" aria-labelledby="promo-label"><span id="promo-label" class="sr-only">Promo code entry</span> <!></div>');
|
|
287
|
-
function
|
|
287
|
+
function Ne(w, t) {
|
|
288
288
|
e.push(t, !0);
|
|
289
289
|
let n = e.prop(t, "labels", 19, () => ({})), B = e.state(!1), h = e.state("");
|
|
290
290
|
function T() {
|
|
@@ -362,7 +362,7 @@ function Me(w, t) {
|
|
|
362
362
|
$$slots: { default: !0 }
|
|
363
363
|
});
|
|
364
364
|
}
|
|
365
|
-
},
|
|
365
|
+
}, K = (d) => {
|
|
366
366
|
{
|
|
367
367
|
let o = e.derived(() => t.promoState.isValidating || !e.get(h).trim()), c = e.derived(() => t.promoState.isValidating ? n().checkingPromoCode || "Checking promo code" : n().applyPromoCode || "Apply promo code");
|
|
368
368
|
R(d, {
|
|
@@ -384,18 +384,18 @@ function Me(w, t) {
|
|
|
384
384
|
}
|
|
385
385
|
};
|
|
386
386
|
e.if(O, (d) => {
|
|
387
|
-
t.promoState.isApplied ? d(F) : d(
|
|
387
|
+
t.promoState.isApplied ? d(F) : d(K, !1);
|
|
388
388
|
});
|
|
389
389
|
}
|
|
390
390
|
e.reset(y);
|
|
391
391
|
var P = e.sibling(y, 2);
|
|
392
392
|
{
|
|
393
|
-
var
|
|
393
|
+
var L = (d) => {
|
|
394
394
|
var o = Re(), c = e.child(o, !0);
|
|
395
395
|
e.reset(o), e.template_effect(() => e.set_text(c, t.promoState.hint)), e.append(d, o);
|
|
396
396
|
};
|
|
397
397
|
e.if(P, (d) => {
|
|
398
|
-
t.promoState.hint && d(
|
|
398
|
+
t.promoState.hint && d(L);
|
|
399
399
|
});
|
|
400
400
|
}
|
|
401
401
|
e.reset(m), e.template_effect(() => e.set_style(m, `animation: promoSlideIn ${ae.normal}ms ease-out;`)), e.delegated("keydown", y, k), e.append(s, m);
|
|
@@ -408,8 +408,8 @@ function Me(w, t) {
|
|
|
408
408
|
}
|
|
409
409
|
e.delegate(["keydown"]);
|
|
410
410
|
export {
|
|
411
|
-
|
|
412
|
-
|
|
411
|
+
Ne as P,
|
|
412
|
+
Me as T,
|
|
413
413
|
ee as t
|
|
414
414
|
};
|
|
415
|
-
//# sourceMappingURL=PromoCodeInput-
|
|
415
|
+
//# sourceMappingURL=PromoCodeInput-CrXBD0oq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromoCodeInput-B8agz1bc.js","sources":["../src/lib/utils/haptic.ts","../src/lib/public-calendar-flow/TicketCard.svelte","../src/lib/public-calendar-flow/PromoCodeInput.svelte"],"sourcesContent":["/**\r\n * Haptic feedback helper.\r\n *\r\n * One call site for `navigator.vibrate` so consumers don't repeat the\r\n * SSR + capability check. Android browsers vibrate; iOS Safari silently\r\n * no-ops (Apple deliberate — they reserve haptics for native apps via\r\n * the Taptic Engine, no web API exposed). Future-proof: if Apple ever\r\n * ships a web haptic API, swap the impl here and every consumer gets it.\r\n *\r\n * Styles:\r\n * - 'light' (8ms) — UI tick on small interactions (ticket +/-, tap)\r\n * - 'medium' (18ms) — committed state change (drawer snap, month flip)\r\n * - 'heavy' (32ms) — destructive / important confirmations\r\n */\r\nexport function tick(style: 'light' | 'medium' | 'heavy' = 'light'): void {\r\n\tif (typeof window === 'undefined') return;\r\n\tif (typeof navigator === 'undefined' || !navigator.vibrate) return;\r\n\tconst ms = style === 'light' ? 8 : style === 'medium' ? 18 : 32;\r\n\tnavigator.vibrate(ms);\r\n}\r\n","<script lang=\"ts\">\r\n\timport { Add, Subtract } from 'carbon-icons-svelte';\r\n\timport { Badge, Button, Heading, Input, Text, asTicketId, formatCurrency } from '@getmicdrop/svelte-components';\r\n\timport type { TicketId, USD } from '@getmicdrop/svelte-components';\r\n\timport ScarcityBadge from '../../components/ScarcityBadge.svelte';\r\n\timport { tick } from '$lib/utils/haptic';\r\n\timport type { TicketTypeData, ScarcityLevel } from '$lib/public-calendar-flow/types';\r\n\timport {\r\n\t\tgetScarcityLevel,\r\n\t\tgetScarcityText,\r\n\t\tformatSmartSalesDate,\r\n\t\tDURATION\r\n\t} from '$lib/public-calendar-flow/defaults';\r\n\r\n\tinterface Props {\r\n\t\tticket: TicketTypeData;\r\n\t\tquantity: number;\r\n\t\tonQuantityChange: (ticketId: TicketId, quantity: number) => void;\r\n\t\tdonationAmount?: string;\r\n\t\tonDonationChange?: (ticketId: TicketId, amount: string) => void;\r\n\t\tisRevealedByPromo?: boolean;\r\n\t\tisDiscountedByPromo?: boolean;\r\n\t\tdiscountedPrice?: number | null;\r\n\t\t\tlabels?: Record<string, string>;\r\n\t}\r\n\r\n\tlet {\r\n\t\tticket,\r\n\t\tquantity,\r\n\t\tonQuantityChange,\r\n\t\tdonationAmount = '',\r\n\t\tonDonationChange,\r\n\t\tisRevealedByPromo = false,\r\n\t\tisDiscountedByPromo = false,\r\n\t\tdiscountedPrice = null,\r\n\t\tlabels = {},\r\n\t}: Props = $props();\r\n\r\n\t// --- State detection ---\r\n\tlet isDonation = $derived(ticket.isDonation || ticket.ticketType === 2);\r\n\tlet isSoldOut = $derived(ticket.status === 'sold_out' || ticket.quantityAvailable === 0);\r\n\tlet isComingSoon = $derived(ticket.status === 'coming_soon');\r\n\tlet isSalesEnded = $derived(ticket.status === 'sales_ended');\r\n\tlet isDisabled = $derived(isSoldOut || isComingSoon || isSalesEnded);\r\n\r\n\tlet scarcityLevel: ScarcityLevel = $derived(\r\n\t\tgetScarcityLevel(ticket.quantityAvailable, ticket.quantityTotal)\r\n\t);\r\n\tlet scarcityText = $derived(getScarcityText(scarcityLevel, ticket.quantityAvailable, 'ticket'));\r\n\r\n\t// Donation validation\r\n\tlet donationValue = $derived(parseFloat(donationAmount) || 0);\r\n\tlet donationError = $derived(\r\n\t\tisDonation && donationAmount !== '' && donationValue < 1 ? 'Minimum $1.00' : ''\r\n\t);\r\n\tlet isDonationValid = $derived(!isDonation || (donationAmount !== '' && donationValue >= 1));\r\n\r\n\tlet canDecrement = $derived(quantity > 0);\r\n\tlet canIncrement = $derived(\r\n\t\t!isDisabled &&\r\n\t\tquantity < ticket.maxPerOrder &&\r\n\t\tquantity < ticket.quantityAvailable &&\r\n\t\tisDonationValid\r\n\t);\r\n\r\n\tfunction decrement() {\r\n\t\tif (canDecrement) {\r\n\t\t\t// If decrementing would go below minimum, jump to 0 (remove from cart)\r\n\t\t\tconst newQty = quantity - 1;\r\n\t\t\tonQuantityChange(asTicketId(ticket.id), newQty < ticket.minPerOrder ? 0 : newQty);\r\n\t\t\ttick('light');\r\n\t\t}\r\n\t}\r\n\r\n\tfunction increment() {\r\n\t\tif (canIncrement) {\r\n\t\t\t// If at 0, jump to minimum purchase quantity\r\n\t\t\tconst newQty = quantity === 0 ? ticket.minPerOrder : quantity + 1;\r\n\t\t\tonQuantityChange(asTicketId(ticket.id), newQty);\r\n\t\t\ttick('light');\r\n\t\t}\r\n\t}\r\n\r\n\tlet donationInputValue = $state(donationAmount);\r\n\r\n\t// Sync external donationAmount prop to local state\r\n\t$effect(() => {\r\n\t\tdonationInputValue = donationAmount;\r\n\t});\r\n\r\n\t// Push local changes upstream\r\n\tfunction syncDonation() {\r\n\t\tif (donationInputValue !== donationAmount) {\r\n\t\t\t// eslint-disable-next-line micdrop/boundary-only-as-cast -- API response mapper: ticket.id arrives as raw number from server\r\n\t\tonDonationChange?.(asTicketId(ticket.id), donationInputValue);\r\n\t\t}\r\n\t}\r\n\r\n\t// Price display — show total inclusive of fees (matching production TicketBlock.svelte)\r\n\tlet totalPrice = $derived(isDonation ? 0 : ticket.price + (ticket.price === 0 ? 0 : ticket.fee));\r\n\tlet priceDisplay = $derived(\r\n\t\tisDonation ? '' : ticket.price === 0 ? (labels.free || 'Free') : formatCurrency(totalPrice as USD)\r\n\t);\r\n\tlet feeCaption = $derived(\r\n\t\t!isDonation && ticket.fee > 0 && ticket.price > 0 ? `incl. ${formatCurrency(ticket.fee as USD)} ${labels.fee || 'fee'}` : ''\r\n\t);\r\n\r\n\t// Sales start display for coming soon tickets\r\n\tlet salesStartDisplay = $derived(\r\n\t\tisComingSoon && ticket.salesStartDate\r\n\t\t\t? `Sales start ${formatSmartSalesDate(ticket.salesStartDate)}`\r\n\t\t\t: isComingSoon\r\n\t\t\t\t? 'Coming soon'\r\n\t\t\t\t: ''\r\n\t);\r\n</script>\r\n\r\n<article\r\n\tclass=\"ticket-card rounded-lg border p-4 transition-all\"\r\n\tclass:disabled-ticket={isDisabled}\r\n\tclass:revealed={isRevealedByPromo && !isDisabled}\r\n\tstyle=\"transition-duration: {DURATION.normal}ms;\"\r\n>\r\n\t<div class=\"vc-flex-between-start gap-4\">\r\n\t\t<!-- Ticket info -->\r\n\t\t<div class=\"flex-1 min-w-0\">\r\n\t\t\t<div class=\"flex-row-2 flex-wrap\">\r\n\t\t\t\t<Heading level={4} size=\"sm\" weight=\"semibold\">\r\n\t\t\t\t\t{ticket.name}\r\n\t\t\t\t</Heading>\r\n\t\t\t\t{#if isSoldOut}\r\n\t\t\t\t\t<Badge variant=\"error\">{labels.soldOut || 'Sold out'}</Badge>\r\n\t\t\t\t{:else if isSalesEnded}\r\n\t\t\t\t\t<Badge variant=\"neutral\">Sales ended</Badge>\r\n\t\t\t\t{:else if isRevealedByPromo}\r\n\t\t\t\t\t<Badge variant=\"success\">Unlocked</Badge>\r\n\t\t\t\t{:else if isDiscountedByPromo}\r\n\t\t\t\t\t<Badge variant=\"green\">Discount applied</Badge>\r\n\t\t\t\t{:else if scarcityText && !isComingSoon}\r\n\t\t\t\t\t<ScarcityBadge\r\n\t\t\t\t\t\tremaining={ticket.quantityAvailable}\r\n\t\t\t\t\t\ttotal={ticket.quantityTotal}\r\n\t\t\t\t\t\tcontext=\"ticket\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t{/if}\r\n\t\t\t</div>\r\n\r\n\t\t\t{#if ticket.description}\r\n\t\t\t\t<Text size=\"xs\" color=\"muted\" class=\"block mt-1 line-clamp-2\">\r\n\t\t\t\t\t{ticket.description}\r\n\t\t\t\t</Text>\r\n\t\t\t{/if}\r\n\r\n\t\t\t<!-- Price row -->\r\n\t\t\t<div class=\"flex-row-2 mt-2\">\r\n\t\t\t\t{#if isDonation}\r\n\t\t\t\t\t<!-- Donation: $ input -->\r\n\t\t\t\t\t<!-- svelte-ignore a11y_no_static_element_interactions -->\r\n\t\t\t\t\t<div class=\"donation-input-wrapper\" oninput={syncDonation}>\r\n\t\t\t\t\t\t<Input\r\n\t\t\t\t\t\t\tlabel=\"Donation amount\"\r\n\t\t\t\t\t\t\tsize=\"md\"\r\n\t\t\t\t\t\t\ttype=\"text\"\r\n\t\t\t\t\t\t\tplaceholder=\"0.00\"\r\n\t\t\t\t\t\t\tbind:value={donationInputValue}\r\n\t\t\t\t\t\t\tdisabled={isDisabled}\r\n\t\t\t\t\t\t\terrorText={donationError}\r\n\t\t\t\t\t\t\tcolor={donationError ? 'red' : 'base'}\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t{:else if isDiscountedByPromo && discountedPrice !== null}\r\n\t\t\t\t\t<!-- Discounted: strikethrough original total + discounted total (both inclusive of fee) -->\r\n\t\t\t\t\t{@const discountedTotal = discountedPrice + (discountedPrice === 0 ? 0 : ticket.fee)}\r\n\t\t\t\t\t<span class=\"price-strikethrough\">{formatCurrency(totalPrice as USD /* FIXME(canonical-cleanup:toFixed): this cast bypasses the brand boundary; replace with toCents/toUSD at the API-response-transform layer. */)}</span>\r\n\t\t\t\t\t<span class=\"price-discounted\">{formatCurrency(discountedTotal as USD /* FIXME(canonical-cleanup:toFixed): this cast bypasses the brand boundary; replace with toCents/toUSD at the API-response-transform layer. */)}</span>\r\n\t\t\t\t\t{#if feeCaption}\r\n\t\t\t\t\t\t<span class=\"price-fee\">{feeCaption}</span>\r\n\t\t\t\t\t{/if}\r\n\t\t\t\t{:else if isComingSoon}\r\n\t\t\t\t\t<!-- Coming soon: show price dimmed -->\r\n\t\t\t\t\t<span class=\"price-lg text-color-muted\">{priceDisplay}</span>\r\n\t\t\t\t{:else}\r\n\t\t\t\t\t<!-- Standard price -->\r\n\t\t\t\t\t<span class=\"price-lg text-color-primary\">{priceDisplay}</span>\r\n\t\t\t\t\t{#if feeCaption}\r\n\t\t\t\t\t\t<span class=\"price-fee\">{feeCaption}</span>\r\n\t\t\t\t\t{/if}\r\n\t\t\t\t{/if}\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Coming soon / sales ended message -->\r\n\t\t\t{#if salesStartDisplay}\r\n\t\t\t\t<Text size=\"xs\" color=\"muted\" class=\"block mt-1.5\">\r\n\t\t\t\t\t{salesStartDisplay}\r\n\t\t\t\t</Text>\r\n\t\t\t{/if}\r\n\t\t</div>\r\n\r\n\t\t<!-- Quantity controls -->\r\n\t\t<div class=\"flex items-center quantity-selector\">\r\n\t\t\t{#if isSoldOut || isComingSoon || isSalesEnded}\r\n\t\t\t\t<!-- No controls for coming soon / sales ended -->\r\n\t\t\t{:else}\r\n\t\t\t\t<Button\r\n\t\t\t\t\tvariant=\"alternative\"\r\n\t\t\t\t\tsize=\"icon-lg\"\r\n\t\t\t\t\tonclick={decrement}\r\n\t\t\t\t\tdisabled={!canDecrement}\r\n\t\t\t\t\taria-label=\"{labels.decrease || 'Decrease'} {ticket.name} {labels.quantity || 'quantity'}\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<Subtract size={16} />\r\n\t\t\t\t</Button>\r\n\r\n\t\t\t\t<span\r\n\t\t\t\t\tclass=\"qty-display\"\r\n\t\t\t\t\taria-live=\"polite\"\r\n\t\t\t\t\taria-label=\"{ticket.name} {labels.quantity || 'quantity'}: {quantity}\"\r\n\t\t\t\t>\r\n\t\t\t\t\t{quantity}\r\n\t\t\t\t</span>\r\n\r\n\t\t\t\t<Button\r\n\t\t\t\t\tvariant=\"alternative\"\r\n\t\t\t\t\tsize=\"icon-lg\"\r\n\t\t\t\t\tonclick={increment}\r\n\t\t\t\t\tdisabled={!canIncrement}\r\n\t\t\t\t\taria-label=\"{labels.increase || 'Increase'} {ticket.name} {labels.quantity || 'quantity'}\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<Add size={16} />\r\n\t\t\t\t</Button>\r\n\t\t\t{/if}\r\n\t\t</div>\r\n\t</div>\r\n</article>\r\n\r\n<style>\r\n\t/* Card states using HSL CSS variables (matching TicketBlock.svelte) */\r\n\t.ticket-card {\r\n\t\tborder-color: hsl(var(--stroke-secondary, 220 13% 91%));\r\n\t\tbackground-color: hsl(var(--ts-card-bg, var(--bg-primary, 0 0% 100%)));\r\n\t}\r\n\r\n\t.ticket-card.revealed {\r\n\t\tborder-color: hsl(var(--accent-success) / 50%);\r\n\t\tbackground-color: hsl(var(--accent-success) / 8%);\r\n\t}\r\n\r\n\t.ticket-card.disabled-ticket {\r\n\t\topacity: 0.5;\r\n\t}\r\n\r\n\t/* Quantity selector */\r\n\t.quantity-selector {\r\n\t\tgap: 0.5rem;\r\n\t\tuser-select: none;\r\n\t\tuser-select: none;\r\n\t}\r\n\r\n\t.qty-display {\r\n\t\tmin-width: 2rem;\r\n\t\tdisplay: flex;\r\n\t\talign-items: center;\r\n\t\tjustify-content: center;\r\n\t\tfont-size: 1.125rem;\r\n\t\tfont-weight: 600;\r\n\t\tcolor: hsl(var(--text-primary, 222 47% 11%));\r\n\t\tuser-select: none;\r\n\t\tuser-select: none;\r\n\t}\r\n\r\n\t/* Discounted price green text */\r\n\t.price-discounted {\r\n\t\tfont-size: 0.875rem;\r\n\t\tline-height: 1.25rem;\r\n\t\tfont-weight: 600;\r\n\t\tcolor: hsl(var(--accent-success)); /* green-600 */\r\n\t}\r\n\r\n\t/* Donation input wrapper */\r\n\t.donation-input-wrapper {\r\n\t\tmin-width: 10rem;\r\n\t}\r\n\r\n .ticket-card {\r\n &:is([data-theme=\"dark\"], [data-theme=\"dark\"] *) {\r\n\t\tborder-color: hsl(var(--stroke-secondary, 215 19% 35%));\r\n\t\tbackground-color: hsl(var(--ts-card-bg, var(--bg-primary, 222 47% 11%)));\r\n\t }\r\n }\r\n\r\n .ticket-card.revealed {\r\n &:is([data-theme=\"dark\"], [data-theme=\"dark\"] *) {\r\n\t\tborder-color: hsl(var(--accent-success)); /* green-700 */\r\n\t\tbackground-color: hsl(var(--accent-success));\r\n\t }\r\n }\r\n\r\n .qty-display {\r\n &:is([data-theme=\"dark\"], [data-theme=\"dark\"] *) {\r\n\t\tcolor: hsl(var(--text-primary, 0 0% 100%));\r\n\t }\r\n }\r\n</style>\r\n","<script lang=\"ts\">\r\n\timport { Input, Button } from '@getmicdrop/svelte-components';\r\n\timport type { PromoCodeState } from '$lib/public-calendar-flow/types';\r\n\timport { DURATION } from '$lib/public-calendar-flow/defaults';\r\n\r\n\tinterface Props {\r\n\t\tpromoState: PromoCodeState;\r\n\t\tonApply: (code: string) => void;\r\n\t\tonRemove: () => void;\r\n\t\t\tlabels?: Record<string, string>;\r\n\t}\r\n\r\n\tlet { promoState, onApply, onRemove, labels = {}, }: Props = $props();\r\n\r\n\tlet isExpanded = $state(false);\r\n\tlet inputValue = $state('');\r\n\r\n\tfunction handleApply() {\r\n\t\tconst trimmed = inputValue.trim();\r\n\t\tif (!trimmed) return;\r\n\t\tonApply(trimmed);\r\n\t}\r\n\r\n\tfunction handleRemove() {\r\n\t\tinputValue = '';\r\n\t\tonRemove();\r\n\t}\r\n\r\n\tfunction handleKeydown(e: KeyboardEvent) {\r\n\t\tif (e.key === 'Enter') {\r\n\t\t\te.preventDefault();\r\n\t\t\thandleApply();\r\n\t\t}\r\n\t}\r\n\r\n\t// Auto-expand when promo is applied (e.g. on restore)\r\n\tlet shouldExpand = $derived(promoState.isApplied || isExpanded);\r\n</script>\r\n\r\n<div class=\"promo-section\" role=\"group\" aria-labelledby=\"promo-label\">\r\n\t<span id=\"promo-label\" class=\"sr-only\">Promo code entry</span>\r\n\t{#if !shouldExpand}\r\n\t\t<Button variant=\"link\" onclick={() => (isExpanded = true)}>\r\n\t\t\t{labels.havePromoCode || 'Have a promo code?'}\r\n\t\t</Button>\r\n\t{:else}\r\n\t\t<div\r\n\t\t\tclass=\"space-y-2\"\r\n\t\t\tstyle=\"animation: promoSlideIn {DURATION.normal}ms ease-out;\"\r\n\t\t>\r\n\t\t\t<!-- svelte-ignore a11y_no_static_element_interactions -->\r\n\t\t\t<div class=\"promo-input-wrapper\" onkeydown={handleKeydown}>\r\n\t\t\t\t<div class=\"flex-1\">\r\n\t\t\t\t\t<Input\r\n\t\t\t\t\t\tlabel={labels.promoCode || 'Promo code'}\r\n\t\t\t\t\t\tplaceholder={labels.enterCode || 'Enter code'}\r\n\t\t\t\t\t\tsize=\"md\"\r\n\t\t\t\t\t\ttype=\"text\"\r\n\t\t\t\t\t\tbind:value={inputValue}\r\n\t\t\t\t\t\tdisabled={promoState.isApplied || promoState.isValidating}\r\n\t\t\t\t\t\terrorText={promoState.error || ''}\r\n\t\t\t\t\t\tcolor={promoState.error ? 'red' : 'base'}\r\n\t\t\t\t\t/>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t{#if promoState.isApplied}\r\n\t\t\t\t\t<Button variant=\"outline\" onclick={handleRemove} class=\"h-10 self-start mt-5\" aria-label={labels.removePromoCode || 'Remove promo code'}>\r\n\t\t\t\t\t\t{labels.remove || 'Remove'}\r\n\t\t\t\t\t</Button>\r\n\t\t\t\t{:else}\r\n\t\t\t\t\t<Button\r\n\t\t\t\t\t\tonclick={handleApply}\r\n\t\t\t\t\t\tdisabled={promoState.isValidating || !inputValue.trim()}\r\n\t\t\t\t\t\tclass=\"h-10 self-start mt-5\"\r\n\t\t\t\t\t\taria-label={promoState.isValidating ? (labels.checkingPromoCode || 'Checking promo code') : (labels.applyPromoCode || 'Apply promo code')}\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{promoState.isValidating ? (labels.checking || 'Checking...') : (labels.apply || 'Apply')}\r\n\t\t\t\t\t</Button>\r\n\t\t\t\t{/if}\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Success hint -->\r\n\t\t\t{#if promoState.hint}\r\n\t\t\t\t<p class=\"promo-message success body-sm\" role=\"status\" aria-live=\"polite\">\r\n\t\t\t\t\t{promoState.hint}\r\n\t\t\t\t</p>\r\n\t\t\t{/if}\r\n\t\t</div>\r\n\t{/if}\r\n</div>\r\n\r\n<style>\r\n\t.promo-section {\r\n\t\tmargin-top: 1rem;\r\n\t}\r\n\r\n\t.promo-input-wrapper {\r\n\t\tdisplay: flex;\r\n\t\tgap: 0.5rem;\r\n\t\talign-items: flex-start;\r\n\t}\r\n\r\n\t.promo-message {\r\n\t\tmargin-top: 0.5rem;\r\n\t}\r\n\r\n\t.promo-message.success {\r\n\t\tcolor: hsl(var(--accent-success)); /* green-600 */\r\n\t}\r\n\r\n\t@keyframes promoSlideIn {\r\n\t\tfrom {\r\n\t\t\topacity: 0;\r\n\t\t\ttransform: translateY(-4px);\r\n\t\t}\r\n\r\n\t\tto {\r\n\t\t\topacity: 1;\r\n\t\t\ttransform: translateY(0);\r\n\t\t}\r\n\t}\r\n</style>\r\n"],"names":["tick","style","ms","donationAmount","isRevealedByPromo","isDiscountedByPromo","discountedPrice","labels","$","$$props","isDonation","isSoldOut","isComingSoon","isSalesEnded","isDisabled","scarcityLevel","getScarcityLevel","scarcityText","getScarcityText","donationValue","donationError","isDonationValid","canDecrement","canIncrement","decrement","newQty","asTicketId","increment","donationInputValue","syncDonation","totalPrice","priceDisplay","formatCurrency","feeCaption","salesStartDisplay","formatSmartSalesDate","article","root","div","div_1","div_2","Heading","node","Badge","$$anchor","ScarcityBadge","$$render","consequent","consequent_1","consequent_3","consequent_4","Text","consequent_5","div_3","node_2","div_4","root_13","Input","node_4","$$value","discountedTotal","span","fragment_9","span_1","span_2","root_15","consequent_7","span_3","root_16","span_4","fragment_10","span_5","root_18","consequent_10","consequent_9","alternate","consequent_11","div_5","Button","node_9","Subtract","span_6","node_10","Add","consequent_12","alternate_1","classes","DURATION","isExpanded","inputValue","handleApply","trimmed","handleRemove","handleKeydown","e","shouldExpand","root_3","$2","$3","node_1","p","root_8","consequent_2"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PromoCodeInput-CrXBD0oq.js","sources":["../src/lib/utils/haptic.ts","../src/lib/public-calendar-flow/TicketCard.svelte","../src/lib/public-calendar-flow/PromoCodeInput.svelte"],"sourcesContent":["/**\r\n * Haptic feedback helper.\r\n *\r\n * One call site for `navigator.vibrate` so consumers don't repeat the\r\n * SSR + capability check. Android browsers vibrate; iOS Safari silently\r\n * no-ops (Apple deliberate — they reserve haptics for native apps via\r\n * the Taptic Engine, no web API exposed). Future-proof: if Apple ever\r\n * ships a web haptic API, swap the impl here and every consumer gets it.\r\n *\r\n * Styles:\r\n * - 'light' (8ms) — UI tick on small interactions (ticket +/-, tap)\r\n * - 'medium' (18ms) — committed state change (drawer snap, month flip)\r\n * - 'heavy' (32ms) — destructive / important confirmations\r\n */\r\nexport function tick(style: 'light' | 'medium' | 'heavy' = 'light'): void {\r\n\tif (typeof window === 'undefined') return;\r\n\tif (typeof navigator === 'undefined' || !navigator.vibrate) return;\r\n\tconst ms = style === 'light' ? 8 : style === 'medium' ? 18 : 32;\r\n\tnavigator.vibrate(ms);\r\n}\r\n","<script lang=\"ts\">\r\n\timport { Add, Subtract } from 'carbon-icons-svelte';\r\n\timport { Badge, Button, Heading, Input, Text, asTicketId, formatCurrency } from '@getmicdrop/svelte-components';\r\n\timport type { TicketId, USD } from '@getmicdrop/svelte-components';\r\n\timport ScarcityBadge from '../../components/ScarcityBadge.svelte';\r\n\timport { tick } from '$lib/utils/haptic';\r\n\timport type { TicketTypeData, ScarcityLevel } from '$lib/public-calendar-flow/types';\r\n\timport {\r\n\t\tgetScarcityLevel,\r\n\t\tgetScarcityText,\r\n\t\tformatSmartSalesDate,\r\n\t\tDURATION\r\n\t} from '$lib/public-calendar-flow/defaults';\r\n\r\n\tinterface Props {\r\n\t\tticket: TicketTypeData;\r\n\t\tquantity: number;\r\n\t\tonQuantityChange: (ticketId: TicketId, quantity: number) => void;\r\n\t\tdonationAmount?: string;\r\n\t\tonDonationChange?: (ticketId: TicketId, amount: string) => void;\r\n\t\tisRevealedByPromo?: boolean;\r\n\t\tisDiscountedByPromo?: boolean;\r\n\t\tdiscountedPrice?: number | null;\r\n\t\t\tlabels?: Record<string, string>;\r\n\t}\r\n\r\n\tlet {\r\n\t\tticket,\r\n\t\tquantity,\r\n\t\tonQuantityChange,\r\n\t\tdonationAmount = '',\r\n\t\tonDonationChange,\r\n\t\tisRevealedByPromo = false,\r\n\t\tisDiscountedByPromo = false,\r\n\t\tdiscountedPrice = null,\r\n\t\tlabels = {},\r\n\t}: Props = $props();\r\n\r\n\t// --- State detection ---\r\n\tlet isDonation = $derived(ticket.isDonation || ticket.ticketType === 2);\r\n\tlet isSoldOut = $derived(ticket.status === 'sold_out' || ticket.quantityAvailable === 0);\r\n\tlet isComingSoon = $derived(ticket.status === 'coming_soon');\r\n\tlet isSalesEnded = $derived(ticket.status === 'sales_ended');\r\n\tlet isDisabled = $derived(isSoldOut || isComingSoon || isSalesEnded);\r\n\r\n\tlet scarcityLevel: ScarcityLevel = $derived(\r\n\t\tgetScarcityLevel(ticket.quantityAvailable, ticket.quantityTotal)\r\n\t);\r\n\tlet scarcityText = $derived(getScarcityText(scarcityLevel, ticket.quantityAvailable, 'ticket'));\r\n\r\n\t// Donation validation\r\n\tlet donationValue = $derived(parseFloat(donationAmount) || 0);\r\n\tlet donationError = $derived(\r\n\t\tisDonation && donationAmount !== '' && donationValue < 1 ? 'Minimum $1.00' : ''\r\n\t);\r\n\tlet isDonationValid = $derived(!isDonation || (donationAmount !== '' && donationValue >= 1));\r\n\r\n\tlet canDecrement = $derived(quantity > 0);\r\n\tlet canIncrement = $derived(\r\n\t\t!isDisabled &&\r\n\t\tquantity < ticket.maxPerOrder &&\r\n\t\tquantity < ticket.quantityAvailable &&\r\n\t\tisDonationValid\r\n\t);\r\n\r\n\tfunction decrement() {\r\n\t\tif (canDecrement) {\r\n\t\t\t// If decrementing would go below minimum, jump to 0 (remove from cart)\r\n\t\t\tconst newQty = quantity - 1;\r\n\t\t\tonQuantityChange(asTicketId(ticket.id), newQty < ticket.minPerOrder ? 0 : newQty);\r\n\t\t\ttick('light');\r\n\t\t}\r\n\t}\r\n\r\n\tfunction increment() {\r\n\t\tif (canIncrement) {\r\n\t\t\t// If at 0, jump to minimum purchase quantity\r\n\t\t\tconst newQty = quantity === 0 ? ticket.minPerOrder : quantity + 1;\r\n\t\t\tonQuantityChange(asTicketId(ticket.id), newQty);\r\n\t\t\ttick('light');\r\n\t\t}\r\n\t}\r\n\r\n\tlet donationInputValue = $state(donationAmount);\r\n\r\n\t// Sync external donationAmount prop to local state\r\n\t$effect(() => {\r\n\t\tdonationInputValue = donationAmount;\r\n\t});\r\n\r\n\t// Push local changes upstream\r\n\tfunction syncDonation() {\r\n\t\tif (donationInputValue !== donationAmount) {\r\n\t\t\t// eslint-disable-next-line micdrop/boundary-only-as-cast -- API response mapper: ticket.id arrives as raw number from server\r\n\t\tonDonationChange?.(asTicketId(ticket.id), donationInputValue);\r\n\t\t}\r\n\t}\r\n\r\n\t// Price display — show total inclusive of fees (matching production TicketBlock.svelte)\r\n\tlet totalPrice = $derived(isDonation ? 0 : ticket.price + (ticket.price === 0 ? 0 : ticket.fee));\r\n\tlet priceDisplay = $derived(\r\n\t\tisDonation ? '' : ticket.price === 0 ? (labels.free || 'Free') : formatCurrency(totalPrice as USD)\r\n\t);\r\n\tlet feeCaption = $derived(\r\n\t\t!isDonation && ticket.fee > 0 && ticket.price > 0 ? `incl. ${formatCurrency(ticket.fee as USD)} ${labels.fee || 'fee'}` : ''\r\n\t);\r\n\r\n\t// Sales start display for coming soon tickets\r\n\tlet salesStartDisplay = $derived(\r\n\t\tisComingSoon && ticket.salesStartDate\r\n\t\t\t? `Sales start ${formatSmartSalesDate(ticket.salesStartDate)}`\r\n\t\t\t: isComingSoon\r\n\t\t\t\t? 'Coming soon'\r\n\t\t\t\t: ''\r\n\t);\r\n</script>\r\n\r\n<article\r\n\tclass=\"ticket-card rounded-lg border p-4 transition-all\"\r\n\tclass:disabled-ticket={isDisabled}\r\n\tclass:revealed={isRevealedByPromo && !isDisabled}\r\n\tstyle=\"transition-duration: {DURATION.normal}ms;\"\r\n>\r\n\t<div class=\"vc-flex-between-start gap-4\">\r\n\t\t<!-- Ticket info -->\r\n\t\t<div class=\"flex-1 min-w-0\">\r\n\t\t\t<div class=\"flex-row-2 flex-wrap\">\r\n\t\t\t\t<Heading level={4} size=\"sm\" weight=\"semibold\">\r\n\t\t\t\t\t{ticket.name}\r\n\t\t\t\t</Heading>\r\n\t\t\t\t{#if isSoldOut}\r\n\t\t\t\t\t<Badge variant=\"error\">{labels.soldOut || 'Sold out'}</Badge>\r\n\t\t\t\t{:else if isSalesEnded}\r\n\t\t\t\t\t<Badge variant=\"neutral\">Sales ended</Badge>\r\n\t\t\t\t{:else if isRevealedByPromo}\r\n\t\t\t\t\t<Badge variant=\"success\">Unlocked</Badge>\r\n\t\t\t\t{:else if isDiscountedByPromo}\r\n\t\t\t\t\t<Badge variant=\"green\">Discount applied</Badge>\r\n\t\t\t\t{:else if scarcityText && !isComingSoon}\r\n\t\t\t\t\t<ScarcityBadge\r\n\t\t\t\t\t\tremaining={ticket.quantityAvailable}\r\n\t\t\t\t\t\ttotal={ticket.quantityTotal}\r\n\t\t\t\t\t\tcontext=\"ticket\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t{/if}\r\n\t\t\t</div>\r\n\r\n\t\t\t{#if ticket.description}\r\n\t\t\t\t<Text size=\"xs\" color=\"muted\" class=\"block mt-1 line-clamp-2\">\r\n\t\t\t\t\t{ticket.description}\r\n\t\t\t\t</Text>\r\n\t\t\t{/if}\r\n\r\n\t\t\t<!-- Price row -->\r\n\t\t\t<div class=\"flex-row-2 mt-2\">\r\n\t\t\t\t{#if isDonation}\r\n\t\t\t\t\t<!-- Donation: $ input -->\r\n\t\t\t\t\t<!-- svelte-ignore a11y_no_static_element_interactions -->\r\n\t\t\t\t\t<div class=\"donation-input-wrapper\" oninput={syncDonation}>\r\n\t\t\t\t\t\t<Input\r\n\t\t\t\t\t\t\tlabel=\"Donation amount\"\r\n\t\t\t\t\t\t\tsize=\"md\"\r\n\t\t\t\t\t\t\ttype=\"text\"\r\n\t\t\t\t\t\t\tplaceholder=\"0.00\"\r\n\t\t\t\t\t\t\tbind:value={donationInputValue}\r\n\t\t\t\t\t\t\tdisabled={isDisabled}\r\n\t\t\t\t\t\t\terrorText={donationError}\r\n\t\t\t\t\t\t\tcolor={donationError ? 'red' : 'base'}\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t{:else if isDiscountedByPromo && discountedPrice !== null}\r\n\t\t\t\t\t<!-- Discounted: strikethrough original total + discounted total (both inclusive of fee) -->\r\n\t\t\t\t\t{@const discountedTotal = discountedPrice + (discountedPrice === 0 ? 0 : ticket.fee)}\r\n\t\t\t\t\t<span class=\"price-strikethrough\">{formatCurrency(totalPrice as USD /* FIXME(canonical-cleanup:toFixed): this cast bypasses the brand boundary; replace with toCents/toUSD at the API-response-transform layer. */)}</span>\r\n\t\t\t\t\t<span class=\"price-discounted\">{formatCurrency(discountedTotal as USD /* FIXME(canonical-cleanup:toFixed): this cast bypasses the brand boundary; replace with toCents/toUSD at the API-response-transform layer. */)}</span>\r\n\t\t\t\t\t{#if feeCaption}\r\n\t\t\t\t\t\t<span class=\"price-fee\">{feeCaption}</span>\r\n\t\t\t\t\t{/if}\r\n\t\t\t\t{:else if isComingSoon}\r\n\t\t\t\t\t<!-- Coming soon: show price dimmed -->\r\n\t\t\t\t\t<span class=\"price-lg text-color-muted\">{priceDisplay}</span>\r\n\t\t\t\t{:else}\r\n\t\t\t\t\t<!-- Standard price -->\r\n\t\t\t\t\t<span class=\"price-lg text-color-primary\">{priceDisplay}</span>\r\n\t\t\t\t\t{#if feeCaption}\r\n\t\t\t\t\t\t<span class=\"price-fee\">{feeCaption}</span>\r\n\t\t\t\t\t{/if}\r\n\t\t\t\t{/if}\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Coming soon / sales ended message -->\r\n\t\t\t{#if salesStartDisplay}\r\n\t\t\t\t<Text size=\"xs\" color=\"muted\" class=\"block mt-1.5\">\r\n\t\t\t\t\t{salesStartDisplay}\r\n\t\t\t\t</Text>\r\n\t\t\t{/if}\r\n\t\t</div>\r\n\r\n\t\t<!-- Quantity controls -->\r\n\t\t<div class=\"flex items-center quantity-selector\">\r\n\t\t\t{#if isSoldOut || isComingSoon || isSalesEnded}\r\n\t\t\t\t<!-- No controls for coming soon / sales ended -->\r\n\t\t\t{:else}\r\n\t\t\t\t<Button\r\n\t\t\t\t\tvariant=\"alternative\"\r\n\t\t\t\t\tsize=\"icon-lg\"\r\n\t\t\t\t\tonclick={decrement}\r\n\t\t\t\t\tdisabled={!canDecrement}\r\n\t\t\t\t\taria-label=\"{labels.decrease || 'Decrease'} {ticket.name} {labels.quantity || 'quantity'}\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<Subtract size={16} />\r\n\t\t\t\t</Button>\r\n\r\n\t\t\t\t<span\r\n\t\t\t\t\tclass=\"qty-display\"\r\n\t\t\t\t\taria-live=\"polite\"\r\n\t\t\t\t\taria-label=\"{ticket.name} {labels.quantity || 'quantity'}: {quantity}\"\r\n\t\t\t\t>\r\n\t\t\t\t\t{quantity}\r\n\t\t\t\t</span>\r\n\r\n\t\t\t\t<Button\r\n\t\t\t\t\tvariant=\"alternative\"\r\n\t\t\t\t\tsize=\"icon-lg\"\r\n\t\t\t\t\tonclick={increment}\r\n\t\t\t\t\tdisabled={!canIncrement}\r\n\t\t\t\t\taria-label=\"{labels.increase || 'Increase'} {ticket.name} {labels.quantity || 'quantity'}\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<Add size={16} />\r\n\t\t\t\t</Button>\r\n\t\t\t{/if}\r\n\t\t</div>\r\n\t</div>\r\n</article>\r\n\r\n<style>\r\n\t/* Card states using HSL CSS variables (matching TicketBlock.svelte) */\r\n\t.ticket-card {\r\n\t\tborder-color: hsl(var(--stroke-secondary, 220 13% 91%));\r\n\t\tbackground-color: hsl(var(--ts-card-bg, var(--bg-primary, 0 0% 100%)));\r\n\t}\r\n\r\n\t.ticket-card.revealed {\r\n\t\tborder-color: hsl(var(--accent-success) / 50%);\r\n\t\tbackground-color: hsl(var(--accent-success) / 8%);\r\n\t}\r\n\r\n\t.ticket-card.disabled-ticket {\r\n\t\topacity: 0.5;\r\n\t}\r\n\r\n\t/* Quantity selector */\r\n\t.quantity-selector {\r\n\t\tgap: 0.5rem;\r\n\t\tuser-select: none;\r\n\t\tuser-select: none;\r\n\t}\r\n\r\n\t.qty-display {\r\n\t\tmin-width: 2rem;\r\n\t\tdisplay: flex;\r\n\t\talign-items: center;\r\n\t\tjustify-content: center;\r\n\t\tfont-size: 1.125rem;\r\n\t\tfont-weight: 600;\r\n\t\tcolor: hsl(var(--text-primary, 222 47% 11%));\r\n\t\tuser-select: none;\r\n\t\tuser-select: none;\r\n\t}\r\n\r\n\t/* Discounted price green text */\r\n\t.price-discounted {\r\n\t\tfont-size: 0.875rem;\r\n\t\tline-height: 1.25rem;\r\n\t\tfont-weight: 600;\r\n\t\tcolor: hsl(var(--accent-success)); /* green-600 */\r\n\t}\r\n\r\n\t/* Donation input wrapper */\r\n\t.donation-input-wrapper {\r\n\t\tmin-width: 10rem;\r\n\t}\r\n\r\n .ticket-card {\r\n &:is([data-theme=\"dark\"], [data-theme=\"dark\"] *) {\r\n\t\tborder-color: hsl(var(--stroke-secondary, 215 19% 35%));\r\n\t\tbackground-color: hsl(var(--ts-card-bg, var(--bg-primary, 222 47% 11%)));\r\n\t }\r\n }\r\n\r\n .ticket-card.revealed {\r\n &:is([data-theme=\"dark\"], [data-theme=\"dark\"] *) {\r\n\t\tborder-color: hsl(var(--accent-success)); /* green-700 */\r\n\t\tbackground-color: hsl(var(--accent-success));\r\n\t }\r\n }\r\n\r\n .qty-display {\r\n &:is([data-theme=\"dark\"], [data-theme=\"dark\"] *) {\r\n\t\tcolor: hsl(var(--text-primary, 0 0% 100%));\r\n\t }\r\n }\r\n</style>\r\n","<script lang=\"ts\">\r\n\timport { Input, Button } from '@getmicdrop/svelte-components';\r\n\timport type { PromoCodeState } from '$lib/public-calendar-flow/types';\r\n\timport { DURATION } from '$lib/public-calendar-flow/defaults';\r\n\r\n\tinterface Props {\r\n\t\tpromoState: PromoCodeState;\r\n\t\tonApply: (code: string) => void;\r\n\t\tonRemove: () => void;\r\n\t\t\tlabels?: Record<string, string>;\r\n\t}\r\n\r\n\tlet { promoState, onApply, onRemove, labels = {}, }: Props = $props();\r\n\r\n\tlet isExpanded = $state(false);\r\n\tlet inputValue = $state('');\r\n\r\n\tfunction handleApply() {\r\n\t\tconst trimmed = inputValue.trim();\r\n\t\tif (!trimmed) return;\r\n\t\tonApply(trimmed);\r\n\t}\r\n\r\n\tfunction handleRemove() {\r\n\t\tinputValue = '';\r\n\t\tonRemove();\r\n\t}\r\n\r\n\tfunction handleKeydown(e: KeyboardEvent) {\r\n\t\tif (e.key === 'Enter') {\r\n\t\t\te.preventDefault();\r\n\t\t\thandleApply();\r\n\t\t}\r\n\t}\r\n\r\n\t// Auto-expand when promo is applied (e.g. on restore)\r\n\tlet shouldExpand = $derived(promoState.isApplied || isExpanded);\r\n</script>\r\n\r\n<div class=\"promo-section\" role=\"group\" aria-labelledby=\"promo-label\">\r\n\t<span id=\"promo-label\" class=\"sr-only\">Promo code entry</span>\r\n\t{#if !shouldExpand}\r\n\t\t<Button variant=\"link\" onclick={() => (isExpanded = true)}>\r\n\t\t\t{labels.havePromoCode || 'Have a promo code?'}\r\n\t\t</Button>\r\n\t{:else}\r\n\t\t<div\r\n\t\t\tclass=\"space-y-2\"\r\n\t\t\tstyle=\"animation: promoSlideIn {DURATION.normal}ms ease-out;\"\r\n\t\t>\r\n\t\t\t<!-- svelte-ignore a11y_no_static_element_interactions -->\r\n\t\t\t<div class=\"promo-input-wrapper\" onkeydown={handleKeydown}>\r\n\t\t\t\t<div class=\"flex-1\">\r\n\t\t\t\t\t<Input\r\n\t\t\t\t\t\tlabel={labels.promoCode || 'Promo code'}\r\n\t\t\t\t\t\tplaceholder={labels.enterCode || 'Enter code'}\r\n\t\t\t\t\t\tsize=\"md\"\r\n\t\t\t\t\t\ttype=\"text\"\r\n\t\t\t\t\t\tbind:value={inputValue}\r\n\t\t\t\t\t\tdisabled={promoState.isApplied || promoState.isValidating}\r\n\t\t\t\t\t\terrorText={promoState.error || ''}\r\n\t\t\t\t\t\tcolor={promoState.error ? 'red' : 'base'}\r\n\t\t\t\t\t/>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t{#if promoState.isApplied}\r\n\t\t\t\t\t<Button variant=\"outline\" onclick={handleRemove} class=\"h-10 self-start mt-5\" aria-label={labels.removePromoCode || 'Remove promo code'}>\r\n\t\t\t\t\t\t{labels.remove || 'Remove'}\r\n\t\t\t\t\t</Button>\r\n\t\t\t\t{:else}\r\n\t\t\t\t\t<Button\r\n\t\t\t\t\t\tonclick={handleApply}\r\n\t\t\t\t\t\tdisabled={promoState.isValidating || !inputValue.trim()}\r\n\t\t\t\t\t\tclass=\"h-10 self-start mt-5\"\r\n\t\t\t\t\t\taria-label={promoState.isValidating ? (labels.checkingPromoCode || 'Checking promo code') : (labels.applyPromoCode || 'Apply promo code')}\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{promoState.isValidating ? (labels.checking || 'Checking...') : (labels.apply || 'Apply')}\r\n\t\t\t\t\t</Button>\r\n\t\t\t\t{/if}\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Success hint -->\r\n\t\t\t{#if promoState.hint}\r\n\t\t\t\t<p class=\"promo-message success body-sm\" role=\"status\" aria-live=\"polite\">\r\n\t\t\t\t\t{promoState.hint}\r\n\t\t\t\t</p>\r\n\t\t\t{/if}\r\n\t\t</div>\r\n\t{/if}\r\n</div>\r\n\r\n<style>\r\n\t.promo-section {\r\n\t\tmargin-top: 1rem;\r\n\t}\r\n\r\n\t.promo-input-wrapper {\r\n\t\tdisplay: flex;\r\n\t\tgap: 0.5rem;\r\n\t\talign-items: flex-start;\r\n\t}\r\n\r\n\t.promo-message {\r\n\t\tmargin-top: 0.5rem;\r\n\t}\r\n\r\n\t.promo-message.success {\r\n\t\tcolor: hsl(var(--accent-success)); /* green-600 */\r\n\t}\r\n\r\n\t@keyframes promoSlideIn {\r\n\t\tfrom {\r\n\t\t\topacity: 0;\r\n\t\t\ttransform: translateY(-4px);\r\n\t\t}\r\n\r\n\t\tto {\r\n\t\t\topacity: 1;\r\n\t\t\ttransform: translateY(0);\r\n\t\t}\r\n\t}\r\n</style>\r\n"],"names":["tick","style","ms","donationAmount","isRevealedByPromo","isDiscountedByPromo","discountedPrice","labels","$","$$props","isDonation","isSoldOut","isComingSoon","isSalesEnded","isDisabled","scarcityLevel","getScarcityLevel","scarcityText","getScarcityText","donationValue","donationError","isDonationValid","canDecrement","canIncrement","decrement","newQty","asTicketId","increment","donationInputValue","syncDonation","totalPrice","priceDisplay","formatCurrency","feeCaption","salesStartDisplay","formatSmartSalesDate","article","root","div","div_1","div_2","Heading","node","Badge","$$anchor","ScarcityBadge","$$render","consequent","consequent_1","consequent_3","consequent_4","Text","consequent_5","div_3","node_2","div_4","root_13","Input","node_4","$$value","discountedTotal","span","fragment_9","span_1","span_2","root_15","consequent_7","span_3","root_16","span_4","fragment_10","span_5","root_18","consequent_10","consequent_9","alternate","consequent_11","div_5","Button","node_9","Subtract","span_6","node_10","Add","consequent_12","alternate_1","classes","DURATION","isExpanded","inputValue","handleApply","trimmed","handleRemove","handleKeydown","e","shouldExpand","root_3","$2","$3","node_1","p","root_8","consequent_2"],"mappings":"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"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import "svelte/internal/disclose-version";
|
|
2
2
|
import * as e from "svelte/internal/client";
|
|
3
3
|
import { g as E } from "./__SKIP_NAVIGATION__-CJ96TTPE.js";
|
|
4
|
-
import { E as w } from "./Event-
|
|
5
|
-
import { c as S } from "./VenueCalendar-
|
|
4
|
+
import { E as w } from "./Event-BNVO_E6j.js";
|
|
5
|
+
import { c as S } from "./VenueCalendar-BoSdP7xI.js";
|
|
6
6
|
import "svelte/transition";
|
|
7
7
|
import "svelte/easing";
|
|
8
|
-
import { a as C } from "./transform-
|
|
8
|
+
import { a as C } from "./transform-BrlBxayh.js";
|
|
9
9
|
function R(f, a) {
|
|
10
10
|
e.push(a, !0);
|
|
11
11
|
const m = S("SeriesPage");
|
|
12
12
|
let r = e.state(!1), i = e.state(null);
|
|
13
13
|
typeof window < "u" && new URLSearchParams(window.location.search).get("legacy") === "1" && e.set(r, !0), e.user_effect(() => {
|
|
14
|
-
e.get(r) && !e.get(i) && (m.warn("[VC] DEPRECATED: ?legacy=1 fallback for SeriesPage retires on 2026-08-13. See docs/LEGACY_RETIREMENT.md."), import("./SeriesPage.legacy-
|
|
14
|
+
e.get(r) && !e.get(i) && (m.warn("[VC] DEPRECATED: ?legacy=1 fallback for SeriesPage retires on 2026-08-13. See docs/LEGACY_RETIREMENT.md."), import("./SeriesPage.legacy-BlqTBr4n.js").then((t) => {
|
|
15
15
|
e.set(i, t.default, !0);
|
|
16
16
|
}).catch(() => {
|
|
17
17
|
e.set(r, !1);
|
|
@@ -52,4 +52,4 @@ function R(f, a) {
|
|
|
52
52
|
export {
|
|
53
53
|
R as default
|
|
54
54
|
};
|
|
55
|
-
//# sourceMappingURL=SeriesPage-
|
|
55
|
+
//# sourceMappingURL=SeriesPage-DEDSbKuu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SeriesPage-
|
|
1
|
+
{"version":3,"file":"SeriesPage-DEDSbKuu.js","sources":["../src/components/Views/SeriesPage.svelte"],"sourcesContent":["<script lang=\"ts\">\r\n\timport { goto } from '$app/navigation';\r\n\timport AirbnbSplitMain from '$lib/public-calendar-flow/Event.svelte';\r\n\timport { createLogger } from '@getmicdrop/svelte-components';\r\n\timport { transformSeriesPageData } from '$lib/public-calendar-flow/transform';\r\n\r\n\tconst logger = createLogger('SeriesPage');\r\n\r\n\t// --- Legacy fallback ---\r\n\t// RETIREMENT: 2026-08-13 — see docs/LEGACY_RETIREMENT.md.\r\n\tlet useLegacy = $state(false);\r\n\tlet LegacyComponent: any = $state(null);\r\n\r\n\tif (typeof window !== 'undefined') {\r\n\t\tconst params = new URLSearchParams(window.location.search);\r\n\t\tif (params.get('legacy') === '1') {\r\n\t\t\tuseLegacy = true;\r\n\t\t}\r\n\t}\r\n\r\n\t$effect(() => {\r\n\t\tif (useLegacy && !LegacyComponent) {\r\n\t\t\tlogger.warn(\r\n\t\t\t\t'[VC] DEPRECATED: ?legacy=1 fallback for SeriesPage retires on 2026-08-13. See docs/LEGACY_RETIREMENT.md.'\r\n\t\t\t);\r\n\t\t\timport('./SeriesPage.legacy.svelte').then((m) => {\r\n\t\t\t\tLegacyComponent = m.default;\r\n\t\t\t}).catch(() => {\r\n\t\t\t\tuseLegacy = false;\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\t// --- Props (matches old SeriesPage external interface) ---\r\n\tinterface Props {\r\n\t\tseries: any;\r\n\t\tonNavigateToOccurrence?: (id: number, slug: string, name?: string) => void;\r\n\t}\r\n\r\n\tlet {\r\n\t\tseries,\r\n\t\tonNavigateToOccurrence = undefined,\r\n\t}: Props = $props();\r\n\r\n\t// Transform series data to EventData for AirbnbSplitMain\r\n\tlet eventData = $derived(series ? transformSeriesPageData(series) : null);\r\n\r\n\t// Handle occurrence click — delegate to callback or navigate directly\r\n\tfunction handleShowtimeClick(occurrence: { id: number; slug: string }): void {\r\n\t\tif (onNavigateToOccurrence) {\r\n\t\t\tonNavigateToOccurrence(occurrence.id, occurrence.slug);\r\n\t\t} else {\r\n\t\t\t// @url-builder-escape: widget-internal route; SC's url-builders cover /a admin paths, not embedded calendar navigation.\r\n\t\t\tgoto(`/${occurrence.id}/${occurrence.slug}`);\r\n\t\t}\r\n\t}\r\n</script>\r\n\r\n{#if useLegacy && LegacyComponent}\r\n\t<svelte:component this={LegacyComponent}\r\n\t\t{series}\r\n\t\t{onNavigateToOccurrence}\r\n\t/>\r\n{:else if eventData}\r\n\t<AirbnbSplitMain\r\n\t\tevent={eventData}\r\n\t\tonShowtimeClick={handleShowtimeClick}\r\n\t/>\r\n{/if}\r\n\r\n"],"names":["logger","createLogger","useLegacy","$","LegacyComponent","m","onNavigateToOccurrence","eventData","$$props","transformSeriesPageData","handleShowtimeClick","occurrence","goto","$$anchor","$$component","AirbnbSplitMain","$$render","consequent","consequent_1"],"mappings":";;;;;;;;iBAAA;;QAMOA,IAASC,EAAa,YAAY;MAIpCC,IAAYC,EAAA,MAAO,EAAK,GACxBC,IAAuBD,EAAA,MAAO,IAAI;SAE3B,SAAW,WACF,gBAAgB,OAAO,SAAS,MAAM,EAC9C,IAAI,QAAQ,MAAM,OAC5BA,EAAA,IAAAD,GAAY,EAAI,GAIlBC,EAAA,kBAAc;UACTD,CAAS,KAAA,CAAAC,EAAA,IAAKC,CAAe,MAChCJ,EAAO,KACN,0GAA0G,GAEpG,OAAA,iCAA4B,EAAE,KAAI,CAAEK,MAAM;YAChDD,GAAkBC,EAAE,SAAO,EAAA;AAAA,IAC5B,CAAC,EAAE,MAAK,MAAO;AACd,MAAAF,EAAA,IAAAD,GAAY,EAAK;AAAA,IAClB,CAAC;AAAA,EAEH,CAAC;AAUA,MAAAI,2CAAyB,MAAS,GAI/BC,IAASJ,EAAA,QAAA,MAAAK,EAAA,SAAqBC,EAAuBD,EAAA,MAAA,IAAW,IAAI;WAG/DE,EAAoBC,GAAgD;AACxE,IAAAL,EAAsB,IACzBA,EAAsB,EAACK,EAAW,IAAIA,EAAW,IAAI,IAGrDC,MAASD,EAAW,EAAE,IAAIA,EAAW,IAAI,EAAA;AAAA,EAE3C;;;;;iCAIwBP,CAAe,GAAA,CAAAS,GAAAC,MAAA;;;;;;mBAErCR,EAAsB;AAAA;;;;AAGvBS,MAAAA,EAAeF,GAAA;AAAA;uBACRN,CAAS;AAAA;yBACCG;AAAA;;;YARdR,CAAS,KAAAC,EAAA,IAAIC,CAAe,IAAAY,EAAAC,CAAA,IAAAd,EAAA,IAKvBI,CAAS,KAAAS,EAAAE,GAAA,CAAA;AAAA;;;AAPX;"}
|