@seamapi/react 4.13.0 → 4.13.1
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 +2 -2
- package/dist/elements.js +7632 -7483
- package/dist/elements.js.map +1 -1
- package/dist/index.css +1 -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/seam/components/DeviceDetails/LockDeviceDetails.js +2 -23
- package/lib/seam/components/DeviceDetails/LockDeviceDetails.js.map +1 -1
- package/lib/seam/components/DeviceDetails/LockDeviceLockButtons.d.ts +11 -0
- package/lib/seam/components/DeviceDetails/LockDeviceLockButtons.js +68 -0
- package/lib/seam/components/DeviceDetails/LockDeviceLockButtons.js.map +1 -0
- package/lib/seam/locks/use-lock-door.d.ts +17 -0
- package/lib/seam/locks/use-lock-door.js +60 -0
- package/lib/seam/locks/use-lock-door.js.map +1 -0
- package/lib/seam/locks/use-unlock-door.d.ts +17 -0
- package/lib/seam/locks/use-unlock-door.js +60 -0
- package/lib/seam/locks/use-unlock-door.js.map +1 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx +7 -43
- package/src/lib/seam/components/DeviceDetails/LockDeviceLockButtons.tsx +137 -0
- package/src/lib/seam/locks/use-lock-door.ts +101 -0
- package/src/lib/seam/locks/use-unlock-door.ts +104 -0
- package/src/lib/version.ts +1 -1
- package/src/styles/_device-details.scss +1 -0
|
@@ -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;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAA;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wDAAwD,CAAA;AAE9F,OAAO,EAAE,UAAU,EAAE,MAAM,iDAAiD,CAAA;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAC9E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"LockDeviceDetails.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { LockDevice } from '../../../../lib/seam/locks/lock-device.js';
|
|
3
|
+
import type { SnackbarVariant } from '../../../../lib/ui/Snackbar/Snackbar.js';
|
|
4
|
+
interface LockDeviceLockButtonsProps {
|
|
5
|
+
device: LockDevice;
|
|
6
|
+
disableLockUnlock: boolean;
|
|
7
|
+
setSnackbarVisible: (visible: boolean) => void;
|
|
8
|
+
setSnackbarVariant: (variant: SnackbarVariant) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function LockDeviceLockButtons({ device, setSnackbarVariant, setSnackbarVisible, disableLockUnlock, }: LockDeviceLockButtonsProps): JSX.Element | null;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useLock } from '../../../../lib/seam/locks/use-lock-door.js';
|
|
3
|
+
import { useToggleLock } from '../../../../lib/seam/locks/use-toggle-lock.js';
|
|
4
|
+
import { useUnlock } from '../../../../lib/seam/locks/use-unlock-door.js';
|
|
5
|
+
import { Button } from '../../../../lib/ui/Button.js';
|
|
6
|
+
export function LockDeviceLockButtons({ device, setSnackbarVariant, setSnackbarVisible, disableLockUnlock, }) {
|
|
7
|
+
const lockStatus = device.properties.locked ? t.locked : t.unlocked;
|
|
8
|
+
const toggleLockLabel = device.properties.locked ? t.unlock : t.lock;
|
|
9
|
+
const toggleLock = useToggleLock({
|
|
10
|
+
onSuccess: () => {
|
|
11
|
+
setSnackbarVisible(true);
|
|
12
|
+
setSnackbarVariant('success');
|
|
13
|
+
},
|
|
14
|
+
onError: () => {
|
|
15
|
+
setSnackbarVisible(true);
|
|
16
|
+
setSnackbarVariant('error');
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
const lock = useLock({
|
|
20
|
+
onSuccess: () => {
|
|
21
|
+
setSnackbarVisible(true);
|
|
22
|
+
setSnackbarVariant('success');
|
|
23
|
+
},
|
|
24
|
+
onError: () => {
|
|
25
|
+
setSnackbarVisible(true);
|
|
26
|
+
setSnackbarVariant('error');
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
const unlock = useUnlock({
|
|
30
|
+
onSuccess: () => {
|
|
31
|
+
setSnackbarVisible(true);
|
|
32
|
+
setSnackbarVariant('success');
|
|
33
|
+
},
|
|
34
|
+
onError: () => {
|
|
35
|
+
setSnackbarVisible(true);
|
|
36
|
+
setSnackbarVariant('error');
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
if (disableLockUnlock) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (device.can_remotely_lock === true &&
|
|
43
|
+
device.can_remotely_unlock === true) {
|
|
44
|
+
return (_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: () => {
|
|
45
|
+
toggleLock.mutate(device);
|
|
46
|
+
}, children: toggleLockLabel }) })] }));
|
|
47
|
+
}
|
|
48
|
+
if (device.can_remotely_lock === true) {
|
|
49
|
+
return (_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: () => {
|
|
50
|
+
lock.mutate(device);
|
|
51
|
+
}, children: t.lock }) })] }));
|
|
52
|
+
}
|
|
53
|
+
if (device.can_remotely_unlock === true) {
|
|
54
|
+
return (_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: () => {
|
|
55
|
+
unlock.mutate(device);
|
|
56
|
+
}, children: t.unlock }) })] }));
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const t = {
|
|
61
|
+
unlock: 'Unlock',
|
|
62
|
+
lock: 'Lock',
|
|
63
|
+
locked: 'Locked',
|
|
64
|
+
unlocked: 'Unlocked',
|
|
65
|
+
lockStatus: 'Lock status',
|
|
66
|
+
statusUnknown: 'Unknown',
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=LockDeviceLockButtons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LockDeviceLockButtons.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/LockDeviceLockButtons.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SeamActionAttemptFailedError, SeamActionAttemptTimeoutError, SeamHttpApiError } from '@seamapi/http/connect';
|
|
2
|
+
import type { ActionAttempt, Device } from '@seamapi/types/connect';
|
|
3
|
+
import { type UseMutationResult } from '@tanstack/react-query';
|
|
4
|
+
export type UseLockData = undefined;
|
|
5
|
+
export type UseLockMutationVariables = Pick<Device, 'device_id'> & {
|
|
6
|
+
properties: Required<Pick<Device['properties'], 'locked'>>;
|
|
7
|
+
};
|
|
8
|
+
type LockActionAttempt = Extract<ActionAttempt, {
|
|
9
|
+
action_type: 'LOCK_DOOR';
|
|
10
|
+
}>;
|
|
11
|
+
type MutationError = SeamHttpApiError | SeamActionAttemptFailedError<LockActionAttempt> | SeamActionAttemptTimeoutError<LockActionAttempt>;
|
|
12
|
+
interface UseLockParams {
|
|
13
|
+
onError?: () => void;
|
|
14
|
+
onSuccess?: () => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function useLock(params?: UseLockParams): UseMutationResult<UseLockData, MutationError, UseLockMutationVariables>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { NullSeamClientError, useSeamClient } from '@seamapi/react-query';
|
|
2
|
+
import { useMutation, useQueryClient, } from '@tanstack/react-query';
|
|
3
|
+
export function useLock(params = {}) {
|
|
4
|
+
const { client } = useSeamClient();
|
|
5
|
+
const queryClient = useQueryClient();
|
|
6
|
+
return useMutation({
|
|
7
|
+
mutationFn: async (variables) => {
|
|
8
|
+
const { device_id: deviceId, properties: { locked }, } = variables;
|
|
9
|
+
if (client === null)
|
|
10
|
+
throw new NullSeamClientError();
|
|
11
|
+
if (locked == null)
|
|
12
|
+
return;
|
|
13
|
+
await client.locks.lockDoor({ device_id: deviceId });
|
|
14
|
+
},
|
|
15
|
+
onMutate: (variables) => {
|
|
16
|
+
queryClient.setQueryData(['devices', 'list', {}], (devices) => {
|
|
17
|
+
if (devices == null) {
|
|
18
|
+
return devices;
|
|
19
|
+
}
|
|
20
|
+
return devices.map((device) => {
|
|
21
|
+
if (device.device_id !== variables.device_id ||
|
|
22
|
+
device.properties.locked == null) {
|
|
23
|
+
return device;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
...device,
|
|
27
|
+
properties: {
|
|
28
|
+
...device.properties,
|
|
29
|
+
locked: !variables.properties.locked,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
queryClient.setQueryData(['devices', 'get', { device_id: variables.device_id }], (device) => {
|
|
35
|
+
if (device?.properties.locked == null)
|
|
36
|
+
return device;
|
|
37
|
+
return {
|
|
38
|
+
...device,
|
|
39
|
+
properties: {
|
|
40
|
+
...device.properties,
|
|
41
|
+
locked: !variables.properties.locked,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
onError: async (_error, variables) => {
|
|
47
|
+
params.onError?.();
|
|
48
|
+
await queryClient.invalidateQueries({
|
|
49
|
+
queryKey: ['devices', 'list'],
|
|
50
|
+
});
|
|
51
|
+
await queryClient.invalidateQueries({
|
|
52
|
+
queryKey: ['devices', 'get', { device_id: variables.device_id }],
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
onSuccess() {
|
|
56
|
+
params.onSuccess?.();
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=use-lock-door.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-lock-door.js","sourceRoot":"","sources":["../../../src/lib/seam/locks/use-lock-door.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,EACL,WAAW,EAEX,cAAc,GACf,MAAM,uBAAuB,CAAA;AAoB9B,MAAM,UAAU,OAAO,CACrB,SAAwB,EAAE;IAE1B,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC,OAAO,WAAW,CAAuD;QACvE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,MAAM,EACJ,SAAS,EAAE,QAAQ,EACnB,UAAU,EAAE,EAAE,MAAM,EAAE,GACvB,GAAG,SAAS,CAAA;YACb,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM,IAAI,mBAAmB,EAAE,CAAA;YACpD,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAM;YAC1B,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAA;QACtD,CAAC;QACD,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE;YACtB,WAAW,CAAC,YAAY,CAAW,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE;gBACtE,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;oBACpB,OAAO,OAAO,CAAA;gBAChB,CAAC;gBAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;oBAC5B,IACE,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,SAAS;wBACxC,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,EAChC,CAAC;wBACD,OAAO,MAAM,CAAA;oBACf,CAAC;oBAED,OAAO;wBACL,GAAG,MAAM;wBACT,UAAU,EAAE;4BACV,GAAG,MAAM,CAAC,UAAU;4BACpB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM;yBACrC;qBACF,CAAA;gBACH,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;YAEF,WAAW,CAAC,YAAY,CACtB,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,EACtD,CAAC,MAAM,EAAE,EAAE;gBACT,IAAI,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,IAAI;oBAAE,OAAO,MAAM,CAAA;gBAEpD,OAAO;oBACL,GAAG,MAAM;oBACT,UAAU,EAAE;wBACV,GAAG,MAAM,CAAC,UAAU;wBACpB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM;qBACrC;iBACF,CAAA;YACH,CAAC,CACF,CAAA;QACH,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;YACnC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAA;YAElB,MAAM,WAAW,CAAC,iBAAiB,CAAC;gBAClC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;aAC9B,CAAC,CAAA;YACF,MAAM,WAAW,CAAC,iBAAiB,CAAC;gBAClC,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC;aACjE,CAAC,CAAA;QACJ,CAAC;QACD,SAAS;YACP,MAAM,CAAC,SAAS,EAAE,EAAE,CAAA;QACtB,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SeamActionAttemptFailedError, SeamActionAttemptTimeoutError, SeamHttpApiError } from '@seamapi/http/connect';
|
|
2
|
+
import type { ActionAttempt, Device } from '@seamapi/types/connect';
|
|
3
|
+
import { type UseMutationResult } from '@tanstack/react-query';
|
|
4
|
+
export type UseUnlockData = undefined;
|
|
5
|
+
export type UseUnlockMutationVariables = Pick<Device, 'device_id'> & {
|
|
6
|
+
properties: Required<Pick<Device['properties'], 'locked'>>;
|
|
7
|
+
};
|
|
8
|
+
type UnlockActionAttempt = Extract<ActionAttempt, {
|
|
9
|
+
action_type: 'UNLOCK_DOOR';
|
|
10
|
+
}>;
|
|
11
|
+
type MutationError = SeamHttpApiError | SeamActionAttemptFailedError<UnlockActionAttempt> | SeamActionAttemptTimeoutError<UnlockActionAttempt>;
|
|
12
|
+
interface UseUnlockParams {
|
|
13
|
+
onError?: () => void;
|
|
14
|
+
onSuccess?: () => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function useUnlock(params?: UseUnlockParams): UseMutationResult<UseUnlockData, MutationError, UseUnlockMutationVariables>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { NullSeamClientError, useSeamClient } from '@seamapi/react-query';
|
|
2
|
+
import { useMutation, useQueryClient, } from '@tanstack/react-query';
|
|
3
|
+
export function useUnlock(params = {}) {
|
|
4
|
+
const { client } = useSeamClient();
|
|
5
|
+
const queryClient = useQueryClient();
|
|
6
|
+
return useMutation({
|
|
7
|
+
mutationFn: async (variables) => {
|
|
8
|
+
const { device_id: deviceId, properties: { locked }, } = variables;
|
|
9
|
+
if (client === null)
|
|
10
|
+
throw new NullSeamClientError();
|
|
11
|
+
if (locked == null)
|
|
12
|
+
return;
|
|
13
|
+
await client.locks.unlockDoor({ device_id: deviceId });
|
|
14
|
+
},
|
|
15
|
+
onMutate: (variables) => {
|
|
16
|
+
queryClient.setQueryData(['devices', 'list', {}], (devices) => {
|
|
17
|
+
if (devices == null) {
|
|
18
|
+
return devices;
|
|
19
|
+
}
|
|
20
|
+
return devices.map((device) => {
|
|
21
|
+
if (device.device_id !== variables.device_id ||
|
|
22
|
+
device.properties.locked == null) {
|
|
23
|
+
return device;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
...device,
|
|
27
|
+
properties: {
|
|
28
|
+
...device.properties,
|
|
29
|
+
locked: !variables.properties.locked,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
queryClient.setQueryData(['devices', 'get', { device_id: variables.device_id }], (device) => {
|
|
35
|
+
if (device?.properties.locked == null)
|
|
36
|
+
return device;
|
|
37
|
+
return {
|
|
38
|
+
...device,
|
|
39
|
+
properties: {
|
|
40
|
+
...device.properties,
|
|
41
|
+
locked: !variables.properties.locked,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
onError: async (_error, variables) => {
|
|
47
|
+
params.onError?.();
|
|
48
|
+
await queryClient.invalidateQueries({
|
|
49
|
+
queryKey: ['devices', 'list'],
|
|
50
|
+
});
|
|
51
|
+
await queryClient.invalidateQueries({
|
|
52
|
+
queryKey: ['devices', 'get', { device_id: variables.device_id }],
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
onSuccess() {
|
|
56
|
+
params.onSuccess?.();
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=use-unlock-door.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-unlock-door.js","sourceRoot":"","sources":["../../../src/lib/seam/locks/use-unlock-door.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,EACL,WAAW,EAEX,cAAc,GACf,MAAM,uBAAuB,CAAA;AAuB9B,MAAM,UAAU,SAAS,CACvB,SAA0B,EAAE;IAE5B,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC,OAAO,WAAW,CAA2D;QAC3E,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,MAAM,EACJ,SAAS,EAAE,QAAQ,EACnB,UAAU,EAAE,EAAE,MAAM,EAAE,GACvB,GAAG,SAAS,CAAA;YACb,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM,IAAI,mBAAmB,EAAE,CAAA;YACpD,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAM;YAC1B,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAA;QACxD,CAAC;QACD,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE;YACtB,WAAW,CAAC,YAAY,CAAW,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE;gBACtE,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;oBACpB,OAAO,OAAO,CAAA;gBAChB,CAAC;gBAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;oBAC5B,IACE,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,SAAS;wBACxC,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,EAChC,CAAC;wBACD,OAAO,MAAM,CAAA;oBACf,CAAC;oBAED,OAAO;wBACL,GAAG,MAAM;wBACT,UAAU,EAAE;4BACV,GAAG,MAAM,CAAC,UAAU;4BACpB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM;yBACrC;qBACF,CAAA;gBACH,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;YAEF,WAAW,CAAC,YAAY,CACtB,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,EACtD,CAAC,MAAM,EAAE,EAAE;gBACT,IAAI,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,IAAI;oBAAE,OAAO,MAAM,CAAA;gBAEpD,OAAO;oBACL,GAAG,MAAM;oBACT,UAAU,EAAE;wBACV,GAAG,MAAM,CAAC,UAAU;wBACpB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM;qBACrC;iBACF,CAAA;YACH,CAAC,CACF,CAAA;QACH,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;YACnC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAA;YAElB,MAAM,WAAW,CAAC,iBAAiB,CAAC;gBAClC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;aAC9B,CAAC,CAAA;YACF,MAAM,WAAW,CAAC,iBAAiB,CAAC;gBAClC,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC;aACjE,CAAC,CAAA;QACJ,CAAC;QACD,SAAS;YACP,MAAM,CAAC,SAAS,EAAE,EAAE,CAAA;QACtB,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
|
package/lib/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const seamapiReactVersion = "4.13.
|
|
1
|
+
declare const seamapiReactVersion = "4.13.1";
|
|
2
2
|
export default seamapiReactVersion;
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -7,11 +7,10 @@ import { NestedAccessCodeTable } from 'lib/seam/components/AccessCodeTable/Acces
|
|
|
7
7
|
import type { NestedSpecificDeviceDetailsProps } from 'lib/seam/components/DeviceDetails/DeviceDetails.js'
|
|
8
8
|
import { DeviceInfo } from 'lib/seam/components/DeviceDetails/DeviceInfo.js'
|
|
9
9
|
import { DeviceModel } from 'lib/seam/components/DeviceDetails/DeviceModel.js'
|
|
10
|
+
import { LockDeviceLockButtons } from 'lib/seam/components/DeviceDetails/LockDeviceLockButtons.js'
|
|
10
11
|
import { deviceErrorFilter, deviceWarningFilter } from 'lib/seam/filters.js'
|
|
11
12
|
import type { LockDevice } from 'lib/seam/locks/lock-device.js'
|
|
12
|
-
import { useToggleLock } from 'lib/seam/locks/use-toggle-lock.js'
|
|
13
13
|
import { Alerts } from 'lib/ui/Alert/Alerts.js'
|
|
14
|
-
import { Button } from 'lib/ui/Button.js'
|
|
15
14
|
import { BatteryStatusIndicator } from 'lib/ui/device/BatteryStatusIndicator.js'
|
|
16
15
|
import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
|
|
17
16
|
import { EditableDeviceName } from 'lib/ui/device/EditableDeviceName.js'
|
|
@@ -48,20 +47,6 @@ export function LockDeviceDetails({
|
|
|
48
47
|
const [snackbarVariant, setSnackbarVariant] =
|
|
49
48
|
useState<SnackbarVariant>('success')
|
|
50
49
|
|
|
51
|
-
const toggleLock = useToggleLock({
|
|
52
|
-
onSuccess: () => {
|
|
53
|
-
setSnackbarVisible(true)
|
|
54
|
-
setSnackbarVariant('success')
|
|
55
|
-
},
|
|
56
|
-
onError: () => {
|
|
57
|
-
setSnackbarVisible(true)
|
|
58
|
-
setSnackbarVariant('error')
|
|
59
|
-
},
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
const lockStatus = device.properties.locked ? t.locked : t.unlocked
|
|
63
|
-
const toggleLockLabel = device.properties.locked ? t.unlock : t.lock
|
|
64
|
-
|
|
65
50
|
const accessCodeCount = accessCodes?.length
|
|
66
51
|
|
|
67
52
|
if (accessCodes == null) {
|
|
@@ -163,28 +148,12 @@ export function LockDeviceDetails({
|
|
|
163
148
|
</div>
|
|
164
149
|
|
|
165
150
|
<div className='seam-box'>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
<div className='seam-right'>
|
|
173
|
-
{!disableLockUnlock &&
|
|
174
|
-
device.capabilities_supported.includes('lock') && (
|
|
175
|
-
<Button
|
|
176
|
-
size='small'
|
|
177
|
-
onClick={() => {
|
|
178
|
-
toggleLock.mutate(device)
|
|
179
|
-
}}
|
|
180
|
-
>
|
|
181
|
-
{toggleLockLabel}
|
|
182
|
-
</Button>
|
|
183
|
-
)}
|
|
184
|
-
</div>
|
|
185
|
-
</div>
|
|
186
|
-
)}
|
|
187
|
-
|
|
151
|
+
<LockDeviceLockButtons
|
|
152
|
+
setSnackbarVisible={setSnackbarVisible}
|
|
153
|
+
setSnackbarVariant={setSnackbarVariant}
|
|
154
|
+
device={device}
|
|
155
|
+
disableLockUnlock={disableLockUnlock}
|
|
156
|
+
/>
|
|
188
157
|
<AccessCodeLength
|
|
189
158
|
supportedCodeLengths={
|
|
190
159
|
device.properties?.supported_code_lengths ?? []
|
|
@@ -230,14 +199,9 @@ function AccessCodeLength(props: {
|
|
|
230
199
|
|
|
231
200
|
const t = {
|
|
232
201
|
device: 'Device',
|
|
233
|
-
unlock: 'Unlock',
|
|
234
|
-
lock: 'Lock',
|
|
235
|
-
locked: 'Locked',
|
|
236
|
-
unlocked: 'Unlocked',
|
|
237
202
|
accessCodes: 'access codes',
|
|
238
203
|
codeLength: 'Code length',
|
|
239
204
|
digits: 'digits',
|
|
240
|
-
lockStatus: 'Lock status',
|
|
241
205
|
status: 'Status',
|
|
242
206
|
power: 'Power',
|
|
243
207
|
successfullyUpdated: 'Lock status has been successfully updated',
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { LockDevice } from 'lib/seam/locks/lock-device.js'
|
|
2
|
+
import { useLock } from 'lib/seam/locks/use-lock-door.js'
|
|
3
|
+
import { useToggleLock } from 'lib/seam/locks/use-toggle-lock.js'
|
|
4
|
+
import { useUnlock } from 'lib/seam/locks/use-unlock-door.js'
|
|
5
|
+
import { Button } from 'lib/ui/Button.js'
|
|
6
|
+
import type { SnackbarVariant } from 'lib/ui/Snackbar/Snackbar.js'
|
|
7
|
+
|
|
8
|
+
interface LockDeviceLockButtonsProps {
|
|
9
|
+
device: LockDevice
|
|
10
|
+
disableLockUnlock: boolean
|
|
11
|
+
setSnackbarVisible: (visible: boolean) => void
|
|
12
|
+
setSnackbarVariant: (variant: SnackbarVariant) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function LockDeviceLockButtons({
|
|
16
|
+
device,
|
|
17
|
+
setSnackbarVariant,
|
|
18
|
+
setSnackbarVisible,
|
|
19
|
+
disableLockUnlock,
|
|
20
|
+
}: LockDeviceLockButtonsProps): JSX.Element | null {
|
|
21
|
+
const lockStatus = device.properties.locked ? t.locked : t.unlocked
|
|
22
|
+
const toggleLockLabel = device.properties.locked ? t.unlock : t.lock
|
|
23
|
+
|
|
24
|
+
const toggleLock = useToggleLock({
|
|
25
|
+
onSuccess: () => {
|
|
26
|
+
setSnackbarVisible(true)
|
|
27
|
+
setSnackbarVariant('success')
|
|
28
|
+
},
|
|
29
|
+
onError: () => {
|
|
30
|
+
setSnackbarVisible(true)
|
|
31
|
+
setSnackbarVariant('error')
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const lock = useLock({
|
|
36
|
+
onSuccess: () => {
|
|
37
|
+
setSnackbarVisible(true)
|
|
38
|
+
setSnackbarVariant('success')
|
|
39
|
+
},
|
|
40
|
+
onError: () => {
|
|
41
|
+
setSnackbarVisible(true)
|
|
42
|
+
setSnackbarVariant('error')
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const unlock = useUnlock({
|
|
47
|
+
onSuccess: () => {
|
|
48
|
+
setSnackbarVisible(true)
|
|
49
|
+
setSnackbarVariant('success')
|
|
50
|
+
},
|
|
51
|
+
onError: () => {
|
|
52
|
+
setSnackbarVisible(true)
|
|
53
|
+
setSnackbarVariant('error')
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
if (disableLockUnlock) {
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (
|
|
62
|
+
device.can_remotely_lock === true &&
|
|
63
|
+
device.can_remotely_unlock === true
|
|
64
|
+
) {
|
|
65
|
+
return (
|
|
66
|
+
<div className='seam-content seam-lock-status'>
|
|
67
|
+
<div>
|
|
68
|
+
<span className='seam-label'>{t.lockStatus}</span>
|
|
69
|
+
<span className='seam-value'>{lockStatus}</span>
|
|
70
|
+
</div>
|
|
71
|
+
<div className='seam-right'>
|
|
72
|
+
<Button
|
|
73
|
+
size='small'
|
|
74
|
+
onClick={() => {
|
|
75
|
+
toggleLock.mutate(device)
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
{toggleLockLabel}
|
|
79
|
+
</Button>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (device.can_remotely_lock === true) {
|
|
86
|
+
return (
|
|
87
|
+
<div className='seam-content seam-lock-status'>
|
|
88
|
+
<div>
|
|
89
|
+
<span className='seam-label'>{t.lockStatus}</span>
|
|
90
|
+
<span className='seam-value'>{lockStatus}</span>
|
|
91
|
+
</div>
|
|
92
|
+
<div className='seam-right'>
|
|
93
|
+
<Button
|
|
94
|
+
size='small'
|
|
95
|
+
onClick={() => {
|
|
96
|
+
lock.mutate(device)
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
{t.lock}
|
|
100
|
+
</Button>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (device.can_remotely_unlock === true) {
|
|
107
|
+
return (
|
|
108
|
+
<div className='seam-content seam-lock-status'>
|
|
109
|
+
<div>
|
|
110
|
+
<span className='seam-label'>{t.lockStatus}</span>
|
|
111
|
+
<span className='seam-value'>{lockStatus}</span>
|
|
112
|
+
</div>
|
|
113
|
+
<div className='seam-right'>
|
|
114
|
+
<Button
|
|
115
|
+
size='small'
|
|
116
|
+
onClick={() => {
|
|
117
|
+
unlock.mutate(device)
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{t.unlock}
|
|
121
|
+
</Button>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const t = {
|
|
131
|
+
unlock: 'Unlock',
|
|
132
|
+
lock: 'Lock',
|
|
133
|
+
locked: 'Locked',
|
|
134
|
+
unlocked: 'Unlocked',
|
|
135
|
+
lockStatus: 'Lock status',
|
|
136
|
+
statusUnknown: 'Unknown',
|
|
137
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
SeamActionAttemptFailedError,
|
|
3
|
+
SeamActionAttemptTimeoutError,
|
|
4
|
+
SeamHttpApiError,
|
|
5
|
+
} from '@seamapi/http/connect'
|
|
6
|
+
import { NullSeamClientError, useSeamClient } from '@seamapi/react-query'
|
|
7
|
+
import type { ActionAttempt, Device } from '@seamapi/types/connect'
|
|
8
|
+
import {
|
|
9
|
+
useMutation,
|
|
10
|
+
type UseMutationResult,
|
|
11
|
+
useQueryClient,
|
|
12
|
+
} from '@tanstack/react-query'
|
|
13
|
+
|
|
14
|
+
export type UseLockData = undefined
|
|
15
|
+
|
|
16
|
+
export type UseLockMutationVariables = Pick<Device, 'device_id'> & {
|
|
17
|
+
properties: Required<Pick<Device['properties'], 'locked'>>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type LockActionAttempt = Extract<ActionAttempt, { action_type: 'LOCK_DOOR' }>
|
|
21
|
+
|
|
22
|
+
type MutationError =
|
|
23
|
+
| SeamHttpApiError
|
|
24
|
+
| SeamActionAttemptFailedError<LockActionAttempt>
|
|
25
|
+
| SeamActionAttemptTimeoutError<LockActionAttempt>
|
|
26
|
+
|
|
27
|
+
interface UseLockParams {
|
|
28
|
+
onError?: () => void
|
|
29
|
+
onSuccess?: () => void
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function useLock(
|
|
33
|
+
params: UseLockParams = {}
|
|
34
|
+
): UseMutationResult<UseLockData, MutationError, UseLockMutationVariables> {
|
|
35
|
+
const { client } = useSeamClient()
|
|
36
|
+
const queryClient = useQueryClient()
|
|
37
|
+
|
|
38
|
+
return useMutation<UseLockData, MutationError, UseLockMutationVariables>({
|
|
39
|
+
mutationFn: async (variables) => {
|
|
40
|
+
const {
|
|
41
|
+
device_id: deviceId,
|
|
42
|
+
properties: { locked },
|
|
43
|
+
} = variables
|
|
44
|
+
if (client === null) throw new NullSeamClientError()
|
|
45
|
+
if (locked == null) return
|
|
46
|
+
await client.locks.lockDoor({ device_id: deviceId })
|
|
47
|
+
},
|
|
48
|
+
onMutate: (variables) => {
|
|
49
|
+
queryClient.setQueryData<Device[]>(['devices', 'list', {}], (devices) => {
|
|
50
|
+
if (devices == null) {
|
|
51
|
+
return devices
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return devices.map((device) => {
|
|
55
|
+
if (
|
|
56
|
+
device.device_id !== variables.device_id ||
|
|
57
|
+
device.properties.locked == null
|
|
58
|
+
) {
|
|
59
|
+
return device
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
...device,
|
|
64
|
+
properties: {
|
|
65
|
+
...device.properties,
|
|
66
|
+
locked: !variables.properties.locked,
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
queryClient.setQueryData<Device>(
|
|
73
|
+
['devices', 'get', { device_id: variables.device_id }],
|
|
74
|
+
(device) => {
|
|
75
|
+
if (device?.properties.locked == null) return device
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
...device,
|
|
79
|
+
properties: {
|
|
80
|
+
...device.properties,
|
|
81
|
+
locked: !variables.properties.locked,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
},
|
|
87
|
+
onError: async (_error, variables) => {
|
|
88
|
+
params.onError?.()
|
|
89
|
+
|
|
90
|
+
await queryClient.invalidateQueries({
|
|
91
|
+
queryKey: ['devices', 'list'],
|
|
92
|
+
})
|
|
93
|
+
await queryClient.invalidateQueries({
|
|
94
|
+
queryKey: ['devices', 'get', { device_id: variables.device_id }],
|
|
95
|
+
})
|
|
96
|
+
},
|
|
97
|
+
onSuccess() {
|
|
98
|
+
params.onSuccess?.()
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
}
|