@terreno/ui 0.13.0 → 0.14.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/ActionSheet.d.ts +4 -4
- package/dist/ActionSheet.js.map +1 -1
- package/dist/Avatar.js +1 -1
- package/dist/Avatar.js.map +1 -1
- package/dist/Banner.js.map +1 -1
- package/dist/Box.js +2 -0
- package/dist/Box.js.map +1 -1
- package/dist/Button.d.ts +2 -2
- package/dist/Button.js +35 -23
- package/dist/Button.js.map +1 -1
- package/dist/Common.d.ts +8 -2
- package/dist/Common.js.map +1 -1
- package/dist/ConsentFormScreen.js +9 -8
- package/dist/ConsentFormScreen.js.map +1 -1
- package/dist/ConsentNavigator.d.ts +1 -1
- package/dist/ConsentNavigator.js +2 -1
- package/dist/ConsentNavigator.js.map +1 -1
- package/dist/CustomSelectField.js +3 -1
- package/dist/CustomSelectField.js.map +1 -1
- package/dist/DataTable.js +1 -1
- package/dist/DataTable.js.map +1 -1
- package/dist/DateTimeActionSheet.js +2 -1
- package/dist/DateTimeActionSheet.js.map +1 -1
- package/dist/DateTimeField.js +3 -2
- package/dist/DateTimeField.js.map +1 -1
- package/dist/DateUtilities.js.map +1 -1
- package/dist/HeightField.js.map +1 -1
- package/dist/Hyperlink.js +19 -9
- package/dist/Hyperlink.js.map +1 -1
- package/dist/IconButton.js.map +1 -1
- package/dist/ImageBackground.d.ts +2 -5
- package/dist/ImageBackground.js +1 -1
- package/dist/ImageBackground.js.map +1 -1
- package/dist/ModalSheet.d.ts +3 -2
- package/dist/ModalSheet.js +1 -1
- package/dist/ModalSheet.js.map +1 -1
- package/dist/OfflineBanner.d.ts +21 -0
- package/dist/OfflineBanner.js +25 -0
- package/dist/OfflineBanner.js.map +1 -0
- package/dist/OpenAPIContext.js +1 -1
- package/dist/OpenAPIContext.js.map +1 -1
- package/dist/Page.js +1 -0
- package/dist/Page.js.map +1 -1
- package/dist/Pagination.js.map +1 -1
- package/dist/Permissions.js +3 -0
- package/dist/Permissions.js.map +1 -1
- package/dist/PickerSelect.d.ts +22 -10
- package/dist/PickerSelect.js +14 -9
- package/dist/PickerSelect.js.map +1 -1
- package/dist/SelectBadge.js +11 -1
- package/dist/SelectBadge.js.map +1 -1
- package/dist/SelectField.js +3 -3
- package/dist/SelectField.js.map +1 -1
- package/dist/SidebarNavigation.native.js.map +1 -1
- package/dist/Signature.js +4 -0
- package/dist/Signature.js.map +1 -1
- package/dist/Signature.native.js +4 -0
- package/dist/Signature.native.js.map +1 -1
- package/dist/SplitPage.js +7 -2
- package/dist/SplitPage.js.map +1 -1
- package/dist/SplitPage.native.js +4 -1
- package/dist/SplitPage.native.js.map +1 -1
- package/dist/TapToEdit.js +10 -11
- package/dist/TapToEdit.js.map +1 -1
- package/dist/Theme.d.ts +1 -1
- package/dist/Theme.js.map +1 -1
- package/dist/Toast.js.map +1 -1
- package/dist/ToastNotifications.js.map +1 -1
- package/dist/Unifier.d.ts +2 -2
- package/dist/Unifier.js +1 -1
- package/dist/Unifier.js.map +1 -1
- package/dist/Utilities.d.ts +8 -4
- package/dist/Utilities.js +1 -1
- package/dist/Utilities.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/useConsentForms.d.ts +4 -3
- package/dist/useConsentForms.js +26 -4
- package/dist/useConsentForms.js.map +1 -1
- package/dist/useConsentHistory.d.ts +4 -3
- package/dist/useConsentHistory.js +26 -4
- package/dist/useConsentHistory.js.map +1 -1
- package/dist/useSubmitConsent.d.ts +7 -6
- package/dist/useSubmitConsent.js +25 -3
- package/dist/useSubmitConsent.js.map +1 -1
- package/package.json +2 -1
- package/src/ActionSheet.test.tsx +1 -0
- package/src/ActionSheet.tsx +6 -4
- package/src/Avatar.tsx +9 -2
- package/src/Badge.test.tsx +1 -0
- package/src/Banner.tsx +1 -1
- package/src/Box.test.tsx +1 -0
- package/src/Box.tsx +10 -6
- package/src/Button.test.tsx +35 -0
- package/src/Button.tsx +65 -34
- package/src/Common.ts +32 -15
- package/src/ConsentFormScreen.test.tsx +149 -0
- package/src/ConsentFormScreen.tsx +20 -3
- package/src/ConsentNavigator.test.tsx +1 -0
- package/src/ConsentNavigator.tsx +5 -3
- package/src/CustomSelectField.tsx +3 -1
- package/src/DataTable.test.tsx +1 -0
- package/src/DataTable.tsx +1 -1
- package/src/DateTimeActionSheet.tsx +7 -3
- package/src/DateTimeField.test.tsx +1 -0
- package/src/DateTimeField.tsx +3 -2
- package/src/DateUtilities.test.ts +111 -0
- package/src/DateUtilities.tsx +6 -6
- package/src/DecimalRangeActionSheet.test.tsx +28 -0
- package/src/ErrorBoundary.test.tsx +1 -0
- package/src/HeightField.test.tsx +68 -0
- package/src/HeightField.tsx +2 -1
- package/src/Hyperlink.tsx +83 -52
- package/src/IconButton.tsx +1 -1
- package/src/ImageBackground.tsx +5 -6
- package/src/Modal.tsx +2 -2
- package/src/ModalSheet.test.tsx +1 -5
- package/src/ModalSheet.tsx +15 -6
- package/src/NumberField.test.tsx +14 -0
- package/src/OfflineBanner.test.tsx +70 -0
- package/src/OfflineBanner.tsx +54 -0
- package/src/OpenAPIContext.tsx +3 -2
- package/src/Page.tsx +1 -0
- package/src/Pagination.tsx +1 -1
- package/src/Permissions.ts +3 -0
- package/src/PickerSelect.tsx +48 -31
- package/src/SelectBadge.test.tsx +1 -0
- package/src/SelectBadge.tsx +7 -3
- package/src/SelectField.tsx +3 -3
- package/src/SidebarNavigation.native.tsx +6 -2
- package/src/Signature.native.tsx +4 -0
- package/src/Signature.test.tsx +11 -0
- package/src/Signature.tsx +4 -0
- package/src/SplitPage.native.tsx +2 -0
- package/src/SplitPage.tsx +6 -1
- package/src/TapToEdit.test.tsx +17 -0
- package/src/TapToEdit.tsx +11 -11
- package/src/Theme.tsx +17 -14
- package/src/Toast.tsx +1 -1
- package/src/ToastNotifications.tsx +1 -4
- package/src/Tooltip.test.tsx +40 -28
- package/src/Unifier.ts +6 -5
- package/src/Utilities.tsx +9 -6
- package/src/__snapshots__/AddressField.test.tsx.snap +3 -2
- package/src/__snapshots__/Button.test.tsx.snap +92 -50
- package/src/__snapshots__/CustomSelectField.test.tsx.snap +21 -14
- package/src/__snapshots__/DecimalRangeActionSheet.test.tsx.snap +14 -8
- package/src/__snapshots__/ErrorPage.test.tsx.snap +7 -4
- package/src/__snapshots__/Field.test.tsx.snap +18 -12
- package/src/__snapshots__/HeightActionSheet.test.tsx.snap +14 -8
- package/src/__snapshots__/HeightField.test.tsx.snap +35 -20
- package/src/__snapshots__/InfoModalIcon.test.tsx.snap +28 -16
- package/src/__snapshots__/Modal.test.tsx.snap +19 -10
- package/src/__snapshots__/ModalSheet.test.tsx.snap +0 -1
- package/src/__snapshots__/NumberPickerActionSheet.test.tsx.snap +14 -8
- package/src/__snapshots__/Page.test.tsx.snap +7 -4
- package/src/__snapshots__/PickerSelect.test.tsx.snap +0 -7
- package/src/__snapshots__/SelectField.test.tsx.snap +18 -12
- package/src/__snapshots__/TerrenoProvider.test.tsx.snap +2 -18
- package/src/__snapshots__/TimezonePicker.test.tsx.snap +18 -12
- package/src/bunSetup.ts +45 -0
- package/src/index.tsx +1 -0
- package/src/login/__snapshots__/LoginScreen.test.tsx.snap +15 -6
- package/src/signUp/__snapshots__/SignUpScreen.test.tsx.snap +10 -4
- package/src/table/__snapshots__/TableBadge.test.tsx.snap +3 -2
- package/src/types/react-native-swiper-flatlist.d.ts +1 -0
- package/src/useConsentForms.test.ts +25 -0
- package/src/useConsentForms.ts +32 -7
- package/src/useConsentHistory.test.ts +99 -0
- package/src/useConsentHistory.ts +31 -6
- package/src/useSubmitConsent.test.ts +24 -0
- package/src/useSubmitConsent.ts +35 -10
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {describe, expect, it, mock} from "bun:test";
|
|
2
|
+
import {renderHook} from "@testing-library/react-native";
|
|
3
|
+
|
|
4
|
+
import type {ConsentHistoryEntry} from "./useConsentHistory";
|
|
5
|
+
import {useConsentHistory} from "./useConsentHistory";
|
|
6
|
+
|
|
7
|
+
type ConsentHistoryApi = Parameters<typeof useConsentHistory>[0];
|
|
8
|
+
|
|
9
|
+
interface MockQueryDef {
|
|
10
|
+
query: () => string;
|
|
11
|
+
providesTags: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface MockInjectOpts {
|
|
15
|
+
endpoints: (build: {query: (def: MockQueryDef) => string}) => Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe("useConsentHistory", () => {
|
|
19
|
+
const buildApi = (queryResult: {data?: unknown; error?: unknown; isLoading?: boolean}) => {
|
|
20
|
+
const refetch = mock(() => {});
|
|
21
|
+
const useGetMyConsentsQuery = mock(() => ({
|
|
22
|
+
data: queryResult.data,
|
|
23
|
+
error: queryResult.error,
|
|
24
|
+
isLoading: queryResult.isLoading ?? false,
|
|
25
|
+
refetch,
|
|
26
|
+
}));
|
|
27
|
+
const api = {
|
|
28
|
+
injectEndpoints: mock((opts: MockInjectOpts) => {
|
|
29
|
+
const build = {
|
|
30
|
+
query: mock((def: MockQueryDef) => {
|
|
31
|
+
// Exercise the URL builder so the closure captures `base`
|
|
32
|
+
const url = def.query();
|
|
33
|
+
expect(url).toContain("/consents/my");
|
|
34
|
+
return "my-consents-query";
|
|
35
|
+
}),
|
|
36
|
+
};
|
|
37
|
+
opts.endpoints(build);
|
|
38
|
+
return {useGetMyConsentsQuery};
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
return {api, refetch};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
it("returns an array of entries when response is an array", () => {
|
|
45
|
+
const {api} = buildApi({
|
|
46
|
+
data: [{_id: "1", agreed: true} as unknown as ConsentHistoryEntry],
|
|
47
|
+
});
|
|
48
|
+
const {result} = renderHook(() => useConsentHistory(api as unknown as ConsentHistoryApi));
|
|
49
|
+
expect(Array.isArray(result.current.entries)).toBe(true);
|
|
50
|
+
expect(result.current.entries).toHaveLength(1);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("unwraps .data property when response is object shape", () => {
|
|
54
|
+
const {api} = buildApi({
|
|
55
|
+
data: {data: [{_id: "2", agreed: false} as unknown as ConsentHistoryEntry]},
|
|
56
|
+
});
|
|
57
|
+
const {result} = renderHook(() =>
|
|
58
|
+
useConsentHistory(api as unknown as ConsentHistoryApi, "/api")
|
|
59
|
+
);
|
|
60
|
+
expect(Array.isArray(result.current.entries)).toBe(true);
|
|
61
|
+
expect(result.current.entries).toHaveLength(1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("returns empty array when no data is present", () => {
|
|
65
|
+
const {api} = buildApi({data: undefined, isLoading: true});
|
|
66
|
+
const {result} = renderHook(() => useConsentHistory(api as unknown as ConsentHistoryApi));
|
|
67
|
+
expect(result.current.entries).toEqual([]);
|
|
68
|
+
expect(result.current.isLoading).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("surfaces error from the query hook", () => {
|
|
72
|
+
const {api} = buildApi({data: undefined, error: "boom"});
|
|
73
|
+
const {result} = renderHook(() => useConsentHistory(api as unknown as ConsentHistoryApi));
|
|
74
|
+
expect(result.current.error).toBe("boom");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("injects the my-consents endpoint only once per (api, baseUrl)", () => {
|
|
78
|
+
let injectCallCount = 0;
|
|
79
|
+
const refetch = mock(() => {});
|
|
80
|
+
const useGetMyConsentsQuery = mock(() => ({
|
|
81
|
+
data: undefined,
|
|
82
|
+
error: undefined,
|
|
83
|
+
isLoading: false,
|
|
84
|
+
refetch,
|
|
85
|
+
}));
|
|
86
|
+
const api = {
|
|
87
|
+
injectEndpoints: () => {
|
|
88
|
+
injectCallCount += 1;
|
|
89
|
+
return {useGetMyConsentsQuery};
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
const {rerender} = renderHook(() => useConsentHistory(api as unknown as ConsentHistoryApi));
|
|
93
|
+
rerender(undefined);
|
|
94
|
+
rerender(undefined);
|
|
95
|
+
// The hook reuses the cached enhanced api after the first render so the
|
|
96
|
+
// dev-mode RTK warning about re-injecting endpoints never fires.
|
|
97
|
+
expect(injectCallCount).toBe(1);
|
|
98
|
+
});
|
|
99
|
+
});
|
package/src/useConsentHistory.ts
CHANGED
|
@@ -35,19 +35,37 @@ interface ConsentHistoryHookState {
|
|
|
35
35
|
refetch: () => void | Promise<void>;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
interface ConsentHistoryEnhancedApi {
|
|
39
|
+
useGetMyConsentsQuery: () => ConsentHistoryHookState;
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
interface ConsentHistoryApi {
|
|
39
43
|
injectEndpoints: (options: {
|
|
40
44
|
endpoints: (build: ConsentHistoryQueryBuilder) => {getMyConsents: unknown};
|
|
41
45
|
overrideExisting: boolean;
|
|
42
|
-
}) =>
|
|
43
|
-
useGetMyConsentsQuery: () => ConsentHistoryHookState;
|
|
44
|
-
};
|
|
46
|
+
}) => ConsentHistoryEnhancedApi;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Cache the enhanced api per (api, baseUrl). `injectEndpoints` logs a console
|
|
51
|
+
* error in development whenever an endpoint with the same name is re-injected
|
|
52
|
+
* (with `overrideExisting: false`), so calling it on every render of every
|
|
53
|
+
* consumer would flood the console. WeakMap-by-api lets the GC reclaim entries
|
|
54
|
+
* when the api object is unreachable.
|
|
55
|
+
*/
|
|
56
|
+
const enhancedApiCache = new WeakMap<ConsentHistoryApi, Map<string, ConsentHistoryEnhancedApi>>();
|
|
49
57
|
|
|
50
|
-
|
|
58
|
+
const getEnhancedApi = (api: ConsentHistoryApi, base: string): ConsentHistoryEnhancedApi => {
|
|
59
|
+
let byBase = enhancedApiCache.get(api);
|
|
60
|
+
if (!byBase) {
|
|
61
|
+
byBase = new Map();
|
|
62
|
+
enhancedApiCache.set(api, byBase);
|
|
63
|
+
}
|
|
64
|
+
const cached = byBase.get(base);
|
|
65
|
+
if (cached) {
|
|
66
|
+
return cached;
|
|
67
|
+
}
|
|
68
|
+
const enhanced = api.injectEndpoints({
|
|
51
69
|
endpoints: (build) => ({
|
|
52
70
|
getMyConsents: build.query({
|
|
53
71
|
providesTags: ["MyConsents"],
|
|
@@ -56,6 +74,13 @@ export const useConsentHistory = (api: ConsentHistoryApi, baseUrl?: string) => {
|
|
|
56
74
|
}),
|
|
57
75
|
overrideExisting: false,
|
|
58
76
|
});
|
|
77
|
+
byBase.set(base, enhanced);
|
|
78
|
+
return enhanced;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const useConsentHistory = (api: ConsentHistoryApi, baseUrl?: string) => {
|
|
82
|
+
const base = baseUrl || "";
|
|
83
|
+
const enhancedApi = getEnhancedApi(api, base);
|
|
59
84
|
|
|
60
85
|
const {data, isLoading, error, refetch} = enhancedApi.useGetMyConsentsQuery();
|
|
61
86
|
const entries: ConsentHistoryEntry[] = Array.isArray(data) ? data : (data?.data ?? []);
|
|
@@ -72,4 +72,28 @@ describe("useSubmitConsent", () => {
|
|
|
72
72
|
const {result} = renderHook(() => useSubmitConsent(api as unknown as SubmitConsentApi));
|
|
73
73
|
expect(result.current.submit).toBeDefined();
|
|
74
74
|
});
|
|
75
|
+
|
|
76
|
+
it("injects the submit endpoint only once per (api, baseUrl)", () => {
|
|
77
|
+
let injectCallCount = 0;
|
|
78
|
+
const unwrap = mock(async () => ({}));
|
|
79
|
+
const submitMutation = mock(() => ({unwrap}));
|
|
80
|
+
const useSubmitConsentResponseMutation = mock(() => [
|
|
81
|
+
submitMutation,
|
|
82
|
+
{error: undefined, isLoading: false},
|
|
83
|
+
]);
|
|
84
|
+
const api = {
|
|
85
|
+
enhanceEndpoints: () => ({
|
|
86
|
+
injectEndpoints: () => {
|
|
87
|
+
injectCallCount += 1;
|
|
88
|
+
return {useSubmitConsentResponseMutation};
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
const {rerender} = renderHook(() => useSubmitConsent(api as unknown as SubmitConsentApi));
|
|
93
|
+
rerender(undefined);
|
|
94
|
+
rerender(undefined);
|
|
95
|
+
// The hook reuses the cached enhanced api after the first render so the
|
|
96
|
+
// dev-mode RTK warning about re-injecting endpoints never fires.
|
|
97
|
+
expect(injectCallCount).toBe(1);
|
|
98
|
+
});
|
|
75
99
|
});
|
package/src/useSubmitConsent.ts
CHANGED
|
@@ -26,27 +26,45 @@ interface SubmitConsentMutationBuilder {
|
|
|
26
26
|
}) => unknown;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
interface SubmitConsentEnhancedApi {
|
|
30
|
+
useSubmitConsentResponseMutation: () => [
|
|
31
|
+
(body: SubmitConsentBody) => SubmitConsentMutationResult,
|
|
32
|
+
SubmitConsentMutationHookState,
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
interface SubmitConsentApiWithTags {
|
|
30
37
|
injectEndpoints: (options: {
|
|
31
38
|
endpoints: (build: SubmitConsentMutationBuilder) => {submitConsentResponse: unknown};
|
|
32
39
|
overrideExisting: boolean;
|
|
33
|
-
}) =>
|
|
34
|
-
useSubmitConsentResponseMutation: () => [
|
|
35
|
-
(body: SubmitConsentBody) => SubmitConsentMutationResult,
|
|
36
|
-
SubmitConsentMutationHookState,
|
|
37
|
-
];
|
|
38
|
-
};
|
|
40
|
+
}) => SubmitConsentEnhancedApi;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
interface SubmitConsentApi {
|
|
42
44
|
enhanceEndpoints: (options: {addTagTypes: string[]}) => SubmitConsentApiWithTags;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Cache the enhanced api per (api, baseUrl). `injectEndpoints` logs a console
|
|
49
|
+
* error in development whenever an endpoint with the same name is re-injected
|
|
50
|
+
* (with `overrideExisting: false`), so calling it on every render of every
|
|
51
|
+
* consumer would flood the console. WeakMap-by-api lets the GC reclaim entries
|
|
52
|
+
* when the api object is unreachable.
|
|
53
|
+
*/
|
|
54
|
+
const enhancedApiCache = new WeakMap<SubmitConsentApi, Map<string, SubmitConsentEnhancedApi>>();
|
|
48
55
|
|
|
49
|
-
|
|
56
|
+
const getEnhancedApi = (api: SubmitConsentApi, base: string): SubmitConsentEnhancedApi => {
|
|
57
|
+
let byBase = enhancedApiCache.get(api);
|
|
58
|
+
if (!byBase) {
|
|
59
|
+
byBase = new Map();
|
|
60
|
+
enhancedApiCache.set(api, byBase);
|
|
61
|
+
}
|
|
62
|
+
const cached = byBase.get(base);
|
|
63
|
+
if (cached) {
|
|
64
|
+
return cached;
|
|
65
|
+
}
|
|
66
|
+
const apiWithConsentTags = api.enhanceEndpoints({addTagTypes: ["PendingConsents"]});
|
|
67
|
+
const enhanced = apiWithConsentTags.injectEndpoints({
|
|
50
68
|
endpoints: (build) => ({
|
|
51
69
|
submitConsentResponse: build.mutation({
|
|
52
70
|
invalidatesTags: ["PendingConsents"],
|
|
@@ -59,6 +77,13 @@ export const useSubmitConsent = (api: SubmitConsentApi, baseUrl?: string) => {
|
|
|
59
77
|
}),
|
|
60
78
|
overrideExisting: false,
|
|
61
79
|
});
|
|
80
|
+
byBase.set(base, enhanced);
|
|
81
|
+
return enhanced;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const useSubmitConsent = (api: SubmitConsentApi, baseUrl?: string) => {
|
|
85
|
+
const base = baseUrl || "";
|
|
86
|
+
const enhancedApi = getEnhancedApi(api, base);
|
|
62
87
|
|
|
63
88
|
const [submitMutation, {isLoading: isSubmitting, error}] =
|
|
64
89
|
enhancedApi.useSubmitConsentResponseMutation();
|