@licklist/design 0.78.35 → 0.78.37

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.
Files changed (99) hide show
  1. package/dist/index.d.ts +4 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +9 -2
  4. package/dist/v2/components/ActionMenu/ActionMenu.d.ts.map +1 -1
  5. package/dist/v2/components/ActionMenu/ActionMenu.js +6 -16
  6. package/dist/v2/components/ActionMenu/ActionMenu.scss.js +1 -1
  7. package/dist/v2/components/Button/Button.scss.js +1 -1
  8. package/dist/v2/components/Button/GhostButton.scss.js +1 -1
  9. package/dist/v2/components/Checkbox/Checkbox.scss.js +1 -1
  10. package/dist/v2/components/FormField/FormField.d.ts +3 -0
  11. package/dist/v2/components/FormField/FormField.d.ts.map +1 -1
  12. package/dist/v2/components/FormField/FormField.js +14 -3
  13. package/dist/v2/components/FormField/FormField.scss.js +1 -1
  14. package/dist/v2/components/IconButton/IconButton.d.ts +9 -0
  15. package/dist/v2/components/IconButton/IconButton.d.ts.map +1 -0
  16. package/dist/v2/components/IconButton/IconButton.js +137 -0
  17. package/dist/v2/components/IconButton/IconButton.scss.js +6 -0
  18. package/dist/v2/components/IconButton/index.d.ts +3 -0
  19. package/dist/v2/components/IconButton/index.d.ts.map +1 -0
  20. package/dist/v2/components/InputCheckbox/InputCheckbox.d.ts +7 -0
  21. package/dist/v2/components/InputCheckbox/InputCheckbox.d.ts.map +1 -0
  22. package/dist/v2/components/InputCheckbox/InputCheckbox.js +85 -0
  23. package/dist/v2/components/InputCheckbox/InputCheckbox.scss.js +6 -0
  24. package/dist/v2/components/InputCheckbox/index.d.ts +3 -0
  25. package/dist/v2/components/InputCheckbox/index.d.ts.map +1 -0
  26. package/dist/v2/components/NewInput/NewInput.d.ts +1 -0
  27. package/dist/v2/components/NewInput/NewInput.d.ts.map +1 -1
  28. package/dist/v2/components/NewInput/NewInput.js +7 -4
  29. package/dist/v2/components/NewPageHeader/NewPageHeader.scss.js +1 -1
  30. package/dist/v2/components/QuickFilter/QuickFilter.scss.js +1 -1
  31. package/dist/v2/components/ZoneCard/AddResourceButton.d.ts +8 -0
  32. package/dist/v2/components/ZoneCard/AddResourceButton.d.ts.map +1 -0
  33. package/dist/v2/components/ZoneCard/AddResourceButton.js +17 -0
  34. package/dist/v2/components/ZoneCard/ResourceRow.d.ts +28 -0
  35. package/dist/v2/components/ZoneCard/ResourceRow.d.ts.map +1 -0
  36. package/dist/v2/components/ZoneCard/ResourceRow.js +191 -0
  37. package/dist/v2/components/ZoneCard/ZoneCard.d.ts +25 -0
  38. package/dist/v2/components/ZoneCard/ZoneCard.d.ts.map +1 -0
  39. package/dist/v2/components/ZoneCard/ZoneCard.js +43 -0
  40. package/dist/v2/components/ZoneCard/ZoneCard.scss.js +6 -0
  41. package/dist/v2/components/ZoneCard/ZoneContainer.d.ts +12 -0
  42. package/dist/v2/components/ZoneCard/ZoneContainer.d.ts.map +1 -0
  43. package/dist/v2/components/ZoneCard/ZoneContainer.js +16 -0
  44. package/dist/v2/components/ZoneCard/ZoneHeader.d.ts +20 -0
  45. package/dist/v2/components/ZoneCard/ZoneHeader.d.ts.map +1 -0
  46. package/dist/v2/components/ZoneCard/ZoneHeader.js +149 -0
  47. package/dist/v2/components/ZoneCard/index.d.ts +11 -0
  48. package/dist/v2/components/ZoneCard/index.d.ts.map +1 -0
  49. package/dist/v2/components/index.d.ts +7 -1
  50. package/dist/v2/components/index.d.ts.map +1 -1
  51. package/dist/v2/icons/index.js +57 -1
  52. package/dist/v2/index.d.ts +10 -0
  53. package/dist/v2/index.d.ts.map +1 -1
  54. package/dist/v2/pages/Settings/components/SidebarCustomisation.js +6 -0
  55. package/dist/v2/pages/Settings/components/SidebarNavItem.js +6 -0
  56. package/dist/v2/pages/ZonesResources/ZonesResourcesPage.d.ts +12 -0
  57. package/dist/v2/pages/ZonesResources/ZonesResourcesPage.d.ts.map +1 -0
  58. package/dist/v2/pages/ZonesResources/ZonesResourcesPage.js +47 -0
  59. package/dist/v2/pages/ZonesResources/ZonesResourcesPage.scss.js +6 -0
  60. package/dist/v2/pages/ZonesResources/index.d.ts +3 -0
  61. package/dist/v2/pages/ZonesResources/index.d.ts.map +1 -0
  62. package/dist/v2/styles/form/NewInput.scss.js +1 -1
  63. package/package.json +1 -1
  64. package/src/index.ts +4 -1
  65. package/src/v2/components/ActionMenu/ActionMenu.scss +7 -20
  66. package/src/v2/components/ActionMenu/ActionMenu.stories.tsx +58 -0
  67. package/src/v2/components/ActionMenu/ActionMenu.tsx +3 -6
  68. package/src/v2/components/Button/GhostButton.scss +1 -1
  69. package/src/v2/components/Checkbox/Checkbox.scss +3 -3
  70. package/src/v2/components/Customer/CustomersList.scss +26 -8
  71. package/src/v2/components/FormField/FormField.scss +20 -1
  72. package/src/v2/components/FormField/FormField.tsx +33 -19
  73. package/src/v2/components/IconButton/IconButton.scss +81 -0
  74. package/src/v2/components/IconButton/IconButton.stories.tsx +51 -0
  75. package/src/v2/components/IconButton/IconButton.tsx +50 -0
  76. package/src/v2/components/IconButton/index.ts +2 -0
  77. package/src/v2/components/InputCheckbox/InputCheckbox.scss +53 -0
  78. package/src/v2/components/InputCheckbox/InputCheckbox.tsx +24 -0
  79. package/src/v2/components/InputCheckbox/index.ts +2 -0
  80. package/src/v2/components/NewInput/NewInput.tsx +5 -2
  81. package/src/v2/components/NewPageHeader/NewPageHeader.scss +1 -5
  82. package/src/v2/components/NewPageHeader/NewPageHeader.stories.tsx +28 -0
  83. package/src/v2/components/QuickFilter/QuickFilter.scss +0 -1
  84. package/src/v2/components/ZoneCard/AddResourceButton.tsx +20 -0
  85. package/src/v2/components/ZoneCard/ResourceRow.tsx +115 -0
  86. package/src/v2/components/ZoneCard/ZoneCard.scss +226 -0
  87. package/src/v2/components/ZoneCard/ZoneCard.stories.tsx +137 -0
  88. package/src/v2/components/ZoneCard/ZoneCard.tsx +69 -0
  89. package/src/v2/components/ZoneCard/ZoneContainer.tsx +26 -0
  90. package/src/v2/components/ZoneCard/ZoneHeader.tsx +84 -0
  91. package/src/v2/components/ZoneCard/index.ts +14 -0
  92. package/src/v2/components/index.ts +14 -1
  93. package/src/v2/index.ts +21 -0
  94. package/src/v2/pages/ZonesResources/ZonesResourcesPage.scss +43 -0
  95. package/src/v2/pages/ZonesResources/ZonesResourcesPage.stories.tsx +46 -0
  96. package/src/v2/pages/ZonesResources/ZonesResourcesPage.tsx +49 -0
  97. package/src/v2/pages/ZonesResources/index.ts +2 -0
  98. package/src/v2/styles/components/Button.scss +1 -0
  99. package/src/v2/styles/form/NewInput.scss +39 -6
