@wix/headless-bookings 0.0.41 → 0.0.43

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.
@@ -58,6 +58,7 @@ export interface ListDataRenderProps {
58
58
  isLoading: boolean;
59
59
  error: string | null;
60
60
  loadMore: () => Promise<void>;
61
+ isSelectionComplete: boolean;
61
62
  }
62
63
  /**
63
64
  * Props for ListData render prop component
@@ -73,7 +74,7 @@ export interface ListDataProps {
73
74
  * @example
74
75
  * ```tsx
75
76
  * <ListData>
76
- * {({ timeSlots, hasMore, isLoading, loadMore }) => (
77
+ * {({ timeSlots, hasMore, isLoading, loadMore, isSelectionComplete }) => (
77
78
  * <GenericList.Root items={timeSlots} hasMore={hasMore} isLoading={isLoading} loadMore={loadMore}>
78
79
  * {children}
79
80
  * </GenericList.Root>
@@ -68,7 +68,7 @@ export function Timezone(props) {
68
68
  * @example
69
69
  * ```tsx
70
70
  * <ListData>
71
- * {({ timeSlots, hasMore, isLoading, loadMore }) => (
71
+ * {({ timeSlots, hasMore, isLoading, loadMore, isSelectionComplete }) => (
72
72
  * <GenericList.Root items={timeSlots} hasMore={hasMore} isLoading={isLoading} loadMore={loadMore}>
73
73
  * {children}
74
74
  * </GenericList.Root>
@@ -78,12 +78,18 @@ export function Timezone(props) {
78
78
  */
79
79
  export function ListData(props) {
80
80
  const service = useService(TimeSlotListServiceDefinition);
81
+ const bookingService = useService(BookingServiceDefinition);
82
+ const selectedTimeSlot = bookingService.serviceSelections.get()[0]?.timeSlot;
83
+ const hasTimeSlot = !!selectedTimeSlot;
84
+ const hasSelectedStaffMember = (selectedTimeSlot?.resources?.length ?? 0) === 1;
85
+ const isSelectionComplete = hasTimeSlot && hasSelectedStaffMember;
81
86
  return props.children({
82
87
  timeSlots: service.timeSlots.get(),
83
88
  hasMore: service.hasMore.get(),
84
89
  isLoading: service.isLoading.get(),
85
90
  error: service.error.get(),
86
91
  loadMore: service.actions.loadMore,
92
+ isSelectionComplete,
87
93
  });
88
94
  }
89
95
  /**
@@ -8,20 +8,49 @@ import { MoneyData } from '@wix/headless-components/react';
8
8
  import { type Service, type Payment } from '@wix/auto_sdk_bookings_services';
9
9
  import * as ServiceMediaModule from './ServiceMedia.js';
10
10
  /**
11
- * Props for Service.Root component
11
+ * Base props shared by all Service.Root variants
12
12
  */
