Skip to content

Commit

Permalink
Merge pull request #85 from daodaoedu/dev
Browse files Browse the repository at this point in the history
merge dev branch to prod
  • Loading branch information
ruby10127130 authored Oct 2, 2024
2 parents 2ba3936 + 948b9a1 commit 1fcabcd
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 48 deletions.
34 changes: 26 additions & 8 deletions components/Group/Form/Fields/TagsField.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useRef } from 'react';
import IconButton from '@mui/material/IconButton';
import FormHelperText from '@mui/material/FormHelperText';
import ClearIcon from '@mui/icons-material/Clear';
Expand All @@ -8,19 +8,20 @@ import { StyledChip, StyledTagsField } from '../Form.styled';
function TagsField({ name, helperText, control, value = [] }) {
const [input, setInput] = useState('');
const [error, setError] = useState('');
const isComposing = useRef(false);

const handleInput = (e) => {
const handleChange = (e) => {
const _value = e.target.value;
if (_value.length > 8) setError('標籤最多 8 個字');
else setError('');
setInput(_value);
};

const handleKeyDown = (e) => {
if (error) return;
const handleAddTag = () => {
const tag = input.trim();
if (e.key !== 'Enter' || !tag) return;
if (value.indexOf(tag) > -1) return;
if (!tag) return;
if (error) return;
if (value.includes(tag)) return;
setInput('');
control.onChange({
target: {
Expand All @@ -30,6 +31,12 @@ function TagsField({ name, helperText, control, value = [] }) {
});
};

const handleKeyDown = (e) => {
if (e.keyCode !== 13) return;
if (isComposing.current) return;
handleAddTag();
};

const handleDelete = (tag) => () => {
control.onChange({
target: {
Expand All @@ -54,12 +61,23 @@ function TagsField({ name, helperText, control, value = [] }) {
{value.length < 8 && (
<input
value={input}
onChange={handleInput}
onCompositionStart={() => {
isComposing.current = true;
}}
onCompositionEnd={() => {
isComposing.current = false;
}}
onChange={handleChange}
onKeyDown={handleKeyDown}
/>
)}
{input.trim() && (
<IconButton sx={{ textTransform: 'none' }} size="small" edge="end">
<IconButton
sx={{ textTransform: 'none' }}
size="small"
edge="end"
onClick={handleAddTag}
>
<AddCircleOutlineIcon />
</IconButton>
)}
Expand Down
71 changes: 71 additions & 0 deletions components/Group/GroupList/SkeletonGroupCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Skeleton } from '@mui/material';
import {
StyledContainer,
StyledFooter,
StyledGroupCard,
StyledInfo,
StyledText,
} from './GroupCard.styled';

function SkeletonGroupCard() {
return (
<StyledGroupCard href="#" sx={{ cursor: 'default' }}>
<Skeleton variant="rounded" width="100%" height={122} animation="wave" />
<StyledContainer>
<Skeleton
variant="text"
width="100%"
fontSize="14px"
animation="wave"
/>
<StyledInfo>
<StyledText>
<Skeleton
variant="text"
width="60%"
fontSize="64px"
animation="wave"
/>
</StyledText>
<StyledText>
<Skeleton
variant="text"
width="52.8%"
fontSize="12px"
animation="wave"
/>
</StyledText>
</StyledInfo>
<StyledText lineClamp="2" fontSize="14px" style={{ minHeight: '28px' }}>
<Skeleton
variant="text"
fontSize="12px"
width="100%"
animation="wave"
/>
<Skeleton
variant="text"
fontSize="12px"
width="100%"
animation="wave"
/>
</StyledText>
<StyledFooter>
<Skeleton
sx={{
height: '32px',
width: '52.8%',
marginLeft: 'auto',
}}
variant="text"
fontSize="12px"
width="27.2%"
animation="wave"
/>
</StyledFooter>
</StyledContainer>
</StyledGroupCard>
);
}

export default SkeletonGroupCard;
21 changes: 20 additions & 1 deletion components/Group/GroupList/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Box } from '@mui/material';
import useSearchParamsManager from '@/hooks/useSearchParamsManager';
import { setQuery } from '@/redux/actions/group';
import GroupCard from './GroupCard';
import SkeletonGroupCard from './SkeletonGroupCard';

export const StyledGroupItem = styled.li`
position: relative;
Expand Down Expand Up @@ -56,7 +57,25 @@ function GroupList() {
return (
<>
<StyledGroupList>
{items?.length || isLoading ? (
{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 =
Expand Down
55 changes: 29 additions & 26 deletions components/Group/detail/OrganizerCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { EDUCATION_STEP, ROLE } from '@/constants/member';
import locationSvg from '@/public/assets/icons/location.svg';
import Chip from '@/shared/components/Chip';
import { timeDuration } from '@/utils/date';
import Link from 'next/link';

const StyledHeader = styled.div`
display: flex;
Expand Down Expand Up @@ -82,33 +83,35 @@ function OrganizerCard({ data = {}, isLoading }) {
return (
<>
<StyledHeader>
<StyledFlex style={{ marginBottom: '10px', gap: 12 }}>
<Avatar
src={data?.user?.photoURL}
alt={`${data?.user?.name} avatar`}
/>
<div>
<StyledFlex style={{ gap: 10 }}>
<StyledText>
{isLoading ? (
<Skeleton width={80} animation="wave" />
) : (
data?.user?.name
)}
<Link href={`/partner/detail?id=${data?.userId}`}>
<StyledFlex style={{ marginBottom: '10px', gap: 12 }}>
<Avatar
src={data?.user?.photoURL}
alt={`${data?.user?.name} avatar`}
/>
<div>
<StyledFlex style={{ gap: 10 }}>
<StyledText>
{isLoading ? (
<Skeleton width={80} animation="wave" />
) : (
data?.user?.name
)}
</StyledText>
<StyledTag>
{isLoading ? (
<Skeleton width={80} animation="wave" />
) : (
educationStage
)}
</StyledTag>
</StyledFlex>
<StyledText style={{ color: '#92989A' }}>
{isLoading ? <Skeleton width={88} animation="wave" /> : role}
</StyledText>
<StyledTag>
{isLoading ? (
<Skeleton width={80} animation="wave" />
) : (
educationStage
)}
</StyledTag>
</StyledFlex>
<StyledText style={{ color: '#92989A' }}>
{isLoading ? <Skeleton width={88} animation="wave" /> : role}
</StyledText>
</div>
</StyledFlex>
</div>
</StyledFlex>
</Link>
<StyledText style={{ alignSelf: 'flex-start', gap: 1 }}>
<img src={locationSvg.src} alt="location icon" />
{isLoading ? <Skeleton width={48} animation="wave" /> : location}
Expand Down
60 changes: 60 additions & 0 deletions components/Group/detail/ShareButtonGroup.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import getShareApi from '@/utils/share';
import styled from '@emotion/styled';
import IconButton from '@mui/material/IconButton';
import {
FaSquareFacebook,
FaLine,
FaLinkedin,
FaSquareThreads,
FaSquareXTwitter,
FaShareFromSquare,
} from 'react-icons/fa6';

const StyledShareButtonGroup = styled.div`
display: flex;
gap: 0.25rem;
align-items: center;
.share-text {
font-size: 14px;
color: #536166;
}
`;

export default function ShareButtonGroup({ title, text, url, hashtag }) {
const {
hasNativeShare,
nativeShare,
facebookShare,
lineShare,
linkedinShare,
threadsShare,
xShare,
} = getShareApi({ title, text, url, hashtag });

return (
<StyledShareButtonGroup>
<span className="share-text">分享至</span>
<IconButton size="small" onClick={facebookShare}>
<FaSquareFacebook fill="#1877F2" />
</IconButton>
<IconButton size="small" onClick={threadsShare}>
<FaSquareThreads fill="#000" />
</IconButton>
<IconButton size="small" onClick={lineShare}>
<FaLine size={16} fill="#00B900" />
</IconButton>
<IconButton size="small" onClick={linkedinShare}>
<FaLinkedin fill="#0A66C2" />
</IconButton>
<IconButton size="small" onClick={xShare}>
<FaSquareXTwitter fill="#000" />
</IconButton>
{hasNativeShare && (
<IconButton size="small" onClick={nativeShare}>
<FaShareFromSquare size={16} />
</IconButton>
)}
</StyledShareButtonGroup>
);
}
33 changes: 20 additions & 13 deletions components/Group/detail/index.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { useRouter } from 'next/navigation';
import { useSelector } from 'react-redux';
import styled from '@emotion/styled';
import Button from '@mui/material/Button';
import Box from '@mui/material/Box';
import Skeleton from '@mui/material/Skeleton';
import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
Expand All @@ -19,6 +17,7 @@ import {
StyledMobileEditButton,
} from './Detail.styled';
import ContactButton from './Contact';
import ShareButtonGroup from './ShareButtonGroup';

function GroupDetail({ id, source, isLoading }) {
const router = useRouter();
Expand All @@ -38,18 +37,26 @@ function GroupDetail({ id, source, isLoading }) {
<Image height="300px" src={source?.photoURL} alt={source?.photoAlt} />
)}
<Box sx={{ position: 'relative', p: '10px' }}>
{isLoading ? (
<Skeleton
variant="rounded"
height={26}
width={68}
animation="wave"
<Box sx={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
{isLoading ? (
<Skeleton
variant="rounded"
height={26}
width={68}
animation="wave"
/>
) : source?.isGrouping ? (
<StyledStatus>揪團中</StyledStatus>
) : (
<StyledStatus className="finished">已結束</StyledStatus>
)}
<ShareButtonGroup
title={source?.title}
text={source?.description}
url={window.location.href}
hashtag={source?.hashtag}
/>
) : source?.isGrouping ? (
<StyledStatus>揪團中</StyledStatus>
) : (
<StyledStatus className="finished">已結束</StyledStatus>
)}
</Box>
{isMyGroup ? (
<StyledDesktopEditButton
variant="outlined"
Expand Down
Loading

0 comments on commit 1fcabcd

Please sign in to comment.