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

[FE] 🚧 μ™„λ£Œ μƒνƒœ νŽ˜μ–΄λ£Έ 1μ°¨ κ΅¬ν˜„ #820

Merged
merged 14 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
40370fa
✨ μ™„λ£Œ μƒνƒœμ˜ νŽ˜μ–΄ λ£Έ κ΅¬ν˜„
greetings1012 Oct 16, 2024
973721f
✨ νŽ˜μ–΄λ£Έ μ’…λ£Œ λ²„νŠΌ 볡원
greetings1012 Oct 17, 2024
063bae1
✨ Sse 톡신을 ν†΅ν•œ νŽ˜μ–΄λ£Έ μ’…λ£Œ 둜직 κ΅¬ν˜„
greetings1012 Oct 17, 2024
6f3eae2
πŸ’„ νŽ˜μ–΄λ£Έ μ™„λ£Œ νŽ˜μ΄μ§€ λ””μžμΈ κ°œμ„ 
greetings1012 Oct 17, 2024
0fd6f19
♻️ μ™„λ£Œλœ μƒνƒœμ—μ„œλŠ” μΉ΄ν…Œκ³ λ¦¬ μˆ˜μ •μ΄ λΆˆκ°€ν•˜λ„λ‘ μ½”λ“œ λ³€κ²½
greetings1012 Oct 17, 2024
263cc64
πŸ’„ μŠ€νƒ€μΌ λ³€μˆ˜λͺ… μˆ˜μ •
greetings1012 Oct 17, 2024
763aabd
♻️ UpdatePairRoomStatus μ—λŸ¬ λ©”μ‹œμ§€ μƒμˆ˜ν™” 및 μ‚¬μš©
greetings1012 Oct 17, 2024
b3b8039
🚚 νŽ˜μ–΄λ£Έ μ™„λ£Œ λ²„νŠΌ 이름 λ³€κ²½
greetings1012 Oct 17, 2024
bc29475
🎨 App.tsxμ—μ„œ CompletedPairRoom의 Suspense 제거
greetings1012 Oct 17, 2024
768c13f
♻️ ν•„μš”μ—†λŠ” 쀑간 μ»΄ν¬λ„ŒνŠΈ μ‚­μ œ
greetings1012 Oct 18, 2024
484fad0
♻️ ν•„μš” μ—†λŠ” ReadOnlyCategoryItem μ‚­μ œ
greetings1012 Oct 18, 2024
8364f16
♻️ ν•„μš”μ—†λŠ” λ³€μˆ˜λͺ… μˆ˜μ •
greetings1012 Oct 18, 2024
a220e54
♻️ λ³€μˆ˜ ν• λ‹Ή λŒ€μ‹  속성 μΆ”μΆœ 방식 μ‚¬μš©
greetings1012 Oct 18, 2024
4fe6aac
🎨 ν•„μš”μ—†λŠ” 폴더 제거
greetings1012 Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Callback from '@/pages/Callback/Callback';
import CoduoDocs from '@/pages/CoduoDocs/CoduoDocs';
import CompletedPairRoom from '@/pages/CompletedPairRoom/CompletedPairRoom';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ»΄ν¬λ„ŒνŠΈ 이름 μ§„μ§œ μŠ€κ»„ν•˜λ„€μš” 😭

import Error from '@/pages/Error/Error';
import Landing from '@/pages/Landing/Landing';
import Layout from '@/pages/Layout';
Expand Down Expand Up @@ -47,7 +48,7 @@

useEffect(() => {
if (window.location.pathname !== '/callback') updateUser();
}, []);

Check warning on line 51 in frontend/src/App.tsx

View workflow job for this annotation

GitHub Actions / test-and-lint

React Hook useEffect has a missing dependency: 'updateUser'. Either include it or remove the dependency array

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -83,6 +84,10 @@
</Suspense>
),
},
{
path: 'room/:accessCode/completed',
element: <CompletedPairRoom />,
},
{
path: 'sign-up',
element: <SignUp />,
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/apis/pairRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ export const updatePairRole = async ({ accessCode }: UpdatePairRoleRequest) => {
});
};

interface UpdatePairRoomStatusRequest {
accessCode: string;
}

export const updatePairRoomStatus = async ({ accessCode }: UpdatePairRoomStatusRequest) => {
await fetcher.patch({
url: `${API_URL}/pair-room/${accessCode}/complete`,
errorMessage: ERROR_MESSAGES.UPDATE_PAIR_ROOM_STATUS,
});
};

