@seamapi/react 1.41.1 → 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.
Files changed (63) hide show
  1. package/README.md +1 -1
  2. package/dist/elements.js +4970 -4793
  3. package/dist/elements.js.map +1 -1
  4. package/dist/index.css +10 -1
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.min.css +1 -1
  7. package/dist/index.min.css.map +1 -1
  8. package/lib/dates.d.ts +8 -0
  9. package/lib/dates.js +8 -0
  10. package/lib/dates.js.map +1 -1
  11. package/lib/seam/access-codes/use-update-access-code.d.ts +6 -0
  12. package/lib/seam/access-codes/use-update-access-code.js +22 -0
  13. package/lib/seam/access-codes/use-update-access-code.js.map +1 -0
  14. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.d.ts +2 -1
  15. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js +5 -2
  16. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js.map +1 -1
  17. package/lib/seam/components/AccessCodeTable/AccessCodeTable.js +34 -18
  18. package/lib/seam/components/AccessCodeTable/AccessCodeTable.js.map +1 -1
  19. package/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.d.ts +7 -0
  20. package/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.js +49 -0
  21. package/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.js.map +1 -0
  22. package/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.d.ts +7 -0
  23. package/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.js +60 -0
  24. package/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.js.map +1 -0
  25. package/lib/ui/AccessCodeForm/AccessCodeForm.d.ts +21 -0
  26. package/lib/ui/AccessCodeForm/AccessCodeForm.js +97 -0
  27. package/lib/ui/AccessCodeForm/AccessCodeForm.js.map +1 -0
  28. package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormDatePicker.js +6 -6
  29. package/lib/ui/AccessCodeForm/AccessCodeFormDatePicker.js.map +1 -0
  30. package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimes.js +3 -3
  31. package/lib/ui/AccessCodeForm/AccessCodeFormTimes.js.map +1 -0
  32. package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimezonePicker.js +4 -4
  33. package/lib/ui/AccessCodeForm/AccessCodeFormTimezonePicker.js.map +1 -0
  34. package/lib/version.d.ts +1 -1
  35. package/lib/version.js +1 -1
  36. package/package.json +3 -3
  37. package/src/lib/dates.ts +10 -0
  38. package/src/lib/seam/access-codes/use-update-access-code.ts +46 -0
  39. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.element.ts +1 -0
  40. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx +14 -1
  41. package/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx +62 -13
  42. package/src/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.element.ts +12 -0
  43. package/src/lib/seam/components/CreateAccessCodeForm/CreateAccessCodeForm.tsx +94 -0
  44. package/src/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.element.ts +12 -0
  45. package/src/lib/seam/components/EditAccessCodeForm/EditAccessCodeForm.tsx +117 -0
  46. package/src/lib/{seam/components → ui}/AccessCodeForm/AccessCodeForm.tsx +86 -84
  47. package/src/lib/version.ts +1 -1
  48. package/src/styles/_access-code-details.scss +5 -0
  49. package/src/styles/_access-code-table.scss +1 -1
  50. package/src/styles/_menus.scss +6 -0
  51. package/lib/seam/components/AccessCodeForm/AccessCodeForm.d.ts +0 -7
  52. package/lib/seam/components/AccessCodeForm/AccessCodeForm.js +0 -106
  53. package/lib/seam/components/AccessCodeForm/AccessCodeForm.js.map +0 -1
  54. package/lib/seam/components/AccessCodeForm/AccessCodeFormDatePicker.js.map +0 -1
  55. package/lib/seam/components/AccessCodeForm/AccessCodeFormTimes.js.map +0 -1
  56. package/lib/seam/components/AccessCodeForm/AccessCodeFormTimezonePicker.js.map +0 -1
  57. package/src/lib/seam/components/AccessCodeForm/AccessCodeForm.element.ts +0 -12
  58. /package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormDatePicker.d.ts +0 -0
  59. /package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimes.d.ts +0 -0
  60. /package/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimezonePicker.d.ts +0 -0
  61. /package/src/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormDatePicker.tsx +0 -0
  62. /package/src/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimes.tsx +0 -0
  63. /package/src/lib/{seam/components → ui}/AccessCodeForm/AccessCodeFormTimezonePicker.tsx +0 -0
