@axinom/mosaic-ui 0.33.0-rc.0 → 0.33.0-rc.19
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/components/Actions/Actions.models.d.ts +0 -13
- package/dist/components/Actions/Actions.models.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicDataList.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListRow/DynamicListRow.d.ts +3 -1
- package/dist/components/DynamicDataList/DynamicListRow/DynamicListRow.d.ts.map +1 -1
- package/dist/components/FormElements/CustomTags/CustomTags.d.ts.map +1 -1
- package/dist/components/FormElements/FileUploadControl/FileUploadControl.d.ts.map +1 -1
- package/dist/components/FormElements/Radio/Radio.d.ts.map +1 -1
- package/dist/components/FormElements/Tags/Tags.d.ts.map +1 -1
- package/dist/components/FormElements/formStoryHelper.d.ts.map +1 -1
- package/dist/components/FormStation/FormStation.d.ts.map +1 -1
- package/dist/components/FormStation/SaveOnNavigate/SaveOnNavigate.d.ts +2 -0
- package/dist/components/FormStation/SaveOnNavigate/SaveOnNavigate.d.ts.map +1 -1
- package/dist/components/FormStation/SaveOnNavigate/handleNavigationAttempt.d.ts +1 -1
- package/dist/components/FormStation/SaveOnNavigate/handleNavigationAttempt.d.ts.map +1 -1
- package/dist/components/FormStation/StationErrorStateType.d.ts +5 -0
- package/dist/components/FormStation/StationErrorStateType.d.ts.map +1 -0
- package/dist/components/FormStation/useValidationError.d.ts +15 -0
- package/dist/components/FormStation/useValidationError.d.ts.map +1 -0
- package/dist/components/InfoPanel/InfoImage/InfoImage.d.ts.map +1 -1
- package/dist/components/List/List.d.ts.map +1 -1
- package/dist/components/Loaders/ImageLoader/ImageLoader.d.ts +2 -0
- package/dist/components/Loaders/ImageLoader/ImageLoader.d.ts.map +1 -1
- package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts +1 -11
- package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +3 -3
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/initialize.d.ts +7 -4
- package/dist/initialize.d.ts.map +1 -1
- package/dist/utils/ErrorMapper/ApolloClient/ApolloErrorMapper.d.ts +9 -0
- package/dist/utils/ErrorMapper/ApolloClient/ApolloErrorMapper.d.ts.map +1 -0
- package/dist/utils/ErrorMapper/ErrorMapper.d.ts +15 -0
- package/dist/utils/ErrorMapper/ErrorMapper.d.ts.map +1 -0
- package/dist/utils/ErrorMapper/ErrorMapper.type.d.ts +11 -0
- package/dist/utils/ErrorMapper/ErrorMapper.type.d.ts.map +1 -0
- package/dist/utils/ErrorMapper/index.d.ts +4 -0
- package/dist/utils/ErrorMapper/index.d.ts.map +1 -0
- package/dist/utils/ErrorTypeToStationError.d.ts +1 -1
- package/dist/utils/ErrorTypeToStationError.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/Accordion/Accordion.scss +1 -1
- package/src/components/Accordion/AccordionItem/AccordionItem.scss +1 -1
- package/src/components/Actions/Action/Action.scss +0 -2
- package/src/components/Actions/Actions.models.ts +0 -14
- package/src/components/Actions/Actions.stories.tsx +4 -1
- package/src/components/Buttons/Button/Button.scss +66 -20
- package/src/components/Buttons/CompositeButton/CompositeButton.scss +50 -18
- package/src/components/Buttons/TextButton/TextButton.scss +45 -16
- package/src/components/DateTime/DatePicker/DatePicker.scss +15 -6
- package/src/components/DateTime/DateTimePicker.scss +6 -2
- package/src/components/DynamicDataList/DynamicDataList.tsx +1 -0
- package/src/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.scss +15 -5
- package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.tsx +1 -1
- package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer.scss +36 -12
- package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer.tsx +2 -2
- package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.scss +26 -0
- package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.tsx +7 -1
- package/src/components/Filters/Filter/Filter.scss +8 -2
- package/src/components/Filters/SelectionTypes/DateTimeFilter/DateTimeFilter.scss +4 -1
- package/src/components/FormElements/Checkbox/Checkbox.scss +20 -0
- package/src/components/FormElements/CustomTags/CustomTags.scss +24 -0
- package/src/components/FormElements/CustomTags/CustomTags.tsx +8 -2
- package/src/components/FormElements/DateTimeField/DateTimeText.spec.tsx +1 -1
- package/src/components/FormElements/DateTimeField/DateTimeText.tsx +1 -1
- package/src/components/FormElements/FileUploadControl/FileUploadControl.scss +4 -2
- package/src/components/FormElements/FileUploadControl/FileUploadControl.tsx +12 -3
- package/src/components/FormElements/Radio/Radio.scss +18 -3
- package/src/components/FormElements/Radio/Radio.tsx +2 -2
- package/src/components/FormElements/Select/Select.scss +10 -0
- package/src/components/FormElements/SingleLineText/SingleLineText.spec.tsx +2 -2
- package/src/components/FormElements/SingleLineText/SingleLineText.tsx +1 -1
- package/src/components/FormElements/Tags/Tags.scss +14 -0
- package/src/components/FormElements/Tags/Tags.tsx +5 -1
- package/src/components/FormElements/TextArea/TextArea.spec.tsx +2 -2
- package/src/components/FormElements/TextArea/TextArea.tsx +1 -1
- package/src/components/FormElements/formStoryHelper.tsx +163 -97
- package/src/components/FormStation/FormStation.spec.tsx +13 -3
- package/src/components/FormStation/FormStation.tsx +43 -19
- package/src/components/FormStation/SaveOnNavigate/SaveOnNavigate.tsx +5 -0
- package/src/components/FormStation/SaveOnNavigate/handleNavigationAttempt.spec.ts +21 -0
- package/src/components/FormStation/SaveOnNavigate/handleNavigationAttempt.ts +2 -0
- package/src/components/FormStation/StationErrorStateType.tsx +5 -0
- package/src/components/FormStation/useValidationError.tsx +59 -0
- package/src/components/InfoPanel/InfoImage/InfoImage.scss +8 -3
- package/src/components/InfoPanel/InfoImage/InfoImage.tsx +1 -0
- package/src/components/List/List.tsx +3 -1
- package/src/components/List/ListCheckBox/ListCheckBox.scss +8 -3
- package/src/components/List/ListRow/ListRow.scss +0 -4
- package/src/components/Loaders/ImageLoader/ImageLoader.scss +27 -21
- package/src/components/Loaders/ImageLoader/ImageLoader.spec.tsx +8 -12
- package/src/components/Loaders/ImageLoader/ImageLoader.tsx +8 -3
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.model.ts +0 -10
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.scss +0 -1
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.stories.tsx +5 -0
- package/src/components/index.ts +1 -1
- package/src/index.ts +1 -0
- package/src/initialize.ts +15 -12
- package/src/styles/variables.scss +32 -2
- package/src/utils/ErrorMapper/ApolloClient/ApolloErrorMapper.spec.ts +32 -0
- package/src/utils/ErrorMapper/ApolloClient/ApolloErrorMapper.tsx +33 -0
- package/src/utils/ErrorMapper/ErrorMapper.spec.ts +67 -0
- package/src/utils/ErrorMapper/ErrorMapper.ts +31 -0
- package/src/utils/ErrorMapper/ErrorMapper.type.ts +11 -0
- package/src/utils/ErrorMapper/index.ts +3 -0
- package/src/utils/ErrorTypeToStationError.spec.tsx +12 -0
- package/src/utils/ErrorTypeToStationError.tsx +5 -1
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Checkbox,
|
|
5
|
+
CustomTags,
|
|
6
|
+
Divider,
|
|
7
|
+
FileUploadControl,
|
|
8
|
+
Radio,
|
|
9
|
+
ReadOnlyField,
|
|
10
|
+
Select,
|
|
11
|
+
SingleLineText,
|
|
12
|
+
Tags,
|
|
13
|
+
} from '.';
|
|
4
14
|
import { generateItemArray } from '../../helpers/storybook';
|
|
15
|
+
import { TextButton } from '../Buttons';
|
|
5
16
|
import { DynamicListColumn } from '../DynamicDataList/DynamicDataList.model';
|
|
6
17
|
import {
|
|
7
18
|
createInputRenderer,
|
|
@@ -10,6 +21,8 @@ import {
|
|
|
10
21
|
import { formatDateTime } from '../Utils';
|
|
11
22
|
import { BooleanViewField } from './BooleanView/BooleanViewField';
|
|
12
23
|
import { DynamicDataListControl } from './DynamicDataListControl/DynamicDataListControl';
|
|
24
|
+
import { FileUpload } from './FileUploadControl/FileUploadControl';
|
|
25
|
+
import { TextArea } from './TextArea/TextArea';
|
|
13
26
|
|
|
14
27
|
interface DynamicListStoryData {
|
|
15
28
|
position: number;
|
|
@@ -67,13 +80,13 @@ const dataListColumns: DynamicListColumn<DynamicListStoryData>[] = [
|
|
|
67
80
|
];
|
|
68
81
|
|
|
69
82
|
export const SampleForm: React.FC = () => useCreateForm().form;
|
|
70
|
-
|
|
71
83
|
export const useCreateForm = (): {
|
|
72
84
|
form: JSX.Element;
|
|
73
85
|
title: string;
|
|
74
86
|
} => {
|
|
75
87
|
const [id] = useState(faker.datatype.uuid());
|
|
76
88
|
const [title, setTitle] = useState(`The ${generateTitle()}`);
|
|
89
|
+
const [title2, setTitle2] = useState(`The ${generateTitle()}`);
|
|
77
90
|
const [genres, setGenres] = useState<string[]>(['Crime', 'Drama']);
|
|
78
91
|
const [ratings, setRatings] = useState<
|
|
79
92
|
string | number | string[] | undefined
|
|
@@ -94,104 +107,157 @@ export const useCreateForm = (): {
|
|
|
94
107
|
country: faker.address.country(),
|
|
95
108
|
})),
|
|
96
109
|
);
|
|
110
|
+
const [radio, setRadio] = useState(1);
|
|
111
|
+
const [check, setCheck] = useState<boolean>();
|
|
112
|
+
const [file, setFile] = useState<FileUpload>();
|
|
113
|
+
|
|
114
|
+
const [disabled, setDisabled] = useState<boolean>(false);
|
|
97
115
|
|
|
98
116
|
return {
|
|
99
117
|
form: (
|
|
100
|
-
|
|
101
|
-
style={{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
label="
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
118
|
+
<>
|
|
119
|
+
<div style={{ marginBottom: 10 }}>
|
|
120
|
+
<TextButton
|
|
121
|
+
onButtonClicked={() => setDisabled(!disabled)}
|
|
122
|
+
text="Toggle Disabled"
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
<Divider />
|
|
126
|
+
<form
|
|
127
|
+
style={{
|
|
128
|
+
display: 'grid',
|
|
129
|
+
gridAutoRows: 'max-content',
|
|
130
|
+
gridTemplateColumns: '1fr',
|
|
131
|
+
rowGap: '20px',
|
|
132
|
+
}}
|
|
133
|
+
>
|
|
134
|
+
<ReadOnlyField label="Id" value={id} />
|
|
135
|
+
<SingleLineText
|
|
136
|
+
name="title"
|
|
137
|
+
label="Title"
|
|
138
|
+
value={title}
|
|
139
|
+
disabled={disabled}
|
|
140
|
+
onChange={(e) => setTitle(e.currentTarget.value)}
|
|
141
|
+
/>
|
|
142
|
+
<ReadOnlyField label="Publish State" value="PUBLISHED" />
|
|
143
|
+
<BooleanViewField
|
|
144
|
+
label="Status"
|
|
145
|
+
value={status}
|
|
146
|
+
trueLabel="Enabled"
|
|
147
|
+
falseLabel="Disabled"
|
|
148
|
+
/>
|
|
149
|
+
<Tags
|
|
150
|
+
name="genres"
|
|
151
|
+
label="Genre(s)"
|
|
152
|
+
value={genres}
|
|
153
|
+
tagsOptions={genresOptions}
|
|
154
|
+
onChange={(e) =>
|
|
155
|
+
setGenres(e.currentTarget.value as unknown as string[])
|
|
156
|
+
}
|
|
157
|
+
disabled={disabled}
|
|
158
|
+
/>
|
|
159
|
+
<Select
|
|
160
|
+
name="ratings"
|
|
161
|
+
label="Rating"
|
|
162
|
+
value={ratings}
|
|
163
|
+
options={selectOptions}
|
|
164
|
+
onChange={(e) => setRatings(e.currentTarget.value)}
|
|
165
|
+
disabled={disabled}
|
|
166
|
+
/>
|
|
167
|
+
<SingleLineText
|
|
168
|
+
name="shortDescription"
|
|
169
|
+
label="Short Description"
|
|
170
|
+
value={shortDescription}
|
|
171
|
+
placeholder="Enter a short description..."
|
|
172
|
+
onChange={(e) => setShortDescription(e.currentTarget.value)}
|
|
173
|
+
disabled={disabled}
|
|
174
|
+
/>
|
|
175
|
+
<TextArea
|
|
176
|
+
name="longDescription"
|
|
177
|
+
label="Long Description"
|
|
178
|
+
value={longDescription}
|
|
179
|
+
placeholder="Enter a description..."
|
|
180
|
+
onChange={(e) => setLongDescription(e.currentTarget.value)}
|
|
181
|
+
disabled={disabled}
|
|
182
|
+
/>
|
|
183
|
+
<CustomTags
|
|
184
|
+
name="cast"
|
|
185
|
+
value={cast}
|
|
186
|
+
label="Cast"
|
|
187
|
+
onChange={(e) =>
|
|
188
|
+
setCast(e.currentTarget.value as unknown as string[])
|
|
189
|
+
}
|
|
190
|
+
disabled={disabled}
|
|
191
|
+
/>
|
|
192
|
+
<CustomTags
|
|
193
|
+
name="directors"
|
|
194
|
+
value={directors}
|
|
195
|
+
label="Director(s)"
|
|
196
|
+
onChange={(e) =>
|
|
197
|
+
setDirectors(e.currentTarget.value as unknown as string[])
|
|
198
|
+
}
|
|
199
|
+
disabled={disabled}
|
|
200
|
+
/>
|
|
201
|
+
<Tags
|
|
202
|
+
name="locales"
|
|
203
|
+
value={locales}
|
|
204
|
+
label="Locale(s)"
|
|
205
|
+
tagsOptions={['en_US', 'pt_PT', 'zh_CN']}
|
|
206
|
+
onChange={(e) =>
|
|
207
|
+
setLocales(e.currentTarget.value as unknown as string[])
|
|
208
|
+
}
|
|
209
|
+
disabled={disabled}
|
|
210
|
+
/>
|
|
211
|
+
<DynamicDataListControl
|
|
212
|
+
name={'dataList'}
|
|
213
|
+
label={'Subtitles'}
|
|
214
|
+
columns={dataListColumns}
|
|
215
|
+
value={dataList}
|
|
216
|
+
positionPropertyName={'position'}
|
|
217
|
+
allowReordering={true}
|
|
218
|
+
allowRowDragging={true}
|
|
219
|
+
allowNewData={true}
|
|
220
|
+
onChange={(e) => setDataList(e as DynamicListStoryData[])}
|
|
221
|
+
disabled={disabled}
|
|
222
|
+
/>
|
|
223
|
+
|
|
224
|
+
<Radio
|
|
225
|
+
value={radio}
|
|
226
|
+
onChange={(e) => setRadio(Number(e.currentTarget.value))}
|
|
227
|
+
options={[
|
|
228
|
+
{ value: 1, label: 'A' },
|
|
229
|
+
{ value: 2, label: 'B' },
|
|
230
|
+
{ value: 3, label: 'C' },
|
|
231
|
+
]}
|
|
232
|
+
name={'radio'}
|
|
233
|
+
label={'Category'}
|
|
234
|
+
disabled={disabled}
|
|
235
|
+
/>
|
|
236
|
+
|
|
237
|
+
<Checkbox
|
|
238
|
+
value={check}
|
|
239
|
+
onChange={setCheck}
|
|
240
|
+
name={'check'}
|
|
241
|
+
label={'Is Premium?'}
|
|
242
|
+
disabled={disabled}
|
|
243
|
+
/>
|
|
244
|
+
|
|
245
|
+
<FileUploadControl
|
|
246
|
+
name={'file'}
|
|
247
|
+
value={file}
|
|
248
|
+
onFileSelected={(file) => setFile(file)}
|
|
249
|
+
placeholder={'Select a file'}
|
|
250
|
+
label={'File'}
|
|
251
|
+
disabled={disabled}
|
|
252
|
+
/>
|
|
253
|
+
<ReadOnlyField
|
|
254
|
+
label="Created At"
|
|
255
|
+
value={createdTime.toISOString()}
|
|
256
|
+
transform={formatDateTime}
|
|
257
|
+
/>
|
|
258
|
+
<ReadOnlyField label="Writer(s)" value={writers} />
|
|
259
|
+
</form>
|
|
260
|
+
</>
|
|
195
261
|
),
|
|
196
262
|
title,
|
|
197
263
|
};
|
|
@@ -5,7 +5,7 @@ import { act } from 'react-dom/test-utils';
|
|
|
5
5
|
import { MemoryRouter, Route } from 'react-router-dom';
|
|
6
6
|
import * as Yup from 'yup';
|
|
7
7
|
import { noop } from '../../helpers/utils';
|
|
8
|
-
import {
|
|
8
|
+
import { IndicatorType, setSaveIndicator } from '../../initialize';
|
|
9
9
|
import { ActionData, Actions } from '../Actions';
|
|
10
10
|
import { Action } from '../Actions/Action';
|
|
11
11
|
import { MessageBar } from '../MessageBar/MessageBar';
|
|
@@ -675,6 +675,11 @@ describe('Details', () => {
|
|
|
675
675
|
</FormStation>
|
|
676
676
|
</MemoryRouter>,
|
|
677
677
|
);
|
|
678
|
+
expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
679
|
+
1,
|
|
680
|
+
IndicatorType.Inactive,
|
|
681
|
+
); // 1. inactive 2. dirty
|
|
682
|
+
expect(setSaveIndicator).toHaveBeenNthCalledWith(2, IndicatorType.Dirty); // 1. inactive 2. dirty
|
|
678
683
|
|
|
679
684
|
// submit form
|
|
680
685
|
const actionSelected = wrapper
|
|
@@ -692,7 +697,7 @@ describe('Details', () => {
|
|
|
692
697
|
|
|
693
698
|
wrapper.update();
|
|
694
699
|
|
|
695
|
-
expect(
|
|
700
|
+
expect(setSaveIndicator).toHaveBeenNthCalledWith(3, IndicatorType.Saving);
|
|
696
701
|
|
|
697
702
|
// complete form submission
|
|
698
703
|
await act(async () => {
|
|
@@ -700,7 +705,12 @@ describe('Details', () => {
|
|
|
700
705
|
});
|
|
701
706
|
wrapper.update();
|
|
702
707
|
|
|
703
|
-
expect(
|
|
708
|
+
expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
709
|
+
4,
|
|
710
|
+
IndicatorType.Inactive,
|
|
711
|
+
);
|
|
712
|
+
|
|
713
|
+
console.warn((setSaveIndicator as jest.Mock).mock.calls);
|
|
704
714
|
});
|
|
705
715
|
});
|
|
706
716
|
});
|
|
@@ -16,7 +16,7 @@ import React, {
|
|
|
16
16
|
} from 'react';
|
|
17
17
|
import { useHistory } from 'react-router-dom';
|
|
18
18
|
import { OptionalObjectSchema } from 'yup/lib/object';
|
|
19
|
-
import {
|
|
19
|
+
import { IndicatorType, setSaveIndicator } from '../../initialize';
|
|
20
20
|
import { Data } from '../../types/data';
|
|
21
21
|
import { ErrorTypeToStationError } from '../../utils/ErrorTypeToStationError';
|
|
22
22
|
import { Actions, ActionsProps } from '../Actions';
|
|
@@ -28,10 +28,12 @@ import {
|
|
|
28
28
|
PageHeaderActionType,
|
|
29
29
|
PageHeaderProps,
|
|
30
30
|
} from '../PageHeader';
|
|
31
|
-
import { ErrorType,
|
|
31
|
+
import { ErrorType, StationMessage } from '../models';
|
|
32
32
|
import { FormActionData, InitialFormData } from './FormStation.models';
|
|
33
33
|
import classes from './FormStation.scss';
|
|
34
34
|
import { SaveOnNavigate } from './SaveOnNavigate/SaveOnNavigate';
|
|
35
|
+
import { StationErrorStateType } from './StationErrorStateType';
|
|
36
|
+
import { useValidationError } from './useValidationError';
|
|
35
37
|
|
|
36
38
|
export type ObjectSchemaDefinition<
|
|
37
39
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -103,7 +105,8 @@ interface FormActionProps<T, Y> extends Omit<ActionsProps, 'actions'> {
|
|
|
103
105
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
104
106
|
validationSchema?: OptionalObjectSchema<ObjectSchemaDefinition<any>>;
|
|
105
107
|
actions?: FormActionData<T, Y>[];
|
|
106
|
-
setStationError: (error:
|
|
108
|
+
setStationError: (error: StationErrorStateType) => void;
|
|
109
|
+
setValidationError: () => void;
|
|
107
110
|
submitResponse?: React.MutableRefObject<Y | undefined>;
|
|
108
111
|
alwaysSubmitBeforeAction?: boolean;
|
|
109
112
|
className?: string;
|
|
@@ -131,8 +134,12 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
131
134
|
}: PropsWithChildren<
|
|
132
135
|
FormStationProps<TValues, TSubmitResponse>
|
|
133
136
|
>): JSX.Element => {
|
|
134
|
-
const [stationError, setStationError] = useState<
|
|
135
|
-
|
|
137
|
+
const [stationError, setStationError] = useState<StationErrorStateType>();
|
|
138
|
+
|
|
139
|
+
const { setValidationError, validationWatcher } = useValidationError(
|
|
140
|
+
stationError,
|
|
141
|
+
setStationError,
|
|
142
|
+
);
|
|
136
143
|
|
|
137
144
|
const submitResponse = useRef<TSubmitResponse>();
|
|
138
145
|
const [isFormSubmitting, setIsFormSubmitting] = useState<boolean>(false);
|
|
@@ -148,7 +155,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
148
155
|
|
|
149
156
|
try {
|
|
150
157
|
setIsFormSubmitting(true);
|
|
151
|
-
|
|
158
|
+
setSaveIndicator(IndicatorType.Saving);
|
|
152
159
|
setStationError(undefined);
|
|
153
160
|
if (!initialData.loading && saveData) {
|
|
154
161
|
const response = await saveData(values, initialData, formikHelpers);
|
|
@@ -164,13 +171,14 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
164
171
|
),
|
|
165
172
|
);
|
|
166
173
|
|
|
174
|
+
setSaveIndicator(IndicatorType.Dirty);
|
|
175
|
+
|
|
167
176
|
// We still throw the error, to make sure that navigation or action execution
|
|
168
177
|
// will not continue after a failed save.
|
|
169
178
|
throw error;
|
|
170
179
|
} finally {
|
|
171
180
|
formikHelpers.setSubmitting(false);
|
|
172
181
|
setIsFormSubmitting(false);
|
|
173
|
-
hideSaveIndicator();
|
|
174
182
|
}
|
|
175
183
|
},
|
|
176
184
|
[isFormSubmitting, initialData, saveData, setStationError],
|
|
@@ -182,19 +190,20 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
182
190
|
(initialData.data === null && !initialData.loading) ||
|
|
183
191
|
initialData.entityNotFound
|
|
184
192
|
) {
|
|
185
|
-
const stationError =
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
193
|
+
const stationError = {
|
|
194
|
+
...ErrorTypeToStationError(
|
|
195
|
+
initialData.error,
|
|
196
|
+
'An error occurred when trying to load data.',
|
|
197
|
+
'Entity not found',
|
|
198
|
+
),
|
|
199
|
+
type: 'loading',
|
|
200
|
+
};
|
|
190
201
|
|
|
191
202
|
setStationError(stationError);
|
|
192
|
-
setIsLoadingError(true);
|
|
193
203
|
} else {
|
|
194
|
-
if (
|
|
204
|
+
if (stationError?.type === 'loading') {
|
|
195
205
|
// Only clear the error if it is a loading error, which now seems to be cleared.
|
|
196
206
|
setStationError(undefined);
|
|
197
|
-
setIsLoadingError(false);
|
|
198
207
|
}
|
|
199
208
|
}
|
|
200
209
|
}, [
|
|
@@ -202,7 +211,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
202
211
|
initialData.error,
|
|
203
212
|
initialData.entityNotFound,
|
|
204
213
|
initialData.data,
|
|
205
|
-
|
|
214
|
+
stationError?.type,
|
|
206
215
|
]);
|
|
207
216
|
|
|
208
217
|
const getContent = (): JSX.Element | undefined => {
|
|
@@ -223,7 +232,10 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
223
232
|
// Loading successful
|
|
224
233
|
return (
|
|
225
234
|
<>
|
|
226
|
-
<SaveOnNavigate
|
|
235
|
+
<SaveOnNavigate
|
|
236
|
+
isSubmitting={isFormSubmitting}
|
|
237
|
+
onNavigationCancelled={setValidationError}
|
|
238
|
+
/>
|
|
227
239
|
<div className={classes.main}>
|
|
228
240
|
<div
|
|
229
241
|
className={clsx(classes.formWrapper, {
|
|
@@ -272,6 +284,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
272
284
|
enableReinitialize={true}
|
|
273
285
|
>
|
|
274
286
|
<>
|
|
287
|
+
{validationWatcher}
|
|
275
288
|
<FormStationHeader
|
|
276
289
|
titleProperty={titleProperty as string}
|
|
277
290
|
defaultTitle={defaultTitle}
|
|
@@ -296,6 +309,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
296
309
|
width={actionsWidth}
|
|
297
310
|
validationSchema={validationSchema}
|
|
298
311
|
setStationError={setStationError}
|
|
312
|
+
setValidationError={setValidationError}
|
|
299
313
|
submitResponse={submitResponse}
|
|
300
314
|
alwaysSubmitBeforeAction={alwaysSubmitBeforeAction}
|
|
301
315
|
className={classes.actionsPanel}
|
|
@@ -317,6 +331,7 @@ const FormStationAction = <T, Y>(
|
|
|
317
331
|
actions,
|
|
318
332
|
validationSchema,
|
|
319
333
|
setStationError,
|
|
334
|
+
setValidationError,
|
|
320
335
|
submitResponse,
|
|
321
336
|
alwaysSubmitBeforeAction,
|
|
322
337
|
className = '',
|
|
@@ -352,8 +367,7 @@ const FormStationAction = <T, Y>(
|
|
|
352
367
|
!isValid ||
|
|
353
368
|
(await validationSchema?.isValid(values)) === false
|
|
354
369
|
) {
|
|
355
|
-
|
|
356
|
-
console.log('form invalid, action not performed');
|
|
370
|
+
setValidationError();
|
|
357
371
|
// Making sure that the fields will actually show the validation messages (they won't if the from was not touched yet - e.g. on a create station)
|
|
358
372
|
validateForm();
|
|
359
373
|
return;
|
|
@@ -405,6 +419,7 @@ const FormStationAction = <T, Y>(
|
|
|
405
419
|
isValid,
|
|
406
420
|
resetForm,
|
|
407
421
|
setStationError,
|
|
422
|
+
setValidationError,
|
|
408
423
|
submitForm,
|
|
409
424
|
submitResponse,
|
|
410
425
|
validateForm,
|
|
@@ -431,6 +446,15 @@ const FormStationHeader: React.FC<
|
|
|
431
446
|
> = ({ titleProperty, defaultTitle, subtitle, cancelNavigationUrl }) => {
|
|
432
447
|
const { dirty, resetForm, values } = useFormikContext<FormikValues>();
|
|
433
448
|
|
|
449
|
+
useEffect(() => {
|
|
450
|
+
// Set the save indicator to dirty depending on the form state
|
|
451
|
+
if (dirty) {
|
|
452
|
+
setSaveIndicator(IndicatorType.Dirty);
|
|
453
|
+
} else {
|
|
454
|
+
setSaveIndicator(IndicatorType.Inactive);
|
|
455
|
+
}
|
|
456
|
+
}, [dirty]);
|
|
457
|
+
|
|
434
458
|
const history = useHistory();
|
|
435
459
|
|
|
436
460
|
const title =
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { useFormikContext } from 'formik';
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
|
+
import { noop } from '../../../helpers/utils';
|
|
3
4
|
import { NavigationAPI, useReactRouterPause } from '../../../hooks';
|
|
4
5
|
import { handleNavigationAttempt } from './handleNavigationAttempt';
|
|
5
6
|
|
|
6
7
|
interface SaveOnNavigateProps {
|
|
7
8
|
/** If set to true, will prevent form submission when navigating away. (default: false) */
|
|
8
9
|
isSubmitting?: boolean;
|
|
10
|
+
/** Callback that will be called when a navigation attempt was cancelled */
|
|
11
|
+
onNavigationCancelled?: () => void;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
/**
|
|
@@ -13,6 +16,7 @@ interface SaveOnNavigateProps {
|
|
|
13
16
|
*/
|
|
14
17
|
export const SaveOnNavigate: React.FC<SaveOnNavigateProps> = ({
|
|
15
18
|
isSubmitting = false,
|
|
19
|
+
onNavigationCancelled = noop,
|
|
16
20
|
}) => {
|
|
17
21
|
const { dirty, isValid, submitForm } = useFormikContext();
|
|
18
22
|
const [canSubmit, setCanSubmit] = useState<boolean>(true);
|
|
@@ -28,6 +32,7 @@ export const SaveOnNavigate: React.FC<SaveOnNavigateProps> = ({
|
|
|
28
32
|
isSubmitting,
|
|
29
33
|
canSubmit,
|
|
30
34
|
setCanSubmit,
|
|
35
|
+
onNavigationCancelled,
|
|
31
36
|
),
|
|
32
37
|
},
|
|
33
38
|
dirty,
|