@seamapi/react 1.21.0 → 1.23.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/dist/elements.js +3698 -3585
- package/dist/elements.js.map +1 -1
- package/dist/index.css +6 -0
- package/dist/index.css.map +1 -1
- package/dist/index.min.css +1 -1
- package/dist/index.min.css.map +1 -1
- package/lib/icons/TriangleWarningOutline.d.ts +2 -0
- package/lib/icons/TriangleWarningOutline.js +3 -0
- package/lib/icons/TriangleWarningOutline.js.map +1 -0
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.d.ts +2 -1
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js +23 -3
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js.map +1 -1
- package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.d.ts +2 -1
- package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js +8 -6
- package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js.map +1 -1
- package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.d.ts +10 -0
- package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.js +29 -0
- package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.js.map +1 -0
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.d.ts +2 -1
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.js +30 -10
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.js.map +1 -1
- package/lib/seam/components/DeviceDetails/DeviceDetails.d.ts +2 -1
- package/lib/seam/components/DeviceDetails/DeviceDetails.js +2 -2
- package/lib/seam/components/DeviceDetails/DeviceDetails.js.map +1 -1
- package/lib/seam/components/DeviceDetails/LockDeviceDetails.d.ts +1 -0
- package/lib/seam/components/DeviceDetails/LockDeviceDetails.js +4 -4
- package/lib/seam/components/DeviceDetails/LockDeviceDetails.js.map +1 -1
- package/lib/seam/components/DeviceTable/DeviceTable.d.ts +2 -1
- package/lib/seam/components/DeviceTable/DeviceTable.js +2 -2
- package/lib/seam/components/DeviceTable/DeviceTable.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/lib/icons/TriangleWarningOutline.tsx +18 -0
- package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx +47 -2
- package/src/lib/seam/components/AccessCodeDetails/AccessCodeDevice.tsx +23 -10
- package/src/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.tsx +68 -0
- package/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx +47 -6
- package/src/lib/seam/components/DeviceDetails/DeviceDetails.tsx +3 -0
- package/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx +14 -9
- package/src/lib/seam/components/DeviceTable/DeviceTable.tsx +3 -0
- package/src/lib/version.ts +1 -1
- package/src/styles/_access-code-details.scss +4 -0
- package/src/styles/_alert.scss +4 -0
|
@@ -13,7 +13,7 @@ import { OnlineStatus } from '../../../../lib/ui/device/OnlineStatus.js';
|
|
|
13
13
|
import { ContentHeader } from '../../../../lib/ui/layout/ContentHeader.js';
|
|
14
14
|
import { useToggle } from '../../../../lib/ui/use-toggle.js';
|
|
15
15
|
export function LockDeviceDetails(props) {
|
|
16
|
-
const { device, onBack, className } = props;
|
|
16
|
+
const { device, disableLockUnlock, onBack, className } = props;
|
|
17
17
|
const [accessCodesOpen, toggleAccessCodesOpen] = useToggle();
|
|
18
18
|
const toggleLock = useToggleLock(device);
|
|
19
19
|
const { accessCodes } = useAccessCodes({
|
|
@@ -26,7 +26,7 @@ export function LockDeviceDetails(props) {
|
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
28
|
if (accessCodesOpen) {
|
|
29
|
-
return (_jsx(AccessCodeTable, { className: className, deviceId: device.device_id, onBack: toggleAccessCodesOpen }));
|
|
29
|
+
return (_jsx(AccessCodeTable, { className: className, deviceId: device.device_id, onBack: toggleAccessCodesOpen, disableLockUnlock: disableLockUnlock }));
|
|
30
30
|
}
|
|
31
31
|
const alerts = [
|
|
32
32
|
...device.errors.map((error) => ({
|
|
@@ -38,9 +38,9 @@ export function LockDeviceDetails(props) {
|
|
|
38
38
|
message: warning.message,
|
|
39
39
|
})),
|
|
40
40
|
];
|
|
41
|
-
return (_jsxs("div", { className: classNames('seam-device-details', className), children: [_jsx(ContentHeader, { title: 'Device', onBack: onBack }), _jsxs("div", { className: 'seam-body', children: [_jsxs("div", { className: 'seam-summary', children: [_jsxs("div", { className: 'seam-content', children: [_jsx("div", { className: 'seam-image', children: _jsx(DeviceImage, { device: device }) }), _jsxs("div", { className: 'seam-info', children: [_jsx("span", { className: 'seam-label', children: t.device }), _jsx("h4", { className: 'seam-device-name', children: device.properties.name }), _jsxs("div", { className: 'seam-properties', children: [_jsxs("span", { className: 'seam-label', children: [t.status, ":"] }), ' ', _jsx(OnlineStatus, { device: device }), _jsxs("span", { className: 'seam-label', children: [t.power, ":"] }), ' ', _jsx(BatteryStatus, { device: device }), _jsx(DeviceModel, { device: device })] })] })] }), _jsx(Alerts, { alerts: alerts, className: 'seam-alerts-space-top' })] }), _jsx("div", { className: 'seam-box', children: _jsxs("div", { className: 'seam-content seam-access-codes', onClick: toggleAccessCodesOpen, children: [_jsxs("span", { className: 'seam-value', children: [accessCodeCount, " ", t.accessCodes] }), _jsx(ChevronRightIcon, {})] }) }), _jsxs("div", { className: 'seam-box', children: [_jsxs("div", { className: 'seam-content seam-lock-status', children: [_jsxs("div", { children: [_jsx("span", { className: 'seam-label', children: t.lockStatus }), _jsx("span", { className: 'seam-value', children: lockStatus })] }), _jsx("div", { className: 'seam-right', children: _jsx(Button, { size: 'small', onClick: () => {
|
|
41
|
+
return (_jsxs("div", { className: classNames('seam-device-details', className), children: [_jsx(ContentHeader, { title: 'Device', onBack: onBack }), _jsxs("div", { className: 'seam-body', children: [_jsxs("div", { className: 'seam-summary', children: [_jsxs("div", { className: 'seam-content', children: [_jsx("div", { className: 'seam-image', children: _jsx(DeviceImage, { device: device }) }), _jsxs("div", { className: 'seam-info', children: [_jsx("span", { className: 'seam-label', children: t.device }), _jsx("h4", { className: 'seam-device-name', children: device.properties.name }), _jsxs("div", { className: 'seam-properties', children: [_jsxs("span", { className: 'seam-label', children: [t.status, ":"] }), ' ', _jsx(OnlineStatus, { device: device }), _jsxs("span", { className: 'seam-label', children: [t.power, ":"] }), ' ', _jsx(BatteryStatus, { device: device }), _jsx(DeviceModel, { device: device })] })] })] }), _jsx(Alerts, { alerts: alerts, className: 'seam-alerts-space-top' })] }), _jsx("div", { className: 'seam-box', children: _jsxs("div", { className: 'seam-content seam-access-codes', onClick: toggleAccessCodesOpen, children: [_jsxs("span", { className: 'seam-value', children: [accessCodeCount, " ", t.accessCodes] }), _jsx(ChevronRightIcon, {})] }) }), _jsxs("div", { className: 'seam-box', children: [_jsxs("div", { className: 'seam-content seam-lock-status', children: [_jsxs("div", { children: [_jsx("span", { className: 'seam-label', children: t.lockStatus }), _jsx("span", { className: 'seam-value', children: lockStatus })] }), _jsx("div", { className: 'seam-right', children: !disableLockUnlock && (_jsx(Button, { size: 'small', onClick: () => {
|
|
42
42
|
toggleLock.mutate();
|
|
43
|
-
}, children: toggleLockLabel }) })] }), _jsx(AccessCodeLength, { supportedCodeLengths: device.properties?.supported_code_lengths ?? [] })] })] })] }));
|
|
43
|
+
}, children: toggleLockLabel })) })] }), _jsx(AccessCodeLength, { supportedCodeLengths: device.properties?.supported_code_lengths ?? [] })] })] })] }));
|
|
44
44
|
}
|
|
45
45
|
function AccessCodeLength(props) {
|
|
46
46
|
const { supportedCodeLengths } = props;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LockDeviceDetails.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAGnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAA;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,wDAAwD,CAAA;AACxF,OAAO,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"LockDeviceDetails.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx"],"names":[],"mappings":"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"}
|
|
@@ -8,8 +8,9 @@ export interface DeviceTableProps {
|
|
|
8
8
|
deviceComparator?: (deviceA: Device, deviceB: Device) => number;
|
|
9
9
|
onDeviceClick?: (deviceId: string) => void;
|
|
10
10
|
preventDefaultOnDeviceClick?: boolean;
|
|
11
|
+
disableLockUnlock?: boolean;
|
|
11
12
|
onBack?: () => void;
|
|
12
13
|
className?: string;
|
|
13
14
|
}
|
|
14
|
-
export declare function DeviceTable({ deviceIds, connectedAccountIds, onDeviceClick, preventDefaultOnDeviceClick, onBack, deviceFilter, deviceComparator, className, }?: DeviceTableProps): JSX.Element;
|
|
15
|
+
export declare function DeviceTable({ deviceIds, connectedAccountIds, onDeviceClick, preventDefaultOnDeviceClick, disableLockUnlock, onBack, deviceFilter, deviceComparator, className, }?: DeviceTableProps): JSX.Element;
|
|
15
16
|
export {};
|
|
@@ -20,7 +20,7 @@ const defaultDeviceFilter = (device, searchInputValue) => {
|
|
|
20
20
|
return true;
|
|
21
21
|
return new RegExp(value, 'i').test(device.properties.name ?? '');
|
|
22
22
|
};
|
|
23
|
-
export function DeviceTable({ deviceIds, connectedAccountIds, onDeviceClick = () => { }, preventDefaultOnDeviceClick = false, onBack, deviceFilter = defaultDeviceFilter, deviceComparator = compareByCreatedAtDesc, className, } = {}) {
|
|
23
|
+
export function DeviceTable({ deviceIds, connectedAccountIds, onDeviceClick = () => { }, preventDefaultOnDeviceClick = false, disableLockUnlock = false, onBack, deviceFilter = defaultDeviceFilter, deviceComparator = compareByCreatedAtDesc, className, } = {}) {
|
|
24
24
|
const { devices, isLoading, isError, error } = useDevices({
|
|
25
25
|
device_ids: deviceIds,
|
|
26
26
|
connected_account_ids: connectedAccountIds,
|
|
@@ -40,7 +40,7 @@ export function DeviceTable({ deviceIds, connectedAccountIds, onDeviceClick = ()
|
|
|
40
40
|
if (selectedDeviceId != null) {
|
|
41
41
|
return (_jsx(DeviceDetails, { className: className, deviceId: selectedDeviceId, onBack: () => {
|
|
42
42
|
setSelectedDeviceId(null);
|
|
43
|
-
} }));
|
|
43
|
+
}, disableLockUnlock: disableLockUnlock }));
|
|
44
44
|
}
|
|
45
45
|
if (isLoading) {
|
|
46
46
|
return _jsx("p", { className: className, children: "..." });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceTable.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceTable/DeviceTable.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,oDAAoD,CAAA;AAClF,OAAO,EAEL,eAAe,GAChB,MAAM,oDAAoD,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,8CAA8C,CAAA;AACxE,OAAO,EACL,UAAU,GAEX,MAAM,iCAAiC,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;
|
|
1
|
+
{"version":3,"file":"DeviceTable.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceTable/DeviceTable.tsx"],"names":[],"mappings":"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"}
|
package/lib/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const seamapiReactVersion = "1.
|
|
1
|
+
declare const seamapiReactVersion = "1.23.0";
|
|
2
2
|
export default seamapiReactVersion;
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
export const TriangleWarningOutlineIcon = (
|
|
3
|
+
props: SVGProps<SVGSVGElement>
|
|
4
|
+
): JSX.Element => (
|
|
5
|
+
<svg
|
|
6
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
7
|
+
width={24}
|
|
8
|
+
height={24}
|
|
9
|
+
fill='none'
|
|
10
|
+
{...props}
|
|
11
|
+
>
|
|
12
|
+
<path
|
|
13
|
+
fill='#FF9800'
|
|
14
|
+
d='m12 6.49 7.53 13.01H4.47L12 6.49Zm0-3.99-11 19h22l-11-19Z'
|
|
15
|
+
/>
|
|
16
|
+
<path fill='#FF9800' d='M13 16.5h-2v2h2v-2ZM13 10.5h-2v5h2v-5Z' />
|
|
17
|
+
</svg>
|
|
18
|
+
)
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
import classNames from 'classnames'
|
|
2
2
|
import { DateTime } from 'luxon'
|
|
3
3
|
import { useState } from 'react'
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
AccessCode,
|
|
6
|
+
AccessCodeError,
|
|
7
|
+
ConnectedAccountError,
|
|
8
|
+
DeviceError,
|
|
9
|
+
} from 'seamapi'
|
|
5
10
|
|
|
6
11
|
import { useAccessCode } from 'lib/seam/access-codes/use-access-code.js'
|
|
7
12
|
import { AccessCodeDevice } from 'lib/seam/components/AccessCodeDetails/AccessCodeDevice.js'
|
|
8
13
|
import { DeviceDetails } from 'lib/seam/components/DeviceDetails/DeviceDetails.js'
|
|
14
|
+
import { Alerts } from 'lib/ui/Alert/Alerts.js'
|
|
9
15
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
10
16
|
import { useIsDateInPast } from 'lib/ui/use-is-date-in-past.js'
|
|
11
17
|
|
|
12
18
|
export interface AccessCodeDetailsProps {
|
|
13
19
|
accessCodeId: string
|
|
14
20
|
onBack?: () => void
|
|
21
|
+
disableLockUnlock?: boolean
|
|
15
22
|
className?: string
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
export function AccessCodeDetails({
|
|
19
26
|
accessCodeId,
|
|
20
27
|
onBack,
|
|
28
|
+
disableLockUnlock = false,
|
|
21
29
|
className,
|
|
22
30
|
}: AccessCodeDetailsProps): JSX.Element | null {
|
|
23
31
|
const { accessCode } = useAccessCode(accessCodeId)
|
|
@@ -37,15 +45,32 @@ export function AccessCodeDetails({
|
|
|
37
45
|
onBack={() => {
|
|
38
46
|
selectDevice(null)
|
|
39
47
|
}}
|
|
48
|
+
disableLockUnlock={disableLockUnlock}
|
|
40
49
|
/>
|
|
41
50
|
)
|
|
42
51
|
}
|
|
43
52
|
|
|
53
|
+
const alerts = [
|
|
54
|
+
...accessCode.errors.filter(errorFilter).map((error) => ({
|
|
55
|
+
variant: 'error' as const,
|
|
56
|
+
message: error.message,
|
|
57
|
+
})),
|
|
58
|
+
...accessCode.warnings.map((warning) => ({
|
|
59
|
+
variant: 'warning' as const,
|
|
60
|
+
message: warning.message,
|
|
61
|
+
})),
|
|
62
|
+
]
|
|
63
|
+
|
|
44
64
|
return (
|
|
45
65
|
<div className={classNames('seam-access-code-details', className)}>
|
|
46
66
|
<ContentHeader title='Access code' onBack={onBack} />
|
|
47
67
|
<div className='seam-summary'>
|
|
48
|
-
<div
|
|
68
|
+
<div
|
|
69
|
+
className={classNames(
|
|
70
|
+
'seam-top',
|
|
71
|
+
alerts.length > 0 && 'seam-top-has-alerts'
|
|
72
|
+
)}
|
|
73
|
+
>
|
|
49
74
|
<span className='seam-label'>{t.accessCode}</span>
|
|
50
75
|
<h5 className='seam-access-code-name'>{name}</h5>
|
|
51
76
|
<div className='seam-code'>{accessCode.code}</div>
|
|
@@ -53,8 +78,12 @@ export function AccessCodeDetails({
|
|
|
53
78
|
<Duration accessCode={accessCode} />
|
|
54
79
|
</div>
|
|
55
80
|
</div>
|
|
81
|
+
|
|
82
|
+
<Alerts alerts={alerts} className='seam-alerts-padded' />
|
|
83
|
+
|
|
56
84
|
<AccessCodeDevice
|
|
57
85
|
deviceId={accessCode.device_id}
|
|
86
|
+
disableLockUnlock={disableLockUnlock}
|
|
58
87
|
onSelectDevice={selectDevice}
|
|
59
88
|
/>
|
|
60
89
|
</div>
|
|
@@ -157,6 +186,22 @@ function formatDate(date: string): string {
|
|
|
157
186
|
})
|
|
158
187
|
}
|
|
159
188
|
|
|
189
|
+
const errorFilter = (
|
|
190
|
+
error: AccessCodeError | DeviceError | ConnectedAccountError
|
|
191
|
+
): boolean => {
|
|
192
|
+
if ('is_access_code_error' in error && !error.is_access_code_error)
|
|
193
|
+
return true
|
|
194
|
+
|
|
195
|
+
if (
|
|
196
|
+
error.error_code === 'failed_to_set_on_device' ||
|
|
197
|
+
error.error_code === 'failed_to_remove_on_device'
|
|
198
|
+
) {
|
|
199
|
+
return true
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return false
|
|
203
|
+
}
|
|
204
|
+
|
|
160
205
|
const t = {
|
|
161
206
|
accessCode: 'Access code',
|
|
162
207
|
fallbackName: 'Code',
|
|
@@ -8,12 +8,16 @@ import { TextButton } from 'lib/ui/TextButton.js'
|
|
|
8
8
|
|
|
9
9
|
export function AccessCodeDevice({
|
|
10
10
|
deviceId,
|
|
11
|
+
disableLockUnlock,
|
|
11
12
|
onSelectDevice,
|
|
12
13
|
}: {
|
|
13
14
|
deviceId: string
|
|
15
|
+
disableLockUnlock: boolean
|
|
14
16
|
onSelectDevice: (deviceId: string) => void
|
|
15
17
|
}): JSX.Element | null {
|
|
16
|
-
const { isLoading, device } = useDevice({
|
|
18
|
+
const { isLoading, device } = useDevice({
|
|
19
|
+
device_id: deviceId,
|
|
20
|
+
})
|
|
17
21
|
|
|
18
22
|
if (isLoading) {
|
|
19
23
|
return null
|
|
@@ -27,14 +31,21 @@ export function AccessCodeDevice({
|
|
|
27
31
|
return null
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
return
|
|
34
|
+
return (
|
|
35
|
+
<Content
|
|
36
|
+
device={device}
|
|
37
|
+
disableLockUnlock={disableLockUnlock}
|
|
38
|
+
onSelectDevice={onSelectDevice}
|
|
39
|
+
/>
|
|
40
|
+
)
|
|
31
41
|
}
|
|
32
42
|
|
|
33
43
|
function Content(props: {
|
|
34
44
|
device: LockDevice
|
|
45
|
+
disableLockUnlock: boolean
|
|
35
46
|
onSelectDevice: (deviceId: string) => void
|
|
36
47
|
}): JSX.Element {
|
|
37
|
-
const { device, onSelectDevice } = props
|
|
48
|
+
const { device, disableLockUnlock, onSelectDevice } = props
|
|
38
49
|
const toggleLock = useToggleLock(device)
|
|
39
50
|
|
|
40
51
|
const toggleLockLabel = device.properties.locked ? t.unlock : t.lock
|
|
@@ -54,13 +65,15 @@ function Content(props: {
|
|
|
54
65
|
{t.deviceDetails}
|
|
55
66
|
</TextButton>
|
|
56
67
|
</div>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
{!disableLockUnlock && (
|
|
69
|
+
<Button
|
|
70
|
+
onClick={() => {
|
|
71
|
+
toggleLock.mutate()
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
{toggleLockLabel}
|
|
75
|
+
</Button>
|
|
76
|
+
)}
|
|
64
77
|
</div>
|
|
65
78
|
)
|
|
66
79
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { CheckIcon } from 'lib/icons/Check.js'
|
|
2
|
+
import { ExclamationCircleOutlineIcon } from 'lib/icons/ExclamationCircleOutline.js'
|
|
3
|
+
import type { UseAccessCodesData } from 'lib/seam/access-codes/use-access-codes.js'
|
|
4
|
+
import { TableFilterBar } from 'lib/ui/Table/TableFilterBar/TableFilterBar.js'
|
|
5
|
+
import { TableFilterItem } from 'lib/ui/Table/TableFilterBar/TableFilterItem.js'
|
|
6
|
+
|
|
7
|
+
export type AccessCodeFilter = 'access_code_issues'
|
|
8
|
+
|
|
9
|
+
interface AccessCodeHealthBarProps {
|
|
10
|
+
accessCodes: Array<UseAccessCodesData[number]>
|
|
11
|
+
filter: AccessCodeFilter | null
|
|
12
|
+
onFilterSelect: (filter: AccessCodeFilter | null) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function AccessCodeHealthBar({
|
|
16
|
+
accessCodes,
|
|
17
|
+
filter,
|
|
18
|
+
onFilterSelect,
|
|
19
|
+
}: AccessCodeHealthBarProps): JSX.Element {
|
|
20
|
+
const codesWithIssues = accessCodes.filter(
|
|
21
|
+
({ errors, warnings }) => errors.length > 0 || warnings.length > 0
|
|
22
|
+
)
|
|
23
|
+
const issueCount = codesWithIssues.length
|
|
24
|
+
|
|
25
|
+
const toggle = (target: AccessCodeFilter) => () => {
|
|
26
|
+
const newFilter = target === filter ? null : target
|
|
27
|
+
onFilterSelect(newFilter)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const isPlural = issueCount === 0 || issueCount > 1
|
|
31
|
+
const label = isPlural
|
|
32
|
+
? `${issueCount} ${t.accessCodeIssues}`
|
|
33
|
+
: `${issueCount} ${t.accessCodeIssue}`
|
|
34
|
+
|
|
35
|
+
if (issueCount === 0) {
|
|
36
|
+
return (
|
|
37
|
+
<TableFilterBar filterCleared>
|
|
38
|
+
<TableFilterItem>
|
|
39
|
+
<CheckIcon />
|
|
40
|
+
{t.accessCodesOk}
|
|
41
|
+
</TableFilterItem>
|
|
42
|
+
</TableFilterBar>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<TableFilterBar
|
|
48
|
+
filterCleared={filter == null}
|
|
49
|
+
onFilterClear={() => {
|
|
50
|
+
onFilterSelect(null)
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<TableFilterItem
|
|
54
|
+
onClick={toggle('access_code_issues')}
|
|
55
|
+
selected={filter === 'access_code_issues'}
|
|
56
|
+
>
|
|
57
|
+
<ExclamationCircleOutlineIcon />
|
|
58
|
+
{label}
|
|
59
|
+
</TableFilterItem>
|
|
60
|
+
</TableFilterBar>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const t = {
|
|
65
|
+
accessCodesOk: 'Access codes OK',
|
|
66
|
+
accessCodeIssue: 'access code issue',
|
|
67
|
+
accessCodeIssues: 'access code issues',
|
|
68
|
+
}
|
|
@@ -5,11 +5,16 @@ import { compareByCreatedAtDesc } from 'lib/dates.js'
|
|
|
5
5
|
import { AccessCodeKeyIcon } from 'lib/icons/AccessCodeKey.js'
|
|
6
6
|
import { CopyIcon } from 'lib/icons/Copy.js'
|
|
7
7
|
import { ExclamationCircleOutlineIcon } from 'lib/icons/ExclamationCircleOutline.js'
|
|
8
|
+
import { TriangleWarningOutlineIcon } from 'lib/icons/TriangleWarningOutline.js'
|
|
8
9
|
import {
|
|
9
10
|
useAccessCodes,
|
|
10
11
|
type UseAccessCodesData,
|
|
11
12
|
} from 'lib/seam/access-codes/use-access-codes.js'
|
|
12
13
|
import { AccessCodeDetails } from 'lib/seam/components/AccessCodeDetails/AccessCodeDetails.js'
|
|
14
|
+
import {
|
|
15
|
+
type AccessCodeFilter,
|
|
16
|
+
AccessCodeHealthBar,
|
|
17
|
+
} from 'lib/seam/components/AccessCodeTable/AccessCodeHealthBar.js'
|
|
13
18
|
import { CodeDetails } from 'lib/seam/components/AccessCodeTable/CodeDetails.js'
|
|
14
19
|
import { copyToClipboard } from 'lib/ui/clipboard.js'
|
|
15
20
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
@@ -37,6 +42,7 @@ export interface AccessCodeTableProps {
|
|
|
37
42
|
) => number
|
|
38
43
|
onAccessCodeClick?: (accessCodeId: string) => void
|
|
39
44
|
preventDefaultOnAccessCodeClick?: boolean
|
|
45
|
+
disableLockUnlock?: boolean
|
|
40
46
|
onBack?: () => void
|
|
41
47
|
className?: string
|
|
42
48
|
}
|
|
@@ -49,13 +55,18 @@ const defaultAccessCodeFilter = (
|
|
|
49
55
|
): boolean => {
|
|
50
56
|
const value = searchInputValue.trim()
|
|
51
57
|
if (value === '') return true
|
|
52
|
-
|
|
58
|
+
const searchRegex = new RegExp(value, 'i')
|
|
59
|
+
return (
|
|
60
|
+
searchRegex.test(accessCode?.name ?? '') ||
|
|
61
|
+
searchRegex.test(accessCode?.code ?? '')
|
|
62
|
+
)
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
export function AccessCodeTable({
|
|
56
66
|
deviceId,
|
|
57
67
|
onAccessCodeClick = () => {},
|
|
58
68
|
preventDefaultOnAccessCodeClick = false,
|
|
69
|
+
disableLockUnlock = false,
|
|
59
70
|
onBack,
|
|
60
71
|
accessCodeFilter = defaultAccessCodeFilter,
|
|
61
72
|
accessCodeComparator = compareByCreatedAtDesc,
|
|
@@ -100,6 +111,7 @@ export function AccessCodeTable({
|
|
|
100
111
|
onBack={() => {
|
|
101
112
|
setSelectedAccessCodeId(null)
|
|
102
113
|
}}
|
|
114
|
+
disableLockUnlock={disableLockUnlock}
|
|
103
115
|
/>
|
|
104
116
|
)
|
|
105
117
|
}
|
|
@@ -132,6 +144,21 @@ function Content(props: {
|
|
|
132
144
|
onAccessCodeClick: (accessCodeId: string) => void
|
|
133
145
|
}): JSX.Element {
|
|
134
146
|
const { accessCodes, onAccessCodeClick } = props
|
|
147
|
+
const [filter, setFilter] = useState<AccessCodeFilter | null>(null)
|
|
148
|
+
|
|
149
|
+
const filteredAccessCodes = useMemo(() => {
|
|
150
|
+
if (filter === null) {
|
|
151
|
+
return accessCodes
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (filter === 'access_code_issues') {
|
|
155
|
+
return accessCodes.filter((accessCode) => {
|
|
156
|
+
return accessCode.errors.length > 0 || accessCode.warnings.length > 0
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return accessCodes
|
|
161
|
+
}, [accessCodes, filter])
|
|
135
162
|
|
|
136
163
|
if (accessCodes.length === 0) {
|
|
137
164
|
return <EmptyPlaceholder>{t.noAccessCodesMessage}</EmptyPlaceholder>
|
|
@@ -139,7 +166,12 @@ function Content(props: {
|
|
|
139
166
|
|
|
140
167
|
return (
|
|
141
168
|
<>
|
|
142
|
-
|
|
169
|
+
<AccessCodeHealthBar
|
|
170
|
+
accessCodes={accessCodes}
|
|
171
|
+
filter={filter}
|
|
172
|
+
onFilterSelect={setFilter}
|
|
173
|
+
/>
|
|
174
|
+
{filteredAccessCodes.map((accessCode) => (
|
|
143
175
|
<AccessCodeRow
|
|
144
176
|
key={accessCode.access_code_id}
|
|
145
177
|
accessCode={accessCode}
|
|
@@ -158,14 +190,18 @@ function AccessCodeRow(props: {
|
|
|
158
190
|
}): JSX.Element {
|
|
159
191
|
const { onClick, accessCode } = props
|
|
160
192
|
|
|
161
|
-
const errorCount = accessCode.errors
|
|
193
|
+
const errorCount = accessCode.errors.length
|
|
194
|
+
const warningCount = accessCode.warnings.length
|
|
162
195
|
const isPlural = errorCount === 0 || errorCount > 1
|
|
163
|
-
const
|
|
196
|
+
const errorIconTitle = isPlural
|
|
164
197
|
? `${errorCount} ${t.codeIssues}`
|
|
165
198
|
: `${errorCount} ${t.codeIssue}`
|
|
199
|
+
const warningIconTitle = isPlural
|
|
200
|
+
? `${warningCount} ${t.codeIssues}`
|
|
201
|
+
: `${warningCount} ${t.codeIssue}`
|
|
166
202
|
|
|
167
203
|
return (
|
|
168
|
-
<TableRow
|
|
204
|
+
<TableRow onClick={onClick}>
|
|
169
205
|
<TableCell className='seam-icon-cell'>
|
|
170
206
|
<div>
|
|
171
207
|
<AccessCodeKeyIcon />
|
|
@@ -177,10 +213,15 @@ function AccessCodeRow(props: {
|
|
|
177
213
|
</TableCell>
|
|
178
214
|
<TableCell className='seam-action-cell'>
|
|
179
215
|
{errorCount > 0 && (
|
|
180
|
-
<div className='seam-code-issue-icon-wrap' title={
|
|
216
|
+
<div className='seam-code-issue-icon-wrap' title={errorIconTitle}>
|
|
181
217
|
<ExclamationCircleOutlineIcon />
|
|
182
218
|
</div>
|
|
183
219
|
)}
|
|
220
|
+
{errorCount === 0 && warningCount > 0 && (
|
|
221
|
+
<div className='seam-code-issue-icon-wrap' title={warningIconTitle}>
|
|
222
|
+
<TriangleWarningOutlineIcon />
|
|
223
|
+
</div>
|
|
224
|
+
)}
|
|
184
225
|
<MoreActionsMenu
|
|
185
226
|
menuProps={{
|
|
186
227
|
backgroundProps: {
|
|
@@ -5,12 +5,14 @@ import { useDevice } from 'lib/seam/devices/use-device.js'
|
|
|
5
5
|
|
|
6
6
|
export interface DeviceDetailsProps {
|
|
7
7
|
deviceId: string
|
|
8
|
+
disableLockUnlock?: boolean
|
|
8
9
|
onBack?: () => void
|
|
9
10
|
className?: string
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export function DeviceDetails({
|
|
13
14
|
deviceId,
|
|
15
|
+
disableLockUnlock = false,
|
|
14
16
|
onBack,
|
|
15
17
|
className,
|
|
16
18
|
}: DeviceDetailsProps): JSX.Element | null {
|
|
@@ -27,6 +29,7 @@ export function DeviceDetails({
|
|
|
27
29
|
<LockDeviceDetails
|
|
28
30
|
className={className}
|
|
29
31
|
device={device}
|
|
32
|
+
disableLockUnlock={disableLockUnlock}
|
|
30
33
|
onBack={onBack}
|
|
31
34
|
/>
|
|
32
35
|
)
|
|
@@ -13,12 +13,14 @@ import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
|
|
|
13
13
|
import { OnlineStatus } from 'lib/ui/device/OnlineStatus.js'
|
|
14
14
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
15
15
|
import { useToggle } from 'lib/ui/use-toggle.js'
|
|
16
|
+
|
|
16
17
|
export function LockDeviceDetails(props: {
|
|
17
18
|
device: LockDevice
|
|
19
|
+
disableLockUnlock: boolean
|
|
18
20
|
onBack?: () => void
|
|
19
21
|
className?: string
|
|
20
22
|
}): JSX.Element | null {
|
|
21
|
-
const { device, onBack, className } = props
|
|
23
|
+
const { device, disableLockUnlock, onBack, className } = props
|
|
22
24
|
|
|
23
25
|
const [accessCodesOpen, toggleAccessCodesOpen] = useToggle()
|
|
24
26
|
const toggleLock = useToggleLock(device)
|
|
@@ -41,6 +43,7 @@ export function LockDeviceDetails(props: {
|
|
|
41
43
|
className={className}
|
|
42
44
|
deviceId={device.device_id}
|
|
43
45
|
onBack={toggleAccessCodesOpen}
|
|
46
|
+
disableLockUnlock={disableLockUnlock}
|
|
44
47
|
/>
|
|
45
48
|
)
|
|
46
49
|
}
|
|
@@ -98,14 +101,16 @@ export function LockDeviceDetails(props: {
|
|
|
98
101
|
<span className='seam-value'>{lockStatus}</span>
|
|
99
102
|
</div>
|
|
100
103
|
<div className='seam-right'>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
{!disableLockUnlock && (
|
|
105
|
+
<Button
|
|
106
|
+
size='small'
|
|
107
|
+
onClick={() => {
|
|
108
|
+
toggleLock.mutate()
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
{toggleLockLabel}
|
|
112
|
+
</Button>
|
|
113
|
+
)}
|
|
109
114
|
</div>
|
|
110
115
|
</div>
|
|
111
116
|
<AccessCodeLength
|
|
@@ -30,6 +30,7 @@ export interface DeviceTableProps {
|
|
|
30
30
|
deviceComparator?: (deviceA: Device, deviceB: Device) => number
|
|
31
31
|
onDeviceClick?: (deviceId: string) => void
|
|
32
32
|
preventDefaultOnDeviceClick?: boolean
|
|
33
|
+
disableLockUnlock?: boolean
|
|
33
34
|
onBack?: () => void
|
|
34
35
|
className?: string
|
|
35
36
|
}
|
|
@@ -48,6 +49,7 @@ export function DeviceTable({
|
|
|
48
49
|
connectedAccountIds,
|
|
49
50
|
onDeviceClick = () => {},
|
|
50
51
|
preventDefaultOnDeviceClick = false,
|
|
52
|
+
disableLockUnlock = false,
|
|
51
53
|
onBack,
|
|
52
54
|
deviceFilter = defaultDeviceFilter,
|
|
53
55
|
deviceComparator = compareByCreatedAtDesc,
|
|
@@ -87,6 +89,7 @@ export function DeviceTable({
|
|
|
87
89
|
onBack={() => {
|
|
88
90
|
setSelectedDeviceId(null)
|
|
89
91
|
}}
|
|
92
|
+
disableLockUnlock={disableLockUnlock}
|
|
90
93
|
/>
|
|
91
94
|
)
|
|
92
95
|
}
|
package/src/lib/version.ts
CHANGED