@@ -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 [selectedAccessCodeId, setSelectedAccessCodeId] = useState<
96
+ const [selectedViewAccessCodeId, setSelectedViewAccessCodeId] = useState<
95
97
  string | null
96
98
  >(null)
97
99
 
98
100
  const [searchInputValue, setSearchInputValue] = useState('')
99
- const [accessCodeFormVisible, toggleAddAccessCodeForm] = useToggle()
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
- setSelectedAccessCodeId(accessCodeId)
118
+ setSelectedViewAccessCodeId(accessCodeId)
114
119
  },
115
120
  [
116
121
  onAccessCodeClick,
117
122
  preventDefaultOnAccessCodeClick,
118
- setSelectedAccessCodeId,
123
+ setSelectedViewAccessCodeId,
119
124
  ]
120
125
  )
121
126
 
122
- if (selectedAccessCodeId != null) {
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={selectedAccessCodeId}
150
+ accessCodeId={selectedViewAccessCodeId}
127
151
  onBack={() => {
128
- setSelectedAccessCodeId(null)
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 (accessCodeFormVisible) {
162
+ if (addAccessCodeFormVisible) {
136
163
  return (
137
- <AccessCodeForm
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 { accessCodes, onAccessCodeClick } = props
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
+ }
@@ -3,16 +3,16 @@ import { useState } from 'react'
3
3
  import type { AccessCode } from 'seamapi'
4
4
 
5
5
  import {
6
- createIsoDate,
7
6
  get24HoursLater,
8
7
  getBrowserTimezone,
9
8
  getNow,
9
+ getTimezoneFromIsoDate,
10
10
  } from 'lib/dates.js'
11
- import { useCreateAccessCode } from 'lib/seam/access-codes/use-create-access-code.js'
12
- import { AccessCodeFormDatePicker } from 'lib/seam/components/AccessCodeForm/AccessCodeFormDatePicker.js'
13
- import { AccessCodeFormTimes } from 'lib/seam/components/AccessCodeForm/AccessCodeFormTimes.js'
14
- import { AccessCodeFormTimezonePicker } from 'lib/seam/components/AccessCodeForm/AccessCodeFormTimezonePicker.js'
15
- import { useDevice, type UseDeviceData } from 'lib/seam/devices/use-device.js'
11
+ import type { UseAccessCodeData } from 'lib/seam/access-codes/use-access-code.js'
12
+ import type { UseDeviceData } from 'lib/seam/devices/use-device.js'
13
+ import { AccessCodeFormDatePicker } from 'lib/ui/AccessCodeForm/AccessCodeFormDatePicker.js'
14
+ import { AccessCodeFormTimes } from 'lib/ui/AccessCodeForm/AccessCodeFormTimes.js'
15
+ import { AccessCodeFormTimezonePicker } from 'lib/ui/AccessCodeForm/AccessCodeFormTimezonePicker.js'
16
16
  import { Button } from 'lib/ui/Button.js'
17
17
  import { FormField } from 'lib/ui/FormField.js'
18
18
  import { InputLabel } from 'lib/ui/InputLabel.js'
@@ -21,55 +21,72 @@ import { RadioField } from 'lib/ui/RadioField/RadioField.js'
21
21
  import { TextField } from 'lib/ui/TextField/TextField.js'
22
22
  import { useToggle } from 'lib/ui/use-toggle.js'
23
23
 
24
+ export interface AccessCodeFormSubmitData {
25
+ name: string
26
+ type: AccessCode['type']
27
+ device: NonNullable<UseDeviceData>
28
+ startDate: string
29
+ endDate: string
30
+ timezone: string
31
+ }
32
+
24
33
  export interface AccessCodeFormProps {
25
- deviceId: string
26
- onBack?: () => void
27
34
  className?: string
35
+ onBack?: () => void
36
+ accessCode?: NonNullable<UseAccessCodeData>
37
+ device: NonNullable<UseDeviceData>
38
+ isSubmitting: boolean
39
+ onSubmit: (data: AccessCodeFormSubmitData) => void
28
40
  }
29
41
 
30
42
  export function AccessCodeForm({
31
- deviceId,
32
- onBack,
33
43
  className,
44
+ ...props
34
45
  }: AccessCodeFormProps): JSX.Element | null {
35
- const { device } = useDevice({
36
- device_id: deviceId,
37
- })
38
-
39
- if (device == null) {
40
- return null
41
- }
42
-
43
46
  return (
44
47
  <div className={classNames('seam-access-code-form', className)}>
45
- <Content className={className} onBack={onBack} device={device} />
48
+ <Content {...props} />
46
49
  </div>
47
50
  )
48
51
  }
49
52
 
50
53
  function Content({
51
54
  onBack,
55
+ accessCode,
52
56
  device,
53
- }: Omit<AccessCodeFormProps, 'deviceId'> & {
54
- device: NonNullable<UseDeviceData>
55
- }): JSX.Element {
56
- const [name, setName] = useState('')
57
- const [type, setType] = useState<AccessCode['type']>('ongoing')
57
+ onSubmit,
58
+ isSubmitting,
59
+ }: Omit<AccessCodeFormProps, 'className'>): JSX.Element {
60
+ const [name, setName] = useState(accessCode?.name ?? '')
61
+ const [type, setType] = useState<AccessCode['type']>(
62
+ accessCode?.type ?? 'ongoing'
63
+ )
58
64
  const [datePickerVisible, setDatePickerVisible] = useState(false)
59
- const [timezone, setTimezone] = useState<string>(getBrowserTimezone())
60
- const [startDate, setStartDate] = useState<string>(getNow())
61
- const [endDate, setEndDate] = useState<string>(get24HoursLater())
65
+ const [timezone, setTimezone] = useState<string>(
66
+ getAccessCodeTimezone(accessCode) ?? getBrowserTimezone()
67
+ )
68
+ const [startDate, setStartDate] = useState<string>(
69
+ getAccessCodeDate('starts_at', accessCode) ?? getNow()
70
+ )
71
+ const [endDate, setEndDate] = useState<string>(
72
+ getAccessCodeDate('ends_at', accessCode) ?? get24HoursLater()
73
+ )
62
74
  const [timezonePickerVisible, toggleTimezonePicker] = useToggle()
63
75
 
64
- const { submit, isLoading } = useSubmit({
65
- name,
66
- type,
67
- device,
68
- startDate,
69
- endDate,
70
- timezone,
71
- onSuccess: onBack,
72
- })
76
+ const submit = (): void => {
77
+ if (isSubmitting) {
78
+ return
79
+ }
80
+
81
+ onSubmit({
82
+ name,
83
+ type,
84
+ device,
85
+ startDate,
86
+ endDate,
87
+ timezone,
88
+ })
89
+ }
73
90
 
74
91
  if (timezonePickerVisible) {
75
92
  return (
@@ -100,12 +117,14 @@ function Content({
100
117
  const nameError = name.length > 60 ? t.overCharacterLimitError : undefined
101
118
 
102
119
  const isFormValid =
103
- name.trim().length > 0 && nameError === undefined && !isLoading
120
+ name.trim().length > 0 && nameError === undefined && !isSubmitting
121
+
122
+ const title = accessCode == null ? t.addNewAccessCode : t.editAccessCode
104
123
 
105
124
  return (
106
125
  <>
107
126
  <ContentHeader
108
- title={t.addNewAccessCode}
127
+ title={title}
109
128
  subheading={device.properties.name}
110
129
  onBack={onBack}
111
130
  />
@@ -161,62 +180,45 @@ function Content({
161
180
  )
162
181
  }
163
182
 
164
- function useSubmit(params: {
165
- name: string
166
- type: AccessCode['type']
167
- device: NonNullable<UseDeviceData>
168
- startDate: string
169
- endDate: string
170
- timezone: string
171
- onSuccess?: () => void
172
- }): {
173
- submit: () => void
174
- isLoading: boolean
175
- } {
176
- const { name, type, device, startDate, endDate, timezone, onSuccess } = params
177
-
178
- const { mutate, isLoading } = useCreateAccessCode()
179
- const submit = (): void => {
180
- if (name === '') {
181
- return
182
- }
183
+ function getAccessCodeTimezone(
184
+ accessCode?: NonNullable<UseAccessCodeData>
185
+ ): undefined | string {
186
+ if (accessCode == null) {
187
+ return undefined
188
+ }
183
189
 
184
- if (isLoading) {
185
- return
186
- }
190
+ if (accessCode.type === 'ongoing') {
191
+ return undefined
192
+ }
187
193
 
188
- if (type === 'time_bound') {
189
- mutate(
190
- {
191
- name,
192
- device_id: device.device_id,
193
- starts_at: createIsoDate(startDate, timezone),
194
- ends_at: createIsoDate(endDate, timezone),
195
- },
196
- {
197
- onSuccess,
198
- }
199
- )
194
+ const date = accessCode.starts_at
200
195
 
201
- return
202
- }
196
+ const timezone = getTimezoneFromIsoDate(date)
197
+ if (timezone == null) {
198
+ return undefined
199
+ }
203
200
 
204
- mutate(
205
- {
206
- name,
207
- device_id: device.device_id,
208
- },
209
- {
210
- onSuccess,
211
- }
212
- )
201
+ return timezone
202
+ }
203
+
204
+ function getAccessCodeDate(
205
+ date: 'starts_at' | 'ends_at',
206
+ accessCode?: NonNullable<UseAccessCodeData>
207
+ ): string | undefined {
208
+ if (accessCode == null) {
209
+ return undefined
210
+ }
211
+
212
+ if (accessCode.type !== 'time_bound') {
213
+ return undefined
213
214
  }
214
215
 
215
- return { submit, isLoading }
216
+ return accessCode[date]
216
217
  }
217
218
 
218
219
  const t = {
219
220
  addNewAccessCode: 'Add new access code',
221
+ editAccessCode: 'Edit access code',
220
222
  overCharacterLimitError: '60 characters max',
221
223
  nameInputLabel: 'Name the new code',
222
224
  cancel: 'Cancel',
@@ -1,3 +1,3 @@
1
- const seamapiReactVersion = '1.41.1'
1
+ const seamapiReactVersion = '1.42.0'
2
2
 
3
3
  export default seamapiReactVersion
@@ -79,6 +79,11 @@
79
79
  }
80
80
  }
81
81
 
82
+ .seam-actions {
83
+ margin-bottom: 16px;
84
+ padding: 0 24px;
85
+ }
86
+
82
87
  .seam-details {
83
88
  font-size: 16px;
84
89
  line-height: 134%;
@@ -82,7 +82,7 @@
82
82
  }
83
83
 
84
84
  .seam-access-code-table-action-menu {
85
- .menu-item-copy {
85
+ .seam-menu-item-copy {
86
86
  display: flex;
87
87
  align-items: center;
88
88
  justify-content: space-between;
@@ -43,6 +43,12 @@
43
43
  background: colors.$item-hover-bg;
44
44
  }
45
45
  }
46
+
47
+ .seam-divider {
48
+ height: 1px;
49
+ background: colors.$divider-stroke-light;
50
+ margin: 8px 0;
51
+ }
46
52
  }
47
53
 
48
54
  .seam-menu-shadow {