13
- export interface ServiceRootProps {
13
+ interface ServiceRootBaseProps {
14
14
  children?: React.ReactNode | AsChildChildren<{
15
15
  selected: boolean;
16
16
  bookable: boolean;
17
17
  }>;
18
- service: Service;
19
18
  appId?: string;
20
19
  asChild?: boolean;
21
20
  className?: string;
22
21
  }
22
+ /**
23
+ * Props for Service.Root with pre-loaded service object (SSR pattern)
24
+ */
25
+ type ServiceRootWithService = ServiceRootBaseProps & {
26
+ service: Service;
27
+ serviceId?: never;
28
+ serviceSlug?: never;
29
+ };
30
+ /**
31
+ * Props for Service.Root with dynamic loading by service ID
32
+ */
33
+ type ServiceRootWithId = ServiceRootBaseProps & {
34
+ service?: never;
35
+ serviceId: string;
36
+ serviceSlug?: never;
37
+ };
38
+ /**
39
+ * Props for Service.Root with dynamic loading by service slug
40
+ */
41
+ type ServiceRootWithSlug = ServiceRootBaseProps & {
42
+ service?: never;
43
+ serviceId?: never;
44
+ serviceSlug: string;
45
+ };
46
+ /**
47
+ * Props for Service.Root component.
48
+ * Requires exactly one of: service, serviceId, or serviceSlug.
49
+ */
50
+ export type ServiceRootProps = ServiceRootWithService | ServiceRootWithId | ServiceRootWithSlug;
23
51
  /**
24
52
  * Root component that provides service context to the entire app.
53
+ * Requires exactly one of: service, serviceId, or serviceSlug.
25
54
  *
26
55
  * @order 1
27
56
  * @component
@@ -29,6 +58,7 @@ export interface ServiceRootProps {
29
58
  * ```tsx
30
59
  * import { Service } from '@wix/bookings/components';
31
60
  *
61
+ * // With pre-loaded service object (SSR pattern)
32
62
  * function ServicePage({ service }) {
33
63
  * return (
34
64
  * <Service.Root service={service}>
@@ -37,6 +67,26 @@ export interface ServiceRootProps {
37
67
  * </Service.Root>
38
68
  * );
39
69
  * }
70
+ *
71
+ * // With dynamic loading by serviceId
72
+ * function ServicePageById({ serviceId }) {
73
+ * return (
74
+ * <Service.Root serviceId={serviceId}>
75
+ * <Service.Name />
76
+ * <Service.Description />
77
+ * </Service.Root>
78
+ * );
79
+ * }
80
+ *
81
+ * // With dynamic loading by serviceSlug
82
+ * function ServicePageBySlug({ slug }) {
83
+ * return (
84
+ * <Service.Root serviceSlug={slug}>
85
+ * <Service.Name />
86
+ * <Service.Description />
87
+ * </Service.Root>
88
+ * );
89
+ * }
40
90
  * ```
41
91
  */
42
92
  export declare const Root: React.ForwardRefExoticComponent<ServiceRootProps & React.RefAttributes<HTMLElement>>;
@@ -47,6 +47,7 @@ var TestIds;
47
47
  })(TestIds || (TestIds = {}));
48
48
  /**
49
49
  * Root component that provides service context to the entire app.
50
+ * Requires exactly one of: service, serviceId, or serviceSlug.
50
51
  *
51
52
  * @order 1
52
53
  * @component
@@ -54,6 +55,7 @@ var TestIds;
54
55
  * ```tsx
55
56
  * import { Service } from '@wix/bookings/components';
56
57
  *
58
+ * // With pre-loaded service object (SSR pattern)
57
59
  * function ServicePage({ service }) {
58
60
  * return (
59
61
  * <Service.Root service={service}>
@@ -62,11 +64,31 @@ var TestIds;
62
64
  * </Service.Root>
63
65
  * );
64
66
  * }
67
+ *
68
+ * // With dynamic loading by serviceId
69
+ * function ServicePageById({ serviceId }) {
70
+ * return (
71
+ * <Service.Root serviceId={serviceId}>
72
+ * <Service.Name />
73
+ * <Service.Description />
74
+ * </Service.Root>
75
+ * );
76
+ * }
77
+ *
78
+ * // With dynamic loading by serviceSlug
79
+ * function ServicePageBySlug({ slug }) {
80
+ * return (
81
+ * <Service.Root serviceSlug={slug}>
82
+ * <Service.Name />
83
+ * <Service.Description />
84
+ * </Service.Root>
85
+ * );
86
+ * }
65
87
  * ```
66
88
  */
67
89
  export const Root = React.forwardRef((props, ref) => {
68
- const { children, service, appId, asChild, className, ...attrs } = props;
69
- return (_jsx(CoreService.Root, { serviceServiceConfig: { service, appId }, children: ({ selected, bookable }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceRoot, "data-selected": selected, "data-bookable": bookable, customElement: children, customElementProps: { selected, bookable }, ...attrs, children: children })) }));
90
+ const { children, service, serviceId, serviceSlug, appId, asChild, className, ...attrs } = props;
91
+ return (_jsx(CoreService.Root, { serviceServiceConfig: { service, serviceId, serviceSlug, appId }, children: ({ selected, bookable }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceRoot, "data-selected": selected, "data-bookable": bookable, customElement: children, customElementProps: { selected, bookable }, ...attrs, children: children })) }));
70
92
  });
