@licklist/design 0.78.45 → 0.78.46
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.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/v2/components/PeriodCard/PeriodCard.d.ts +66 -0
- package/dist/v2/components/PeriodCard/PeriodCard.d.ts.map +1 -0
- package/dist/v2/components/PeriodCard/PeriodCard.js +351 -0
- package/dist/v2/components/PeriodCard/PeriodCard.scss.js +6 -0
- package/dist/v2/components/PeriodCard/index.d.ts +3 -0
- package/dist/v2/components/PeriodCard/index.d.ts.map +1 -0
- package/dist/v2/components/ReorderRow/ReorderRow.d.ts +24 -0
- package/dist/v2/components/ReorderRow/ReorderRow.d.ts.map +1 -0
- package/dist/v2/components/ReorderRow/ReorderRow.js +109 -0
- package/dist/v2/components/ReorderRow/ReorderRow.scss.js +6 -0
- package/dist/v2/components/ReorderRow/index.d.ts +3 -0
- package/dist/v2/components/ReorderRow/index.d.ts.map +1 -0
- package/dist/v2/components/index.d.ts +4 -0
- package/dist/v2/components/index.d.ts.map +1 -1
- package/dist/v2/index.d.ts +6 -0
- package/dist/v2/index.d.ts.map +1 -1
- package/dist/v2/pages/DeleteEntity/DeleteEntityPage.d.ts +29 -0
- package/dist/v2/pages/DeleteEntity/DeleteEntityPage.d.ts.map +1 -0
- package/dist/v2/pages/DeleteEntity/DeleteEntityPage.js +294 -0
- package/dist/v2/pages/DeleteEntity/DeleteEntityPage.scss.js +6 -0
- package/dist/v2/pages/DeleteEntity/index.d.ts +3 -0
- package/dist/v2/pages/DeleteEntity/index.d.ts.map +1 -0
- package/dist/v2/pages/Settings/components/SidebarCustomisation.js +2 -0
- package/dist/v2/pages/Settings/components/SidebarNavItem.js +2 -0
- package/dist/v2/pages/SettingsSubPage/SettingsSubPage.js +47 -0
- package/dist/v2/pages/SettingsSubPage/SettingsSubPage.scss.js +6 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/v2/components/PeriodCard/PeriodCard.scss +157 -0
- package/src/v2/components/PeriodCard/PeriodCard.stories.tsx +245 -0
- package/src/v2/components/PeriodCard/PeriodCard.tsx +350 -0
- package/src/v2/components/PeriodCard/index.ts +8 -0
- package/src/v2/components/ReorderRow/ReorderRow.scss +68 -0
- package/src/v2/components/ReorderRow/ReorderRow.stories.tsx +124 -0
- package/src/v2/components/ReorderRow/ReorderRow.tsx +88 -0
- package/src/v2/components/ReorderRow/index.ts +2 -0
- package/src/v2/components/index.ts +6 -0
- package/src/v2/index.ts +13 -0
- package/src/v2/pages/DeleteEntity/DeleteEntityPage.scss +96 -0
- package/src/v2/pages/DeleteEntity/DeleteEntityPage.stories.tsx +83 -0
- package/src/v2/pages/DeleteEntity/DeleteEntityPage.tsx +120 -0
- package/src/v2/pages/DeleteEntity/index.ts +2 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/react'
|
|
3
|
+
import { ReorderRow } from './ReorderRow'
|
|
4
|
+
import { Badge } from '../Badge'
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'v2/Components/ReorderRow',
|
|
8
|
+
component: ReorderRow,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'padded',
|
|
11
|
+
},
|
|
12
|
+
} as Meta<typeof ReorderRow>
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof ReorderRow>
|
|
15
|
+
|
|
16
|
+
export const Default: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
label: 'Test Zone',
|
|
19
|
+
subtitle: '0 resources · Total capacity: 0',
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const WithSubtitle: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
label: 'Bowling Alley',
|
|
26
|
+
subtitle: '3 resources · Total capacity: 12',
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const WithoutSubtitle: Story = {
|
|
31
|
+
args: {
|
|
32
|
+
label: 'VIP Lounge',
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const NoDragHandle: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
label: 'Static Row',
|
|
39
|
+
subtitle: 'No drag handle shown',
|
|
40
|
+
hideDragHandle: true,
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const Clickable: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
label: 'Click me',
|
|
47
|
+
subtitle: 'Has hover state',
|
|
48
|
+
onClick: () => alert('Clicked!'),
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const MultipleRows: Story = {
|
|
53
|
+
render: () => (
|
|
54
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px', maxWidth: 500 }}>
|
|
55
|
+
<ReorderRow
|
|
56
|
+
label="Main Floor"
|
|
57
|
+
subtitle="5 resources · Total capacity: 20"
|
|
58
|
+
/>
|
|
59
|
+
<ReorderRow
|
|
60
|
+
label="VIP Lounge"
|
|
61
|
+
subtitle="2 resources · Total capacity: 8"
|
|
62
|
+
/>
|
|
63
|
+
<ReorderRow
|
|
64
|
+
label="Outdoor Area"
|
|
65
|
+
subtitle="3 resources · Total capacity: 15"
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const ColorDot = ({ color }: { color: string }) => (
|
|
72
|
+
<span
|
|
73
|
+
style={{
|
|
74
|
+
width: 12,
|
|
75
|
+
height: 12,
|
|
76
|
+
borderRadius: '50%',
|
|
77
|
+
backgroundColor: color,
|
|
78
|
+
display: 'inline-block',
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
export const PriorityReorder: Story = {
|
|
84
|
+
render: () => (
|
|
85
|
+
<div style={{ maxWidth: 500 }}>
|
|
86
|
+
<div style={{ marginBottom: 16 }}>
|
|
87
|
+
<h3 style={{ margin: '0 0 4px', fontSize: 16, fontWeight: 600, color: '#121e52' }}>
|
|
88
|
+
Set a new priority order for your pricing periods
|
|
89
|
+
</h3>
|
|
90
|
+
<p style={{ margin: 0, fontSize: 13, color: '#6b7a99' }}>
|
|
91
|
+
Update the priority order of your pricing periods. The first period in the list has the highest priority and will take precedence when multiple periods overlap.
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
95
|
+
<ReorderRow
|
|
96
|
+
label="Peak"
|
|
97
|
+
subtitle="Peak Period"
|
|
98
|
+
leftContent={<ColorDot color="#ef4444" />}
|
|
99
|
+
rightContent={<Badge variant="neutral">Priority 1</Badge>}
|
|
100
|
+
/>
|
|
101
|
+
<ReorderRow
|
|
102
|
+
label="Xmas"
|
|
103
|
+
leftContent={<ColorDot color="#f97316" />}
|
|
104
|
+
rightContent={<Badge variant="neutral">Priority 2</Badge>}
|
|
105
|
+
/>
|
|
106
|
+
<ReorderRow
|
|
107
|
+
label="Off Peak"
|
|
108
|
+
subtitle="This is for when we're not busy."
|
|
109
|
+
leftContent={<ColorDot color="#3b82f6" />}
|
|
110
|
+
rightContent={<Badge variant="neutral">Priority 3</Badge>}
|
|
111
|
+
/>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
),
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const WithLeftAndRightContent: Story = {
|
|
118
|
+
args: {
|
|
119
|
+
label: 'Peak',
|
|
120
|
+
subtitle: 'Peak Period',
|
|
121
|
+
leftContent: <ColorDot color="#ef4444" />,
|
|
122
|
+
rightContent: <Badge variant="neutral">Priority 1</Badge>,
|
|
123
|
+
},
|
|
124
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React, { HTMLAttributes } from 'react'
|
|
2
|
+
import { GripVerticalIcon } from '../../icons'
|
|
3
|
+
import './ReorderRow.scss'
|
|
4
|
+
|
|
5
|
+
export interface DragHandleRenderProps {
|
|
6
|
+
/** Spread onto the drag handle element for dnd-kit or similar */
|
|
7
|
+
attributes?: HTMLAttributes<HTMLElement>
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
9
|
+
listeners?: Record<string, Function> | undefined
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ReorderRowProps {
|
|
13
|
+
label: string
|
|
14
|
+
subtitle?: string
|
|
15
|
+
/** Render prop for the drag handle — receives attributes/listeners to spread */
|
|
16
|
+
dragHandleProps?: DragHandleRenderProps
|
|
17
|
+
/** Hide the drag handle (e.g. when not in reorder mode) */
|
|
18
|
+
hideDragHandle?: boolean
|
|
19
|
+
/** Content between the drag handle and label (e.g. color dot, icon) */
|
|
20
|
+
leftContent?: React.ReactNode
|
|
21
|
+
/** Right-side content (e.g. action menu, capacity badge) */
|
|
22
|
+
rightContent?: React.ReactNode
|
|
23
|
+
onClick?: () => void
|
|
24
|
+
className?: string
|
|
25
|
+
style?: React.CSSProperties
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const ReorderRow = React.forwardRef<HTMLDivElement, ReorderRowProps>(
|
|
29
|
+
(
|
|
30
|
+
{
|
|
31
|
+
label,
|
|
32
|
+
subtitle,
|
|
33
|
+
dragHandleProps,
|
|
34
|
+
hideDragHandle = false,
|
|
35
|
+
leftContent,
|
|
36
|
+
rightContent,
|
|
37
|
+
onClick,
|
|
38
|
+
className = '',
|
|
39
|
+
style,
|
|
40
|
+
},
|
|
41
|
+
ref,
|
|
42
|
+
) => {
|
|
43
|
+
const handleKeyDown = onClick
|
|
44
|
+
? (e: React.KeyboardEvent) => {
|
|
45
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
46
|
+
e.preventDefault()
|
|
47
|
+
onClick()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
: undefined
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
ref={ref}
|
|
55
|
+
style={style}
|
|
56
|
+
className={`reorder-row ${onClick ? 'reorder-row--clickable' : ''} ${className}`}
|
|
57
|
+
onClick={onClick}
|
|
58
|
+
onKeyDown={handleKeyDown}
|
|
59
|
+
role={onClick ? 'button' : undefined}
|
|
60
|
+
tabIndex={onClick ? 0 : undefined}
|
|
61
|
+
>
|
|
62
|
+
{!hideDragHandle && (
|
|
63
|
+
<div
|
|
64
|
+
className="reorder-row__drag-handle"
|
|
65
|
+
{...dragHandleProps?.attributes}
|
|
66
|
+
{...dragHandleProps?.listeners}
|
|
67
|
+
>
|
|
68
|
+
{GripVerticalIcon({ width: 20, height: 20 })}
|
|
69
|
+
</div>
|
|
70
|
+
)}
|
|
71
|
+
{leftContent && (
|
|
72
|
+
<div className="reorder-row__left">{leftContent}</div>
|
|
73
|
+
)}
|
|
74
|
+
<div className="reorder-row__content">
|
|
75
|
+
<span className="reorder-row__label">{label}</span>
|
|
76
|
+
{subtitle && (
|
|
77
|
+
<span className="reorder-row__subtitle">{subtitle}</span>
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
{rightContent && (
|
|
81
|
+
<div className="reorder-row__right">{rightContent}</div>
|
|
82
|
+
)}
|
|
83
|
+
</div>
|
|
84
|
+
)
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
ReorderRow.displayName = 'ReorderRow'
|
|
@@ -68,6 +68,12 @@ export type { PaginationProps } from './Pagination'
|
|
|
68
68
|
export { ZoneCard, ZoneContainer, ZoneHeader, ResourceRow, AddResourceButton } from './ZoneCard'
|
|
69
69
|
export type { ZoneCardProps, ZoneResource, ZoneContainerProps, DragHandleProps, ZoneHeaderProps, ResourceRowProps, AddResourceButtonProps } from './ZoneCard'
|
|
70
70
|
|
|
71
|
+
export { PeriodCard, PeriodCardSection, PeriodCardTimeRange } from './PeriodCard'
|
|
72
|
+
|
|
73
|
+
export { ReorderRow } from './ReorderRow'
|
|
74
|
+
export type { ReorderRowProps, DragHandleRenderProps } from './ReorderRow'
|
|
75
|
+
export type { PeriodCardProps, PeriodCardValue, PeriodCardLabels, PeriodCardSectionProps, PeriodCardTimeRangeProps } from './PeriodCard'
|
|
76
|
+
|
|
71
77
|
// Icons
|
|
72
78
|
export {
|
|
73
79
|
InfoIcon,
|
package/src/v2/index.ts
CHANGED
|
@@ -53,6 +53,19 @@ export type { UserPanelProps } from './components/UserPanel'
|
|
|
53
53
|
export { ZoneCard, ZoneContainer, ZoneHeader, ResourceRow, AddResourceButton } from './components/ZoneCard'
|
|
54
54
|
export type { ZoneCardProps, ZoneResource, ZoneContainerProps, DragHandleProps, ZoneHeaderProps, ResourceRowProps, ResourceRowLabels, AddResourceButtonProps } from './components/ZoneCard'
|
|
55
55
|
|
|
56
|
+
// SettingsSubPage (generic settings sub-page layout)
|
|
57
|
+
export { SettingsSubPage } from './pages/SettingsSubPage'
|
|
58
|
+
export type { SettingsSubPageProps } from './pages/SettingsSubPage'
|
|
59
|
+
|
|
60
|
+
// ZonesResources Page (deprecated — use SettingsSubPage)
|
|
61
|
+
// PeriodCard Component
|
|
62
|
+
export { PeriodCard, PeriodCardSection, PeriodCardTimeRange } from './components/PeriodCard'
|
|
63
|
+
export type { PeriodCardProps, PeriodCardValue, PeriodCardLabels, PeriodCardSectionProps, PeriodCardTimeRangeProps } from './components/PeriodCard'
|
|
64
|
+
|
|
65
|
+
// ReorderRow Component
|
|
66
|
+
export { ReorderRow } from './components/ReorderRow'
|
|
67
|
+
export type { ReorderRowProps, DragHandleRenderProps } from './components/ReorderRow'
|
|
68
|
+
|
|
56
69
|
// ZonesResources Page
|
|
57
70
|
export { ZonesResourcesPage } from './pages/ZonesResources'
|
|
58
71
|
export type { ZonesResourcesPageProps } from './pages/ZonesResources'
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
.delete-entity-page {
|
|
2
|
+
padding: 0;
|
|
3
|
+
|
|
4
|
+
&__content {
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
align-items: center;
|
|
8
|
+
padding: 48px 32px;
|
|
9
|
+
|
|
10
|
+
@media (max-width: 768px) {
|
|
11
|
+
padding: 24px 16px;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&__inner {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: 24px;
|
|
19
|
+
width: 100%;
|
|
20
|
+
max-width: 672px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&__entity-name {
|
|
24
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
25
|
+
font-size: 20px;
|
|
26
|
+
font-weight: 600;
|
|
27
|
+
line-height: 28px;
|
|
28
|
+
color: var(--label-primary, #121e52);
|
|
29
|
+
margin: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&__warning-card {
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: 16px;
|
|
36
|
+
padding: 24px;
|
|
37
|
+
background: var(--surface-secondary, #f8f8fa);
|
|
38
|
+
border: 1px solid var(--border-primary, #e8e9ef);
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&__warning-text {
|
|
43
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
44
|
+
font-size: 14px;
|
|
45
|
+
font-weight: 600;
|
|
46
|
+
color: var(--label-status-error, #ef4444);
|
|
47
|
+
margin: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&__warning-description {
|
|
51
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
52
|
+
font-size: 14px;
|
|
53
|
+
color: var(--label-secondary, #626a90);
|
|
54
|
+
margin: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&__consequences {
|
|
58
|
+
list-style: disc;
|
|
59
|
+
padding-left: 20px;
|
|
60
|
+
margin: 0;
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
gap: 4px;
|
|
64
|
+
|
|
65
|
+
li {
|
|
66
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
67
|
+
font-size: 14px;
|
|
68
|
+
color: var(--label-secondary, #626a90);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&__confirm-field {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-direction: column;
|
|
75
|
+
gap: var(--spacing-xs, 2px);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&__confirm-label {
|
|
79
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
80
|
+
font-size: 14px;
|
|
81
|
+
font-weight: 500;
|
|
82
|
+
line-height: 20px;
|
|
83
|
+
color: var(--label-primary, #121e52);
|
|
84
|
+
margin: 0;
|
|
85
|
+
|
|
86
|
+
strong {
|
|
87
|
+
font-weight: 700;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&__confirm-error {
|
|
92
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
93
|
+
font-size: 11px;
|
|
94
|
+
color: var(--label-status-error, #ef4444);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
3
|
+
import { DeleteEntityPage } from './DeleteEntityPage'
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof DeleteEntityPage> = {
|
|
6
|
+
title: 'v2/Pages/DeleteEntity',
|
|
7
|
+
component: DeleteEntityPage,
|
|
8
|
+
parameters: { layout: 'fullscreen' },
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default meta
|
|
12
|
+
type Story = StoryObj<typeof DeleteEntityPage>
|
|
13
|
+
|
|
14
|
+
const baseArgs = {
|
|
15
|
+
confirmWord: 'DELETE',
|
|
16
|
+
warningTitle: 'This action cannot be undone',
|
|
17
|
+
confirmLabelPrefix: 'Type',
|
|
18
|
+
confirmLabelSuffix: 'to confirm deletion',
|
|
19
|
+
confirmErrorMessage: 'Please type DELETE to confirm.',
|
|
20
|
+
isDeleting: false,
|
|
21
|
+
onDelete: () => console.log('Delete confirmed'),
|
|
22
|
+
onCancel: () => console.log('Cancel'),
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* **Delete Zone** — confirmation page for deleting a zone.
|
|
27
|
+
*
|
|
28
|
+
* Lists the consequences of the action and requires the user to type
|
|
29
|
+
* the confirmation word before the destructive button is enabled.
|
|
30
|
+
*/
|
|
31
|
+
export const DeleteZone: Story = {
|
|
32
|
+
name: 'Delete Zone',
|
|
33
|
+
args: {
|
|
34
|
+
...baseArgs,
|
|
35
|
+
title: 'Delete Zone',
|
|
36
|
+
entityName: 'Main Hall',
|
|
37
|
+
deleteButtonLabel: 'Delete Zone',
|
|
38
|
+
warningDescription:
|
|
39
|
+
'You are about to permanently delete the zone "Main Hall". This will:',
|
|
40
|
+
consequences: [
|
|
41
|
+
'Remove the zone from your venue layout',
|
|
42
|
+
'Delete all resources assigned to this zone',
|
|
43
|
+
'Cancel any future bookings linked to this zone',
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* **Delete Special Hours** — confirmation page for removing a special hours schedule.
|
|
50
|
+
*/
|
|
51
|
+
export const DeleteSpecialHours: Story = {
|
|
52
|
+
name: 'Delete Special Hours',
|
|
53
|
+
args: {
|
|
54
|
+
...baseArgs,
|
|
55
|
+
title: 'Delete Special Hours',
|
|
56
|
+
entityName: 'Christmas Closure',
|
|
57
|
+
deleteButtonLabel: 'Delete Schedule',
|
|
58
|
+
warningDescription:
|
|
59
|
+
'You are about to permanently delete the special hours schedule "Christmas Closure". This will:',
|
|
60
|
+
consequences: [
|
|
61
|
+
'Remove all date-specific overrides from this schedule',
|
|
62
|
+
'Restore your default opening hours for the affected dates',
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* **Deleting** — destructive button shown in its loading state while the
|
|
69
|
+
* delete request is in flight.
|
|
70
|
+
*/
|
|
71
|
+
export const Deleting: Story = {
|
|
72
|
+
name: 'Deleting',
|
|
73
|
+
args: {
|
|
74
|
+
...baseArgs,
|
|
75
|
+
title: 'Delete Zone',
|
|
76
|
+
entityName: 'Main Hall',
|
|
77
|
+
deleteButtonLabel: 'Delete Zone',
|
|
78
|
+
warningDescription:
|
|
79
|
+
'You are about to permanently delete the zone "Main Hall". This will:',
|
|
80
|
+
consequences: ['Remove the zone from your venue layout'],
|
|
81
|
+
isDeleting: true,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { NewPageHeader } from '../../components/NewPageHeader'
|
|
3
|
+
import { Button } from '../../components/Button/Button'
|
|
4
|
+
import { NewInput } from '../../components/NewInput/NewInput'
|
|
5
|
+
import './DeleteEntityPage.scss'
|
|
6
|
+
|
|
7
|
+
export interface DeleteEntityPageProps {
|
|
8
|
+
/** Page title shown in the header (e.g. "Delete Zone") */
|
|
9
|
+
title: string
|
|
10
|
+
/** Name of the entity being deleted, displayed prominently */
|
|
11
|
+
entityName: string
|
|
12
|
+
/** Bullet list of consequences shown inside the warning card */
|
|
13
|
+
consequences: string[]
|
|
14
|
+
/** Label for the destructive action button */
|
|
15
|
+
deleteButtonLabel: string
|
|
16
|
+
/** Whether the delete request is in flight */
|
|
17
|
+
isDeleting: boolean
|
|
18
|
+
/** Word the user must type to confirm deletion (e.g. "DELETE") */
|
|
19
|
+
confirmWord: string
|
|
20
|
+
/** Heading inside the warning card (e.g. "This action cannot be undone") */
|
|
21
|
+
warningTitle: string
|
|
22
|
+
/** Description below the warning title */
|
|
23
|
+
warningDescription: string
|
|
24
|
+
/** Label above the confirmation input — `confirmWord` is rendered as <strong> */
|
|
25
|
+
confirmLabelPrefix: string
|
|
26
|
+
confirmLabelSuffix: string
|
|
27
|
+
/** Error message shown when the typed value does not match `confirmWord` */
|
|
28
|
+
confirmErrorMessage: string
|
|
29
|
+
onDelete: () => void | Promise<void>
|
|
30
|
+
onCancel: () => void
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function DeleteEntityPage({
|
|
34
|
+
title,
|
|
35
|
+
entityName,
|
|
36
|
+
consequences,
|
|
37
|
+
deleteButtonLabel,
|
|
38
|
+
isDeleting,
|
|
39
|
+
confirmWord,
|
|
40
|
+
warningTitle,
|
|
41
|
+
warningDescription,
|
|
42
|
+
confirmLabelPrefix,
|
|
43
|
+
confirmLabelSuffix,
|
|
44
|
+
confirmErrorMessage,
|
|
45
|
+
onDelete,
|
|
46
|
+
onCancel,
|
|
47
|
+
}: DeleteEntityPageProps) {
|
|
48
|
+
const [confirmationInput, setConfirmationInput] = useState('')
|
|
49
|
+
const [confirmationError, setConfirmationError] = useState(false)
|
|
50
|
+
|
|
51
|
+
const handleDelete = async () => {
|
|
52
|
+
if (confirmationInput.toLowerCase() !== confirmWord.toLowerCase()) {
|
|
53
|
+
setConfirmationError(true)
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await onDelete()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div className="delete-entity-page">
|
|
62
|
+
<NewPageHeader title={title} onCancel={onCancel} />
|
|
63
|
+
<div className="delete-entity-page__content">
|
|
64
|
+
<div className="delete-entity-page__inner">
|
|
65
|
+
<h2 className="delete-entity-page__entity-name">{entityName}</h2>
|
|
66
|
+
|
|
67
|
+
<div className="delete-entity-page__warning-card">
|
|
68
|
+
<p className="delete-entity-page__warning-text">{warningTitle}</p>
|
|
69
|
+
<p className="delete-entity-page__warning-description">
|
|
70
|
+
{warningDescription}
|
|
71
|
+
</p>
|
|
72
|
+
<ul className="delete-entity-page__consequences">
|
|
73
|
+
{consequences.map((item, i) => (
|
|
74
|
+
<li key={i}>{item}</li>
|
|
75
|
+
))}
|
|
76
|
+
</ul>
|
|
77
|
+
|
|
78
|
+
<div className="delete-entity-page__confirm-field">
|
|
79
|
+
<p className="delete-entity-page__confirm-label">
|
|
80
|
+
{confirmLabelPrefix} <strong>{confirmWord}</strong>{' '}
|
|
81
|
+
{confirmLabelSuffix}
|
|
82
|
+
</p>
|
|
83
|
+
{confirmationError && (
|
|
84
|
+
<span className="delete-entity-page__confirm-error">
|
|
85
|
+
{confirmErrorMessage}
|
|
86
|
+
</span>
|
|
87
|
+
)}
|
|
88
|
+
<NewInput
|
|
89
|
+
value={confirmationInput}
|
|
90
|
+
onChange={(e) => {
|
|
91
|
+
setConfirmationInput(
|
|
92
|
+
(e.target as HTMLInputElement).value,
|
|
93
|
+
)
|
|
94
|
+
setConfirmationError(false)
|
|
95
|
+
}}
|
|
96
|
+
error={confirmationError ? ' ' : undefined}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div>
|
|
102
|
+
<Button
|
|
103
|
+
variant="destructive-strong"
|
|
104
|
+
onClick={handleDelete}
|
|
105
|
+
disabled={isDeleting}
|
|
106
|
+
isLoading={isDeleting}
|
|
107
|
+
style={{
|
|
108
|
+
background: 'var(--fills-main-fill-danger, #cc3c35)',
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
{deleteButtonLabel}
|
|
112
|
+
</Button>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export default DeleteEntityPage
|