@seamapi/react 0.15.0 → 0.16.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/lib/SeamProvider.d.ts +14 -6
- package/lib/SeamProvider.js +62 -16
- package/lib/SeamProvider.js.map +1 -1
- package/lib/hooks/use-access-codes.d.ts +5 -0
- package/lib/hooks/use-access-codes.js +16 -0
- package/lib/hooks/use-access-codes.js.map +1 -0
- package/lib/hooks/use-device.d.ts +5 -0
- package/lib/hooks/use-device.js +17 -0
- package/lib/hooks/use-device.js.map +1 -0
- package/lib/hooks/use-devices.d.ts +1 -0
- package/lib/hooks/use-devices.js +2 -0
- package/lib/hooks/use-devices.js.map +1 -0
- package/lib/hooks/use-seam-client.d.ts +1 -0
- package/lib/hooks/use-seam-client.js +2 -0
- package/lib/hooks/use-seam-client.js.map +1 -0
- package/lib/seam/use-seam-client.js +28 -26
- package/lib/seam/use-seam-client.js.map +1 -1
- package/lib/types/use-seam-query-result.d.ts +5 -0
- package/lib/types/use-seam-query-result.js +2 -0
- package/lib/types/use-seam-query-result.js.map +1 -0
- package/lib/ui/AccessCodeTable/AccessCodeTable.d.ts +3 -5
- package/lib/ui/AccessCodeTable/AccessCodeTable.js +8 -2
- package/lib/ui/AccessCodeTable/AccessCodeTable.js.map +1 -1
- package/lib/ui/DeviceDetails/DeviceDetails.js +1 -3
- package/lib/ui/DeviceDetails/DeviceDetails.js.map +1 -1
- package/package.json +5 -3
- package/src/lib/SeamProvider.tsx +102 -30
- package/src/lib/hooks/use-access-codes.ts +21 -0
- package/src/lib/hooks/use-device.ts +26 -0
- package/src/lib/hooks/use-devices.ts +1 -0
- package/src/lib/hooks/use-seam-client.ts +1 -0
- package/src/lib/seam/use-seam-client.ts +45 -39
- package/src/lib/types/use-seam-query-result.ts +7 -0
- package/src/lib/ui/AccessCodeTable/AccessCodeTable.tsx +9 -7
- package/src/lib/ui/DeviceDetails/DeviceDetails.tsx +2 -5
package/lib/SeamProvider.d.ts
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import { type PropsWithChildren } from 'react';
|
|
2
2
|
import type { Seam, SeamClientOptions } from 'seamapi';
|
|
3
3
|
declare global {
|
|
4
|
-
var seam:
|
|
4
|
+
var seam: SeamProviderProps | undefined;
|
|
5
5
|
}
|
|
6
6
|
export interface SeamContext {
|
|
7
7
|
client: Seam | null;
|
|
8
|
-
clientOptions?:
|
|
8
|
+
clientOptions?: AllowedSeamClientOptions | undefined;
|
|
9
9
|
publishableKey?: string | undefined;
|
|
10
10
|
userIdentifierKey?: string | undefined;
|
|
11
|
+
clientSessionToken?: string | undefined;
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
type SeamProviderProps = SeamProviderPropsWithClient | (SeamProviderPropsWithPublishableKey & AllowedSeamClientOptions) | (SeamProviderPropsWithClientSessionToken & AllowedSeamClientOptions);
|
|
14
|
+
interface SeamProviderPropsWithClient {
|
|
15
|
+
client: Seam;
|
|
16
|
+
}
|
|
17
|
+
interface SeamProviderPropsWithPublishableKey {
|
|
18
|
+
publishableKey: string;
|
|
15
19
|
userIdentifierKey?: string;
|
|
16
|
-
endpoint?: string;
|
|
17
20
|
}
|
|
21
|
+
interface SeamProviderPropsWithClientSessionToken {
|
|
22
|
+
clientSessionToken: string;
|
|
23
|
+
}
|
|
24
|
+
type AllowedSeamClientOptions = Pick<SeamClientOptions, 'endpoint'>;
|
|
18
25
|
export declare function SeamProvider({ children, ...props }: PropsWithChildren<SeamProviderProps>): JSX.Element;
|
|
19
26
|
export declare const seamContext: import("react").Context<SeamContext>;
|
|
20
27
|
export declare function useSeamContext(): SeamContext;
|
|
28
|
+
export {};
|
package/lib/SeamProvider.js
CHANGED
|
@@ -17,8 +17,7 @@ export function SeamProvider({ children, ...props }) {
|
|
|
17
17
|
return (_jsx("div", { className: 'seam-components', children: _jsx(QueryClientProvider, { client: queryClientRef.current, children: _jsx(Provider, { value: { ...contextRef.current }, children: children }) }) }));
|
|
18
18
|
}
|
|
19
19
|
const createDefaultSeamContextValue = () => {
|
|
20
|
-
if (globalThis.seam
|
|
21
|
-
globalThis.seam?.publishableKey == null) {
|
|
20
|
+
if (globalThis.seam == null) {
|
|
22
21
|
return { client: null };
|
|
23
22
|
}
|
|
24
23
|
try {
|
|
@@ -30,23 +29,28 @@ const createDefaultSeamContextValue = () => {
|
|
|
30
29
|
return { client: null };
|
|
31
30
|
}
|
|
32
31
|
};
|
|
33
|
-
const createSeamContextValue = (
|
|
34
|
-
if (
|
|
35
|
-
return
|
|
32
|
+
const createSeamContextValue = (options) => {
|
|
33
|
+
if (isSeamProviderPropsWithClient(options)) {
|
|
34
|
+
return options;
|
|
36
35
|
}
|
|
37
|
-
if (
|
|
38
|
-
|
|
36
|
+
if (isSeamProviderPropsWithClientSessionToken(options)) {
|
|
37
|
+
const { clientSessionToken, ...clientOptions } = options;
|
|
38
|
+
return {
|
|
39
|
+
clientSessionToken,
|
|
40
|
+
clientOptions,
|
|
41
|
+
client: null,
|
|
42
|
+
};
|
|
39
43
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return {
|
|
44
|
+
if (isSeamProviderPropsWithPublishableKey(options)) {
|
|
45
|
+
const { publishableKey, userIdentifierKey, ...clientOptions } = options;
|
|
46
|
+
return {
|
|
47
|
+
publishableKey,
|
|
48
|
+
userIdentifierKey,
|
|
49
|
+
clientOptions,
|
|
50
|
+
client: null,
|
|
51
|
+
};
|
|
43
52
|
}
|
|
44
|
-
|
|
45
|
-
client: null,
|
|
46
|
-
publishableKey,
|
|
47
|
-
userIdentifierKey,
|
|
48
|
-
clientOptions,
|
|
49
|
-
};
|
|
53
|
+
throw new Error('Invalid SeamProvider options');
|
|
50
54
|
};
|
|
51
55
|
const defaultSeamContextValue = createDefaultSeamContextValue();
|
|
52
56
|
export const seamContext = createContext(defaultSeamContextValue);
|
|
@@ -57,4 +61,46 @@ export function useSeamContext() {
|
|
|
57
61
|
}
|
|
58
62
|
return context;
|
|
59
63
|
}
|
|
64
|
+
const isSeamProviderPropsWithClient = (props) => {
|
|
65
|
+
if (!('client' in props))
|
|
66
|
+
return false;
|
|
67
|
+
const { client } = props;
|
|
68
|
+
if (client == null)
|
|
69
|
+
return false;
|
|
70
|
+
if (Object.values(props).some((v) => v == null)) {
|
|
71
|
+
throw new Error('Cannot provide a Seam client along with other options.');
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
};
|
|
75
|
+
const isSeamProviderPropsWithPublishableKey = (props) => {
|
|
76
|
+
if (!('publishableKey' in props))
|
|
77
|
+
return false;
|
|
78
|
+
const { publishableKey } = props;
|
|
79
|
+
if (publishableKey == null)
|
|
80
|
+
return false;
|
|
81
|
+
if ('client' in props && props.client != null) {
|
|
82
|
+
throw new Error('Cannot provide a Seam client along with other options.');
|
|
83
|
+
}
|
|
84
|
+
if ('clientSessionToken' in props && props.clientSessionToken != null) {
|
|
85
|
+
throw new Error('Cannot provide both a publishableKey and a clientSessionToken.');
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
};
|
|
89
|
+
const isSeamProviderPropsWithClientSessionToken = (props) => {
|
|
90
|
+
if (!('clientSessionToken' in props))
|
|
91
|
+
return false;
|
|
92
|
+
const { clientSessionToken } = props;
|
|
93
|
+
if (clientSessionToken == null)
|
|
94
|
+
return false;
|
|
95
|
+
if ('client' in props && props.client != null) {
|
|
96
|
+
throw new Error('Cannot provide a Seam client along with other options.');
|
|
97
|
+
}
|
|
98
|
+
if ('publishableKey' in props && props.publishableKey != null) {
|
|
99
|
+
throw new Error('Cannot provide both a clientSessionToken and a publishableKey .');
|
|
100
|
+
}
|
|
101
|
+
if ('userIdentifierKey' in props && props.userIdentifierKey != null) {
|
|
102
|
+
throw new Error('Cannot use a userIdentifierKey with a clientSessionToken.');
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
};
|
|
60
106
|
//# sourceMappingURL=SeamProvider.js.map
|
package/lib/SeamProvider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SeamProvider.js","sourceRoot":"","sources":["../src/lib/SeamProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AACxE,OAAO,EACL,aAAa,EAEb,UAAU,EACV,MAAM,GACP,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"SeamProvider.js","sourceRoot":"","sources":["../src/lib/SeamProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { useSeamClient } from '../../lib/seam/use-seam-client.js';
|
|
3
|
+
export function useAccessCodes(params) {
|
|
4
|
+
const { client } = useSeamClient();
|
|
5
|
+
const { data, ...rest } = useQuery({
|
|
6
|
+
enabled: client != null,
|
|
7
|
+
queryKey: ['access_codes', 'list', params],
|
|
8
|
+
queryFn: async () => {
|
|
9
|
+
if (client == null)
|
|
10
|
+
return [];
|
|
11
|
+
return await client?.accessCodes.list(params);
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
return { ...rest, accessCodes: data };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=use-access-codes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-access-codes.js","sourceRoot":"","sources":["../../src/lib/hooks/use-access-codes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAG3D,MAAM,UAAU,cAAc,CAAC,MAE9B;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAiB;QACjD,OAAO,EAAE,MAAM,IAAI,IAAI;QACvB,QAAQ,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC;QAC1C,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,EAAE,CAAA;YAC7B,OAAO,MAAM,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC/C,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;AACvC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { useSeamClient } from '../../lib/seam/use-seam-client.js';
|
|
3
|
+
export function useDevice(params) {
|
|
4
|
+
const objParams = typeof params === 'string' ? { device_id: params } : params;
|
|
5
|
+
const { client } = useSeamClient();
|
|
6
|
+
const { data, ...rest } = useQuery({
|
|
7
|
+
enabled: client != null,
|
|
8
|
+
queryKey: ['devices', 'get', params],
|
|
9
|
+
queryFn: async () => {
|
|
10
|
+
if (client == null)
|
|
11
|
+
return [];
|
|
12
|
+
return await client?.devices.get(objParams);
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
return { ...rest, device: data };
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=use-device.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-device.js","sourceRoot":"","sources":["../../src/lib/hooks/use-device.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAG3D,MAAM,UAAU,SAAS,CACvB,MAIU;IAEV,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;IAC7E,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAiB;QACjD,OAAO,EAAE,MAAM,IAAI,IAAI;QACvB,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC;QACpC,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,EAAE,CAAA;YAC7B,OAAO,MAAM,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC7C,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;AAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useDevices } from '../../lib/seam/devices/use-devices.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-devices.js","sourceRoot":"","sources":["../../src/lib/hooks/use-devices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useSeamClient } from '../../lib/seam/use-seam-client.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-seam-client.js","sourceRoot":"","sources":["../../src/lib/hooks/use-seam-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA"}
|
|
@@ -3,23 +3,31 @@ import { Seam } from 'seamapi';
|
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
4
|
import { useSeamContext } from '../../lib/SeamProvider.js';
|
|
5
5
|
export function useSeamClient() {
|
|
6
|
-
const { client, clientOptions, publishableKey, ...context } = useSeamContext();
|
|
7
|
-
const
|
|
8
|
-
const userIdentifierKey = useUserIdentifierKey(context.userIdentifierKey);
|
|
6
|
+
const { client, clientOptions, publishableKey, clientSessionToken, ...context } = useSeamContext();
|
|
7
|
+
const userIdentifierKey = useUserIdentifierKeyOrFingerprint(clientSessionToken != null ? '' : context.userIdentifierKey);
|
|
9
8
|
const { isLoading, isError, error, data } = useQuery({
|
|
10
|
-
queryKey: [
|
|
9
|
+
queryKey: [
|
|
10
|
+
'client',
|
|
11
|
+
{
|
|
12
|
+
client,
|
|
13
|
+
clientOptions,
|
|
14
|
+
publishableKey,
|
|
15
|
+
userIdentifierKey,
|
|
16
|
+
clientSessionToken,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
11
19
|
queryFn: async () => {
|
|
12
20
|
if (client != null)
|
|
13
21
|
return client;
|
|
14
|
-
if (
|
|
15
|
-
throw new Error('Missing publishableKey');
|
|
16
|
-
}
|
|
17
|
-
if (clientSession != null) {
|
|
22
|
+
if (clientSessionToken != null) {
|
|
18
23
|
return new Seam({
|
|
19
24
|
...clientOptions,
|
|
20
|
-
clientSessionToken
|
|
25
|
+
clientSessionToken,
|
|
21
26
|
});
|
|
22
27
|
}
|
|
28
|
+
if (publishableKey == null) {
|
|
29
|
+
throw new Error('Missing either a client, publishableKey, or clientSessionToken');
|
|
30
|
+
}
|
|
23
31
|
const res = await Seam.getClientSessionToken({
|
|
24
32
|
...clientOptions,
|
|
25
33
|
publishableKey,
|
|
@@ -28,7 +36,6 @@ export function useSeamClient() {
|
|
|
28
36
|
if (!res.ok || res.client_session?.token == null) {
|
|
29
37
|
throw new Error('Failed to get client access token');
|
|
30
38
|
}
|
|
31
|
-
setClientSession(res.client_session);
|
|
32
39
|
return new Seam({
|
|
33
40
|
...clientOptions,
|
|
34
41
|
clientSessionToken: res.client_session.token,
|
|
@@ -37,24 +44,19 @@ export function useSeamClient() {
|
|
|
37
44
|
});
|
|
38
45
|
return { client: data ?? null, isLoading, isError, error };
|
|
39
46
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
cachedClientSession != null ? JSON.parse(cachedClientSession) : null,
|
|
48
|
-
setClientSession,
|
|
49
|
-
];
|
|
50
|
-
}
|
|
51
|
-
function useUserIdentifierKey(userIdentifierKey) {
|
|
47
|
+
/**
|
|
48
|
+
* You'll almost always want to supply a user identifier key, but if you don't
|
|
49
|
+
* we'll automatically pick a fingerprint for this user. The user interface
|
|
50
|
+
* will show warnings when you use a fingerprint because this client session
|
|
51
|
+
* is bound to this machine, and is effectively ephemeral.
|
|
52
|
+
*/
|
|
53
|
+
function useUserIdentifierKeyOrFingerprint(userIdentifierKey) {
|
|
52
54
|
if (userIdentifierKey != null) {
|
|
53
55
|
return userIdentifierKey;
|
|
54
56
|
}
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
globalThis?.localStorage?.setItem(
|
|
58
|
-
return
|
|
57
|
+
const fingerprintValue = globalThis?.localStorage?.getItem('seam_user_fingerprint') ??
|
|
58
|
+
`fingerprint_${uuidv4()}`;
|
|
59
|
+
globalThis?.localStorage?.setItem('seam_user_fingerprint', fingerprintValue);
|
|
60
|
+
return fingerprintValue;
|
|
59
61
|
}
|
|
60
62
|
//# sourceMappingURL=use-seam-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-seam-client.js","sourceRoot":"","sources":["../../src/lib/seam/use-seam-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,
|
|
1
|
+
{"version":3,"file":"use-seam-client.js","sourceRoot":"","sources":["../../src/lib/seam/use-seam-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC9B,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAA;AAEnC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEpD,MAAM,UAAU,aAAa;IAM3B,MAAM,EACJ,MAAM,EACN,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,GAAG,OAAO,EACX,GAAG,cAAc,EAAE,CAAA;IACpB,MAAM,iBAAiB,GAAG,iCAAiC,CACzD,kBAAkB,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAC5D,CAAA;IAED,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAO;QACzD,QAAQ,EAAE;YACR,QAAQ;YACR;gBACE,MAAM;gBACN,aAAa;gBACb,cAAc;gBACd,iBAAiB;gBACjB,kBAAkB;aACnB;SACF;QACD,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,MAAM,CAAA;YAEjC,IAAI,kBAAkB,IAAI,IAAI,EAAE;gBAC9B,OAAO,IAAI,IAAI,CAAC;oBACd,GAAG,aAAa;oBAChB,kBAAkB;iBACnB,CAAC,CAAA;aACH;YAED,IAAI,cAAc,IAAI,IAAI,EAAE;gBAC1B,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAA;aACF;YAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC;gBAC3C,GAAG,aAAa;gBAChB,cAAc;gBACd,iBAAiB;aAClB,CAAC,CAAA;YAEF,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,cAAc,EAAE,KAAK,IAAI,IAAI,EAAE;gBAChD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;aACrD;YAED,OAAO,IAAI,IAAI,CAAC;gBACd,GAAG,aAAa;gBAChB,kBAAkB,EAAE,GAAG,CAAC,cAAc,CAAC,KAAK;aAC7C,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,MAAM,EAAE,IAAI,IAAI,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;AAC5D,CAAC;AAED;;;;;GAKG;AACH,SAAS,iCAAiC,CACxC,iBAAqC;IAErC,IAAI,iBAAiB,IAAI,IAAI,EAAE;QAC7B,OAAO,iBAAiB,CAAA;KACzB;IAED,MAAM,gBAAgB,GACpB,UAAU,EAAE,YAAY,EAAE,OAAO,CAAC,uBAAuB,CAAC;QAC1D,eAAe,MAAM,EAAE,EAAE,CAAA;IAE3B,UAAU,EAAE,YAAY,EAAE,OAAO,CAAC,uBAAuB,EAAE,gBAAgB,CAAC,CAAA;IAE5E,OAAO,gBAAgB,CAAA;AACzB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { UseQueryResult } from '@tanstack/react-query';
|
|
2
|
+
import type { SeamError } from 'seamapi';
|
|
3
|
+
export type UseSeamQueryResult<Field extends string, ResponsePayload> = Omit<UseQueryResult<ResponsePayload, SeamError>, 'data'> & {
|
|
4
|
+
[key in Field]?: ResponsePayload;
|
|
5
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-seam-query-result.js","sourceRoot":"","sources":["../../src/lib/types/use-seam-query-result.ts"],"names":[],"mappings":""}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
accessCodes: AccessCode[];
|
|
1
|
+
export declare function AccessCodeTable(props: {
|
|
2
|
+
deviceId: string;
|
|
4
3
|
onClickBack?: () => void;
|
|
5
|
-
}
|
|
6
|
-
export declare function AccessCodeTable(props: AccessCodeTableProps): JSX.Element;
|
|
4
|
+
}): JSX.Element;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { TableBody, TableCell, TableHeader, TableRow, TableTitle, } from '../../../lib/ui/Table/index.js';
|
|
3
|
+
import { useAccessCodes } from '../../../lib/hooks/use-access-codes.js';
|
|
3
4
|
import { AccessCodeKeyIcon } from '../../../lib/icons/AccessCodeKey.js';
|
|
4
5
|
import { CodeDetails } from '../../../lib/ui/AccessCodeTable/CodeDetails.js';
|
|
5
6
|
import { ContentHeader } from '../../../lib/ui/layout/ContentHeader.js';
|
|
6
7
|
import { Caption } from '../../../lib/ui/typography/Caption.js';
|
|
7
8
|
import { Title } from '../../../lib/ui/typography/Title.js';
|
|
8
9
|
export function AccessCodeTable(props) {
|
|
9
|
-
const { accessCodes
|
|
10
|
+
const { accessCodes } = useAccessCodes({
|
|
11
|
+
device_id: props.deviceId,
|
|
12
|
+
});
|
|
13
|
+
const { onClickBack } = props;
|
|
14
|
+
if (!accessCodes)
|
|
15
|
+
return _jsx(_Fragment, { children: null });
|
|
10
16
|
return (_jsxs("div", { className: 'seam-access-code-table', children: [_jsx(ContentHeader, { onClickBack: onClickBack }), _jsx(TableHeader, { children: _jsxs(TableTitle, { children: [t.accessCodes, " ", _jsxs(Caption, { children: ["(", accessCodes.length, ")"] })] }) }), _jsx(TableBody, { children: accessCodes.map((code) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: 'seam-icon-cell', children: _jsx("div", { children: _jsx(AccessCodeKeyIcon, {}) }) }), _jsxs(TableCell, { className: 'seam-name-cell', children: [_jsx(Title, { children: code.name }), _jsx(CodeDetails, { accessCode: code })] }), _jsx(TableCell, { className: 'seam-action-cell' })] }, code.access_code_id))) })] }));
|
|
11
17
|
}
|
|
12
18
|
const t = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessCodeTable.js","sourceRoot":"","sources":["../../../src/lib/ui/AccessCodeTable/AccessCodeTable.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"AccessCodeTable.js","sourceRoot":"","sources":["../../../src/lib/ui/AccessCodeTable/AccessCodeTable.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,EACR,UAAU,GACX,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,MAAM,UAAU,eAAe,CAAC,KAG/B;IACC,MAAM,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC;QACrC,SAAS,EAAE,KAAK,CAAC,QAAQ;KAC1B,CAAC,CAAA;IACF,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAA;IAE7B,IAAI,CAAC,WAAW;QAAE,OAAO,4BAAG,IAAI,GAAI,CAAA;IAEpC,OAAO,CACL,eAAK,SAAS,EAAC,wBAAwB,aACrC,KAAC,aAAa,IAAC,WAAW,EAAE,WAAW,GAAI,EAC3C,KAAC,WAAW,cACV,MAAC,UAAU,eACR,CAAC,CAAC,WAAW,OAAE,MAAC,OAAO,oBAAG,WAAW,CAAC,MAAM,SAAY,IAC9C,GACD,EACd,KAAC,SAAS,cACP,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACzB,MAAC,QAAQ,eACP,KAAC,SAAS,IAAC,SAAS,EAAC,gBAAgB,YACnC,wBACE,KAAC,iBAAiB,KAAG,GACjB,GACI,EACZ,MAAC,SAAS,IAAC,SAAS,EAAC,gBAAgB,aACnC,KAAC,KAAK,cAAE,IAAI,CAAC,IAAI,GAAS,EAC1B,KAAC,WAAW,IAAC,UAAU,EAAE,IAAI,GAAI,IACvB,EACZ,KAAC,SAAS,IAAC,SAAS,EAAC,kBAAkB,GAI3B,KAdC,IAAI,CAAC,cAAc,CAevB,CACZ,CAAC,GACQ,IACR,CACP,CAAA;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,WAAW,EAAE,cAAc;CAC5B,CAAA"}
|
|
@@ -12,11 +12,9 @@ export function DeviceDetails(props) {
|
|
|
12
12
|
const { device } = props;
|
|
13
13
|
const lockStatus = device.properties.locked ? t.locked : t.unlocked;
|
|
14
14
|
const accessCodeLength = device.properties?.schlage_metadata?.access_code_length;
|
|
15
|
-
// TODO : Fetch access codes
|
|
16
|
-
const accessCodes = [];
|
|
17
15
|
const [showingAccessCodes, toggleAccessCodes] = useToggle();
|
|
18
16
|
if (showingAccessCodes) {
|
|
19
|
-
return (_jsx(AccessCodeTable, {
|
|
17
|
+
return (_jsx(AccessCodeTable, { deviceId: device.device_id, onClickBack: toggleAccessCodes }));
|
|
20
18
|
}
|
|
21
19
|
return (_jsxs("div", { className: 'seam-device-details', children: [_jsx(ContentHeader, { title: 'Device' }), _jsxs("div", { className: 'seam-body', children: [_jsx("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("h4", { className: 'seam-device-name', children: device.properties.name }), _jsxs("div", { className: 'seam-properties', children: [_jsx(OnlineStatus, { device: device }), _jsx(BatteryStatus, { device: device }), _jsx(ModelStatus, { device: device })] })] })] }) }), _jsx("div", { className: 'seam-box', children: _jsxs("div", { className: 'seam-content seam-access-codes', onClick: toggleAccessCodes, children: [_jsxs("span", { className: 'seam-value', children: ["49 ", t.accessCodes] }), _jsx(ChevronRightIcon, {})] }) }), _jsxs("div", { className: 'seam-box', children: [_jsxs("div", { className: 'seam-content', children: [_jsx("span", { className: 'seam-label', children: t.lockStatus }), _jsx("span", { className: 'seam-value', children: lockStatus })] }), _jsx(AccessCodeLength, { accessCodeLength: accessCodeLength })] })] })] }));
|
|
22
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceDetails.js","sourceRoot":"","sources":["../../../src/lib/ui/DeviceDetails/DeviceDetails.tsx"],"names":[],"mappings":";AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"DeviceDetails.js","sourceRoot":"","sources":["../../../src/lib/ui/DeviceDetails/DeviceDetails.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seamapi/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Seam React component library.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
],
|
|
46
46
|
"scripts": {
|
|
47
47
|
"start": "concurrently --raw --kill-others npm:examples npm:storybook",
|
|
48
|
+
"dev": "npm run start",
|
|
48
49
|
"build": "npm run build:js",
|
|
49
50
|
"prebuild": "del 'index.*' lib",
|
|
50
51
|
"postbuild": "node ./index.js",
|
|
@@ -93,17 +94,17 @@
|
|
|
93
94
|
"@tanstack/react-query": "^4.28.0",
|
|
94
95
|
"classnames": "^2.3.2",
|
|
95
96
|
"luxon": "^3.3.0",
|
|
96
|
-
"seamapi": "^5.19.0-alpha.
|
|
97
|
+
"seamapi": "^5.19.0-alpha.3",
|
|
97
98
|
"uuid": "^9.0.0"
|
|
98
99
|
},
|
|
99
100
|
"devDependencies": {
|
|
100
101
|
"@babel/preset-env": "^7.21.4",
|
|
101
102
|
"@babel/preset-react": "^7.18.6",
|
|
102
103
|
"@babel/preset-typescript": "^7.21.4",
|
|
103
|
-
"@seamapi/fake-seam-connect": "^0.3.0-alpha.5",
|
|
104
104
|
"@emotion/styled": "^11.10.6",
|
|
105
105
|
"@mui/icons-material": "^5.11.16",
|
|
106
106
|
"@mui/material": "^5.12.2",
|
|
107
|
+
"@seamapi/fake-seam-connect": "^0.3.0-alpha.5",
|
|
107
108
|
"@storybook/addon-essentials": "^7.0.2",
|
|
108
109
|
"@storybook/addon-interactions": "^7.0.2",
|
|
109
110
|
"@storybook/addon-links": "^7.0.2",
|
|
@@ -135,6 +136,7 @@
|
|
|
135
136
|
"eslint-plugin-unused-imports": "^2.0.0",
|
|
136
137
|
"fast-glob": "^3.2.12",
|
|
137
138
|
"http-proxy-middleware": "^2.0.6",
|
|
139
|
+
"isomorphic-fetch": "^3.0.0",
|
|
138
140
|
"jest": "^29.5.0",
|
|
139
141
|
"jest-environment-jsdom": "^29.5.0",
|
|
140
142
|
"prettier": "^2.3.0",
|
package/src/lib/SeamProvider.tsx
CHANGED
|
@@ -11,23 +11,37 @@ import type { Seam, SeamClientOptions } from 'seamapi'
|
|
|
11
11
|
|
|
12
12
|
declare global {
|
|
13
13
|
// eslint-disable-next-line no-var
|
|
14
|
-
var seam:
|
|
14
|
+
var seam: SeamProviderProps | undefined
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface SeamContext {
|
|
18
18
|
client: Seam | null
|
|
19
|
-
clientOptions?:
|
|
19
|
+
clientOptions?: AllowedSeamClientOptions | undefined
|
|
20
20
|
publishableKey?: string | undefined
|
|
21
21
|
userIdentifierKey?: string | undefined
|
|
22
|
+
clientSessionToken?: string | undefined
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
type SeamProviderProps =
|
|
26
|
+
| SeamProviderPropsWithClient
|
|
27
|
+
| (SeamProviderPropsWithPublishableKey & AllowedSeamClientOptions)
|
|
28
|
+
| (SeamProviderPropsWithClientSessionToken & AllowedSeamClientOptions)
|
|
29
|
+
|
|
30
|
+
interface SeamProviderPropsWithClient {
|
|
31
|
+
client: Seam
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface SeamProviderPropsWithPublishableKey {
|
|
35
|
+
publishableKey: string
|
|
27
36
|
userIdentifierKey?: string
|
|
28
|
-
endpoint?: string
|
|
29
37
|
}
|
|
30
38
|
|
|
39
|
+
interface SeamProviderPropsWithClientSessionToken {
|
|
40
|
+
clientSessionToken: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type AllowedSeamClientOptions = Pick<SeamClientOptions, 'endpoint'>
|
|
44
|
+
|
|
31
45
|
export function SeamProvider({
|
|
32
46
|
children,
|
|
33
47
|
...props
|
|
@@ -61,10 +75,7 @@ export function SeamProvider({
|
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
const createDefaultSeamContextValue = (): SeamContext => {
|
|
64
|
-
if (
|
|
65
|
-
globalThis.seam?.client == null &&
|
|
66
|
-
globalThis.seam?.publishableKey == null
|
|
67
|
-
) {
|
|
78
|
+
if (globalThis.seam == null) {
|
|
68
79
|
return { client: null }
|
|
69
80
|
}
|
|
70
81
|
|
|
@@ -77,32 +88,31 @@ const createDefaultSeamContextValue = (): SeamContext => {
|
|
|
77
88
|
}
|
|
78
89
|
}
|
|
79
90
|
|
|
80
|
-
const createSeamContextValue = ({
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}: Omit<SeamProviderProps, 'children'>): SeamContext => {
|
|
84
|
-
if (client == null && Object.keys(options).length === 0) {
|
|
85
|
-
return { client: null }
|
|
91
|
+
const createSeamContextValue = (options: SeamProviderProps): SeamContext => {
|
|
92
|
+
if (isSeamProviderPropsWithClient(options)) {
|
|
93
|
+
return options
|
|
86
94
|
}
|
|
87
95
|
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
if (isSeamProviderPropsWithClientSessionToken(options)) {
|
|
97
|
+
const { clientSessionToken, ...clientOptions } = options
|
|
98
|
+
return {
|
|
99
|
+
clientSessionToken,
|
|
100
|
+
clientOptions,
|
|
101
|
+
client: null,
|
|
102
|
+
}
|
|
92
103
|
}
|
|
93
104
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
if (isSeamProviderPropsWithPublishableKey(options)) {
|
|
106
|
+
const { publishableKey, userIdentifierKey, ...clientOptions } = options
|
|
107
|
+
return {
|
|
108
|
+
publishableKey,
|
|
109
|
+
userIdentifierKey,
|
|
110
|
+
clientOptions,
|
|
111
|
+
client: null,
|
|
112
|
+
}
|
|
98
113
|
}
|
|
99
114
|
|
|
100
|
-
|
|
101
|
-
client: null,
|
|
102
|
-
publishableKey,
|
|
103
|
-
userIdentifierKey,
|
|
104
|
-
clientOptions,
|
|
105
|
-
}
|
|
115
|
+
throw new Error('Invalid SeamProvider options')
|
|
106
116
|
}
|
|
107
117
|
|
|
108
118
|
const defaultSeamContextValue = createDefaultSeamContextValue()
|
|
@@ -118,3 +128,65 @@ export function useSeamContext(): SeamContext {
|
|
|
118
128
|
|
|
119
129
|
return context
|
|
120
130
|
}
|
|
131
|
+
|
|
132
|
+
const isSeamProviderPropsWithClient = (
|
|
133
|
+
props: SeamProviderProps
|
|
134
|
+
): props is SeamProviderPropsWithClient => {
|
|
135
|
+
if (!('client' in props)) return false
|
|
136
|
+
|
|
137
|
+
const { client } = props
|
|
138
|
+
if (client == null) return false
|
|
139
|
+
|
|
140
|
+
if (Object.values(props).some((v) => v == null)) {
|
|
141
|
+
throw new Error('Cannot provide a Seam client along with other options.')
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return true
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const isSeamProviderPropsWithPublishableKey = (
|
|
148
|
+
props: SeamProviderProps
|
|
149
|
+
): props is SeamProviderPropsWithPublishableKey & AllowedSeamClientOptions => {
|
|
150
|
+
if (!('publishableKey' in props)) return false
|
|
151
|
+
|
|
152
|
+
const { publishableKey } = props
|
|
153
|
+
if (publishableKey == null) return false
|
|
154
|
+
|
|
155
|
+
if ('client' in props && props.client != null) {
|
|
156
|
+
throw new Error('Cannot provide a Seam client along with other options.')
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if ('clientSessionToken' in props && props.clientSessionToken != null) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
'Cannot provide both a publishableKey and a clientSessionToken.'
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return true
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const isSeamProviderPropsWithClientSessionToken = (
|
|
169
|
+
props: SeamProviderProps
|
|
170
|
+
): props is SeamProviderPropsWithClientSessionToken &
|
|
171
|
+
AllowedSeamClientOptions => {
|
|
172
|
+
if (!('clientSessionToken' in props)) return false
|
|
173
|
+
|
|
174
|
+
const { clientSessionToken } = props
|
|
175
|
+
if (clientSessionToken == null) return false
|
|
176
|
+
|
|
177
|
+
if ('client' in props && props.client != null) {
|
|
178
|
+
throw new Error('Cannot provide a Seam client along with other options.')
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if ('publishableKey' in props && props.publishableKey != null) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
'Cannot provide both a clientSessionToken and a publishableKey .'
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if ('userIdentifierKey' in props && props.userIdentifierKey != null) {
|
|
188
|
+
throw new Error('Cannot use a userIdentifierKey with a clientSessionToken.')
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return true
|
|
192
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query'
|
|
2
|
+
import type { AccessCode, SeamError } from 'seamapi'
|
|
3
|
+
|
|
4
|
+
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
5
|
+
import type { UseSeamQueryResult } from 'lib/types/use-seam-query-result.js'
|
|
6
|
+
|
|
7
|
+
export function useAccessCodes(params: {
|
|
8
|
+
device_id: string
|
|
9
|
+
}): UseSeamQueryResult<'accessCodes', AccessCode[]> {
|
|
10
|
+
const { client } = useSeamClient()
|
|
11
|
+
const { data, ...rest } = useQuery<any, SeamError>({
|
|
12
|
+
enabled: client != null,
|
|
13
|
+
queryKey: ['access_codes', 'list', params],
|
|
14
|
+
queryFn: async () => {
|
|
15
|
+
if (client == null) return []
|
|
16
|
+
return await client?.accessCodes.list(params)
|
|
17
|
+
},
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
return { ...rest, accessCodes: data }
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query'
|
|
2
|
+
import type { Device, SeamError } from 'seamapi'
|
|
3
|
+
|
|
4
|
+
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
5
|
+
import type { UseSeamQueryResult } from 'lib/types/use-seam-query-result.js'
|
|
6
|
+
|
|
7
|
+
export function useDevice(
|
|
8
|
+
params:
|
|
9
|
+
| {
|
|
10
|
+
device_id: string
|
|
11
|
+
}
|
|
12
|
+
| string
|
|
13
|
+
): UseSeamQueryResult<'device', Device<any>> {
|
|
14
|
+
const objParams = typeof params === 'string' ? { device_id: params } : params
|
|
15
|
+
const { client } = useSeamClient()
|
|
16
|
+
const { data, ...rest } = useQuery<any, SeamError>({
|
|
17
|
+
enabled: client != null,
|
|
18
|
+
queryKey: ['devices', 'get', params],
|
|
19
|
+
queryFn: async () => {
|
|
20
|
+
if (client == null) return []
|
|
21
|
+
return await client?.devices.get(objParams)
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
return { ...rest, device: data }
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useDevices } from 'lib/seam/devices/use-devices.js'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query'
|
|
2
|
-
import {
|
|
2
|
+
import { Seam } from 'seamapi'
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid'
|
|
4
4
|
|
|
5
5
|
import { useSeamContext } from 'lib/SeamProvider.js'
|
|
@@ -10,26 +10,44 @@ export function useSeamClient(): {
|
|
|
10
10
|
isError: boolean
|
|
11
11
|
error: unknown
|
|
12
12
|
} {
|
|
13
|
-
const {
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const {
|
|
14
|
+
client,
|
|
15
|
+
clientOptions,
|
|
16
|
+
publishableKey,
|
|
17
|
+
clientSessionToken,
|
|
18
|
+
...context
|
|
19
|
+
} = useSeamContext()
|
|
20
|
+
const userIdentifierKey = useUserIdentifierKeyOrFingerprint(
|
|
21
|
+
clientSessionToken != null ? '' : context.userIdentifierKey
|
|
22
|
+
)
|
|
16
23
|
|
|
17
24
|
const { isLoading, isError, error, data } = useQuery<Seam>({
|
|
18
|
-
queryKey: [
|
|
25
|
+
queryKey: [
|
|
26
|
+
'client',
|
|
27
|
+
{
|
|
28
|
+
client,
|
|
29
|
+
clientOptions,
|
|
30
|
+
publishableKey,
|
|
31
|
+
userIdentifierKey,
|
|
32
|
+
clientSessionToken,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
19
35
|
queryFn: async () => {
|
|
20
36
|
if (client != null) return client
|
|
21
37
|
|
|
22
|
-
if (
|
|
23
|
-
throw new Error('Missing publishableKey')
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (clientSession != null) {
|
|
38
|
+
if (clientSessionToken != null) {
|
|
27
39
|
return new Seam({
|
|
28
40
|
...clientOptions,
|
|
29
|
-
clientSessionToken
|
|
41
|
+
clientSessionToken,
|
|
30
42
|
})
|
|
31
43
|
}
|
|
32
44
|
|
|
45
|
+
if (publishableKey == null) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
'Missing either a client, publishableKey, or clientSessionToken'
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
33
51
|
const res = await Seam.getClientSessionToken({
|
|
34
52
|
...clientOptions,
|
|
35
53
|
publishableKey,
|
|
@@ -40,8 +58,6 @@ export function useSeamClient(): {
|
|
|
40
58
|
throw new Error('Failed to get client access token')
|
|
41
59
|
}
|
|
42
60
|
|
|
43
|
-
setClientSession(res.client_session)
|
|
44
|
-
|
|
45
61
|
return new Seam({
|
|
46
62
|
...clientOptions,
|
|
47
63
|
clientSessionToken: res.client_session.token,
|
|
@@ -52,34 +68,24 @@ export function useSeamClient(): {
|
|
|
52
68
|
return { client: data ?? null, isLoading, isError, error }
|
|
53
69
|
}
|
|
54
70
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
JSON.stringify(clientSession)
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const cachedClientSession = globalThis?.localStorage?.getItem(localStorageKey)
|
|
69
|
-
|
|
70
|
-
return [
|
|
71
|
-
cachedClientSession != null ? JSON.parse(cachedClientSession) : null,
|
|
72
|
-
setClientSession,
|
|
73
|
-
]
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function useUserIdentifierKey(userIdentifierKey: string | undefined): string {
|
|
71
|
+
/**
|
|
72
|
+
* You'll almost always want to supply a user identifier key, but if you don't
|
|
73
|
+
* we'll automatically pick a fingerprint for this user. The user interface
|
|
74
|
+
* will show warnings when you use a fingerprint because this client session
|
|
75
|
+
* is bound to this machine, and is effectively ephemeral.
|
|
76
|
+
*/
|
|
77
|
+
function useUserIdentifierKeyOrFingerprint(
|
|
78
|
+
userIdentifierKey: string | undefined
|
|
79
|
+
): string {
|
|
77
80
|
if (userIdentifierKey != null) {
|
|
78
81
|
return userIdentifierKey
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
const fingerprintValue =
|
|
85
|
+
globalThis?.localStorage?.getItem('seam_user_fingerprint') ??
|
|
86
|
+
`fingerprint_${uuidv4()}`
|
|
87
|
+
|
|
88
|
+
globalThis?.localStorage?.setItem('seam_user_fingerprint', fingerprintValue)
|
|
89
|
+
|
|
90
|
+
return fingerprintValue
|
|
85
91
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { UseQueryResult } from '@tanstack/react-query'
|
|
2
|
+
import type { SeamError } from 'seamapi'
|
|
3
|
+
|
|
4
|
+
export type UseSeamQueryResult<Field extends string, ResponsePayload> = Omit<
|
|
5
|
+
UseQueryResult<ResponsePayload, SeamError>,
|
|
6
|
+
'data'
|
|
7
|
+
> & { [key in Field]?: ResponsePayload }
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { AccessCode } from 'seamapi'
|
|
2
|
-
|
|
3
1
|
import {
|
|
4
2
|
TableBody,
|
|
5
3
|
TableCell,
|
|
@@ -8,19 +6,23 @@ import {
|
|
|
8
6
|
TableTitle,
|
|
9
7
|
} from 'lib/ui/Table/index.js'
|
|
10
8
|
|
|
9
|
+
import { useAccessCodes } from 'lib/hooks/use-access-codes.js'
|
|
11
10
|
import { AccessCodeKeyIcon } from 'lib/icons/AccessCodeKey.js'
|
|
12
11
|
import { CodeDetails } from 'lib/ui/AccessCodeTable/CodeDetails.js'
|
|
13
12
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
14
13
|
import { Caption } from 'lib/ui/typography/Caption.js'
|
|
15
14
|
import { Title } from 'lib/ui/typography/Title.js'
|
|
16
15
|
|
|
17
|
-
export
|
|
18
|
-
|
|
16
|
+
export function AccessCodeTable(props: {
|
|
17
|
+
deviceId: string
|
|
19
18
|
onClickBack?: () => void
|
|
20
|
-
}
|
|
19
|
+
}): JSX.Element {
|
|
20
|
+
const { accessCodes } = useAccessCodes({
|
|
21
|
+
device_id: props.deviceId,
|
|
22
|
+
})
|
|
23
|
+
const { onClickBack } = props
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
const { accessCodes, onClickBack } = props
|
|
25
|
+
if (!accessCodes) return <>{null}</>
|
|
24
26
|
|
|
25
27
|
return (
|
|
26
28
|
<div className='seam-access-code-table'>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type LockDevice } from 'seamapi'
|
|
2
2
|
|
|
3
3
|
import { ChevronRightIcon } from 'lib/icons/ChevronRight.js'
|
|
4
4
|
import { AccessCodeTable } from 'lib/ui/AccessCodeTable/AccessCodeTable.js'
|
|
@@ -21,15 +21,12 @@ export function DeviceDetails(props: DeviceDetailsProps): JSX.Element {
|
|
|
21
21
|
const accessCodeLength =
|
|
22
22
|
device.properties?.schlage_metadata?.access_code_length
|
|
23
23
|
|
|
24
|
-
// TODO : Fetch access codes
|
|
25
|
-
const accessCodes: AccessCode[] = []
|
|
26
|
-
|
|
27
24
|
const [showingAccessCodes, toggleAccessCodes] = useToggle()
|
|
28
25
|
|
|
29
26
|
if (showingAccessCodes) {
|
|
30
27
|
return (
|
|
31
28
|
<AccessCodeTable
|
|
32
|
-
|
|
29
|
+
deviceId={device.device_id}
|
|
33
30
|
onClickBack={toggleAccessCodes}
|
|
34
31
|
/>
|
|
35
32
|
)
|