@resira/ui 0.4.2 → 0.4.5
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/index.cjs +116 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -1
- package/dist/index.d.ts +114 -1
- package/dist/index.js +115 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -790,6 +790,119 @@ interface UseCheckoutSessionReturn {
|
|
|
790
790
|
* ```
|
|
791
791
|
*/
|
|
792
792
|
declare function useCheckoutSession(token: string | undefined): UseCheckoutSessionReturn;
|
|
793
|
+
/** A single duration/price option for a service. */
|
|
794
|
+
interface ServiceOption {
|
|
795
|
+
/** Duration in minutes. */
|
|
796
|
+
durationMinutes: number;
|
|
797
|
+
/** Human-readable duration label (e.g. "1h 30m"). */
|
|
798
|
+
durationLabel: string;
|
|
799
|
+
/** Price in minor units (cents). */
|
|
800
|
+
priceCents: number;
|
|
801
|
+
/** Formatted price string (e.g. "€50.00"). */
|
|
802
|
+
priceFormatted: string;
|
|
803
|
+
}
|
|
804
|
+
/** Enriched service data ready for display. */
|
|
805
|
+
interface Service {
|
|
806
|
+
/** Unique service ID. */
|
|
807
|
+
id: string;
|
|
808
|
+
/** Service name. */
|
|
809
|
+
name: string;
|
|
810
|
+
/** Optional description. */
|
|
811
|
+
description?: string;
|
|
812
|
+
/** Image URL. */
|
|
813
|
+
imageUrl?: string;
|
|
814
|
+
/** ISO 4217 currency code. */
|
|
815
|
+
currency: string;
|
|
816
|
+
/** Whether the service is active. */
|
|
817
|
+
active: boolean;
|
|
818
|
+
/** Pricing model: "per_session" | "per_person" | "per_rider". */
|
|
819
|
+
pricingModel: string;
|
|
820
|
+
/** Default/base price in minor units. */
|
|
821
|
+
priceCents: number;
|
|
822
|
+
/** Formatted base price (e.g. "€50.00"). */
|
|
823
|
+
priceFormatted: string;
|
|
824
|
+
/** Lowest price across all options (for "from €X" display). */
|
|
825
|
+
lowestPriceCents: number;
|
|
826
|
+
/** Formatted lowest price. */
|
|
827
|
+
lowestPriceFormatted: string;
|
|
828
|
+
/** Whether multiple duration/price options exist. */
|
|
829
|
+
hasMultipleOptions: boolean;
|
|
830
|
+
/** Default duration in minutes. */
|
|
831
|
+
durationMinutes: number;
|
|
832
|
+
/** Human-readable default duration (e.g. "2h"). */
|
|
833
|
+
durationLabel: string;
|
|
834
|
+
/** All available duration/price options. */
|
|
835
|
+
options: ServiceOption[];
|
|
836
|
+
/** Maximum party/group size. */
|
|
837
|
+
maxPartySize?: number;
|
|
838
|
+
/** IDs of linked equipment/resources. */
|
|
839
|
+
equipmentIds: string[];
|
|
840
|
+
/** Names of linked equipment/resources. */
|
|
841
|
+
equipmentNames?: string[];
|
|
842
|
+
/** Display color. */
|
|
843
|
+
serviceColor?: string;
|
|
844
|
+
/** Sort order. */
|
|
845
|
+
sortOrder?: number;
|
|
846
|
+
/** Raw product object from the API. */
|
|
847
|
+
raw: Product;
|
|
848
|
+
}
|
|
849
|
+
interface UseServicesReturn {
|
|
850
|
+
/** Enriched service list. */
|
|
851
|
+
services: Service[];
|
|
852
|
+
/** Whether loading. */
|
|
853
|
+
loading: boolean;
|
|
854
|
+
/** Error message. */
|
|
855
|
+
error: string | null;
|
|
856
|
+
/** Re-fetch services. */
|
|
857
|
+
refetch: () => void;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Fetch all services for the organisation with enriched display data.
|
|
861
|
+
*
|
|
862
|
+
* Returns formatted prices, duration labels, and "from €X" logic
|
|
863
|
+
* so you can render service cards with your own styling.
|
|
864
|
+
*
|
|
865
|
+
* Requires `<ResiraProvider>` ancestor.
|
|
866
|
+
*
|
|
867
|
+
* ```tsx
|
|
868
|
+
* const { services, loading, error } = useServices();
|
|
869
|
+
*
|
|
870
|
+
* return services.map(s => (
|
|
871
|
+
* <div key={s.id}>
|
|
872
|
+
* <h3>{s.name}</h3>
|
|
873
|
+
* <img src={s.imageUrl} alt={s.name} />
|
|
874
|
+
* <p>{s.hasMultipleOptions ? `from ${s.lowestPriceFormatted}` : s.priceFormatted}</p>
|
|
875
|
+
* <p>{s.durationLabel}</p>
|
|
876
|
+
* {s.options.map(opt => (
|
|
877
|
+
* <span key={opt.durationMinutes}>{opt.durationLabel} — {opt.priceFormatted}</span>
|
|
878
|
+
* ))}
|
|
879
|
+
* </div>
|
|
880
|
+
* ));
|
|
881
|
+
* ```
|
|
882
|
+
*/
|
|
883
|
+
declare function useServices(): UseServicesReturn;
|
|
884
|
+
/**
|
|
885
|
+
* Fetch all services for an organisation — standalone, no React needed.
|
|
886
|
+
*
|
|
887
|
+
* Use this in non-React contexts, server components, scripts, or
|
|
888
|
+
* when you want full control over rendering.
|
|
889
|
+
*
|
|
890
|
+
* ```ts
|
|
891
|
+
* import { fetchServices } from "@resira/ui";
|
|
892
|
+
*
|
|
893
|
+
* const services = await fetchServices("your-api-key");
|
|
894
|
+
* services.forEach(s => {
|
|
895
|
+
* console.log(s.name, s.lowestPriceFormatted, s.options);
|
|
896
|
+
* });
|
|
897
|
+
* ```
|
|
898
|
+
*
|
|
899
|
+
* @param apiKey Your Resira public API key
|
|
900
|
+
* @param opts Optional: baseUrl override
|
|
901
|
+
* @returns Array of enriched Service objects
|
|
902
|
+
*/
|
|
903
|
+
declare function fetchServices(apiKey: string, opts?: {
|
|
904
|
+
baseUrl?: string;
|
|
905
|
+
}): Promise<Service[]>;
|
|
793
906
|
|
|
794
907
|
/** Default theme values. */
|
|
795
908
|
declare const DEFAULT_THEME: Required<ResiraTheme>;
|
|
@@ -829,4 +942,4 @@ declare function TagIcon({ size, className }: IconProps): react_jsx_runtime.JSX.
|
|
|
829
942
|
declare function CubeIcon({ size, className }: IconProps): react_jsx_runtime.JSX.Element;
|
|
830
943
|
declare function ViewfinderIcon({ size, className }: IconProps): react_jsx_runtime.JSX.Element;
|
|
831
944
|
|
|
832
|
-
export { AlertCircleIcon, BookingCalendar, BookingModal, type BookingSelection, type BookingStep, CalendarIcon, CheckCircleIcon, CheckIcon, type CheckoutSessionErrorCode, ChevronLeftIcon, ChevronRightIcon, ClockIcon, ConfirmationView, CreditCardIcon, CubeIcon, DEFAULT_LOCALE, DEFAULT_THEME, type DeeplinkGuest, type DeeplinkSelection, DishShowcase, type DishShowcaseProps, type DomainConfig, GuestForm, type GuestFormErrors, type GuestFormValues, LockIcon, MailIcon, MinusIcon, NoteIcon, PaymentForm, PhoneIcon, PlusIcon, ProductSelector, ResiraBookingWidget, type ResiraClassNames, type ResiraContextValue, type ResiraDomain, type ResiraLocale, ResiraProvider, type ResiraProviderConfig, type ResiraProviderProps, type ResiraTheme, ResourcePicker, type ServiceLayout, ShieldIcon, SummaryPreview, TagIcon, TimeSlotPicker, UserIcon, UsersIcon, ViewfinderIcon, WaiverConsent, XIcon, resolveTheme, themeToCSS, useAvailability, useCheckoutSession, useDish, useDishes, usePaymentIntent, useProducts, useReservation, useResira, useResources, validateGuestForm };
|
|
945
|
+
export { AlertCircleIcon, BookingCalendar, BookingModal, type BookingSelection, type BookingStep, CalendarIcon, CheckCircleIcon, CheckIcon, type CheckoutSessionErrorCode, ChevronLeftIcon, ChevronRightIcon, ClockIcon, ConfirmationView, CreditCardIcon, CubeIcon, DEFAULT_LOCALE, DEFAULT_THEME, type DeeplinkGuest, type DeeplinkSelection, DishShowcase, type DishShowcaseProps, type DomainConfig, GuestForm, type GuestFormErrors, type GuestFormValues, LockIcon, MailIcon, MinusIcon, NoteIcon, PaymentForm, PhoneIcon, PlusIcon, ProductSelector, ResiraBookingWidget, type ResiraClassNames, type ResiraContextValue, type ResiraDomain, type ResiraLocale, ResiraProvider, type ResiraProviderConfig, type ResiraProviderProps, type ResiraTheme, ResourcePicker, type Service, type ServiceLayout, type ServiceOption, ShieldIcon, SummaryPreview, TagIcon, TimeSlotPicker, type UseServicesReturn, UserIcon, UsersIcon, ViewfinderIcon, WaiverConsent, XIcon, fetchServices, resolveTheme, themeToCSS, useAvailability, useCheckoutSession, useDish, useDishes, usePaymentIntent, useProducts, useReservation, useResira, useResources, useServices, validateGuestForm };
|
package/dist/index.d.ts
CHANGED
|
@@ -790,6 +790,119 @@ interface UseCheckoutSessionReturn {
|
|
|
790
790
|
* ```
|
|
791
791
|
*/
|
|
792
792
|
declare function useCheckoutSession(token: string | undefined): UseCheckoutSessionReturn;
|
|
793
|
+
/** A single duration/price option for a service. */
|
|
794
|
+
interface ServiceOption {
|
|
795
|
+
/** Duration in minutes. */
|
|
796
|
+
durationMinutes: number;
|
|
797
|
+
/** Human-readable duration label (e.g. "1h 30m"). */
|
|
798
|
+
durationLabel: string;
|
|
799
|
+
/** Price in minor units (cents). */
|
|
800
|
+
priceCents: number;
|
|
801
|
+
/** Formatted price string (e.g. "€50.00"). */
|
|
802
|
+
priceFormatted: string;
|
|
803
|
+
}
|
|
804
|
+
/** Enriched service data ready for display. */
|
|
805
|
+
interface Service {
|
|
806
|
+
/** Unique service ID. */
|
|
807
|
+
id: string;
|
|
808
|
+
/** Service name. */
|
|
809
|
+
name: string;
|
|
810
|
+
/** Optional description. */
|
|
811
|
+
description?: string;
|
|
812
|
+
/** Image URL. */
|
|
813
|
+
imageUrl?: string;
|
|
814
|
+
/** ISO 4217 currency code. */
|
|
815
|
+
currency: string;
|
|
816
|
+
/** Whether the service is active. */
|
|
817
|
+
active: boolean;
|
|
818
|
+
/** Pricing model: "per_session" | "per_person" | "per_rider". */
|
|
819
|
+
pricingModel: string;
|
|
820
|
+
/** Default/base price in minor units. */
|
|
821
|
+
priceCents: number;
|
|
822
|
+
/** Formatted base price (e.g. "€50.00"). */
|
|
823
|
+
priceFormatted: string;
|
|
824
|
+
/** Lowest price across all options (for "from €X" display). */
|
|
825
|
+
lowestPriceCents: number;
|
|
826
|
+
/** Formatted lowest price. */
|
|
827
|
+
lowestPriceFormatted: string;
|
|
828
|
+
/** Whether multiple duration/price options exist. */
|
|
829
|
+
hasMultipleOptions: boolean;
|
|
830
|
+
/** Default duration in minutes. */
|
|
831
|
+
durationMinutes: number;
|
|
832
|
+
/** Human-readable default duration (e.g. "2h"). */
|
|
833
|
+
durationLabel: string;
|
|
834
|
+
/** All available duration/price options. */
|
|
835
|
+
options: ServiceOption[];
|
|
836
|
+
/** Maximum party/group size. */
|
|
837
|
+
maxPartySize?: number;
|
|
838
|
+
/** IDs of linked equipment/resources. */
|
|
839
|
+
equipmentIds: string[];
|
|
840
|
+
/** Names of linked equipment/resources. */
|
|
841
|
+
equipmentNames?: string[];
|
|
842
|
+
/** Display color. */
|
|
843
|
+
serviceColor?: string;
|
|
844
|
+
/** Sort order. */
|
|
845
|
+
sortOrder?: number;
|
|
846
|
+
/** Raw product object from the API. */
|
|
847
|
+
raw: Product;
|
|
848
|
+
}
|
|
849
|
+
interface UseServicesReturn {
|
|
850
|
+
/** Enriched service list. */
|
|
851
|
+
services: Service[];
|
|
852
|
+
/** Whether loading. */
|
|
853
|
+
loading: boolean;
|
|
854
|
+
/** Error message. */
|
|
855
|
+
error: string | null;
|
|
856
|
+
/** Re-fetch services. */
|
|
857
|
+
refetch: () => void;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Fetch all services for the organisation with enriched display data.
|
|
861
|
+
*
|
|
862
|
+
* Returns formatted prices, duration labels, and "from €X" logic
|
|
863
|
+
* so you can render service cards with your own styling.
|
|
864
|
+
*
|
|
865
|
+
* Requires `<ResiraProvider>` ancestor.
|
|
866
|
+
*
|
|
867
|
+
* ```tsx
|
|
868
|
+
* const { services, loading, error } = useServices();
|
|
869
|
+
*
|
|
870
|
+
* return services.map(s => (
|
|
871
|
+
* <div key={s.id}>
|
|
872
|
+
* <h3>{s.name}</h3>
|
|
873
|
+
* <img src={s.imageUrl} alt={s.name} />
|
|
874
|
+
* <p>{s.hasMultipleOptions ? `from ${s.lowestPriceFormatted}` : s.priceFormatted}</p>
|
|
875
|
+
* <p>{s.durationLabel}</p>
|
|
876
|
+
* {s.options.map(opt => (
|
|
877
|
+
* <span key={opt.durationMinutes}>{opt.durationLabel} — {opt.priceFormatted}</span>
|
|
878
|
+
* ))}
|
|
879
|
+
* </div>
|
|
880
|
+
* ));
|
|
881
|
+
* ```
|
|
882
|
+
*/
|
|
883
|
+
declare function useServices(): UseServicesReturn;
|
|
884
|
+
/**
|
|
885
|
+
* Fetch all services for an organisation — standalone, no React needed.
|
|
886
|
+
*
|
|
887
|
+
* Use this in non-React contexts, server components, scripts, or
|
|
888
|
+
* when you want full control over rendering.
|
|
889
|
+
*
|
|
890
|
+
* ```ts
|
|
891
|
+
* import { fetchServices } from "@resira/ui";
|
|
892
|
+
*
|
|
893
|
+
* const services = await fetchServices("your-api-key");
|
|
894
|
+
* services.forEach(s => {
|
|
895
|
+
* console.log(s.name, s.lowestPriceFormatted, s.options);
|
|
896
|
+
* });
|
|
897
|
+
* ```
|
|
898
|
+
*
|
|
899
|
+
* @param apiKey Your Resira public API key
|
|
900
|
+
* @param opts Optional: baseUrl override
|
|
901
|
+
* @returns Array of enriched Service objects
|
|
902
|
+
*/
|
|
903
|
+
declare function fetchServices(apiKey: string, opts?: {
|
|
904
|
+
baseUrl?: string;
|
|
905
|
+
}): Promise<Service[]>;
|
|
793
906
|
|
|
794
907
|
/** Default theme values. */
|
|
795
908
|
declare const DEFAULT_THEME: Required<ResiraTheme>;
|
|
@@ -829,4 +942,4 @@ declare function TagIcon({ size, className }: IconProps): react_jsx_runtime.JSX.
|
|
|
829
942
|
declare function CubeIcon({ size, className }: IconProps): react_jsx_runtime.JSX.Element;
|
|
830
943
|
declare function ViewfinderIcon({ size, className }: IconProps): react_jsx_runtime.JSX.Element;
|
|
831
944
|
|
|
832
|
-
export { AlertCircleIcon, BookingCalendar, BookingModal, type BookingSelection, type BookingStep, CalendarIcon, CheckCircleIcon, CheckIcon, type CheckoutSessionErrorCode, ChevronLeftIcon, ChevronRightIcon, ClockIcon, ConfirmationView, CreditCardIcon, CubeIcon, DEFAULT_LOCALE, DEFAULT_THEME, type DeeplinkGuest, type DeeplinkSelection, DishShowcase, type DishShowcaseProps, type DomainConfig, GuestForm, type GuestFormErrors, type GuestFormValues, LockIcon, MailIcon, MinusIcon, NoteIcon, PaymentForm, PhoneIcon, PlusIcon, ProductSelector, ResiraBookingWidget, type ResiraClassNames, type ResiraContextValue, type ResiraDomain, type ResiraLocale, ResiraProvider, type ResiraProviderConfig, type ResiraProviderProps, type ResiraTheme, ResourcePicker, type ServiceLayout, ShieldIcon, SummaryPreview, TagIcon, TimeSlotPicker, UserIcon, UsersIcon, ViewfinderIcon, WaiverConsent, XIcon, resolveTheme, themeToCSS, useAvailability, useCheckoutSession, useDish, useDishes, usePaymentIntent, useProducts, useReservation, useResira, useResources, validateGuestForm };
|
|
945
|
+
export { AlertCircleIcon, BookingCalendar, BookingModal, type BookingSelection, type BookingStep, CalendarIcon, CheckCircleIcon, CheckIcon, type CheckoutSessionErrorCode, ChevronLeftIcon, ChevronRightIcon, ClockIcon, ConfirmationView, CreditCardIcon, CubeIcon, DEFAULT_LOCALE, DEFAULT_THEME, type DeeplinkGuest, type DeeplinkSelection, DishShowcase, type DishShowcaseProps, type DomainConfig, GuestForm, type GuestFormErrors, type GuestFormValues, LockIcon, MailIcon, MinusIcon, NoteIcon, PaymentForm, PhoneIcon, PlusIcon, ProductSelector, ResiraBookingWidget, type ResiraClassNames, type ResiraContextValue, type ResiraDomain, type ResiraLocale, ResiraProvider, type ResiraProviderConfig, type ResiraProviderProps, type ResiraTheme, ResourcePicker, type Service, type ServiceLayout, type ServiceOption, ShieldIcon, SummaryPreview, TagIcon, TimeSlotPicker, type UseServicesReturn, UserIcon, UsersIcon, ViewfinderIcon, WaiverConsent, XIcon, fetchServices, resolveTheme, themeToCSS, useAvailability, useCheckoutSession, useDish, useDishes, usePaymentIntent, useProducts, useReservation, useResira, useResources, useServices, validateGuestForm };
|
package/dist/index.js
CHANGED
|
@@ -650,6 +650,101 @@ function useCheckoutSession(token) {
|
|
|
650
650
|
}, [client, token]);
|
|
651
651
|
return { session, loading, error, errorCode };
|
|
652
652
|
}
|
|
653
|
+
function formatPriceCentsUtil(cents, currency) {
|
|
654
|
+
return new Intl.NumberFormat("default", { style: "currency", currency }).format(cents / 100);
|
|
655
|
+
}
|
|
656
|
+
function formatDurationUtil(minutes) {
|
|
657
|
+
if (minutes < 60) return `${minutes} min`;
|
|
658
|
+
const h = Math.floor(minutes / 60);
|
|
659
|
+
const m = minutes % 60;
|
|
660
|
+
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
661
|
+
}
|
|
662
|
+
function enrichProduct(product) {
|
|
663
|
+
const currency = product.currency ?? "EUR";
|
|
664
|
+
const options = [];
|
|
665
|
+
if (product.durationPricing?.length) {
|
|
666
|
+
for (const dp of product.durationPricing) {
|
|
667
|
+
options.push({
|
|
668
|
+
durationMinutes: dp.durationMinutes,
|
|
669
|
+
durationLabel: formatDurationUtil(dp.durationMinutes),
|
|
670
|
+
priceCents: dp.priceCents,
|
|
671
|
+
priceFormatted: formatPriceCentsUtil(dp.priceCents, currency)
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
} else {
|
|
675
|
+
options.push({
|
|
676
|
+
durationMinutes: product.durationMinutes,
|
|
677
|
+
durationLabel: formatDurationUtil(product.durationMinutes),
|
|
678
|
+
priceCents: product.priceCents,
|
|
679
|
+
priceFormatted: formatPriceCentsUtil(product.priceCents, currency)
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
const lowestPriceCents = Math.min(...options.map((o) => o.priceCents));
|
|
683
|
+
return {
|
|
684
|
+
id: product.id,
|
|
685
|
+
name: product.name,
|
|
686
|
+
description: product.description,
|
|
687
|
+
imageUrl: product.imageUrl,
|
|
688
|
+
currency,
|
|
689
|
+
active: product.active,
|
|
690
|
+
pricingModel: product.pricingModel,
|
|
691
|
+
priceCents: product.priceCents,
|
|
692
|
+
priceFormatted: formatPriceCentsUtil(product.priceCents, currency),
|
|
693
|
+
lowestPriceCents,
|
|
694
|
+
lowestPriceFormatted: formatPriceCentsUtil(lowestPriceCents, currency),
|
|
695
|
+
hasMultipleOptions: options.length > 1,
|
|
696
|
+
durationMinutes: product.durationMinutes,
|
|
697
|
+
durationLabel: formatDurationUtil(product.durationMinutes),
|
|
698
|
+
options,
|
|
699
|
+
maxPartySize: product.maxPartySize,
|
|
700
|
+
equipmentIds: product.equipmentIds,
|
|
701
|
+
equipmentNames: product.equipmentNames,
|
|
702
|
+
serviceColor: product.serviceColor,
|
|
703
|
+
sortOrder: product.sortOrder,
|
|
704
|
+
raw: product
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
function useServices() {
|
|
708
|
+
const { client } = useResira();
|
|
709
|
+
const [services, setServices] = useState([]);
|
|
710
|
+
const [loading, setLoading] = useState(true);
|
|
711
|
+
const [error, setError] = useState(null);
|
|
712
|
+
const [fetchCount, setFetchCount] = useState(0);
|
|
713
|
+
useEffect(() => {
|
|
714
|
+
let cancelled = false;
|
|
715
|
+
setLoading(true);
|
|
716
|
+
setError(null);
|
|
717
|
+
async function load() {
|
|
718
|
+
try {
|
|
719
|
+
const data = await client.listProducts();
|
|
720
|
+
if (!cancelled) {
|
|
721
|
+
setServices((data.products ?? []).map(enrichProduct));
|
|
722
|
+
}
|
|
723
|
+
} catch (err) {
|
|
724
|
+
if (!cancelled) {
|
|
725
|
+
setError(err instanceof Error ? err.message : "Failed to load services");
|
|
726
|
+
}
|
|
727
|
+
} finally {
|
|
728
|
+
if (!cancelled) setLoading(false);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
load();
|
|
732
|
+
return () => {
|
|
733
|
+
cancelled = true;
|
|
734
|
+
};
|
|
735
|
+
}, [client, fetchCount]);
|
|
736
|
+
const refetch = useCallback(() => setFetchCount((c) => c + 1), []);
|
|
737
|
+
return { services, loading, error, refetch };
|
|
738
|
+
}
|
|
739
|
+
async function fetchServices(apiKey, opts) {
|
|
740
|
+
const { Resira: Resira2 } = await import('@resira/sdk');
|
|
741
|
+
const client = new Resira2({
|
|
742
|
+
apiKey,
|
|
743
|
+
...opts?.baseUrl ? { baseUrl: opts.baseUrl } : {}
|
|
744
|
+
});
|
|
745
|
+
const data = await client.listProducts();
|
|
746
|
+
return (data.products ?? []).map(enrichProduct);
|
|
747
|
+
}
|
|
653
748
|
var defaultSize = 20;
|
|
654
749
|
function CalendarIcon({ size = defaultSize, className }) {
|
|
655
750
|
return /* @__PURE__ */ jsxs(
|
|
@@ -1777,6 +1872,10 @@ function ServiceOverlayCard({
|
|
|
1777
1872
|
}) {
|
|
1778
1873
|
const currency = product.currency ?? "EUR";
|
|
1779
1874
|
const priceLabel = product.pricingModel === "per_rider" ? "per rider" : product.pricingModel === "per_person" ? locale.perPerson : locale.perSession;
|
|
1875
|
+
const hasMultipleOptions = (product.durationPricing?.length ?? 0) > 1 || (product.riderTierPricing?.length ?? 0) > 1;
|
|
1876
|
+
const lowestPrice = hasMultipleOptions && product.durationPricing?.length ? Math.min(...product.durationPricing.map((dp) => dp.priceCents)) : product.priceCents;
|
|
1877
|
+
const pricePrefix = hasMultipleOptions ? "from " : "";
|
|
1878
|
+
const optionCount = product.durationPricing?.length ?? (product.riderTierPricing?.length ?? 0);
|
|
1780
1879
|
let className = "resira-service-overlay-card";
|
|
1781
1880
|
if (isSelected) className += " resira-service-overlay-card--selected";
|
|
1782
1881
|
if (cardClassName) className += ` ${cardClassName}`;
|
|
@@ -1797,17 +1896,22 @@ function ServiceOverlayCard({
|
|
|
1797
1896
|
] }),
|
|
1798
1897
|
/* @__PURE__ */ jsxs("div", { className: "resira-service-overlay-card-bottom", children: [
|
|
1799
1898
|
/* @__PURE__ */ jsxs("span", { className: "resira-service-overlay-card-price", children: [
|
|
1800
|
-
|
|
1899
|
+
pricePrefix,
|
|
1900
|
+
formatPrice2(lowestPrice, currency),
|
|
1801
1901
|
/* @__PURE__ */ jsxs("span", { className: "resira-service-overlay-card-price-unit", children: [
|
|
1802
1902
|
"/",
|
|
1803
1903
|
priceLabel
|
|
1804
1904
|
] })
|
|
1805
1905
|
] }),
|
|
1806
1906
|
/* @__PURE__ */ jsxs("div", { className: "resira-service-overlay-card-pills", children: [
|
|
1807
|
-
|
|
1907
|
+
hasMultipleOptions && optionCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "resira-service-overlay-card-pill", children: [
|
|
1908
|
+
/* @__PURE__ */ jsx(ClockIcon, { size: 11 }),
|
|
1909
|
+
optionCount,
|
|
1910
|
+
" options"
|
|
1911
|
+
] }) : product.durationMinutes > 0 ? /* @__PURE__ */ jsxs("span", { className: "resira-service-overlay-card-pill", children: [
|
|
1808
1912
|
/* @__PURE__ */ jsx(ClockIcon, { size: 11 }),
|
|
1809
1913
|
formatDuration2(product.durationMinutes)
|
|
1810
|
-
] }),
|
|
1914
|
+
] }) : null,
|
|
1811
1915
|
product.maxPartySize && /* @__PURE__ */ jsxs("span", { className: "resira-service-overlay-card-pill", children: [
|
|
1812
1916
|
/* @__PURE__ */ jsx(UsersIcon, { size: 11 }),
|
|
1813
1917
|
"max ",
|
|
@@ -3024,8 +3128,14 @@ function ResiraBookingWidget() {
|
|
|
3024
3128
|
partySize: clampedPartySize
|
|
3025
3129
|
};
|
|
3026
3130
|
});
|
|
3131
|
+
if (step === "resource" && isServiceBased) {
|
|
3132
|
+
const nextIdx = stepIndex("resource", STEPS) + 1;
|
|
3133
|
+
if (nextIdx < STEPS.length) {
|
|
3134
|
+
setStep(STEPS[nextIdx]);
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3027
3137
|
},
|
|
3028
|
-
[setActiveResourceId, domainConfig.maxPartySize]
|
|
3138
|
+
[setActiveResourceId, domainConfig.maxPartySize, step, isServiceBased, STEPS]
|
|
3029
3139
|
);
|
|
3030
3140
|
const handleResourceSelect = useCallback(
|
|
3031
3141
|
(resourceId) => {
|
|
@@ -4207,6 +4317,6 @@ function DishShowcase({
|
|
|
4207
4317
|
] });
|
|
4208
4318
|
}
|
|
4209
4319
|
|
|
4210
|
-
export { AlertCircleIcon, BookingCalendar, BookingModal, CalendarIcon, CheckCircleIcon, CheckIcon, ChevronLeftIcon, ChevronRightIcon, ClockIcon, ConfirmationView, CreditCardIcon, CubeIcon, DEFAULT_LOCALE, DEFAULT_THEME, DishShowcase, GuestForm, LockIcon, MailIcon, MinusIcon, NoteIcon, PaymentForm, PhoneIcon, PlusIcon, ProductSelector, ResiraBookingWidget, ResiraProvider, ResourcePicker, ShieldIcon, SummaryPreview, TagIcon, TimeSlotPicker, UserIcon, UsersIcon, ViewfinderIcon, WaiverConsent, XIcon, resolveTheme, themeToCSS, useAvailability, useCheckoutSession, useDish, useDishes, usePaymentIntent, useProducts, useReservation, useResira, useResources, validateGuestForm };
|
|
4320
|
+
export { AlertCircleIcon, BookingCalendar, BookingModal, CalendarIcon, CheckCircleIcon, CheckIcon, ChevronLeftIcon, ChevronRightIcon, ClockIcon, ConfirmationView, CreditCardIcon, CubeIcon, DEFAULT_LOCALE, DEFAULT_THEME, DishShowcase, GuestForm, LockIcon, MailIcon, MinusIcon, NoteIcon, PaymentForm, PhoneIcon, PlusIcon, ProductSelector, ResiraBookingWidget, ResiraProvider, ResourcePicker, ShieldIcon, SummaryPreview, TagIcon, TimeSlotPicker, UserIcon, UsersIcon, ViewfinderIcon, WaiverConsent, XIcon, fetchServices, resolveTheme, themeToCSS, useAvailability, useCheckoutSession, useDish, useDishes, usePaymentIntent, useProducts, useReservation, useResira, useResources, useServices, validateGuestForm };
|
|
4211
4321
|
//# sourceMappingURL=index.js.map
|
|
4212
4322
|
//# sourceMappingURL=index.js.map
|