@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.cjs
CHANGED
|
@@ -652,6 +652,101 @@ function useCheckoutSession(token) {
|
|
|
652
652
|
}, [client, token]);
|
|
653
653
|
return { session, loading, error, errorCode };
|
|
654
654
|
}
|
|
655
|
+
function formatPriceCentsUtil(cents, currency) {
|
|
656
|
+
return new Intl.NumberFormat("default", { style: "currency", currency }).format(cents / 100);
|
|
657
|
+
}
|
|
658
|
+
function formatDurationUtil(minutes) {
|
|
659
|
+
if (minutes < 60) return `${minutes} min`;
|
|
660
|
+
const h = Math.floor(minutes / 60);
|
|
661
|
+
const m = minutes % 60;
|
|
662
|
+
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
663
|
+
}
|
|
664
|
+
function enrichProduct(product) {
|
|
665
|
+
const currency = product.currency ?? "EUR";
|
|
666
|
+
const options = [];
|
|
667
|
+
if (product.durationPricing?.length) {
|
|
668
|
+
for (const dp of product.durationPricing) {
|
|
669
|
+
options.push({
|
|
670
|
+
durationMinutes: dp.durationMinutes,
|
|
671
|
+
durationLabel: formatDurationUtil(dp.durationMinutes),
|
|
672
|
+
priceCents: dp.priceCents,
|
|
673
|
+
priceFormatted: formatPriceCentsUtil(dp.priceCents, currency)
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
} else {
|
|
677
|
+
options.push({
|
|
678
|
+
durationMinutes: product.durationMinutes,
|
|
679
|
+
durationLabel: formatDurationUtil(product.durationMinutes),
|
|
680
|
+
priceCents: product.priceCents,
|
|
681
|
+
priceFormatted: formatPriceCentsUtil(product.priceCents, currency)
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
const lowestPriceCents = Math.min(...options.map((o) => o.priceCents));
|
|
685
|
+
return {
|
|
686
|
+
id: product.id,
|
|
687
|
+
name: product.name,
|
|
688
|
+
description: product.description,
|
|
689
|
+
imageUrl: product.imageUrl,
|
|
690
|
+
currency,
|
|
691
|
+
active: product.active,
|
|
692
|
+
pricingModel: product.pricingModel,
|
|
693
|
+
priceCents: product.priceCents,
|
|
694
|
+
priceFormatted: formatPriceCentsUtil(product.priceCents, currency),
|
|
695
|
+
lowestPriceCents,
|
|
696
|
+
lowestPriceFormatted: formatPriceCentsUtil(lowestPriceCents, currency),
|
|
697
|
+
hasMultipleOptions: options.length > 1,
|
|
698
|
+
durationMinutes: product.durationMinutes,
|
|
699
|
+
durationLabel: formatDurationUtil(product.durationMinutes),
|
|
700
|
+
options,
|
|
701
|
+
maxPartySize: product.maxPartySize,
|
|
702
|
+
equipmentIds: product.equipmentIds,
|
|
703
|
+
equipmentNames: product.equipmentNames,
|
|
704
|
+
serviceColor: product.serviceColor,
|
|
705
|
+
sortOrder: product.sortOrder,
|
|
706
|
+
raw: product
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
function useServices() {
|
|
710
|
+
const { client } = useResira();
|
|
711
|
+
const [services, setServices] = react.useState([]);
|
|
712
|
+
const [loading, setLoading] = react.useState(true);
|
|
713
|
+
const [error, setError] = react.useState(null);
|
|
714
|
+
const [fetchCount, setFetchCount] = react.useState(0);
|
|
715
|
+
react.useEffect(() => {
|
|
716
|
+
let cancelled = false;
|
|
717
|
+
setLoading(true);
|
|
718
|
+
setError(null);
|
|
719
|
+
async function load() {
|
|
720
|
+
try {
|
|
721
|
+
const data = await client.listProducts();
|
|
722
|
+
if (!cancelled) {
|
|
723
|
+
setServices((data.products ?? []).map(enrichProduct));
|
|
724
|
+
}
|
|
725
|
+
} catch (err) {
|
|
726
|
+
if (!cancelled) {
|
|
727
|
+
setError(err instanceof Error ? err.message : "Failed to load services");
|
|
728
|
+
}
|
|
729
|
+
} finally {
|
|
730
|
+
if (!cancelled) setLoading(false);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
load();
|
|
734
|
+
return () => {
|
|
735
|
+
cancelled = true;
|
|
736
|
+
};
|
|
737
|
+
}, [client, fetchCount]);
|
|
738
|
+
const refetch = react.useCallback(() => setFetchCount((c) => c + 1), []);
|
|
739
|
+
return { services, loading, error, refetch };
|
|
740
|
+
}
|
|
741
|
+
async function fetchServices(apiKey, opts) {
|
|
742
|
+
const { Resira: Resira2 } = await import('@resira/sdk');
|
|
743
|
+
const client = new Resira2({
|
|
744
|
+
apiKey,
|
|
745
|
+
...opts?.baseUrl ? { baseUrl: opts.baseUrl } : {}
|
|
746
|
+
});
|
|
747
|
+
const data = await client.listProducts();
|
|
748
|
+
return (data.products ?? []).map(enrichProduct);
|
|
749
|
+
}
|
|
655
750
|
var defaultSize = 20;
|
|
656
751
|
function CalendarIcon({ size = defaultSize, className }) {
|
|
657
752
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1779,6 +1874,10 @@ function ServiceOverlayCard({
|
|
|
1779
1874
|
}) {
|
|
1780
1875
|
const currency = product.currency ?? "EUR";
|
|
1781
1876
|
const priceLabel = product.pricingModel === "per_rider" ? "per rider" : product.pricingModel === "per_person" ? locale.perPerson : locale.perSession;
|
|
1877
|
+
const hasMultipleOptions = (product.durationPricing?.length ?? 0) > 1 || (product.riderTierPricing?.length ?? 0) > 1;
|
|
1878
|
+
const lowestPrice = hasMultipleOptions && product.durationPricing?.length ? Math.min(...product.durationPricing.map((dp) => dp.priceCents)) : product.priceCents;
|
|
1879
|
+
const pricePrefix = hasMultipleOptions ? "from " : "";
|
|
1880
|
+
const optionCount = product.durationPricing?.length ?? (product.riderTierPricing?.length ?? 0);
|
|
1782
1881
|
let className = "resira-service-overlay-card";
|
|
1783
1882
|
if (isSelected) className += " resira-service-overlay-card--selected";
|
|
1784
1883
|
if (cardClassName) className += ` ${cardClassName}`;
|
|
@@ -1799,17 +1898,22 @@ function ServiceOverlayCard({
|
|
|
1799
1898
|
] }),
|
|
1800
1899
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-service-overlay-card-bottom", children: [
|
|
1801
1900
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "resira-service-overlay-card-price", children: [
|
|
1802
|
-
|
|
1901
|
+
pricePrefix,
|
|
1902
|
+
formatPrice2(lowestPrice, currency),
|
|
1803
1903
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "resira-service-overlay-card-price-unit", children: [
|
|
1804
1904
|
"/",
|
|
1805
1905
|
priceLabel
|
|
1806
1906
|
] })
|
|
1807
1907
|
] }),
|
|
1808
1908
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-service-overlay-card-pills", children: [
|
|
1809
|
-
|
|
1909
|
+
hasMultipleOptions && optionCount > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "resira-service-overlay-card-pill", children: [
|
|
1910
|
+
/* @__PURE__ */ jsxRuntime.jsx(ClockIcon, { size: 11 }),
|
|
1911
|
+
optionCount,
|
|
1912
|
+
" options"
|
|
1913
|
+
] }) : product.durationMinutes > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "resira-service-overlay-card-pill", children: [
|
|
1810
1914
|
/* @__PURE__ */ jsxRuntime.jsx(ClockIcon, { size: 11 }),
|
|
1811
1915
|
formatDuration2(product.durationMinutes)
|
|
1812
|
-
] }),
|
|
1916
|
+
] }) : null,
|
|
1813
1917
|
product.maxPartySize && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "resira-service-overlay-card-pill", children: [
|
|
1814
1918
|
/* @__PURE__ */ jsxRuntime.jsx(UsersIcon, { size: 11 }),
|
|
1815
1919
|
"max ",
|
|
@@ -3026,8 +3130,14 @@ function ResiraBookingWidget() {
|
|
|
3026
3130
|
partySize: clampedPartySize
|
|
3027
3131
|
};
|
|
3028
3132
|
});
|
|
3133
|
+
if (step === "resource" && isServiceBased) {
|
|
3134
|
+
const nextIdx = stepIndex("resource", STEPS) + 1;
|
|
3135
|
+
if (nextIdx < STEPS.length) {
|
|
3136
|
+
setStep(STEPS[nextIdx]);
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3029
3139
|
},
|
|
3030
|
-
[setActiveResourceId, domainConfig.maxPartySize]
|
|
3140
|
+
[setActiveResourceId, domainConfig.maxPartySize, step, isServiceBased, STEPS]
|
|
3031
3141
|
);
|
|
3032
3142
|
const handleResourceSelect = react.useCallback(
|
|
3033
3143
|
(resourceId) => {
|
|
@@ -4245,6 +4355,7 @@ exports.UsersIcon = UsersIcon;
|
|
|
4245
4355
|
exports.ViewfinderIcon = ViewfinderIcon;
|
|
4246
4356
|
exports.WaiverConsent = WaiverConsent;
|
|
4247
4357
|
exports.XIcon = XIcon;
|
|
4358
|
+
exports.fetchServices = fetchServices;
|
|
4248
4359
|
exports.resolveTheme = resolveTheme;
|
|
4249
4360
|
exports.themeToCSS = themeToCSS;
|
|
4250
4361
|
exports.useAvailability = useAvailability;
|
|
@@ -4256,6 +4367,7 @@ exports.useProducts = useProducts;
|
|
|
4256
4367
|
exports.useReservation = useReservation;
|
|
4257
4368
|
exports.useResira = useResira;
|
|
4258
4369
|
exports.useResources = useResources;
|
|
4370
|
+
exports.useServices = useServices;
|
|
4259
4371
|
exports.validateGuestForm = validateGuestForm;
|
|
4260
4372
|
//# sourceMappingURL=index.cjs.map
|
|
4261
4373
|
//# sourceMappingURL=index.cjs.map
|