@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,194 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Plus, X } from "lucide-react";
|
|
5
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
6
|
+
import { FormDialog } from "@withpotter/ui-kit/form-dialog";
|
|
7
|
+
import { ErrorBanner } from "@withpotter/ui-kit/error-banner";
|
|
8
|
+
import { Field } from "@withpotter/ui-kit/field";
|
|
9
|
+
import { Input } from "@withpotter/ui-kit";
|
|
10
|
+
import { TimeField } from "@withpotter/ui-kit/time-field";
|
|
11
|
+
import { ToggleRow } from "@withpotter/ui-kit/toggle";
|
|
12
|
+
import {
|
|
13
|
+
DAY_LONG,
|
|
14
|
+
WEEK_DAYS,
|
|
15
|
+
blocksOn,
|
|
16
|
+
businessSlots,
|
|
17
|
+
daySlots,
|
|
18
|
+
isoDay
|
|
19
|
+
} from "../_lib/week";
|
|
20
|
+
function DayEditor({
|
|
21
|
+
row,
|
|
22
|
+
date,
|
|
23
|
+
hours,
|
|
24
|
+
blocks,
|
|
25
|
+
saving,
|
|
26
|
+
onSave,
|
|
27
|
+
onClose
|
|
28
|
+
}) {
|
|
29
|
+
const dow = date.getDay();
|
|
30
|
+
const iso = isoDay(date);
|
|
31
|
+
const own = daySlots(row.schedule, dow);
|
|
32
|
+
const inherited = own === void 0;
|
|
33
|
+
const resolved = inherited ? businessSlots(hours, dow) : own;
|
|
34
|
+
const existing = blocksOn(blocks, row.id, iso);
|
|
35
|
+
const [working, setWorking] = useState(!!resolved);
|
|
36
|
+
const [slots, setSlots] = useState(
|
|
37
|
+
resolved?.length ? resolved : [{ start: "09:00", end: "17:00" }]
|
|
38
|
+
);
|
|
39
|
+
const [timeOff, setTimeOff] = useState(existing.length > 0);
|
|
40
|
+
const [reason, setReason] = useState(existing[0]?.title ?? "");
|
|
41
|
+
const [error, setError] = useState(null);
|
|
42
|
+
const dateLabel = date.toLocaleDateString("en-GB", {
|
|
43
|
+
weekday: "short",
|
|
44
|
+
day: "numeric",
|
|
45
|
+
month: "short"
|
|
46
|
+
});
|
|
47
|
+
const setSlot = (index, part, value) => setSlots(
|
|
48
|
+
(prev) => prev.map((slot, i) => i === index ? { ...slot, [part]: value } : slot)
|
|
49
|
+
);
|
|
50
|
+
const nextSchedule = () => {
|
|
51
|
+
const week = {};
|
|
52
|
+
for (const day of WEEK_DAYS) {
|
|
53
|
+
const existingDay = daySlots(row.schedule, day);
|
|
54
|
+
const base = existingDay === void 0 ? businessSlots(hours, day) : existingDay;
|
|
55
|
+
week[day] = base ? { available: true, slots: base } : { available: false };
|
|
56
|
+
}
|
|
57
|
+
week[dow] = working ? { available: true, slots } : { available: false };
|
|
58
|
+
return week;
|
|
59
|
+
};
|
|
60
|
+
const handleSave = async () => {
|
|
61
|
+
if (working) {
|
|
62
|
+
const bad = slots.find((s) => !s.start || !s.end || s.end <= s.start);
|
|
63
|
+
if (bad) {
|
|
64
|
+
setError("Each shift needs an end time after its start.");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
setError(null);
|
|
69
|
+
const change = { schedule: nextSchedule() };
|
|
70
|
+
if (timeOff && existing.length === 0) {
|
|
71
|
+
const first = working && slots.length ? slots[0].start : "00:00";
|
|
72
|
+
const last = working && slots.length ? slots[slots.length - 1].end : "23:59";
|
|
73
|
+
change.block = {
|
|
74
|
+
date: iso,
|
|
75
|
+
startTime: first,
|
|
76
|
+
endTime: last,
|
|
77
|
+
reason: reason.trim() || void 0
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (!timeOff && existing.length > 0) {
|
|
81
|
+
change.unblock = {
|
|
82
|
+
date: iso,
|
|
83
|
+
startTime: new Date(existing[0].start).toTimeString().slice(0, 5)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
await onSave(change);
|
|
87
|
+
};
|
|
88
|
+
return /* @__PURE__ */ jsx(
|
|
89
|
+
FormDialog,
|
|
90
|
+
{
|
|
91
|
+
title: `${row.name}, ${DAY_LONG[dow]}`,
|
|
92
|
+
onClose,
|
|
93
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
94
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Cancel" }),
|
|
95
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleSave, loading: saving, children: "Save" })
|
|
96
|
+
] }),
|
|
97
|
+
children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
98
|
+
/* @__PURE__ */ jsx(ErrorBanner, { children: error }),
|
|
99
|
+
/* @__PURE__ */ jsx("div", { className: "surface-inset rounded-lg", children: /* @__PURE__ */ jsx(
|
|
100
|
+
ToggleRow,
|
|
101
|
+
{
|
|
102
|
+
label: `Works every ${DAY_LONG[dow]}`,
|
|
103
|
+
hint: inherited ? "Follows the business hours until you change it here." : void 0,
|
|
104
|
+
checked: working,
|
|
105
|
+
onChange: setWorking
|
|
106
|
+
}
|
|
107
|
+
) }),
|
|
108
|
+
working && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
109
|
+
slots.map((slot, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
|
|
110
|
+
/* @__PURE__ */ jsx("div", { className: "grid flex-1 grid-cols-2 gap-2", children: index === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
111
|
+
/* @__PURE__ */ jsx(Field, { label: "From", children: /* @__PURE__ */ jsx(
|
|
112
|
+
TimeField,
|
|
113
|
+
{
|
|
114
|
+
value: slot.start,
|
|
115
|
+
onChange: (v) => setSlot(index, "start", v)
|
|
116
|
+
}
|
|
117
|
+
) }),
|
|
118
|
+
/* @__PURE__ */ jsx(Field, { label: "Until", children: /* @__PURE__ */ jsx(
|
|
119
|
+
TimeField,
|
|
120
|
+
{
|
|
121
|
+
value: slot.end,
|
|
122
|
+
onChange: (v) => setSlot(index, "end", v)
|
|
123
|
+
}
|
|
124
|
+
) })
|
|
125
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
126
|
+
/* @__PURE__ */ jsx(
|
|
127
|
+
TimeField,
|
|
128
|
+
{
|
|
129
|
+
"aria-label": "From",
|
|
130
|
+
value: slot.start,
|
|
131
|
+
onChange: (v) => setSlot(index, "start", v)
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
TimeField,
|
|
136
|
+
{
|
|
137
|
+
"aria-label": "Until",
|
|
138
|
+
value: slot.end,
|
|
139
|
+
onChange: (v) => setSlot(index, "end", v)
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
] }) }),
|
|
143
|
+
slots.length > 1 && /* @__PURE__ */ jsx(
|
|
144
|
+
Button,
|
|
145
|
+
{
|
|
146
|
+
size: "icon",
|
|
147
|
+
variant: "ghost",
|
|
148
|
+
"aria-label": "Remove this shift",
|
|
149
|
+
onClick: () => setSlots((prev) => prev.filter((_, i) => i !== index)),
|
|
150
|
+
children: /* @__PURE__ */ jsx(X, {})
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
] }, index)),
|
|
154
|
+
slots.length < 2 && /* @__PURE__ */ jsxs(
|
|
155
|
+
Button,
|
|
156
|
+
{
|
|
157
|
+
size: "md",
|
|
158
|
+
variant: "ghost",
|
|
159
|
+
onClick: () => setSlots((prev) => [
|
|
160
|
+
...prev,
|
|
161
|
+
{ start: "14:00", end: "18:00" }
|
|
162
|
+
]),
|
|
163
|
+
children: [
|
|
164
|
+
/* @__PURE__ */ jsx(Plus, {}),
|
|
165
|
+
"Split the day"
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
] }),
|
|
170
|
+
/* @__PURE__ */ jsx("div", { className: "surface-inset rounded-lg", children: /* @__PURE__ */ jsx(
|
|
171
|
+
ToggleRow,
|
|
172
|
+
{
|
|
173
|
+
label: `Time off on ${dateLabel}`,
|
|
174
|
+
hint: "This date only. The week above keeps its shape.",
|
|
175
|
+
checked: timeOff,
|
|
176
|
+
onChange: setTimeOff
|
|
177
|
+
}
|
|
178
|
+
) }),
|
|
179
|
+
timeOff && existing.length === 0 && /* @__PURE__ */ jsx(Field, { label: "Reason", hint: "Shown to you, never to a customer.", children: /* @__PURE__ */ jsx(
|
|
180
|
+
Input,
|
|
181
|
+
{
|
|
182
|
+
value: reason,
|
|
183
|
+
onChange: (e) => setReason(e.target.value),
|
|
184
|
+
placeholder: "e.g. deep clean, private hire, annual leave"
|
|
185
|
+
}
|
|
186
|
+
) })
|
|
187
|
+
] })
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
export {
|
|
192
|
+
DayEditor
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=day-editor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_components/day-editor.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { Plus, X } from 'lucide-react';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { FormDialog } from '@withpotter/ui-kit/form-dialog';\nimport { ErrorBanner } from '@withpotter/ui-kit/error-banner';\nimport { Field } from '@withpotter/ui-kit/field';\nimport { Input } from '@withpotter/ui-kit';\nimport { TimeField } from '@withpotter/ui-kit/time-field';\nimport { ToggleRow } from '@withpotter/ui-kit/toggle';\nimport type { WeeklyHours } from '@withpotter/hooks/use-hours-data';\nimport type { CalendarEventItem } from '@withpotter/lib/api/types';\nimport type { ScheduleSlot, WeeklySchedule } from '@withpotter/lib/resource-types';\nimport type { RosterRow } from '../_hooks/use-roster';\nimport {\n DAY_LONG,\n WEEK_DAYS,\n blocksOn,\n businessSlots,\n daySlots,\n isoDay,\n} from '../_lib/week';\n\n/**\n * One resource, one day: the pattern and the exception, told apart.\n *\n * These are two different sentences and the old surface could only say one of\n * them. Editing the weekly schedule to close one Tuesday closed every Tuesday;\n * the block endpoints that close exactly one day had no door at all. Both are\n * here, named for what they do — \"every Tuesday\" against \"Tue 26 Aug\" — because\n * a merchant who cannot see the difference will reach for whichever is nearer.\n */\nexport function DayEditor({\n row,\n date,\n hours,\n blocks,\n saving,\n onSave,\n onClose,\n}: {\n row: RosterRow;\n date: Date;\n hours: WeeklyHours;\n blocks: CalendarEventItem[];\n saving: boolean;\n onSave: (change: {\n schedule?: WeeklySchedule;\n block?: {\n date: string;\n startTime: string;\n endTime: string;\n reason?: string;\n };\n unblock?: { date: string; startTime: string };\n }) => Promise<void>;\n onClose: () => void;\n}) {\n const dow = date.getDay();\n const iso = isoDay(date);\n const own = daySlots(row.schedule, dow);\n const inherited = own === undefined;\n const resolved = inherited ? businessSlots(hours, dow) : own;\n const existing = blocksOn(blocks, row.id, iso);\n\n const [working, setWorking] = useState(!!resolved);\n const [slots, setSlots] = useState<ScheduleSlot[]>(\n resolved?.length ? resolved : [{ start: '09:00', end: '17:00' }],\n );\n const [timeOff, setTimeOff] = useState(existing.length > 0);\n const [reason, setReason] = useState(existing[0]?.title ?? '');\n const [error, setError] = useState<string | null>(null);\n\n const dateLabel = date.toLocaleDateString('en-GB', {\n weekday: 'short',\n day: 'numeric',\n month: 'short',\n });\n\n const setSlot = (index: number, part: 'start' | 'end', value: string) =>\n setSlots((prev) =>\n prev.map((slot, i) => (i === index ? { ...slot, [part]: value } : slot)),\n );\n\n /**\n * Every day the resource has an answer for, not just the one being edited.\n *\n * A `WeeklySchedule` is the whole week, so writing back only the edited day\n * would erase the other six. A resource that has never had one inherits the\n * business's week here, which is what it was already being booked against.\n */\n const nextSchedule = (): WeeklySchedule => {\n const week: WeeklySchedule = {};\n for (const day of WEEK_DAYS) {\n const existingDay = daySlots(row.schedule, day);\n const base =\n existingDay === undefined ? businessSlots(hours, day) : existingDay;\n week[day] = base\n ? { available: true, slots: base }\n : { available: false };\n }\n week[dow] = working ? { available: true, slots } : { available: false };\n return week;\n };\n\n const handleSave = async () => {\n if (working) {\n const bad = slots.find((s) => !s.start || !s.end || s.end <= s.start);\n if (bad) {\n setError('Each shift needs an end time after its start.');\n return;\n }\n }\n setError(null);\n\n const change: Parameters<typeof onSave>[0] = { schedule: nextSchedule() };\n\n if (timeOff && existing.length === 0) {\n const first = working && slots.length ? slots[0].start : '00:00';\n const last =\n working && slots.length ? slots[slots.length - 1].end : '23:59';\n change.block = {\n date: iso,\n startTime: first,\n endTime: last,\n reason: reason.trim() || undefined,\n };\n }\n if (!timeOff && existing.length > 0) {\n change.unblock = {\n date: iso,\n startTime: new Date(existing[0].start).toTimeString().slice(0, 5),\n };\n }\n\n await onSave(change);\n };\n\n return (\n <FormDialog\n title={`${row.name}, ${DAY_LONG[dow]}`}\n onClose={onClose}\n footer={\n <>\n <Button variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n <Button onClick={handleSave} loading={saving}>\n Save\n </Button>\n </>\n }\n >\n <div className=\"space-y-4\">\n <ErrorBanner>{error}</ErrorBanner>\n\n <div className=\"surface-inset rounded-lg\">\n <ToggleRow\n label={`Works every ${DAY_LONG[dow]}`}\n hint={\n inherited\n ? 'Follows the business hours until you change it here.'\n : undefined\n }\n checked={working}\n onChange={setWorking}\n />\n </div>\n\n {working && (\n <div className=\"space-y-2\">\n {slots.map((slot, index) => (\n <div key={index} className=\"flex items-end gap-2\">\n {/* The pair is labelled once. A second \"From / Until\" over the\n split shift labels the same two things twice. */}\n <div className=\"grid flex-1 grid-cols-2 gap-2\">\n {index === 0 ? (\n <>\n <Field label=\"From\">\n <TimeField\n value={slot.start}\n onChange={(v) => setSlot(index, 'start', v)}\n />\n </Field>\n <Field label=\"Until\">\n <TimeField\n value={slot.end}\n onChange={(v) => setSlot(index, 'end', v)}\n />\n </Field>\n </>\n ) : (\n <>\n <TimeField\n aria-label=\"From\"\n value={slot.start}\n onChange={(v) => setSlot(index, 'start', v)}\n />\n <TimeField\n aria-label=\"Until\"\n value={slot.end}\n onChange={(v) => setSlot(index, 'end', v)}\n />\n </>\n )}\n </div>\n {slots.length > 1 && (\n <Button\n size=\"icon\"\n variant=\"ghost\"\n aria-label=\"Remove this shift\"\n onClick={() =>\n setSlots((prev) => prev.filter((_, i) => i !== index))\n }\n >\n <X />\n </Button>\n )}\n </div>\n ))}\n {slots.length < 2 && (\n <Button\n size=\"md\"\n variant=\"ghost\"\n onClick={() =>\n setSlots((prev) => [\n ...prev,\n { start: '14:00', end: '18:00' },\n ])\n }\n >\n <Plus />\n Split the day\n </Button>\n )}\n </div>\n )}\n\n <div className=\"surface-inset rounded-lg\">\n <ToggleRow\n label={`Time off on ${dateLabel}`}\n hint=\"This date only. The week above keeps its shape.\"\n checked={timeOff}\n onChange={setTimeOff}\n />\n </div>\n\n {timeOff && existing.length === 0 && (\n <Field label=\"Reason\" hint=\"Shown to you, never to a customer.\">\n <Input\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n placeholder=\"e.g. deep clean, private hire, annual leave\"\n />\n </Field>\n )}\n </div>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Building2, DoorOpen, Users, Wrench } from "lucide-react";
|
|
5
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
6
|
+
import { FormDialog } from "@withpotter/ui-kit/form-dialog";
|
|
7
|
+
import { ErrorBanner } from "@withpotter/ui-kit/error-banner";
|
|
8
|
+
import { Field } from "@withpotter/ui-kit/field";
|
|
9
|
+
import { Input } from "@withpotter/ui-kit";
|
|
10
|
+
import { InlineDeleteButton } from "@withpotter/ui-kit/inline-delete-button";
|
|
11
|
+
import { OptionButton } from "@withpotter/ui-kit/option-button";
|
|
12
|
+
import { singularise } from "@withpotter/lib/intents/use-entity-label";
|
|
13
|
+
import { ResourcePicker } from "./resource-picker";
|
|
14
|
+
import { SHAPES, shapeExamples, shapesFor } from "../_lib/shapes";
|
|
15
|
+
const ICON_BY_KIND = {
|
|
16
|
+
person: Users,
|
|
17
|
+
space: DoorOpen,
|
|
18
|
+
equipment: Wrench,
|
|
19
|
+
unit: Building2
|
|
20
|
+
};
|
|
21
|
+
function GroupDialog({
|
|
22
|
+
category,
|
|
23
|
+
intentKey,
|
|
24
|
+
saving,
|
|
25
|
+
onSave,
|
|
26
|
+
onDelete,
|
|
27
|
+
onClose
|
|
28
|
+
}) {
|
|
29
|
+
const editing = !!category;
|
|
30
|
+
const [shape, setShape] = useState(
|
|
31
|
+
category ? SHAPES.find((s) => s.kind === category.kind) ?? null : null
|
|
32
|
+
);
|
|
33
|
+
const [plural, setPlural] = useState(category?.labelPlural ?? "");
|
|
34
|
+
const [error, setError] = useState(null);
|
|
35
|
+
const [presetId, setPresetId] = useState(null);
|
|
36
|
+
const [showingAll] = useState(false);
|
|
37
|
+
const [pickerStep, setPickerStep] = useState(
|
|
38
|
+
null
|
|
39
|
+
);
|
|
40
|
+
const [freeform, setFreeform] = useState(false);
|
|
41
|
+
const pick = (preset) => {
|
|
42
|
+
setPresetId(preset.id);
|
|
43
|
+
setShape({
|
|
44
|
+
kind: preset.kind,
|
|
45
|
+
type: preset.type,
|
|
46
|
+
title: preset.plural,
|
|
47
|
+
description: "",
|
|
48
|
+
suggestion: preset.plural
|
|
49
|
+
});
|
|
50
|
+
setPlural(preset.plural);
|
|
51
|
+
};
|
|
52
|
+
const singular = plural.trim() ? singularise(plural.trim()) : "";
|
|
53
|
+
const handleSave = async () => {
|
|
54
|
+
if (!shape) return;
|
|
55
|
+
if (!plural.trim()) {
|
|
56
|
+
setError("Give them a name.");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
setError(null);
|
|
60
|
+
await onSave({
|
|
61
|
+
label: singular || plural.trim(),
|
|
62
|
+
labelPlural: plural.trim(),
|
|
63
|
+
kind: shape.kind
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
return /* @__PURE__ */ jsx(
|
|
67
|
+
FormDialog,
|
|
68
|
+
{
|
|
69
|
+
title: editing ? `Rename ${category.labelPlural}` : pickerStep ? `Choose a ${pickerStep === "person" ? "people" : pickerStep} type` : "Add a group",
|
|
70
|
+
description: editing ? void 0 : "A group is one kind of thing a booking takes up. A club has two: its courts and its coaches.",
|
|
71
|
+
size: shape || editing ? "md" : "lg",
|
|
72
|
+
onBack: pickerStep ? () => setPickerStep(null) : void 0,
|
|
73
|
+
onClose,
|
|
74
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
75
|
+
editing && onDelete ? /* @__PURE__ */ jsx(
|
|
76
|
+
InlineDeleteButton,
|
|
77
|
+
{
|
|
78
|
+
onDelete: async () => {
|
|
79
|
+
try {
|
|
80
|
+
await onDelete(category.id);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
setError(
|
|
83
|
+
err instanceof Error ? err.message : `Something still books ${category.labelPlural.toLowerCase()}.`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
confirmText: `Delete ${category.labelPlural}?`
|
|
88
|
+
}
|
|
89
|
+
) : /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Cancel" }),
|
|
90
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleSave, loading: saving, disabled: !shape, children: editing ? "Save" : "Add" })
|
|
91
|
+
] }),
|
|
92
|
+
children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
93
|
+
/* @__PURE__ */ jsx(ErrorBanner, { children: error }),
|
|
94
|
+
!editing && !freeform && /* @__PURE__ */ jsx(
|
|
95
|
+
ResourcePicker,
|
|
96
|
+
{
|
|
97
|
+
category: pickerStep,
|
|
98
|
+
intentKeys: intentKey ? [intentKey] : [],
|
|
99
|
+
selectedId: presetId,
|
|
100
|
+
showingAll,
|
|
101
|
+
onPick: pick,
|
|
102
|
+
onCategoryChange: setPickerStep
|
|
103
|
+
}
|
|
104
|
+
),
|
|
105
|
+
!editing && freeform && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
106
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: shapesFor(intentKey).map((option) => {
|
|
107
|
+
const Icon = ICON_BY_KIND[option.kind];
|
|
108
|
+
const picked = shape?.kind === option.kind;
|
|
109
|
+
return /* @__PURE__ */ jsxs(
|
|
110
|
+
OptionButton,
|
|
111
|
+
{
|
|
112
|
+
shape: "card",
|
|
113
|
+
selected: picked,
|
|
114
|
+
className: "w-full flex-col items-start gap-1 text-left",
|
|
115
|
+
onClick: () => {
|
|
116
|
+
setShape(option);
|
|
117
|
+
setPresetId(null);
|
|
118
|
+
if (!plural.trim()) setPlural(option.suggestion);
|
|
119
|
+
},
|
|
120
|
+
children: [
|
|
121
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
122
|
+
/* @__PURE__ */ jsx(Icon, { className: "size-4 text-[var(--text-tertiary)]" }),
|
|
123
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-primary)]", children: option.title })
|
|
124
|
+
] }),
|
|
125
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-[var(--text-secondary)]", children: option.description }),
|
|
126
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--text-muted)]", children: shapeExamples(option.kind, intentKey) })
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
option.kind
|
|
130
|
+
);
|
|
131
|
+
}) }),
|
|
132
|
+
/* @__PURE__ */ jsx(
|
|
133
|
+
Button,
|
|
134
|
+
{
|
|
135
|
+
variant: "ghost",
|
|
136
|
+
size: "md",
|
|
137
|
+
onClick: () => {
|
|
138
|
+
setFreeform(false);
|
|
139
|
+
setShape(null);
|
|
140
|
+
setPlural("");
|
|
141
|
+
},
|
|
142
|
+
children: "Back to the list"
|
|
143
|
+
}
|
|
144
|
+
)
|
|
145
|
+
] }),
|
|
146
|
+
(shape || editing) && /* @__PURE__ */ jsx(
|
|
147
|
+
Field,
|
|
148
|
+
{
|
|
149
|
+
label: "What do you call them?",
|
|
150
|
+
hint: singular ? `One of them is a ${singular.toLowerCase()}.` : void 0,
|
|
151
|
+
required: true,
|
|
152
|
+
children: /* @__PURE__ */ jsx(
|
|
153
|
+
Input,
|
|
154
|
+
{
|
|
155
|
+
value: plural,
|
|
156
|
+
onChange: (e) => setPlural(e.target.value),
|
|
157
|
+
placeholder: shape?.suggestion ?? "Courts",
|
|
158
|
+
autoFocus: true
|
|
159
|
+
}
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
] })
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
export {
|
|
168
|
+
GroupDialog
|
|
169
|
+
};
|
|
170
|
+
//# sourceMappingURL=group-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_components/group-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { Building2, DoorOpen, Users, Wrench } from 'lucide-react';\nimport type { LucideIcon } from 'lucide-react';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { FormDialog } from '@withpotter/ui-kit/form-dialog';\nimport { ErrorBanner } from '@withpotter/ui-kit/error-banner';\nimport { Field } from '@withpotter/ui-kit/field';\nimport { Input } from '@withpotter/ui-kit';\nimport { InlineDeleteButton } from '@withpotter/ui-kit/inline-delete-button';\nimport { OptionButton } from '@withpotter/ui-kit/option-button';\nimport { singularise } from '@withpotter/lib/intents/use-entity-label';\nimport type {\n CreateResourceCategoryInput,\n ResourceCategory,\n ResourceCategoryKind,\n UpdateResourceCategoryInput,\n} from '@withpotter/lib/resource-types';\nimport { ResourcePicker } from './resource-picker';\nimport type { ResourcePreset } from '../_lib/presets';\nimport { SHAPES, shapeExamples, shapesFor, type Shape } from '../_lib/shapes';\n\nconst ICON_BY_KIND: Record<ResourceCategoryKind, LucideIcon> = {\n person: Users,\n space: DoorOpen,\n equipment: Wrench,\n unit: Building2,\n};\n\n/**\n * Adding a group of bookable things: what shape it is, then what you call it.\n *\n * Two questions in the order they can be answered. The old dialog asked for a\n * label, a plural label and a `kind` — our word for the shape — in one form,\n * behind a hand-drawn overlay that closed on neither Escape nor a click\n * outside, with the shape offered as a select of five options one of which was\n * a team size. A merchant naming their courts had to know what we meant by\n * \"space\" before they could type \"Courts\".\n *\n * The shape is asked first because it is the answer that cannot be changed\n * casually later: availability and assignment key off it.\n */\nexport function GroupDialog({\n category,\n intentKey,\n saving,\n onSave,\n onDelete,\n onClose,\n}: {\n /** Present when renaming an existing group; absent when adding one. */\n category?: ResourceCategory | null;\n intentKey?: string | null;\n saving: boolean;\n onSave: (\n data: CreateResourceCategoryInput & Partial<UpdateResourceCategoryInput>,\n ) => Promise<void>;\n onDelete?: (id: string) => void | Promise<void>;\n onClose: () => void;\n}) {\n const editing = !!category;\n const [shape, setShape] = useState<Shape | null>(\n category ? (SHAPES.find((s) => s.kind === category.kind) ?? null) : null,\n );\n const [plural, setPlural] = useState(category?.labelPlural ?? '');\n const [error, setError] = useState<string | null>(null);\n const [presetId, setPresetId] = useState<string | null>(null);\n const [showingAll] = useState(false);\n const [pickerStep, setPickerStep] = useState<ResourceCategoryKind | null>(\n null,\n );\n /** The four shapes and a blank field — the route out of the catalogue. */\n const [freeform, setFreeform] = useState(false);\n\n /** One press carries the shape, the row type and both words. */\n const pick = (preset: ResourcePreset) => {\n setPresetId(preset.id);\n setShape({\n kind: preset.kind,\n type: preset.type,\n title: preset.plural,\n description: '',\n suggestion: preset.plural,\n });\n setPlural(preset.plural);\n };\n\n const singular = plural.trim() ? singularise(plural.trim()) : '';\n\n const handleSave = async () => {\n if (!shape) return;\n if (!plural.trim()) {\n setError('Give them a name.');\n return;\n }\n setError(null);\n await onSave({\n label: singular || plural.trim(),\n labelPlural: plural.trim(),\n kind: shape.kind,\n });\n };\n\n return (\n <FormDialog\n title={\n editing\n ? `Rename ${category.labelPlural}`\n : pickerStep\n ? `Choose a ${pickerStep === 'person' ? 'people' : pickerStep} type`\n : 'Add a group'\n }\n description={\n editing\n ? undefined\n : 'A group is one kind of thing a booking takes up. A club has two: its courts and its coaches.'\n }\n size={shape || editing ? 'md' : 'lg'}\n onBack={pickerStep ? () => setPickerStep(null) : undefined}\n onClose={onClose}\n footer={\n <>\n {editing && onDelete ? (\n <InlineDeleteButton\n onDelete={async () => {\n /**\n * The API refuses while a service still asks for this group,\n * and says which count — a 409 carrying the only sentence that\n * makes the refusal actionable. Swallowing it left a Delete\n * that appeared to do nothing.\n */\n try {\n await onDelete(category.id);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : `Something still books ${category.labelPlural.toLowerCase()}.`,\n );\n }\n }}\n confirmText={`Delete ${category.labelPlural}?`}\n />\n ) : (\n <Button variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n )}\n <Button onClick={handleSave} loading={saving} disabled={!shape}>\n {editing ? 'Save' : 'Add'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-4\">\n <ErrorBanner>{error}</ErrorBanner>\n\n {!editing && !freeform && (\n <ResourcePicker\n category={pickerStep}\n intentKeys={intentKey ? [intentKey] : []}\n selectedId={presetId}\n showingAll={showingAll}\n onPick={pick}\n onCategoryChange={setPickerStep}\n />\n )}\n\n {!editing && freeform && (\n <div className=\"space-y-2\">\n <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n {shapesFor(intentKey).map((option) => {\n const Icon = ICON_BY_KIND[option.kind];\n const picked = shape?.kind === option.kind;\n return (\n <OptionButton\n key={option.kind}\n shape=\"card\"\n selected={picked}\n className=\"w-full flex-col items-start gap-1 text-left\"\n onClick={() => {\n setShape(option);\n setPresetId(null);\n if (!plural.trim()) setPlural(option.suggestion);\n }}\n >\n <span className=\"flex items-center gap-2\">\n <Icon className=\"size-4 text-[var(--text-tertiary)]\" />\n <span className=\"text-sm font-medium text-[var(--text-primary)]\">\n {option.title}\n </span>\n </span>\n <span className=\"text-sm text-[var(--text-secondary)]\">\n {option.description}\n </span>\n <span className=\"text-xs text-[var(--text-muted)]\">\n {shapeExamples(option.kind, intentKey)}\n </span>\n </OptionButton>\n );\n })}\n </div>\n <Button\n variant=\"ghost\"\n size=\"md\"\n onClick={() => {\n setFreeform(false);\n setShape(null);\n setPlural('');\n }}\n >\n Back to the list\n </Button>\n </div>\n )}\n\n {(shape || editing) && (\n <Field\n label=\"What do you call them?\"\n hint={\n singular\n ? `One of them is a ${singular.toLowerCase()}.`\n : undefined\n }\n required\n >\n <Input\n value={plural}\n onChange={(e) => setPlural(e.target.value)}\n placeholder={shape?.suggestion ?? 'Courts'}\n autoFocus\n />\n </Field>\n )}\n </div>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { Plus, Settings } from "lucide-react";
|
|
5
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
6
|
+
import { Badge } from "@withpotter/ui-kit/badge";
|
|
7
|
+
function GroupBand({
|
|
8
|
+
span,
|
|
9
|
+
category,
|
|
10
|
+
count,
|
|
11
|
+
usage,
|
|
12
|
+
onAdd,
|
|
13
|
+
onRename
|
|
14
|
+
}) {
|
|
15
|
+
return /* @__PURE__ */ jsx("tr", { className: "bg-[var(--bg-muted)]", children: /* @__PURE__ */ jsx("td", { colSpan: span, className: "px-4 py-2", children: /* @__PURE__ */ jsx(
|
|
16
|
+
GroupHeadingContent,
|
|
17
|
+
{
|
|
18
|
+
category,
|
|
19
|
+
count,
|
|
20
|
+
onAdd,
|
|
21
|
+
onRename
|
|
22
|
+
}
|
|
23
|
+
) }) });
|
|
24
|
+
}
|
|
25
|
+
function GroupHeading({
|
|
26
|
+
category,
|
|
27
|
+
count,
|
|
28
|
+
onAdd
|
|
29
|
+
}) {
|
|
30
|
+
return /* @__PURE__ */ jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsx(GroupHeadingContent, { category, count, onAdd }) });
|
|
31
|
+
}
|
|
32
|
+
function GroupHeadingContent({
|
|
33
|
+
category,
|
|
34
|
+
count,
|
|
35
|
+
onAdd,
|
|
36
|
+
onRename
|
|
37
|
+
}) {
|
|
38
|
+
const title = category?.labelPlural ?? "No group";
|
|
39
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
40
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
41
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
42
|
+
/* @__PURE__ */ jsx("h2", { className: "truncate text-base font-semibold text-[var(--text-primary)]", children: title }),
|
|
43
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", children: count })
|
|
44
|
+
] }),
|
|
45
|
+
!category ? /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--text-tertiary)]", children: "Open one to put it somewhere." }) : null
|
|
46
|
+
] }),
|
|
47
|
+
category && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: onRename ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
48
|
+
/* @__PURE__ */ jsx(
|
|
49
|
+
Button,
|
|
50
|
+
{
|
|
51
|
+
size: "icon",
|
|
52
|
+
variant: "secondary",
|
|
53
|
+
"aria-label": `Configure ${title}`,
|
|
54
|
+
onClick: () => onRename(category),
|
|
55
|
+
children: /* @__PURE__ */ jsx(Settings, {})
|
|
56
|
+
}
|
|
57
|
+
),
|
|
58
|
+
/* @__PURE__ */ jsxs(
|
|
59
|
+
Button,
|
|
60
|
+
{
|
|
61
|
+
size: "md",
|
|
62
|
+
variant: "secondary",
|
|
63
|
+
onClick: () => onAdd(category),
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ jsx(Plus, {}),
|
|
66
|
+
"Add ",
|
|
67
|
+
category.label.toLowerCase()
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
72
|
+
/* @__PURE__ */ jsx(
|
|
73
|
+
Button,
|
|
74
|
+
{
|
|
75
|
+
size: "icon",
|
|
76
|
+
variant: "secondary",
|
|
77
|
+
"aria-label": `Add ${category.label.toLowerCase()}`,
|
|
78
|
+
onClick: () => onAdd(category),
|
|
79
|
+
children: /* @__PURE__ */ jsx(Plus, {})
|
|
80
|
+
}
|
|
81
|
+
),
|
|
82
|
+
/* @__PURE__ */ jsx(Button, { asChild: true, size: "md", variant: "secondary", children: /* @__PURE__ */ jsx(Link, { href: `/dashboard/resources?group=${category.id}`, children: "View all" }) })
|
|
83
|
+
] }) })
|
|
84
|
+
] });
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
GroupBand,
|
|
88
|
+
GroupHeading
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=group-header.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_components/group-header.tsx"],"sourcesContent":["'use client';\n\nimport Link from 'next/link';\nimport { Plus, Settings } from 'lucide-react';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Badge } from '@withpotter/ui-kit/badge';\nimport type { CategoryUsage, ResourceCategory } from '@withpotter/lib/resource-types';\n\n/**\n * A group of bookable things, drawn as a band INSIDE the table it heads.\n *\n * It used to be a block above its own table, which meant every group redrew\n * the column header under it — four groups, four \"Name / Week / Today /\n * Status\" rows down one screen — and in the week view four copies of the week\n * navigator too. One table, one header, and the groups are bands in it.\n *\n * The band also says which services ask for this group, because that is the\n * sentence the screen was missing. A merchant adds a coach and expects a\n * customer to be able to book one; nothing happens, because a booking is\n * assigned through a SERVICE that declares what it needs, and until some\n * service asks for a coach the coaches are names in a list. John, 2026-08-23:\n * *\"i have coaches so i add them there, so on the website people can book a\n * court then book a coach\"* — true, and true only after that one link is made.\n *\n * That sentence only earns its line when the group HAS members. An empty\n * group has nothing that could be unreachable, so saying \"nothing books\n * stylists yet\" under a group with no stylists is the page answering a\n * question nobody asked — three times over, in three identical sentences,\n * which is exactly how this screen filled up with words that said nothing.\n */\nexport function GroupBand({\n span,\n category,\n count,\n usage,\n onAdd,\n onRename,\n}: {\n /** Columns to span — the table it sits in owns the number. */\n span: number;\n /** `null` for the rows that are in no group at all. */\n category: ResourceCategory | null;\n count: number;\n usage: CategoryUsage | undefined;\n onAdd: (category: ResourceCategory) => void;\n onRename: (category: ResourceCategory) => void;\n}) {\n return (\n <tr className=\"bg-[var(--bg-muted)]\">\n <td colSpan={span} className=\"px-4 py-2\">\n <GroupHeadingContent\n category={category}\n count={count}\n onAdd={onAdd}\n onRename={onRename}\n />\n </td>\n </tr>\n );\n}\n\n/**\n * The same heading, outside a table — the grid's section head.\n *\n * No band fill here: in the grid the cards are the surfaces and the ground\n * between them is the page, so painting a strip behind the title would put a\n * second surface under things that are already surfaces.\n */\nexport function GroupHeading({\n category,\n count,\n onAdd,\n}: {\n category: ResourceCategory | null;\n count: number;\n onAdd: (category: ResourceCategory) => void;\n}) {\n return (\n <div className=\"mb-1\">\n <GroupHeadingContent category={category} count={count} onAdd={onAdd} />\n </div>\n );\n}\n\nfunction GroupHeadingContent({\n category,\n count,\n onAdd,\n onRename,\n}: {\n category: ResourceCategory | null;\n count: number;\n onAdd: (category: ResourceCategory) => void;\n onRename?: (category: ResourceCategory) => void;\n}) {\n const title = category?.labelPlural ?? 'No group';\n\n return (\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"truncate text-base font-semibold text-[var(--text-primary)]\">\n {title}\n </h2>\n <Badge size=\"sm\">{count}</Badge>\n </div>\n\n {!category ? (\n <p className=\"text-sm text-[var(--text-tertiary)]\">\n Open one to put it somewhere.\n </p>\n ) : null}\n </div>\n\n {category && (\n <div className=\"flex items-center gap-2\">\n {onRename ? (\n <>\n <Button\n size=\"icon\"\n variant=\"secondary\"\n aria-label={`Configure ${title}`}\n onClick={() => onRename(category)}\n >\n <Settings />\n </Button>\n <Button\n size=\"md\"\n variant=\"secondary\"\n onClick={() => onAdd(category)}\n >\n <Plus />\n Add {category.label.toLowerCase()}\n </Button>\n </>\n ) : (\n <>\n <Button\n size=\"icon\"\n variant=\"secondary\"\n aria-label={`Add ${category.label.toLowerCase()}`}\n onClick={() => onAdd(category)}\n >\n <Plus />\n </Button>\n <Button asChild size=\"md\" variant=\"secondary\">\n <Link href={`/dashboard/resources?group=${category.id}`}>\n View all\n </Link>\n </Button>\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";AAkDQ,SAmEI,UAnEJ,KAkDA,YAlDA;AAhDR,OAAO,UAAU;AACjB,SAAS,MAAM,gBAAgB;AAC/B,SAAS,cAAc;AACvB,SAAS,aAAa;AAyBf,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,SACE,oBAAC,QAAG,WAAU,wBACZ,8BAAC,QAAG,SAAS,MAAM,WAAU,aAC3B;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF,GACF,GACF;AAEJ;AASO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,oBAAC,SAAI,WAAU,QACb,8BAAC,uBAAoB,UAAoB,OAAc,OAAc,GACvE;AAEJ;AAEA,SAAS,oBAAoB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,UAAU,eAAe;AAEvC,SACE,qBAAC,SAAI,WAAU,qDACb;AAAA,yBAAC,SAAI,WAAU,WACb;AAAA,2BAAC,SAAI,WAAU,2BACb;AAAA,4BAAC,QAAG,WAAU,+DACX,iBACH;AAAA,QACA,oBAAC,SAAM,MAAK,MAAM,iBAAM;AAAA,SAC1B;AAAA,MAEC,CAAC,WACA,oBAAC,OAAE,WAAU,uCAAsC,2CAEnD,IACE;AAAA,OACN;AAAA,IAEC,YACC,oBAAC,SAAI,WAAU,2BACZ,qBACC,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,cAAY,aAAa,KAAK;AAAA,UAC9B,SAAS,MAAM,SAAS,QAAQ;AAAA,UAEhC,8BAAC,YAAS;AAAA;AAAA,MACZ;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS,MAAM,MAAM,QAAQ;AAAA,UAE7B;AAAA,gCAAC,QAAK;AAAA,YAAE;AAAA,YACH,SAAS,MAAM,YAAY;AAAA;AAAA;AAAA,MAClC;AAAA,OACF,IAEA,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,cAAY,OAAO,SAAS,MAAM,YAAY,CAAC;AAAA,UAC/C,SAAS,MAAM,MAAM,QAAQ;AAAA,UAE7B,8BAAC,QAAK;AAAA;AAAA,MACR;AAAA,MACA,oBAAC,UAAO,SAAO,MAAC,MAAK,MAAK,SAAQ,aAChC,8BAAC,QAAK,MAAM,8BAA8B,SAAS,EAAE,IAAI,sBAEzD,GACF;AAAA,OACF,GAEJ;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BlockTimeModal } from "./block-time-modal";
|
|
2
|
+
import { DayEditor } from "./day-editor";
|
|
3
|
+
import { GroupDialog } from "./group-dialog";
|
|
4
|
+
import { GroupBand } from "./group-header";
|
|
5
|
+
import { ResourceForm } from "./resource-form";
|
|
6
|
+
import { RosterEmpty } from "./roster-empty";
|
|
7
|
+
import { RosterGrid } from "./roster-grid";
|
|
8
|
+
import { ScheduleEditor, getDefaultSchedule } from "./schedule-editor";
|
|
9
|
+
import { WeekGrid } from "./week-grid";
|
|
10
|
+
export {
|
|
11
|
+
BlockTimeModal,
|
|
12
|
+
DayEditor,
|
|
13
|
+
GroupBand,
|
|
14
|
+
GroupDialog,
|
|
15
|
+
ResourceForm,
|
|
16
|
+
RosterEmpty,
|
|
17
|
+
RosterGrid,
|
|
18
|
+
ScheduleEditor,
|
|
19
|
+
WeekGrid,
|
|
20
|
+
getDefaultSchedule
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_components/index.ts"],"sourcesContent":["export { BlockTimeModal } from './block-time-modal';\nexport { DayEditor } from './day-editor';\nexport { GroupDialog } from './group-dialog';\nexport { GroupBand } from './group-header';\nexport { ResourceForm } from './resource-form';\nexport { RosterEmpty } from './roster-empty';\nexport { RosterGrid } from './roster-grid';\nexport { ScheduleEditor, getDefaultSchedule } from './schedule-editor';\nexport { WeekGrid } from './week-grid';\n"],"mappings":"AAAA,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB,0BAA0B;AACnD,SAAS,gBAAgB;","names":[]}
|