71
93
  Root.displayName = 'Service.Root';
72
94
  /**
@@ -86,13 +86,10 @@ Root.displayName = 'TimeSlotList.Root';
86
86
  */
87
87
  const RootContent = React.forwardRef((props, ref) => {
88
88
  const { children, className, variant } = props;
89
- return (_jsx(CoreTimeSlotList.ListData, { children: ({ timeSlots, hasMore, isLoading, error, loadMore }) => (
90
- // Add stable `id` for GenericList at the headless boundary only.
91
- // The underlying service slots remain raw (no grouping / no extra fields).
92
- _jsx(GenericList.Root, { items: timeSlots.map((slot) => ({
89
+ return (_jsx(CoreTimeSlotList.ListData, { children: ({ timeSlots, hasMore, isLoading, error, loadMore, isSelectionComplete, }) => (_jsx(GenericList.Root, { items: timeSlots.map((slot) => ({
93
90
  ...slot,
94
91
  id: generateSlotKey(slot),
95
- })), loadMore: loadMore, hasMore: hasMore, isLoading: isLoading, error: error, className: className, ref: ref, "data-testid": TestIds.timeSlotListRoot, variant: variant, children: children })) }));
92
+ })), loadMore: loadMore, hasMore: hasMore, isLoading: isLoading, error: error, className: className, ref: ref, "data-testid": TestIds.timeSlotListRoot, "data-selection-complete": isSelectionComplete, variant: variant, children: children })) }));
96
93
  });
97
94
  RootContent.displayName = 'TimeSlotList.RootContent';
98
95
  /**
@@ -58,6 +58,7 @@ export interface ListDataRenderProps {
58
58
  isLoading: boolean;
59
59
  error: string | null;
60
60
  loadMore: () => Promise<void>;
61
+ isSelectionComplete: boolean;
61
62
  }
62
63
  /**
63
64
  * Props for ListData render prop component
@@ -73,7 +74,7 @@ export interface ListDataProps {
73
74
  * @example
74
75
  * ```tsx
75
76
  * <ListData>
76
- * {({ timeSlots, hasMore, isLoading, loadMore }) => (
77
+ * {({ timeSlots, hasMore, isLoading, loadMore, isSelectionComplete }) => (
77
78
  * <GenericList.Root items={timeSlots} hasMore={hasMore} isLoading={isLoading} loadMore={loadMore}>
78
79
  * {children}
79
80
  * </GenericList.Root>
@@ -68,7 +68,7 @@ export function Timezone(props) {
68
68
  * @example
69
69
  * ```tsx
70
70
  * <ListData>
71
- * {({ timeSlots, hasMore, isLoading, loadMore }) => (
71
+ * {({ timeSlots, hasMore, isLoading, loadMore, isSelectionComplete }) => (
72
72
  * <GenericList.Root items={timeSlots} hasMore={hasMore} isLoading={isLoading} loadMore={loadMore}>
73
73
  * {children}
74
74
  * </GenericList.Root>
@@ -78,12 +78,18 @@ export function Timezone(props) {
78
78
  */
79
79
  export function ListData(props) {
80
80
  const service = useService(TimeSlotListServiceDefinition);
81
+ const bookingService = useService(BookingServiceDefinition);
82
+ const selectedTimeSlot = bookingService.serviceSelections.get()[0]?.timeSlot;
83
+ const hasTimeSlot = !!selectedTimeSlot;
84
+ const hasSelectedStaffMember = (selectedTimeSlot?.resources?.length ?? 0) === 1;
85
+ const isSelectionComplete = hasTimeSlot && hasSelectedStaffMember;
81
86
  return props.children({
82
87
  timeSlots: service.timeSlots.get(),
83
88
  hasMore: service.hasMore.get(),
84
89
  isLoading: service.isLoading.get(),
85
90
  error: service.error.get(),
86
91
  loadMore: service.actions.loadMore,
92
+ isSelectionComplete,
87
93
  });
88
94
  }
