@seamapi/react 1.41.0 → 1.42.0
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/README.md +1 -1
- package/dist/elements.js +5008 -4833
- package/dist/elements.js.map +1 -1
- package/dist/index.css +10 -1
- package/dist/index.css.map +1 -1
- package/dist/index.min.css +1 -1
- package/dist/index.min.css.map +1 -1
- package/lib/dates.d.ts +8 -0
- package/lib/dates.js +8 -0
- package/lib/dates.js.map +1 -1
- package/lib/seam/access-codes/use-update-access-code.d.ts +6 -0
- package/lib/seam/access-codes/use-update-access-code.js +22 -0
- package/lib/seam/access-codes/use-update-access-code.js.map +1 -0
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.d.ts +2 -1
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js +5 -2
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js.map +1 -1
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.js +34 -18
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.js.map +1 -1
- package/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.d.ts +7 -0
- package/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.js +49 -0
- package/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.js.map +1 -0
- package/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.d.ts +7 -0
- package/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.js +60 -0
- package/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.js.map +1 -0
- package/lib/seam/components/SupportedDeviceTable/FilterCategoryMenu.js +1 -1
- package/lib/seam/components/SupportedDeviceTable/FilterCategoryMenu.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.d.ts +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js +1 -5
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.d.ts +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js +25 -16
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.d.ts +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js +2 -3
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.d.ts +1 -2
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js +7 -8
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js.map +1 -1
- package/lib/ui/AccessCodeForm/AccessCodeForm.d.ts +21 -0
- package/lib/ui/AccessCodeForm/AccessCodeForm.js +97 -0
- package/lib/ui/AccessCodeForm/AccessCodeForm.js.map +1 -0
- package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormDatePicker.js +6 -6
- package/lib/ui/AccessCodeForm/AccessCodeFormDatePicker.js.map +1 -0
- package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimes.js +3 -3
- package/lib/ui/AccessCodeForm/AccessCodeFormTimes.js.map +1 -0
- package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimezonePicker.js +4 -4
- package/lib/ui/AccessCodeForm/AccessCodeFormTimezonePicker.js.map +1 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +3 -3
- package/src/lib/dates.ts +10 -0
- package/src/lib/seam/access-codes/use-update-access-code.ts +46 -0
- package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.element.ts +1 -0
- package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx +14 -1
- package/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx +62 -13
- package/src/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.element.ts +12 -0
- package/src/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.tsx +94 -0
- package/src/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.element.ts +12 -0
- package/src/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.tsx +117 -0
- package/src/lib/seam/components/SupportedDeviceTable/FilterCategoryMenu.tsx +1 -1
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.tsx +3 -7
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.tsx +29 -30
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.tsx +3 -4
- package/src/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.ts +10 -14
- package/src/lib/{seam/components → ui}/AccessCodeForm/AccessCodeForm.tsx +86 -84
- package/src/lib/version.ts +1 -1
- package/src/styles/_access-code-details.scss +5 -0
- package/src/styles/_access-code-table.scss +1 -1
- package/src/styles/_menus.scss +6 -0
- package/lib/seam/components/AccessCodeForm/AccessCodeForm.d.ts +0 -7
- package/lib/seam/components/AccessCodeForm/AccessCodeForm.js +0 -106
- package/lib/seam/components/AccessCodeForm/AccessCodeForm.js.map +0 -1
- package/lib/seam/components/AccessCodeForm/AccessCodeFormDatePicker.js.map +0 -1
- package/lib/seam/components/AccessCodeForm/AccessCodeFormTimes.js.map +0 -1
- package/lib/seam/components/AccessCodeForm/AccessCodeFormTimezonePicker.js.map +0 -1
- package/src/lib/seam/components/AccessCodeForm/AccessCodeForm.element.ts +0 -12
- /package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormDatePicker.d.ts +0 -0
- /package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimes.d.ts +0 -0
- /package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimezonePicker.d.ts +0 -0
- /package/src/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormDatePicker.tsx +0 -0
- /package/src/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimes.tsx +0 -0
- /package/src/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimezonePicker.tsx +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seamapi/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.42.0",
|
|
4
4
|
"description": "Seam Components.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"@tanstack/react-query": "^4.28.0",
|
|
123
123
|
"classnames": "^2.3.2",
|
|
124
124
|
"luxon": "^3.3.0",
|
|
125
|
-
"seamapi": "^8.
|
|
125
|
+
"seamapi": "^8.2.4",
|
|
126
126
|
"uuid": "^9.0.0"
|
|
127
127
|
},
|
|
128
128
|
"devDependencies": {
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"@mui/icons-material": "^5.11.16",
|
|
134
134
|
"@mui/material": "^5.12.2",
|
|
135
135
|
"@rxfork/r2wc-react-to-web-component": "^2.2.3",
|
|
136
|
-
"@seamapi/fake-seam-connect": "^1.
|
|
136
|
+
"@seamapi/fake-seam-connect": "^1.3.1",
|
|
137
137
|
"@storybook/addon-designs": "^7.0.1",
|
|
138
138
|
"@storybook/addon-essentials": "^7.0.2",
|
|
139
139
|
"@storybook/addon-links": "^7.0.2",
|
package/src/lib/dates.ts
CHANGED
|
@@ -128,3 +128,13 @@ export const createIsoDate = (date: string, timezone: string): string => {
|
|
|
128
128
|
const offset = getTimezoneOffset(timezone)
|
|
129
129
|
return `${date}.000${offset}`
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Takes a ISO datetime string (2023-07-20T00:00:00.000-07:00) and returns
|
|
134
|
+
* the IANA timezone (America/Los_angeles).
|
|
135
|
+
*
|
|
136
|
+
* @param date
|
|
137
|
+
* @returns string
|
|
138
|
+
*/
|
|
139
|
+
export const getTimezoneFromIsoDate = (date: string): string | null =>
|
|
140
|
+
DateTime.fromISO(date).zoneName
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useMutation,
|
|
3
|
+
type UseMutationResult,
|
|
4
|
+
useQueryClient,
|
|
5
|
+
} from '@tanstack/react-query'
|
|
6
|
+
import type {
|
|
7
|
+
AccessCodeUpdateRequest,
|
|
8
|
+
AccessCodeUpdateResponse,
|
|
9
|
+
ActionAttempt,
|
|
10
|
+
SeamError,
|
|
11
|
+
} from 'seamapi'
|
|
12
|
+
|
|
13
|
+
import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
14
|
+
|
|
15
|
+
export type UseUpdateAccessCodeParams = never
|
|
16
|
+
export type UseUpdateAccessCodeData = ActionAttempt<'UPDATE_ACCESS_CODE'>
|
|
17
|
+
export type UseUpdateAccessCodeMutationParams = AccessCodeUpdateRequest
|
|
18
|
+
|
|
19
|
+
export function useUpdateAccessCode(): UseMutationResult<
|
|
20
|
+
UseUpdateAccessCodeData,
|
|
21
|
+
SeamError,
|
|
22
|
+
UseUpdateAccessCodeMutationParams
|
|
23
|
+
> {
|
|
24
|
+
const { client } = useSeamClient()
|
|
25
|
+
const queryClient = useQueryClient()
|
|
26
|
+
|
|
27
|
+
return useMutation<
|
|
28
|
+
AccessCodeUpdateResponse['action_attempt'],
|
|
29
|
+
SeamError,
|
|
30
|
+
AccessCodeUpdateRequest
|
|
31
|
+
>({
|
|
32
|
+
mutationFn: async (mutationParams: UseUpdateAccessCodeMutationParams) => {
|
|
33
|
+
if (client === null) throw new NullSeamClientError()
|
|
34
|
+
|
|
35
|
+
return await client.accessCodes.update(mutationParams)
|
|
36
|
+
},
|
|
37
|
+
onSuccess: (_data, variables) => {
|
|
38
|
+
void queryClient.invalidateQueries([
|
|
39
|
+
'access_codes',
|
|
40
|
+
'get',
|
|
41
|
+
{ access_code_id: variables.access_code_id },
|
|
42
|
+
])
|
|
43
|
+
void queryClient.invalidateQueries(['access_codes', 'list'])
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
}
|
|
@@ -12,20 +12,25 @@ import { useAccessCode } from 'lib/seam/access-codes/use-access-code.js'
|
|
|
12
12
|
import { AccessCodeDevice } from 'lib/seam/components/AccessCodeDetails/AccessCodeDevice.js'
|
|
13
13
|
import { DeviceDetails } from 'lib/seam/components/DeviceDetails/DeviceDetails.js'
|
|
14
14
|
import { Alerts } from 'lib/ui/Alert/Alerts.js'
|
|
15
|
+
import { Button } from 'lib/ui/Button.js'
|
|
15
16
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
16
17
|
import { useIsDateInPast } from 'lib/ui/use-is-date-in-past.js'
|
|
17
18
|
|
|
19
|
+
const disableEditAccessCode = false
|
|
20
|
+
|
|
18
21
|
export interface AccessCodeDetailsProps {
|
|
19
22
|
accessCodeId: string
|
|
20
23
|
disableLockUnlock?: boolean
|
|
21
24
|
onBack?: () => void
|
|
25
|
+
onEdit: () => void
|
|
22
26
|
className?: string
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export function AccessCodeDetails({
|
|
26
30
|
accessCodeId,
|
|
27
|
-
onBack,
|
|
28
31
|
disableLockUnlock = false,
|
|
32
|
+
onBack,
|
|
33
|
+
onEdit,
|
|
29
34
|
className,
|
|
30
35
|
}: AccessCodeDetailsProps): JSX.Element | null {
|
|
31
36
|
const { accessCode } = useAccessCode(accessCodeId)
|
|
@@ -87,6 +92,13 @@ export function AccessCodeDetails({
|
|
|
87
92
|
onSelectDevice={selectDevice}
|
|
88
93
|
/>
|
|
89
94
|
</div>
|
|
95
|
+
{!disableEditAccessCode && (
|
|
96
|
+
<div className='seam-actions'>
|
|
97
|
+
<Button size='small' onClick={onEdit}>
|
|
98
|
+
{t.editCode}
|
|
99
|
+
</Button>
|
|
100
|
+
</div>
|
|
101
|
+
)}
|
|
90
102
|
<div className='seam-details'>
|
|
91
103
|
<div className='seam-row'>
|
|
92
104
|
<div className='seam-heading'>{t.id}:</div>
|
|
@@ -211,4 +223,5 @@ const t = {
|
|
|
211
223
|
ongoing: 'Ongoing',
|
|
212
224
|
start: 'Start',
|
|
213
225
|
end: 'End',
|
|
226
|
+
editCode: 'Edit code',
|
|
214
227
|
}
|
|
@@ -12,12 +12,13 @@ import {
|
|
|
12
12
|
type UseAccessCodesData,
|
|
13
13
|
} from 'lib/seam/access-codes/use-access-codes.js'
|
|
14
14
|
import { AccessCodeDetails } from 'lib/seam/components/AccessCodeDetails/AccessCodeDetails.js'
|
|
15
|
-
import { AccessCodeForm } from 'lib/seam/components/AccessCodeForm/AccessCodeForm.js'
|
|
16
15
|
import {
|
|
17
16
|
type AccessCodeFilter,
|
|
18
17
|
AccessCodeHealthBar,
|
|
19
18
|
} from 'lib/seam/components/AccessCodeTable/AccessCodeHealthBar.js'
|
|
20
19
|
import { CodeDetails } from 'lib/seam/components/AccessCodeTable/CodeDetails.js'
|
|
20
|
+
import { CreateAccessCodeForm } from 'lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.js'
|
|
21
|
+
import { EditAccessCodeForm } from 'lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.js'
|
|
21
22
|
import { copyToClipboard } from 'lib/ui/clipboard.js'
|
|
22
23
|
import { IconButton } from 'lib/ui/IconButton.js'
|
|
23
24
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
@@ -35,6 +36,7 @@ import { Title } from 'lib/ui/typography/Title.js'
|
|
|
35
36
|
import { useToggle } from 'lib/ui/use-toggle.js'
|
|
36
37
|
|
|
37
38
|
const disableCreateAccessCode = true
|
|
39
|
+
const disableEditAccessCode = false
|
|
38
40
|
|
|
39
41
|
export interface AccessCodeTableProps {
|
|
40
42
|
deviceId: string
|
|
@@ -91,12 +93,15 @@ export function AccessCodeTable({
|
|
|
91
93
|
device_id: deviceId,
|
|
92
94
|
})
|
|
93
95
|
|
|
94
|
-
const [
|
|
96
|
+
const [selectedViewAccessCodeId, setSelectedViewAccessCodeId] = useState<
|
|
95
97
|
string | null
|
|
96
98
|
>(null)
|
|
97
99
|
|
|
98
100
|
const [searchInputValue, setSearchInputValue] = useState('')
|
|
99
|
-
const [
|
|
101
|
+
const [addAccessCodeFormVisible, toggleAddAccessCodeForm] = useToggle()
|
|
102
|
+
const [selectedEditAccessCodeId, setSelectedEditAccessCodeId] = useState<
|
|
103
|
+
string | null
|
|
104
|
+
>(null)
|
|
100
105
|
|
|
101
106
|
const filteredAccessCodes = useMemo(
|
|
102
107
|
() =>
|
|
@@ -110,31 +115,53 @@ export function AccessCodeTable({
|
|
|
110
115
|
(accessCodeId: string): void => {
|
|
111
116
|
onAccessCodeClick(accessCodeId)
|
|
112
117
|
if (preventDefaultOnAccessCodeClick) return
|
|
113
|
-
|
|
118
|
+
setSelectedViewAccessCodeId(accessCodeId)
|
|
114
119
|
},
|
|
115
120
|
[
|
|
116
121
|
onAccessCodeClick,
|
|
117
122
|
preventDefaultOnAccessCodeClick,
|
|
118
|
-
|
|
123
|
+
setSelectedViewAccessCodeId,
|
|
119
124
|
]
|
|
120
125
|
)
|
|
121
126
|
|
|
122
|
-
|
|
127
|
+
const handleAccessCodeEdit = useCallback(
|
|
128
|
+
(accessCodeId: string): void => {
|
|
129
|
+
setSelectedEditAccessCodeId(accessCodeId)
|
|
130
|
+
},
|
|
131
|
+
[setSelectedEditAccessCodeId]
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
if (selectedEditAccessCodeId != null) {
|
|
135
|
+
return (
|
|
136
|
+
<EditAccessCodeForm
|
|
137
|
+
accessCodeId={selectedEditAccessCodeId}
|
|
138
|
+
className={className}
|
|
139
|
+
onBack={() => {
|
|
140
|
+
setSelectedEditAccessCodeId(null)
|
|
141
|
+
}}
|
|
142
|
+
/>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (selectedViewAccessCodeId != null) {
|
|
123
147
|
return (
|
|
124
148
|
<AccessCodeDetails
|
|
125
149
|
className={className}
|
|
126
|
-
accessCodeId={
|
|
150
|
+
accessCodeId={selectedViewAccessCodeId}
|
|
127
151
|
onBack={() => {
|
|
128
|
-
|
|
152
|
+
setSelectedViewAccessCodeId(null)
|
|
129
153
|
}}
|
|
130
154
|
disableLockUnlock={disableLockUnlock}
|
|
155
|
+
onEdit={() => {
|
|
156
|
+
setSelectedEditAccessCodeId(selectedViewAccessCodeId)
|
|
157
|
+
}}
|
|
131
158
|
/>
|
|
132
159
|
)
|
|
133
160
|
}
|
|
134
161
|
|
|
135
|
-
if (
|
|
162
|
+
if (addAccessCodeFormVisible) {
|
|
136
163
|
return (
|
|
137
|
-
<
|
|
164
|
+
<CreateAccessCodeForm
|
|
138
165
|
className={className}
|
|
139
166
|
onBack={toggleAddAccessCodeForm}
|
|
140
167
|
deviceId={deviceId}
|
|
@@ -176,6 +203,8 @@ export function AccessCodeTable({
|
|
|
176
203
|
<Content
|
|
177
204
|
accessCodes={filteredAccessCodes}
|
|
178
205
|
onAccessCodeClick={handleAccessCodeClick}
|
|
206
|
+
onAccessCodeEdit={handleAccessCodeEdit}
|
|
207
|
+
disableEditAccessCode={disableEditAccessCode}
|
|
179
208
|
/>
|
|
180
209
|
</TableBody>
|
|
181
210
|
</div>
|
|
@@ -185,8 +214,15 @@ export function AccessCodeTable({
|
|
|
185
214
|
function Content(props: {
|
|
186
215
|
accessCodes: Array<UseAccessCodesData[number]>
|
|
187
216
|
onAccessCodeClick: (accessCodeId: string) => void
|
|
217
|
+
onAccessCodeEdit: (accessCodeId: string) => void
|
|
218
|
+
disableEditAccessCode: boolean
|
|
188
219
|
}): JSX.Element {
|
|
189
|
-
const {
|
|
220
|
+
const {
|
|
221
|
+
accessCodes,
|
|
222
|
+
onAccessCodeClick,
|
|
223
|
+
onAccessCodeEdit,
|
|
224
|
+
disableEditAccessCode,
|
|
225
|
+
} = props
|
|
190
226
|
const [filter, setFilter] = useState<AccessCodeFilter | null>(null)
|
|
191
227
|
|
|
192
228
|
const filteredAccessCodes = useMemo(() => {
|
|
@@ -221,6 +257,10 @@ function Content(props: {
|
|
|
221
257
|
onClick={() => {
|
|
222
258
|
onAccessCodeClick(accessCode.access_code_id)
|
|
223
259
|
}}
|
|
260
|
+
disableEditAccessCode={disableEditAccessCode}
|
|
261
|
+
onEdit={() => {
|
|
262
|
+
onAccessCodeEdit(accessCode.access_code_id)
|
|
263
|
+
}}
|
|
224
264
|
/>
|
|
225
265
|
))}
|
|
226
266
|
</>
|
|
@@ -230,8 +270,10 @@ function Content(props: {
|
|
|
230
270
|
function AccessCodeRow(props: {
|
|
231
271
|
accessCode: UseAccessCodesData[number]
|
|
232
272
|
onClick: () => void
|
|
273
|
+
onEdit: () => void
|
|
274
|
+
disableEditAccessCode: boolean
|
|
233
275
|
}): JSX.Element {
|
|
234
|
-
const { onClick, accessCode } = props
|
|
276
|
+
const { onClick, accessCode, onEdit, disableEditAccessCode } = props
|
|
235
277
|
|
|
236
278
|
const errorCount = accessCode.errors.length
|
|
237
279
|
const warningCount = accessCode.warnings.length
|
|
@@ -277,13 +319,19 @@ function AccessCodeRow(props: {
|
|
|
277
319
|
void copyToClipboard(accessCode.code ?? '')
|
|
278
320
|
}}
|
|
279
321
|
>
|
|
280
|
-
<div className='menu-item-copy'>
|
|
322
|
+
<div className='seam-menu-item-copy'>
|
|
281
323
|
<span>
|
|
282
324
|
{t.copyCode} - {accessCode.code}
|
|
283
325
|
</span>
|
|
284
326
|
<CopyIcon />
|
|
285
327
|
</div>
|
|
286
328
|
</MenuItem>
|
|
329
|
+
{!disableEditAccessCode && (
|
|
330
|
+
<>
|
|
331
|
+
<div className='seam-divider' />
|
|
332
|
+
<MenuItem onClick={onEdit}>{t.editCode}</MenuItem>
|
|
333
|
+
</>
|
|
334
|
+
)}
|
|
287
335
|
</MoreActionsMenu>
|
|
288
336
|
</TableCell>
|
|
289
337
|
</TableRow>
|
|
@@ -296,4 +344,5 @@ const t = {
|
|
|
296
344
|
noAccessCodesMessage: 'Sorry, no access codes were found',
|
|
297
345
|
codeIssue: 'code issue',
|
|
298
346
|
codeIssues: 'code issues',
|
|
347
|
+
editCode: 'Edit code',
|
|
299
348
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ElementProps } from 'lib/element.js'
|
|
2
|
+
import type { CreateAccessCodeFormProps } from 'lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.js'
|
|
3
|
+
|
|
4
|
+
export const name = 'seam-create-access-code-form'
|
|
5
|
+
|
|
6
|
+
export const props: ElementProps<CreateAccessCodeFormProps> = {
|
|
7
|
+
className: 'string',
|
|
8
|
+
onBack: 'object',
|
|
9
|
+
deviceId: 'string',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { CreateAccessCodeForm as Component } from './CreateAccessCodeForm.js'
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createIsoDate } from 'lib/dates.js'
|
|
2
|
+
import { useCreateAccessCode } from 'lib/seam/access-codes/use-create-access-code.js'
|
|
3
|
+
import { useDevice, type UseDeviceData } from 'lib/seam/devices/use-device.js'
|
|
4
|
+
import {
|
|
5
|
+
AccessCodeForm,
|
|
6
|
+
type AccessCodeFormSubmitData,
|
|
7
|
+
} from 'lib/ui/AccessCodeForm/AccessCodeForm.js'
|
|
8
|
+
|
|
9
|
+
export interface CreateAccessCodeFormProps {
|
|
10
|
+
className?: string
|
|
11
|
+
onBack?: () => void
|
|
12
|
+
deviceId: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function CreateAccessCodeForm({
|
|
16
|
+
className,
|
|
17
|
+
onBack,
|
|
18
|
+
deviceId,
|
|
19
|
+
}: CreateAccessCodeFormProps): JSX.Element | null {
|
|
20
|
+
const { device } = useDevice({
|
|
21
|
+
device_id: deviceId,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
if (device == null) {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return <Content device={device} className={className} onBack={onBack} />
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Content({
|
|
32
|
+
device,
|
|
33
|
+
className,
|
|
34
|
+
onBack,
|
|
35
|
+
}: Omit<CreateAccessCodeFormProps, 'deviceId'> & {
|
|
36
|
+
device: NonNullable<UseDeviceData>
|
|
37
|
+
}): JSX.Element {
|
|
38
|
+
const { submit, isSubmitting } = useSubmitCreateAccessCode(onBack)
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<AccessCodeForm
|
|
42
|
+
device={device}
|
|
43
|
+
className={className}
|
|
44
|
+
onBack={onBack}
|
|
45
|
+
onSubmit={submit}
|
|
46
|
+
isSubmitting={isSubmitting}
|
|
47
|
+
/>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function useSubmitCreateAccessCode(onSuccess?: () => void): {
|
|
52
|
+
submit: (data: AccessCodeFormSubmitData) => void
|
|
53
|
+
isSubmitting: boolean
|
|
54
|
+
} {
|
|
55
|
+
const { mutate, isLoading: isSubmitting } = useCreateAccessCode()
|
|
56
|
+
const submit = (data: AccessCodeFormSubmitData): void => {
|
|
57
|
+
const { name, type, device, startDate, endDate, timezone } = data
|
|
58
|
+
if (name === '') {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (isSubmitting) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (type === 'time_bound') {
|
|
67
|
+
mutate(
|
|
68
|
+
{
|
|
69
|
+
name,
|
|
70
|
+
device_id: device.device_id,
|
|
71
|
+
starts_at: createIsoDate(startDate, timezone),
|
|
72
|
+
ends_at: createIsoDate(endDate, timezone),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
onSuccess,
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
mutate(
|
|
83
|
+
{
|
|
84
|
+
name,
|
|
85
|
+
device_id: device.device_id,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
onSuccess,
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { submit, isSubmitting }
|
|
94
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ElementProps } from 'lib/element.js'
|
|
2
|
+
import type { EditAccessCodeFormProps } from 'lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.js'
|
|
3
|
+
|
|
4
|
+
export const name = 'seam-create-access-code-form'
|
|
5
|
+
|
|
6
|
+
export const props: ElementProps<EditAccessCodeFormProps> = {
|
|
7
|
+
className: 'string',
|
|
8
|
+
onBack: 'object',
|
|
9
|
+
accessCodeId: 'string',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { EditAccessCodeForm as Component } from './EditAccessCodeForm.js'
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { createIsoDate } from 'lib/dates.js'
|
|
2
|
+
import {
|
|
3
|
+
useAccessCode,
|
|
4
|
+
type UseAccessCodeData,
|
|
5
|
+
} from 'lib/seam/access-codes/use-access-code.js'
|
|
6
|
+
import { useUpdateAccessCode } from 'lib/seam/access-codes/use-update-access-code.js'
|
|
7
|
+
import { useDevice } from 'lib/seam/devices/use-device.js'
|
|
8
|
+
import {
|
|
9
|
+
AccessCodeForm,
|
|
10
|
+
type AccessCodeFormSubmitData,
|
|
11
|
+
} from 'lib/ui/AccessCodeForm/AccessCodeForm.js'
|
|
12
|
+
|
|
13
|
+
export interface EditAccessCodeFormProps {
|
|
14
|
+
className?: string
|
|
15
|
+
onBack?: () => void
|
|
16
|
+
accessCodeId: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function EditAccessCodeForm({
|
|
20
|
+
accessCodeId,
|
|
21
|
+
onBack,
|
|
22
|
+
className,
|
|
23
|
+
}: EditAccessCodeFormProps): JSX.Element | null {
|
|
24
|
+
const { accessCode } = useAccessCode({
|
|
25
|
+
access_code_id: accessCodeId,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
if (accessCode == null) {
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Content accessCode={accessCode} className={className} onBack={onBack} />
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function Content({
|
|
38
|
+
className,
|
|
39
|
+
onBack,
|
|
40
|
+
accessCode,
|
|
41
|
+
}: Omit<EditAccessCodeFormProps, 'accessCodeId'> & {
|
|
42
|
+
accessCode: NonNullable<UseAccessCodeData>
|
|
43
|
+
}): JSX.Element | null {
|
|
44
|
+
const { device } = useDevice({
|
|
45
|
+
device_id: accessCode.device_id,
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const { submit, isSubmitting } = useSubmitEditAccessCode(accessCode, onBack)
|
|
49
|
+
|
|
50
|
+
if (device == null) {
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<AccessCodeForm
|
|
56
|
+
onBack={onBack}
|
|
57
|
+
className={className}
|
|
58
|
+
accessCode={accessCode}
|
|
59
|
+
device={device}
|
|
60
|
+
onSubmit={submit}
|
|
61
|
+
isSubmitting={isSubmitting}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function useSubmitEditAccessCode(
|
|
67
|
+
accessCode: NonNullable<UseAccessCodeData>,
|
|
68
|
+
onSuccess?: () => void
|
|
69
|
+
): {
|
|
70
|
+
submit: (data: AccessCodeFormSubmitData) => void
|
|
71
|
+
isSubmitting: boolean
|
|
72
|
+
} {
|
|
73
|
+
const { mutate, isLoading: isSubmitting } = useUpdateAccessCode()
|
|
74
|
+
|
|
75
|
+
const submit = (data: AccessCodeFormSubmitData): void => {
|
|
76
|
+
const { name, type, device, startDate, endDate, timezone } = data
|
|
77
|
+
if (name === '') {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (isSubmitting) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (type === 'time_bound') {
|
|
86
|
+
mutate(
|
|
87
|
+
{
|
|
88
|
+
access_code_id: accessCode.access_code_id,
|
|
89
|
+
name,
|
|
90
|
+
device_id: device.device_id,
|
|
91
|
+
type: 'time_bound',
|
|
92
|
+
starts_at: createIsoDate(startDate, timezone),
|
|
93
|
+
ends_at: createIsoDate(endDate, timezone),
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
onSuccess,
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
mutate(
|
|
104
|
+
{
|
|
105
|
+
access_code_id: accessCode.access_code_id,
|
|
106
|
+
name,
|
|
107
|
+
type: 'ongoing',
|
|
108
|
+
device_id: device.device_id,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
onSuccess,
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { submit, isSubmitting }
|
|
117
|
+
}
|
|
@@ -36,7 +36,7 @@ export function FilterCategoryMenu({
|
|
|
36
36
|
onAllOptionSelect,
|
|
37
37
|
buttonLabel,
|
|
38
38
|
}: FilterCategoryMenuProps): JSX.Element {
|
|
39
|
-
const usableOptions = hideAllOption ? options : [
|
|
39
|
+
const usableOptions = hideAllOption ? options : [allLabel, ...options]
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
42
|
<div className='seam-supported-device-table-filter-menu-wrap'>
|
|
@@ -13,7 +13,7 @@ interface SupportedDeviceContentProps {
|
|
|
13
13
|
filterValue: string
|
|
14
14
|
resetFilterValue: () => void
|
|
15
15
|
filters: DeviceModelFilters
|
|
16
|
-
brands: string[]
|
|
16
|
+
brands: string[] | null
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function SupportedDeviceContent({
|
|
@@ -71,12 +71,8 @@ export function SupportedDeviceContent({
|
|
|
71
71
|
)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
filterValue.trim() !== '' ||
|
|
77
|
-
filters.supportedOnly ||
|
|
78
|
-
filters.category !== null ||
|
|
79
|
-
filters.brand !== null
|
|
74
|
+
const hasFilters = filterValue.trim() !== '' || filters.brand !== null
|
|
75
|
+
|
|
80
76
|
if (hasFilters) {
|
|
81
77
|
return (
|
|
82
78
|
<div className='seam-supported-device-table-content'>
|