@@ -1,5 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react'
2
2
  import { NewPageHeader } from './NewPageHeader'
3
+ import { Button, ButtonText } from '../Button'
3
4
 
4
5
  const meta: Meta<typeof NewPageHeader> = {
5
6
  title: 'V2/Components/NewPageHeader',
@@ -42,3 +43,30 @@ export const CustomCancelLabel: Story = {
42
43
  onCancel: () => alert('Go Back clicked'),
43
44
  },
44
45
  }
46
+
47
+ export const WithAction: Story = {
48
+ args: {
49
+ title: 'Zones & Resources',
50
+ renderRight: () => (
51
+ <Button variant="primary" onClick={() => alert('Add Zone clicked')}>
52
+ <ButtonText color="white">+ Add Zone</ButtonText>
53
+ </Button>
54
+ ),
55
+ },
56
+ }
57
+
58
+ export const WithMultipleActions: Story = {
59
+ args: {
60
+ title: 'Zones & Resources',
61
+ renderRight: () => (
62
+ <>
63
+ <Button variant="secondary" onClick={() => alert('Export clicked')}>
64
+ <ButtonText color="action">Export</ButtonText>
65
+ </Button>
66
+ <Button variant="primary" onClick={() => alert('Add Zone clicked')}>
67
+ <ButtonText color="white">+ Add Zone</ButtonText>
68
+ </Button>
69
+ </>
70
+ ),
71
+ },
72
+ }
@@ -17,7 +17,6 @@
17
17
  gap: 8px;
