Skip to content

Commit

Permalink
Merge pull request #102 from daodaoedu/dev
Browse files Browse the repository at this point in the history
merge: dev to prod
  • Loading branch information
JohnsonMao authored Oct 13, 2024
2 parents 6fbc3b9 + 218b596 commit cab6a20
Show file tree
Hide file tree
Showing 37 changed files with 1,354 additions and 621 deletions.
8 changes: 7 additions & 1 deletion components/Group/Form/useGroupForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,13 @@ export default function useGroupForm() {
};

useEffect(() => {
if (notLogin) openLoginWindow('/login');
let timer;
if (notLogin) {
timer = setTimeout(() => {
openLoginWindow();
}, 100);
}
return () => clearTimeout(timer);
}, [notLogin]);

return {
Expand Down
7 changes: 5 additions & 2 deletions components/Group/GroupList/GroupCard.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import LocationOnOutlinedIcon from '@mui/icons-material/LocationOnOutlined';
import Image from '@/shared/components/Image';
import emptyCoverImg from '@/public/assets/empty-cover.png';
import { timeDuration } from '@/utils/date';
import emptyCoverWithBackgroundImg from '@/public/assets/empty-cover-with-background.png';
import {
StyledAreas,
StyledContainer,
Expand Down Expand Up @@ -31,7 +31,10 @@ function GroupCard({

return (
<StyledGroupCard href={`/group/detail?id=${_id}`}>
<Image alt={photoAlt || '未放封面'} src={photoURL || emptyCoverImg.src} />
<Image
alt={photoAlt || '未放封面'}
src={photoURL || emptyCoverWithBackgroundImg.src}
/>
<StyledContainer>
<StyledTitle>{title}</StyledTitle>
<StyledInfo>
Expand Down
190 changes: 142 additions & 48 deletions components/Group/GroupList/index.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useEffect, Fragment } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import styled from '@emotion/styled';
import Button from '@mui/material/Button';
import useMediaQuery from '@mui/material/useMediaQuery';
import { Box } from '@mui/material';
import useSearchParamsManager from '@/hooks/useSearchParamsManager';
import { setQuery } from '@/redux/actions/group';
import Image from '@/shared/components/Image';
import emptyCoverImg from '@/public/assets/empty-cover.png';
import errorCoverImg from '@/public/assets/contacterror.png';
import GroupCard from './GroupCard';
import SkeletonGroupCard from './SkeletonGroupCard';

Expand Down Expand Up @@ -41,10 +44,93 @@ const StyledGroupList = styled.ul`
flex-wrap: wrap;
`;

const StyledFullItem = styled.li`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 412px;
.color-gray {
color: #536166;
}
.color-gray-light {
color: #92989a;
}
p {
margin-top: 20px;
}
span {
margin-top: 6px;
font-size: 14px;
}
`;

function shouldRenderDivider(
index,
isLast,
isMobileScreen,
isPadScreen,
isDeskTopScreen,
) {
return (
(isMobileScreen && !isLast) ||
(isPadScreen && !isLast && index % 2 === 1) ||
(isDeskTopScreen && !isLast && index % 3 === 2)
);
}

function GroupItems({ items, isMobileScreen, isPadScreen, isDeskTopScreen }) {
return (
Array.isArray(items) &&
items.map((data, index) => {
const isLast = index === items.length - 1;
return (
<Fragment key={data._id}>
<StyledGroupItem>
<GroupCard {...data} />
</StyledGroupItem>
{shouldRenderDivider(
index,
isLast,
isMobileScreen,
isPadScreen,
isDeskTopScreen,
) && <StyledDivider />}
</Fragment>
);
})
);
}

function SkeletonItems({ isMobileScreen, isPadScreen, isDeskTopScreen }) {
return Array.from({ length: isMobileScreen ? 3 : 6 }, (_, index) => {
const isLast = index === (isMobileScreen ? 2 : 5);
return (
<Fragment key={index}>
<StyledGroupItem>
<SkeletonGroupCard />
</StyledGroupItem>
{shouldRenderDivider(
index,
isLast,
isMobileScreen,
isPadScreen,
isDeskTopScreen,
) && <StyledDivider />}
</Fragment>
);
});
}

function GroupList() {
const dispatch = useDispatch();
const [getSearchParams] = useSearchParamsManager();
const { items, isLoading } = useSelector((state) => state.group);
const { items, isLoading, isError } = useSelector((state) => state.group);

const isMobileScreen = useMediaQuery('(max-width: 560px)');
const isPadScreen = useMediaQuery('(max-width: 767px)') && !isMobileScreen;
Expand All @@ -55,54 +141,62 @@ function GroupList() {
}, [getSearchParams]);

return (
<>
<StyledGroupList>
{isLoading ? (
// always show 3 || 6 skeleton cards in mobile || desktop screen
Array.from({ length: isMobileScreen ? 3 : 6 }, (_, index) => {
const isLast = index === (isMobileScreen ? 2 : 5);
const shouldRenderDivider =
(isMobileScreen && !isLast) ||
(isPadScreen && !isLast && index % 2 === 1) ||
(isDeskTopScreen && !isLast && index % 3 === 2);

return (
<Fragment key={index}>
<StyledGroupItem>
<SkeletonGroupCard />
</StyledGroupItem>
{shouldRenderDivider && <StyledDivider />}
</Fragment>
);
})
) : items?.length ? (
items.map((data, index) => {
const isLast = index === items.length - 1;
const shouldRenderDivider =
(isMobileScreen && !isLast) ||
(isPadScreen && !isLast && index % 2 === 1) ||
(isDeskTopScreen && !isLast && index % 3 === 2);

return (
<Fragment key={data._id}>
<StyledGroupItem>
<GroupCard {...data} />
</StyledGroupItem>
{shouldRenderDivider && <StyledDivider />}
</Fragment>
);
})
) : (
<li style={{ textAlign: 'center', width: '100%' }}>
哎呀!這裡好像沒有符合你條件的揪團,別失望!讓我們試試其他選項。
</li>
)}
</StyledGroupList>

<StyledGroupList>
<GroupItems
items={items}
isMobileScreen={isMobileScreen}
isPadScreen={isPadScreen}
isDeskTopScreen={isDeskTopScreen}
/>
{isLoading && (
<Box sx={{ textAlign: 'center', paddingTop: '32px' }}>搜尋揪團中~</Box>
<SkeletonItems
isMobileScreen={isMobileScreen}
isPadScreen={isPadScreen}
isDeskTopScreen={isDeskTopScreen}
/>
)}
{isError ? (
<StyledFullItem>
<Image
alt="異常錯誤"
src={errorCoverImg.src}
width={160}
height={142}
/>
<p className="color-gray-light">哎呀!有不明錯誤</p>
<Button
variant="outlined"
sx={{
marginTop: '20px',
fontSize: '16px',
color: '#536166',
borderColor: '#16B9B3',
borderRadius: '20px',
padding: '6px 48px',
}}
onClick={() => dispatch(setQuery(getSearchParams()))}
>
重新載入
</Button>
</StyledFullItem>
) : (
!isLoading &&
items.length === 0 && (
<StyledFullItem>
<Image
alt="查無資料"
src={emptyCoverImg.src}
width={160}
height={120}
/>
<p className="color-gray">哎呀!這裡沒有符合條件的揪團</p>
<span className="color-gray-light">
試著更改條件或搜尋其他關鍵字吧
</span>
</StyledFullItem>
)
)}
</>
</StyledGroupList>
);
}

Expand Down
4 changes: 1 addition & 3 deletions components/Group/More.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function More() {
<Box
sx={{ textAlign: 'center', paddingTop: '80px', paddingBottom: '100px' }}
>
{isMore ? (
{isMore && (
<Button
variant="outlined"
sx={{
Expand All @@ -26,8 +26,6 @@ export default function More() {
>
顯示更多
</Button>
) : (
'已經到底囉~'
)}
</Box>
);
Expand Down
6 changes: 3 additions & 3 deletions components/Group/SearchField/SearchInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const SearchInput = () => {
const [getSearchParams, pushState] = useSearchParamsManager();
const [keyword, setKeyword] = useState('');
const [isSpeechMode, setIsSpeechMode] = useState(false);
const currentKeyword = getSearchParams('q').toString();
const currentKeyword = getSearchParams('search').toString();

useEffect(() => {
setKeyword(currentKeyword);
Expand All @@ -67,15 +67,15 @@ const SearchInput = () => {
/** @type {(event: SubmitEvent) => void} */
const handleSubmit = (event) => {
event.preventDefault();
pushState('q', keyword);
pushState('search', keyword);
};

return (
<SearchInputWrapper as="form" onSubmit={handleSubmit}>
<InputBaseWrapper
type="search"
inputProps={{ 'aria-label': 'search group' }}
name="q"
name="search"
value={keyword}
placeholder="想尋找甚麼類型的揪團呢?"
onChange={handleChange}
Expand Down
Loading

0 comments on commit cab6a20

Please sign in to comment.