From 9991c64d0902393f9a3a7834232fa397a8594a24 Mon Sep 17 00:00:00 2001 From: hsuifang Date: Wed, 27 Dec 2023 21:07:40 +0800 Subject: [PATCH] feat(partner): Deal with Fetching Search Partners results --- components/Partner/Parnter.styled.jsx | 3 +- .../Partner/PartnerList/PartnerCard/index.jsx | 1 - components/Partner/PartnerList/index.jsx | 26 +++--- components/Partner/SearchParamsList/index.jsx | 17 ++-- components/Partner/index.jsx | 90 ++++++++++++++++--- hooks/useSearchParamsManager.jsx | 17 +++- redux/actions/partners.js | 9 +- redux/reducers/partners.js | 21 ++++- redux/sagas/partnersSaga.js | 35 ++++++-- 9 files changed, 168 insertions(+), 51 deletions(-) diff --git a/components/Partner/Parnter.styled.jsx b/components/Partner/Parnter.styled.jsx index 7ea799b2..5f50432d 100644 --- a/components/Partner/Parnter.styled.jsx +++ b/components/Partner/Parnter.styled.jsx @@ -4,13 +4,14 @@ import { Box } from '@mui/material'; export const StyledWrapper = styled.div` position: relative; margin: 70px auto 0; + padding-bottom: 14px; width: 100%; max-width: 1024px; min-height: 100vh; margin-top: -80px; @media (max-width: 900px) { - padding: 0 16px; + padding: 0 16px 44px; margin-top: -50px; } `; diff --git a/components/Partner/PartnerList/PartnerCard/index.jsx b/components/Partner/PartnerList/PartnerCard/index.jsx index e9c1e5ad..1f1ee828 100644 --- a/components/Partner/PartnerList/PartnerCard/index.jsx +++ b/components/Partner/PartnerList/PartnerCard/index.jsx @@ -44,7 +44,6 @@ function PartnerCard({ return ( - {/* TODO: href redirect */} diff --git a/components/Partner/PartnerList/index.jsx b/components/Partner/PartnerList/index.jsx index 2fc0cf10..fc3a15d5 100644 --- a/components/Partner/PartnerList/index.jsx +++ b/components/Partner/PartnerList/index.jsx @@ -1,22 +1,14 @@ -import { useEffect, Fragment } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { fetchAllPartners } from '@/redux/actions/partners'; +import { Fragment } from 'react'; +import { useRouter } from 'next/router'; +import { useSelector } from 'react-redux'; import useMediaQuery from '@mui/material/useMediaQuery'; import { Grid, Box } from '@mui/material'; import PartnerCard from './PartnerCard'; function PartnerList() { - const partners = useSelector((state) => state.partners); - const dispatch = useDispatch(); - - // TODO: ADD PAGE - const handleFetchData = () => { - dispatch(fetchAllPartners()); - }; + const router = useRouter(); - useEffect(() => { - handleFetchData(); - }, []); + const partners = useSelector((state) => state.partners); const lists = partners.items || []; const mobileScreen = useMediaQuery('(max-width: 900px)'); @@ -34,7 +26,13 @@ function PartnerList() { > {lists.map((item, idx) => ( - + router.push(`partner/${item._id}`)} + item + width="100%" + md={6} + mb={mobileScreen && '12px'} + > { - const [getSearchParams, pushState] = useSearchParamsManager(); +const SearchParamsList = ({ paramsKey = [], paramsKeyOptions = {} }) => { + const [getSearchParams, pushState, genParamsItems] = useSearchParamsManager(); - const handleGenerateParams = (params) => { - return params.reduce((acc, param) => { - const values = getSearchParams(param).filter((value) => - keySelections[param]?.includes(value), - ); - return [...acc, { key: param, values }]; - }, []); - }; const params = useMemo( - () => (Array.isArray(paramsKey) ? handleGenerateParams(paramsKey) : []), + () => + Array.isArray(paramsKey) + ? genParamsItems(paramsKey, paramsKeyOptions) + : [], [getSearchParams], ); diff --git a/components/Partner/index.jsx b/components/Partner/index.jsx index 3747dfee..34fbd87a 100644 --- a/components/Partner/index.jsx +++ b/components/Partner/index.jsx @@ -1,8 +1,13 @@ -import { useSelector } from 'react-redux'; +import { useEffect, useMemo } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import { Box, Button } from '@mui/material'; import useMediaQuery from '@mui/material/useMediaQuery'; import { AREAS } from '@/constants/areas'; +import { fetchPartners } from '@/redux/actions/partners'; import { EDUCATION_STEP, ROLE } from '@/constants/member'; +import { SEARCH_TAGS } from '@/constants/category'; +import useSearchParamsManager from '@/hooks/useSearchParamsManager'; + import PartnerList from './PartnerList'; import SearchField from './SearchField'; import SearchParamsList from './SearchParamsList'; @@ -13,11 +18,79 @@ import { StyledSearchWrapper, } from './Parnter.styled'; +// utils +const _compose = + (...fns) => + (x) => + fns.reduceRight((v, f) => f(v), x); const _map = (arr, key) => arr.map((item) => item[key]); +const mapValues = (values, mapFn) => values.map(mapFn).join(','); + +const createObjFromArrary = (arr, keyProp = 'label', valueProp = 'label') => { + return arr.reduce( + (obj, item) => ({ + ...obj, + [item[keyProp]]: item[valueProp], + }), + {}, + ); +}; + +// constants +const keySelections = { + area: _map(AREAS, 'name'), + edu: _map(EDUCATION_STEP, 'label'), + role: _map(ROLE, 'label'), + tag: SEARCH_TAGS['全部'], + q: 'PASS_STRING', +}; + +const eduObj = createObjFromArrary(EDUCATION_STEP); +const roleObj = createObjFromArrary(ROLE); function Partner() { + const dispatch = useDispatch(); const mobileScreen = useMediaQuery('(max-width: 767px)'); + + // main data const partners = useSelector((state) => state.partners); + const { page: current = 1, totalPages } = partners.pagination; + + // queryStr + const [getSearchParams, _, generateParamsItems] = useSearchParamsManager(); + const searchParamsItems = useMemo( + () => + generateParamsItems(['area', 'role', 'edu', 'tag', 'q'], keySelections), + [getSearchParams], + ); + + // fetch api - params + const findValues = (params, key) => + params.find((item) => item.key === key)?.values; + const prepareData = _compose( + ([location, educationStage, roleList, tag, search]) => ({ + location, + educationStage, + roleList, + tag, + search, + }), + (arg) => [ + findValues(arg, 'area').join(','), + mapValues(findValues(arg, 'edu'), (item) => eduObj[item]), + mapValues(findValues(arg, 'role'), (item) => roleObj[item]), + findValues(arg, 'tag').join(','), + findValues(arg, 'q').join(','), + ], + ); + + const handleFetchData = (page = 1) => { + dispatch(fetchPartners({ page, ...prepareData(searchParamsItems) })); + }; + + useEffect(() => { + handleFetchData(); + }, [getSearchParams]); return ( <> @@ -28,24 +101,21 @@ function Partner() { - {partners.items.length > 0 && ( + {partners.items.length > 0 && current < totalPages && (