Skip to content

Commit 18e939b

Browse files
authored
Merge pull request #2 from tienduy-nguyen/alert
Integrate Alert actions
2 parents cc03700 + 0d60905 commit 18e939b

File tree

13 files changed

+173
-38
lines changed

13 files changed

+173
-38
lines changed

server/db/db.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@
9797
"brand": "APPLE",
9898
"image_url": "https://store.storeimages.cdn-apple.com/4982/as-images.apple.com/is/iphone-12-pro-gold-hero?wid=470&hei=556&fmt=jpeg&qlt=95&op_usm=0.5,0.5&.v=1604021659000",
9999
"id": "f1d30887-14f9-4238-8ecd-c106d5f529e8"
100+
},
101+
{
102+
"name": "test",
103+
"brand": "OTHERS",
104+
"image_url": "/images/image-default.jpg",
105+
"id": "72fc536d-6992-4d26-a9ff-1294bb38cd5a"
100106
}
101107
]
102108
}

src/@types/alert.d.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//eslint-disable-next-line
2-
enum AlertTypes {
3-
SUCCESS = 'sucess',
4-
ERROR = 'error',
2+
3+
interface IAlert {
4+
id: string;
5+
msg: string;
6+
type: AlertTypes;
57
}

src/assets/scss/_home.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@
4242
background: rgba(0, 0, 0, 0.2);
4343
height: 100vh;
4444
}
45+
.alert-section {
46+
margin-top: 3px;
47+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as types from './Alert.constants';
2+
3+
export const setAlertSuccess = (payload: IAlert) => ({
4+
type: types.SET_ALERT,
5+
payload,
6+
});
7+
8+
export const removeAlertSuccess = (payload: string) => ({
9+
type: types.REMOVE_ALERT,
10+
payload,
11+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const SET_ALERT = 'view/Alert/SET_ALERT';
2+
export const REMOVE_ALERT = 'view/Alert/REMOVE_ALERT';
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as types from './Alert.constants';
2+
3+
const initialState = [] as IAlert[];
4+
5+
export const alertReducer = (state = initialState, action: ActionRedux) => {
6+
const { type, payload } = action;
7+
switch (type) {
8+
case types.SET_ALERT:
9+
return [...state, payload];
10+
case types.REMOVE_ALERT:
11+
return state.filter(alert => alert.id !== payload);
12+
default:
13+
return state;
14+
}
15+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as actions from './Alert.actions';
2+
import { v4 as uuid } from 'uuid';
3+
4+
interface PayloadAlert {
5+
msg: string;
6+
type: AlertTypes;
7+
}
8+
export const setAlert = (payload: PayloadAlert) => async dispatch => {
9+
const newAlert = { ...payload, id: uuid() };
10+
dispatch(actions.setAlertSuccess(newAlert));
11+
setTimeout(() => dispatch(actions.removeAlertSuccess(newAlert.id)), 4000);
12+
};

src/components/Alert/index.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react';
2+
import { connect, ConnectedProps } from 'react-redux';
3+
import { Alert } from 'antd';
4+
5+
const mapStateToProps = (state: AppState) => ({
6+
alerts: state.alerts,
7+
});
8+
const mapDispatchToProps = {};
9+
10+
const connector = connect(mapStateToProps, mapDispatchToProps);
11+
interface Props extends ConnectedProps<typeof connector> {}
12+
13+
const _AppAlert = (props: Props) => {
14+
const { alerts } = props;
15+
return (
16+
alerts !== null &&
17+
alerts.length > 0 &&
18+
alerts.map((alert, index) => {
19+
return (
20+
<div className="container">
21+
<div className="alert-section">
22+
<Alert
23+
message={alert.msg}
24+
type={alert.type}
25+
key={index}
26+
showIcon
27+
closable
28+
></Alert>
29+
</div>
30+
</div>
31+
);
32+
})
33+
);
34+
};
35+
36+
export const AppAlert = connector(_AppAlert);

src/components/Auth/Auth.thunks.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,30 @@ import axios from 'axios';
22
import { URL } from 'src/constants/urls';
33
import * as actions from './Auth.actions';
44
import { v4 as uuid } from 'uuid';
5+
import { setAlert } from 'src/components/Alert/Alert.thunks';
6+
import { AlertTypes } from 'src/constants/alerts';
57

68
export const loadUser = () => async dispatch => {
79
const userJson = localStorage.getItem('user') || '{}';
810
const user = JSON.parse(userJson) as IUser;
911
const id = user.id;
1012
if (!id) {
11-
return dispatch(actions.authError());
13+
dispatch(actions.authError());
14+
dispatch(setAlert({ msg: 'Cant not load user!', type: AlertTypes.ERROR }));
15+
return;
1216
}
1317
try {
1418
const res = await axios.get(`${URL.baseAPIUrl}/api/users/${id}`);
1519
if (res) {
1620
return dispatch(actions.userLoaded(res.data));
1721
}
18-
return dispatch(actions.authError());
22+
dispatch(actions.authError());
23+
dispatch(setAlert({ msg: 'Get user error!', type: AlertTypes.ERROR }));
24+
return;
1925
} catch (error) {
20-
return dispatch(actions.authError());
26+
dispatch(actions.authError());
27+
dispatch(setAlert({ msg: error.message, type: AlertTypes.ERROR }));
28+
return;
2129
}
2230
};
2331

@@ -30,6 +38,12 @@ export const login = (payload: ReqLogin) => async dispatch => {
3038
let user = allUsers.filter(x => x.username === username)[0];
3139
if (user && user.password === password) {
3240
dispatch(actions.loginSuccess(user));
41+
dispatch(
42+
setAlert({
43+
msg: 'You are logged!',
44+
type: AlertTypes.SUCCESS,
45+
}),
46+
);
3347
dispatch(loadUser());
3448
return;
3549
}
@@ -47,11 +61,23 @@ export const register = (payload: ReqLogin) => async dispatch => {
4761
const newUser = { ...payload, id, accessToken };
4862
await axios.post(`${URL.baseAPIUrl}/api/users`, newUser);
4963
dispatch(actions.registerSuccess(newUser));
64+
dispatch(
65+
setAlert({
66+
msg: 'Register successfully!',
67+
type: AlertTypes.SUCCESS,
68+
}),
69+
);
5070
dispatch(loadUser());
5171
} catch (error) {
5272
return dispatch(actions.registerFailed());
5373
}
5474
};
5575
export const logout = () => async dispatch => {
56-
return dispatch(actions.logoutSuccess());
76+
dispatch(actions.logoutSuccess());
77+
dispatch(
78+
setAlert({
79+
msg: 'You are logged out!',
80+
type: AlertTypes.WARNING,
81+
}),
82+
);
5783
};

src/components/Products/Product.thunks.ts

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,30 @@ import axios from 'axios';
22
import { URL } from 'src/constants/urls';
33
import * as actions from './Product.actions';
44
import { v4 as uuid } from 'uuid';
5+
import { setAlert } from 'src/components/Alert/Alert.thunks';
6+
import { AlertTypes } from 'src/constants/alerts';
7+
8+
const dispatchError = (dispatch, error) => {
9+
const payload = {
10+
msg: error.response?.statusText,
11+
status: error.response?.status,
12+
};
13+
dispatch(actions.productError(payload));
14+
dispatch(
15+
setAlert({
16+
msg: error.response?.statusText,
17+
type: AlertTypes.ERROR,
18+
}),
19+
);
20+
};
521

622
export const getProducts = () => async dispatch => {
723
try {
824
const res = await axios.get(`${URL.baseAPIUrl}/api/products`);
925
const products = res.data;
1026
dispatch(actions.getProductsSuccess(products));
1127
} catch (error) {
12-
const payload = {
13-
msg: error.response?.statusText,
14-
status: error.response?.status,
15-
};
16-
dispatch(actions.productError(payload));
28+
dispatchError(dispatch, error);
1729
}
1830
};
1931

@@ -23,11 +35,7 @@ export const getProduct = id => async dispatch => {
2335
const product = res.data as Product;
2436
dispatch(actions.getProductSuccess(product));
2537
} catch (error) {
26-
const payload = {
27-
msg: error.response?.statusText,
28-
status: error.response?.status,
29-
};
30-
dispatch(actions.productError(payload));
38+
dispatchError(dispatch, error);
3139
}
3240
};
3341
export const clearProduct = () => dispatch => {
@@ -44,27 +52,31 @@ export const createProduct = (formData: ProductForm) => async dispatch => {
4452
};
4553
await axios.post(`${URL.baseAPIUrl}/api/products`, newProduct);
4654
dispatch(actions.createProductSuccess(newProduct));
55+
dispatch(
56+
setAlert({
57+
msg: 'Create product successfully',
58+
type: AlertTypes.SUCCESS,
59+
}),
60+
);
4761
dispatch(getProducts());
4862
} catch (error) {
49-
const payload = {
50-
msg: error.response?.statusText,
51-
status: error.response?.status,
52-
};
53-
dispatch(actions.productError(payload));
63+
dispatchError(dispatch, error);
5464
}
5565
};
5666

5767
export const deleteProduct = (id: string) => async dispatch => {
5868
try {
5969
await axios.delete(`${URL.baseAPIUrl}/api/products/${id}`);
6070
dispatch(actions.deleteProductSuccess(id));
71+
dispatch(
72+
setAlert({
73+
msg: 'Delete product successfully',
74+
type: AlertTypes.SUCCESS,
75+
}),
76+
);
6177
dispatch(getProducts());
6278
} catch (error) {
63-
const payload = {
64-
msg: error.response?.statusText,
65-
status: error.response?.status,
66-
};
67-
dispatch(actions.productError(payload));
79+
dispatchError(dispatch, error);
6880
}
6981
};
7082

@@ -74,24 +86,22 @@ export const editProduct = (id: string) => async dispatch => {
7486
const product = res.data as Product;
7587
dispatch(actions.editProductSuccess(product));
7688
} catch (error) {
77-
const payload = {
78-
msg: error.response?.statusText,
79-
status: error.response?.status,
80-
};
81-
dispatch(actions.productError(payload));
89+
dispatchError(dispatch, error);
8290
}
8391
};
8492

8593
export const updateProduct = (product: Product) => async dispatch => {
8694
try {
8795
await axios.put(`${URL.baseAPIUrl}/api/products/${product.id}`, product);
8896
dispatch(actions.updateProductSuccess(product));
97+
dispatch(
98+
setAlert({
99+
msg: 'Update product successfully',
100+
type: AlertTypes.SUCCESS,
101+
}),
102+
);
89103
dispatch(getProducts());
90104
} catch (error) {
91-
const payload = {
92-
msg: error.response?.statusText,
93-
status: error.response?.status,
94-
};
95-
dispatch(actions.productError(payload));
105+
dispatchError(dispatch, error);
96106
}
97107
};

0 commit comments

Comments
 (0)