@licklist/design 0.78.5-dev.49 → 0.78.5-dev.50

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 (135) hide show
  1. package/dist/index.js +11 -1
  2. package/dist/v2/components/ActionMenu/ActionMenu.d.ts +13 -0
  3. package/dist/v2/components/ActionMenu/ActionMenu.d.ts.map +1 -0
  4. package/dist/v2/components/ActionMenu/ActionMenu.js +100 -0
  5. package/dist/v2/components/ActionMenu/ActionMenu.scss.js +6 -0
  6. package/dist/v2/components/ActionMenu/index.d.ts +2 -0
  7. package/dist/v2/components/ActionMenu/index.d.ts.map +1 -0
  8. package/dist/v2/components/Alert/Alert.scss.js +1 -1
  9. package/dist/v2/components/Badge/Badge.d.ts +10 -0
  10. package/dist/v2/components/Badge/Badge.d.ts.map +1 -0
  11. package/dist/v2/components/Badge/Badge.js +19 -0
  12. package/dist/v2/components/Badge/Badge.scss.js +6 -0
  13. package/dist/v2/components/Badge/index.d.ts +2 -0
  14. package/dist/v2/components/Badge/index.d.ts.map +1 -0
  15. package/dist/v2/components/Checkbox/Checkbox.scss.js +1 -1
  16. package/dist/v2/components/Customer/CustomerCreate/CustomerCreate.d.ts +11 -0
  17. package/dist/v2/components/Customer/CustomerCreate/CustomerCreate.d.ts.map +1 -0
  18. package/dist/v2/components/Customer/CustomerCreate/CustomerCreate.js +32 -0
  19. package/dist/v2/components/Customer/CustomerCreate/index.d.ts +2 -0
  20. package/dist/v2/components/Customer/CustomerCreate/index.d.ts.map +1 -0
  21. package/dist/v2/components/Customer/CustomerDetail/CustomerDetail.d.ts +35 -0
  22. package/dist/v2/components/Customer/CustomerDetail/CustomerDetail.d.ts.map +1 -0
  23. package/dist/v2/components/Customer/CustomerDetail/CustomerDetail.js +235 -0
  24. package/dist/v2/components/Customer/CustomerDetail/CustomerDetail.scss.js +6 -0
  25. package/dist/v2/components/Customer/CustomerDetail/index.d.ts +2 -0
  26. package/dist/v2/components/Customer/CustomerDetail/index.d.ts.map +1 -0
  27. package/dist/v2/components/Customer/CustomerEdit/CustomerEdit.d.ts +11 -0
  28. package/dist/v2/components/Customer/CustomerEdit/CustomerEdit.d.ts.map +1 -0
  29. package/dist/v2/components/Customer/CustomerEdit/CustomerEdit.js +32 -0
  30. package/dist/v2/components/Customer/CustomerEdit/index.d.ts +2 -0
  31. package/dist/v2/components/Customer/CustomerEdit/index.d.ts.map +1 -0
  32. package/dist/v2/components/Customer/CustomerForm/CustomerForm.d.ts +22 -0
  33. package/dist/v2/components/Customer/CustomerForm/CustomerForm.d.ts.map +1 -0
  34. package/dist/v2/components/Customer/CustomerForm/CustomerForm.js +535 -0
  35. package/dist/v2/components/Customer/CustomerForm/index.d.ts +2 -0
  36. package/dist/v2/components/Customer/CustomerForm/index.d.ts.map +1 -0
  37. package/dist/v2/components/Customer/CustomersList.d.ts +37 -0
  38. package/dist/v2/components/Customer/CustomersList.d.ts.map +1 -0
  39. package/dist/v2/components/Customer/CustomersList.js +204 -0
  40. package/dist/v2/components/Customer/CustomersList.scss.js +6 -0
  41. package/dist/v2/components/Customer/index.d.ts +6 -0
  42. package/dist/v2/components/Customer/index.d.ts.map +1 -0
  43. package/dist/v2/components/FormField/FormField.scss.js +1 -1
  44. package/dist/v2/components/Modal/DeleteModal.d.ts +15 -0
  45. package/dist/v2/components/Modal/DeleteModal.d.ts.map +1 -0
  46. package/dist/v2/components/Modal/DeleteModal.js +147 -0
  47. package/dist/v2/components/Modal/DeleteModal.scss.js +6 -0
  48. package/dist/v2/components/Modal/index.d.ts +3 -0
  49. package/dist/v2/components/Modal/index.d.ts.map +1 -0
  50. package/dist/v2/components/NewInput/NewInput.d.ts +2 -0
  51. package/dist/v2/components/NewInput/NewInput.d.ts.map +1 -1
  52. package/dist/v2/components/NewInput/NewInput.js +29 -12
  53. package/dist/v2/components/NewPageHeader/NewPageHeader.d.ts +1 -0
  54. package/dist/v2/components/NewPageHeader/NewPageHeader.d.ts.map +1 -1
  55. package/dist/v2/components/NewPageHeader/NewPageHeader.js +15 -9
  56. package/dist/v2/components/NewPageHeader/NewPageHeader.scss.js +1 -1
  57. package/dist/v2/components/NewTable/NewTable.d.ts +20 -0
  58. package/dist/v2/components/NewTable/NewTable.d.ts.map +1 -0
  59. package/dist/v2/components/NewTable/NewTable.js +57 -0
  60. package/dist/v2/components/NewTable/NewTable.scss.js +6 -0
  61. package/dist/v2/components/NewTable/index.d.ts +2 -0
  62. package/dist/v2/components/NewTable/index.d.ts.map +1 -0
  63. package/dist/v2/components/Pagination/Pagination.d.ts +13 -0
  64. package/dist/v2/components/Pagination/Pagination.d.ts.map +1 -0
  65. package/dist/v2/components/Pagination/Pagination.js +79 -0
  66. package/dist/v2/components/Pagination/Pagination.scss.js +6 -0
  67. package/dist/v2/components/Pagination/index.d.ts +2 -0
  68. package/dist/v2/components/Pagination/index.d.ts.map +1 -0
  69. package/dist/v2/components/QuickFilter/QuickFilter.d.ts +14 -0
  70. package/dist/v2/components/QuickFilter/QuickFilter.d.ts.map +1 -0
  71. package/dist/v2/components/QuickFilter/QuickFilter.js +67 -0
  72. package/dist/v2/components/QuickFilter/QuickFilter.scss.js +6 -0
  73. package/dist/v2/components/QuickFilter/index.d.ts +2 -0
  74. package/dist/v2/components/QuickFilter/index.d.ts.map +1 -0
  75. package/dist/v2/components/Select/Select.d.ts +7 -4
  76. package/dist/v2/components/Select/Select.d.ts.map +1 -1
  77. package/dist/v2/components/Select/Select.js +53 -24
  78. package/dist/v2/components/Select/Select.scss.js +1 -1
  79. package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.scss.js +1 -1
  80. package/dist/v2/components/index.d.ts +18 -0
  81. package/dist/v2/components/index.d.ts.map +1 -1
  82. package/dist/v2/icons/index.d.ts +21 -0
  83. package/dist/v2/icons/index.d.ts.map +1 -1
  84. package/dist/v2/icons/index.js +155 -4
  85. package/dist/v2/navigation/DashboardLayout/ProviderSidebar.d.ts.map +1 -1
  86. package/dist/v2/navigation/DashboardLayout/ProviderSidebar.js +4 -8
  87. package/dist/v2/styles/common.scss +7 -0
  88. package/dist/v2/styles/form/NewInput.scss +45 -21
  89. package/dist/v2/styles/form/NewInput.scss.js +1 -1
  90. package/dist/v2/styles/index.scss +1 -0
  91. package/package.json +3 -3
  92. package/src/v2/components/ActionMenu/ActionMenu.scss +78 -0
  93. package/src/v2/components/ActionMenu/ActionMenu.tsx +64 -0
  94. package/src/v2/components/ActionMenu/index.ts +1 -0
  95. package/src/v2/components/Badge/Badge.scss +69 -0
  96. package/src/v2/components/Badge/Badge.tsx +23 -0
  97. package/src/v2/components/Badge/index.ts +1 -0
  98. package/src/v2/components/Customer/CustomerCreate/CustomerCreate.tsx +36 -0
  99. package/src/v2/components/Customer/CustomerCreate/index.ts +1 -0
  100. package/src/v2/components/Customer/CustomerDetail/CustomerDetail.scss +315 -0
  101. package/src/v2/components/Customer/CustomerDetail/CustomerDetail.tsx +161 -0
  102. package/src/v2/components/Customer/CustomerDetail/index.ts +1 -0
  103. package/src/v2/components/Customer/CustomerEdit/CustomerEdit.tsx +37 -0
  104. package/src/v2/components/Customer/CustomerEdit/index.ts +1 -0
  105. package/src/v2/components/Customer/CustomerForm/CustomerForm.tsx +434 -0
  106. package/src/v2/components/Customer/CustomerForm/index.ts +1 -0
  107. package/src/v2/components/Customer/CustomersList.scss +586 -0
  108. package/src/v2/components/Customer/CustomersList.tsx +193 -0
  109. package/src/v2/components/Customer/index.ts +5 -0
  110. package/src/v2/components/Modal/DeleteModal.scss +254 -0
  111. package/src/v2/components/Modal/DeleteModal.tsx +100 -0
  112. package/src/v2/components/Modal/index.ts +3 -0
  113. package/src/v2/components/NewInput/NewInput.stories.tsx +3 -18
  114. package/src/v2/components/NewInput/NewInput.tsx +23 -12
  115. package/src/v2/components/NewPageHeader/NewPageHeader.scss +13 -7
  116. package/src/v2/components/NewPageHeader/NewPageHeader.tsx +14 -9
  117. package/src/v2/components/NewTable/NewTable.scss +110 -0
  118. package/src/v2/components/NewTable/NewTable.tsx +85 -0
  119. package/src/v2/components/NewTable/index.ts +1 -0
  120. package/src/v2/components/Pagination/Pagination.scss +142 -0
  121. package/src/v2/components/Pagination/Pagination.tsx +80 -0
  122. package/src/v2/components/Pagination/index.ts +1 -0
  123. package/src/v2/components/QuickFilter/QuickFilter.scss +84 -0
  124. package/src/v2/components/QuickFilter/QuickFilter.tsx +49 -0
  125. package/src/v2/components/QuickFilter/index.ts +1 -0
  126. package/src/v2/components/Select/Select.scss +61 -24
  127. package/src/v2/components/Select/Select.stories.tsx +77 -1
  128. package/src/v2/components/Select/Select.tsx +63 -34
  129. package/src/v2/components/index.ts +28 -0
  130. package/src/v2/icons/index.tsx +79 -2
  131. package/src/v2/navigation/DashboardLayout/ProviderSidebar.tsx +3 -1
  132. package/src/v2/navigation/config.tsx +1 -1
  133. package/src/v2/styles/common.scss +7 -0
  134. package/src/v2/styles/form/NewInput.scss +45 -21
  135. package/src/v2/styles/index.scss +1 -0
