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

Mara 23 친구 냉장고 화면 구현 #7

Merged
merged 4 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20,121 changes: 20,121 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

Binary file added src/assets/profile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/atoms/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface ButtonProps {
const Button: React.FC<ButtonProps> = ({ text, className, onClick }) => {
return (
<button
className={` text-white p-18 gap-12 rounded-12 heading4-semibold ${className}`}
className={`text-white p-18 gap-12 rounded-12 heading4-semibold ${className}`}
onClick={onClick}
>
{text}
Expand Down
45 changes: 45 additions & 0 deletions src/components/atoms/Icon.tsx
Copy link
Member

@choipureum choipureum Jan 24, 2024

Choose a reason for hiding this comment

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

해당 부분은 아이콘이 추가될 수록 관리가 점차 힘들어 질 것 같은데요..!
svgr를 사용해서 아이콘 컴포넌트화를 통해 관리하던지 따로 배럴파일을 둬서 아이콘을 에셋으로 관리하던지 선택이 필요해 보입니다.🙀

https://github.com/gregberge/svgr

Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,48 @@ export const TrashcanSVG: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (
</defs>
</svg>
);

export const SearchSVG: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.16667 15.8333C12.8486 15.8333 15.8333 12.8486 15.8333 9.16667C15.8333 5.48477 12.8486 2.5 9.16667 2.5C5.48477 2.5 2.5 5.48477 2.5 9.16667C2.5 12.8486 5.48477 15.8333 9.16667 15.8333Z"
stroke="#9299AA"
stroke-width="1.66667"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M17.5002 17.4998L13.9169 13.9165"
stroke="#9299AA"
stroke-width="1.66667"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);

export const ArrowRightGray: React.FC<React.SVGProps<SVGSVGElement>> = (
Copy link
Member

Choose a reason for hiding this comment

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

색상과 방향 정도는 커스텀해도 좋을 것 같습니다..! 컴포넌트화의 이점을 살려서 Arrow 컴포넌트를 두고 방향과 스트로크정도는 커스텀화 해서 확장성 있게 가져가는게 좋아보입니다..!👀

props,
) => (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 14L11 8L5 2"
stroke="#CCCFD7"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
5 changes: 4 additions & 1 deletion src/components/atoms/ModalBottom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ const ModalBox: React.FC<ModalBoxProps> = ({ children, blackClickHandler }) => {
onClick={blackClickHandler}
>
<div
className="w-full max-w-[480px] min-h-[500px] pt-[40px] mb-[-24px] bg-white p-[20px] rounded-[24px]"
className="w-full max-w-[480px] pt-[40px] mb-[-24px] bg-white p-[20px] pb-[40px] rounded-[24px]"
onClick={handleWhiteContentClick}
>
<div className="relative">
<div className="absolute top-[-16px] right-[200px] left-[200px] h-[4px] bg-gray-500 rounded-[100px]"></div>
</div>
{children}
</div>
</div>
Expand Down
25 changes: 17 additions & 8 deletions src/components/atoms/SearchInput.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import React from 'react';
import { SearchSVG } from './Icon';

interface SearchInputProps {
searchKeyword: string;
onChangeHandler: () => void;
onClickHandler: () => void;
className: string;
searchKeyword?: string;
onChange?: () => void;
onClick?: () => void;
className?: string;
placeholder?: string;
}

const SearchInput: React.FC<SearchInputProps> = ({
searchKeyword,
onClickHandler,
onChangeHandler,
onClick,
placeholder,
onChange,
className,
}) => {
return (
<div
className={`flex items-center justify-center w-full bg-primary2 text-white p-18 gap-12 rounded-12 heading4-semibold ${className}`}
className={`flex items-center justify-center w-full bg-gray1 text-white p-18 gap-12 rounded-12 heading4-semibold ${className}`}
>
<input onChange={onChangeHandler} value={searchKeyword} />
<input
className="w-full bg-gray1 text"
placeholder={placeholder}
onChange={onChange}
value={searchKeyword}
/>
<SearchSVG width={20} height={20} />
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions src/components/atoms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export { default as ModalBottom } from './ModalBottom';
export { default as ModalCenter } from './ModalCenter';
export { default as Toggle } from './Toggle';
export { default as ToastMessage } from './ToastMessage';
export { default as SearchInput } from './SearchInput';
38 changes: 38 additions & 0 deletions src/components/molecules/FriendsFridgeItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Link from 'next/link';
import React from 'react';
import profileImg from '@/assets/profile.png';
import Image from 'next/image';
import { ArrowRightGray } from '../atoms/Icon';

interface FriendsFridgeItemProps {
name: string;
ingredientCount: number;
linkTo: string;
}

const FriendsFridgeItem: React.FC<FriendsFridgeItemProps> = ({
name,
ingredientCount,
linkTo,
}) => {
return (
<div className="w-full flex items-center justify-between">
<div className="flex gap-[12px]">
<div>
<Image src={profileImg} alt={`누군가의 프로필`} />
</div>
<div className="flex flex-col">
<div className="heading4-semibold text-gray7">{name}</div>
<div className="body2-medium text-gray5">
냉장고 저장 목록 {ingredientCount}개
</div>
</div>
</div>
<Link href={`${linkTo}`}>
<ArrowRightGray />
</Link>
</div>
);
};

export default FriendsFridgeItem;
1 change: 1 addition & 0 deletions src/components/molecules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { default as FridgeTab } from './FridgeTab';
export { default as Counter } from './Counter';
export { default as IngredientAddItemContainer } from './IngredientAddItemContainer';
export { default as FridgeListItem } from './FridgeListItem';
export { default as FriendsFridgeItem } from './FriendsFridgeItem';
14 changes: 8 additions & 6 deletions src/components/organisms/FridgeInfoBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AllowBottom } from '../atoms/Icon';

const FridgeInfoBox: React.FC<{
toggleIsOpenFridgeListModal: () => void;
toggleIsOpenIngredientAddModal: () => void;
toggleIsOpenIngredientAddModal?: () => void;
}> = ({ toggleIsOpenFridgeListModal, toggleIsOpenIngredientAddModal }) => {
return (
<div className="flex justify-between items-end mb-[28px]">
Expand All @@ -18,11 +18,13 @@ const FridgeInfoBox: React.FC<{
<AllowBottom />
</div>
</div>
<Button
className="rounded-6 w-[100px] p-[10px] body1-semibold bg-primary2"
text="식자재 추가"
onClick={toggleIsOpenIngredientAddModal}
/>
{toggleIsOpenIngredientAddModal && (
<Button
className="rounded-6 w-[100px] p-[10px] body1-semibold bg-primary2"
text="식자재 추가"
onClick={toggleIsOpenIngredientAddModal}
/>
)}
</div>
);
};
Expand Down
22 changes: 14 additions & 8 deletions src/components/organisms/FridgeListModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { FridgeListItem } from '../molecules';
import { PlusSVG, TrashcanSVG } from '../atoms/Icon';

const FridgeListModal: React.FC<{
isMyFridgeList?: boolean;
toggleIsOpenFridgeListModal: () => void;
}> = ({ toggleIsOpenFridgeListModal }) => {
}> = ({ toggleIsOpenFridgeListModal, isMyFridgeList }) => {
const [currentFridgeName, setCurrentFridgeName] = useState('기본 냉장고');
const FRIDGE_NAME_LIST = ['기본 냉장고', '김치 냉장고', '주류 냉장고'];

return (
<ModalBottom blackClickHandler={toggleIsOpenFridgeListModal}>
<div>
Expand All @@ -27,15 +29,19 @@ const FridgeListModal: React.FC<{
/>
))}

<button className="flex justify-center items-center h-[64px] border-2 rounded-[12px] text-gray3">
<PlusSVG />
냉장고 추가
</button>
{!isMyFridgeList && (
<button className="flex justify-center items-center h-[64px] border-2 rounded-[12px] text-gray3">
Copy link
Member

Choose a reason for hiding this comment

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

공통으로 사용하는 버튼들은 atom에 미리 빼놔도 좋을 것 같네유..!🙇‍♂️

<PlusSVG />
냉장고 추가
</button>
)}
</div>
<div className="flex w-full gap-[8px]">
<button className="p-[13px] border-2 border-2 rounded-[12px]">
<TrashcanSVG />
</button>
{!isMyFridgeList && (
<button className="p-[13px] border-2 border-2 rounded-[12px]">
<TrashcanSVG />
</button>
)}
<Button className="flex-grow bg-primary2" text="이동하기" />
</div>
</ModalBottom>
Expand Down
35 changes: 35 additions & 0 deletions src/components/organisms/FriendsFridgeList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { SearchInput, WhiteBox } from '../atoms';
import { FriendsFridgeItem } from '../molecules';
import { AllowBottom } from '../atoms/Icon';

const FriendsFridgeList: React.FC<{
toggleIsOpenOrderListModal: () => void;
}> = ({ toggleIsOpenOrderListModal }) => {
return (
<div className="mt-[37px]">
<div className="mb-[19.5px] flex justify-between">
<div className="heading2-semibold text-gray8">
친구 목록<span className="heading2-bold text-primary3">13</span>
</div>
<div
className="flex items-center gap-[6px]"
onClick={toggleIsOpenOrderListModal}
>
<div>등록순</div>
<AllowBottom />
</div>
</div>
<WhiteBox>
<SearchInput placeholder="친구의 이름을 입력하세요" />
<div className="w-full flex flex-col gap-[24px]">
<FriendsFridgeItem name="김지수" ingredientCount={13} linkTo="#" />
<FriendsFridgeItem name="김지수" ingredientCount={13} linkTo="#" />
<FriendsFridgeItem name="김지수" ingredientCount={13} linkTo="#" />
</div>
</WhiteBox>
</div>
);
};

export default FriendsFridgeList;
44 changes: 44 additions & 0 deletions src/components/organisms/FriendsRecentBoard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { GreenArrowButton, WhiteBox } from '../atoms';
import { AppleIcon } from '@/components/atoms/IngredientIcons';
import Link from 'next/link';

const FriendsRecentBoard: React.FC = () => {
const INGREDIENT_LIST = [
{ isToday: true },
{ isToday: false },
{ isToday: false },
];
return (
<WhiteBox className="flex">
<div className="text-primary2 body2-semibold">최신근황</div>
<div className="text-center text-gray8">
김지수님이
<br />
토마토를 추가했어요!
</div>
<div className="text-gray6 body2-medium">
그밖에 신선한 재료를 구경할 수 있어요.
</div>
<div className="flex w-full justify-center gap-[6px]">
{INGREDIENT_LIST.map((ingredient) => (
<div
className={`flex flex-col items-center gap-[9.5px] ${ingredient.isToday ? 'bg-[#FFD5C6]' : 'bg-gray1'} p-[12px] rounded-[12px]`}
>
<AppleIcon width={38} height={38} />
<div
className={`body2-semibold ${ingredient.isToday ? 'text-point3' : ''}`}
>
오늘 추가
</div>
</div>
))}
</div>
<Link className="w-full" href="/friend/12">
<GreenArrowButton className="bg-primary2" text="친구 냉장고 보러가기" />
</Link>
</WhiteBox>
);
};

export default FriendsRecentBoard;
35 changes: 35 additions & 0 deletions src/components/organisms/OrderListModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { Button, ModalBottom } from '../atoms';
import { EmptyRadioSVG, FullRadioSVG } from '../atoms/Icon';

const OrderListModal: React.FC<{
currentOrder: string;
toggleIsOpenOrderListModal: () => void;
}> = ({ toggleIsOpenOrderListModal, currentOrder }) => {
const ORDER_LIST = ['등록순', '이름순'];

return (
<ModalBottom blackClickHandler={toggleIsOpenOrderListModal}>
<div className="w-full">
{ORDER_LIST.map((order) => (
<div className="flex flex-row items-center justify-between h-[70px]">
{currentOrder === order ? (
<>
<div className="heading3-semibold">{order}</div>
<FullRadioSVG />
</>
) : (
<>
<div className="heading3-semibold text-gray5">{order}</div>
<EmptyRadioSVG />
</>
)}
</div>
))}
</div>
<Button className="w-full bg-primary2" text="선택 완료" />
</ModalBottom>
);
};

export default OrderListModal;
3 changes: 3 additions & 0 deletions src/components/organisms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ export { default as FridgeBoard } from './FridgeBoard';
export { default as FridgeInfoBox } from './FridgeInfoBox';
export { default as IngredientAddModal } from './IngredientAddModal';
export { default as FridgeListModal } from './FridgeListModal';
export { default as FriendsRecentBoard } from './FriendsRecentBoard';
export { default as FriendsFridgeList } from './FriendsFridgeList';
export { default as OrderListModal } from './OrderListModal';
37 changes: 37 additions & 0 deletions src/pages/friend/[id]/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
FridgeBoard,
FridgeInfoBox,
FridgeListModal,
} from '@/components/organisms';
import Header from '@/components/organisms/Header';
import { type NextPage } from 'next';
import { useState } from 'react';

const FriendIdPage: NextPage = () => {
const [isOpenFridgeListModal, setIsOpenFridgeListModal] = useState(false);

const toggleIsOpenFridgeListModal: () => void = () => {
setIsOpenFridgeListModal((prev) => !prev);
};

return (
<>
{isOpenFridgeListModal && (
<FridgeListModal
isMyFridgeList
toggleIsOpenFridgeListModal={toggleIsOpenFridgeListModal}
/>
)}
<div className={'pt-[52px] min-h-screen'}>
<Header headerTitle={'친구 냉장고'} />
<section className={`flex flex-col min-h-screen p-20 bg-gray1`}>
<FridgeInfoBox
toggleIsOpenFridgeListModal={toggleIsOpenFridgeListModal}
/>
<FridgeBoard />
</section>
</div>
</>
);
};
export default FriendIdPage;
Loading
Loading