@withpotter/pages-bookings 0.13.0-next.101
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/dashboard/(bookings)/attendees/page.js +8 -0
- package/dist/dashboard/(bookings)/attendees/page.js.map +1 -0
- package/dist/dashboard/(bookings)/availability/_components/availability-screen.js +714 -0
- package/dist/dashboard/(bookings)/availability/_components/availability-screen.js.map +1 -0
- package/dist/dashboard/(bookings)/availability/_components/month-availability.js +130 -0
- package/dist/dashboard/(bookings)/availability/_components/month-availability.js.map +1 -0
- package/dist/dashboard/(bookings)/availability/page.js +10 -0
- package/dist/dashboard/(bookings)/availability/page.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/assign-resource-modal.js +133 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/assign-resource-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-constants.js +26 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-constants.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-desktop-layout.js +194 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-desktop-layout.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-layout-props.js +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-layout-props.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-lede.js +189 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-lede.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-meta.js +38 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-meta.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-mobile-layout.js +315 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-mobile-layout.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-mobile-screen.js +94 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-mobile-screen.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-money.js +54 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-money.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-split.js +71 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-split.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancel-booking-modal.js +102 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancel-booking-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancellation-notice.js +33 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancellation-notice.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/customer-info-card.js +65 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/customer-info-card.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/index.js +23 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/index.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/intake-answers-card.js +19 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/intake-answers-card.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/refund-booking-modal.js +156 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/refund-booking-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/reschedule-booking-modal.js +120 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/reschedule-booking-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/security-deposit-card.js +63 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/security-deposit-card.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/settle-deposit-modal.js +141 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/settle-deposit-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/ticket-row-actions.js +49 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/ticket-row-actions.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/waiting-queue-notice.js +42 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/waiting-queue-notice.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_components.js +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks/index.js +19 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks/index.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks/use-booking-detail-data.js +352 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks/use-booking-detail-data.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks.js +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/layout.js +33 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/layout.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/page.js +356 -0
- package/dist/dashboard/(bookings)/bookings/[bookingId]/page.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/appointment-calendar-layout.js +34 -0
- package/dist/dashboard/(bookings)/bookings/_components/appointment-calendar-layout.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/booking-constants.js +92 -0
- package/dist/dashboard/(bookings)/bookings/_components/booking-constants.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/booking-tab-hints.js +32 -0
- package/dist/dashboard/(bookings)/bookings/_components/booking-tab-hints.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/bookings-filter-bar.js +131 -0
- package/dist/dashboard/(bookings)/bookings/_components/bookings-filter-bar.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/bookings-mobile-controls.js +119 -0
- package/dist/dashboard/(bookings)/bookings/_components/bookings-mobile-controls.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/bookings-screen.js +414 -0
- package/dist/dashboard/(bookings)/bookings/_components/bookings-screen.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/bookings-table.js +192 -0
- package/dist/dashboard/(bookings)/bookings/_components/bookings-table.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/cannot-take-bookings.js +34 -0
- package/dist/dashboard/(bookings)/bookings/_components/cannot-take-bookings.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/demo-data.js +176 -0
- package/dist/dashboard/(bookings)/bookings/_components/demo-data.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/index.js +9 -0
- package/dist/dashboard/(bookings)/bookings/_components/index.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/booking-card.js +126 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/booking-card.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/demo-data.js +142 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/demo-data.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/handover.js +128 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/handover.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/index.js +17 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/index.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/past-band.js +69 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/past-band.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/resource-board.js +111 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/resource-board.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/today-band.js +61 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/today-band.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/upcoming-band.js +113 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/upcoming-band.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/waiting-queue.js +62 -0
- package/dist/dashboard/(bookings)/bookings/_components/today/waiting-queue.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today-board.js +192 -0
- package/dist/dashboard/(bookings)/bookings/_components/today-board.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_components/today.js +1 -0
- package/dist/dashboard/(bookings)/bookings/_components.js +1 -0
- package/dist/dashboard/(bookings)/bookings/_hooks/index.js +5 -0
- package/dist/dashboard/(bookings)/bookings/_hooks/index.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_hooks/use-bookings-data.js +331 -0
- package/dist/dashboard/(bookings)/bookings/_hooks/use-bookings-data.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_hooks/use-today-data.js +309 -0
- package/dist/dashboard/(bookings)/bookings/_hooks/use-today-data.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/_hooks.js +1 -0
- package/dist/dashboard/(bookings)/bookings/_lib/booking-link.js +13 -0
- package/dist/dashboard/(bookings)/bookings/_lib/booking-link.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/attendees/_components/attendee-cards.js +60 -0
- package/dist/dashboard/(bookings)/bookings/attendees/_components/attendee-cards.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/attendees/_components/qr-scanner-modal.js +225 -0
- package/dist/dashboard/(bookings)/bookings/attendees/_components/qr-scanner-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/attendees/demo-data.js +195 -0
- package/dist/dashboard/(bookings)/bookings/attendees/demo-data.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/attendees/page.js +341 -0
- package/dist/dashboard/(bookings)/bookings/attendees/page.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/new/page.js +129 -0
- package/dist/dashboard/(bookings)/bookings/new/page.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/page.js +10 -0
- package/dist/dashboard/(bookings)/bookings/page.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/sessions/new/_components/save-buttons.js +36 -0
- package/dist/dashboard/(bookings)/bookings/sessions/new/_components/save-buttons.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/sessions/new/_components/session-creator.js +386 -0
- package/dist/dashboard/(bookings)/bookings/sessions/new/_components/session-creator.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/sessions/new/_lib/session-payload.js +62 -0
- package/dist/dashboard/(bookings)/bookings/sessions/new/_lib/session-payload.js.map +1 -0
- package/dist/dashboard/(bookings)/bookings/sessions/new/page.js +10 -0
- package/dist/dashboard/(bookings)/bookings/sessions/new/page.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/calendar-nav.js +84 -0
- package/dist/dashboard/(bookings)/calendar/_components/calendar-nav.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/calendar-range.js +84 -0
- package/dist/dashboard/(bookings)/calendar/_components/calendar-range.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/day-board-view.js +279 -0
- package/dist/dashboard/(bookings)/calendar/_components/day-board-view.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/event-detail-modal.js +113 -0
- package/dist/dashboard/(bookings)/calendar/_components/event-detail-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/format.js +22 -0
- package/dist/dashboard/(bookings)/calendar/_components/format.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/month-grid.js +109 -0
- package/dist/dashboard/(bookings)/calendar/_components/month-grid.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/resource-day-grid.js +325 -0
- package/dist/dashboard/(bookings)/calendar/_components/resource-day-grid.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/slot-action-sheet.js +209 -0
- package/dist/dashboard/(bookings)/calendar/_components/slot-action-sheet.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/use-block-drag.js +77 -0
- package/dist/dashboard/(bookings)/calendar/_components/use-block-drag.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/use-calendar-nav.js +69 -0
- package/dist/dashboard/(bookings)/calendar/_components/use-calendar-nav.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/week-grid.js +202 -0
- package/dist/dashboard/(bookings)/calendar/_components/week-grid.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/_components/year-grid.js +111 -0
- package/dist/dashboard/(bookings)/calendar/_components/year-grid.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar/page.js +8 -0
- package/dist/dashboard/(bookings)/calendar/page.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar-sync/_components/channel-feed-modal.js +126 -0
- package/dist/dashboard/(bookings)/calendar-sync/_components/channel-feed-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar-sync/_components/channel-feeds-section.js +99 -0
- package/dist/dashboard/(bookings)/calendar-sync/_components/channel-feeds-section.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar-sync/demo-data.js +64 -0
- package/dist/dashboard/(bookings)/calendar-sync/demo-data.js.map +1 -0
- package/dist/dashboard/(bookings)/calendar-sync/page.js +15 -0
- package/dist/dashboard/(bookings)/calendar-sync/page.js.map +1 -0
- package/dist/dashboard/(bookings)/check-in/page.js +252 -0
- package/dist/dashboard/(bookings)/check-in/page.js.map +1 -0
- package/dist/dashboard/(bookings)/events/[eventId]/_components/event-attendees.js +108 -0
- package/dist/dashboard/(bookings)/events/[eventId]/_components/event-attendees.js.map +1 -0
- package/dist/dashboard/(bookings)/events/[eventId]/_components/event-share.js +73 -0
- package/dist/dashboard/(bookings)/events/[eventId]/_components/event-share.js.map +1 -0
- package/dist/dashboard/(bookings)/events/[eventId]/layout.js +10 -0
- package/dist/dashboard/(bookings)/events/[eventId]/layout.js.map +1 -0
- package/dist/dashboard/(bookings)/events/[eventId]/page.js +247 -0
- package/dist/dashboard/(bookings)/events/[eventId]/page.js.map +1 -0
- package/dist/dashboard/(bookings)/events/_components/event-grid.js +44 -0
- package/dist/dashboard/(bookings)/events/_components/event-grid.js.map +1 -0
- package/dist/dashboard/(bookings)/events/_components/event-poster.js +17 -0
- package/dist/dashboard/(bookings)/events/_components/event-poster.js.map +1 -0
- package/dist/dashboard/(bookings)/events/_hooks/use-events-data.js +55 -0
- package/dist/dashboard/(bookings)/events/_hooks/use-events-data.js.map +1 -0
- package/dist/dashboard/(bookings)/events/_lib/event-facts.js +68 -0
- package/dist/dashboard/(bookings)/events/_lib/event-facts.js.map +1 -0
- package/dist/dashboard/(bookings)/events/new/_components/event-composer.js +295 -0
- package/dist/dashboard/(bookings)/events/new/_components/event-composer.js.map +1 -0
- package/dist/dashboard/(bookings)/events/new/_components/event-poster.js +65 -0
- package/dist/dashboard/(bookings)/events/new/_components/event-poster.js.map +1 -0
- package/dist/dashboard/(bookings)/events/new/_components/ticket-tiers.js +75 -0
- package/dist/dashboard/(bookings)/events/new/_components/ticket-tiers.js.map +1 -0
- package/dist/dashboard/(bookings)/events/new/page.js +10 -0
- package/dist/dashboard/(bookings)/events/new/page.js.map +1 -0
- package/dist/dashboard/(bookings)/events/page.js +214 -0
- package/dist/dashboard/(bookings)/events/page.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/[resourceId]/layout.js +36 -0
- package/dist/dashboard/(bookings)/resources/[resourceId]/layout.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/[resourceId]/page.js +351 -0
- package/dist/dashboard/(bookings)/resources/[resourceId]/page.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/block-time-modal.js +130 -0
- package/dist/dashboard/(bookings)/resources/_components/block-time-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/category-card.js +74 -0
- package/dist/dashboard/(bookings)/resources/_components/category-card.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/category-form-dialog.js +197 -0
- package/dist/dashboard/(bookings)/resources/_components/category-form-dialog.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/day-editor.js +194 -0
- package/dist/dashboard/(bookings)/resources/_components/day-editor.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/group-dialog.js +170 -0
- package/dist/dashboard/(bookings)/resources/_components/group-dialog.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/group-header.js +90 -0
- package/dist/dashboard/(bookings)/resources/_components/group-header.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/index.js +22 -0
- package/dist/dashboard/(bookings)/resources/_components/index.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/mobile-category-form-sheet.js +256 -0
- package/dist/dashboard/(bookings)/resources/_components/mobile-category-form-sheet.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/resource-form.js +420 -0
- package/dist/dashboard/(bookings)/resources/_components/resource-form.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/resource-picker.js +144 -0
- package/dist/dashboard/(bookings)/resources/_components/resource-picker.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/resource-type-picker-empty.js +109 -0
- package/dist/dashboard/(bookings)/resources/_components/resource-type-picker-empty.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/roster-empty.js +103 -0
- package/dist/dashboard/(bookings)/resources/_components/roster-empty.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/roster-grid.js +160 -0
- package/dist/dashboard/(bookings)/resources/_components/roster-grid.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/schedule-editor.js +244 -0
- package/dist/dashboard/(bookings)/resources/_components/schedule-editor.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/schedule-timezone-field.js +25 -0
- package/dist/dashboard/(bookings)/resources/_components/schedule-timezone-field.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/solo-schedule-view.js +146 -0
- package/dist/dashboard/(bookings)/resources/_components/solo-schedule-view.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/team-onboarding-dialog.js +161 -0
- package/dist/dashboard/(bookings)/resources/_components/team-onboarding-dialog.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components/week-grid.js +175 -0
- package/dist/dashboard/(bookings)/resources/_components/week-grid.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_components.js +1 -0
- package/dist/dashboard/(bookings)/resources/_hooks/index.js +8 -0
- package/dist/dashboard/(bookings)/resources/_hooks/index.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_hooks/use-resource-categories-data.js +86 -0
- package/dist/dashboard/(bookings)/resources/_hooks/use-resource-categories-data.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_hooks/use-roster-page.js +138 -0
- package/dist/dashboard/(bookings)/resources/_hooks/use-roster-page.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_hooks/use-roster.js +182 -0
- package/dist/dashboard/(bookings)/resources/_hooks/use-roster.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_hooks.js +1 -0
- package/dist/dashboard/(bookings)/resources/_lib/presets.js +147 -0
- package/dist/dashboard/(bookings)/resources/_lib/presets.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_lib/schedule-timezone.js +17 -0
- package/dist/dashboard/(bookings)/resources/_lib/schedule-timezone.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_lib/shapes.js +105 -0
- package/dist/dashboard/(bookings)/resources/_lib/shapes.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/_lib/week.js +122 -0
- package/dist/dashboard/(bookings)/resources/_lib/week.js.map +1 -0
- package/dist/dashboard/(bookings)/resources/page.js +391 -0
- package/dist/dashboard/(bookings)/resources/page.js.map +1 -0
- package/dist/dashboard/(bookings)/schedule/page.js +8 -0
- package/dist/dashboard/(bookings)/schedule/page.js.map +1 -0
- package/dist/dashboard/(bookings)/today/page.js +14 -0
- package/dist/dashboard/(bookings)/today/page.js.map +1 -0
- package/dist/dashboard/(bookings)/waitlist/_components/demo-data.js +99 -0
- package/dist/dashboard/(bookings)/waitlist/_components/demo-data.js.map +1 -0
- package/dist/dashboard/(bookings)/waitlist/_components/offer-spot-modal.js +71 -0
- package/dist/dashboard/(bookings)/waitlist/_components/offer-spot-modal.js.map +1 -0
- package/dist/dashboard/(bookings)/waitlist/_components/waitlist-entry-editor.js +150 -0
- package/dist/dashboard/(bookings)/waitlist/_components/waitlist-entry-editor.js.map +1 -0
- package/dist/dashboard/(bookings)/waitlist/new/page.js +59 -0
- package/dist/dashboard/(bookings)/waitlist/new/page.js.map +1 -0
- package/dist/dashboard/(bookings)/waitlist/page.js +317 -0
- package/dist/dashboard/(bookings)/waitlist/page.js.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/bookings/%5BbookingId%5D/_components/booking-split.tsx"],"sourcesContent":["import type { SplitBooking } from '@withpotter/lib/api/types';\n\ninterface BookingSplitProps {\n split: SplitBooking;\n formatCurrency: (n: number) => string;\n}\n\nconst STATUS: Record<SplitParticipantStatus, { label: string; cls: string }> = {\n paid: { label: 'Paid', cls: 'bg-[var(--success-bg)] text-[var(--success)]' },\n pending: {\n label: 'Pending',\n cls: 'bg-[var(--warning-bg)] text-[var(--warning)]',\n },\n cancelled: {\n label: 'Out',\n cls: 'bg-[var(--bg-muted)] text-[var(--text-muted)]',\n },\n};\n\ntype SplitParticipantStatus = SplitBooking['participants'][number]['status'];\n\n/**\n * The group/split state of a booking: who's in, each person's share, and who\n * has paid. Vertical-agnostic — a group class, a group dinner, or a shared\n * class all split the same way. Read-only view for the desk; joining/paying a\n * share is a customer-side action.\n */\nexport function BookingSplit({ split, formatCurrency }: BookingSplitProps) {\n const { participants, summary } = split;\n\n return (\n <div className=\"max-lg:bg-[var(--bg-subtle)] max-lg:rounded-ios-lg lg:surface overflow-hidden\">\n <div className=\"flex items-center justify-between border-b border-[var(--border-subtle)] px-4 py-3 lg:bg-[var(--bg-subtle)]\">\n <h2 className=\"font-semibold text-[var(--text-primary)]\">\n Group split\n </h2>\n <span className=\"text-xs font-medium text-[var(--text-tertiary)]\">\n {summary.paidCount}/{summary.activeCount} paid\n </span>\n </div>\n\n <div className=\"p-4 space-y-3\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-[var(--text-secondary)]\">Collected</span>\n <span className=\"font-medium text-[var(--text-primary)]\">\n {formatCurrency(summary.paidTotal)} of{' '}\n {formatCurrency(summary.pledgedTotal)}\n </span>\n </div>\n {summary.outstanding > 0 && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-[var(--text-secondary)]\">Outstanding</span>\n <span className=\"font-semibold text-[var(--warning)]\">\n {formatCurrency(summary.outstanding)}\n </span>\n </div>\n )}\n\n <div className=\"divide-y divide-[var(--border-subtle)] border-t border-[var(--border-subtle)] pt-1\">\n {participants.map((p) => {\n const s = STATUS[p.status];\n return (\n <div\n key={p.id}\n className=\"flex items-center justify-between gap-3 py-2\"\n >\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-[var(--text-primary)]\">\n {p.name}\n </p>\n {(p.email || p.phone) && (\n <p className=\"truncate text-xs text-[var(--text-tertiary)]\">\n {p.email || p.phone}\n </p>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <span className=\"text-sm text-[var(--text-primary)]\">\n {formatCurrency(Number(p.shareAmount))}\n </span>\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${s.cls}`}\n >\n {s.label}\n </span>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"AAiCQ,cAGA,YAHA;AA1BR,MAAM,SAAyE;AAAA,EAC7E,MAAM,EAAE,OAAO,QAAQ,KAAK,+CAA+C;AAAA,EAC3E,SAAS;AAAA,IACP,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,WAAW;AAAA,IACT,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AACF;AAUO,SAAS,aAAa,EAAE,OAAO,eAAe,GAAsB;AACzE,QAAM,EAAE,cAAc,QAAQ,IAAI;AAElC,SACE,qBAAC,SAAI,WAAU,iFACb;AAAA,yBAAC,SAAI,WAAU,+GACb;AAAA,0BAAC,QAAG,WAAU,4CAA2C,yBAEzD;AAAA,MACA,qBAAC,UAAK,WAAU,mDACb;AAAA,gBAAQ;AAAA,QAAU;AAAA,QAAE,QAAQ;AAAA,QAAY;AAAA,SAC3C;AAAA,OACF;AAAA,IAEA,qBAAC,SAAI,WAAU,iBACb;AAAA,2BAAC,SAAI,WAAU,gCACb;AAAA,4BAAC,UAAK,WAAU,gCAA+B,uBAAS;AAAA,QACxD,qBAAC,UAAK,WAAU,0CACb;AAAA,yBAAe,QAAQ,SAAS;AAAA,UAAE;AAAA,UAAI;AAAA,UACtC,eAAe,QAAQ,YAAY;AAAA,WACtC;AAAA,SACF;AAAA,MACC,QAAQ,cAAc,KACrB,qBAAC,SAAI,WAAU,gCACb;AAAA,4BAAC,UAAK,WAAU,gCAA+B,yBAAW;AAAA,QAC1D,oBAAC,UAAK,WAAU,uCACb,yBAAe,QAAQ,WAAW,GACrC;AAAA,SACF;AAAA,MAGF,oBAAC,SAAI,WAAU,sFACZ,uBAAa,IAAI,CAAC,MAAM;AACvB,cAAM,IAAI,OAAO,EAAE,MAAM;AACzB,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YAEV;AAAA,mCAAC,SAAI,WAAU,WACb;AAAA,oCAAC,OAAE,WAAU,2DACV,YAAE,MACL;AAAA,iBACE,EAAE,SAAS,EAAE,UACb,oBAAC,OAAE,WAAU,gDACV,YAAE,SAAS,EAAE,OAChB;AAAA,iBAEJ;AAAA,cACA,qBAAC,SAAI,WAAU,oCACb;AAAA,oCAAC,UAAK,WAAU,sCACb,yBAAe,OAAO,EAAE,WAAW,CAAC,GACvC;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW,yEAAyE,EAAE,GAAG;AAAA,oBAExF,YAAE;AAAA;AAAA,gBACL;AAAA,iBACF;AAAA;AAAA;AAAA,UAtBK,EAAE;AAAA,QAuBT;AAAA,MAEJ,CAAC,GACH;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { RefreshCw, XCircle } from "lucide-react";
|
|
4
|
+
import {
|
|
5
|
+
Dialog,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogHeader,
|
|
8
|
+
DialogTitle,
|
|
9
|
+
DialogDescription,
|
|
10
|
+
DialogFooter
|
|
11
|
+
} from "@withpotter/ui-kit/dialog";
|
|
12
|
+
import { WaitingQueueNotice } from "./waiting-queue-notice";
|
|
13
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
14
|
+
import { Textarea } from "@withpotter/ui-kit";
|
|
15
|
+
function CancelBookingModal({
|
|
16
|
+
bookingNumber,
|
|
17
|
+
customerName,
|
|
18
|
+
bookingDate,
|
|
19
|
+
resourceId,
|
|
20
|
+
cancelReason,
|
|
21
|
+
setCancelReason,
|
|
22
|
+
handleCancel,
|
|
23
|
+
updatingStatus,
|
|
24
|
+
onClose
|
|
25
|
+
}) {
|
|
26
|
+
return /* @__PURE__ */ jsx(
|
|
27
|
+
Dialog,
|
|
28
|
+
{
|
|
29
|
+
open: true,
|
|
30
|
+
onOpenChange: (o) => {
|
|
31
|
+
if (!o) onClose();
|
|
32
|
+
},
|
|
33
|
+
children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-md", children: [
|
|
34
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
35
|
+
/* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
|
|
36
|
+
/* @__PURE__ */ jsx(XCircle, { className: "size-5 text-[var(--error)]" }),
|
|
37
|
+
"Cancel booking"
|
|
38
|
+
] }),
|
|
39
|
+
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
40
|
+
"Are you sure you want to cancel booking",
|
|
41
|
+
" ",
|
|
42
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
43
|
+
"#",
|
|
44
|
+
bookingNumber
|
|
45
|
+
] }),
|
|
46
|
+
customerName && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
47
|
+
" ",
|
|
48
|
+
"for ",
|
|
49
|
+
/* @__PURE__ */ jsx("strong", { children: customerName })
|
|
50
|
+
] }),
|
|
51
|
+
"?"
|
|
52
|
+
] })
|
|
53
|
+
] }),
|
|
54
|
+
/* @__PURE__ */ jsx(WaitingQueueNotice, { date: bookingDate, resourceId }),
|
|
55
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
56
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-[var(--text-tertiary)]", children: "Reason (optional)" }),
|
|
57
|
+
/* @__PURE__ */ jsx(
|
|
58
|
+
Textarea,
|
|
59
|
+
{
|
|
60
|
+
value: cancelReason,
|
|
61
|
+
onChange: (e) => setCancelReason(e.target.value),
|
|
62
|
+
placeholder: "Enter cancellation reason...",
|
|
63
|
+
rows: 3,
|
|
64
|
+
className: "w-full resize-none"
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
] }),
|
|
68
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
69
|
+
/* @__PURE__ */ jsx(
|
|
70
|
+
"button",
|
|
71
|
+
{
|
|
72
|
+
type: "button",
|
|
73
|
+
onClick: onClose,
|
|
74
|
+
className: "px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]",
|
|
75
|
+
children: "Keep booking"
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
Button,
|
|
80
|
+
{
|
|
81
|
+
variant: "danger",
|
|
82
|
+
className: "hover:opacity-90",
|
|
83
|
+
onClick: handleCancel,
|
|
84
|
+
disabled: updatingStatus,
|
|
85
|
+
children: updatingStatus ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
86
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: "size-4 animate-spin" }),
|
|
87
|
+
"Cancelling..."
|
|
88
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
89
|
+
/* @__PURE__ */ jsx(XCircle, { className: "size-4" }),
|
|
90
|
+
"Cancel booking"
|
|
91
|
+
] })
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
] })
|
|
95
|
+
] })
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
CancelBookingModal
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=cancel-booking-modal.js.map
|
package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancel-booking-modal.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/bookings/%5BbookingId%5D/_components/cancel-booking-modal.tsx"],"sourcesContent":["'use client';\n\nimport { RefreshCw, XCircle } from 'lucide-react';\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogDescription,\n DialogFooter,\n} from '@withpotter/ui-kit/dialog';\nimport { WaitingQueueNotice } from './waiting-queue-notice';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Textarea } from '@withpotter/ui-kit';\n\ninterface CancelBookingModalProps {\n bookingNumber: string;\n customerName?: string;\n /** The slot being freed, so the waiting queue for it can be shown. */\n bookingDate?: string;\n resourceId?: string;\n cancelReason: string;\n setCancelReason: (reason: string) => void;\n handleCancel: () => void;\n updatingStatus: boolean;\n onClose: () => void;\n}\n\nexport function CancelBookingModal({\n bookingNumber,\n customerName,\n bookingDate,\n resourceId,\n cancelReason,\n setCancelReason,\n handleCancel,\n updatingStatus,\n onClose,\n}: CancelBookingModalProps) {\n return (\n <Dialog\n open\n onOpenChange={(o) => {\n if (!o) onClose();\n }}\n >\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <XCircle className=\"size-5 text-[var(--error)]\" />\n Cancel booking\n </DialogTitle>\n <DialogDescription>\n Are you sure you want to cancel booking{' '}\n <strong>#{bookingNumber}</strong>\n {customerName && (\n <>\n {' '}\n for <strong>{customerName}</strong>\n </>\n )}\n ?\n </DialogDescription>\n </DialogHeader>\n\n <WaitingQueueNotice date={bookingDate} resourceId={resourceId} />\n\n <div>\n <label className=\"mb-1 block text-xs font-medium text-[var(--text-tertiary)]\">\n Reason (optional)\n </label>\n <Textarea\n value={cancelReason}\n onChange={(e) => setCancelReason(e.target.value)}\n placeholder=\"Enter cancellation reason...\"\n rows={3}\n className=\"w-full resize-none\"\n />\n </div>\n\n <DialogFooter>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]\"\n >\n Keep booking\n </button>\n <Button\n variant=\"danger\"\n className=\"hover:opacity-90\"\n onClick={handleCancel}\n disabled={updatingStatus}\n >\n {updatingStatus ? (\n <>\n <RefreshCw className=\"size-4 animate-spin\" />\n Cancelling...\n </>\n ) : (\n <>\n <XCircle className=\"size-4\" />\n Cancel booking\n </>\n )}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";AAgDU,SAQI,UAPF,KADF;AA9CV,SAAS,WAAW,eAAe;AACnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;AACnC,SAAS,cAAc;AACvB,SAAS,gBAAgB;AAelB,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAI;AAAA,MACJ,cAAc,CAAC,MAAM;AACnB,YAAI,CAAC,EAAG,SAAQ;AAAA,MAClB;AAAA,MAEA,+BAAC,iBAAc,WAAU,YACvB;AAAA,6BAAC,gBACC;AAAA,+BAAC,eAAY,WAAU,2BACrB;AAAA,gCAAC,WAAQ,WAAU,8BAA6B;AAAA,YAAE;AAAA,aAEpD;AAAA,UACA,qBAAC,qBAAkB;AAAA;AAAA,YACuB;AAAA,YACxC,qBAAC,YAAO;AAAA;AAAA,cAAE;AAAA,eAAc;AAAA,YACvB,gBACC,iCACG;AAAA;AAAA,cAAI;AAAA,cACD,oBAAC,YAAQ,wBAAa;AAAA,eAC5B;AAAA,YACA;AAAA,aAEJ;AAAA,WACF;AAAA,QAEA,oBAAC,sBAAmB,MAAM,aAAa,YAAwB;AAAA,QAE/D,qBAAC,SACC;AAAA,8BAAC,WAAM,WAAU,8DAA6D,+BAE9E;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,gBAAgB,EAAE,OAAO,KAAK;AAAA,cAC/C,aAAY;AAAA,cACZ,MAAM;AAAA,cACN,WAAU;AAAA;AAAA,UACZ;AAAA,WACF;AAAA,QAEA,qBAAC,gBACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,WAAU;AAAA,cACV,SAAS;AAAA,cACT,UAAU;AAAA,cAET,2BACC,iCACE;AAAA,oCAAC,aAAU,WAAU,uBAAsB;AAAA,gBAAE;AAAA,iBAE/C,IAEA,iCACE;AAAA,oCAAC,WAAQ,WAAU,UAAS;AAAA,gBAAE;AAAA,iBAEhC;AAAA;AAAA,UAEJ;AAAA,WACF;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { AlertCircle, CheckCircle2 } from "lucide-react";
|
|
4
|
+
function CancellationNotice({
|
|
5
|
+
metadata
|
|
6
|
+
}) {
|
|
7
|
+
const data = metadata;
|
|
8
|
+
if (data?.withinFreeCancellationWindow === void 0) return null;
|
|
9
|
+
const inWindow = data.withinFreeCancellationWindow;
|
|
10
|
+
const hours = data.hoursBeforeStart;
|
|
11
|
+
const when = typeof hours === "number" ? hours >= 1 ? `${Math.round(hours)}h before the start` : hours >= 0 ? "less than an hour before the start" : `${Math.abs(Math.round(hours))}h after it was due to start` : null;
|
|
12
|
+
return /* @__PURE__ */ jsxs(
|
|
13
|
+
"div",
|
|
14
|
+
{
|
|
15
|
+
className: `flex items-start gap-3 rounded-md border p-3 ${inWindow ? "border-[var(--border-subtle)] bg-[var(--bg-subtle)]" : "border-[var(--warning)]/25 bg-[var(--warning-bg)]"}`,
|
|
16
|
+
children: [
|
|
17
|
+
inWindow ? /* @__PURE__ */ jsx(CheckCircle2, { className: "mt-px size-4 shrink-0 text-[var(--text-tertiary)]" }) : /* @__PURE__ */ jsx(AlertCircle, { className: "mt-px size-4 shrink-0 text-[var(--warning)]" }),
|
|
18
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm", children: [
|
|
19
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[var(--text-primary)]", children: [
|
|
20
|
+
inWindow ? "Cancelled inside the free window" : "Cancelled outside the free window",
|
|
21
|
+
when ? `, ${when}` : "",
|
|
22
|
+
"."
|
|
23
|
+
] }),
|
|
24
|
+
data.cancellationReason ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[var(--text-tertiary)]", children: data.cancellationReason }) : null
|
|
25
|
+
] })
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
CancellationNotice
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=cancellation-notice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/bookings/%5BbookingId%5D/_components/cancellation-notice.tsx"],"sourcesContent":["'use client';\n\nimport { AlertCircle, CheckCircle2 } from 'lucide-react';\n\n/**\n * Whether a cancellation landed inside the free window, and by how much.\n *\n * `cancel-booking` has computed this since the policy was written — it reads\n * the tenant's `freeCancellationHours`, works out the hours to the start and\n * writes `withinFreeCancellationWindow` and `hoursBeforeStart` onto the\n * booking. Nothing ever showed it, so the one fact that decides whether a\n * deposit gets returned was sitting on the record where only the database\n * could see it.\n *\n * It states the fact and stops. Whether to refund is the merchant's call and\n * the refund action is already on this page; a screen that decided for them\n * would be enforcing a policy the money rails cannot enforce.\n */\nexport function CancellationNotice({\n metadata,\n}: {\n metadata?: Record<string, unknown>;\n}) {\n const data = metadata as\n | {\n withinFreeCancellationWindow?: boolean;\n hoursBeforeStart?: number;\n cancellationReason?: string;\n }\n | undefined;\n\n if (data?.withinFreeCancellationWindow === undefined) return null;\n\n const inWindow = data.withinFreeCancellationWindow;\n const hours = data.hoursBeforeStart;\n const when =\n typeof hours === 'number'\n ? hours >= 1\n ? `${Math.round(hours)}h before the start`\n : hours >= 0\n ? 'less than an hour before the start'\n : `${Math.abs(Math.round(hours))}h after it was due to start`\n : null;\n\n return (\n <div\n className={`flex items-start gap-3 rounded-md border p-3 ${\n inWindow\n ? 'border-[var(--border-subtle)] bg-[var(--bg-subtle)]'\n : 'border-[var(--warning)]/25 bg-[var(--warning-bg)]'\n }`}\n >\n {inWindow ? (\n <CheckCircle2 className=\"mt-px size-4 shrink-0 text-[var(--text-tertiary)]\" />\n ) : (\n <AlertCircle className=\"mt-px size-4 shrink-0 text-[var(--warning)]\" />\n )}\n <div className=\"text-sm\">\n <p className=\"text-[var(--text-primary)]\">\n {inWindow\n ? 'Cancelled inside the free window'\n : 'Cancelled outside the free window'}\n {when ? `, ${when}` : ''}.\n </p>\n {data.cancellationReason ? (\n <p className=\"mt-0.5 text-[var(--text-tertiary)]\">\n {data.cancellationReason}\n </p>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":";AAqDQ,cAKA,YALA;AAnDR,SAAS,aAAa,oBAAoB;AAgBnC,SAAS,mBAAmB;AAAA,EACjC;AACF,GAEG;AACD,QAAM,OAAO;AAQb,MAAI,MAAM,iCAAiC,OAAW,QAAO;AAE7D,QAAM,WAAW,KAAK;AACtB,QAAM,QAAQ,KAAK;AACnB,QAAM,OACJ,OAAO,UAAU,WACb,SAAS,IACP,GAAG,KAAK,MAAM,KAAK,CAAC,uBACpB,SAAS,IACP,uCACA,GAAG,KAAK,IAAI,KAAK,MAAM,KAAK,CAAC,CAAC,gCAClC;AAEN,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,gDACT,WACI,wDACA,mDACN;AAAA,MAEC;AAAA,mBACC,oBAAC,gBAAa,WAAU,qDAAoD,IAE5E,oBAAC,eAAY,WAAU,+CAA8C;AAAA,QAEvE,qBAAC,SAAI,WAAU,WACb;AAAA,+BAAC,OAAE,WAAU,8BACV;AAAA,uBACG,qCACA;AAAA,YACH,OAAO,KAAK,IAAI,KAAK;AAAA,YAAG;AAAA,aAC3B;AAAA,UACC,KAAK,qBACJ,oBAAC,OAAE,WAAU,sCACV,eAAK,oBACR,IACE;AAAA,WACN;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { Mail, Phone } from "lucide-react";
|
|
5
|
+
import { Avatar, Card } from "@withpotter/ui-kit";
|
|
6
|
+
function CustomerInfoCard({
|
|
7
|
+
memberId,
|
|
8
|
+
customerName,
|
|
9
|
+
customerEmail,
|
|
10
|
+
customerPhone
|
|
11
|
+
}) {
|
|
12
|
+
const name = customerName || "Guest";
|
|
13
|
+
const identity = /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-3", children: [
|
|
14
|
+
/* @__PURE__ */ jsx(Avatar, { name, size: "sm" }),
|
|
15
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
|
|
16
|
+
/* @__PURE__ */ jsx(
|
|
17
|
+
"span",
|
|
18
|
+
{
|
|
19
|
+
className: `block truncate font-medium text-[var(--text-primary)] ${memberId ? "underline-offset-2 group-hover:underline" : ""}`,
|
|
20
|
+
children: name
|
|
21
|
+
}
|
|
22
|
+
),
|
|
23
|
+
memberId && /* @__PURE__ */ jsx("span", { className: "block text-xs text-[var(--text-tertiary)]", children: "See their record" })
|
|
24
|
+
] })
|
|
25
|
+
] });
|
|
26
|
+
return /* @__PURE__ */ jsxs(Card, { className: "space-y-3", children: [
|
|
27
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-medium text-[var(--text-primary)]", children: "Customer" }),
|
|
28
|
+
memberId ? /* @__PURE__ */ jsx(
|
|
29
|
+
Link,
|
|
30
|
+
{
|
|
31
|
+
href: `/dashboard/customers/${memberId}`,
|
|
32
|
+
className: "group block transition-opacity hover:opacity-90",
|
|
33
|
+
children: identity
|
|
34
|
+
}
|
|
35
|
+
) : identity,
|
|
36
|
+
(customerPhone || customerEmail) && /* @__PURE__ */ jsxs("div", { className: "space-y-2 border-t border-[var(--border-subtle)] pt-3", children: [
|
|
37
|
+
customerPhone && /* @__PURE__ */ jsxs(
|
|
38
|
+
"a",
|
|
39
|
+
{
|
|
40
|
+
href: `tel:${customerPhone}`,
|
|
41
|
+
className: "flex items-center gap-2 text-sm text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]",
|
|
42
|
+
children: [
|
|
43
|
+
/* @__PURE__ */ jsx(Phone, { className: "shrink-0 text-[var(--text-tertiary)]" }),
|
|
44
|
+
customerPhone
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
),
|
|
48
|
+
customerEmail && /* @__PURE__ */ jsxs(
|
|
49
|
+
"a",
|
|
50
|
+
{
|
|
51
|
+
href: `mailto:${customerEmail}`,
|
|
52
|
+
className: "flex items-center gap-2 text-sm text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]",
|
|
53
|
+
children: [
|
|
54
|
+
/* @__PURE__ */ jsx(Mail, { className: "shrink-0 text-[var(--text-tertiary)]" }),
|
|
55
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: customerEmail })
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
] })
|
|
60
|
+
] });
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
CustomerInfoCard
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=customer-info-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/bookings/%5BbookingId%5D/_components/customer-info-card.tsx"],"sourcesContent":["'use client';\n\nimport Link from 'next/link';\nimport { Mail, Phone } from 'lucide-react';\nimport { Avatar, Card } from '@withpotter/ui-kit';\n\ninterface CustomerInfoCardProps {\n memberId?: string;\n customerName?: string;\n customerEmail?: string;\n customerPhone?: string;\n}\n\n/**\n * Who the booking is for.\n *\n * THE EMAIL WAS PRINTED TWICE — once as the line under the name and again as a\n * mail row two lines below it, so a customer with no phone number had their\n * address on the screen twice and nothing else. The name and the face are the\n * identity; the ways to reach them are the rows, and each way appears once.\n *\n * A generic `User` glyph in a grey circle stood in for the avatar. Every other\n * person in the app wears `Avatar`, which generates a mark from the name when\n * there is no photo — so this was the one place a customer had no face.\n */\nexport function CustomerInfoCard({\n memberId,\n customerName,\n customerEmail,\n customerPhone,\n}: CustomerInfoCardProps) {\n const name = customerName || 'Guest';\n\n const identity = (\n <span className=\"flex items-center gap-3\">\n <Avatar name={name} size=\"sm\" />\n <span className=\"min-w-0\">\n <span\n className={`block truncate font-medium text-[var(--text-primary)] ${memberId ? 'underline-offset-2 group-hover:underline' : ''}`}\n >\n {name}\n </span>\n {memberId && (\n <span className=\"block text-xs text-[var(--text-tertiary)]\">\n See their record\n </span>\n )}\n </span>\n </span>\n );\n\n return (\n <Card className=\"space-y-3\">\n <h2 className=\"text-sm font-medium text-[var(--text-primary)]\">\n Customer\n </h2>\n\n {memberId ? (\n <Link\n href={`/dashboard/customers/${memberId}`}\n className=\"group block transition-opacity hover:opacity-90\"\n >\n {identity}\n </Link>\n ) : (\n identity\n )}\n\n {(customerPhone || customerEmail) && (\n <div className=\"space-y-2 border-t border-[var(--border-subtle)] pt-3\">\n {/* The phone first: a desk that needs the customer picks it up. */}\n {customerPhone && (\n <a\n href={`tel:${customerPhone}`}\n className=\"flex items-center gap-2 text-sm text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]\"\n >\n <Phone className=\"shrink-0 text-[var(--text-tertiary)]\" />\n {customerPhone}\n </a>\n )}\n {customerEmail && (\n <a\n href={`mailto:${customerEmail}`}\n className=\"flex items-center gap-2 text-sm text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]\"\n >\n <Mail className=\"shrink-0 text-[var(--text-tertiary)]\" />\n <span className=\"truncate\">{customerEmail}</span>\n </a>\n )}\n </div>\n )}\n </Card>\n );\n}\n"],"mappings":";AAmCM,cACA,YADA;AAjCN,OAAO,UAAU;AACjB,SAAS,MAAM,aAAa;AAC5B,SAAS,QAAQ,YAAY;AAqBtB,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,OAAO,gBAAgB;AAE7B,QAAM,WACJ,qBAAC,UAAK,WAAU,2BACd;AAAA,wBAAC,UAAO,MAAY,MAAK,MAAK;AAAA,IAC9B,qBAAC,UAAK,WAAU,WACd;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,yDAAyD,WAAW,6CAA6C,EAAE;AAAA,UAE7H;AAAA;AAAA,MACH;AAAA,MACC,YACC,oBAAC,UAAK,WAAU,6CAA4C,8BAE5D;AAAA,OAEJ;AAAA,KACF;AAGF,SACE,qBAAC,QAAK,WAAU,aACd;AAAA,wBAAC,QAAG,WAAU,kDAAiD,sBAE/D;AAAA,IAEC,WACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,wBAAwB,QAAQ;AAAA,QACtC,WAAU;AAAA,QAET;AAAA;AAAA,IACH,IAEA;AAAA,KAGA,iBAAiB,kBACjB,qBAAC,SAAI,WAAU,yDAEZ;AAAA,uBACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,OAAO,aAAa;AAAA,UAC1B,WAAU;AAAA,UAEV;AAAA,gCAAC,SAAM,WAAU,wCAAuC;AAAA,YACvD;AAAA;AAAA;AAAA,MACH;AAAA,MAED,iBACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,UAAU,aAAa;AAAA,UAC7B,WAAU;AAAA,UAEV;AAAA,gCAAC,QAAK,WAAU,wCAAuC;AAAA,YACvD,oBAAC,UAAK,WAAU,YAAY,yBAAc;AAAA;AAAA;AAAA,MAC5C;AAAA,OAEJ;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CancelBookingModal } from "./cancel-booking-modal";
|
|
2
|
+
import { CustomerInfoCard } from "./customer-info-card";
|
|
3
|
+
import { BookingMoney } from "./booking-money";
|
|
4
|
+
import { BookingSplit } from "./booking-split";
|
|
5
|
+
import { RescheduleBookingModal } from "./reschedule-booking-modal";
|
|
6
|
+
import { RefundBookingModal } from "./refund-booking-modal";
|
|
7
|
+
import { SecurityDepositCard } from "./security-deposit-card";
|
|
8
|
+
import { SettleDepositModal } from "./settle-deposit-modal";
|
|
9
|
+
import { IntakeAnswersCard } from "./intake-answers-card";
|
|
10
|
+
import { CancellationNotice } from "./cancellation-notice";
|
|
11
|
+
export {
|
|
12
|
+
BookingMoney,
|
|
13
|
+
BookingSplit,
|
|
14
|
+
CancelBookingModal,
|
|
15
|
+
CancellationNotice,
|
|
16
|
+
CustomerInfoCard,
|
|
17
|
+
IntakeAnswersCard,
|
|
18
|
+
RefundBookingModal,
|
|
19
|
+
RescheduleBookingModal,
|
|
20
|
+
SecurityDepositCard,
|
|
21
|
+
SettleDepositModal
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/bookings/%5BbookingId%5D/_components/index.ts"],"sourcesContent":["export { CancelBookingModal } from './cancel-booking-modal';\nexport { CustomerInfoCard } from './customer-info-card';\nexport { BookingMoney } from './booking-money';\nexport { BookingSplit } from './booking-split';\nexport { RescheduleBookingModal } from './reschedule-booking-modal';\nexport { RefundBookingModal } from './refund-booking-modal';\nexport { SecurityDepositCard } from './security-deposit-card';\nexport { SettleDepositModal } from './settle-deposit-modal';\nexport { IntakeAnswersCard } from './intake-answers-card';\nexport { CancellationNotice } from './cancellation-notice';\n"],"mappings":"AAAA,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,2BAA2B;AACpC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,0BAA0B;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { AnswersList } from "@withpotter/components/shared/answers-list";
|
|
4
|
+
import { toAnswers } from "@withpotter/lib/form-answers";
|
|
5
|
+
function IntakeAnswersCard({
|
|
6
|
+
metadata
|
|
7
|
+
}) {
|
|
8
|
+
const intake = metadata?.intake;
|
|
9
|
+
const answers = toAnswers(intake);
|
|
10
|
+
if (answers.length === 0) return null;
|
|
11
|
+
return /* @__PURE__ */ jsxs("div", { className: "max-lg:bg-[var(--bg-subtle)] max-lg:rounded-ios-lg lg:surface overflow-hidden", children: [
|
|
12
|
+
/* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b border-[var(--border-subtle)] lg:bg-[var(--bg-subtle)]", children: /* @__PURE__ */ jsx("h2", { className: "font-semibold text-[var(--text-primary)]", children: "Before the appointment" }) }),
|
|
13
|
+
/* @__PURE__ */ jsx(AnswersList, { answers, className: "px-4 py-1" })
|
|
14
|
+
] });
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
IntakeAnswersCard
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=intake-answers-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/bookings/%5BbookingId%5D/_components/intake-answers-card.tsx"],"sourcesContent":["'use client';\n\nimport { AnswersList } from '@withpotter/components/shared/answers-list';\nimport { toAnswers } from '@withpotter/lib/form-answers';\n\n/**\n * What the service asked before the day, and what the customer said.\n *\n * A clinic that asks about medication and cannot see the answer on the day has\n * collected a liability rather than an answer. Read out of the booking's own\n * metadata, which is where the create screen and the storefront both put it.\n *\n * Keyed by the field key the service defined, so an answer whose question has\n * since been renamed or deleted still shows rather than vanishing with it.\n *\n * The shaping is `toAnswers`, shared with the enquiry inbox. This file used to\n * do it inline as `String(value)` against the raw key, which is why a date\n * arrived as `2026-12-12` and a tick box as `true`. Two surfaces reading two\n * metadata blobs had one job between them, and now have one implementation.\n */\nexport function IntakeAnswersCard({\n metadata,\n}: {\n metadata?: Record<string, unknown>;\n}) {\n const intake = (metadata as { intake?: Record<string, unknown> } | undefined)\n ?.intake;\n const answers = toAnswers(intake);\n\n if (answers.length === 0) return null;\n\n return (\n <div className=\"max-lg:bg-[var(--bg-subtle)] max-lg:rounded-ios-lg lg:surface overflow-hidden\">\n <div className=\"px-4 py-3 border-b border-[var(--border-subtle)] lg:bg-[var(--bg-subtle)]\">\n <h2 className=\"font-semibold text-[var(--text-primary)]\">\n Before the appointment\n </h2>\n </div>\n <AnswersList answers={answers} className=\"px-4 py-1\" />\n </div>\n );\n}\n"],"mappings":";AAgCI,SAEI,KAFJ;AA9BJ,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAiBnB,SAAS,kBAAkB;AAAA,EAChC;AACF,GAEG;AACD,QAAM,SAAU,UACZ;AACJ,QAAM,UAAU,UAAU,MAAM;AAEhC,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SACE,qBAAC,SAAI,WAAU,iFACb;AAAA,wBAAC,SAAI,WAAU,6EACb,8BAAC,QAAG,WAAU,4CAA2C,oCAEzD,GACF;AAAA,IACA,oBAAC,eAAY,SAAkB,WAAU,aAAY;AAAA,KACvD;AAEJ;","names":[]}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import { RefreshCw, Undo2 } from "lucide-react";
|
|
5
|
+
import {
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogContent,
|
|
8
|
+
DialogHeader,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
DialogDescription,
|
|
11
|
+
DialogFooter
|
|
12
|
+
} from "@withpotter/ui-kit/dialog";
|
|
13
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
14
|
+
import { Input, ErrorBanner } from "@withpotter/ui-kit";
|
|
15
|
+
function RefundBookingModal({
|
|
16
|
+
bookingNumber,
|
|
17
|
+
entries,
|
|
18
|
+
formatCurrency,
|
|
19
|
+
refunding,
|
|
20
|
+
error,
|
|
21
|
+
onRefund,
|
|
22
|
+
onClose
|
|
23
|
+
}) {
|
|
24
|
+
const refundable = useMemo(
|
|
25
|
+
() => entries.filter((e) => e.type === "payment").map((e) => ({ ...e, remaining: e.amount - e.refundedAmount })).filter((e) => e.remaining > 0),
|
|
26
|
+
[entries]
|
|
27
|
+
);
|
|
28
|
+
const [selectedId, setSelectedId] = useState(refundable[0]?.id ?? "");
|
|
29
|
+
const selected = refundable.find((e) => e.id === selectedId);
|
|
30
|
+
const [amount, setAmount] = useState(
|
|
31
|
+
refundable[0] ? String(refundable[0].remaining) : ""
|
|
32
|
+
);
|
|
33
|
+
const [reason, setReason] = useState("");
|
|
34
|
+
const pick = (id) => {
|
|
35
|
+
setSelectedId(id);
|
|
36
|
+
const entry = refundable.find((e) => e.id === id);
|
|
37
|
+
if (entry) setAmount(String(entry.remaining));
|
|
38
|
+
};
|
|
39
|
+
const numericAmount = Number(amount);
|
|
40
|
+
const canSubmit = !!selected && numericAmount > 0 && numericAmount <= selected.remaining && !refunding;
|
|
41
|
+
return /* @__PURE__ */ jsx(
|
|
42
|
+
Dialog,
|
|
43
|
+
{
|
|
44
|
+
open: true,
|
|
45
|
+
onOpenChange: (o) => {
|
|
46
|
+
if (!o) onClose();
|
|
47
|
+
},
|
|
48
|
+
children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-md", children: [
|
|
49
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
50
|
+
/* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
|
|
51
|
+
/* @__PURE__ */ jsx(Undo2, { className: "size-5 text-[var(--text-tertiary)]" }),
|
|
52
|
+
"Refund"
|
|
53
|
+
] }),
|
|
54
|
+
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
55
|
+
"Return money collected on #",
|
|
56
|
+
bookingNumber,
|
|
57
|
+
"."
|
|
58
|
+
] })
|
|
59
|
+
] }),
|
|
60
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
61
|
+
error && /* @__PURE__ */ jsx(ErrorBanner, { children: error }),
|
|
62
|
+
refundable.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--text-tertiary)]", children: "There is nothing left to refund on this booking." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
63
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
64
|
+
/* @__PURE__ */ jsx("label", { className: "mb-2 block text-xs font-medium text-[var(--text-tertiary)]", children: "Payment to refund" }),
|
|
65
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2", children: refundable.map((e) => {
|
|
66
|
+
const on = e.id === selectedId;
|
|
67
|
+
return /* @__PURE__ */ jsx(
|
|
68
|
+
"button",
|
|
69
|
+
{
|
|
70
|
+
type: "button",
|
|
71
|
+
onClick: () => pick(e.id),
|
|
72
|
+
className: `flex w-full items-center justify-between rounded-lg border px-3 py-2 text-left transition-colors ${on ? "border-brand-500/40 bg-[var(--accent-secondary)]" : "border-[var(--border-default)] bg-[var(--bg-base)] hover:bg-[var(--interactive-hover)]"}`,
|
|
73
|
+
children: /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
|
|
74
|
+
/* @__PURE__ */ jsxs("span", { className: "block text-sm font-medium text-[var(--text-primary)]", children: [
|
|
75
|
+
formatCurrency(e.remaining),
|
|
76
|
+
" available"
|
|
77
|
+
] }),
|
|
78
|
+
/* @__PURE__ */ jsxs("span", { className: "block truncate text-xs text-[var(--text-tertiary)]", children: [
|
|
79
|
+
e.channel || "payment",
|
|
80
|
+
" \xB7 ",
|
|
81
|
+
e.reference
|
|
82
|
+
] })
|
|
83
|
+
] })
|
|
84
|
+
},
|
|
85
|
+
e.id
|
|
86
|
+
);
|
|
87
|
+
}) })
|
|
88
|
+
] }),
|
|
89
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
90
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-[var(--text-tertiary)]", children: "Amount" }),
|
|
91
|
+
/* @__PURE__ */ jsx(
|
|
92
|
+
Input,
|
|
93
|
+
{
|
|
94
|
+
type: "number",
|
|
95
|
+
inputMode: "decimal",
|
|
96
|
+
min: 0,
|
|
97
|
+
max: selected?.remaining,
|
|
98
|
+
value: amount,
|
|
99
|
+
onChange: (e) => setAmount(e.target.value)
|
|
100
|
+
}
|
|
101
|
+
),
|
|
102
|
+
selected && numericAmount > selected.remaining && /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-[var(--error)]", children: [
|
|
103
|
+
"Can\u2019t exceed ",
|
|
104
|
+
formatCurrency(selected.remaining),
|
|
105
|
+
"."
|
|
106
|
+
] })
|
|
107
|
+
] }),
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
109
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-[var(--text-tertiary)]", children: "Reason (optional)" }),
|
|
110
|
+
/* @__PURE__ */ jsx(
|
|
111
|
+
Input,
|
|
112
|
+
{
|
|
113
|
+
value: reason,
|
|
114
|
+
onChange: (e) => setReason(e.target.value),
|
|
115
|
+
placeholder: "e.g. customer cancelled in time"
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
] })
|
|
119
|
+
] })
|
|
120
|
+
] }),
|
|
121
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
122
|
+
/* @__PURE__ */ jsx(
|
|
123
|
+
"button",
|
|
124
|
+
{
|
|
125
|
+
type: "button",
|
|
126
|
+
onClick: onClose,
|
|
127
|
+
className: "px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]",
|
|
128
|
+
children: "Cancel"
|
|
129
|
+
}
|
|
130
|
+
),
|
|
131
|
+
/* @__PURE__ */ jsx(
|
|
132
|
+
Button,
|
|
133
|
+
{
|
|
134
|
+
variant: "danger",
|
|
135
|
+
className: "hover:opacity-90",
|
|
136
|
+
onClick: () => selected && onRefund({
|
|
137
|
+
transactionId: selected.id,
|
|
138
|
+
amount: numericAmount,
|
|
139
|
+
reason: reason || void 0
|
|
140
|
+
}),
|
|
141
|
+
disabled: !canSubmit,
|
|
142
|
+
children: refunding ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
143
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: "size-4 animate-spin" }),
|
|
144
|
+
"Refunding..."
|
|
145
|
+
] }) : "Refund"
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
] })
|
|
149
|
+
] })
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
RefundBookingModal
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=refund-booking-modal.js.map
|
package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/refund-booking-modal.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/bookings/%5BbookingId%5D/_components/refund-booking-modal.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo, useState } from 'react';\nimport { RefreshCw, Undo2 } from 'lucide-react';\nimport type { BookingFinanceEntry } from '@withpotter/lib/api/types';\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogDescription,\n DialogFooter,\n} from '@withpotter/ui-kit/dialog';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Input, ErrorBanner } from '@withpotter/ui-kit';\n\ninterface RefundBookingModalProps {\n bookingNumber: string;\n entries: BookingFinanceEntry[];\n formatCurrency: (n: number) => string;\n refunding: boolean;\n error?: string | null;\n onRefund: (data: {\n transactionId: string;\n amount: number;\n reason?: string;\n }) => void;\n onClose: () => void;\n}\n\n/**\n * Refund a specific payment on the booking. Lists the refundable payments\n * (a payment with money still un-refunded), caps the amount at what remains,\n * and posts to POST /bookings/:id/refunds. Vertical-agnostic.\n */\nexport function RefundBookingModal({\n bookingNumber,\n entries,\n formatCurrency,\n refunding,\n error,\n onRefund,\n onClose,\n}: RefundBookingModalProps) {\n const refundable = useMemo(\n () =>\n entries\n .filter((e) => e.type === 'payment')\n .map((e) => ({ ...e, remaining: e.amount - e.refundedAmount }))\n .filter((e) => e.remaining > 0),\n [entries],\n );\n\n const [selectedId, setSelectedId] = useState(refundable[0]?.id ?? '');\n const selected = refundable.find((e) => e.id === selectedId);\n const [amount, setAmount] = useState(\n refundable[0] ? String(refundable[0].remaining) : '',\n );\n const [reason, setReason] = useState('');\n\n const pick = (id: string) => {\n setSelectedId(id);\n const entry = refundable.find((e) => e.id === id);\n if (entry) setAmount(String(entry.remaining));\n };\n\n const numericAmount = Number(amount);\n const canSubmit =\n !!selected &&\n numericAmount > 0 &&\n numericAmount <= selected.remaining &&\n !refunding;\n\n return (\n <Dialog\n open\n onOpenChange={(o) => {\n if (!o) onClose();\n }}\n >\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <Undo2 className=\"size-5 text-[var(--text-tertiary)]\" />\n Refund\n </DialogTitle>\n <DialogDescription>\n Return money collected on #{bookingNumber}.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n {error && <ErrorBanner>{error}</ErrorBanner>}\n\n {refundable.length === 0 ? (\n <p className=\"text-sm text-[var(--text-tertiary)]\">\n There is nothing left to refund on this booking.\n </p>\n ) : (\n <>\n <div>\n <label className=\"mb-2 block text-xs font-medium text-[var(--text-tertiary)]\">\n Payment to refund\n </label>\n <div className=\"space-y-2\">\n {refundable.map((e) => {\n const on = e.id === selectedId;\n return (\n <button\n key={e.id}\n type=\"button\"\n onClick={() => pick(e.id)}\n className={`flex w-full items-center justify-between rounded-lg border px-3 py-2 text-left transition-colors ${\n on\n ? 'border-brand-500/40 bg-[var(--accent-secondary)]'\n : 'border-[var(--border-default)] bg-[var(--bg-base)] hover:bg-[var(--interactive-hover)]'\n }`}\n >\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-medium text-[var(--text-primary)]\">\n {formatCurrency(e.remaining)} available\n </span>\n <span className=\"block truncate text-xs text-[var(--text-tertiary)]\">\n {e.channel || 'payment'} · {e.reference}\n </span>\n </span>\n </button>\n );\n })}\n </div>\n </div>\n\n <div>\n <label className=\"mb-1 block text-xs font-medium text-[var(--text-tertiary)]\">\n Amount\n </label>\n <Input\n type=\"number\"\n inputMode=\"decimal\"\n min={0}\n max={selected?.remaining}\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n />\n {selected && numericAmount > selected.remaining && (\n <p className=\"mt-1 text-xs text-[var(--error)]\">\n Can’t exceed {formatCurrency(selected.remaining)}.\n </p>\n )}\n </div>\n\n <div>\n <label className=\"mb-1 block text-xs font-medium text-[var(--text-tertiary)]\">\n Reason (optional)\n </label>\n <Input\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n placeholder=\"e.g. customer cancelled in time\"\n />\n </div>\n </>\n )}\n </div>\n\n <DialogFooter>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]\"\n >\n Cancel\n </button>\n <Button\n variant=\"danger\"\n className=\"hover:opacity-90\"\n onClick={() =>\n selected &&\n onRefund({\n transactionId: selected.id,\n amount: numericAmount,\n reason: reason || undefined,\n })\n }\n disabled={!canSubmit}\n >\n {refunding ? (\n <>\n <RefreshCw className=\"size-4 animate-spin\" />\n Refunding...\n </>\n ) : (\n 'Refund'\n )}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";AAkFU,SAiBE,UAhBA,KADF;AAhFV,SAAS,SAAS,gBAAgB;AAClC,SAAS,WAAW,aAAa;AAEjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AACvB,SAAS,OAAO,mBAAmB;AAqB5B,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,aAAa;AAAA,IACjB,MACE,QACG,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS,EAClC,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,EAC7D,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA,IAClC,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,WAAW,CAAC,GAAG,MAAM,EAAE;AACpE,QAAM,WAAW,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AAC3D,QAAM,CAAC,QAAQ,SAAS,IAAI;AAAA,IAC1B,WAAW,CAAC,IAAI,OAAO,WAAW,CAAC,EAAE,SAAS,IAAI;AAAA,EACpD;AACA,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,EAAE;AAEvC,QAAM,OAAO,CAAC,OAAe;AAC3B,kBAAc,EAAE;AAChB,UAAM,QAAQ,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAChD,QAAI,MAAO,WAAU,OAAO,MAAM,SAAS,CAAC;AAAA,EAC9C;AAEA,QAAM,gBAAgB,OAAO,MAAM;AACnC,QAAM,YACJ,CAAC,CAAC,YACF,gBAAgB,KAChB,iBAAiB,SAAS,aAC1B,CAAC;AAEH,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAI;AAAA,MACJ,cAAc,CAAC,MAAM;AACnB,YAAI,CAAC,EAAG,SAAQ;AAAA,MAClB;AAAA,MAEA,+BAAC,iBAAc,WAAU,YACvB;AAAA,6BAAC,gBACC;AAAA,+BAAC,eAAY,WAAU,2BACrB;AAAA,gCAAC,SAAM,WAAU,sCAAqC;AAAA,YAAE;AAAA,aAE1D;AAAA,UACA,qBAAC,qBAAkB;AAAA;AAAA,YACW;AAAA,YAAc;AAAA,aAC5C;AAAA,WACF;AAAA,QAEA,qBAAC,SAAI,WAAU,aACZ;AAAA,mBAAS,oBAAC,eAAa,iBAAM;AAAA,UAE7B,WAAW,WAAW,IACrB,oBAAC,OAAE,WAAU,uCAAsC,8DAEnD,IAEA,iCACE;AAAA,iCAAC,SACC;AAAA,kCAAC,WAAM,WAAU,8DAA6D,+BAE9E;AAAA,cACA,oBAAC,SAAI,WAAU,aACZ,qBAAW,IAAI,CAAC,MAAM;AACrB,sBAAM,KAAK,EAAE,OAAO;AACpB,uBACE;AAAA,kBAAC;AAAA;AAAA,oBAEC,MAAK;AAAA,oBACL,SAAS,MAAM,KAAK,EAAE,EAAE;AAAA,oBACxB,WAAW,oGACT,KACI,qDACA,wFACN;AAAA,oBAEA,+BAAC,UAAK,WAAU,WACd;AAAA,2CAAC,UAAK,WAAU,wDACb;AAAA,uCAAe,EAAE,SAAS;AAAA,wBAAE;AAAA,yBAC/B;AAAA,sBACA,qBAAC,UAAK,WAAU,sDACb;AAAA,0BAAE,WAAW;AAAA,wBAAU;AAAA,wBAAI,EAAE;AAAA,yBAChC;AAAA,uBACF;AAAA;AAAA,kBAhBK,EAAE;AAAA,gBAiBT;AAAA,cAEJ,CAAC,GACH;AAAA,eACF;AAAA,YAEA,qBAAC,SACC;AAAA,kCAAC,WAAM,WAAU,8DAA6D,oBAE9E;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,KAAK;AAAA,kBACL,KAAK,UAAU;AAAA,kBACf,OAAO;AAAA,kBACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA;AAAA,cAC3C;AAAA,cACC,YAAY,gBAAgB,SAAS,aACpC,qBAAC,OAAE,WAAU,oCAAmC;AAAA;AAAA,gBAChC,eAAe,SAAS,SAAS;AAAA,gBAAE;AAAA,iBACnD;AAAA,eAEJ;AAAA,YAEA,qBAAC,SACC;AAAA,kCAAC,WAAM,WAAU,8DAA6D,+BAE9E;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,kBACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,kBACzC,aAAY;AAAA;AAAA,cACd;AAAA,eACF;AAAA,aACF;AAAA,WAEJ;AAAA,QAEA,qBAAC,gBACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,WAAU;AAAA,cACV,SAAS,MACP,YACA,SAAS;AAAA,gBACP,eAAe,SAAS;AAAA,gBACxB,QAAQ;AAAA,gBACR,QAAQ,UAAU;AAAA,cACpB,CAAC;AAAA,cAEH,UAAU,CAAC;AAAA,cAEV,sBACC,iCACE;AAAA,oCAAC,aAAU,WAAU,uBAAsB;AAAA,gBAAE;AAAA,iBAE/C,IAEA;AAAA;AAAA,UAEJ;AAAA,WACF;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/reschedule-booking-modal.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { CalendarClock, RefreshCw } from "lucide-react";
|
|
5
|
+
import {
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogContent,
|
|
8
|
+
DialogHeader,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
DialogDescription,
|
|
11
|
+
DialogFooter
|
|
12
|
+
} from "@withpotter/ui-kit/dialog";
|
|
13
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
14
|
+
import { DateField } from "@withpotter/ui-kit/date-field";
|
|
15
|
+
import { TimeField } from "@withpotter/ui-kit/time-field";
|
|
16
|
+
import { Textarea, ErrorBanner } from "@withpotter/ui-kit";
|
|
17
|
+
function RescheduleBookingModal({
|
|
18
|
+
entityLabel,
|
|
19
|
+
bookingNumber,
|
|
20
|
+
initialDate,
|
|
21
|
+
initialStartTime,
|
|
22
|
+
initialEndTime,
|
|
23
|
+
rescheduling,
|
|
24
|
+
error,
|
|
25
|
+
onReschedule,
|
|
26
|
+
onClose
|
|
27
|
+
}) {
|
|
28
|
+
const [date, setDate] = useState(initialDate ? initialDate.slice(0, 10) : "");
|
|
29
|
+
const [startTime, setStartTime] = useState(initialStartTime ?? "");
|
|
30
|
+
const [endTime, setEndTime] = useState(initialEndTime ?? "");
|
|
31
|
+
const [reason, setReason] = useState("");
|
|
32
|
+
const canSubmit = Boolean(date && startTime) && !rescheduling;
|
|
33
|
+
return /* @__PURE__ */ jsx(
|
|
34
|
+
Dialog,
|
|
35
|
+
{
|
|
36
|
+
open: true,
|
|
37
|
+
onOpenChange: (o) => {
|
|
38
|
+
if (!o) onClose();
|
|
39
|
+
},
|
|
40
|
+
children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-md", children: [
|
|
41
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
42
|
+
/* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
|
|
43
|
+
/* @__PURE__ */ jsx(CalendarClock, { className: "size-5 text-[var(--text-tertiary)]" }),
|
|
44
|
+
"Reschedule ",
|
|
45
|
+
entityLabel.toLowerCase()
|
|
46
|
+
] }),
|
|
47
|
+
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
48
|
+
"Move #",
|
|
49
|
+
bookingNumber,
|
|
50
|
+
" to a new slot. The new time is checked for conflicts."
|
|
51
|
+
] })
|
|
52
|
+
] }),
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
54
|
+
error && /* @__PURE__ */ jsx(ErrorBanner, { children: error }),
|
|
55
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
56
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-[var(--text-tertiary)]", children: "New date" }),
|
|
57
|
+
/* @__PURE__ */ jsx(DateField, { value: date, onChange: setDate })
|
|
58
|
+
] }),
|
|
59
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
60
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
61
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-[var(--text-tertiary)]", children: "Start time" }),
|
|
62
|
+
/* @__PURE__ */ jsx(TimeField, { value: startTime, onChange: setStartTime })
|
|
63
|
+
] }),
|
|
64
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
65
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-[var(--text-tertiary)]", children: "End time" }),
|
|
66
|
+
/* @__PURE__ */ jsx(TimeField, { value: endTime, onChange: setEndTime })
|
|
67
|
+
] })
|
|
68
|
+
] }),
|
|
69
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
70
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-[var(--text-tertiary)]", children: "Reason (optional)" }),
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
Textarea,
|
|
73
|
+
{
|
|
74
|
+
value: reason,
|
|
75
|
+
onChange: (e) => setReason(e.target.value),
|
|
76
|
+
rows: 2,
|
|
77
|
+
placeholder: "e.g. customer requested a later time",
|
|
78
|
+
className: "resize-none"
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
] })
|
|
82
|
+
] }),
|
|
83
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
"button",
|
|
86
|
+
{
|
|
87
|
+
type: "button",
|
|
88
|
+
onClick: onClose,
|
|
89
|
+
className: "px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]",
|
|
90
|
+
children: "Cancel"
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
/* @__PURE__ */ jsx(
|
|
94
|
+
Button,
|
|
95
|
+
{
|
|
96
|
+
onClick: () => onReschedule({
|
|
97
|
+
date,
|
|
98
|
+
startTime,
|
|
99
|
+
endTime: endTime || void 0,
|
|
100
|
+
reason: reason || void 0
|
|
101
|
+
}),
|
|
102
|
+
disabled: !canSubmit,
|
|
103
|
+
children: rescheduling ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
104
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: "size-4 animate-spin" }),
|
|
105
|
+
"Rescheduling..."
|
|
106
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
107
|
+
/* @__PURE__ */ jsx(CalendarClock, { className: "size-4" }),
|
|
108
|
+
"Reschedule"
|
|
109
|
+
] })
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
] })
|
|
113
|
+
] })
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
export {
|
|
118
|
+
RescheduleBookingModal
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=reschedule-booking-modal.js.map
|
package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/reschedule-booking-modal.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/bookings/%5BbookingId%5D/_components/reschedule-booking-modal.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { CalendarClock, RefreshCw } from 'lucide-react';\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogDescription,\n DialogFooter,\n} from '@withpotter/ui-kit/dialog';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { DateField } from '@withpotter/ui-kit/date-field';\nimport { TimeField } from '@withpotter/ui-kit/time-field';\nimport { Textarea, ErrorBanner } from '@withpotter/ui-kit';\n\ninterface RescheduleBookingModalProps {\n /** Config-driven entity noun, e.g. \"Reservation\" / \"Appointment\" / \"Booking\". */\n entityLabel: string;\n bookingNumber: string;\n initialDate: string;\n initialStartTime?: string;\n initialEndTime?: string;\n rescheduling: boolean;\n /** Conflict / validation message from the server (e.g. slot taken). */\n error?: string | null;\n onReschedule: (data: {\n date: string;\n startTime: string;\n endTime?: string;\n reason?: string;\n }) => void;\n onClose: () => void;\n}\n\n/**\n * Reschedule a booking to a new slot. Vertical-agnostic: the noun comes from\n * config (`entityLabel`), so it reads \"Reschedule reservation\" for dine-in,\n * \"Reschedule appointment\" for services, etc. The server re-checks the new\n * slot for conflicts and surfaces the reason back through `error`.\n */\nexport function RescheduleBookingModal({\n entityLabel,\n bookingNumber,\n initialDate,\n initialStartTime,\n initialEndTime,\n rescheduling,\n error,\n onReschedule,\n onClose,\n}: RescheduleBookingModalProps) {\n const [date, setDate] = useState(initialDate ? initialDate.slice(0, 10) : '');\n const [startTime, setStartTime] = useState(initialStartTime ?? '');\n const [endTime, setEndTime] = useState(initialEndTime ?? '');\n const [reason, setReason] = useState('');\n const canSubmit = Boolean(date && startTime) && !rescheduling;\n\n return (\n <Dialog\n open\n onOpenChange={(o) => {\n if (!o) onClose();\n }}\n >\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <CalendarClock className=\"size-5 text-[var(--text-tertiary)]\" />\n Reschedule {entityLabel.toLowerCase()}\n </DialogTitle>\n <DialogDescription>\n Move #{bookingNumber} to a new slot. The new time is checked for\n conflicts.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n {error && <ErrorBanner>{error}</ErrorBanner>}\n <div>\n <label className=\"mb-1 block text-xs font-medium text-[var(--text-tertiary)]\">\n New date\n </label>\n <DateField value={date} onChange={setDate} />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"mb-1 block text-xs font-medium text-[var(--text-tertiary)]\">\n Start time\n </label>\n <TimeField value={startTime} onChange={setStartTime} />\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium text-[var(--text-tertiary)]\">\n End time\n </label>\n <TimeField value={endTime} onChange={setEndTime} />\n </div>\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium text-[var(--text-tertiary)]\">\n Reason (optional)\n </label>\n <Textarea\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n rows={2}\n placeholder=\"e.g. customer requested a later time\"\n className=\"resize-none\"\n />\n </div>\n </div>\n\n <DialogFooter>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]\"\n >\n Cancel\n </button>\n <Button\n onClick={() =>\n onReschedule({\n date,\n startTime,\n endTime: endTime || undefined,\n reason: reason || undefined,\n })\n }\n disabled={!canSubmit}\n >\n {rescheduling ? (\n <>\n <RefreshCw className=\"size-4 animate-spin\" />\n Rescheduling...\n </>\n ) : (\n <>\n <CalendarClock className=\"size-4\" />\n Reschedule\n </>\n )}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
|