@@ -0,0 +1,193 @@
1
+ import React from 'react'
2
+ import { QuickFilter, QuickFilterOption } from '../QuickFilter'
3
+ import { NewTable, NewTableColumn } from '../NewTable'
4
+ import { NewInput } from '../NewInput'
5
+ import { Pagination } from '../Pagination'
6
+ import { SearchIcon, RefreshIcon, SendIcon, ExternalLinkIcon, ExportIcon, ClearIcon } from '../../icons'
7
+ import './CustomersList.scss'
8
+
9
+ export interface CustomersListProps {
10
+ t: (key: string, options?: any) => string
11
+ customers: any[]
12
+ isLoading: boolean
13
+ kioskLink?: string
14
+ waiversEnabled?: boolean
15
+ search: string
16
+ onSearchChange: (value: string) => void
17
+ onSearchIconClick?: () => void
18
+ onClearSearch?: () => void
19
+ quickFilters: string[]
20
+ onQuickFiltersChange: (values: string[]) => void
21
+ onRefresh: () => void
22
+ onExport: () => void
23
+ onSendWaiverRequest: () => void
24
+ onAddCustomer?: () => void
25
+ onTabChange?: (tabId: string) => void
26
+ activeTab?: string
27
+ tabs?: { id: string; label: string; path: string }[]
28
+ columns: NewTableColumn<any>[]
29
+ pagination?: {
30
+ currentPage: number
31
+ totalPages: number
32
+ onPageChange: (page: number) => void
33
+ totalItems?: number
34
+ itemsPerPage?: number
35
+ }
36
+ }
37
+
38
+
39
+ export const CustomersList: React.FC<CustomersListProps> = ({
40
+ t,
41
+ customers,
42
+ isLoading,
43
+ kioskLink,
44
+ search,
45
+ onSearchChange,
46
+ quickFilters,
47
+ onSearchIconClick,
48
+ onClearSearch,
49
+ onQuickFiltersChange,
50
+ onRefresh,
51
+ onExport,
52
+ onSendWaiverRequest,
53
+ onTabChange,
54
+ activeTab,
55
+ tabs,
56
+ columns,
57
+ pagination,
58
+ waiversEnabled,
59
+ onAddCustomer,
60
+ }) => {
61
+ const quickFilterOptions: QuickFilterOption[] = waiversEnabled ? [
62
+ { label: t('App:todayBookings'), value: 'today' },
63
+ { label: t('App:signed', 'Signed'), value: 'signed' },
64
+ { label: t('App:unsigned', 'Unsigned'), value: 'unsigned' },
65
+ ] : [
66
+ { label: t('App:todayBookings', 'Bookings for: Today'), value: 'today' },
67
+ ]
68
+
69
+ // Handle mutually exclusive signed/unsigned filters
70
+ const handleQuickFiltersChange = (newFilters: string[]) => {
71
+ const hasSigned = newFilters.includes('signed')
72
+ const hasUnsigned = newFilters.includes('unsigned')
73
+ const hadSigned = quickFilters.includes('signed')
74
+ const hadUnsigned = quickFilters.includes('unsigned')
75
+
76
+ // If both signed and unsigned are being selected, keep only the newly selected one
77
+ if (hasSigned && hasUnsigned) {
78
+ if (!hadSigned && hasUnsigned) {
79
+ // signed was just added, remove unsigned
80
+ onQuickFiltersChange(newFilters.filter(f => f !== 'unsigned'))
81
+ } else if (hasSigned && !hadUnsigned) {
82
+ // unsigned was just added, remove signed
83
+ onQuickFiltersChange(newFilters.filter(f => f !== 'signed'))
84
+ }
85
+ } else {
86
+ onQuickFiltersChange(newFilters)
87
+ }
88
+ }
89
+
90
+ return (
91
+ <div className="waivers-page">
92
+ <header className="waivers-page__header">
93
+ {tabs && tabs.length > 0 ? (
94
+ <div className="waivers-page__tabs-container">
95
+ <nav className="waivers-page__tabs">
96
+ {tabs.map((tab) => (
97
+ <button
98
+ key={tab.id}
99
+ className={`waivers-page__tab ${tab.id === activeTab ? 'waivers-page__tab--active' : ''}`}
100
+ onClick={() => onTabChange?.(tab.id)}
101
+ >
102
+ {tab.label}
103
+ {tab.id === activeTab && <div className="waivers-page__tab-indicator" />}
104
+ </button>
105
+ ))}
106
+ </nav>
107
+ {kioskLink && (
108
+ <a href={kioskLink} target="_blank" rel="noopener noreferrer" className="kiosk-link">
109
+ <ExternalLinkIcon />
110
+ {t('App:launchKiosk', 'Launch Kiosk')}
111
+ </a>
112
+ )}
113
+ </div>
114
+ ) : (
115
+ <div className="waivers-page__simple-header">
116
+
117
+ {onAddCustomer && (
118
+ <button className="waivers-page__add-customer-btn" onClick={onAddCustomer}>
119
+ + {t('App:addCustomer', 'Add Customer')}
120
+ </button>
121
+ )}
122
+ </div>
123
+ )}
124
+ </header>
125
+
126
+ <main className="waivers-page__content">
127
+ <section className="filter-section">
128
+ <div className="search-row">
129
+ <div className="search-input-wrapper">
130
+ <NewInput
131
+ label={t('App:search', 'Search')}
132
+ value={search}
133
+ onChange={(e) => onSearchChange(e.target.value)}
134
+ onIconClick={search ? onClearSearch : onSearchIconClick}
135
+ icon={search ? <ClearIcon /> : <SearchIcon />}
136
+ iconPosition={search ? 'right' : 'left'}
137
+ />
138
+ <p className="search-helper-text">{t('App:searchPlaceholder')}</p>
139
+ </div>
140
+ </div>
141
+
142
+ <div className="filters-actions-row">
143
+ <div className="quick-filters-wrapper">
144
+ <QuickFilter
145
+ label={t('App:quickFilters', 'Quick Filters:')}
146
+ options={quickFilterOptions}
147
+ selectedValues={quickFilters}
148
+ onChange={handleQuickFiltersChange}
149
+ />
150
+ </div>
151
+ <div className="action-buttons">
152
+ <button className="action-btn" onClick={onExport}>
153
+ <ExportIcon />
154
+ {t('App:exportData', 'Export')}
155
+ </button>
156
+ {waiversEnabled && (
157
+ <button className="action-btn" onClick={onSendWaiverRequest}>
158
+ <SendIcon />
159
+ {t('App:requestWaiver', 'Request Waiver')}
160
+ </button>
161
+ )}
162
+ <button className="action-btn" onClick={onRefresh}>
163
+ <RefreshIcon />
164
+ {t('App:refresh', 'Refresh')}
165
+ </button>
166
+ </div>
167
+ </div>
168
+ </section>
169
+
170
+ <section className="table-section">
171
+ <NewTable
172
+ columns={columns}
173
+ data={customers}
174
+ noDataText={!isLoading && customers.length === 0 ? t('App:noResultsFound') : undefined}
175
+ />
176
+ {pagination && customers.length > 0 && (
177
+ <div className="waivers-page__pagination">
178
+ <Pagination
179
+ currentPage={pagination.currentPage}
180
+ totalPages={pagination.totalPages}
181
+ totalItems={pagination.totalItems ?? 0}
182
+ itemsPerPage={pagination.itemsPerPage ?? 24}
183
+ onPageChange={pagination.onPageChange}
184
+ t={t}
185
+ entityName={t('App:customersLowerCase', 'customers')}
186
+ />
187
+ </div>
188
+ )}
189
+ </section>
190
+ </main>
191
+ </div>
192
+ )
193
+ }
@@ -0,0 +1,5 @@
1
+ export * from './CustomersList'
2
+ export * from './CustomerCreate'
3
+ export * from './CustomerDetail'
4
+ export * from './CustomerEdit'
5
+ export * from './CustomerForm'
@@ -0,0 +1,254 @@
1
+ .delete-modal-overlay {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ right: 0;
6
+ bottom: 0;
7
+ background-color: rgba(0, 0, 0, 0.4);
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ z-index: 1000;
12
+ animation: fadeIn 0.2s ease-in-out;
13
+ }
14
+
15
+ @keyframes fadeIn {
16
+ from { opacity: 0; }
17
+ to { opacity: 1; }
18
+ }
19
+
20
+ .delete-modal {
21
+ background: white;
22
+ border-radius: 12px;
23
+ width: 95%;
24
+ max-width: 800px;
25
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
26
+ animation: slideUp 0.2s ease-in-out;
27
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
28
+ }
29
+
30
+ @keyframes slideUp {
31
+ from {
32
+ transform: translateY(10px);
33
+ opacity: 0;
34
+ }
35
+ to {
36
+ transform: translateY(0);
37
+ opacity: 1;
38
+ }
39
+ }
40
+
41
+ .delete-modal__content {
42
+ padding: 48px;
43
+ }
44
+
45
+ .delete-modal__title {
46
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
47
+ font-size: 32px;
48
+ font-weight: 700;
49
+ color: #14215A;
50
+ margin: 0 0 24px 0;
51
+ line-height: 40px;
52
+ }
53
+
54
+ .delete-modal__description-group {
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: 24px;
58
+ margin-bottom: 32px;
59
+ }
60
+
61
+ .delete-modal__description {
62
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
63
+ font-size: 20px;
64
+ font-weight: 400;
65
+ color: #626A90;
66
+ margin: 0;
67
+ line-height: 28px;
68
+ }
69
+
70
+ .delete-modal__confirmation {
71
+ margin-bottom: 40px;
72
+ }
73
+
74
+ .delete-modal__label {
75
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
76
+ display: block;
77
+ font-size: 20px;
78
+ color: #14215A;
79
+ margin-bottom: 16px;
80
+ font-weight: 600;
81
+
82
+ strong {
83
+ font-weight: 700;
84
+ }
85
+ }
86
+
87
+ .delete-modal__input {
88
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
89
+ width: 100%;
90
+ padding: 16px 24px;
91
+ font-size: 20px;
92
+ border: 1px solid #E8E9EF;
93
+ border-radius: 12px;
94
+ outline: none;
95
+ transition: all 0.2s ease-in-out;
96
+ font-family: inherit;
97
+ color: #14215A;
98
+
99
+ &::placeholder {
100
+ color: #626A90;
101
+ opacity: 0.6;
102
+ }
103
+
104
+ &:focus {
105
+ border-color: #D2D5E3;
106
+ }
107
+ }
108
+
109
+ .delete-modal__actions {
110
+ display: flex;
111
+ gap: 16px;
112
+ align-items: center;
113
+ }
114
+
115
+ .delete-modal__button {
116
+ font-family: var(--font-family-sans, 'Geist', sans-serif);
117
+ padding: 12px 32px;
118
+ font-size: 20px;
119
+ font-weight: 600;
120
+ border-radius: 12px;
121
+ border: none;
122
+ cursor: pointer;
123
+ transition: all 0.2s ease-in-out;
124
+ font-family: inherit;
125
+ outline: none;
126
+ min-height: 64px;
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+
131
+ &:disabled {
132
+ opacity: 0.6;
133
+ cursor: not-allowed;
134
+ }
135
+
136
+ &--delete {
137
+ background-color: #CC3C35;
138
+ color: white;
139
+
140
+ &:disabled {
141
+ opacity: 0.5;
142
+ }
143
+
144
+ &:hover:not(:disabled) {
145
+ background-color: #b33630;
146
+ }
147
+ }
148
+
149
+ &--cancel {
150
+ background-color: transparent;
151
+ color: var(--label-primary);
152
+ border: 2px solid #D2D5E3;
153
+
154
+ &:hover:not(:disabled) {
155
+ background-color: var(--surface-secondary);
156
+ }
157
+ }
158
+ }
159
+
160
+ // Mobile styles
161
+ @media (max-width: 768px) {
162
+ .delete-modal {
163
+ max-width: 90%;
164
+ width: 90%;
165
+ }
166
+
167
+ .delete-modal__content {
168
+ padding: 32px 24px;
169
+ }
170
+
171
+ .delete-modal__title {
172
+ font-size: 24px;
173
+ line-height: 32px;
174
+ margin-bottom: 16px;
175
+ }
176
+
177
+ .delete-modal__description-group {
178
+ gap: 16px;
179
+ margin-bottom: 24px;
180
+ }
181
+
182
+ .delete-modal__description {
183
+ font-size: 16px;
184
+ line-height: 24px;
185
+ }
186
+
187
+ .delete-modal__confirmation {
188
+ margin-bottom: 32px;
189
+ }
190
+
191
+ .delete-modal__label {
192
+ font-size: 16px;
193
+ margin-bottom: 12px;
194
+ }
195
+
196
+ .delete-modal__actions {
197
+ gap: 12px;
198
+ }
199
+
200
+ .delete-modal__button {
201
+ padding: 10px 24px;
202
+ font-size: 16px;
203
+ min-height: 52px;
204
+ }
205
+ }
206
+
207
+ @media (max-width: 480px) {
208
+ .delete-modal {
209
+ max-width: 95%;
210
+ width: 95%;
211
+ }
212
+
213
+ .delete-modal__content {
214
+ padding: 24px 16px;
215
+ }
216
+
217
+ .delete-modal__title {
218
+ font-size: 20px;
219
+ line-height: 28px;
220
+ margin-bottom: 12px;
221
+ }
222
+
223
+ .delete-modal__description-group {
224
+ gap: 12px;
225
+ margin-bottom: 20px;
226
+ }
227
+
228
+ .delete-modal__description {
229
+ font-size: 14px;
230
+ line-height: 20px;
231
+ }
232
+
233
+ .delete-modal__confirmation {
234
+ margin-bottom: 24px;
235
+ }
236
+
237
+ .delete-modal__label {
238
+ font-size: 14px;
239
+ margin-bottom: 10px;
240
+ }
241
+
242
+ .delete-modal__actions {
243
+ flex-direction: column;
244
+ gap: 8px;
245
+ }
246
+
247
+ .delete-modal__button {
248
+ width: 100%;
249
+ padding: 8px 20px;
250
+ font-size: 14px;
251
+ min-height: 48px;
252
+ }
253
+ }
254
+
@@ -0,0 +1,100 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import './DeleteModal.scss'
3
+ import { NewInput } from '../NewInput'
4
+
5
+ export interface DeleteModalProps {
6
+ isOpen: boolean
7
+ onClose: () => void
8
+ onConfirm: () => void
9
+ title: string
10
+ description?: string
11
+ description_1?: string
12
+ confirmationText: string
13
+ confirmationPlaceholder?: string
14
+ isDeleting?: boolean
15
+ }
16
+
17
+ export const DeleteModal: React.FC<DeleteModalProps> = ({
18
+ isOpen,
19
+ onClose,
20
+ onConfirm,
21
+ title,
22
+ description,
23
+ description_1,
24
+ confirmationText,
25
+ confirmationPlaceholder,
26
+ isDeleting = false,
27
+ }) => {
28
+ const [inputValue, setInputValue] = useState('')
29
+
30
+ useEffect(() => {
31
+ if (!isOpen) {
32
+ setInputValue('')
33
+ }
34
+ }, [isOpen])
35
+
36
+ const handleClose = () => {
37
+ onClose()
38
+ }
39
+
40
+ const handleConfirm = () => {
41
+ if (inputValue === confirmationText) {
42
+ onConfirm()
43
+ }
44
+ }
45
+
46
+ const isConfirmDisabled = inputValue !== confirmationText || isDeleting
47
+
48
+ if (!isOpen) return null
49
+
50
+ return (
51
+ <div className="delete-modal-overlay" onClick={handleClose}>
52
+ <div className="delete-modal" onClick={(e) => e.stopPropagation()}>
53
+ <div className="delete-modal__content">
54
+ <h2 className="delete-modal__title">{title}</h2>
55
+
56
+ <div className="delete-modal__description-group">
57
+ {description && (
58
+ <p className="delete-modal__description">{description}</p>
59
+ )}
60
+
61
+ {description_1 && (
62
+ <p className="delete-modal__description">{description_1}</p>
63
+ )}
64
+ </div>
65
+
66
+ <div className="delete-modal__confirmation">
67
+ <p className="delete-modal__label">
68
+ Type <strong>{confirmationText}</strong> to confirm deletion
69
+ </p>
70
+ <NewInput
71
+ type="text"
72
+ placeholder={confirmationPlaceholder || confirmationText}
73
+ value={inputValue}
74
+ onChange={(e) => setInputValue(e.target.value)}
75
+ autoFocus
76
+ />
77
+ </div>
78
+
79
+ <div className="delete-modal__actions">
80
+ <button
81
+ className="delete-modal__button delete-modal__button--delete"
82
+ onClick={handleConfirm}
83
+ disabled={isConfirmDisabled}
84
+ >
85
+ {isDeleting ? 'Deleting...' : 'Delete'}
86
+ </button>
87
+ <button
88
+ className="delete-modal__button delete-modal__button--cancel"
89
+ onClick={handleClose}
90
+ disabled={isDeleting}
91
+ >
92
+ Cancel
93
+ </button>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ )
99
+ }
100
+
@@ -0,0 +1,3 @@
1
+ export { DeleteModal } from './DeleteModal'
2
+ export type { DeleteModalProps } from './DeleteModal'
3
+
@@ -1,6 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react'
2
2
  import { NewInput } from './NewInput'