export const deletePairRoom = async (accessCode: string) => {
await fetcher.delete({
url: `${API_URL}/pair-room/${accessCode}`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import styled from 'styled-components';

export const Layout = styled.div`
display: flex;
justify-content: space-between;
gap: 1rem;

width: 100%;
`;

export const Container = styled.div`
display: flex;
flex-direction: column;
gap: 0.3rem;

width: 100%;
height: 6rem;

cursor: pointer;

img {
width: 2rem;
}
`;

export const ItemLayout = styled.div`
display: flex;
align-items: center;
gap: 1rem;

width: 100%;
`;

export const Item = styled.li<{ $isChecked: boolean }>`
display: flex;
justify-content: space-between;
align-items: center;

width: 100%;
height: 4.4rem;
padding: 0 1rem;
border: 1px solid ${({ theme }) => theme.color.black[50]};
border-radius: 0.5rem;

background-color: ${({ theme, $isChecked }) => ($isChecked ? theme.color.primary[700] : theme.color.black[10])};
color: ${({ theme, $isChecked }) => ($isChecked ? theme.color.black[10] : theme.color.black[70])};
font-size: ${({ theme }) => theme.fontSize.md};

transition: all 0.2s ease-out;

&:hover {
background-color: ${({ theme }) => theme.color.primary[700]};
color: ${({ theme }) => theme.color.black[10]};
}

&:active {
background-color: ${({ theme }) => theme.color.primary[800]};
color: ${({ theme }) => theme.color.black[10]};
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { CheckBoxChecked, CheckBoxUnchecked } from '@/assets';

import * as S from './CategoryItem.styles';

interface CategoryItemProps {
categoryName: string;
categoryId: string;
isChecked: boolean;
closeModal: () => void;
handleSelectCategory: (categoryId: string) => void;
}

const CategoryItem = ({ closeModal, categoryName, categoryId, isChecked, handleSelectCategory }: CategoryItemProps) => {
Copy link
Contributor

@anttiey anttiey Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ν˜Ήμ‹œ μ΄λ ‡κ²Œ ReferenceCard μ•ˆμ— CategoryManagementModal μ•ˆμ— CategoriesEditor μ•ˆμ— CategoryItem 이 μžˆλŠ” μ΄μœ κ°€ μžˆλ‚˜μš”? μ»΄ν¬λ„ŒνŠΈ κ²½λ‘œκ°€ λ„ˆλ¬΄ κΈΈμ–΄μ§€λŠ” κ±° κ°™μ•„μ„œμš” πŸ€”

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

κΈ‰ν•˜κ²Œ μ›λž˜ 파일 ꡬ쑰 κ·ΈλŒ€λ‘œ λ”°μ˜€λŠλΌ ν•„μš”μ—†λŠ” ꡬ쑰가 μƒκ²Όλ„€μš”!
CategoriesEditor 단계λ₯Ό μ‚­μ œν–ˆμŠ΅λ‹ˆλ‹€ πŸ‘

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크란샷 2024-10-18 α„‹α…©α„Œα…₯ᆫ 10 55 46

폴더 ꡬ쑰가 μ΄λ ‡κ²Œ λ³΄μ΄λŠ”λ° μ•ˆμ— CategoryItem 만 μžˆμ–΄μ„œ ν˜Ήμ‹œ μƒμœ„μ— CategoriesEditor 폴더가 μžˆλŠ” κ±°λ©΄ μ œκ±°ν•˜κ³  CategoryItem ν΄λ”λ§Œ 남겨도 될 κ±° κ°™λ„€μš”!

return (
<S.Layout>
<S.Container>
<S.ItemLayout
id={categoryId}
onClick={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
if (event.currentTarget.id === 'μΉ΄ν…Œκ³ λ¦¬') return;
if (isChecked) return;
handleSelectCategory(event.currentTarget.id);
closeModal();
}}
>
<img
src={isChecked ? CheckBoxChecked : CheckBoxUnchecked}
alt={isChecked ? '체크된 μ²΄ν¬λ°•μŠ€' : 'μ²΄ν¬λ˜μ§€ μ•Šμ€ μ²΄ν¬λ°•μŠ€'}
/>

<S.Item $isChecked={isChecked}>
<p>{categoryName}</p>
</S.Item>
</S.ItemLayout>
</S.Container>
</S.Layout>
);
};

export default CategoryItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import styled, { css } from 'styled-components';

export const inputStyles = css`
width: 100%;

font-size: ${({ theme }) => theme.fontSize.md};
`;

export const Header = styled.div`
display: flex;
align-items: center;
gap: 1rem;

color: ${({ theme }) => theme.color.black[80]};
font-size: ${({ theme }) => theme.fontSize.lg};
`;

export const CategoryList = styled.ul`
display: flex;
flex-direction: column-reverse;
gap: 1rem;

width: 100%;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { FaFilter } from 'react-icons/fa';

import { Modal } from '@/components/common/Modal';
import CategoryItem from '@/components/CompletedPairRoom/ReferenceCard/CategoryManagementModal/CategoriesEditor/CategoryItem/CategoryItem';
import { Category } from '@/components/PairRoom/ReferenceCard/ReferenceCard.type';

import * as S from './CategoryManagementModal.styles';

interface CategoryManagementModalProps {
isOpen: boolean;
closeModal: () => void;
categories: Category[];
isCategoryExist: (categoryName: string) => boolean;
selectedCategory: string;
handleSelectCategory: (categoryId: string) => void;
}

const CategoryManagementModal = ({
isOpen,
closeModal,
categories,
selectedCategory,
handleSelectCategory,
}: CategoryManagementModalProps) => {
return (
<Modal isOpen={isOpen} close={closeModal} size="45rem">
<Modal.Header>
<S.Header>
<FaFilter />
<p>μΉ΄ν…Œκ³ λ¦¬ 선택</p>
</S.Header>
</Modal.Header>
<Modal.CloseButton close={closeModal} />
<Modal.Body>
<S.CategoryList>
{categories.map((category) => (
<CategoryItem
closeModal={closeModal}
key={category.id}
categoryName={category.value}
categoryId={category.id}
isChecked={category.id === selectedCategory}
handleSelectCategory={handleSelectCategory}
/>
))}
</S.CategoryList>
</Modal.Body>
</Modal>
);
};

export default CategoryManagementModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import styled, { css } from 'styled-components';

export const buttonStyles = css`
width: fit-content;
min-width: 6rem;
padding: 0 1rem;
`;

export const Layout = styled.div`
display: flex;
justify-content: space-between;
align-items: center;

width: 100%;
height: 6rem;
padding: 2rem;

font-size: ${({ theme }) => theme.fontSize.lg};
`;

export const Container = styled.div`
display: flex;
align-items: center;
gap: 0.8rem;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { IoIosLink } from 'react-icons/io';

import Button from '@/components/common/Button/Button';

import { theme } from '@/styles/theme';

import * as S from './Header.styles';

interface HeaderProps {
selectedFilteringCategoryName: string;
onButtonClick: () => void;
}

const Header = ({ selectedFilteringCategoryName, onButtonClick }: React.PropsWithChildren<HeaderProps>) => {
return (
<S.Layout>
<S.Container>
<IoIosLink size={theme.fontSize.h6} color={theme.color.primary[600]} />
<p>링크</p>
</S.Container>
<Button
css={S.buttonStyles}
size="sm"
rounded={true}
onClick={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
event.stopPropagation();
onButtonClick();
}}
>
{selectedFilteringCategoryName}
</Button>
</S.Layout>
);
};

export default Header;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import styled from 'styled-components';

export const Layout = styled.div`
min-width: 49rem;
`;

export const Body = styled.div`
display: flex;
flex-direction: column;
overflow: hidden;
height: calc(100vh - 20rem);
border-top: 1px solid ${({ theme }) => theme.color.black[30]};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useState } from 'react';

import CategoryManagementModal from '@/components/CompletedPairRoom/ReferenceCard/CategoryManagementModal/CategoryManagementModal';
import Header from '@/components/CompletedPairRoom/ReferenceCard/Header/Header';
import ReferenceList from '@/components/CompletedPairRoom/ReferenceCard/ReferenceList/ReferenceList';
import { PairRoomCard } from '@/components/PairRoom/PairRoomCard';

import useModal from '@/hooks/common/useModal';
import useCategories, { DEFAULT_CATEGORY_ID, DEFAULT_CATEGORY_VALUE } from '@/hooks/PairRoom/useCategories';

import { useGetReference } from '@/queries/PairRoom/reference/query';

import * as S from './ReferenceCard.styles';

interface ReferenceCardProps {
accessCode: string;
}

const ReferenceCard = ({ accessCode }: ReferenceCardProps) => {
const [selectedFilteringCategoryId, setSelectedFilteringCategoryId] = useState(DEFAULT_CATEGORY_ID);
const { isModalOpen, openModal, closeModal } = useModal();

const { categories, isCategoryExist, getCategoryNameById } = useCategories(accessCode);

const { data: references } = useGetReference(selectedFilteringCategoryId, accessCode);
const selectedFilteringCategoryName = getCategoryNameById(selectedFilteringCategoryId) || DEFAULT_CATEGORY_VALUE;

return (
<>
<S.Layout>
<PairRoomCard>
<Header selectedFilteringCategoryName={selectedFilteringCategoryName} onButtonClick={openModal} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selectedFilteringCategoryName 이거 λ³€μˆ˜λͺ…을 쀄일 수 μžˆλŠ” 방법은 μ—†μ„κΉŒμš”...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

원본 μ½”λ“œμ™€ 같은 이름이라 λ¦¬νŒ©ν„°λ§ν•  λ•Œ ν•œ λ²ˆμ— 고쳐야 ν•  것 κ°™μ•„μš” πŸ₯²

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ½”λ“œ λ‹€μ΄μ–΄νŠΈκ°€ μ‹œκΈ‰ν•˜κ΅°μš” ⚠️

<S.Body>
<ReferenceList references={references} />
</S.Body>
</PairRoomCard>
</S.Layout>

<CategoryManagementModal
isOpen={isModalOpen}
closeModal={closeModal}
categories={categories}
isCategoryExist={isCategoryExist}
selectedCategory={selectedFilteringCategoryId}
handleSelectCategory={(categoryId: string) => setSelectedFilteringCategoryId(categoryId)}
/>
</>
);
};

export default ReferenceCard;
Loading
Loading