18
18
  -ms-overflow-style: none; /* IE and Edge */
19
19
  scrollbar-width: none; /* Firefox */
20
- padding-bottom: 2px; /* Prevent button shadows/borders from being cut off during scroll if any */
21
20
 
22
21
  &::-webkit-scrollbar {
23
22
  display: none; /* Chrome, Safari and Opera */
@@ -0,0 +1,20 @@
1
+ import React from 'react'
2
+ import { IconButton } from '../IconButton'
3
+
4
+ export interface AddResourceButtonProps {
5
+ label?: string
6
+ onClick: () => void
7
+ className?: string
8
+ }
9
+
10
+ export const AddResourceButton: React.FC<AddResourceButtonProps> = ({
11
+ label = 'Add Resource',
12
+ onClick,
13
+ className = '',
14
+ }) => {
15
+ return (
16
+ <div className={`zone-card__add-resource-wrapper ${className}`}>
17
+ <IconButton label={label} icon='add' onClick={onClick} />
18
+ </div>
19
+ )
20
+ }
@@ -0,0 +1,115 @@
1
+ import React from 'react'
2
+ import { ActionMenu, ActionMenuItem } from '../ActionMenu'
3
+ import { GripVerticalIcon, ArrowUpIcon, ArrowDownIcon } from '../../icons'
4
+ import { DragHandleProps } from './ZoneContainer'
5
+ import './ZoneCard.scss'
6
+
7
+ export interface ResourceRowLabels {
8
+ quantity?: string
9
+ capacity?: string
10
+ total?: string
11
+ }
12
+
13
+ export interface ResourceRowProps {
14
+ name: string
15
+ quantity: number
16
+ capacity: number
17
+ labels?: ResourceRowLabels
18
+ menuItems?: ActionMenuItem[]
19
+ draggable?: boolean
20
+ dragHandleProps?: DragHandleProps
21
+ onClick?: () => void
22
+ className?: string
23
+ style?: React.CSSProperties
24
+ isMobile?: boolean
25
+ isFirst?: boolean
26
+ isLast?: boolean
27
+ onMoveUp?: () => void
28
+ onMoveDown?: () => void
29
+ }
30
+
31
+ export const ResourceRow = React.forwardRef<HTMLDivElement, ResourceRowProps>(({
32
+ name,
33
+ quantity,
34
+ capacity,
35
+ labels = {},
36
+ menuItems = [],
37
+ draggable = true,
38
+ dragHandleProps,
39
+ onClick,
40
+ className = '',
41
+ style,
42
+ isMobile = false,
43
+ isFirst = false,
44
+ isLast = false,
45
+ onMoveUp,
46
+ onMoveDown,
47
+ }, ref) => {
48
+ const qtyLabel = labels.quantity ?? 'Qty'
49
+ const capLabel = labels.capacity ?? 'Cap'
50
+ const totalLabel = labels.total ?? 'Total'
51
+ const classes = [
52
+ 'zone-card__resource',
53
+ onClick ? 'zone-card__resource--clickable' : '',
54
+ isMobile ? 'zone-card__resource--mobile' : '',
55
+ className,
56
+ ].filter(Boolean).join(' ')
57
+
58
+ return (
59
+ <div ref={ref} className={classes} style={style} onClick={onClick}>
60
+ {draggable && !isMobile && (
61
+ <div
62
+ className="zone-card__drag-handle zone-card__drag-handle--resource"
63
+ {...dragHandleProps}
64
+ onClick={(e) => e.stopPropagation()}
65
+ >
66
+ {GripVerticalIcon({ width: 16, height: 16 })}
67
+ </div>
68
+ )}
69
+ {draggable && isMobile && (
70
+ <div className="zone-card__reorder-arrows zone-card__reorder-arrows--resource" onClick={(e) => e.stopPropagation()}>
71
+ <button
72
+ className="zone-card__arrow-btn"
73
+ disabled={isFirst}
74
+ onClick={(e) => { e.stopPropagation(); onMoveUp?.() }}
75
+ >
76
+ <ArrowUpIcon />
77
+ </button>
78
+ <button
79
+ className="zone-card__arrow-btn"
80
+ disabled={isLast}
81
+ onClick={(e) => { e.stopPropagation(); onMoveDown?.() }}
82
+ >
83
+ <ArrowDownIcon />
84
+ </button>
85
+ </div>
86
+ )}
87
+ {isMobile ? (
88
+ <div className="zone-card__resource-info">
89
+ <span className="zone-card__resource-name">{name}</span>
90
+ <span className="zone-card__resource-stats-mobile">
91
+ {qtyLabel}: {quantity} &middot; {capLabel}: {capacity} &middot; {totalLabel}: {quantity * capacity}
92
+ </span>
93
+ </div>
94
+ ) : (
95
+ <>
96
+ <span className="zone-card__resource-name">{name}</span>
97
+ <div className="zone-card__resource-stats">
98
+ <span className="zone-card__resource-stat">{qtyLabel}: {quantity}</span>
99
+ <span className="zone-card__resource-stat">{capLabel}: {capacity}</span>
100
+ <span className="zone-card__resource-stat zone-card__resource-stat--total">
101
+ {totalLabel}: {quantity * capacity}
102
+ </span>
103
+ </div>
104
+ </>
105
+ )}
106
+ {menuItems.length > 0 && (
107
+ <div className="zone-card__resource-actions" onClick={(e) => e.stopPropagation()}>
108
+ <ActionMenu items={menuItems} />
109
+ </div>
110
+ )}
111
+ </div>
112
+ )
113
+ })
114
+
115
+ ResourceRow.displayName = 'ResourceRow'
@@ -0,0 +1,226 @@
1
+ .zone-card {
2
+ border: 1px solid var(--border-primary);
3
+ border-radius: 8px;
4
+ overflow: visible;
5
+ background: var(--surface-primary);
6
+
7
+ &__header {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: 16px;
11
+ padding: 12px 16px;
12
+ background: var(--surface-secondary);
13
+ }
14
+
15
+ &__drag-handle {
16
+ display: flex;
17
+ align-items: center;
18
+ padding: 6px;
19
+ border-radius: 6px;
20
+ cursor: grab;
21
+ color: var(--label-tertiary, var(--label-secondary));
22
+ transition: all 0.2s ease;
23
+ flex-shrink: 0;
24
+
25
+ &:hover {
26
+ color: var(--label-secondary);
27
+ background: var(--surface-primary);
28
+ }
29
+
30
+ &:active {
31
+ cursor: grabbing;
32
+ }
33
+
34
+ &--resource {
35
+ color: var(--label-tertiary, var(--label-secondary));
36
+ }
37
+ }
38
+
39
+ // Mobile reorder arrows (replaces drag handles)
40
+ &__reorder-arrows {
41
+ display: flex;
42
+ flex-direction: column;
43
+ gap: 2px;
44
+ flex-shrink: 0;
45
+
46
+ &--resource {
47
+ margin-right: 0;
48
+ }
49
+ }
50
+
51
+ &__arrow-btn {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ width: 28px;
56
+ height: 28px;
57
+ border: none;
58
+ border-radius: 4px;
59
+ background: transparent;
60
+ color: var(--label-tertiary, var(--label-secondary));
61
+ cursor: pointer;
62
+ transition: all 0.2s ease;
63
+ padding: 0;
64
+
65
+ &:hover:not(:disabled) {
66
+ color: var(--label-secondary);
67
+ background: var(--surface-primary);
68
+ }
69
+
70
+ &:disabled {
71
+ opacity: 0.25;
72
+ pointer-events: none;
73
+ }
74
+ }
75
+
76
+ &__name {
77
+ flex: 1;
78
+ min-width: 0;
79
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
80
+ font-size: 15px;
81
+ font-weight: 600;
82
+ line-height: 20px;
83
+ color: var(--label-primary);
84
+ }
85
+
86
+ &__header-info {
87
+ display: flex;
88
+ flex-direction: column;
89
+ flex: 1;
90
+ min-width: 0;
91
+ gap: 2px;
92
+
93
+ .zone-card__total {
94
+ text-align: left;
95
+ min-width: auto;
96
+ }
97
+ }
98
+
99
+ &__header-right {
100
+ display: flex;
101
+ align-items: center;
102
+ gap: 16px;
103
+ flex-shrink: 0;
104
+ }
105
+
106
+ &__total {
107
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
108
+ font-size: 13px;
109
+ font-weight: 400;
110
+ line-height: 16px;
111
+ color: var(--label-secondary);
112
+ white-space: nowrap;
113
+ min-width: 72px;
114
+ text-align: right;
115
+ }
116
+
117
+ // Resource rows
118
+ &__resource {
119
+ display: flex;
120
+ align-items: center;
121
+ gap: 16px;
122
+ padding: 10px 16px 10px 32px;
123
+ border-top: 1px solid var(--border-primary);
124
+ transition: background 0.2s ease;
125
+
126
+ &--clickable {
127
+ cursor: pointer;
128
+
129
+ &:hover {
130
+ background: var(--surface-secondary);
131
+ }
132
+ }
133
+
134
+ &--mobile {
135
+ padding-left: 16px;
136
+ }
137
+ }
138
+
139
+ &__resource-name {
140
+ flex: 1;
141
+ min-width: 0;
142
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
143
+ font-size: 15px;
144
+ font-weight: 400;
145
+ line-height: 20px;
146
+ color: var(--label-primary);
147
+ }
148
+
149
+ &__resource-stats {
150
+ display: flex;
151
+ align-items: center;
152
+ gap: 32px;
153
+ flex-shrink: 0;
154
+ }
155
+
156
+ &__resource-stat {
157
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
158
+ font-size: 13px;
159
+ font-weight: 400;
160
+ line-height: 16px;
161
+ color: var(--label-secondary);
162
+ white-space: nowrap;
163
+ min-width: 72px;
164
+
165
+ &--total {
166
+ min-width: 72px;
167
+ text-align: right;
168
+ }
169
+ }
170
+
171
+ &__resource-info {
172
+ display: flex;
173
+ flex-direction: column;
174
+ flex: 1;
175
+ min-width: 0;
176
+ gap: 2px;
177
+ }
178
+
179
+ // Mobile-only compact stats line
180
+ &__resource-stats-mobile {
181
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
182
+ font-size: 12px;
183
+ font-weight: 400;
184
+ line-height: 16px;
185
+ color: var(--label-secondary);
186
+ white-space: nowrap;
187
+ }
188
+
189
+ &__resource-actions {
190
+ flex-shrink: 0;
191
+ width: 32px;
192
+ display: flex;
193
+ justify-content: flex-end;
194
+ }
195
+
196
+ // Add resource button wrapper
197
+ &__add-resource-wrapper {
198
+ padding: 12px 16px;
199
+ border-top: 1px solid var(--border-primary);
200
+ }
201
+ }
202
+
203
+ @media (max-width: 768px) {
204
+ .zone-card {
205
+ &__header {
206
+ padding: 10px 12px;
207
+ }
208
+
209
+ &__resource {
210
+ padding: 10px 12px 10px 12px;
211
+ gap: 12px;
212
+ }
213
+
214
+ &__resource-stats {
215
+ gap: 16px;
216
+ }
217
+
218
+ &__resource-stat {
219
+ min-width: auto;
220
+ }
221
+
222
+ &__add-resource-wrapper {
223
+ padding: 10px 12px;
224
+ }
225
+ }
226
+ }
@@ -0,0 +1,137 @@
1
+ import React from 'react'
2
+ import { Meta, StoryObj } from '@storybook/react'
3
+ import { ZoneCard } from './ZoneCard'
4
+ import { ZoneContainer } from './ZoneContainer'
5
+ import { ZoneHeader } from './ZoneHeader'
6
+ import { ResourceRow } from './ResourceRow'
7
+ import { AddResourceButton } from './AddResourceButton'
8
+
9
+ export default {
10
+ title: 'v2/Components/ZoneCard',
11
+ component: ZoneCard,
12
+ parameters: {
13
+ layout: 'padded',
14
+ },
15
+ } as Meta<typeof ZoneCard>
16
+
17
+ type Story = StoryObj<typeof ZoneCard>
18
+
19
+ const zoneMenuItems = [
20
+ { label: 'Edit Zone', onClick: () => alert('Edit Zone') },
21
+ { label: 'Delete Zone', onClick: () => alert('Delete Zone'), variant: 'danger' as const },
22
+ ]
23
+
24
+ const resourceMenuItems = [
25
+ { label: 'Edit Resource', onClick: () => alert('Edit Resource') },
26
+ { label: 'Delete Resource', onClick: () => alert('Delete Resource'), variant: 'danger' as const },
27
+ ]
28
+
29
+ // Composed ZoneCard (all-in-one)
30
+ export const Default: Story = {
31
+ args: {
32
+ name: 'Bowling',
33
+
34
+ totalCapacity: 2,
35
+ menuItems: zoneMenuItems,
36
+ onAddResource: () => alert('Add Resource'),
37
+ resources: [
38
+ { id: '1', name: 'Table', quantity: 1, capacity: 1, menuItems: resourceMenuItems },
39
+ { id: '2', name: 'Lane', quantity: 1, capacity: 1, menuItems: resourceMenuItems },
40
+ ],
41
+ },
42
+ }
43
+
44
+ export const EmptyZone: Story = {
45
+ args: {
46
+ name: 'VIP Lounge',
47
+ totalCapacity: 0,
48
+ menuItems: zoneMenuItems,
49
+ onAddResource: () => alert('Add Resource'),
50
+ resources: [],
51
+ },
52
+ }
53
+
54
+ // Individual components composed manually
55
+ export const ComposedManually: Story = {
56
+ render: () => (
57
+ <ZoneContainer>
58
+ <ZoneHeader
59
+ name="Bowling"
60
+ totalCapacity={2}
61
+ menuItems={zoneMenuItems}
62
+ />
63
+ <ResourceRow
64
+ name="Table"
65
+ quantity={1}
66
+ capacity={1}
67
+ menuItems={resourceMenuItems}
68
+ onClick={() => alert('Edit Table')}
69
+ />
70
+ <ResourceRow
71
+ name="Lane"
72
+ quantity={1}
73
+ capacity={1}
74
+ menuItems={resourceMenuItems}
75
+ onClick={() => alert('Edit Lane')}
76
+ />
77
+ <AddResourceButton onClick={() => alert('Add Resource')} />
78
+ </ZoneContainer>
79
+ ),
80
+ }
81
+
82
+ // Standalone ZoneHeader
83
+ export const StandaloneHeader: Story = {
84
+ render: () => (
85
+ <ZoneContainer>
86
+ <ZoneHeader
87
+ name="Main Floor"
88
+ totalCapacity={50}
89
+ menuItems={zoneMenuItems}
90
+ />
91
+ </ZoneContainer>
92
+ ),
93
+ }
94
+
95
+ // Standalone ResourceRow
96
+ export const StandaloneResource: Story = {
97
+ render: () => (
98
+ <ZoneContainer>
99
+ <ResourceRow
100
+ name="Table"
101
+ quantity={10}
102
+ capacity={4}
103
+ menuItems={resourceMenuItems}
104
+ onClick={() => alert('Edit Table')}
105
+ />
106
+ </ZoneContainer>
107
+ ),
108
+ }
109
+
110
+ // Multiple zones
111
+ export const MultipleZones: Story = {
112
+ render: () => (
113
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
114
+ <ZoneCard
115
+ name="Bowling"
116
+ status="active"
117
+ totalCapacity={2}
118
+ menuItems={zoneMenuItems}
119
+ onAddResource={() => alert('Add Resource')}
120
+ resources={[
121
+ { id: '1', name: 'Table', quantity: 1, capacity: 1, menuItems: resourceMenuItems },
122
+ { id: '2', name: 'Lane', quantity: 1, capacity: 1, menuItems: resourceMenuItems },
123
+ ]}
124
+ />
125
+ <ZoneCard
126
+ name="VIP Lounge"
127
+ status="active"
128
+ totalCapacity={20}
129
+ menuItems={zoneMenuItems}
130
+ onAddResource={() => alert('Add Resource')}
131
+ resources={[
132
+ { id: '3', name: 'Sofa', quantity: 4, capacity: 5, menuItems: resourceMenuItems },
133
+ ]}
134
+ />
135
+ </div>
136
+ ),
137
+ }
@@ -0,0 +1,69 @@
1
+ import React from 'react'
2
+ import { ActionMenuItem } from '../ActionMenu'
3
+ import { ZoneContainer } from './ZoneContainer'
4
+ import { ZoneHeader } from './ZoneHeader'
5
+ import { ResourceRow } from './ResourceRow'
6
+ import { AddResourceButton } from './AddResourceButton'
7
+ import { DragHandleProps } from './ZoneContainer'
8
+
9
+ export interface ZoneResource {
10
+ id: string
11
+ name: string
12
+ quantity: number
13
+ capacity: number
14
+ menuItems?: ActionMenuItem[]
15
+ dragHandleProps?: DragHandleProps
16
+ }
17
+
18
+ export interface ZoneCardProps {
19
+ name: string
20
+ totalCapacity: number
21
+ resources?: ZoneResource[]
22
+ menuItems?: ActionMenuItem[]
23
+ onAddResource?: () => void
24
+ className?: string
25
+ draggable?: boolean
26
+ onResourceClick?: (resource: ZoneResource) => void
27
+ dragHandleProps?: DragHandleProps
28
+ style?: React.CSSProperties
29
+ }
30
+
31
+ export const ZoneCard = React.forwardRef<HTMLDivElement, ZoneCardProps>(({
32
+ name,
33
+ totalCapacity,
34
+ resources = [],
35
+ menuItems = [],
36
+ onAddResource,
37
+ className = '',
38
+ draggable = true,
39
+ onResourceClick,
40
+ dragHandleProps,
41
+ style,
42
+ }, ref) => {
43
+ return (
44
+ <ZoneContainer ref={ref} className={className} style={style}>
45
+ <ZoneHeader
46
+ name={name}
47
+ totalCapacity={totalCapacity}
48
+ menuItems={menuItems}
49
+ draggable={draggable}
50
+ dragHandleProps={dragHandleProps}
51
+ />
52
+ {resources.map((resource) => (
53
+ <ResourceRow
54
+ key={resource.id}
55
+ name={resource.name}
56
+ quantity={resource.quantity}
57
+ capacity={resource.capacity}
58
+ menuItems={resource.menuItems}
59
+ draggable={draggable}
60
+ dragHandleProps={resource.dragHandleProps}
61
+ onClick={onResourceClick ? () => onResourceClick(resource) : undefined}
62
+ />
63
+ ))}
64
+ {onAddResource && <AddResourceButton onClick={onAddResource} />}
65
+ </ZoneContainer>
66
+ )
67
+ })
68
+
69
+ ZoneCard.displayName = 'ZoneCard'
@@ -0,0 +1,26 @@
1
+ import React from 'react'
2
+ import './ZoneCard.scss'
3
+
4
+ export interface DragHandleProps {
5
+ [key: string]: unknown
6
+ }
7
+
8
+ export interface ZoneContainerProps {
9
+ children: React.ReactNode
10
+ className?: string
11
+ style?: React.CSSProperties
12
+ }
13
+
14
+ export const ZoneContainer = React.forwardRef<HTMLDivElement, ZoneContainerProps>(({
15
+ children,
16
+ className = '',
17
+ style,
18
+ }, ref) => {
19
+ return (
20
+ <div ref={ref} className={`zone-card ${className}`} style={style}>
21
+ {children}
22
+ </div>
23
+ )
24
+ })
25
+
26
+ ZoneContainer.displayName = 'ZoneContainer'