3
3
  import { useState } from 'react'
4
+ import { SearchIcon, CalendarSmallIcon } from '../../icons'
4
5
 
5
6
  const meta: Meta<typeof NewInput> = {
6
7
  title: 'V2/Components/NewInput',
@@ -121,6 +122,7 @@ export const DateInput: Story = {
121
122
  args: {
122
123
  label: 'Date of Birth',
123
124
  type: 'date',
125
+ icon: <CalendarSmallIcon />,
124
126
  },
125
127
  }
126
128
 
@@ -202,24 +204,7 @@ export const RequiredField: Story = {
202
204
  export const WithIcon: Story = {
203
205
  args: {
204
206
  label: 'Search',
205
- placeholder: 'Search...',
206
- icon: (
207
- <svg
208
- width="20"
209
- height="20"
210
- viewBox="0 0 20 20"
211
- fill="none"
212
- xmlns="http://www.w3.org/2000/svg"
213
- >
214
- <path
215
- d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16zM18 18l-4.35-4.35"
216
- stroke="currentColor"
217
- strokeWidth="2"
218
- strokeLinecap="round"
219
- strokeLinejoin="round"
220
- />
221
- </svg>
222
- ),
207
+ icon: <SearchIcon />,
223
208
  },
224
209
  }
225
210
 
@@ -7,7 +7,9 @@ type CommonInputProps = {
7
7
  helperText?: string;
8
8
  error?: string;
9
9
  icon?: ReactNode;
10
+ iconPosition?: 'left' | 'right';
10
11
  required?: boolean;
12
+ onIconClick?: () => void;
11
13
  }
12
14
 
13
15
  type InputProps = CommonInputProps & {
@@ -21,7 +23,8 @@ type TextareaProps = CommonInputProps & {
21
23
  export type NewInputProps = InputProps | TextareaProps
22
24
 
23
25
  export const NewInput = forwardRef<HTMLInputElement | HTMLTextAreaElement, NewInputProps>(
24
- ({label, optional, helperText, error, icon, as = 'input', required, className = '', ...props}, ref) => {
26
+ ({label, optional, helperText, error, icon, iconPosition = 'left', as = 'input', required, className = '', onIconClick, ...props}, ref) => {
27
+ const inputRef = React.useRef<HTMLInputElement>(null);
25
28
  const isError = !!error;
26
29
  const containerClasses = [
27
30
  'new-form-input',
@@ -30,6 +33,17 @@ export const NewInput = forwardRef<HTMLInputElement | HTMLTextAreaElement, NewIn
30
33
  className
31
34
  ].filter(Boolean).join(' ');
32
35
 
36
+ // Merge refs
37
+ React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);
38
+
39
+ const handleIconClick = () => {
40
+ if (onIconClick) {
41
+ onIconClick();
42
+ } else if (inputRef.current && (props as any).type === 'date') {
43
+ inputRef.current.showPicker?.();
44
+ }
45
+ };
46
+
33
47
  const renderInput = () => {
34
48
  if (as === 'textarea') {
35
49
  return (
@@ -43,12 +57,14 @@ export const NewInput = forwardRef<HTMLInputElement | HTMLTextAreaElement, NewIn
43
57
 
44
58
  if (icon) {
45
59
  return (
46
- <div className="new-form-input__input-with-icon">
60
+ <div className={`new-form-input__input-with-icon new-form-input__input-with-icon--${iconPosition}`}>
47
61
  <input
48
- ref={ref as React.Ref<HTMLInputElement>}
62
+ ref={inputRef}
49
63
  {...(props as React.InputHTMLAttributes<HTMLInputElement>)}
50
64
  />
51
- <div className="icon">{icon}</div>
65
+ <div className="icon" onClick={handleIconClick} style={{ cursor: (onIconClick || (props as any).type === 'date') ? 'pointer' : 'default' }}>
66
+ {icon}
67
+ </div>
52
68
  </div>
53
69
  );
54
70
  }
@@ -65,14 +81,9 @@ export const NewInput = forwardRef<HTMLInputElement | HTMLTextAreaElement, NewIn
65
81
  return (
66
82
  <div className={containerClasses}>
67
83
  {(label || optional) && (
68
- <div className="new-form-input__label-row">
69
- {label && (
70
- <label className="new-form-input__label">
71
- {label}
72
- </label>
73
- )}
74
- {optional && <span className="new-form-input__label-optional">Optional</span>}
75
- </div>
84
+ <label className="new-form-input__label">
85
+ {label} {optional && <span className="new-form-input__label-optional">(Optional)</span>}
86
+ </label>
76
87
  )}
77
88
 
78
89
  {renderInput()}