@seamapi/react 0.17.0 → 0.19.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 +23 -0
- package/lib/seam/access-codes/use-access-code.d.ts +3 -6
- package/lib/seam/access-codes/use-access-code.js +4 -19
- package/lib/seam/access-codes/use-access-code.js.map +1 -1
- package/lib/seam/access-codes/use-access-codes.d.ts +1 -5
- package/lib/seam/access-codes/use-access-codes.js +2 -1
- package/lib/seam/access-codes/use-access-codes.js.map +1 -1
- package/lib/seam/devices/use-device.d.ts +2 -2
- package/lib/seam/devices/use-device.js.map +1 -1
- package/lib/seam/devices/use-devices.js +2 -1
- package/lib/seam/devices/use-devices.js.map +1 -1
- package/lib/sort-by.d.ts +5 -0
- package/lib/sort-by.js +9 -0
- package/lib/sort-by.js.map +1 -0
- package/lib/ui/AccessCodeDetails/AccessCodeDetails.d.ts +4 -2
- package/lib/ui/AccessCodeDetails/AccessCodeDetails.js +11 -10
- package/lib/ui/AccessCodeDetails/AccessCodeDetails.js.map +1 -1
- package/lib/ui/AccessCodeDetails/AccessCodeDevice.d.ts +4 -2
- package/lib/ui/AccessCodeDetails/AccessCodeDevice.js +3 -6
- package/lib/ui/AccessCodeDetails/AccessCodeDevice.js.map +1 -1
- package/lib/ui/AccessCodeTable/AccessCodeTable.d.ts +2 -1
- package/lib/ui/AccessCodeTable/AccessCodeTable.js +15 -10
- package/lib/ui/AccessCodeTable/AccessCodeTable.js.map +1 -1
- package/lib/ui/AccessCodeTable/AccessCodeTableContent.d.ts +1 -0
- package/lib/ui/AccessCodeTable/AccessCodeTableContent.js +2 -2
- package/lib/ui/AccessCodeTable/AccessCodeTableContent.js.map +1 -1
- package/lib/ui/Button.d.ts +1 -1
- package/lib/ui/DeviceDetails/DeviceDetails.d.ts +3 -1
- package/lib/ui/DeviceDetails/DeviceDetails.js +12 -14
- package/lib/ui/DeviceDetails/DeviceDetails.js.map +1 -1
- package/lib/ui/DeviceDetails/DeviceModel.js +1 -1
- package/lib/ui/DeviceDetails/DeviceModel.js.map +1 -1
- package/lib/ui/DeviceTable/DeviceTable.d.ts +1 -1
- package/lib/ui/DeviceTable/DeviceTable.js +18 -8
- package/lib/ui/DeviceTable/DeviceTable.js.map +1 -1
- package/lib/ui/Table/TableCell.d.ts +1 -1
- package/lib/ui/Table/TableCell.js +2 -2
- package/lib/ui/Table/TableCell.js.map +1 -1
- package/lib/ui/TextField/SearchTextField.d.ts +1 -1
- package/lib/ui/TextField/SearchTextField.js +2 -2
- package/lib/ui/TextField/SearchTextField.js.map +1 -1
- package/lib/ui/device/BatteryStatus.d.ts +1 -1
- package/lib/ui/layout/ContentHeader.d.ts +1 -0
- package/lib/ui/layout/ContentHeader.js +3 -5
- package/lib/ui/layout/ContentHeader.js.map +1 -1
- package/package.json +2 -5
- package/src/lib/seam/access-codes/use-access-code.ts +18 -29
- package/src/lib/seam/access-codes/use-access-codes.ts +8 -10
- package/src/lib/seam/devices/use-device.ts +4 -1
- package/src/lib/seam/devices/use-devices.ts +2 -4
- package/src/lib/sort-by.ts +11 -0
- package/src/lib/ui/AccessCodeDetails/AccessCodeDetails.tsx +28 -18
- package/src/lib/ui/AccessCodeDetails/AccessCodeDevice.tsx +11 -6
- package/src/lib/ui/AccessCodeTable/AccessCodeTable.tsx +29 -14
- package/src/lib/ui/AccessCodeTable/AccessCodeTableContent.tsx +4 -7
- package/src/lib/ui/Button.tsx +1 -1
- package/src/lib/ui/DeviceDetails/DeviceDetails.tsx +22 -18
- package/src/lib/ui/DeviceDetails/DeviceModel.tsx +1 -1
- package/src/lib/ui/DeviceTable/DeviceTable.tsx +39 -10
- package/src/lib/ui/Table/TableCell.tsx +2 -4
- package/src/lib/ui/TextField/SearchTextField.tsx +2 -2
- package/src/lib/ui/device/BatteryStatus.tsx +2 -2
- package/src/lib/ui/device/LockStatus.tsx +1 -1
- package/src/lib/ui/device/OnlineStatus.tsx +1 -1
- package/src/lib/ui/layout/ContentHeader.tsx +7 -7
- package/lib/NavigationProvider.d.ts +0 -27
- package/lib/NavigationProvider.js +0 -36
- package/lib/NavigationProvider.js.map +0 -1
- package/lib/NavigationView.d.ts +0 -5
- package/lib/NavigationView.js +0 -25
- package/lib/NavigationView.js.map +0 -1
- package/src/lib/NavigationProvider.tsx +0 -86
- package/src/lib/NavigationView.tsx +0 -32
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { DivProps } from '../../../lib/ui/types.js';
|
|
2
|
-
export declare function TableCell({ className, ...
|
|
2
|
+
export declare function TableCell({ className, ...props }: DivProps): JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
export function TableCell({ className, ...
|
|
4
|
-
return
|
|
3
|
+
export function TableCell({ className, ...props }) {
|
|
4
|
+
return _jsx("div", { className: classNames('seam-table-cell', className), ...props });
|
|
5
5
|
}
|
|
6
6
|
//# sourceMappingURL=TableCell.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableCell.js","sourceRoot":"","sources":["../../../src/lib/ui/Table/TableCell.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAInC,MAAM,UAAU,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"TableCell.js","sourceRoot":"","sources":["../../../src/lib/ui/Table/TableCell.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAInC,MAAM,UAAU,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAY;IACzD,OAAO,cAAK,SAAS,EAAE,UAAU,CAAC,iBAAiB,EAAE,SAAS,CAAC,KAAM,KAAK,GAAI,CAAA;AAChF,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type TextFieldProps } from '../../../lib/ui/TextField/TextField.js';
|
|
2
|
-
export declare function SearchTextField({ className, ...
|
|
2
|
+
export declare function SearchTextField({ className, ...props }: TextFieldProps): JSX.Element;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { TextField } from '../../../lib/ui/TextField/TextField.js';
|
|
4
|
-
export function SearchTextField({ className, ...
|
|
5
|
-
return (_jsx(TextField, { ...
|
|
4
|
+
export function SearchTextField({ className, ...props }) {
|
|
5
|
+
return (_jsx(TextField, { ...props, className: classNames(className, 'seam-search-text-field') }));
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=SearchTextField.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchTextField.js","sourceRoot":"","sources":["../../../src/lib/ui/TextField/SearchTextField.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAEnC,OAAO,EAAE,SAAS,EAAuB,MAAM,+BAA+B,CAAA;AAE9E,MAAM,UAAU,eAAe,CAAC,EAC9B,SAAS,EACT,GAAG,
|
|
1
|
+
{"version":3,"file":"SearchTextField.js","sourceRoot":"","sources":["../../../src/lib/ui/TextField/SearchTextField.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAEnC,OAAO,EAAE,SAAS,EAAuB,MAAM,+BAA+B,CAAA;AAE9E,MAAM,UAAU,eAAe,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACO;IACf,OAAO,CACL,KAAC,SAAS,OACJ,KAAK,EACT,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,wBAAwB,CAAC,GAC1D,CACH,CAAA;AACH,CAAC"}
|
|
@@ -2,4 +2,4 @@ import type { LockDevice } from 'seamapi';
|
|
|
2
2
|
export interface BatteryStatusProps {
|
|
3
3
|
device: LockDevice;
|
|
4
4
|
}
|
|
5
|
-
export declare function BatteryStatus(props: BatteryStatusProps):
|
|
5
|
+
export declare function BatteryStatus(props: BatteryStatusProps): JSX.Element;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ArrowBackIcon } from '../../../lib/icons/ArrowBack.js';
|
|
3
|
-
import { useNavigation } from '../../../lib/NavigationProvider.js';
|
|
4
3
|
export function ContentHeader(props) {
|
|
5
|
-
const { title } = props;
|
|
6
|
-
|
|
7
|
-
if (!title && !goBack) {
|
|
4
|
+
const { title, onBack } = props;
|
|
5
|
+
if (title == null && onBack == null) {
|
|
8
6
|
return null;
|
|
9
7
|
}
|
|
10
|
-
return (_jsxs("div", { className: 'seam-content-header', children: [
|
|
8
|
+
return (_jsxs("div", { className: 'seam-content-header', children: [_jsx(BackIcon, { onClick: onBack }), _jsx("span", { className: 'seam-title', children: title })] }));
|
|
11
9
|
}
|
|
12
10
|
function BackIcon(props) {
|
|
13
11
|
if (props.onClick == null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentHeader.js","sourceRoot":"","sources":["../../../src/lib/ui/layout/ContentHeader.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"ContentHeader.js","sourceRoot":"","sources":["../../../src/lib/ui/layout/ContentHeader.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAEtD,MAAM,UAAU,aAAa,CAAC,KAG7B;IACC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAC/B,IAAI,KAAK,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,EAAE;QACnC,OAAO,IAAI,CAAA;KACZ;IAED,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,QAAQ,IAAC,OAAO,EAAE,MAAM,GAAI,EAC7B,eAAM,SAAS,EAAC,YAAY,YAAE,KAAK,GAAQ,IACvC,CACP,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAA+B;IAC/C,IAAI,KAAK,CAAC,OAAO,IAAI,IAAI,EAAE;QACzB,OAAO,IAAI,CAAA;KACZ;IAED,OAAO,KAAC,aAAa,IAAC,SAAS,EAAC,gBAAgB,EAAC,OAAO,EAAE,KAAK,CAAC,OAAO,GAAI,CAAA;AAC7E,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seamapi/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Seam React component library.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -58,7 +58,6 @@
|
|
|
58
58
|
"docs:build": "storybook build --docs --output-dir docs",
|
|
59
59
|
"predocs:build": "npm run examples:build",
|
|
60
60
|
"typecheck": "tsc",
|
|
61
|
-
"dependencies": "dpdm --exit-code circular:1 src/index.ts",
|
|
62
61
|
"test": "jest --collect-coverage",
|
|
63
62
|
"test:update": "jest --updateSnapshot",
|
|
64
63
|
"test:watch": "jest --watch",
|
|
@@ -95,7 +94,7 @@
|
|
|
95
94
|
"@tanstack/react-query": "^4.28.0",
|
|
96
95
|
"classnames": "^2.3.2",
|
|
97
96
|
"luxon": "^3.3.0",
|
|
98
|
-
"seamapi": "^5.21.
|
|
97
|
+
"seamapi": "^5.21.1",
|
|
99
98
|
"uuid": "^9.0.0"
|
|
100
99
|
},
|
|
101
100
|
"devDependencies": {
|
|
@@ -126,7 +125,6 @@
|
|
|
126
125
|
"concurrently": "^8.0.1",
|
|
127
126
|
"copy-webpack-plugin": "^11.0.0",
|
|
128
127
|
"del-cli": "^5.0.0",
|
|
129
|
-
"dpdm": "^3.13.0",
|
|
130
128
|
"eslint": "^8.9.0",
|
|
131
129
|
"eslint-config-prettier": "^8.4.0",
|
|
132
130
|
"eslint-config-standard-jsx": "^11.0.0",
|
|
@@ -137,7 +135,6 @@
|
|
|
137
135
|
"eslint-plugin-unused-imports": "^2.0.0",
|
|
138
136
|
"fast-glob": "^3.2.12",
|
|
139
137
|
"http-proxy-middleware": "^2.0.6",
|
|
140
|
-
"isomorphic-fetch": "^3.0.0",
|
|
141
138
|
"jest": "^29.5.0",
|
|
142
139
|
"jest-environment-jsdom": "^29.5.0",
|
|
143
140
|
"prettier": "^2.3.0",
|
|
@@ -1,45 +1,34 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import type {
|
|
3
|
+
AccessCode,
|
|
4
|
+
AccessCodeGetRequest,
|
|
5
|
+
AccessCodeGetResponse,
|
|
6
|
+
SeamError,
|
|
7
|
+
} from 'seamapi'
|
|
5
8
|
|
|
6
9
|
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
10
|
+
import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
|
|
7
11
|
|
|
8
12
|
export type UseAccessCodeParams = AccessCodeGetRequest | string
|
|
9
|
-
export type UseAccessCodeData = AccessCode
|
|
10
|
-
|
|
11
|
-
export function useAccessCode(params: UseAccessCodeParams) {
|
|
12
|
-
const { client } = useSeamClient()
|
|
13
|
+
export type UseAccessCodeData = AccessCode | null
|
|
13
14
|
|
|
15
|
+
export function useAccessCode(
|
|
16
|
+
params: UseAccessCodeParams
|
|
17
|
+
): UseSeamQueryResult<'accessCode', UseAccessCodeData> {
|
|
14
18
|
const normalizedParams =
|
|
15
19
|
typeof params === 'string' ? { access_code_id: params } : params
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
const { client } = useSeamClient()
|
|
22
|
+
const { data, ...rest } = useQuery<
|
|
23
|
+
AccessCodeGetResponse['access_code'] | null,
|
|
24
|
+
SeamError
|
|
25
|
+
>({
|
|
18
26
|
enabled: client != null,
|
|
19
|
-
queryKey: ['
|
|
27
|
+
queryKey: ['access_codes', 'get', normalizedParams],
|
|
20
28
|
queryFn: async () => {
|
|
21
29
|
if (client == null) return null
|
|
22
|
-
|
|
23
30
|
return await client?.accessCodes.get(normalizedParams)
|
|
24
31
|
},
|
|
25
32
|
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function useFakeAccessCode(_params: UseAccessCodeParams): {
|
|
29
|
-
isLoading: boolean
|
|
30
|
-
data: AccessCode
|
|
31
|
-
} {
|
|
32
|
-
const accessCode: AccessCode = {
|
|
33
|
-
access_code_id: uuid(),
|
|
34
|
-
type: 'time_bound',
|
|
35
|
-
starts_at: DateTime.now().minus({ days: 2 }).toISO() ?? '',
|
|
36
|
-
ends_at: DateTime.now().plus({ days: 1 }).toISO() ?? '',
|
|
37
|
-
code: '1234',
|
|
38
|
-
created_at: DateTime.now().toISO() ?? '',
|
|
39
|
-
device_id: 'some_device_id',
|
|
40
|
-
status: 'set',
|
|
41
|
-
name: 'Guest - Kranz',
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return { isLoading: false, data: accessCode }
|
|
33
|
+
return { ...rest, accessCode: data }
|
|
45
34
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query'
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
AccessCode,
|
|
4
|
+
AccessCodesListRequest,
|
|
5
|
+
AccessCodesListResponse,
|
|
6
|
+
SeamError,
|
|
7
|
+
} from 'seamapi'
|
|
3
8
|
|
|
4
9
|
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
5
10
|
import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
|
|
11
|
+
import { byCreatedAt } from 'lib/sort-by.js'
|
|
6
12
|
|
|
7
13
|
export type UseAccessCodesParams = AccessCodesListRequest | string
|
|
8
14
|
export type UseAccessCodesData = AccessCode[]
|
|
@@ -23,17 +29,9 @@ export function useAccessCodes(
|
|
|
23
29
|
queryFn: async () => {
|
|
24
30
|
if (client == null) return []
|
|
25
31
|
const accessCodes = await client?.accessCodes.list(normalizedParams)
|
|
26
|
-
return accessCodes.sort(
|
|
27
|
-
(a, b) =>
|
|
28
|
-
new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
29
|
-
)
|
|
32
|
+
return accessCodes.sort(byCreatedAt)
|
|
30
33
|
},
|
|
31
34
|
})
|
|
32
35
|
|
|
33
36
|
return { ...rest, accessCodes: data }
|
|
34
37
|
}
|
|
35
|
-
|
|
36
|
-
// UPSTREAM: https://github.com/seamapi/javascript/pull/200
|
|
37
|
-
interface AccessCodesListRequest {
|
|
38
|
-
device_id: string
|
|
39
|
-
}
|
|
@@ -36,7 +36,10 @@ export function useDevice(
|
|
|
36
36
|
return { ...rest, device: data }
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
export function useFakeDevice(_params: DeviceGetRequest) {
|
|
39
|
+
export function useFakeDevice(_params: DeviceGetRequest): {
|
|
40
|
+
isLoading: boolean
|
|
41
|
+
device: UseDeviceData
|
|
42
|
+
} {
|
|
40
43
|
const device: LockDevice = {
|
|
41
44
|
device_id: 'f9a9ab36-9e14-4390-a88c-b4c78304c6aa',
|
|
42
45
|
device_type: 'august_lock',
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
|
|
10
10
|
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
11
11
|
import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
|
|
12
|
+
import { byCreatedAt } from 'lib/sort-by.js'
|
|
12
13
|
|
|
13
14
|
export type UseDevicesParams = DevicesListRequest
|
|
14
15
|
export type UseDevicesData = Array<Device<CommonDeviceProperties>>
|
|
@@ -24,10 +25,7 @@ export function useDevices(
|
|
|
24
25
|
queryFn: async () => {
|
|
25
26
|
if (client == null) return []
|
|
26
27
|
const devices = await client?.devices.list(params)
|
|
27
|
-
return devices.sort(
|
|
28
|
-
(a, b) =>
|
|
29
|
-
new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
30
|
-
)
|
|
28
|
+
return devices.sort(byCreatedAt)
|
|
31
29
|
},
|
|
32
30
|
}
|
|
33
31
|
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DateTime } from 'luxon'
|
|
2
|
+
|
|
3
|
+
export const byCreatedAt = (
|
|
4
|
+
a: { created_at: string },
|
|
5
|
+
b: { created_at: string }
|
|
6
|
+
): number => {
|
|
7
|
+
const t1 = DateTime.fromISO(a.created_at)
|
|
8
|
+
const t2 = DateTime.fromISO(b.created_at)
|
|
9
|
+
if (!t1.isValid || !t2.isValid) return 0
|
|
10
|
+
return t1.toMillis() - t2.toMillis()
|
|
11
|
+
}
|
|
@@ -1,31 +1,38 @@
|
|
|
1
1
|
import { DateTime } from 'luxon'
|
|
2
|
-
import
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import type { AccessCode, CommonDeviceProperties, Device } from 'seamapi'
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import AccessCodeDevice from 'lib/ui/AccessCodeDetails/AccessCodeDevice.js'
|
|
5
|
+
import { AccessCodeDevice } from 'lib/ui/AccessCodeDetails/AccessCodeDevice.js'
|
|
6
|
+
import { DeviceDetails } from 'lib/ui/DeviceDetails/DeviceDetails.js'
|
|
7
7
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
8
8
|
|
|
9
9
|
export interface AccessCodeDetailsProps {
|
|
10
|
-
|
|
10
|
+
accessCode: AccessCode
|
|
11
|
+
onBack?: () => void
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
export function AccessCodeDetails({
|
|
15
|
+
accessCode,
|
|
16
|
+
onBack,
|
|
17
|
+
}: AccessCodeDetailsProps): JSX.Element {
|
|
18
|
+
const name = accessCode.name ?? t.fallbackName
|
|
19
|
+
const [selectedDevice, selectDevice] =
|
|
20
|
+
useState<Device<CommonDeviceProperties> | null>(null)
|
|
19
21
|
|
|
20
|
-
if (
|
|
21
|
-
return
|
|
22
|
+
if (selectedDevice != null) {
|
|
23
|
+
return (
|
|
24
|
+
<DeviceDetails
|
|
25
|
+
device={selectedDevice}
|
|
26
|
+
onBack={() => {
|
|
27
|
+
selectDevice(null)
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
)
|
|
22
31
|
}
|
|
23
32
|
|
|
24
|
-
const name = accessCode.name ?? t.fallbackName
|
|
25
|
-
|
|
26
33
|
return (
|
|
27
34
|
<div className='seam-access-code-details'>
|
|
28
|
-
<ContentHeader title='Access code' />
|
|
35
|
+
<ContentHeader title='Access code' onBack={onBack} />
|
|
29
36
|
<div className='seam-summary'>
|
|
30
37
|
<div className='seam-top'>
|
|
31
38
|
<span className='seam-label'>{t.accessCode}</span>
|
|
@@ -35,7 +42,10 @@ export default function AccessCodeDetails({
|
|
|
35
42
|
<Duration accessCode={accessCode} />
|
|
36
43
|
</div>
|
|
37
44
|
</div>
|
|
38
|
-
<AccessCodeDevice
|
|
45
|
+
<AccessCodeDevice
|
|
46
|
+
deviceId={accessCode.device_id}
|
|
47
|
+
onSelectDevice={selectDevice}
|
|
48
|
+
/>
|
|
39
49
|
</div>
|
|
40
50
|
<div className='seam-details'>
|
|
41
51
|
<div className='seam-row'>
|
|
@@ -60,7 +70,7 @@ export default function AccessCodeDetails({
|
|
|
60
70
|
)
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
function ScheduleInfo({ accessCode }: { accessCode: AccessCode }) {
|
|
73
|
+
function ScheduleInfo({ accessCode }: { accessCode: AccessCode }): JSX.Element {
|
|
64
74
|
if (accessCode.type === 'ongoing') {
|
|
65
75
|
return <span>{t.ongoing}</span>
|
|
66
76
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CommonDeviceProperties, Device } from 'seamapi'
|
|
2
|
+
|
|
2
3
|
import { isLockDevice } from 'lib/seam/devices/types.js'
|
|
3
4
|
import { useFakeDevice } from 'lib/seam/devices/use-device.js'
|
|
4
5
|
import { Button } from 'lib/ui/Button.js'
|
|
@@ -6,13 +7,17 @@ import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
|
|
|
6
7
|
import { getDeviceModel } from 'lib/ui/DeviceDetails/DeviceModel.js'
|
|
7
8
|
import { TextButton } from 'lib/ui/TextButton.js'
|
|
8
9
|
|
|
9
|
-
export
|
|
10
|
+
export function AccessCodeDevice({
|
|
11
|
+
deviceId,
|
|
12
|
+
onSelectDevice,
|
|
13
|
+
}: {
|
|
14
|
+
deviceId: string
|
|
15
|
+
onSelectDevice: (device: Device<CommonDeviceProperties>) => void
|
|
16
|
+
}): JSX.Element | null {
|
|
10
17
|
// TODO: Replace with `useDevice()` once ready
|
|
11
18
|
const { isLoading, device } = useFakeDevice({ device_id: deviceId })
|
|
12
|
-
const { show } = useNavigation()
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
if (isLoading || !device || !isLockDevice(device)) {
|
|
20
|
+
if (isLoading || device == null || !isLockDevice(device)) {
|
|
16
21
|
return null
|
|
17
22
|
}
|
|
18
23
|
|
|
@@ -27,7 +32,7 @@ export default function AccessCodeDevice({ deviceId }: { deviceId: string }) {
|
|
|
27
32
|
<div className='seam-model'>{model}</div>
|
|
28
33
|
<TextButton
|
|
29
34
|
onClick={() => {
|
|
30
|
-
|
|
35
|
+
onSelectDevice(device)
|
|
31
36
|
}}
|
|
32
37
|
>
|
|
33
38
|
{t.deviceDetails}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import type { AccessCode } from 'seamapi'
|
|
3
|
+
|
|
1
4
|
import { AccessCodeKeyIcon } from 'lib/icons/AccessCodeKey.js'
|
|
2
|
-
import { useNavigation } from 'lib/NavigationProvider.js'
|
|
3
5
|
import { useAccessCodes } from 'lib/seam/access-codes/use-access-codes.js'
|
|
6
|
+
import { AccessCodeDetails } from 'lib/ui/AccessCodeDetails/AccessCodeDetails.js'
|
|
4
7
|
import { CodeDetails } from 'lib/ui/AccessCodeTable/CodeDetails.js'
|
|
5
8
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
6
9
|
import { TableBody } from 'lib/ui/Table/TableBody.js'
|
|
@@ -11,18 +14,37 @@ import { TableTitle } from 'lib/ui/Table/TableTitle.js'
|
|
|
11
14
|
import { Caption } from 'lib/ui/typography/Caption.js'
|
|
12
15
|
import { Title } from 'lib/ui/typography/Title.js'
|
|
13
16
|
|
|
14
|
-
export function AccessCodeTable(props: {
|
|
17
|
+
export function AccessCodeTable(props: {
|
|
18
|
+
deviceId: string
|
|
19
|
+
onBack?: () => void
|
|
20
|
+
}): JSX.Element | null {
|
|
15
21
|
const { accessCodes } = useAccessCodes({
|
|
16
22
|
device_id: props.deviceId,
|
|
17
23
|
})
|
|
24
|
+
const { onBack } = props
|
|
25
|
+
|
|
26
|
+
const [selectedAccessCode, selectAccessCode] = useState<AccessCode | null>(
|
|
27
|
+
null
|
|
28
|
+
)
|
|
18
29
|
|
|
19
|
-
|
|
30
|
+
if (selectedAccessCode != null) {
|
|
31
|
+
return (
|
|
32
|
+
<AccessCodeDetails
|
|
33
|
+
accessCode={selectedAccessCode}
|
|
34
|
+
onBack={() => {
|
|
35
|
+
selectAccessCode(null)
|
|
36
|
+
}}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
20
40
|
|
|
21
|
-
if (
|
|
41
|
+
if (accessCodes == null) {
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
22
44
|
|
|
23
45
|
return (
|
|
24
46
|
<div className='seam-access-code-table'>
|
|
25
|
-
<ContentHeader />
|
|
47
|
+
<ContentHeader onBack={onBack} />
|
|
26
48
|
<TableHeader>
|
|
27
49
|
<TableTitle>
|
|
28
50
|
{t.accessCodes} <Caption>({accessCodes.length})</Caption>
|
|
@@ -33,10 +55,7 @@ export function AccessCodeTable(props: { deviceId: string }): JSX.Element {
|
|
|
33
55
|
<TableRow
|
|
34
56
|
key={code.access_code_id}
|
|
35
57
|
onClick={() => {
|
|
36
|
-
|
|
37
|
-
name: 'access_code_detail',
|
|
38
|
-
accessCodeId: code.access_code_id,
|
|
39
|
-
})
|
|
58
|
+
selectAccessCode(code)
|
|
40
59
|
}}
|
|
41
60
|
>
|
|
42
61
|
<TableCell className='seam-icon-cell'>
|
|
@@ -48,11 +67,7 @@ export function AccessCodeTable(props: { deviceId: string }): JSX.Element {
|
|
|
48
67
|
<Title>{code.name}</Title>
|
|
49
68
|
<CodeDetails accessCode={code} />
|
|
50
69
|
</TableCell>
|
|
51
|
-
<TableCell className='seam-action-cell'
|
|
52
|
-
{/* <IconButton>
|
|
53
|
-
<DotsEllipsisMoreIcon />
|
|
54
|
-
</IconButton> */}
|
|
55
|
-
</TableCell>
|
|
70
|
+
<TableCell className='seam-action-cell' />
|
|
56
71
|
</TableRow>
|
|
57
72
|
))}
|
|
58
73
|
</TableBody>
|
|
@@ -13,16 +13,17 @@ import { Title } from 'lib/ui/typography/Title.js'
|
|
|
13
13
|
|
|
14
14
|
export interface AccessCodeTableContentProps {
|
|
15
15
|
accessCodes: AccessCode[]
|
|
16
|
+
onBack?: () => void
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export function AccessCodeTableContent(
|
|
19
20
|
props: AccessCodeTableContentProps
|
|
20
21
|
): JSX.Element {
|
|
21
|
-
const { accessCodes } = props
|
|
22
|
+
const { accessCodes, onBack } = props
|
|
22
23
|
|
|
23
24
|
return (
|
|
24
25
|
<div className='seam-access-code-table'>
|
|
25
|
-
<ContentHeader />
|
|
26
|
+
<ContentHeader onBack={onBack} />
|
|
26
27
|
<TableHeader>
|
|
27
28
|
<TableTitle>
|
|
28
29
|
{t.accessCodes} <Caption>({accessCodes.length})</Caption>
|
|
@@ -40,11 +41,7 @@ export function AccessCodeTableContent(
|
|
|
40
41
|
<Title>{code.name}</Title>
|
|
41
42
|
<CodeDetails accessCode={code} />
|
|
42
43
|
</TableCell>
|
|
43
|
-
<TableCell className='seam-action-cell'
|
|
44
|
-
{/* <IconButton>
|
|
45
|
-
<DotsEllipsisMoreIcon />
|
|
46
|
-
</IconButton> */}
|
|
47
|
-
</TableCell>
|
|
44
|
+
<TableCell className='seam-action-cell' />
|
|
48
45
|
</TableRow>
|
|
49
46
|
))}
|
|
50
47
|
</TableBody>
|
package/src/lib/ui/Button.tsx
CHANGED
|
@@ -1,38 +1,44 @@
|
|
|
1
|
+
import { type CommonDeviceProperties, type Device } from 'seamapi'
|
|
2
|
+
|
|
1
3
|
import { ChevronRightIcon } from 'lib/icons/ChevronRight.js'
|
|
2
|
-
import { useNavigation } from 'lib/NavigationProvider.js'
|
|
3
4
|
import { useAccessCodes } from 'lib/seam/access-codes/use-access-codes.js'
|
|
4
5
|
import { isLockDevice } from 'lib/seam/devices/types.js'
|
|
5
|
-
import {
|
|
6
|
+
import { AccessCodeTable } from 'lib/ui/AccessCodeTable/AccessCodeTable.js'
|
|
6
7
|
import { Button } from 'lib/ui/Button.js'
|
|
7
8
|
import { BatteryStatus } from 'lib/ui/device/BatteryStatus.js'
|
|
8
9
|
import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
|
|
9
10
|
import { OnlineStatus } from 'lib/ui/device/OnlineStatus.js'
|
|
10
11
|
import { DeviceModel } from 'lib/ui/DeviceDetails/DeviceModel.js'
|
|
11
12
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
13
|
+
import useToggle from 'lib/use-toggle.js'
|
|
12
14
|
|
|
13
15
|
export interface DeviceDetailsProps {
|
|
14
|
-
|
|
16
|
+
device: Device<CommonDeviceProperties>
|
|
17
|
+
onBack?: () => void
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export function DeviceDetails(props: DeviceDetailsProps): JSX.Element | null {
|
|
18
|
-
const {
|
|
21
|
+
const { device, onBack } = props
|
|
19
22
|
|
|
20
|
-
const
|
|
21
|
-
device_id: deviceId,
|
|
22
|
-
})
|
|
23
|
+
const [accessCodesOpen, toggleAccessCodesOpen] = useToggle()
|
|
23
24
|
|
|
24
|
-
const { isLoading
|
|
25
|
-
device_id:
|
|
25
|
+
const { isLoading, accessCodes } = useAccessCodes({
|
|
26
|
+
device_id: device.device_id,
|
|
26
27
|
})
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const { show } = useNavigation()
|
|
31
|
-
|
|
32
|
-
if (isLoading || !device) {
|
|
29
|
+
if (isLoading) {
|
|
33
30
|
return null
|
|
34
31
|
}
|
|
35
32
|
|
|
33
|
+
if (accessCodesOpen) {
|
|
34
|
+
return (
|
|
35
|
+
<AccessCodeTable
|
|
36
|
+
deviceId={device.device_id}
|
|
37
|
+
onBack={toggleAccessCodesOpen}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
36
42
|
if (!isLockDevice(device)) {
|
|
37
43
|
return null
|
|
38
44
|
}
|
|
@@ -46,7 +52,7 @@ export function DeviceDetails(props: DeviceDetailsProps): JSX.Element | null {
|
|
|
46
52
|
|
|
47
53
|
return (
|
|
48
54
|
<div className='seam-device-details'>
|
|
49
|
-
<ContentHeader title='Device' />
|
|
55
|
+
<ContentHeader title='Device' onBack={onBack} />
|
|
50
56
|
<div className='seam-body'>
|
|
51
57
|
<div className='seam-summary'>
|
|
52
58
|
<div className='seam-content'>
|
|
@@ -69,9 +75,7 @@ export function DeviceDetails(props: DeviceDetailsProps): JSX.Element | null {
|
|
|
69
75
|
<div className='seam-box'>
|
|
70
76
|
<div
|
|
71
77
|
className='seam-content seam-access-codes'
|
|
72
|
-
onClick={
|
|
73
|
-
show({ name: 'access_code_table', deviceId: device.device_id })
|
|
74
|
-
}}
|
|
78
|
+
onClick={toggleAccessCodesOpen}
|
|
75
79
|
>
|
|
76
80
|
<span className='seam-value'>
|
|
77
81
|
{accessCodeCount} {t.accessCodes}
|