@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,109 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { motion, useReducedMotion } from "motion/react";
|
|
5
|
+
import { springs, eases } from "@withpotter/lib/motion";
|
|
6
|
+
import { cn } from "@withpotter/lib/utils";
|
|
7
|
+
import {
|
|
8
|
+
monthDays,
|
|
9
|
+
parseISO,
|
|
10
|
+
toISODate,
|
|
11
|
+
bookingsByDay,
|
|
12
|
+
fullness
|
|
13
|
+
} from "./calendar-range";
|
|
14
|
+
const WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
15
|
+
function MonthGrid({
|
|
16
|
+
anchor,
|
|
17
|
+
events,
|
|
18
|
+
resourceCount,
|
|
19
|
+
onOpenDay
|
|
20
|
+
}) {
|
|
21
|
+
const reduce = useReducedMotion();
|
|
22
|
+
const days = useMemo(() => monthDays(anchor), [anchor]);
|
|
23
|
+
const counts = useMemo(() => bookingsByDay(events), [events]);
|
|
24
|
+
const today = toISODate(/* @__PURE__ */ new Date());
|
|
25
|
+
const leadingBlanks = parseISO(days[0]).getDay();
|
|
26
|
+
const grid = {
|
|
27
|
+
hidden: {},
|
|
28
|
+
shown: { transition: { staggerChildren: reduce ? 0 : 8e-3 } }
|
|
29
|
+
};
|
|
30
|
+
const cell = {
|
|
31
|
+
hidden: reduce ? {} : { opacity: 0, y: 6 },
|
|
32
|
+
shown: {
|
|
33
|
+
opacity: 1,
|
|
34
|
+
y: 0,
|
|
35
|
+
transition: { duration: 0.2, ease: eases.settle }
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
return /* @__PURE__ */ jsxs("div", { className: "surface p-3", children: [
|
|
39
|
+
/* @__PURE__ */ jsx("div", { className: "mb-2 grid grid-cols-7 gap-2", children: WEEKDAYS.map((w) => /* @__PURE__ */ jsx(
|
|
40
|
+
"span",
|
|
41
|
+
{
|
|
42
|
+
className: "px-1 text-3xs uppercase tracking-wide text-[var(--text-muted)]",
|
|
43
|
+
children: w
|
|
44
|
+
},
|
|
45
|
+
w
|
|
46
|
+
)) }),
|
|
47
|
+
/* @__PURE__ */ jsxs(
|
|
48
|
+
motion.div,
|
|
49
|
+
{
|
|
50
|
+
variants: grid,
|
|
51
|
+
initial: "hidden",
|
|
52
|
+
animate: "shown",
|
|
53
|
+
className: "grid grid-cols-7 gap-2",
|
|
54
|
+
children: [
|
|
55
|
+
Array.from({ length: leadingBlanks }).map((_, i) => /* @__PURE__ */ jsx("span", {}, `blank-${i}`)),
|
|
56
|
+
days.map((d) => {
|
|
57
|
+
const booked = counts.get(d) ?? 0;
|
|
58
|
+
const fill = fullness(booked, resourceCount);
|
|
59
|
+
const dt = parseISO(d);
|
|
60
|
+
return /* @__PURE__ */ jsxs(
|
|
61
|
+
motion.button,
|
|
62
|
+
{
|
|
63
|
+
variants: cell,
|
|
64
|
+
onClick: () => onOpenDay(d),
|
|
65
|
+
whileHover: reduce ? void 0 : { y: -2 },
|
|
66
|
+
whileTap: reduce ? void 0 : { scale: 0.98 },
|
|
67
|
+
transition: springs.snappy,
|
|
68
|
+
className: cn(
|
|
69
|
+
"flex min-h-[76px] flex-col justify-between rounded-lg border p-2 text-left transition-[background-color,border-color,box-shadow] duration-[var(--motion-fast)]",
|
|
70
|
+
d === today ? "border-brand-500/50 bg-brand-500/[0.08]" : "border-[var(--border-default)] bg-[var(--bg-base)] hover:border-[var(--border-strong)] hover:bg-[var(--interactive-hover)]"
|
|
71
|
+
),
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
"span",
|
|
75
|
+
{
|
|
76
|
+
className: cn(
|
|
77
|
+
"text-sm font-semibold tabular-nums",
|
|
78
|
+
d === today ? "text-brand-500" : "text-[var(--text-primary)]"
|
|
79
|
+
),
|
|
80
|
+
children: dt.getDate()
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsxs("span", { className: "space-y-1", children: [
|
|
84
|
+
/* @__PURE__ */ jsx("span", { className: "block text-2xs text-[var(--text-tertiary)]", children: booked > 0 ? `${booked} booked` : "" }),
|
|
85
|
+
/* @__PURE__ */ jsx("span", { className: "block h-1 rounded-full bg-[var(--bg-muted)]", children: /* @__PURE__ */ jsx(
|
|
86
|
+
motion.span,
|
|
87
|
+
{
|
|
88
|
+
className: "block h-1 rounded-full bg-brand-500",
|
|
89
|
+
initial: reduce ? false : { scaleX: 0 },
|
|
90
|
+
animate: { scaleX: fill },
|
|
91
|
+
style: { transformOrigin: "left" },
|
|
92
|
+
transition: { duration: 0.4, ease: eases.settle }
|
|
93
|
+
}
|
|
94
|
+
) })
|
|
95
|
+
] })
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
d
|
|
99
|
+
);
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
] });
|
|
105
|
+
}
|
|
106
|
+
export {
|
|
107
|
+
MonthGrid
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=month-grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/month-grid.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport { motion, useReducedMotion } from 'motion/react';\nimport { springs, eases } from '@withpotter/lib/motion';\nimport { cn } from '@withpotter/lib/utils';\nimport type { CalendarEventItem } from '@withpotter/lib/api/types';\nimport {\n monthDays,\n parseISO,\n toISODate,\n bookingsByDay,\n fullness,\n} from './calendar-range';\n\nconst WEEKDAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n\nexport interface MonthGridProps {\n anchor: string;\n events: CalendarEventItem[];\n resourceCount: number;\n onOpenDay: (date: string) => void;\n}\n\n/**\n * A month you read for shape, not for detail.\n *\n * A month of individual bookings is unreadable and nobody tries — what the\n * question \"what does next month look like?\" actually wants is where the busy\n * weeks are and where the holes are. So each day carries its count and a\n * fullness bar, and pressing one drops into the day board where the detail is.\n */\nexport function MonthGrid({\n anchor,\n events,\n resourceCount,\n onOpenDay,\n}: MonthGridProps) {\n const reduce = useReducedMotion();\n const days = useMemo(() => monthDays(anchor), [anchor]);\n const counts = useMemo(() => bookingsByDay(events), [events]);\n const today = toISODate(new Date());\n\n // Blank cells so the 1st lands under its weekday.\n const leadingBlanks = parseISO(days[0]).getDay();\n\n const grid = {\n hidden: {},\n shown: { transition: { staggerChildren: reduce ? 0 : 0.008 } },\n };\n const cell = {\n hidden: reduce ? {} : { opacity: 0, y: 6 },\n shown: {\n opacity: 1,\n y: 0,\n transition: { duration: 0.2, ease: eases.settle },\n },\n };\n\n return (\n <div className=\"surface p-3\">\n <div className=\"mb-2 grid grid-cols-7 gap-2\">\n {WEEKDAYS.map((w) => (\n <span\n key={w}\n className=\"px-1 text-3xs uppercase tracking-wide text-[var(--text-muted)]\"\n >\n {w}\n </span>\n ))}\n </div>\n\n <motion.div\n variants={grid}\n initial=\"hidden\"\n animate=\"shown\"\n className=\"grid grid-cols-7 gap-2\"\n >\n {Array.from({ length: leadingBlanks }).map((_, i) => (\n <span key={`blank-${i}`} />\n ))}\n\n {days.map((d) => {\n const booked = counts.get(d) ?? 0;\n const fill = fullness(booked, resourceCount);\n const dt = parseISO(d);\n return (\n <motion.button\n key={d}\n variants={cell}\n onClick={() => onOpenDay(d)}\n whileHover={reduce ? undefined : { y: -2 }}\n whileTap={reduce ? undefined : { scale: 0.98 }}\n transition={springs.snappy}\n className={cn(\n 'flex min-h-[76px] flex-col justify-between rounded-lg border p-2 text-left transition-[background-color,border-color,box-shadow] duration-[var(--motion-fast)]',\n d === today\n ? 'border-brand-500/50 bg-brand-500/[0.08]'\n : 'border-[var(--border-default)] bg-[var(--bg-base)] hover:border-[var(--border-strong)] hover:bg-[var(--interactive-hover)]',\n )}\n >\n <span\n className={cn(\n 'text-sm font-semibold tabular-nums',\n d === today ? 'text-brand-500' : 'text-[var(--text-primary)]',\n )}\n >\n {dt.getDate()}\n </span>\n\n <span className=\"space-y-1\">\n <span className=\"block text-2xs text-[var(--text-tertiary)]\">\n {booked > 0 ? `${booked} booked` : ''}\n </span>\n <span className=\"block h-1 rounded-full bg-[var(--bg-muted)]\">\n <motion.span\n className=\"block h-1 rounded-full bg-brand-500\"\n initial={reduce ? false : { scaleX: 0 }}\n animate={{ scaleX: fill }}\n style={{ transformOrigin: 'left' }}\n transition={{ duration: 0.4, ease: eases.settle }}\n />\n </span>\n </span>\n </motion.button>\n );\n })}\n </motion.div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { motion, useReducedMotion } from "motion/react";
|
|
5
|
+
import { Plus, Ban } from "lucide-react";
|
|
6
|
+
import { springs, eases, PRESS_SCALE_LARGE } from "@withpotter/lib/motion";
|
|
7
|
+
import { cn } from "@withpotter/lib/utils";
|
|
8
|
+
import { Button } from "@withpotter/ui-kit/button";
|
|
9
|
+
import { statusTextClass } from "@withpotter/components/shared/status-badge";
|
|
10
|
+
import { useBlockDrag } from "./use-block-drag";
|
|
11
|
+
import { formatTime } from "./format";
|
|
12
|
+
const HOUR_PX = 60;
|
|
13
|
+
function hhmm(h) {
|
|
14
|
+
return `${String(h).padStart(2, "0")}:00`;
|
|
15
|
+
}
|
|
16
|
+
function clockLabel(h) {
|
|
17
|
+
const suffix = h >= 12 ? "pm" : "am";
|
|
18
|
+
const hour = h % 12 === 0 ? 12 : h % 12;
|
|
19
|
+
return `${hour}${suffix}`;
|
|
20
|
+
}
|
|
21
|
+
function hourOf(iso) {
|
|
22
|
+
const d = new Date(iso);
|
|
23
|
+
return d.getHours() + d.getMinutes() / 60;
|
|
24
|
+
}
|
|
25
|
+
function ResourceDayGrid({
|
|
26
|
+
date,
|
|
27
|
+
resources,
|
|
28
|
+
events,
|
|
29
|
+
openHour = 8,
|
|
30
|
+
closeHour = 20,
|
|
31
|
+
resourceLabel,
|
|
32
|
+
onBookSlot,
|
|
33
|
+
onSelectEvent,
|
|
34
|
+
onMoveEvent,
|
|
35
|
+
loading
|
|
36
|
+
}) {
|
|
37
|
+
const reduce = useReducedMotion();
|
|
38
|
+
const [nowHour, setNowHour] = useState(null);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const tick = () => {
|
|
41
|
+
const d = /* @__PURE__ */ new Date();
|
|
42
|
+
const isToday = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}` === date;
|
|
43
|
+
setNowHour(isToday ? d.getHours() + d.getMinutes() / 60 : null);
|
|
44
|
+
};
|
|
45
|
+
tick();
|
|
46
|
+
const id = setInterval(tick, 6e4);
|
|
47
|
+
return () => clearInterval(id);
|
|
48
|
+
}, [date]);
|
|
49
|
+
const hours = useMemo(() => {
|
|
50
|
+
const out = [];
|
|
51
|
+
for (let h = openHour; h < closeHour; h += 1) out.push(h);
|
|
52
|
+
return out;
|
|
53
|
+
}, [openHour, closeHour]);
|
|
54
|
+
const byResource = useMemo(() => {
|
|
55
|
+
const map = /* @__PURE__ */ new Map();
|
|
56
|
+
for (const r of resources) map.set(r.id, []);
|
|
57
|
+
const loose = [];
|
|
58
|
+
for (const e of events) {
|
|
59
|
+
if (e.isAllDay) continue;
|
|
60
|
+
if (e.resourceId && map.has(e.resourceId)) map.get(e.resourceId).push(e);
|
|
61
|
+
else loose.push(e);
|
|
62
|
+
}
|
|
63
|
+
return { map, loose };
|
|
64
|
+
}, [events, resources]);
|
|
65
|
+
const column = {
|
|
66
|
+
hidden: {},
|
|
67
|
+
shown: { transition: { staggerChildren: reduce ? 0 : 0.03 } }
|
|
68
|
+
};
|
|
69
|
+
const block = {
|
|
70
|
+
hidden: reduce ? {} : { opacity: 0, y: 8 },
|
|
71
|
+
shown: {
|
|
72
|
+
opacity: 1,
|
|
73
|
+
y: 0,
|
|
74
|
+
transition: { duration: 0.24, ease: eases.settle }
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const gridHeight = hours.length * HOUR_PX;
|
|
78
|
+
const {
|
|
79
|
+
moving,
|
|
80
|
+
dragging,
|
|
81
|
+
dragged,
|
|
82
|
+
columnRefs,
|
|
83
|
+
canMove,
|
|
84
|
+
startDrag,
|
|
85
|
+
handleDrop
|
|
86
|
+
} = useBlockDrag({
|
|
87
|
+
resources,
|
|
88
|
+
gridHeight,
|
|
89
|
+
hourPx: HOUR_PX,
|
|
90
|
+
onMoveEvent
|
|
91
|
+
});
|
|
92
|
+
if (resources.length === 0) {
|
|
93
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-[var(--border-default)] px-6 py-14 text-center", children: [
|
|
94
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--text-primary)]", children: loading ? "Loading the board" : `No ${resourceLabel.plural.toLowerCase()} yet` }),
|
|
95
|
+
!loading && /* @__PURE__ */ jsxs("p", { className: "mx-auto mt-1 max-w-sm text-sm text-[var(--text-tertiary)]", children: [
|
|
96
|
+
"Add the ",
|
|
97
|
+
resourceLabel.plural.toLowerCase(),
|
|
98
|
+
" you take bookings against and the day fills in as columns here."
|
|
99
|
+
] })
|
|
100
|
+
] });
|
|
101
|
+
}
|
|
102
|
+
return (
|
|
103
|
+
/* ONE GREY ON THIS SCREEN, and it is the strip's. The board drew itself on
|
|
104
|
+
`--bg-elevated` under a week strip of `surface` boxes, so the page
|
|
105
|
+
carried two panel colours eight pixels apart — and the cells, which
|
|
106
|
+
paint nothing, let the page wash through under both. `surface` is the
|
|
107
|
+
house's card fill; everything inside it now shows it. */
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { className: "surface overflow-hidden", children: [
|
|
109
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-[calc(100dvh-15rem)] overflow-auto", children: /* @__PURE__ */ jsxs(
|
|
110
|
+
"div",
|
|
111
|
+
{
|
|
112
|
+
className: "grid min-w-max",
|
|
113
|
+
style: {
|
|
114
|
+
gridTemplateColumns: `56px repeat(${resources.length}, minmax(180px, 1fr))`
|
|
115
|
+
},
|
|
116
|
+
children: [
|
|
117
|
+
/* @__PURE__ */ jsx("div", { className: "sticky left-0 top-0 z-40 border-b border-r border-[var(--border-default)] bg-[var(--card-bg)]" }),
|
|
118
|
+
resources.map((r) => {
|
|
119
|
+
const busy = (byResource.map.get(r.id) ?? []).filter(
|
|
120
|
+
(e) => e.type === "booking"
|
|
121
|
+
).length;
|
|
122
|
+
return /* @__PURE__ */ jsxs(
|
|
123
|
+
"div",
|
|
124
|
+
{
|
|
125
|
+
className: "sticky top-0 z-30 flex items-baseline justify-between gap-2 border-b border-r border-[var(--border-default)] bg-[var(--card-bg)] px-3 py-3 last:border-r-0",
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-[var(--text-primary)]", children: r.name }),
|
|
128
|
+
busy > 0 && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-brand-500/15 px-2 py-0.5 text-3xs font-medium tabular-nums text-brand-500", children: busy })
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
r.id
|
|
132
|
+
);
|
|
133
|
+
}),
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
"div",
|
|
136
|
+
{
|
|
137
|
+
className: "sticky left-0 z-20 border-r border-[var(--border-subtle)] bg-[var(--card-bg)]",
|
|
138
|
+
style: { height: gridHeight },
|
|
139
|
+
children: hours.map((h) => /* @__PURE__ */ jsx(
|
|
140
|
+
"div",
|
|
141
|
+
{
|
|
142
|
+
className: "relative border-b border-[var(--border-subtle)] last:border-b-0",
|
|
143
|
+
style: { height: HOUR_PX },
|
|
144
|
+
children: /* @__PURE__ */ jsx(
|
|
145
|
+
"span",
|
|
146
|
+
{
|
|
147
|
+
className: cn(
|
|
148
|
+
"absolute right-2 text-2xs tabular-nums text-[var(--text-muted)]",
|
|
149
|
+
h === openHour ? "top-1" : "-top-2"
|
|
150
|
+
),
|
|
151
|
+
children: clockLabel(h)
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
},
|
|
155
|
+
h
|
|
156
|
+
))
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
resources.map((r, colIndex) => {
|
|
160
|
+
const mine = byResource.map.get(r.id) ?? [];
|
|
161
|
+
return /* @__PURE__ */ jsxs(
|
|
162
|
+
motion.div,
|
|
163
|
+
{
|
|
164
|
+
variants: column,
|
|
165
|
+
initial: "hidden",
|
|
166
|
+
animate: "shown",
|
|
167
|
+
ref: (el) => {
|
|
168
|
+
columnRefs.current.set(r.id, el);
|
|
169
|
+
},
|
|
170
|
+
className: cn(
|
|
171
|
+
"relative border-r border-[var(--border-subtle)] last:border-r-0",
|
|
172
|
+
/* The column holding the dragged block rises above its
|
|
173
|
+
neighbours, so the block travels OVER the next schedule
|
|
174
|
+
instead of sliding behind it. */
|
|
175
|
+
dragging && (byResource.map.get(r.id) ?? []).some(
|
|
176
|
+
(ev) => ev.id === dragging
|
|
177
|
+
) && "z-30"
|
|
178
|
+
),
|
|
179
|
+
style: { height: gridHeight },
|
|
180
|
+
children: [
|
|
181
|
+
hours.map((h) => /* @__PURE__ */ jsx(
|
|
182
|
+
FreeBand,
|
|
183
|
+
{
|
|
184
|
+
hour: h,
|
|
185
|
+
top: (h - openHour) * HOUR_PX,
|
|
186
|
+
reduce: !!reduce,
|
|
187
|
+
onClick: () => onBookSlot(r.id, hhmm(h), hhmm(h + 1))
|
|
188
|
+
},
|
|
189
|
+
h
|
|
190
|
+
)),
|
|
191
|
+
nowHour !== null && nowHour >= openHour && nowHour < closeHour && /* @__PURE__ */ jsx(
|
|
192
|
+
"div",
|
|
193
|
+
{
|
|
194
|
+
className: "pointer-events-none absolute inset-x-0 z-20",
|
|
195
|
+
style: { top: (nowHour - openHour) * HOUR_PX },
|
|
196
|
+
"aria-hidden": true,
|
|
197
|
+
children: /* @__PURE__ */ jsx("div", { className: "relative h-px w-full bg-brand-500/70", children: colIndex === 0 && /* @__PURE__ */ jsx("span", { className: "absolute -left-[3px] -top-[3px] h-[7px] w-[7px] rounded-full bg-brand-500" }) })
|
|
198
|
+
}
|
|
199
|
+
),
|
|
200
|
+
mine.map((e) => {
|
|
201
|
+
const startH = hourOf(e.start);
|
|
202
|
+
const endH = hourOf(e.end);
|
|
203
|
+
const top = (startH - openHour) * HOUR_PX;
|
|
204
|
+
const height = Math.max((endH - startH) * HOUR_PX, 24);
|
|
205
|
+
if (top + height < 0 || top > gridHeight) return null;
|
|
206
|
+
const isBlock = e.type === "block";
|
|
207
|
+
return /* @__PURE__ */ jsxs(
|
|
208
|
+
motion.button,
|
|
209
|
+
{
|
|
210
|
+
type: "button",
|
|
211
|
+
variants: block,
|
|
212
|
+
onClick: () => {
|
|
213
|
+
if (dragged.current) return;
|
|
214
|
+
onSelectEvent(e);
|
|
215
|
+
},
|
|
216
|
+
drag: canMove(e),
|
|
217
|
+
dragMomentum: false,
|
|
218
|
+
dragElastic: 0.04,
|
|
219
|
+
dragConstraints: {
|
|
220
|
+
top: -top,
|
|
221
|
+
bottom: gridHeight - top - height
|
|
222
|
+
},
|
|
223
|
+
onDragStart: () => startDrag(e.id),
|
|
224
|
+
onDragEnd: (_, info) => void handleDrop(
|
|
225
|
+
e,
|
|
226
|
+
info.offset,
|
|
227
|
+
info.point.x,
|
|
228
|
+
top,
|
|
229
|
+
height
|
|
230
|
+
),
|
|
231
|
+
animate: {
|
|
232
|
+
x: moving?.id === e.id ? moving.dx : 0,
|
|
233
|
+
y: moving?.id === e.id ? moving.dy : 0
|
|
234
|
+
},
|
|
235
|
+
whileHover: reduce ? void 0 : { scale: 1.01 },
|
|
236
|
+
whileTap: reduce ? void 0 : { scale: PRESS_SCALE_LARGE },
|
|
237
|
+
whileDrag: { scale: 1.03, zIndex: 40 },
|
|
238
|
+
transition: springs.snappy,
|
|
239
|
+
className: cn(
|
|
240
|
+
"absolute inset-x-2 z-10 overflow-hidden rounded-lg px-3 py-2 text-left",
|
|
241
|
+
"transition-colors duration-[var(--motion-fast)]",
|
|
242
|
+
canMove(e) && "cursor-grab active:cursor-grabbing",
|
|
243
|
+
isBlock ? "border border-dashed border-[var(--warning)]/40 bg-[var(--warning-bg)] text-[var(--warning)]" : e.type === "synced" ? "border border-[var(--border-default)] bg-[var(--bg-muted)] text-[var(--text-secondary)]" : "bg-brand-500/[0.16] text-[var(--text-primary)] ring-1 ring-inset ring-brand-500/30 hover:ring-brand-500/60"
|
|
244
|
+
),
|
|
245
|
+
style: {
|
|
246
|
+
top,
|
|
247
|
+
height,
|
|
248
|
+
// A booking is an object resting on the day, so it casts.
|
|
249
|
+
boxShadow: isBlock || e.type === "synced" ? void 0 : "var(--shadow-md)"
|
|
250
|
+
},
|
|
251
|
+
children: [
|
|
252
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 truncate text-xs font-medium", children: [
|
|
253
|
+
isBlock ? /* @__PURE__ */ jsx(Ban, { className: "flex-shrink-0" }) : /* @__PURE__ */ jsx(
|
|
254
|
+
"span",
|
|
255
|
+
{
|
|
256
|
+
"aria-hidden": true,
|
|
257
|
+
className: cn(
|
|
258
|
+
"size-2 shrink-0 rounded-full bg-current",
|
|
259
|
+
statusTextClass(e.status ?? "")
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
),
|
|
263
|
+
e.customerName || e.title
|
|
264
|
+
] }),
|
|
265
|
+
height > 38 && /* @__PURE__ */ jsx("span", { className: "block truncate text-2xs opacity-70", children: isBlock ? e.blockReason || "Blocked" : e.serviceName ?? `${formatTime(e.start)} \u2013 ${formatTime(e.end)}` })
|
|
266
|
+
]
|
|
267
|
+
},
|
|
268
|
+
e.id
|
|
269
|
+
);
|
|
270
|
+
})
|
|
271
|
+
]
|
|
272
|
+
},
|
|
273
|
+
r.id
|
|
274
|
+
);
|
|
275
|
+
})
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
) }),
|
|
279
|
+
byResource.loose.length > 0 && /* @__PURE__ */ jsxs("div", { className: "border-t border-[var(--border-subtle)] px-4 py-3", children: [
|
|
280
|
+
/* @__PURE__ */ jsxs("p", { className: "mb-2 text-2xs uppercase tracking-wide text-[var(--text-muted)]", children: [
|
|
281
|
+
"Not assigned to a ",
|
|
282
|
+
resourceLabel.singular.toLowerCase()
|
|
283
|
+
] }),
|
|
284
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: byResource.loose.map((e) => /* @__PURE__ */ jsx(
|
|
285
|
+
Button,
|
|
286
|
+
{
|
|
287
|
+
variant: "ghost",
|
|
288
|
+
onClick: () => onSelectEvent(e),
|
|
289
|
+
children: e.customerName || e.title
|
|
290
|
+
},
|
|
291
|
+
e.id
|
|
292
|
+
)) })
|
|
293
|
+
] })
|
|
294
|
+
] })
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
function FreeBand({
|
|
298
|
+
hour,
|
|
299
|
+
top,
|
|
300
|
+
reduce,
|
|
301
|
+
onClick
|
|
302
|
+
}) {
|
|
303
|
+
return /* @__PURE__ */ jsx(
|
|
304
|
+
motion.button,
|
|
305
|
+
{
|
|
306
|
+
type: "button",
|
|
307
|
+
onClick,
|
|
308
|
+
"aria-label": `Book ${clockLabel(hour)}`,
|
|
309
|
+
whileHover: reduce ? void 0 : { scale: 1.015 },
|
|
310
|
+
whileTap: reduce ? void 0 : { scale: PRESS_SCALE_LARGE },
|
|
311
|
+
transition: springs.snappy,
|
|
312
|
+
className: "group absolute inset-x-2 flex items-center justify-center rounded-lg border border-transparent transition-colors duration-[var(--motion-fast)] hover:border-brand-500/30 hover:bg-brand-500/[0.06]",
|
|
313
|
+
style: { top: top + 4, height: HOUR_PX - 8 },
|
|
314
|
+
"data-hour": hour,
|
|
315
|
+
children: /* @__PURE__ */ jsxs("span", { className: "pointer-events-none flex items-center gap-1 text-2xs font-medium text-brand-500 opacity-0 transition-opacity duration-[var(--motion-fast)] group-hover:opacity-100", children: [
|
|
316
|
+
/* @__PURE__ */ jsx(Plus, {}),
|
|
317
|
+
"Book"
|
|
318
|
+
] })
|
|
319
|
+
}
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
export {
|
|
323
|
+
ResourceDayGrid
|
|
324
|
+
};
|
|
325
|
+
//# sourceMappingURL=resource-day-grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/resource-day-grid.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { motion, useReducedMotion } from 'motion/react';\nimport { Plus, Ban } from 'lucide-react';\nimport { springs, eases, PRESS_SCALE_LARGE } from '@withpotter/lib/motion';\nimport { cn } from '@withpotter/lib/utils';\nimport type { CalendarEventItem, ResourceItem } from '@withpotter/lib/api/types';\nimport type { EntityLabel } from '@withpotter/lib/intents/types';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { statusTextClass } from '@withpotter/components/shared/status-badge';\nimport { useBlockDrag, type MoveEvent } from './use-block-drag';\nimport { formatTime } from './format';\n\nexport interface ResourceDayGridProps {\n /** yyyy-mm-dd being shown. */\n date: string;\n resources: ResourceItem[];\n events: CalendarEventItem[];\n /** Earliest and latest hour to draw, in 24h. Derived from the day's data. */\n openHour?: number;\n closeHour?: number;\n resourceLabel: EntityLabel;\n onBookSlot: (resourceId: string, startTime: string, endTime: string) => void;\n onSelectEvent: (event: CalendarEventItem) => void;\n /**\n * A booking was dragged to a new time. Resolve `true` to keep it there,\n * `false` to send it back — the grid holds the block at the dropped position\n * until this settles, so the question can be asked with the answer already\n * drawn.\n */\n onMoveEvent?: MoveEvent;\n loading?: boolean;\n}\n\n/** Row height for one hour. Big enough to hold a name and press comfortably. */\nconst HOUR_PX = 60;\n\nfunction hhmm(h: number) {\n return `${String(h).padStart(2, '0')}:00`;\n}\n\nfunction clockLabel(h: number) {\n const suffix = h >= 12 ? 'pm' : 'am';\n const hour = h % 12 === 0 ? 12 : h % 12;\n return `${hour}${suffix}`;\n}\n\n/** Local hour of an ISO timestamp. */\nfunction hourOf(iso: string) {\n const d = new Date(iso);\n return d.getHours() + d.getMinutes() / 60;\n}\n\n/**\n * The day as a front desk actually reads it: one column per bookable thing,\n * time running down.\n *\n * The design decision that drives everything here is that FREE TIME IS THE\n * SUBJECT. A week-grid diary draws booked and open hours as the same kind of\n * cell, with the open ones simply empty — which is backwards, because the open\n * ones are the only hours you can still sell. So here the empty bands are the\n * loud, pressable, hoverable element and the booked blocks go quiet: they are\n * settled business, and settled business does not need to shout.\n */\nexport function ResourceDayGrid({\n date,\n resources,\n events,\n openHour = 8,\n closeHour = 20,\n resourceLabel,\n onBookSlot,\n onSelectEvent,\n onMoveEvent,\n loading,\n}: ResourceDayGridProps) {\n const reduce = useReducedMotion();\n\n /**\n * Where we are in the day, as a fraction of an hour past `openHour`.\n *\n * A desk board without a now-line makes you do the arithmetic yourself every\n * time you look at it. Ticks each minute; null when the day being shown is\n * not today, because a line marking \"now\" on next Tuesday means nothing.\n */\n const [nowHour, setNowHour] = useState<number | null>(null);\n useEffect(() => {\n const tick = () => {\n const d = new Date();\n const isToday =\n `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` ===\n date;\n setNowHour(isToday ? d.getHours() + d.getMinutes() / 60 : null);\n };\n tick();\n const id = setInterval(tick, 60_000);\n return () => clearInterval(id);\n }, [date]);\n\n const hours = useMemo(() => {\n const out: number[] = [];\n for (let h = openHour; h < closeHour; h += 1) out.push(h);\n return out;\n }, [openHour, closeHour]);\n\n /** Events grouped by the column they belong to. */\n const byResource = useMemo(() => {\n const map = new Map<string, CalendarEventItem[]>();\n for (const r of resources) map.set(r.id, []);\n const loose: CalendarEventItem[] = [];\n for (const e of events) {\n if (e.isAllDay) continue;\n if (e.resourceId && map.has(e.resourceId)) map.get(e.resourceId)!.push(e);\n else loose.push(e);\n }\n return { map, loose };\n }, [events, resources]);\n\n const column = {\n hidden: {},\n shown: { transition: { staggerChildren: reduce ? 0 : 0.03 } },\n };\n const block = {\n hidden: reduce ? {} : { opacity: 0, y: 8 },\n shown: {\n opacity: 1,\n y: 0,\n transition: { duration: 0.24, ease: eases.settle },\n },\n };\n\n const gridHeight = hours.length * HOUR_PX;\n\n const {\n moving,\n dragging,\n dragged,\n columnRefs,\n canMove,\n startDrag,\n handleDrop,\n } = useBlockDrag({\n resources,\n gridHeight,\n hourPx: HOUR_PX,\n onMoveEvent,\n });\n\n // With nothing to put in columns there is no grid to draw. Rendering the\n // frame anyway pushed the time gutter into the first resource column and\n // produced a lone axis floating against an empty board.\n if (resources.length === 0) {\n return (\n <div className=\"rounded-xl border border-dashed border-[var(--border-default)] px-6 py-14 text-center\">\n <p className=\"text-sm font-medium text-[var(--text-primary)]\">\n {loading\n ? 'Loading the board'\n : `No ${resourceLabel.plural.toLowerCase()} yet`}\n </p>\n {!loading && (\n <p className=\"mx-auto mt-1 max-w-sm text-sm text-[var(--text-tertiary)]\">\n Add the {resourceLabel.plural.toLowerCase()} you take bookings\n against and the day fills in as columns here.\n </p>\n )}\n </div>\n );\n }\n\n return (\n /* ONE GREY ON THIS SCREEN, and it is the strip's. The board drew itself on\n `--bg-elevated` under a week strip of `surface` boxes, so the page\n carried two panel colours eight pixels apart — and the cells, which\n paint nothing, let the page wash through under both. `surface` is the\n house's card fill; everything inside it now shows it. */\n <div className=\"surface overflow-hidden\">\n {/* The board scrolls, not the page — the same change the week grid took,\n for the same reason: reading down to the evening must not carry the\n column headings off the screen. */}\n <div className=\"max-h-[calc(100dvh-15rem)] overflow-auto\">\n <div\n className=\"grid min-w-max\"\n style={{\n gridTemplateColumns: `56px repeat(${resources.length}, minmax(180px, 1fr))`,\n }}\n >\n {/* Column headers. Opaque where they are sticky — content scrolls\n under them — but the SAME fill as the card, not a second grey. */}\n <div className=\"sticky left-0 top-0 z-40 border-b border-r border-[var(--border-default)] bg-[var(--card-bg)]\" />\n {resources.map((r) => {\n const busy = (byResource.map.get(r.id) ?? []).filter(\n (e) => e.type === 'booking',\n ).length;\n return (\n <div\n key={r.id}\n className=\"sticky top-0 z-30 flex items-baseline justify-between gap-2 border-b border-r border-[var(--border-default)] bg-[var(--card-bg)] px-3 py-3 last:border-r-0\"\n >\n <p className=\"truncate text-sm font-medium text-[var(--text-primary)]\">\n {r.name}\n </p>\n {busy > 0 && (\n <span className=\"shrink-0 rounded-full bg-brand-500/15 px-2 py-0.5 text-3xs font-medium tabular-nums text-brand-500\">\n {busy}\n </span>\n )}\n </div>\n );\n })}\n\n {/* Time gutter */}\n <div\n className=\"sticky left-0 z-20 border-r border-[var(--border-subtle)] bg-[var(--card-bg)]\"\n style={{ height: gridHeight }}\n >\n {hours.map((h) => (\n <div\n key={h}\n className=\"relative border-b border-[var(--border-subtle)] last:border-b-0\"\n style={{ height: HOUR_PX }}\n >\n {/* The label straddles the line that starts its hour — except\n the first, which has no line above it and half of which was\n being cut off by the card's own edge. */}\n <span\n className={cn(\n 'absolute right-2 text-2xs tabular-nums text-[var(--text-muted)]',\n h === openHour ? 'top-1' : '-top-2',\n )}\n >\n {clockLabel(h)}\n </span>\n </div>\n ))}\n </div>\n\n {/* One column per resource */}\n {resources.map((r, colIndex) => {\n const mine = byResource.map.get(r.id) ?? [];\n return (\n <motion.div\n key={r.id}\n variants={column}\n initial=\"hidden\"\n animate=\"shown\"\n /* Measured on drop to work out which schedule the block was\n let go over. */\n ref={(el) => {\n columnRefs.current.set(r.id, el);\n }}\n className={cn(\n 'relative border-r border-[var(--border-subtle)] last:border-r-0',\n /* The column holding the dragged block rises above its\n neighbours, so the block travels OVER the next schedule\n instead of sliding behind it. */\n dragging &&\n (byResource.map.get(r.id) ?? []).some(\n (ev) => ev.id === dragging,\n ) &&\n 'z-30',\n )}\n style={{ height: gridHeight }}\n >\n {/* Free bands: one per hour, pressable. Drawn first so booked\n blocks sit on top of them. */}\n {hours.map((h) => (\n <FreeBand\n key={h}\n hour={h}\n top={(h - openHour) * HOUR_PX}\n reduce={!!reduce}\n onClick={() => onBookSlot(r.id, hhmm(h), hhmm(h + 1))}\n />\n ))}\n\n {/* Now-line. Lives inside the column because this is the only\n element whose coordinate space already excludes the header. */}\n {nowHour !== null &&\n nowHour >= openHour &&\n nowHour < closeHour && (\n <div\n className=\"pointer-events-none absolute inset-x-0 z-20\"\n style={{ top: (nowHour - openHour) * HOUR_PX }}\n aria-hidden\n >\n <div className=\"relative h-px w-full bg-brand-500/70\">\n {/* One marker for the line, on the first column only —\n a dot per column reads as three separate events. */}\n {colIndex === 0 && (\n <span className=\"absolute -left-[3px] -top-[3px] h-[7px] w-[7px] rounded-full bg-brand-500\" />\n )}\n </div>\n </div>\n )}\n\n {/* Booked and blocked, positioned by real time. */}\n {mine.map((e) => {\n const startH = hourOf(e.start);\n const endH = hourOf(e.end);\n const top = (startH - openHour) * HOUR_PX;\n const height = Math.max((endH - startH) * HOUR_PX, 24);\n if (top + height < 0 || top > gridHeight) return null;\n const isBlock = e.type === 'block';\n return (\n <motion.button\n key={e.id}\n type=\"button\"\n variants={block}\n onClick={() => {\n if (dragged.current) return;\n onSelectEvent(e);\n }}\n /* ONLY A BOOKING MOVES. A block-out is the absence of a\n booking and a synced event belongs to somebody else's\n calendar; dragging either would promise something this\n screen cannot deliver. */\n /* Both axes: down the day is a new time, across the\n board is a new person. */\n drag={canMove(e)}\n dragMomentum={false}\n dragElastic={0.04}\n dragConstraints={{\n top: -top,\n bottom: gridHeight - top - height,\n }}\n onDragStart={() => startDrag(e.id)}\n onDragEnd={(_, info) =>\n void handleDrop(\n e,\n info.offset,\n info.point.x,\n top,\n height,\n )\n }\n animate={{\n x: moving?.id === e.id ? moving.dx : 0,\n y: moving?.id === e.id ? moving.dy : 0,\n }}\n whileHover={reduce ? undefined : { scale: 1.01 }}\n whileTap={\n reduce ? undefined : { scale: PRESS_SCALE_LARGE }\n }\n /* Off the board and under the hand: a bigger lift than\n the hover, the house's deepest card shadow, and out of\n its own column's stacking so it can travel over the\n next one. */\n whileDrag={{ scale: 1.03, zIndex: 40 }}\n transition={springs.snappy}\n className={cn(\n 'absolute inset-x-2 z-10 overflow-hidden rounded-lg px-3 py-2 text-left',\n 'transition-colors duration-[var(--motion-fast)]',\n canMove(e) && 'cursor-grab active:cursor-grabbing',\n isBlock\n ? 'border border-dashed border-[var(--warning)]/40 bg-[var(--warning-bg)] text-[var(--warning)]'\n : e.type === 'synced'\n ? 'border border-[var(--border-default)] bg-[var(--bg-muted)] text-[var(--text-secondary)]'\n : 'bg-brand-500/[0.16] text-[var(--text-primary)] ring-1 ring-inset ring-brand-500/30 hover:ring-brand-500/60',\n )}\n style={{\n top,\n height,\n // A booking is an object resting on the day, so it casts.\n boxShadow:\n isBlock || e.type === 'synced'\n ? undefined\n : 'var(--shadow-md)',\n }}\n >\n {/* A MARK, and it is the state. A blocked slot wore a `Ban` and a\n booking wore nothing, so the one kind of event you can act on was\n the one with no glyph. The dot takes its colour from the shared\n status map through `bg-current`, so this is not a sixteenth private\n copy of \"confirmed is blue\". */}\n <span className=\"flex items-center gap-2 truncate text-xs font-medium\">\n {isBlock ? (\n <Ban className=\"flex-shrink-0\" />\n ) : (\n <span\n aria-hidden\n className={cn(\n 'size-2 shrink-0 rounded-full bg-current',\n statusTextClass(e.status ?? ''),\n )}\n />\n )}\n {e.customerName || e.title}\n </span>\n {height > 38 && (\n <span className=\"block truncate text-2xs opacity-70\">\n {/* What it is, or when it is. Never the word \"confirmed\" —\n the dot already said that, and a status repeated as a\n caption is a caption spent. */}\n {isBlock\n ? e.blockReason || 'Blocked'\n : (e.serviceName ??\n `${formatTime(e.start)} – ${formatTime(e.end)}`)}\n </span>\n )}\n </motion.button>\n );\n })}\n </motion.div>\n );\n })}\n </div>\n </div>\n\n {byResource.loose.length > 0 && (\n <div className=\"border-t border-[var(--border-subtle)] px-4 py-3\">\n <p className=\"mb-2 text-2xs uppercase tracking-wide text-[var(--text-muted)]\">\n Not assigned to a {resourceLabel.singular.toLowerCase()}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {byResource.loose.map((e) => (\n <Button\n variant=\"ghost\"\n key={e.id}\n onClick={() => onSelectEvent(e)}\n >\n {e.customerName || e.title}\n </Button>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n\n/**\n * An hour nobody has bought yet.\n *\n * Quiet until you approach it, then it becomes an offer: the band lifts, tints\n * toward brand, and a Book affordance fades in. That reveal-on-hover is the\n * whole point of the redesign — the calendar should feel like it wants the gap\n * filled.\n */\nfunction FreeBand({\n hour,\n top,\n reduce,\n onClick,\n}: {\n hour: number;\n top: number;\n reduce: boolean;\n onClick: () => void;\n}) {\n return (\n <motion.button\n type=\"button\"\n onClick={onClick}\n aria-label={`Book ${clockLabel(hour)}`}\n whileHover={reduce ? undefined : { scale: 1.015 }}\n whileTap={reduce ? undefined : { scale: PRESS_SCALE_LARGE }}\n transition={springs.snappy}\n /* INSET FROM THE COLUMN, not flush with it. At `inset-x-1` and a\n two-pixel vertical trim the band's rounded edge sat against the\n column's own border and the hour lines above and below it — a 10px\n radius reads as a mistake when it is touching a straight line. It\n stands off all four edges now, so the offer looks placed in the gap\n rather than jammed into it. */\n className=\"group absolute inset-x-2 flex items-center justify-center rounded-lg border border-transparent transition-colors duration-[var(--motion-fast)] hover:border-brand-500/30 hover:bg-brand-500/[0.06]\"\n style={{ top: top + 4, height: HOUR_PX - 8 }}\n data-hour={hour}\n >\n <span className=\"pointer-events-none flex items-center gap-1 text-2xs font-medium text-brand-500 opacity-0 transition-opacity duration-[var(--motion-fast)] group-hover:opacity-100\">\n <Plus />\n Book\n </span>\n </motion.button>\n );\n}\n"],"mappings":"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","names":[]}
|