Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions server/db/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@
"brand": "APPLE",
"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",
"id": "f1d30887-14f9-4238-8ecd-c106d5f529e8"
},
{
"name": "test",
"brand": "OTHERS",
"image_url": "/images/image-default.jpg",
"id": "72fc536d-6992-4d26-a9ff-1294bb38cd5a"
}
]
}
8 changes: 5 additions & 3 deletions src/@types/alert.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//eslint-disable-next-line
enum AlertTypes {
SUCCESS = 'sucess',
ERROR = 'error',

interface IAlert {
id: string;
msg: string;
type: AlertTypes;
}
3 changes: 3 additions & 0 deletions src/assets/scss/_home.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@
background: rgba(0, 0, 0, 0.2);
height: 100vh;
}
.alert-section {
margin-top: 3px;
}
11 changes: 11 additions & 0 deletions src/components/Alert/Alert.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as types from './Alert.constants';

export const setAlertSuccess = (payload: IAlert) => ({
type: types.SET_ALERT,
payload,
});

export const removeAlertSuccess = (payload: string) => ({
type: types.REMOVE_ALERT,
payload,
});
2 changes: 2 additions & 0 deletions src/components/Alert/Alert.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const SET_ALERT = 'view/Alert/SET_ALERT';
export const REMOVE_ALERT = 'view/Alert/REMOVE_ALERT';
15 changes: 15 additions & 0 deletions src/components/Alert/Alert.reducers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as types from './Alert.constants';

const initialState = [] as IAlert[];

export const alertReducer = (state = initialState, action: ActionRedux) => {
const { type, payload } = action;
switch (type) {
case types.SET_ALERT:
return [...state, payload];
case types.REMOVE_ALERT:
return state.filter(alert => alert.id !== payload);
default:
return state;
}
};
12 changes: 12 additions & 0 deletions src/components/Alert/Alert.thunks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as actions from './Alert.actions';
import { v4 as uuid } from 'uuid';

interface PayloadAlert {
msg: string;
type: AlertTypes;
}
export const setAlert = (payload: PayloadAlert) => async dispatch => {
const newAlert = { ...payload, id: uuid() };
dispatch(actions.setAlertSuccess(newAlert));
setTimeout(() => dispatch(actions.removeAlertSuccess(newAlert.id)), 4000);
};
36 changes: 36 additions & 0 deletions src/components/Alert/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { Alert } from 'antd';

const mapStateToProps = (state: AppState) => ({
alerts: state.alerts,
});
const mapDispatchToProps = {};

const connector = connect(mapStateToProps, mapDispatchToProps);
interface Props extends ConnectedProps<typeof connector> {}

const _AppAlert = (props: Props) => {
const { alerts } = props;
return (
alerts !== null &&
alerts.length > 0 &&
alerts.map((alert, index) => {
return (
<div className="container">
<div className="alert-section">
<Alert
message={alert.msg}
type={alert.type}
key={index}
showIcon
closable
></Alert>
</div>
</div>
);
})
);
};

export const AppAlert = connector(_AppAlert);
34 changes: 30 additions & 4 deletions src/components/Auth/Auth.thunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,30 @@ import axios from 'axios';
import { URL } from 'src/constants/urls';
import * as actions from './Auth.actions';
import { v4 as uuid } from 'uuid';
import { setAlert } from 'src/components/Alert/Alert.thunks';
import { AlertTypes } from 'src/constants/alerts';

export const loadUser = () => async dispatch => {
const userJson = localStorage.getItem('user') || '{}';
const user = JSON.parse(userJson) as IUser;
const id = user.id;
if (!id) {
return dispatch(actions.authError());
dispatch(actions.authError());
dispatch(setAlert({ msg: 'Cant not load user!', type: AlertTypes.ERROR }));
return;
}
try {
const res = await axios.get(`${URL.baseAPIUrl}/api/users/${id}`);
if (res) {
return dispatch(actions.userLoaded(res.data));
}
return dispatch(actions.authError());
dispatch(actions.authError());
dispatch(setAlert({ msg: 'Get user error!', type: AlertTypes.ERROR }));
return;
} catch (error) {
return dispatch(actions.authError());
dispatch(actions.authError());
dispatch(setAlert({ msg: error.message, type: AlertTypes.ERROR }));
return;
}
};

Expand All @@ -30,6 +38,12 @@ export const login = (payload: ReqLogin) => async dispatch => {
let user = allUsers.filter(x => x.username === username)[0];
if (user && user.password === password) {
dispatch(actions.loginSuccess(user));
dispatch(
setAlert({
msg: 'You are logged!',
type: AlertTypes.SUCCESS,
}),
);
dispatch(loadUser());
return;
}
Expand All @@ -47,11 +61,23 @@ export const register = (payload: ReqLogin) => async dispatch => {
const newUser = { ...payload, id, accessToken };
await axios.post(`${URL.baseAPIUrl}/api/users`, newUser);
dispatch(actions.registerSuccess(newUser));
dispatch(
setAlert({
msg: 'Register successfully!',
type: AlertTypes.SUCCESS,
}),
);
dispatch(loadUser());
} catch (error) {
return dispatch(actions.registerFailed());
}
};
export const logout = () => async dispatch => {
return dispatch(actions.logoutSuccess());
dispatch(actions.logoutSuccess());
dispatch(
setAlert({
msg: 'You are logged out!',
type: AlertTypes.WARNING,
}),
);
};
70 changes: 40 additions & 30 deletions src/components/Products/Product.thunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,30 @@ import axios from 'axios';
import { URL } from 'src/constants/urls';
import * as actions from './Product.actions';
import { v4 as uuid } from 'uuid';
import { setAlert } from 'src/components/Alert/Alert.thunks';
import { AlertTypes } from 'src/constants/alerts';

