Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/#1707 main #1720

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
236 changes: 136 additions & 100 deletions src/components/projects/main/ProjectList.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import styled from '@emotion/styled';
import { colors } from '@sopt-makers/colors';
import { fonts } from '@sopt-makers/fonts';
import { IconPlus } from '@sopt-makers/icons';
import { Button, Chip, SearchField, SelectV2 } from '@sopt-makers/ui';
import { Flex, width100 } from '@toss/emotion-utils';
import { ImpressionArea } from '@toss/impression-area';
import { useDebounce } from '@toss/react';
import { uniqBy as _uniqBy } from 'lodash-es';
import Link from 'next/link';
import React, { useMemo, useState } from 'react';
import React, { useState } from 'react';
import { BooleanParam, createEnumParam, StringParam, useQueryParams, withDefault } from 'use-query-params';

import BottomSheetSelect from '@/components/coffeechat/upload/CoffeechatForm/BottomSheetSelect';
import EmptyView from '@/components/common/EmptyView';
import Loading from '@/components/common/Loading';
import Responsive from '@/components/common/Responsive';
import Text from '@/components/common/Text';
import MobileProjectCard from '@/components/projects/main/card/MobileProjectCard';
import ProjectCard from '@/components/projects/main/card/ProjectCard';
import ProjectCategorySelect from '@/components/projects/main/ProjectCategorySelect';
import ProjectFilterChip from '@/components/projects/main/ProjectFilterChip';
import ProjectSearch from '@/components/projects/main/ProjectSearch';
import useGetProjectListQuery from '@/components/projects/upload/hooks/useGetProjectListQuery';
import { playgroundLink } from '@/constants/links';
import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery';
Expand All @@ -32,6 +31,15 @@ const PROJECT_CATEGORY_LIST: Array<{ value: ProjectCategory; label: string }> =
{ value: 'ETC', label: '์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ' },
];

const PROJECT_CATEGORY_LIST_MOBILE: Array<{ value: string; queryValue: ProjectCategory | null; label: string }> = [
{ queryValue: null, value: '', label: '์ „์ฒด' },
{ queryValue: 'APPJAM', value: '์•ฑ์žผ', label: '์•ฑ์žผ' },
{ queryValue: 'SOPKATHON', value: '์†์ปคํ†ค', label: '์†์ปคํ†ค' },
{ queryValue: 'SOPTERM', value: '์†ํ…€ ํ”„๋กœ์ ํŠธ', label: '์†ํ…€ ํ”„๋กœ์ ํŠธ' },
{ queryValue: 'STUDY', value: '์Šคํ„ฐ๋””', label: '์Šคํ„ฐ๋””' },
{ queryValue: 'ETC', value: '์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ', label: '์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ' },
];

