@availity/mui-spaces 0.1.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/CHANGELOG.md +19 -0
- package/README.md +61 -0
- package/dist/index.d.mts +104 -0
- package/dist/index.d.ts +104 -0
- package/dist/index.js +456 -0
- package/dist/index.mjs +428 -0
- package/introduction.stories.mdx +7 -0
- package/jest.config.js +7 -0
- package/package.json +59 -0
- package/project.json +41 -0
- package/src/index.ts +1 -0
- package/src/lib/Spaces.stories.tsx +75 -0
- package/src/lib/Spaces.test.tsx +265 -0
- package/src/lib/Spaces.tsx +202 -0
- package/src/lib/configurationFindMany.tsx +105 -0
- package/src/lib/helpers.test.tsx +26 -0
- package/src/lib/helpers.tsx +15 -0
- package/src/lib/spaces-data.test.tsx +57 -0
- package/src/lib/spaces-data.tsx +116 -0
- package/src/lib/spaces-types.tsx +136 -0
- package/src/lib/topApps.test.tsx +93 -0
- package/src/lib/topApps.tsx +65 -0
- package/tsconfig.json +5 -0
- package/tsconfig.spec.json +10 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { render, waitFor, fireEvent } from '@testing-library/react';
|
|
4
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
5
|
+
import { Spaces, useSpaces, useSpacesContext } from '..';
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line @nx/enforce-module-boundaries
|
|
8
|
+
import { server } from '../../../mock/src/lib/server';
|
|
9
|
+
import { NormalizedSpace } from './spaces-types';
|
|
10
|
+
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
// Start the interception.
|
|
13
|
+
server.listen();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
// Remove any handlers you may have added
|
|
18
|
+
// in individual tests (runtime handlers).
|
|
19
|
+
server.resetHandlers();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterAll(() => {
|
|
23
|
+
// Disable request interception and clean up.
|
|
24
|
+
server.close();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('Spaces', () => {
|
|
28
|
+
it('provides correct spaces from props and from avWebQL', async () => {
|
|
29
|
+
const queryClient = new QueryClient();
|
|
30
|
+
// Create a space component that renders "Space <id-here> is in provider" if the space is in the provider and "Space <id-here> is not in provider" if it is not the provider
|
|
31
|
+
const SpaceComponent = ({ spaceId }: { spaceId: string }) => {
|
|
32
|
+
const space = useSpaces(spaceId);
|
|
33
|
+
return (
|
|
34
|
+
<div>
|
|
35
|
+
<span id={`space-for-${spaceId}`}>
|
|
36
|
+
{space && space.length > 0 ? `Space ${spaceId} is in provider` : `Space ${spaceId} is not in provider`}
|
|
37
|
+
</span>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
// Create component that renders a SpaceComponent for ids 1, 2, and 3
|
|
42
|
+
const MyComponent = () => {
|
|
43
|
+
const [spaceIds, setSpaceIds] = useState(['1', '3']);
|
|
44
|
+
return (
|
|
45
|
+
<QueryClientProvider client={queryClient}>
|
|
46
|
+
<Spaces
|
|
47
|
+
spaceIds={spaceIds}
|
|
48
|
+
spaces={[{ id: '3', configurationId: '3', type: 'space', name: 'Space 3' }]}
|
|
49
|
+
clientId="my-client-id"
|
|
50
|
+
>
|
|
51
|
+
<SpaceComponent spaceId="1" />
|
|
52
|
+
<SpaceComponent spaceId="2" />
|
|
53
|
+
<SpaceComponent spaceId="3" />
|
|
54
|
+
<button type="button" id="add-spaceid-btn" onClick={() => setSpaceIds(['1', '2', '3'])}>
|
|
55
|
+
Add
|
|
56
|
+
</button>
|
|
57
|
+
</Spaces>
|
|
58
|
+
</QueryClientProvider>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
const { container, getByText } = render(<MyComponent />);
|
|
62
|
+
// Check that space 1 (fetched from avWebQL) is accessible by spaces provider
|
|
63
|
+
await waitFor(() => getByText('Space 1 is in provider'));
|
|
64
|
+
expect(getByText('Space 1 is in provider')).toBeDefined();
|
|
65
|
+
// Check that space 2 (not provided) is not accessible by spaces provider
|
|
66
|
+
await waitFor(() => getByText('Space 2 is not in provider'));
|
|
67
|
+
expect(getByText('Space 2 is not in provider')).toBeDefined();
|
|
68
|
+
// Check that space 3 (provided by props) is accessible by spaces provider
|
|
69
|
+
await waitFor(() => getByText('Space 3 is in provider'));
|
|
70
|
+
expect(getByText('Space 3 is in provider')).toBeDefined();
|
|
71
|
+
// Check that avWebQL was only queried for space 1 because space 3 was provided by props
|
|
72
|
+
// Click button that adds another space id, "2", to the provider
|
|
73
|
+
const button = container.querySelector('#add-spaceid-btn');
|
|
74
|
+
if (button) fireEvent.click(button);
|
|
75
|
+
// // Check that space 1 (fetched from avWebQL) is still accessible by spaces provider
|
|
76
|
+
await waitFor(() => getByText('Space 1 is in provider'));
|
|
77
|
+
expect(getByText('Space 1 is in provider')).toBeDefined();
|
|
78
|
+
// // Check that space 2 (now fetched from avWebQL) is now accessible by spaces provider
|
|
79
|
+
await waitFor(() => getByText('Space 2 is in provider'));
|
|
80
|
+
expect(getByText('Space 2 is in provider')).toBeDefined();
|
|
81
|
+
// // Check that space 3 (provided by props) is still accessible by spaces provider
|
|
82
|
+
await waitFor(() => getByText('Space 3 is in provider'));
|
|
83
|
+
expect(getByText('Space 3 is in provider')).toBeDefined();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('toggles whether the spaces provider is loading', async () => {
|
|
88
|
+
const queryClient = new QueryClient();
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
90
|
+
const fn = jest.fn();
|
|
91
|
+
// Create component to call mock function
|
|
92
|
+
const SpaceComponent = ({ spaceId }: { spaceId: string }) => {
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
94
|
+
|
|
95
|
+
const space = useSpaces(spaceId);
|
|
96
|
+
const { loading } = useSpacesContext();
|
|
97
|
+
|
|
98
|
+
if (loading) fn();
|
|
99
|
+
|
|
100
|
+
// Should be called when we fetch spaces from avWebQL gets executed
|
|
101
|
+
return loading ? null : (
|
|
102
|
+
<span id={`space-for-${spaceId}`}>{space?.[0] ? `Space ${space[0].id}` : 'No Space '}</span>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Create component that renders a SpaceComponent for the current space id
|
|
107
|
+
const MyComponent = () => {
|
|
108
|
+
const [spaceId, setSpaceId] = useState(['1']);
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<QueryClientProvider client={queryClient}>
|
|
112
|
+
<Spaces spaceIds={spaceId} clientId="my-client-id">
|
|
113
|
+
<SpaceComponent spaceId={spaceId[0]} />
|
|
114
|
+
|
|
115
|
+
<button type="button" id="add-spaceid-btn" onClick={() => setSpaceId(['2'])}>
|
|
116
|
+
Add
|
|
117
|
+
</button>
|
|
118
|
+
</Spaces>
|
|
119
|
+
</QueryClientProvider>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const { container, getByText } = render(<MyComponent />);
|
|
124
|
+
|
|
125
|
+
expect(fn).toHaveBeenCalled();
|
|
126
|
+
|
|
127
|
+
await waitFor(() => getByText('Space 1'));
|
|
128
|
+
|
|
129
|
+
// Add a space id
|
|
130
|
+
const button = container.querySelector('#add-spaceid-btn');
|
|
131
|
+
if (button) fireEvent.click(button);
|
|
132
|
+
|
|
133
|
+
expect(fn).toHaveBeenCalled();
|
|
134
|
+
|
|
135
|
+
await waitFor(() => getByText('Space 2'));
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('useSpaces', () => {
|
|
139
|
+
// Create a spaces component that renders ids passed in
|
|
140
|
+
const SpacesComponent = ({ ids = [] }: { ids?: string[] }) => {
|
|
141
|
+
const spaces = useSpaces(...ids) || [];
|
|
142
|
+
|
|
143
|
+
const dataTestIdSuffix = ids && ids.length > 0 ? ids.join('-') : 'all-spaces';
|
|
144
|
+
return (
|
|
145
|
+
<div>
|
|
146
|
+
<span id={`spaces-for-${dataTestIdSuffix}`}>{spaces.map((spc) => `Id: ${spc.id} `)}</span>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
it('returns spaces by id', async () => {
|
|
152
|
+
const queryClient = new QueryClient();
|
|
153
|
+
const { container } = render(
|
|
154
|
+
<QueryClientProvider client={queryClient}>
|
|
155
|
+
<Spaces spaceIds={['1', '2', '3']} clientId="test-client-id">
|
|
156
|
+
<SpacesComponent />
|
|
157
|
+
<SpacesComponent ids={['2', '3']} />
|
|
158
|
+
</Spaces>
|
|
159
|
+
</QueryClientProvider>
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Check that all spaces get returned when no ids get passed to useSpaces hook
|
|
163
|
+
const allSpaces = await waitFor(() => container.querySelector('#spaces-for-all-spaces'));
|
|
164
|
+
await waitFor(() => expect(allSpaces?.textContent).toBe('Id: 1 Id: 2 Id: 3 '));
|
|
165
|
+
|
|
166
|
+
// Check that spaces for ids get returned when ids passed to useSpaces hook
|
|
167
|
+
const specificSpaces = await waitFor(() => container.querySelector('#spaces-for-2-3'));
|
|
168
|
+
expect(specificSpaces?.textContent).toBe('Id: 2 Id: 3 ');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('returns spaces by configurationId', async () => {
|
|
172
|
+
const queryClient = new QueryClient();
|
|
173
|
+
const { getByText } = render(
|
|
174
|
+
<QueryClientProvider client={queryClient}>
|
|
175
|
+
<Spaces spaceIds={['11', '22', '33']} clientId="test-client-id">
|
|
176
|
+
<SpacesComponent />
|
|
177
|
+
<SpacesComponent ids={['22', '33']} />
|
|
178
|
+
</Spaces>
|
|
179
|
+
</QueryClientProvider>
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// Check that all spaces get returned when no configurationIds get passed to useSpaces hook
|
|
183
|
+
await waitFor(() => getByText('Id: 1 Id: 2 Id: 3'));
|
|
184
|
+
|
|
185
|
+
// Check that spaces for configurationIds get returned when configurationIds passed to useSpaces hook
|
|
186
|
+
await waitFor(() => getByText('Id: 2 Id: 3'));
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('returns all matching spaces when searching by payerId', async () => {
|
|
190
|
+
const queryClient = new QueryClient();
|
|
191
|
+
const { getByText } = render(
|
|
192
|
+
<QueryClientProvider client={queryClient}>
|
|
193
|
+
<Spaces payerIds={['a', 'b', 'c']} clientId="test-client-id">
|
|
194
|
+
<SpacesComponent ids={['b']} />
|
|
195
|
+
<SpacesComponent ids={['c']} />
|
|
196
|
+
</Spaces>
|
|
197
|
+
</QueryClientProvider>
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
// Check that spaces for payer ids get returned when ids passed to useSpaces hook
|
|
201
|
+
await waitFor(() => getByText('Id: 1 Id: 2'));
|
|
202
|
+
await waitFor(() => getByText('Id: 1 Id: 2 Id: 3'));
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('renders with warning when returning all spaces because no ids were passed in', async () => {
|
|
206
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
207
|
+
const consoleWarnMock = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
208
|
+
const SpacesComponent = ({ ids = [] }) => {
|
|
209
|
+
const spaces = useSpaces(...ids) || [];
|
|
210
|
+
|
|
211
|
+
const dataTestIdSuffix = ids && ids.length > 0 ? ids.join('-') : 'all-spaces';
|
|
212
|
+
return (
|
|
213
|
+
<div>
|
|
214
|
+
<span id={`spaces-for-${dataTestIdSuffix}`}>{spaces.map((spc) => `Id: ${spc && spc.id} `)}</span>
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const queryClient = new QueryClient();
|
|
220
|
+
|
|
221
|
+
const { container } = render(
|
|
222
|
+
<QueryClientProvider client={queryClient}>
|
|
223
|
+
<Spaces spaceIds={['1', '2']} clientId="test-client-id">
|
|
224
|
+
<SpacesComponent />
|
|
225
|
+
</Spaces>
|
|
226
|
+
</QueryClientProvider>
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
await waitFor(() => container.querySelector('#spaces-for-all-spaces'));
|
|
230
|
+
|
|
231
|
+
expect(consoleWarnMock).toHaveBeenCalled();
|
|
232
|
+
expect(consoleWarnMock.mock.calls[0][0]).toBe('You did not pass in an ID to find a space, returning all spaces.');
|
|
233
|
+
|
|
234
|
+
consoleWarnMock.mockRestore();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('returns first payer space with when no spaceId passed', async () => {
|
|
239
|
+
// Create component that renders a SpaceComponent for the current space id
|
|
240
|
+
const SpaceComponent = () => {
|
|
241
|
+
const spaces = useSpaces() || [];
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<div id={`space-${spaces[0]?.id}`}>
|
|
245
|
+
<span>{spaces[0]?.name}</span>
|
|
246
|
+
</div>
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const queryClient = new QueryClient();
|
|
251
|
+
|
|
252
|
+
const { container, getByText } = render(
|
|
253
|
+
<QueryClientProvider client={queryClient}>
|
|
254
|
+
<Spaces spaceIds={['1']} clientId="my-client-id">
|
|
255
|
+
<SpaceComponent />
|
|
256
|
+
</Spaces>
|
|
257
|
+
</QueryClientProvider>
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const spc1 = await waitFor(() => container.querySelector('#space-1'));
|
|
261
|
+
const spc2 = await waitFor(() => getByText('Space 1'));
|
|
262
|
+
|
|
263
|
+
expect(spc1).toBeDefined();
|
|
264
|
+
expect(spc2).toBeDefined();
|
|
265
|
+
});
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { createContext, useContext, useReducer, useEffect } from 'react';
|
|
2
|
+
import { useQueries } from '@tanstack/react-query';
|
|
3
|
+
import { normalizeSpaces, spacesReducer, fetchAllSpaces } from './spaces-data';
|
|
4
|
+
import { Space, SpacesProps, SpacesContextType } from './spaces-types';
|
|
5
|
+
import configurationFindMany from './configurationFindMany';
|
|
6
|
+
|
|
7
|
+
export const INITIAL_STATE = {
|
|
8
|
+
loading: true,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const SpacesContext = createContext<SpacesContextType>(INITIAL_STATE);
|
|
12
|
+
|
|
13
|
+
export const useSpacesContext = () => useContext(SpacesContext);
|
|
14
|
+
|
|
15
|
+
export const Spaces = ({
|
|
16
|
+
query = configurationFindMany,
|
|
17
|
+
variables = { types: ['PAYERSPACE'] },
|
|
18
|
+
clientId,
|
|
19
|
+
children,
|
|
20
|
+
payerIds,
|
|
21
|
+
spaceIds,
|
|
22
|
+
spaces: spacesFromProps,
|
|
23
|
+
}: SpacesProps): JSX.Element => {
|
|
24
|
+
const [{ previousSpacesMap, previousSpacesByConfigMap, previousSpacesByPayerMap, loading, error }, dispatch] =
|
|
25
|
+
useReducer(spacesReducer, INITIAL_STATE);
|
|
26
|
+
|
|
27
|
+
const spacesMap: Map<string, Space> = new Map(previousSpacesMap);
|
|
28
|
+
const configIdsMap: Map<string, Space> = new Map(previousSpacesByConfigMap);
|
|
29
|
+
const payerIdsMap: Map<string, Space[]> = new Map(previousSpacesByPayerMap);
|
|
30
|
+
const spaceIdsToQuery: Set<string> = new Set();
|
|
31
|
+
const payerIdsToQuery: Set<string> = new Set();
|
|
32
|
+
|
|
33
|
+
if (spacesFromProps && spacesFromProps.length > 0) {
|
|
34
|
+
for (const space of spacesFromProps) {
|
|
35
|
+
if (space.id && !spacesMap.has(space.id)) {
|
|
36
|
+
spacesMap.set(space.id, space);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (space.configurationId && !configIdsMap.has(space.configurationId)) {
|
|
40
|
+
configIdsMap.set(space.configurationId, space);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (space.payerIDs) {
|
|
44
|
+
for (const pId of space.payerIDs) {
|
|
45
|
+
const currentSpacesForPayerId = payerIdsMap.get(pId);
|
|
46
|
+
if (currentSpacesForPayerId) {
|
|
47
|
+
payerIdsMap.set(pId, [...currentSpacesForPayerId, space]);
|
|
48
|
+
} else {
|
|
49
|
+
payerIdsMap.set(pId, [space]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (spaceIds && spaceIds.length > 0) {
|
|
57
|
+
for (const id of spaceIds) {
|
|
58
|
+
if (!(spacesMap.has(id) || configIdsMap.has(id))) {
|
|
59
|
+
spaceIdsToQuery.add(id);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (payerIds && payerIds.length > 0) {
|
|
65
|
+
for (const pid of payerIds) {
|
|
66
|
+
if (!payerIdsMap.has(pid)) {
|
|
67
|
+
payerIdsToQuery.add(pid);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const spaceIdVars = { ...variables, ids: [...spaceIdsToQuery.keys()] };
|
|
73
|
+
|
|
74
|
+
const payerIdVars = { ...variables, payerIds: [...payerIdsToQuery.keys()] };
|
|
75
|
+
|
|
76
|
+
const [
|
|
77
|
+
{ data: spacesBySpaceIds, isFetching: isLoadingBySpaceIds, error: errorBySpaceIds },
|
|
78
|
+
{ data: spacesByPayerIds, isFetching: isLoadingByPayerIds, error: errorByPayerIds },
|
|
79
|
+
] = useQueries({
|
|
80
|
+
queries: [
|
|
81
|
+
{
|
|
82
|
+
queryKey: ['id', spaceIdVars],
|
|
83
|
+
queryFn: () => fetchAllSpaces({ query, clientId, variables: spaceIdVars }),
|
|
84
|
+
enabled: spaceIdsToQuery.size > 0,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
queryKey: ['id', payerIdVars],
|
|
88
|
+
queryFn: () => fetchAllSpaces({ query, clientId, variables: payerIdVars }),
|
|
89
|
+
enabled: payerIdsToQuery.size > 0,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (errorByPayerIds || errorBySpaceIds) {
|
|
96
|
+
dispatch({
|
|
97
|
+
type: 'ERROR',
|
|
98
|
+
error: errorByPayerIds?.message || errorBySpaceIds?.message,
|
|
99
|
+
loading: false,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}, [errorByPayerIds, errorBySpaceIds]);
|
|
103
|
+
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
dispatch({
|
|
106
|
+
type: 'LOADING',
|
|
107
|
+
loading: true,
|
|
108
|
+
});
|
|
109
|
+
if (spaceIdsToQuery.size === 0 && payerIdsToQuery.size === 0) {
|
|
110
|
+
dispatch({
|
|
111
|
+
type: 'LOADING',
|
|
112
|
+
loading: false,
|
|
113
|
+
});
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (spacesBySpaceIds) {
|
|
117
|
+
for (const space of spacesBySpaceIds) {
|
|
118
|
+
if (!spacesMap.has(space.id)) {
|
|
119
|
+
spacesMap.set(space.id, space);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!configIdsMap.has(space.configurationId)) {
|
|
123
|
+
configIdsMap.set(space.configurationId, space);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (space.payerIDs) {
|
|
127
|
+
for (const pId of space.payerIDs) {
|
|
128
|
+
const currentSpacesForPayerId = payerIdsMap.get(pId);
|
|
129
|
+
if (currentSpacesForPayerId) {
|
|
130
|
+
payerIdsMap.set(pId, [...currentSpacesForPayerId, space]);
|
|
131
|
+
} else {
|
|
132
|
+
payerIdsMap.set(pId, [space]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (payerIdsToQuery.size > 0) {
|
|
139
|
+
if (spacesByPayerIds) {
|
|
140
|
+
for (const space of spacesByPayerIds) {
|
|
141
|
+
if (!spacesMap.has(space.id)) {
|
|
142
|
+
spacesMap.set(space.id, space);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!configIdsMap.has(space.configurationId)) {
|
|
146
|
+
configIdsMap.set(space.configurationId, space);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (space.payerIDs) {
|
|
150
|
+
for (const pId of space.payerIDs) {
|
|
151
|
+
const currentSpacesForPayerId = payerIdsMap.get(pId);
|
|
152
|
+
if (currentSpacesForPayerId) {
|
|
153
|
+
payerIdsMap.set(pId, [...currentSpacesForPayerId, space]);
|
|
154
|
+
} else {
|
|
155
|
+
payerIdsMap.set(pId, [space]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
dispatch({
|
|
163
|
+
type: 'SPACES',
|
|
164
|
+
spaces: spacesMap,
|
|
165
|
+
spacesByConfig: configIdsMap,
|
|
166
|
+
spacesByPayer: payerIdsMap,
|
|
167
|
+
loading: false,
|
|
168
|
+
});
|
|
169
|
+
}, [spacesBySpaceIds, spacesByPayerIds, payerIds, spaceIds]);
|
|
170
|
+
|
|
171
|
+
// const hasParentModalProvider = useModal() !== undefined;
|
|
172
|
+
return (
|
|
173
|
+
<SpacesContext.Provider
|
|
174
|
+
children={children}
|
|
175
|
+
value={{
|
|
176
|
+
spaces: spacesMap,
|
|
177
|
+
spacesByConfig: configIdsMap,
|
|
178
|
+
spacesByPayer: payerIdsMap,
|
|
179
|
+
loading: loading || isLoadingByPayerIds || isLoadingBySpaceIds,
|
|
180
|
+
error,
|
|
181
|
+
}}
|
|
182
|
+
/>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const useSpaces = (...ids: string[]) => {
|
|
187
|
+
const { spaces, spacesByConfig, spacesByPayer } = useSpacesContext();
|
|
188
|
+
|
|
189
|
+
const idsIsEmpty = !ids || ids.length === 0;
|
|
190
|
+
const callerIsExpectingFirstSpace = ids?.length === 1 && ids[0] === undefined;
|
|
191
|
+
const shouldReturnAllSpaces = idsIsEmpty || callerIsExpectingFirstSpace;
|
|
192
|
+
|
|
193
|
+
if (shouldReturnAllSpaces) {
|
|
194
|
+
console.warn(`You did not pass in an ID to find a space, returning all spaces.`);
|
|
195
|
+
return spaces && normalizeSpaces([...spaces.values()]);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const matchedSpaces = ids.map((id) => spaces?.get(id) || spacesByConfig?.get(id) || spacesByPayer?.get(id));
|
|
199
|
+
const normalized = normalizeSpaces(matchedSpaces);
|
|
200
|
+
|
|
201
|
+
return normalized;
|
|
202
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export default `query configurationFindMany($ids: [String!], $payerIDs: [ID!], $types: [TypeEnum!]) {
|
|
2
|
+
configurationPagination(filter: { ids: $ids, payerIds: $payerIDs, types: $types }) {
|
|
3
|
+
pageInfo {
|
|
4
|
+
hasNextPage
|
|
5
|
+
currentPage
|
|
6
|
+
}
|
|
7
|
+
items {
|
|
8
|
+
... on Configuration {
|
|
9
|
+
configurationId
|
|
10
|
+
name
|
|
11
|
+
shortName
|
|
12
|
+
type
|
|
13
|
+
activeDate
|
|
14
|
+
isNew
|
|
15
|
+
description
|
|
16
|
+
payerIDs
|
|
17
|
+
parentIDs
|
|
18
|
+
metadataPairs {
|
|
19
|
+
name
|
|
20
|
+
value
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
... on Node {
|
|
25
|
+
id
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
... on Alert {
|
|
29
|
+
link {
|
|
30
|
+
text
|
|
31
|
+
target
|
|
32
|
+
url
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
... on Container {
|
|
37
|
+
link {
|
|
38
|
+
text
|
|
39
|
+
target
|
|
40
|
+
url
|
|
41
|
+
}
|
|
42
|
+
images {
|
|
43
|
+
tile
|
|
44
|
+
promotional
|
|
45
|
+
logo
|
|
46
|
+
billboard
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
... on PayerSpace {
|
|
51
|
+
link {
|
|
52
|
+
text
|
|
53
|
+
target
|
|
54
|
+
url
|
|
55
|
+
}
|
|
56
|
+
images {
|
|
57
|
+
tile
|
|
58
|
+
logo
|
|
59
|
+
billboard
|
|
60
|
+
}
|
|
61
|
+
url
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
... on Application {
|
|
65
|
+
link {
|
|
66
|
+
text
|
|
67
|
+
target
|
|
68
|
+
url
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
... on Resource {
|
|
73
|
+
link {
|
|
74
|
+
text
|
|
75
|
+
target
|
|
76
|
+
url
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
... on Navigation {
|
|
81
|
+
icons {
|
|
82
|
+
dashboard
|
|
83
|
+
navigation
|
|
84
|
+
}
|
|
85
|
+
images {
|
|
86
|
+
promotional
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
... on Learning {
|
|
91
|
+
images {
|
|
92
|
+
promotional
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
... on Proxy {
|
|
97
|
+
url
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
... on File {
|
|
101
|
+
url
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}`;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { updateUrl, getUrl } from './helpers';
|
|
2
|
+
|
|
3
|
+
describe('updateUrl', () => {
|
|
4
|
+
it('should parse the given url return the existing and new params in alphabetical order', () => {
|
|
5
|
+
let updatedUrl = updateUrl('http://www.example.com?foo=bar#hashme', 'fakeKey', 'fakeValue');
|
|
6
|
+
expect(updatedUrl).toBe('http://www.example.com?fakeKey=fakeValue&foo=bar%23hashme');
|
|
7
|
+
|
|
8
|
+
updatedUrl = updateUrl('http://www.example.com', 'fakeKey', 'fakeValue');
|
|
9
|
+
expect(updatedUrl).toBe('http://www.example.com?fakeKey=fakeValue');
|
|
10
|
+
|
|
11
|
+
updatedUrl = updateUrl('http://www.example.com?foo=bar', 'fakeKey', 'fakeValue');
|
|
12
|
+
expect(updatedUrl).toBe('http://www.example.com?fakeKey=fakeValue&foo=bar');
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('getUrl', () => {
|
|
17
|
+
it('should return an absolute url', () => {
|
|
18
|
+
const url = getUrl('http://www.availity.com', false, true);
|
|
19
|
+
expect(url).toBe('http://www.availity.com');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return a relative url', () => {
|
|
23
|
+
const url = getUrl('/path/to/my/app', true, false);
|
|
24
|
+
expect(url).toBe('/public/apps/home/#!/loadApp?appUrl=%2Fpath%2Fto%2Fmy%2Fapp');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import qs from 'qs';
|
|
2
|
+
|
|
3
|
+
export const updateUrl = (url: string, key: string, value: string) => {
|
|
4
|
+
const [uri, queryString] = url.split('?');
|
|
5
|
+
const currentParams = qs.parse(queryString);
|
|
6
|
+
const newParams = qs.stringify({ ...currentParams, [key]: value }, { sort: (a, b) => a.localeCompare(b) });
|
|
7
|
+
|
|
8
|
+
return `${uri}?${newParams}`;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const getUrl = (url = '', loadApp: boolean, absolute: boolean) => {
|
|
12
|
+
if (absolute || !loadApp) return url;
|
|
13
|
+
|
|
14
|
+
return `/public/apps/home/#!/loadApp?appUrl=${encodeURIComponent(url)}`;
|
|
15
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { normalizeSpaces, fetchAllSpaces } from './spaces-data';
|
|
2
|
+
import configurationFindMany from './configurationFindMany';
|
|
3
|
+
// eslint-disable-next-line @nx/enforce-module-boundaries
|
|
4
|
+
import { server } from '../../../mock/src/lib/server';
|
|
5
|
+
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
// Start the interception.
|
|
8
|
+
server.listen();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
// Remove any handlers you may have added
|
|
13
|
+
// in individual tests (runtime handlers).
|
|
14
|
+
server.resetHandlers();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterAll(() => {
|
|
18
|
+
// Disable request interception and clean up.
|
|
19
|
+
server.close();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('getAllSpaces', () => {
|
|
23
|
+
it('gets all spaces', async () => {
|
|
24
|
+
const spaces = await fetchAllSpaces({
|
|
25
|
+
query: configurationFindMany,
|
|
26
|
+
clientId: 'clientId',
|
|
27
|
+
variables: {
|
|
28
|
+
types: ['space'],
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
// Check correct spaces get returned
|
|
32
|
+
expect(spaces.length).toBe(10);
|
|
33
|
+
expect(spaces[0].id).toBe('1');
|
|
34
|
+
expect(spaces[spaces.length - 1].id).toBe('10');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('normalizeSpaces', () => {
|
|
39
|
+
it('normalizes space pairs', async () => {
|
|
40
|
+
const spaces = [
|
|
41
|
+
{
|
|
42
|
+
id: '1',
|
|
43
|
+
configurationId: '1',
|
|
44
|
+
type: 'space',
|
|
45
|
+
name: 'Space 1',
|
|
46
|
+
metadata: [
|
|
47
|
+
{ name: 'a', value: '1' },
|
|
48
|
+
{ name: 'b', value: '2' },
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const sanitized = normalizeSpaces(spaces);
|
|
54
|
+
|
|
55
|
+
expect(sanitized[0].metadata).toEqual({ a: '1', b: '2' });
|
|
56
|
+
});
|
|
57
|
+
});
|