const dispatchError = (dispatch, error) => {
const payload = {
msg: error.response?.statusText,
status: error.response?.status,
};
dispatch(actions.productError(payload));
dispatch(
setAlert({
msg: error.response?.statusText,
type: AlertTypes.ERROR,
}),
);
};

export const getProducts = () => async dispatch => {
try {
const res = await axios.get(`${URL.baseAPIUrl}/api/products`);
const products = res.data;
dispatch(actions.getProductsSuccess(products));
} catch (error) {
const payload = {
msg: error.response?.statusText,
status: error.response?.status,
};
dispatch(actions.productError(payload));
dispatchError(dispatch, error);
}
};

Expand All @@ -23,11 +35,7 @@ export const getProduct = id => async dispatch => {
const product = res.data as Product;
dispatch(actions.getProductSuccess(product));
} catch (error) {
const payload = {
msg: error.response?.statusText,
status: error.response?.status,
};
dispatch(actions.productError(payload));
dispatchError(dispatch, error);
}
};
export const clearProduct = () => dispatch => {
Expand All @@ -44,27 +52,31 @@ export const createProduct = (formData: ProductForm) => async dispatch => {
};
await axios.post(`${URL.baseAPIUrl}/api/products`, newProduct);
dispatch(actions.createProductSuccess(newProduct));
dispatch(
setAlert({
msg: 'Create product successfully',
type: AlertTypes.SUCCESS,
}),
);
dispatch(getProducts());
} catch (error) {
const payload = {
msg: error.response?.statusText,
status: error.response?.status,
};
dispatch(actions.productError(payload));
dispatchError(dispatch, error);
}
};

export const deleteProduct = (id: string) => async dispatch => {
try {
await axios.delete(`${URL.baseAPIUrl}/api/products/${id}`);
dispatch(actions.deleteProductSuccess(id));
dispatch(
setAlert({
msg: 'Delete product successfully',
type: AlertTypes.SUCCESS,
}),
);
dispatch(getProducts());
} catch (error) {
const payload = {
msg: error.response?.statusText,
status: error.response?.status,
};
dispatch(actions.productError(payload));
dispatchError(dispatch, error);
}
};

Expand All @@ -74,24 +86,22 @@ export const editProduct = (id: string) => async dispatch => {
const product = res.data as Product;
dispatch(actions.editProductSuccess(product));
} catch (error) {
const payload = {
msg: error.response?.statusText,
status: error.response?.status,
};
dispatch(actions.productError(payload));
dispatchError(dispatch, error);
}
};

export const updateProduct = (product: Product) => async dispatch => {
try {
await axios.put(`${URL.baseAPIUrl}/api/products/${product.id}`, product);
dispatch(actions.updateProductSuccess(product));
dispatch(
setAlert({
msg: 'Update product successfully',
type: AlertTypes.SUCCESS,
}),
);
dispatch(getProducts());
} catch (error) {
const payload = {
msg: error.response?.statusText,
status: error.response?.status,
};
dispatch(actions.productError(payload));
dispatchError(dispatch, error);
}
};
6 changes: 6 additions & 0 deletions src/constants/alerts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum AlertTypes {
SUCCESS = 'success',
ERROR = 'error',
INFO = 'info',
WARNING = 'warning',
}
6 changes: 5 additions & 1 deletion src/pages/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { ReactNode } from 'react';
import { AppHeader } from 'src/components/Header';
import { AppFooter } from 'src/components/Footer';
import { Layout } from 'antd';
import { AppAlert } from 'src/components/Alert';
const { Header, Content, Footer } = Layout;

interface Props {
Expand All @@ -14,7 +15,10 @@ export const MainLayout = (props: Props) => {
<Header>
<AppHeader />
</Header>
<Content className="layout-children">{children}</Content>
<Content className="layout-children">
<AppAlert />
{children}
</Content>
<Footer>
<AppFooter />
</Footer>
Expand Down
2 changes: 2 additions & 0 deletions src/store/reducers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { combineReducers } from 'redux';
import { authReducer } from 'src/components/Auth/Auth.reducers';
import { productReducer } from 'src/components/Products/Product.reducers';
import { alertReducer } from 'src/components/Alert/Alert.reducers';

export const RootReducer = combineReducers({
auth: authReducer,
products: productReducer,
alerts: alertReducer,
});