Skip to content

Commit 82f58c2

Browse files
authored
Merge pull request #41 from darinalleman/10-show-unsaved-warning
Add unsaved changes alert for pack changes
2 parents 5c92eae + 2ab5c33 commit 82f58c2

4 files changed

Lines changed: 53 additions & 16 deletions

File tree

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"react-ga": "^2.5.6",
6464
"react-linkify": "^1.0.0-alpha",
6565
"react-router-dom": "^5.0.1",
66+
"react-router-navigation-confirm": "^1.1.7",
6667
"react-select": "^3.1.0",
6768
"recharts": "^1.7.1",
6869
"resolve": "1.10.0",

frontend/src/app/PackForm/PackForm.tsx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,18 @@ import PackItems from "app/components/PackItems";
1919
import { alertError, alertSuccess } from "app/components/Notifications";
2020
import Loading from "app/components/Loading";
2121
import { useSidebar } from "app/components/Sidebar/Context";
22+
import { NavigationConfirmModal } from 'react-router-navigation-confirm';
2223

23-
import { PageTitle, Controls, Box, Grid } from "styles/common";
24+
import { PageTitle, Controls, Box, Grid, PageDescription } from "styles/common";
2425

2526
const PackForm: React.FC<PackFormSpecs.Props> = ({ history, packId, getPack, exportItems, getItems, createPack, updatePack, user }) => {
2627
const [loading, setLoading] = React.useState<boolean>(true);
2728
const [inventory, setInventory] = React.useState<Item[]>([]);
2829
const [packItems, setPackItems] = React.useState<PackItem[]>([]);
2930
const [packData, setPackData] = React.useState<Pack | null>(null);
31+
const [hasPendingChanges, setHasPendingChanges] = React.useState<boolean>(false);
3032
const { dispatch } = useSidebar();
31-
33+
3234
React.useEffect(() => {
3335
setLoading(true);
3436
async function fetchData(id: number) {
@@ -63,18 +65,21 @@ const PackForm: React.FC<PackFormSpecs.Props> = ({ history, packId, getPack, exp
6365

6466
const addItem = (item: Item) => {
6567
const items = Object.assign([], [...packItems, { ...item, packItem: { notes: item.notes, quantity: 1, worn: false } }]);
68+
setHasPendingChanges(true);
6669
setPackItems(items);
6770
};
6871

6972
const removeItem = (itemId: number) => {
7073
const items = packItems.filter(i => i.id !== itemId);
74+
setHasPendingChanges(true);
7175
setPackItems(items);
7276
};
7377

7478
const updateItem = (itemId: number, field: string, value: string | number | boolean) => {
7579
const items: PackItem[] = Object.assign([], packItems);
7680
const idx = items.findIndex(item => item.id === itemId);
7781
items[idx].packItem[field] = value;
82+
setHasPendingChanges(true);
7883
setPackItems(items);
7984
};
8085

@@ -134,7 +139,10 @@ const PackForm: React.FC<PackFormSpecs.Props> = ({ history, packId, getPack, exp
134139
id: packId
135140
});
136141
updatePack(payload)
137-
.then(() => alertSuccess({ message: 'Packing list saved' }))
142+
.then(() => {
143+
alertSuccess({ message: 'Packing list saved' });
144+
setHasPendingChanges(false);
145+
})
138146
.catch(() => alertError({ message: 'Error saving packing list' }));
139147
}
140148
}}>
@@ -173,15 +181,15 @@ const PackForm: React.FC<PackFormSpecs.Props> = ({ history, packId, getPack, exp
173181
error={wasSubmitted && !!errors.title}
174182
errorMsg={errors.title}
175183
value={values.title}
176-
allowedLength={PackConstants.title}
177-
onChange={v => setFieldValue('title', v)}/>
184+
onChange={v => {setFieldValue('title', v); setHasPendingChanges(true);}}
185+
allowedLength={PackConstants.title}/>
178186

179187
<Textarea label="Field Notes"
180-
placeholder="Additional notes about this trip..."
181-
value={values.description || ''}
182-
onChange={v => setFieldValue('description', v)}
183-
last={true}
184-
allowedLength={PackConstants.description}/>
188+
placeholder="Additional notes about this trip..."
189+
value={values.description || ''}
190+
onChange={v => {setFieldValue('description', v);setHasPendingChanges(true);}}
191+
last={true}
192+
allowedLength={PackConstants.description}/>
185193
</div>
186194
<div className="third">
187195
<Row gutter={8}>
@@ -191,33 +199,34 @@ const PackForm: React.FC<PackFormSpecs.Props> = ({ history, packId, getPack, exp
191199
placeholder="1"
192200
value={values.duration || ''}
193201
onChange={v => {
194-
setFieldValue('duration', v);
202+
setFieldValue('duration', v);
195203
if (!values.duration_unit) {
196204
setFieldValue('duration_unit', DurationUnit.DAYS)
197205
}
206+
setHasPendingChanges(true);
198207
}}/>
199208
</Col>
200209
<Col span={12}>
201210
<Select placeholder="Days"
202211
defaultValue={durationUnit}
203212
value={durationUnit}
204213
options={durationUnitOptions()}
205-
onChange={(option: Option<string>) => setFieldValue('duration_unit', option.value)}
214+
onChange={(option: Option<string>) => {setFieldValue('duration_unit', option.value); setHasPendingChanges(true);}}
206215
style={{ marginTop: '14px' }}/>
207216
</Col>
208217
</Row>
209218
<Input label="Temp Range"
210219
placeholder="43° - 81° F"
211220
allowedLength={PackConstants.temp_range}
212221
value={values.temp_range || ''}
213-
onChange={v => setFieldValue('temp_range', v)}
222+
onChange={v => {setFieldValue('temp_range', v); setHasPendingChanges(true);}}
214223
/>
215224
<Row gutter={8}>
216225
<Col span={12}>
217226
<Input label="Season"
218227
placeholder="Summer"
219228
value={values.season || ''}
220-
onChange={v => setFieldValue('season', v)}
229+
onChange={v => {setFieldValue('season', v); setHasPendingChanges(true);}}
221230
last={true}
222231
allowedLength={PackConstants.season}
223232
/>
@@ -230,7 +239,7 @@ const PackForm: React.FC<PackFormSpecs.Props> = ({ history, packId, getPack, exp
230239
value: values.gender,
231240
label: values.gender
232241
}}
233-
onChange={(option: Option<string>) => setFieldValue('gender', option.value)}
242+
onChange={(option: Option<string>) => {setFieldValue('gender', option.value); setHasPendingChanges(true);}}
234243
last={true}
235244
/>
236245
</Col>
@@ -251,6 +260,16 @@ const PackForm: React.FC<PackFormSpecs.Props> = ({ history, packId, getPack, exp
251260
weightUnit={user.default_weight_unit}
252261
removeItem={removeItem}
253262
updateItem={updateItem}/>
263+
<NavigationConfirmModal
264+
when={hasPendingChanges}
265+
buttonClassName="ant-btn"
266+
buttonConfirmClassName="ant-btn-primary"
267+
footerClassName="navigation-confirm-modal-footer"
268+
bodyClassName="navigation-confirm-modal-body"
269+
confirmText="Yes"
270+
cancelText="No">
271+
<PageDescription><div style={{textAlign: "center"}}>You have unsaved changes. Are you sure you want to leave this page?</div></PageDescription>
272+
</NavigationConfirmModal>
254273
</>
255274
)
256275
}}

frontend/src/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import App from './App';
99
import * as serviceWorker from './serviceWorker';
1010
import { AppProvider } from './AppContext';
1111
import WithAnalytics from 'app/components/higher-order/with-analytics';
12+
import { HistoryListener } from 'react-router-navigation-confirm';
1213

1314
import { theme } from 'styles/theme';
1415
import 'styles/style.less';
@@ -22,7 +23,9 @@ ReactDOM.render(
2223
<Router>
2324
<Route render={(props) => (
2425
<WithAnalytics {...props}>
25-
<App/>
26+
<HistoryListener>
27+
<App/>
28+
</HistoryListener>
2629
</WithAnalytics>
2730
)}/>
2831
</Router>

frontend/src/styles/style.less

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,20 @@ body {
116116
}
117117
}
118118

119+
.navigation-confirm-modal-footer {
120+
font-family: "Open Sans", sans-serif;
121+
margin:.3em;
122+
float:right;
123+
button {
124+
margin:.3em;
125+
}
126+
}
127+
128+
.navigation-confirm-modal-body {
129+
font-family: "Open Sans", sans-serif;
130+
margin: .8em .5em;
131+
}
132+
119133
@media screen and (max-width: 660px) {
120134
html {
121135
font-size: .85em;

0 commit comments

Comments
 (0)