89
95
  /**
@@ -8,20 +8,49 @@ import { MoneyData } from '@wix/headless-components/react';
8
8
  import { type Service, type Payment } from '@wix/auto_sdk_bookings_services';
9
9
  import * as ServiceMediaModule from './ServiceMedia.js';
10
10
  /**
11
- * Props for Service.Root component
11
+ * Base props shared by all Service.Root variants
12
12
  */
13
- export interface ServiceRootProps {
13
+ interface ServiceRootBaseProps {
14
14
  children?: React.ReactNode | AsChildChildren<{
15
15
  selected: boolean;
16
16
  bookable: boolean;
17
17
  }>;
18
- service: Service;
19
18
  appId?: string;
20
19
  asChild?: boolean;
21
20
  className?: string;
22
21
  }
22
+ /**
23
+ * Props for Service.Root with pre-loaded service object (SSR pattern)
24
+ */
25
+ type ServiceRootWithService = ServiceRootBaseProps & {
26
+ service: Service;
27
+ serviceId?: never;
28
+ serviceSlug?: never;
29
+ };
30
+ /**
31
+ * Props for Service.Root with dynamic loading by service ID
32
+ */
33
+ type ServiceRootWithId = ServiceRootBaseProps & {
34
+ service?: never;
35
+ serviceId: string;
36
+ serviceSlug?: never;
37
+ };
38
+ /**
39
+ * Props for Service.Root with dynamic loading by service slug
40
+ */
41
+ type ServiceRootWithSlug = ServiceRootBaseProps & {
42
+ service?: never;
43
+ serviceId?: never;
44
+ serviceSlug: string;
45
+ };
46
+ /**
47
+ * Props for Service.Root component.
48
+ * Requires exactly one of: service, serviceId, or serviceSlug.
49
+ */
50
+ export type ServiceRootProps = ServiceRootWithService | ServiceRootWithId | ServiceRootWithSlug;
23
51
  /**
24
52
  * Root component that provides service context to the entire app.
53
+ * Requires exactly one of: service, serviceId, or serviceSlug.
25
54
  *
26
55
  * @order 1
27
56
  * @component
@@ -29,6 +58,7 @@ export interface ServiceRootProps {
29
58
  * ```tsx
30
59
  * import { Service } from '@wix/bookings/components';
31
60
  *
61
+ * // With pre-loaded service object (SSR pattern)
32
62
  * function ServicePage({ service }) {
33
63
  * return (
34
64
  * <Service.Root service={service}>
@@ -37,6 +67,26 @@ export interface ServiceRootProps {
37
67
  * </Service.Root>
38
68
  * );
39
69
  * }
70
+ *
71
+ * // With dynamic loading by serviceId
72
+ * function ServicePageById({ serviceId }) {
73
+ * return (
74
+ * <Service.Root serviceId={serviceId}>
75
+ * <Service.Name />
76
+ * <Service.Description />
77
+ * </Service.Root>
78
+ * );
79
+ * }
80
+ *
81
+ * // With dynamic loading by serviceSlug
82
+ * function ServicePageBySlug({ slug }) {
83
+ * return (
84
+ * <Service.Root serviceSlug={slug}>
85
+ * <Service.Name />
86
+ * <Service.Description />
87
+ * </Service.Root>
88
+ * );
89
+ * }
40
90
  * ```
41
91
  */
42
92
  export declare const Root: React.ForwardRefExoticComponent<ServiceRootProps & React.RefAttributes<HTMLElement>>;
@@ -47,6 +47,7 @@ var TestIds;
47
47
  })(TestIds || (TestIds = {}));
