@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,420 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import {
|
|
5
|
+
kindToResourceType
|
|
6
|
+
} from "@withpotter/lib/resource-types";
|
|
7
|
+
import { ScheduleEditor, getDefaultSchedule } from "./schedule-editor";
|
|
8
|
+
import { availabilityWords } from "../_lib/shapes";
|
|
9
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
10
|
+
import { FormDialog } from "@withpotter/ui-kit/form-dialog";
|
|
11
|
+
import { ErrorBanner } from "@withpotter/ui-kit/error-banner";
|
|
12
|
+
import { Input, NumberField, Select } from "@withpotter/ui-kit";
|
|
13
|
+
import { ImageUpload } from "@withpotter/components/image-upload";
|
|
14
|
+
import { guessTimezone } from "../_lib/schedule-timezone";
|
|
15
|
+
import { ScheduleTimezoneField } from "./schedule-timezone-field";
|
|
16
|
+
import { useBusinessLocations } from "@withpotter/lib/use-business-locations";
|
|
17
|
+
import { Textarea } from "@withpotter/ui-kit";
|
|
18
|
+
const FORM_ID = "resource-form";
|
|
19
|
+
function ResourceForm({
|
|
20
|
+
open,
|
|
21
|
+
category,
|
|
22
|
+
categories,
|
|
23
|
+
resource,
|
|
24
|
+
onSave,
|
|
25
|
+
onClose
|
|
26
|
+
}) {
|
|
27
|
+
const isEditing = !!resource;
|
|
28
|
+
const [categoryId, setCategoryId] = useState(category.id);
|
|
29
|
+
const groups = categories ?? [];
|
|
30
|
+
const active = groups.find((c) => c.id === categoryId) ?? category;
|
|
31
|
+
const { byTheNight } = availabilityWords(active.kind);
|
|
32
|
+
const [name, setName] = useState("");
|
|
33
|
+
const [description, setDescription] = useState("");
|
|
34
|
+
const [imageUrl, setImageUrl] = useState("");
|
|
35
|
+
const [role, setRole] = useState("");
|
|
36
|
+
const [skills, setSkills] = useState("");
|
|
37
|
+
const [schedule, setSchedule] = useState(getDefaultSchedule());
|
|
38
|
+
const [defaultDuration, setDefaultDuration] = useState(60);
|
|
39
|
+
const [bufferMinutes, setBufferMinutes] = useState(0);
|
|
40
|
+
const [advanceBookingDays, setAdvanceBookingDays] = useState(30);
|
|
41
|
+
const [maxBookingsPerSlot, setMaxBookingsPerSlot] = useState(1);
|
|
42
|
+
const [price, setPrice] = useState("");
|
|
43
|
+
const [locationId, setLocationId] = useState("");
|
|
44
|
+
const [timezone, setTimezone] = useState(guessTimezone);
|
|
45
|
+
const [saving, setSaving] = useState(false);
|
|
46
|
+
const { locations, isMultiSite } = useBusinessLocations();
|
|
47
|
+
const [error, setError] = useState(null);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (resource) {
|
|
50
|
+
setName(resource.name);
|
|
51
|
+
setDescription(resource.description || "");
|
|
52
|
+
setImageUrl(resource.imageUrl || "");
|
|
53
|
+
setRole(
|
|
54
|
+
typeof resource.metadata?.role === "string" ? resource.metadata.role : ""
|
|
55
|
+
);
|
|
56
|
+
setSkills(resource.skills?.join(", ") || "");
|
|
57
|
+
setSchedule(resource.schedule || getDefaultSchedule());
|
|
58
|
+
setDefaultDuration(resource.defaultDurationMinutes || 60);
|
|
59
|
+
setBufferMinutes(resource.bufferMinutes || 0);
|
|
60
|
+
setAdvanceBookingDays(resource.advanceBookingDays || 30);
|
|
61
|
+
setMaxBookingsPerSlot(resource.maxBookingsPerSlot || 1);
|
|
62
|
+
setPrice(resource.price != null ? String(resource.price) : "");
|
|
63
|
+
setLocationId(resource.locationId ?? "");
|
|
64
|
+
setTimezone(resource.timezone || guessTimezone());
|
|
65
|
+
setCategoryId(resource.categoryId ?? category.id);
|
|
66
|
+
} else {
|
|
67
|
+
setName("");
|
|
68
|
+
setDescription("");
|
|
69
|
+
setImageUrl("");
|
|
70
|
+
setRole("");
|
|
71
|
+
setSkills("");
|
|
72
|
+
setSchedule(getDefaultSchedule());
|
|
73
|
+
setDefaultDuration(60);
|
|
74
|
+
setBufferMinutes(0);
|
|
75
|
+
setAdvanceBookingDays(30);
|
|
76
|
+
setMaxBookingsPerSlot(active.kind === "space" ? 10 : 1);
|
|
77
|
+
setPrice("");
|
|
78
|
+
setLocationId("");
|
|
79
|
+
setTimezone(guessTimezone());
|
|
80
|
+
setCategoryId(category.id);
|
|
81
|
+
}
|
|
82
|
+
setError(null);
|
|
83
|
+
}, [resource, open, category.id, active.kind]);
|
|
84
|
+
const handleSubmit = async (e) => {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
if (!name.trim()) {
|
|
87
|
+
setError("Name is required");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
setSaving(true);
|
|
91
|
+
setError(null);
|
|
92
|
+
try {
|
|
93
|
+
const metadata = { ...resource?.metadata ?? {} };
|
|
94
|
+
if (role.trim()) metadata.role = role.trim();
|
|
95
|
+
else delete metadata.role;
|
|
96
|
+
const data = {
|
|
97
|
+
name: name.trim(),
|
|
98
|
+
categoryId,
|
|
99
|
+
type: kindToResourceType(active.kind),
|
|
100
|
+
description: description.trim() || void 0,
|
|
101
|
+
imageUrl: imageUrl.trim() || void 0,
|
|
102
|
+
skills: skills ? skills.split(",").map((s) => s.trim()).filter(Boolean) : void 0,
|
|
103
|
+
metadata,
|
|
104
|
+
schedule,
|
|
105
|
+
timezone,
|
|
106
|
+
defaultDurationMinutes: defaultDuration,
|
|
107
|
+
bufferMinutes,
|
|
108
|
+
advanceBookingDays,
|
|
109
|
+
maxBookingsPerSlot,
|
|
110
|
+
price: price ? Number(price) : void 0,
|
|
111
|
+
// Omitted rather than sent empty: the API reads absence as "the main
|
|
112
|
+
// location", which is the right default and not the same instruction
|
|
113
|
+
// as an empty string.
|
|
114
|
+
...locationId ? { locationId } : {}
|
|
115
|
+
};
|
|
116
|
+
await onSave(data);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
setError(err instanceof Error ? err.message : "Failed to save");
|
|
119
|
+
} finally {
|
|
120
|
+
setSaving(false);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
if (!open) return null;
|
|
124
|
+
const nameLabel = active.kind === "person" ? "Full name" : active.kind === "space" ? "Space name" : active.kind === "unit" ? "Unit name" : "Equipment name";
|
|
125
|
+
const namePlaceholder = active.kind === "person" ? "e.g., Dr. Sarah Johnson" : active.kind === "space" ? "e.g., Studio A" : active.kind === "unit" ? "e.g., Ocean View Suite" : "e.g., Projector HD-1";
|
|
126
|
+
return (
|
|
127
|
+
/* FormDialog, not a right-edge slide-over. The panel this drew is the one
|
|
128
|
+
FormDialog was written to delete — five surfaces had each hand-rolled the
|
|
129
|
+
same edge panel, and none of them closed on Escape, trapped Tab or
|
|
130
|
+
restored focus. `lg` because the body genuinely uses the width: a
|
|
131
|
+
two-column grid and the week's schedule editor. */
|
|
132
|
+
/* @__PURE__ */ jsx(
|
|
133
|
+
FormDialog,
|
|
134
|
+
{
|
|
135
|
+
title: isEditing ? `Edit ${active.label.toLowerCase()}` : `Add ${active.label.toLowerCase()}`,
|
|
136
|
+
size: "lg",
|
|
137
|
+
onClose,
|
|
138
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
139
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Cancel" }),
|
|
140
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", form: FORM_ID, loading: saving, children: saving ? "Saving\u2026" : isEditing ? "Save changes" : `Add ${active.label.toLowerCase()}` })
|
|
141
|
+
] }),
|
|
142
|
+
children: /* @__PURE__ */ jsxs("form", { id: FORM_ID, onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
143
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-end gap-4", children: [
|
|
144
|
+
active.kind === "person" && /* @__PURE__ */ jsx(
|
|
145
|
+
ImageUpload,
|
|
146
|
+
{
|
|
147
|
+
value: imageUrl || void 0,
|
|
148
|
+
onChange: (url) => setImageUrl(url ?? ""),
|
|
149
|
+
label: "Photo",
|
|
150
|
+
aspectRatio: "square",
|
|
151
|
+
size: "avatar"
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
155
|
+
/* @__PURE__ */ jsx(
|
|
156
|
+
"label",
|
|
157
|
+
{
|
|
158
|
+
htmlFor: "resource-name",
|
|
159
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
160
|
+
children: nameLabel
|
|
161
|
+
}
|
|
162
|
+
),
|
|
163
|
+
/* @__PURE__ */ jsx(
|
|
164
|
+
Input,
|
|
165
|
+
{
|
|
166
|
+
id: "resource-name",
|
|
167
|
+
type: "text",
|
|
168
|
+
value: name,
|
|
169
|
+
onChange: (e) => setName(e.target.value),
|
|
170
|
+
placeholder: namePlaceholder,
|
|
171
|
+
className: "w-full"
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
] })
|
|
175
|
+
] }),
|
|
176
|
+
groups.length > 1 && /* @__PURE__ */ jsxs("div", { children: [
|
|
177
|
+
/* @__PURE__ */ jsx(
|
|
178
|
+
"label",
|
|
179
|
+
{
|
|
180
|
+
htmlFor: "resource-group",
|
|
181
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
182
|
+
children: "Group"
|
|
183
|
+
}
|
|
184
|
+
),
|
|
185
|
+
/* @__PURE__ */ jsx(
|
|
186
|
+
Select,
|
|
187
|
+
{
|
|
188
|
+
id: "resource-group",
|
|
189
|
+
value: categoryId,
|
|
190
|
+
onChange: setCategoryId,
|
|
191
|
+
options: groups.map((g) => ({
|
|
192
|
+
value: g.id,
|
|
193
|
+
label: g.labelPlural
|
|
194
|
+
}))
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
] }),
|
|
198
|
+
isMultiSite && /* @__PURE__ */ jsxs("div", { children: [
|
|
199
|
+
/* @__PURE__ */ jsx(
|
|
200
|
+
"label",
|
|
201
|
+
{
|
|
202
|
+
htmlFor: "resource-location",
|
|
203
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
204
|
+
children: "Location"
|
|
205
|
+
}
|
|
206
|
+
),
|
|
207
|
+
/* @__PURE__ */ jsx(
|
|
208
|
+
Select,
|
|
209
|
+
{
|
|
210
|
+
id: "resource-location",
|
|
211
|
+
value: locationId,
|
|
212
|
+
onChange: setLocationId,
|
|
213
|
+
options: locations.map((l) => ({
|
|
214
|
+
value: l.id,
|
|
215
|
+
label: l.name
|
|
216
|
+
})),
|
|
217
|
+
placeholder: "Main location"
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
] }),
|
|
221
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
222
|
+
/* @__PURE__ */ jsx(
|
|
223
|
+
"label",
|
|
224
|
+
{
|
|
225
|
+
htmlFor: "resource-description",
|
|
226
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
227
|
+
children: "Description"
|
|
228
|
+
}
|
|
229
|
+
),
|
|
230
|
+
/* @__PURE__ */ jsx(
|
|
231
|
+
Textarea,
|
|
232
|
+
{
|
|
233
|
+
id: "resource-description",
|
|
234
|
+
value: description,
|
|
235
|
+
onChange: (e) => setDescription(e.target.value),
|
|
236
|
+
placeholder: "Brief description...",
|
|
237
|
+
rows: 3,
|
|
238
|
+
className: "w-full resize-none"
|
|
239
|
+
}
|
|
240
|
+
)
|
|
241
|
+
] }),
|
|
242
|
+
active.kind !== "person" && /* @__PURE__ */ jsx(
|
|
243
|
+
ImageUpload,
|
|
244
|
+
{
|
|
245
|
+
value: imageUrl || void 0,
|
|
246
|
+
onChange: (url) => setImageUrl(url ?? ""),
|
|
247
|
+
label: "Image",
|
|
248
|
+
aspectRatio: "video"
|
|
249
|
+
}
|
|
250
|
+
),
|
|
251
|
+
active.kind === "person" && /* @__PURE__ */ jsxs("div", { children: [
|
|
252
|
+
/* @__PURE__ */ jsx(
|
|
253
|
+
"label",
|
|
254
|
+
{
|
|
255
|
+
htmlFor: "resource-role",
|
|
256
|
+
className: "mb-2 block text-sm font-medium text-[var(--text-primary)]",
|
|
257
|
+
children: "Role"
|
|
258
|
+
}
|
|
259
|
+
),
|
|
260
|
+
/* @__PURE__ */ jsx(
|
|
261
|
+
Input,
|
|
262
|
+
{
|
|
263
|
+
id: "resource-role",
|
|
264
|
+
type: "text",
|
|
265
|
+
value: role,
|
|
266
|
+
onChange: (e) => setRole(e.target.value),
|
|
267
|
+
placeholder: "e.g., Physiotherapist",
|
|
268
|
+
className: "w-full"
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
] }),
|
|
272
|
+
active.kind === "person" && /* @__PURE__ */ jsxs("div", { children: [
|
|
273
|
+
/* @__PURE__ */ jsx(
|
|
274
|
+
"label",
|
|
275
|
+
{
|
|
276
|
+
htmlFor: "resource-skills",
|
|
277
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
278
|
+
children: "Skills / specialties"
|
|
279
|
+
}
|
|
280
|
+
),
|
|
281
|
+
/* @__PURE__ */ jsx(
|
|
282
|
+
Input,
|
|
283
|
+
{
|
|
284
|
+
id: "resource-skills",
|
|
285
|
+
type: "text",
|
|
286
|
+
value: skills,
|
|
287
|
+
onChange: (e) => setSkills(e.target.value),
|
|
288
|
+
placeholder: "e.g., Coloring, Braids, Styling",
|
|
289
|
+
className: "w-full"
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-[var(--text-tertiary)]", children: "Comma-separated list of skills" })
|
|
293
|
+
] }),
|
|
294
|
+
(active.kind === "space" || active.kind === "equipment") && /* @__PURE__ */ jsxs("div", { children: [
|
|
295
|
+
/* @__PURE__ */ jsx(
|
|
296
|
+
"label",
|
|
297
|
+
{
|
|
298
|
+
htmlFor: "resource-capacity",
|
|
299
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
300
|
+
children: "At once"
|
|
301
|
+
}
|
|
302
|
+
),
|
|
303
|
+
/* @__PURE__ */ jsx(
|
|
304
|
+
NumberField,
|
|
305
|
+
{
|
|
306
|
+
id: "resource-capacity",
|
|
307
|
+
min: 1,
|
|
308
|
+
decimal: false,
|
|
309
|
+
value: maxBookingsPerSlot,
|
|
310
|
+
onChange: (v) => setMaxBookingsPerSlot(v ?? 1),
|
|
311
|
+
className: "w-full"
|
|
312
|
+
}
|
|
313
|
+
),
|
|
314
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-[var(--text-tertiary)]", children: "How many bookings can share it" })
|
|
315
|
+
] }),
|
|
316
|
+
/* @__PURE__ */ jsxs("div", { className: "border-t border-[var(--border-default)] pt-4", children: [
|
|
317
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-[var(--text-primary)] mb-4", children: "How it is booked" }),
|
|
318
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4 mb-4", children: [
|
|
319
|
+
!byTheNight && /* @__PURE__ */ jsxs("div", { children: [
|
|
320
|
+
/* @__PURE__ */ jsx(
|
|
321
|
+
"label",
|
|
322
|
+
{
|
|
323
|
+
htmlFor: "resource-duration",
|
|
324
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
325
|
+
children: "Duration (minutes)"
|
|
326
|
+
}
|
|
327
|
+
),
|
|
328
|
+
/* @__PURE__ */ jsx(
|
|
329
|
+
NumberField,
|
|
330
|
+
{
|
|
331
|
+
id: "resource-duration",
|
|
332
|
+
min: 5,
|
|
333
|
+
decimal: false,
|
|
334
|
+
value: defaultDuration,
|
|
335
|
+
onChange: (v) => setDefaultDuration(v ?? 5),
|
|
336
|
+
className: "w-full"
|
|
337
|
+
}
|
|
338
|
+
)
|
|
339
|
+
] }),
|
|
340
|
+
!byTheNight && /* @__PURE__ */ jsxs("div", { children: [
|
|
341
|
+
/* @__PURE__ */ jsx(
|
|
342
|
+
"label",
|
|
343
|
+
{
|
|
344
|
+
htmlFor: "resource-buffer",
|
|
345
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
346
|
+
children: "Gap after (minutes)"
|
|
347
|
+
}
|
|
348
|
+
),
|
|
349
|
+
/* @__PURE__ */ jsx(
|
|
350
|
+
NumberField,
|
|
351
|
+
{
|
|
352
|
+
id: "resource-buffer",
|
|
353
|
+
min: 0,
|
|
354
|
+
decimal: false,
|
|
355
|
+
value: bufferMinutes,
|
|
356
|
+
onChange: (v) => setBufferMinutes(v ?? 0),
|
|
357
|
+
className: "w-full"
|
|
358
|
+
}
|
|
359
|
+
)
|
|
360
|
+
] }),
|
|
361
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
362
|
+
/* @__PURE__ */ jsx(
|
|
363
|
+
"label",
|
|
364
|
+
{
|
|
365
|
+
htmlFor: "resource-advance",
|
|
366
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
367
|
+
children: "Booked ahead (days)"
|
|
368
|
+
}
|
|
369
|
+
),
|
|
370
|
+
/* @__PURE__ */ jsx(
|
|
371
|
+
NumberField,
|
|
372
|
+
{
|
|
373
|
+
id: "resource-advance",
|
|
374
|
+
min: 1,
|
|
375
|
+
decimal: false,
|
|
376
|
+
value: advanceBookingDays,
|
|
377
|
+
onChange: (v) => setAdvanceBookingDays(v ?? 1),
|
|
378
|
+
className: "w-full"
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
] }),
|
|
382
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
383
|
+
/* @__PURE__ */ jsx(
|
|
384
|
+
"label",
|
|
385
|
+
{
|
|
386
|
+
htmlFor: "resource-price",
|
|
387
|
+
className: "block text-sm font-medium text-[var(--text-primary)] mb-2",
|
|
388
|
+
children: byTheNight ? "Price a night" : "Price"
|
|
389
|
+
}
|
|
390
|
+
),
|
|
391
|
+
/* @__PURE__ */ jsx(
|
|
392
|
+
Input,
|
|
393
|
+
{
|
|
394
|
+
id: "resource-price",
|
|
395
|
+
type: "number",
|
|
396
|
+
min: 0,
|
|
397
|
+
step: "0.01",
|
|
398
|
+
value: price,
|
|
399
|
+
onChange: (e) => setPrice(e.target.value),
|
|
400
|
+
placeholder: "0.00",
|
|
401
|
+
className: "w-full"
|
|
402
|
+
}
|
|
403
|
+
)
|
|
404
|
+
] })
|
|
405
|
+
] }),
|
|
406
|
+
!byTheNight && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
407
|
+
/* @__PURE__ */ jsx(ScheduleEditor, { schedule, onChange: setSchedule }),
|
|
408
|
+
/* @__PURE__ */ jsx(ScheduleTimezoneField, { value: timezone, onChange: setTimezone })
|
|
409
|
+
] })
|
|
410
|
+
] }),
|
|
411
|
+
/* @__PURE__ */ jsx(ErrorBanner, { children: error })
|
|
412
|
+
] })
|
|
413
|
+
}
|
|
414
|
+
)
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
export {
|
|
418
|
+
ResourceForm
|
|
419
|
+
};
|
|
420
|
+
//# sourceMappingURL=resource-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_components/resource-form.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect } from 'react';\nimport {\n kindToResourceType,\n type Resource,\n type ResourceCategory,\n type WeeklySchedule,\n} from '@withpotter/lib/resource-types';\nimport { ScheduleEditor, getDefaultSchedule } from './schedule-editor';\nimport { availabilityWords } from '../_lib/shapes';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { FormDialog } from '@withpotter/ui-kit/form-dialog';\nimport { ErrorBanner } from '@withpotter/ui-kit/error-banner';\nimport { Input, NumberField, Select } from '@withpotter/ui-kit';\nimport { ImageUpload } from '@withpotter/components/image-upload';\nimport { guessTimezone } from '../_lib/schedule-timezone';\nimport { ScheduleTimezoneField } from './schedule-timezone-field';\nimport { useBusinessLocations } from '@withpotter/lib/use-business-locations';\nimport { Textarea } from '@withpotter/ui-kit';\n\n/** The footer's submit button lives outside the <form>, so it points at this. */\nconst FORM_ID = 'resource-form';\n\n// ─── Props ───────────────────────────────────────────────────────────────────\n\ninterface ResourceFormProps {\n open: boolean;\n /** The group it lands in unless the merchant picks another. */\n category: ResourceCategory;\n /**\n * Every group, so a business with more than one is asked which.\n *\n * The roster creates from the page header now rather than from inside a\n * group's own screen, so the group is no longer implied by where you pressed.\n * One group and the question does not exist; two and it must be asked, or\n * the new court quietly joins the coaches.\n */\n categories?: ResourceCategory[];\n resource?: Resource | null;\n onSave: (data: Record<string, unknown>) => Promise<void>;\n onClose: () => void;\n}\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport function ResourceForm({\n open,\n category,\n categories,\n resource,\n onSave,\n onClose,\n}: ResourceFormProps) {\n const isEditing = !!resource;\n const [categoryId, setCategoryId] = useState(category.id);\n const groups = categories ?? [];\n /** Labels and defaults follow the group actually chosen, not the one passed. */\n const active = groups.find((c) => c.id === categoryId) ?? category;\n const { byTheNight } = availabilityWords(active.kind);\n\n // Form state\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [imageUrl, setImageUrl] = useState('');\n const [role, setRole] = useState('');\n const [skills, setSkills] = useState('');\n const [schedule, setSchedule] =\n useState<WeeklySchedule>(getDefaultSchedule());\n const [defaultDuration, setDefaultDuration] = useState(60);\n const [bufferMinutes, setBufferMinutes] = useState(0);\n const [advanceBookingDays, setAdvanceBookingDays] = useState(30);\n const [maxBookingsPerSlot, setMaxBookingsPerSlot] = useState(1);\n const [price, setPrice] = useState('');\n const [locationId, setLocationId] = useState('');\n const [timezone, setTimezone] = useState(guessTimezone);\n const [saving, setSaving] = useState(false);\n\n // A court, room or chair sits at one address. Only asked once a second\n // branch exists — before that there is one answer and the API supplies it.\n const { locations, isMultiSite } = useBusinessLocations();\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (resource) {\n setName(resource.name);\n setDescription(resource.description || '');\n setImageUrl(resource.imageUrl || '');\n setRole(\n typeof resource.metadata?.role === 'string'\n ? resource.metadata.role\n : '',\n );\n setSkills(resource.skills?.join(', ') || '');\n setSchedule(resource.schedule || getDefaultSchedule());\n setDefaultDuration(resource.defaultDurationMinutes || 60);\n setBufferMinutes(resource.bufferMinutes || 0);\n setAdvanceBookingDays(resource.advanceBookingDays || 30);\n setMaxBookingsPerSlot(resource.maxBookingsPerSlot || 1);\n setPrice(resource.price != null ? String(resource.price) : '');\n setLocationId(resource.locationId ?? '');\n setTimezone(resource.timezone || guessTimezone());\n setCategoryId(resource.categoryId ?? category.id);\n } else {\n setName('');\n setDescription('');\n setImageUrl('');\n setRole('');\n setSkills('');\n setSchedule(getDefaultSchedule());\n setDefaultDuration(60);\n setBufferMinutes(0);\n setAdvanceBookingDays(30);\n setMaxBookingsPerSlot(active.kind === 'space' ? 10 : 1);\n setPrice('');\n setLocationId('');\n setTimezone(guessTimezone());\n setCategoryId(category.id);\n }\n setError(null);\n }, [resource, open, category.id, active.kind]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!name.trim()) {\n setError('Name is required');\n return;\n }\n\n setSaving(true);\n setError(null);\n\n try {\n const metadata = { ...(resource?.metadata ?? {}) };\n if (role.trim()) metadata.role = role.trim();\n else delete metadata.role;\n\n const data = {\n name: name.trim(),\n categoryId,\n type: kindToResourceType(active.kind),\n description: description.trim() || undefined,\n imageUrl: imageUrl.trim() || undefined,\n skills: skills\n ? skills\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined,\n metadata,\n schedule,\n timezone,\n defaultDurationMinutes: defaultDuration,\n bufferMinutes,\n advanceBookingDays,\n maxBookingsPerSlot,\n price: price ? Number(price) : undefined,\n // Omitted rather than sent empty: the API reads absence as \"the main\n // location\", which is the right default and not the same instruction\n // as an empty string.\n ...(locationId ? { locationId } : {}),\n };\n await onSave(data);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to save');\n } finally {\n setSaving(false);\n }\n };\n\n if (!open) return null;\n\n // Labels that adapt based on category kind\n const nameLabel =\n active.kind === 'person'\n ? 'Full name'\n : active.kind === 'space'\n ? 'Space name'\n : active.kind === 'unit'\n ? 'Unit name'\n : 'Equipment name';\n\n const namePlaceholder =\n active.kind === 'person'\n ? 'e.g., Dr. Sarah Johnson'\n : active.kind === 'space'\n ? 'e.g., Studio A'\n : active.kind === 'unit'\n ? 'e.g., Ocean View Suite'\n : 'e.g., Projector HD-1';\n\n return (\n /* FormDialog, not a right-edge slide-over. The panel this drew is the one\n FormDialog was written to delete — five surfaces had each hand-rolled the\n same edge panel, and none of them closed on Escape, trapped Tab or\n restored focus. `lg` because the body genuinely uses the width: a\n two-column grid and the week's schedule editor. */\n <FormDialog\n title={\n isEditing\n ? `Edit ${active.label.toLowerCase()}`\n : `Add ${active.label.toLowerCase()}`\n }\n size=\"lg\"\n onClose={onClose}\n footer={\n <>\n <Button variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n {/* `form`, because the footer sits outside the <form> element. */}\n <Button type=\"submit\" form={FORM_ID} loading={saving}>\n {saving\n ? 'Saving…'\n : isEditing\n ? 'Save changes'\n : `Add ${active.label.toLowerCase()}`}\n </Button>\n </>\n }\n >\n <form id={FORM_ID} onSubmit={handleSubmit} className=\"space-y-4\">\n {/* THE FACE SITS WITH THE NAME.\n A person's photo was a full-width dashed zone further down the form,\n which read as a header across the top of the fields rather than as\n one of them. It is 80px beside the name now — the shape a staff form\n takes everywhere a merchant has seen one. A room or a court keeps\n the wide field lower down, where a picture of a place is a picture\n of a place. */}\n <div className=\"flex items-end gap-4\">\n {active.kind === 'person' && (\n <ImageUpload\n value={imageUrl || undefined}\n onChange={(url) => setImageUrl(url ?? '')}\n label=\"Photo\"\n aspectRatio=\"square\"\n size=\"avatar\"\n />\n )}\n <div className=\"min-w-0 flex-1\">\n <label\n htmlFor=\"resource-name\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n {nameLabel}\n </label>\n <Input\n id=\"resource-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={namePlaceholder}\n className=\"w-full\"\n />\n </div>\n </div>\n\n {/* Which group it joins. One group and there is nothing to ask. */}\n {groups.length > 1 && (\n <div>\n <label\n htmlFor=\"resource-group\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n Group\n </label>\n <Select\n id=\"resource-group\"\n value={categoryId}\n onChange={setCategoryId}\n options={groups.map((g) => ({\n value: g.id,\n label: g.labelPlural,\n }))}\n />\n </div>\n )}\n\n {/* Which branch it is at. Hidden on a single-site business. */}\n {isMultiSite && (\n <div>\n <label\n htmlFor=\"resource-location\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n Location\n </label>\n <Select\n id=\"resource-location\"\n value={locationId}\n onChange={setLocationId}\n options={locations.map((l) => ({\n value: l.id,\n label: l.name,\n }))}\n placeholder=\"Main location\"\n />\n </div>\n )}\n\n {/* Description */}\n <div>\n <label\n htmlFor=\"resource-description\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n Description\n </label>\n <Textarea\n id=\"resource-description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Brief description...\"\n rows={3}\n className=\"w-full resize-none\"\n />\n </div>\n\n {/* THE PICTURE, WITH SOMEWHERE TO PUT ONE.\n *\n * This was a bare `type=\"url\"` field placeholdered `https://...`, which\n * asks a merchant adding a member of staff to go and host a photograph\n * somewhere first and come back with a link. John, 2026-08-23: *\"when\n * adding a staff it's showing import image with url, there's no\n * affordance to upload an image\"*.\n *\n * `ImageUpload` is the app's image field and has been all along — drop\n * it, browse for it, or paste a link, with the link input still there\n * under the zone. This screen was simply not using it. Nothing about\n * the value changes: both produce a URL in `imageUrl`.\n *\n * A person is not here: a face is 80px beside the name field at the\n * top of this form, not a banner across it. This is the wide zone,\n * and a picture of a room or a court IS wide.\n */}\n {active.kind !== 'person' && (\n <ImageUpload\n value={imageUrl || undefined}\n onChange={(url) => setImageUrl(url ?? '')}\n label=\"Image\"\n aspectRatio=\"video\"\n />\n )}\n\n {/* Skills (person kind only) */}\n {active.kind === 'person' && (\n <div>\n <label\n htmlFor=\"resource-role\"\n className=\"mb-2 block text-sm font-medium text-[var(--text-primary)]\"\n >\n Role\n </label>\n <Input\n id=\"resource-role\"\n type=\"text\"\n value={role}\n onChange={(e) => setRole(e.target.value)}\n placeholder=\"e.g., Physiotherapist\"\n className=\"w-full\"\n />\n </div>\n )}\n\n {active.kind === 'person' && (\n <div>\n <label\n htmlFor=\"resource-skills\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n Skills / specialties\n </label>\n <Input\n id=\"resource-skills\"\n type=\"text\"\n value={skills}\n onChange={(e) => setSkills(e.target.value)}\n placeholder=\"e.g., Coloring, Braids, Styling\"\n className=\"w-full\"\n />\n <p className=\"mt-1 text-xs text-[var(--text-tertiary)]\">\n Comma-separated list of skills\n </p>\n </div>\n )}\n\n {/* Capacity (space kind) */}\n {/* SHARED, NOT JUST SPATIAL.\n\n Capacity was asked only of a space, which left a merchant with ten\n interchangeable rackets no way to say so: either ten rows nobody\n picks between, or one row that takes one booking a slot. The rule is\n the same for both — if a customer would say \"that one\" it is a row,\n and if they would only say \"one of those\" it is this number. A\n person is one person and a let is one let, so neither is asked. */}\n {(active.kind === 'space' || active.kind === 'equipment') && (\n <div>\n <label\n htmlFor=\"resource-capacity\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n At once\n </label>\n <NumberField\n id=\"resource-capacity\"\n min={1}\n decimal={false}\n value={maxBookingsPerSlot}\n onChange={(v) => setMaxBookingsPerSlot(v ?? 1)}\n className=\"w-full\"\n />\n <p className=\"mt-1 text-xs text-[var(--text-tertiary)]\">\n How many bookings can share it\n </p>\n </div>\n )}\n\n {/* Scheduling section */}\n <div className=\"border-t border-[var(--border-default)] pt-4\">\n <h3 className=\"text-sm font-semibold text-[var(--text-primary)] mb-4\">\n How it is booked\n </h3>\n\n {/* A NIGHT IS NOT A SESSION.\n\n Duration, the gap after, and a week of opening hours are the three\n questions an hour-shaped booking answers. An apartment answers\n none of them — it is taken by the night — and asking anyway put\n \"9am to 5pm, Monday to Friday\" on a holiday let and a 60-minute\n duration on a three-night stay. The shape decides which questions\n exist; it is the same form otherwise. */}\n <div className=\"grid grid-cols-2 gap-4 mb-4\">\n {/* Duration */}\n {!byTheNight && (\n <div>\n <label\n htmlFor=\"resource-duration\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n Duration (minutes)\n </label>\n <NumberField\n id=\"resource-duration\"\n min={5}\n decimal={false}\n value={defaultDuration}\n onChange={(v) => setDefaultDuration(v ?? 5)}\n className=\"w-full\"\n />\n </div>\n )}\n\n {/* Buffer */}\n {!byTheNight && (\n <div>\n <label\n htmlFor=\"resource-buffer\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n Gap after (minutes)\n </label>\n <NumberField\n id=\"resource-buffer\"\n min={0}\n decimal={false}\n value={bufferMinutes}\n onChange={(v) => setBufferMinutes(v ?? 0)}\n className=\"w-full\"\n />\n </div>\n )}\n\n {/* Advance booking */}\n <div>\n <label\n htmlFor=\"resource-advance\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n Booked ahead (days)\n </label>\n <NumberField\n id=\"resource-advance\"\n min={1}\n decimal={false}\n value={advanceBookingDays}\n onChange={(v) => setAdvanceBookingDays(v ?? 1)}\n className=\"w-full\"\n />\n </div>\n\n {/* Price */}\n <div>\n <label\n htmlFor=\"resource-price\"\n className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\"\n >\n {byTheNight ? 'Price a night' : 'Price'}\n </label>\n <Input\n id=\"resource-price\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={price}\n onChange={(e) => setPrice(e.target.value)}\n placeholder=\"0.00\"\n className=\"w-full\"\n />\n </div>\n </div>\n\n {/* Schedule Editor — see the note above: not for a let. */}\n {!byTheNight && (\n <>\n <ScheduleEditor schedule={schedule} onChange={setSchedule} />\n <ScheduleTimezoneField value={timezone} onChange={setTimezone} />\n </>\n )}\n </div>\n\n <ErrorBanner>{error}</ErrorBanner>\n </form>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { AnimatePresence, motion } from "motion/react";
|
|
5
|
+
import { Building2, DoorOpen, Plus, Users, Wrench } from "lucide-react";
|
|
6
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
7
|
+
import { Input } from "@withpotter/ui-kit";
|
|
8
|
+
import { OptionButton } from "@withpotter/ui-kit/option-button";
|
|
9
|
+
import { allPresets, customPreset } from "../_lib/presets";
|
|
10
|
+
const ICON_BY_KIND = {
|
|
11
|
+
person: Users,
|
|
12
|
+
space: DoorOpen,
|
|
13
|
+
equipment: Wrench,
|
|
14
|
+
unit: Building2
|
|
15
|
+
};
|
|
16
|
+
const HEADING_BY_KIND = {
|
|
17
|
+
person: "People",
|
|
18
|
+
space: "Places",
|
|
19
|
+
equipment: "Kit",
|
|
20
|
+
unit: "Stays"
|
|
21
|
+
};
|
|
22
|
+
function ResourcePicker({
|
|
23
|
+
selectedId,
|
|
24
|
+
category,
|
|
25
|
+
onPick,
|
|
26
|
+
onCategoryChange
|
|
27
|
+
}) {
|
|
28
|
+
const filterKind = category ?? "";
|
|
29
|
+
const categoryOpen = !!category;
|
|
30
|
+
const matchingPresets = allPresets();
|
|
31
|
+
const filteredPresets = filterKind ? matchingPresets.filter((preset) => preset.kind === filterKind) : matchingPresets;
|
|
32
|
+
const order = [
|
|
33
|
+
"person",
|
|
34
|
+
"space",
|
|
35
|
+
"equipment",
|
|
36
|
+
"unit"
|
|
37
|
+
];
|
|
38
|
+
const visibleKinds = filterKind ? [filterKind] : order;
|
|
39
|
+
const blocks = visibleKinds.map((kind) => ({
|
|
40
|
+
kind,
|
|
41
|
+
items: (() => {
|
|
42
|
+
const all = filteredPresets.filter((p) => p.kind === kind);
|
|
43
|
+
return all;
|
|
44
|
+
})()
|
|
45
|
+
})).filter((block) => block.items.length > 0);
|
|
46
|
+
const closeCategory = () => {
|
|
47
|
+
onCategoryChange(null);
|
|
48
|
+
};
|
|
49
|
+
const [ownName, setOwnName] = useState("");
|
|
50
|
+
const own = filterKind ? customPreset(filterKind, ownName) : null;
|
|
51
|
+
const addOwn = () => {
|
|
52
|
+
if (!own) return;
|
|
53
|
+
closeCategory();
|
|
54
|
+
onPick(own);
|
|
55
|
+
};
|
|
56
|
+
const blockContent = blocks.map(({ kind, items }) => {
|
|
57
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
58
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2 sm:grid-cols-3", children: items.map((preset) => /* @__PURE__ */ jsx(
|
|
59
|
+
OptionButton,
|
|
60
|
+
{
|
|
61
|
+
shape: "card",
|
|
62
|
+
selected: selectedId === preset.id,
|
|
63
|
+
className: "min-h-14 justify-start bg-[var(--bg-muted)]/60 px-4 text-base",
|
|
64
|
+
onClick: () => {
|
|
65
|
+
if (categoryOpen) closeCategory();
|
|
66
|
+
onPick(preset);
|
|
67
|
+
},
|
|
68
|
+
children: preset.plural
|
|
69
|
+
},
|
|
70
|
+
preset.id
|
|
71
|
+
)) }),
|
|
72
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
Input,
|
|
75
|
+
{
|
|
76
|
+
value: ownName,
|
|
77
|
+
onChange: (e) => setOwnName(e.target.value),
|
|
78
|
+
onKeyDown: (e) => {
|
|
79
|
+
if (e.key === "Enter") {
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
addOwn();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
placeholder: "Not listed? Type your own, e.g. Master barbers",
|
|
85
|
+
"aria-label": "Name your own"
|
|
86
|
+
}
|
|
87
|
+
),
|
|
88
|
+
/* @__PURE__ */ jsx(
|
|
89
|
+
Button,
|
|
90
|
+
{
|
|
91
|
+
type: "button",
|
|
92
|
+
variant: "secondary",
|
|
93
|
+
onClick: addOwn,
|
|
94
|
+
disabled: !own,
|
|
95
|
+
icon: /* @__PURE__ */ jsx(Plus, { className: "size-4" }),
|
|
96
|
+
children: "Add"
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
] })
|
|
100
|
+
] }, kind);
|
|
101
|
+
});
|
|
102
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, children: categoryOpen && filterKind ? /* @__PURE__ */ jsx(
|
|
103
|
+
motion.div,
|
|
104
|
+
{
|
|
105
|
+
initial: { opacity: 0, x: 12 },
|
|
106
|
+
animate: { opacity: 1, x: 0 },
|
|
107
|
+
exit: { opacity: 0, x: -12 },
|
|
108
|
+
transition: { duration: 0.16 },
|
|
109
|
+
children: blockContent
|
|
110
|
+
},
|
|
111
|
+
`presets-${filterKind}`
|
|
112
|
+
) : /* @__PURE__ */ jsx(
|
|
113
|
+
motion.div,
|
|
114
|
+
{
|
|
115
|
+
initial: { opacity: 0, x: -12 },
|
|
116
|
+
animate: { opacity: 1, x: 0 },
|
|
117
|
+
exit: { opacity: 0, x: 12 },
|
|
118
|
+
transition: { duration: 0.16 },
|
|
119
|
+
className: "grid grid-cols-2 gap-2 sm:grid-cols-4",
|
|
120
|
+
children: ["person", "space", "equipment", "unit"].map((kind) => {
|
|
121
|
+
const Icon = ICON_BY_KIND[kind];
|
|
122
|
+
return /* @__PURE__ */ jsxs(
|
|
123
|
+
OptionButton,
|
|
124
|
+
{
|
|
125
|
+
shape: "card",
|
|
126
|
+
selected: filterKind === kind,
|
|
127
|
+
className: "min-h-24 flex-col items-start justify-between gap-3 bg-[var(--bg-muted)]/60 p-4 text-left",
|
|
128
|
+
onClick: () => onCategoryChange(kind),
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ jsx(Icon, { className: "size-5 text-[var(--text-tertiary)]" }),
|
|
131
|
+
/* @__PURE__ */ jsx("span", { className: "block text-sm font-semibold", children: HEADING_BY_KIND[kind] })
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
kind
|
|
135
|
+
);
|
|
136
|
+
})
|
|
137
|
+
},
|
|
138
|
+
"categories"
|
|
139
|
+
) }) });
|
|
140
|
+
}
|
|
141
|
+
export {
|
|
142
|
+
ResourcePicker
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=resource-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_components/resource-picker.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { AnimatePresence, motion } from 'motion/react';\nimport { Building2, DoorOpen, Plus, Users, Wrench } from 'lucide-react';\nimport type { LucideIcon } from 'lucide-react';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Input } from '@withpotter/ui-kit';\nimport { OptionButton } from '@withpotter/ui-kit/option-button';\nimport type { ResourceCategoryKind } from '@withpotter/lib/resource-types';\nimport { allPresets, customPreset, type ResourcePreset } from '../_lib/presets';\n\nconst ICON_BY_KIND: Record<ResourceCategoryKind, LucideIcon> = {\n person: Users,\n space: DoorOpen,\n equipment: Wrench,\n unit: Building2,\n};\n\n/**\n * The heading over each block of nouns.\n *\n * NOT the shape titles. \"Someone\" and \"A stay\" are answers to the question\n * *what does a booking take up* — they read as a sentence because they were\n * the whole control. Standing above a row of concrete words they have to be\n * the category those words belong to instead, or the grid reads \"Someone:\n * Stylist, Barber\", which is nobody's English.\n */\nconst HEADING_BY_KIND: Record<ResourceCategoryKind, string> = {\n person: 'People',\n space: 'Places',\n equipment: 'Kit',\n unit: 'Stays',\n};\n\n/**\n * The grid of things this business could be booking.\n *\n * A merchant's own trade first, because that is the list with their word in\n * it, and everything else one press away — a kart track, a storage yard and a\n * hotel with a restaurant in it all exist and none of them is an archetype.\n * The picker stays focused on the supported resource types and presets.\n */\nexport function ResourcePicker({\n selectedId,\n category,\n onPick,\n onCategoryChange,\n}: {\n intentKeys: string[];\n selectedId: string | null;\n showingAll: boolean;\n category: ResourceCategoryKind | null;\n onPick: (preset: ResourcePreset) => void;\n onCategoryChange: (kind: ResourceCategoryKind | null) => void;\n}) {\n const filterKind = category ?? '';\n const categoryOpen = !!category;\n const matchingPresets = allPresets();\n const filteredPresets = filterKind\n ? matchingPresets.filter((preset) => preset.kind === filterKind)\n : matchingPresets;\n\n // The trade's leading shape leads the grid, the same order `shapesFor` puts\n // the shapes in — a restaurant opens on Places, a shortlet on Stays.\n const order: ResourceCategoryKind[] = [\n 'person',\n 'space',\n 'equipment',\n 'unit',\n ];\n const visibleKinds = filterKind ? [filterKind] : order;\n const blocks = visibleKinds\n .map((kind) => ({\n kind,\n items: (() => {\n const all = filteredPresets.filter((p) => p.kind === kind);\n return all;\n })(),\n }))\n .filter((block) => block.items.length > 0);\n\n const closeCategory = () => {\n onCategoryChange(null);\n };\n\n /* The list ends in a blank, because a list of nouns is never finished. */\n const [ownName, setOwnName] = useState('');\n const own = filterKind ? customPreset(filterKind, ownName) : null;\n const addOwn = () => {\n if (!own) return;\n closeCategory();\n onPick(own);\n };\n\n const blockContent = blocks.map(({ kind, items }) => {\n return (\n <div key={kind} className=\"space-y-3\">\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-3\">\n {items.map((preset) => (\n <OptionButton\n key={preset.id}\n shape=\"card\"\n selected={selectedId === preset.id}\n className=\"min-h-14 justify-start bg-[var(--bg-muted)]/60 px-4 text-base\"\n onClick={() => {\n if (categoryOpen) closeCategory();\n onPick(preset);\n }}\n >\n {preset.plural}\n </OptionButton>\n ))}\n </div>\n <div className=\"flex gap-2\">\n <Input\n value={ownName}\n onChange={(e) => setOwnName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n addOwn();\n }\n }}\n placeholder=\"Not listed? Type your own, e.g. Master barbers\"\n aria-label=\"Name your own\"\n />\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={addOwn}\n disabled={!own}\n icon={<Plus className=\"size-4\" />}\n >\n Add\n </Button>\n </div>\n </div>\n );\n });\n\n return (\n <div className=\"space-y-4\">\n <AnimatePresence mode=\"wait\" initial={false}>\n {categoryOpen && filterKind ? (\n <motion.div\n key={`presets-${filterKind}`}\n initial={{ opacity: 0, x: 12 }}\n animate={{ opacity: 1, x: 0 }}\n exit={{ opacity: 0, x: -12 }}\n transition={{ duration: 0.16 }}\n >\n {blockContent}\n </motion.div>\n ) : (\n <motion.div\n key=\"categories\"\n initial={{ opacity: 0, x: -12 }}\n animate={{ opacity: 1, x: 0 }}\n exit={{ opacity: 0, x: 12 }}\n transition={{ duration: 0.16 }}\n className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\"\n >\n {(['person', 'space', 'equipment', 'unit'] as const).map((kind) => {\n const Icon = ICON_BY_KIND[kind];\n return (\n <OptionButton\n key={kind}\n shape=\"card\"\n selected={filterKind === kind}\n className=\"min-h-24 flex-col items-start justify-between gap-3 bg-[var(--bg-muted)]/60 p-4 text-left\"\n onClick={() => onCategoryChange(kind)}\n >\n <Icon className=\"size-5 text-[var(--text-tertiary)]\" />\n <span className=\"block text-sm font-semibold\">\n {HEADING_BY_KIND[kind]}\n </span>\n </OptionButton>\n );\n })}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|