const ProjectList = () => {
const [queryParams, setQueryParams] = useQueryParams({
name: withDefault(StringParam, null),
Expand All @@ -48,92 +56,112 @@ const ProjectList = () => {
isFounding: queryParams.isFounding,
category: queryParams.category,
});

const totalCount = data?.pages && data.pages[0].totalCount;

return (
<StyledContainer>
<StyledContent>
<ProjectSearch
<SearchField
value={value ?? ''}
onValueChange={(value) => {
onChange={(e) => {
const value = e.target.value;
setValue(value);
debouncedChangeName(value === '' ? null : value);
}}
placeholder='ํ”„๋กœ์ ํŠธ ๊ฒ€์ƒ‰'
onSubmit={() => {
//
}}
onReset={() => {
setValue('');
debouncedChangeName(null);
}}
placeholder='์„œ๋น„์Šค ์ด๋ฆ„์„ ๊ฒ€์ƒ‰ํ•ด๋ณด์„ธ์š”!'
/>
{isLoading ? (
<LoadingContainer>
<Loading />
</LoadingContainer>
) : (
<LengthWrapper>
<StyledLength typography='SUIT_18_M'>์ „์ฒด {totalCount}๊ฐœ</StyledLength>
<>
<Responsive only='desktop'>
<Flex css={{ gap: 6 }} align='center'>
<ProjectFilterChip
checked={queryParams.isAvailable ?? false}
onCheckedChange={(checked) => setQueryParams({ isAvailable: checked || null })}
>
์ด์šฉ ๊ฐ€๋Šฅํ•œ ์„œ๋น„์Šค
</ProjectFilterChip>
<ProjectFilterChip
checked={queryParams.isFounding ?? false}
onCheckedChange={(checked) => setQueryParams({ isFounding: checked || null })}
>
์ฐฝ์—… ์ค‘
</ProjectFilterChip>
<ProjectCategorySelect
css={{ marginLeft: 10 }}
placeholder='ํ”„๋กœ์ ํŠธ ์ „์ฒด'
allowClear
onClear={() => setQueryParams({ category: null })}
value={queryParams.category ?? undefined}
onValueChange={(value) => setQueryParams({ category: value as ProjectCategory })}
>
{PROJECT_CATEGORY_LIST.map(({ label, value }) => (
<ProjectCategorySelect.Item key={value} value={value}>
{label}
</ProjectCategorySelect.Item>
))}
</ProjectCategorySelect>
</Flex>
<LengthWrapper>
<StyledLength typography='SUIT_18_M'>์ „์ฒด {totalCount}๊ฐœ</StyledLength>
<Flex css={{ gap: 8 }} align='center'>
<div onClick={() => setQueryParams({ isAvailable: !queryParams.isAvailable || null })}>
<Chip size='md' active={queryParams.isAvailable ?? false}>
์ด์šฉ ๊ฐ€๋Šฅํ•œ ์„œ๋น„์Šค
</Chip>
</div>
<div onClick={() => setQueryParams({ isFounding: !queryParams.isFounding || null })}>
<Chip size='md' active={queryParams.isFounding ?? false}>
์ฐฝ์—… ์ค‘
</Chip>
</div>
<CategorySelect
type='text'
visibleOptions={5}
defaultValue={PROJECT_CATEGORY_LIST.find((option) => option.value === queryParams.category)}
onChange={(value) => setQueryParams({ category: value as ProjectCategory })}
>
<SelectV2.Trigger>
<SelectV2.TriggerContent placeholder={'ํ”„๋กœ์ ํŠธ ์ข…๋ฅ˜'} />
</SelectV2.Trigger>
<SelectV2.Menu>
{PROJECT_CATEGORY_LIST.map((option) => (
<SelectV2.MenuItem key={option.value} option={option} className='menu' />
))}
</SelectV2.Menu>
</CategorySelect>
</Flex>
</LengthWrapper>
</Responsive>
<Responsive only='mobile' css={width100}>
<Flex css={{ marginTop: 4.5, padding: '8px 0' }} justify='space-between' align='center'>
<Flex css={{ gap: 6 }}>
<ProjectFilterChip
size='small'
checked={queryParams.isAvailable ?? false}
onCheckedChange={(checked) => setQueryParams({ isAvailable: checked })}
>
์ด์šฉ ๊ฐ€๋Šฅํ•œ ์„œ๋น„์Šค
</ProjectFilterChip>
<ProjectFilterChip
size='small'
checked={queryParams.isFounding ?? false}
onCheckedChange={(checked) => setQueryParams({ isFounding: checked })}
>
์ฐฝ์—… ์ค‘
</ProjectFilterChip>
<LengthWrapper>
<Flex css={{ marginBottom: '14px', width: '100%' }} justify='space-between' align='center'>
<Flex css={{ gap: 8 }}>
<div onClick={() => setQueryParams({ isAvailable: !queryParams.isAvailable || null })}>
<Chip size='sm' active={queryParams.isAvailable ?? false} style={{ minWidth: 'max-content' }}>
์ด์šฉ ๊ฐ€๋Šฅํ•œ ์„œ๋น„์Šค
</Chip>
</div>
<div
onClick={() => setQueryParams({ isFounding: !queryParams.isFounding || null })}
style={{ minWidth: 'max-content' }}
>
<Chip size='sm' active={queryParams.isFounding ?? false}>
์ฐฝ์—… ์ค‘
</Chip>
</div>
</Flex>
<CategorySelectBottomSheet>
<BottomSheetSelect
options={[
...PROJECT_CATEGORY_LIST_MOBILE.map(({ value, label }) => ({
value,
label,
})),
]}
value={
(queryParams.category &&
PROJECT_CATEGORY_LIST_MOBILE.find((option) => option.queryValue === queryParams.category) &&
PROJECT_CATEGORY_LIST_MOBILE.find((option) => option.queryValue === queryParams.category)
?.label) ??
''
}
placeholder='ํ”„๋กœ์ ํŠธ ์ข…๋ฅ˜'
onChange={(value) =>
setQueryParams({
category: PROJECT_CATEGORY_LIST_MOBILE.find((option) => option.value === value)
?.queryValue as ProjectCategory,
})
}
/>
</CategorySelectBottomSheet>
</Flex>
<ProjectCategorySelect
placeholder='ํ”„๋กœ์ ํŠธ ์ „์ฒด'
size='small'
allowClear
onClear={() => setQueryParams({ category: null })}
value={queryParams.category ?? undefined}
onValueChange={(value) => setQueryParams({ category: value as ProjectCategory })}
>
{PROJECT_CATEGORY_LIST.map(({ label, value }) => (
<ProjectCategorySelect.Item key={value} value={value}>
{label}
</ProjectCategorySelect.Item>
))}
</ProjectCategorySelect>
</Flex>
<StyledLength typography='SUIT_18_M'>์ „์ฒด {totalCount}๊ฐœ</StyledLength>
</LengthWrapper>
</Responsive>
</LengthWrapper>
</>
)}

{totalCount === 0 ? (
Expand Down Expand Up @@ -186,15 +214,44 @@ const ProjectList = () => {
)}
</StyledContent>
<ProjectUploadButton href={playgroundLink.projectUpload()}>
<PlusIcon />
ํ”„๋กœ์ ํŠธ ์˜ฌ๋ฆฌ๊ธฐ
<Responsive only='desktop'>
<Button size='lg' LeftIcon={IconPlus}>
ํ”„๋กœ์ ํŠธ ์˜ฌ๋ฆฌ๊ธฐ
</Button>
</Responsive>
<Responsive only='mobile'>
<Button size='md' LeftIcon={IconPlus}>
ํ”„๋กœ์ ํŠธ ์˜ฌ๋ฆฌ๊ธฐ
</Button>
</Responsive>
</ProjectUploadButton>
</StyledContainer>
);
};

export default ProjectList;

const CategorySelectBottomSheet = styled.div`
position: fixed;
left: 20px;
z-index: 110;
width: 150px;

> div > div {
position: fixed;
top: 133px;
right: 20px;
}
`;

const CategorySelect = styled(SelectV2.Root)`
margin-left: 8px;

> button > div > p {
min-width: max-content;
}
`;

const StyledContainer = styled.div`
display: flex;
align-items: center;
Expand All @@ -207,6 +264,7 @@ const CONTAINER_MAX_WIDTH = 1480;
const StyledContent = styled.div`
justify-self: flex-start;
margin: 64px 0;
padding: 0 24px;
min-width: ${CONTAINER_MAX_WIDTH}px;

@media screen and (max-width: ${CONTAINER_MAX_WIDTH}px) {
Expand All @@ -220,7 +278,7 @@ const StyledContent = styled.div`
@media ${MOBILE_MEDIA_QUERY} {
gap: 12px;
margin: 0;
padding: 12px 10px;
padding: 12px 20px;
width: 100%;
min-width: 352px;
}
Expand All @@ -229,37 +287,15 @@ const StyledContent = styled.div`
const ProjectUploadButton = styled(Link)`
display: flex;
position: fixed;
right: 60px;
right: 100px;
bottom: 80px;
gap: 8px;
align-items: center;
border-radius: 18px;
background-color: ${colors.gray10};
padding: 14px 30px 14px 27px;
color: ${colors.gray950};
${fonts.TITLE_20_SB};

&:hover {
background-color: ${colors.gray50};
}

@media ${MOBILE_MEDIA_QUERY} {
right: 16px;
bottom: 16px;
padding: 12px;
${fonts.LABEL_16_SB}
right: 20px;
bottom: 42px;
}
`;

const PlusIcon = () => (
<svg width='20' height='20' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path
d='M10.9208 2.58751C10.9208 2.07966 10.5091 1.66797 10.0013 1.66797C9.49345 1.66797 9.08176 2.07966 9.08176 2.58751V9.08176H2.58751C2.07966 9.08176 1.66797 9.49345 1.66797 10.0013C1.66797 10.5091 2.07966 10.9208 2.58751 10.9208H9.08176V17.4151C9.08176 17.9229 9.49345 18.3346 10.0013 18.3346C10.5091 18.3346 10.9208 17.9229 10.9208 17.4151V10.9208H17.4151C17.9229 10.9208 18.3346 10.5091 18.3346 10.0013C18.3346 9.49345 17.9229 9.08176 17.4151 9.08176H10.9208V2.58751Z'
fill='#0F0F12'
/>
</svg>
);

const LengthWrapper = styled.div`
display: flex;
align-items: center;
Expand All @@ -270,7 +306,7 @@ const LengthWrapper = styled.div`
@media ${MOBILE_MEDIA_QUERY} {
flex-direction: column;
align-items: flex-start;
margin-top: 18.5px;
margin: 22px 0;
}
`;

Expand Down
Loading