Skip to content

Commit

Permalink
react-boilerplate#33: implement api brand and breadcrumbs
Browse files Browse the repository at this point in the history
  • Loading branch information
Thinh922001 committed Oct 8, 2024
1 parent 756afe0 commit 03b9a2c
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 23 deletions.
16 changes: 7 additions & 9 deletions src/app/pages/Category/components/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import styled from 'styled-components';
import FilterImg from './assets/filter.png';
import { FilterBy } from './ButtonBrand';
import { SortByLabel } from './SortBy';
import { IBrand } from 'types/Card';
import { useProductCateSlice } from '../slice';
import { useSelector } from 'react-redux';
import { selectBrand } from '../slice/selector';

export const Filter = () => {
useProductCateSlice();
const [isSticky, setIsSticky] = useState(false);

useEffect(() => {
Expand All @@ -22,14 +27,7 @@ export const Filter = () => {
};
}, []);

const FilterData = [
'Apple',
'SamSung',
'Xiaomi',
'OPPO',
'Chơi game',
'Pin khủng',
];
const FilterData: IBrand[] = useSelector(selectBrand);

return (
<Wrapper className={isSticky ? 'sticky' : ''}>
Expand All @@ -40,7 +38,7 @@ export const Filter = () => {
Lọc
</BtnFilterAll>
{FilterData.length > 0 &&
FilterData.map((e, index) => <FilterBy key={index} text={e} />)}
FilterData.map(e => <FilterBy key={e.id} text={e.name} />)}
</Brand>
<SortBy>
<SortByLabel />
Expand Down
25 changes: 14 additions & 11 deletions src/app/pages/Category/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import { useEffect } from 'react';
import { ProductCateActions, useProductCateSlice } from './slice';
import { useDispatch, useSelector } from 'react-redux';
import { CenteredLoading } from 'app/components/LoadingCenter';
import { selectIsLoading } from './slice/selector';
import {
selectBrandLoading,
selectBreadCrumb,
selectBreadCrumbLoading,
selectIsLoading,
} from './slice/selector';

export function Category() {
useProductCateSlice();
Expand All @@ -22,28 +27,26 @@ export function Category() {

const isLoading = useSelector(selectIsLoading);

const isBreadCrumbLoading = useSelector(selectBreadCrumbLoading);

const isBrandLoading = useSelector(selectBrandLoading);

useEffect(() => {
dispatch(ProductCateActions.setCateId(id));
dispatch(ProductCateActions.loadProduct());
dispatch(ProductCateActions.loadBreadCrumb());
dispatch(ProductCateActions.loadingBrand());
}, [id]);

const BreakCumData: IBreakCum[] = [
{
name: 'Trang chủ',
link: '/',
},
{
name: '136 điện thoại',
},
];
const BreakCumData: IBreakCum[] = useSelector(selectBreadCrumb);
return (
<>
<Helmet>
<title>Danh mục</title>
<meta name="description" content="login" />
</Helmet>
<Wrapper>
{isLoading ? (
{isLoading || isBreadCrumbLoading || isBrandLoading ? (
<WrapperLoading>
<CenteredLoading minHeight="100%" />
</WrapperLoading>
Expand Down
22 changes: 21 additions & 1 deletion src/app/pages/Category/slice/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@ import { PayloadAction } from '@reduxjs/toolkit';
import { ProductCateState } from './type';
import { createSlice } from 'utils/@reduxjs/toolkit';
import { useInjectReducer, useInjectSaga } from 'utils/redux-injectors';
import { ICard } from 'types/Card';
import { IBrand, IBreadCrumb, ICard } from 'types/Card';
import { ProductCateFromSaga } from './saga';

export const initialState: ProductCateState = {
isLoading: false,
isPageLoading: false,
isBreadCrumbLoading: false,
isBrandLoading: false,
cateId: '0',
take: 10,
skip: 0,
total: 0,
isNext: true,
itemPerPage: 10,
products: [],
breadCrumbs: [],
brand: [],
};

const slice = createSlice({
Expand Down Expand Up @@ -46,6 +50,22 @@ const slice = createSlice({
setTotal(state, action: PayloadAction<number>) {
state.total = action.payload;
},
loadBreadCrumb(state) {
state.isBreadCrumbLoading = true;
state.breadCrumbs = [];
},
breadCrumbLoaded(state, actions: PayloadAction<IBreadCrumb[]>) {
state.isBreadCrumbLoading = false;
state.breadCrumbs = actions.payload;
},
loadingBrand(state) {
state.isBrandLoading = true;
state.brand = [];
},
brandLoaded(state, actions: PayloadAction<IBrand[]>) {
state.isBrandLoading = false;
state.brand = actions.payload;
},
},
});

Expand Down
40 changes: 39 additions & 1 deletion src/app/pages/Category/slice/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { call, put, select, takeLatest } from 'redux-saga/effects';
import { selectCateId, selectSkip, selectTake } from './selector';
import { request } from 'utils/request';
import { BASE_URL } from 'utils/url';
import { createQueryString } from 'utils/string';
import { convertToJSON, createQueryString } from 'utils/string';
import { ProductCateActions } from '.';

export function* getProductCate() {
Expand Down Expand Up @@ -43,7 +43,45 @@ export function* getProductPageCate() {
}
}

export function* getBreadCrumbs() {
try {
const cateId = yield select(selectCateId);

const queryString = createQueryString({ id: cateId, type: 'CATE' });

const data = yield call(request, `${BASE_URL}/breadcrumb?${queryString}`);

if (data.data) {
yield put(ProductCateActions.breadCrumbLoaded(data.data));
} else {
yield put(ProductCateActions.breadCrumbLoaded([]));
}
} catch (error) {
console.log(error);
}
}

export function* getBrand() {
try {
const cateId = yield select(selectCateId);

const queryString = createQueryString({ cateId });

const data = yield call(request, `${BASE_URL}/brand?${queryString}`);

if (data.data) {
yield put(ProductCateActions.brandLoaded(data.data));
} else {
yield put(ProductCateActions.brandLoaded([]));
}
} catch (error) {
console.log(error);
}
}

export function* ProductCateFromSaga() {
yield takeLatest(ProductCateActions.loadProduct, getProductCate);
yield takeLatest(ProductCateActions.loadingPage, getProductPageCate);
yield takeLatest(ProductCateActions.loadBreadCrumb, getBreadCrumbs);
yield takeLatest(ProductCateActions.loadingBrand, getBrand);
}
20 changes: 20 additions & 0 deletions src/app/pages/Category/slice/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,23 @@ export const selectTotal = createSelector(
[(state: RootState) => state.productCateState || initialState],
state => state.total,
);

export const selectBreadCrumb = createSelector(
[(state: RootState) => state.productCateState || initialState],
state => state.breadCrumbs,
);

export const selectBreadCrumbLoading = createSelector(
[(state: RootState) => state.productCateState || initialState],
state => state.isBreadCrumbLoading,
);

export const selectBrand = createSelector(
[(state: RootState) => state.productCateState || initialState],
state => state.brand,
);

export const selectBrandLoading = createSelector(
[(state: RootState) => state.productCateState || initialState],
state => state.isBrandLoading,
);
6 changes: 5 additions & 1 deletion src/app/pages/Category/slice/type.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { ICard } from 'types/Card';
import { IBrand, IBreadCrumb, ICard } from 'types/Card';

export interface ProductCateState {
isLoading: boolean;
isPageLoading: boolean;
isBreadCrumbLoading: boolean;
isBrandLoading: boolean;
cateId: string;
take: number;
skip: number;
total: number;
isNext: boolean;
itemPerPage: number;
products: ICard[];
breadCrumbs: IBreadCrumb[];
brand: IBrand[];
}
10 changes: 10 additions & 0 deletions src/types/Card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ export interface IResultLabel {
type: EResultLabel;
}

export interface IBreadCrumb {
link?: string;
name: string;
}

export interface IBrand {
id: number;
name: string;
}

export interface ICard {
id?: number;
title: string;
Expand Down
4 changes: 4 additions & 0 deletions src/utils/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ export const createQueryString = (

return new URLSearchParams(stringifiedParams).toString();
};

export const convertToJSON = data => {
return JSON.stringify(data);
};

0 comments on commit 03b9a2c

Please sign in to comment.