48
48
  /**
49
49
  * Root component that provides service context to the entire app.
50
+ * Requires exactly one of: service, serviceId, or serviceSlug.
50
51
  *
51
52
  * @order 1
52
53
  * @component
@@ -54,6 +55,7 @@ var TestIds;
54
55
  * ```tsx
55
56
  * import { Service } from '@wix/bookings/components';
56
57
  *
58
+ * // With pre-loaded service object (SSR pattern)
57
59
  * function ServicePage({ service }) {
58
60
  * return (
59
61
  * <Service.Root service={service}>
@@ -62,11 +64,31 @@ var TestIds;
62
64
  * </Service.Root>
63
65
  * );
64
66
  * }
67
+ *
68
+ * // With dynamic loading by serviceId
69
+ * function ServicePageById({ serviceId }) {
70
+ * return (
71
+ * <Service.Root serviceId={serviceId}>
72
+ * <Service.Name />
73
+ * <Service.Description />
74
+ * </Service.Root>
75
+ * );
76
+ * }
77
+ *
78
+ * // With dynamic loading by serviceSlug
79
+ * function ServicePageBySlug({ slug }) {
80
+ * return (
81
+ * <Service.Root serviceSlug={slug}>
82
+ * <Service.Name />
83
+ * <Service.Description />
84
+ * </Service.Root>
85
+ * );
86
+ * }
65
87
  * ```
66
88
  */
67
89
  export const Root = React.forwardRef((props, ref) => {
68
- const { children, service, appId, asChild, className, ...attrs } = props;
69
- return (_jsx(CoreService.Root, { serviceServiceConfig: { service, appId }, children: ({ selected, bookable }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceRoot, "data-selected": selected, "data-bookable": bookable, customElement: children, customElementProps: { selected, bookable }, ...attrs, children: children })) }));
90
+ const { children, service, serviceId, serviceSlug, appId, asChild, className, ...attrs } = props;
91
+ return (_jsx(CoreService.Root, { serviceServiceConfig: { service, serviceId, serviceSlug, appId }, children: ({ selected, bookable }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceRoot, "data-selected": selected, "data-bookable": bookable, customElement: children, customElementProps: { selected, bookable }, ...attrs, children: children })) }));
70
92
  });
71
93
  Root.displayName = 'Service.Root';
72
94
  /**
@@ -86,13 +86,10 @@ Root.displayName = 'TimeSlotList.Root';
86
86
  */
87
87
  const RootContent = React.forwardRef((props, ref) => {
88
88
  const { children, className, variant } = props;
89
- return (_jsx(CoreTimeSlotList.ListData, { children: ({ timeSlots, hasMore, isLoading, error, loadMore }) => (
90
- // Add stable `id` for GenericList at the headless boundary only.
91
- // The underlying service slots remain raw (no grouping / no extra fields).
92
- _jsx(GenericList.Root, { items: timeSlots.map((slot) => ({
89
+ return (_jsx(CoreTimeSlotList.ListData, { children: ({ timeSlots, hasMore, isLoading, error, loadMore, isSelectionComplete, }) => (_jsx(GenericList.Root, { items: timeSlots.map((slot) => ({
93
90
  ...slot,
94
91
  id: generateSlotKey(slot),
95
- })), loadMore: loadMore, hasMore: hasMore, isLoading: isLoading, error: error, className: className, ref: ref, "data-testid": TestIds.timeSlotListRoot, variant: variant, children: children })) }));
92
+ })), loadMore: loadMore, hasMore: hasMore, isLoading: isLoading, error: error, className: className, ref: ref, "data-testid": TestIds.timeSlotListRoot, "data-selection-complete": isSelectionComplete, variant: variant, children: children })) }));
96
93
  });
97
94
  RootContent.displayName = 'TimeSlotList.RootContent';
98
95
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-bookings",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -72,5 +72,5 @@
72
72
  "groupId": "com.wixpress.headless-components"
73
73
  }
74
74
  },
75
- "falconPackageHash": "5847d0ce3b07a2485f7d9b707eee272b9f100b3d13614c2d92018112"
75
+ "falconPackageHash": "7fc1fdfa9ef983dbdae64fb719cdb4674afcf085f05ecbc425214a9e"
76
76
  }