From ae27adc13a5c312e1ca4cf0f90c9c438bccec806 Mon Sep 17 00:00:00 2001 From: kangkibong Date: Tue, 15 Oct 2024 16:23:37 +0900 Subject: [PATCH 001/120] =?UTF-8?q?Refactor/#47=206=EC=A3=BC=EC=B0=A8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A6=AC=EB=B7=B0=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#48)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: separate style and prop-related constants * refactor: remove lambda function * refactor: restructure SignUp and RecruitmentHeader components * feat: separate Button and Text component of SignIn * feat: add SignUpText component * refactor: remove auth page's barrel file --- .../common/InnerContainer/index.tsx | 31 ++++--- src/components/common/List/index.tsx | 2 +- src/features/auth/RoleModal.tsx | 34 -------- src/features/auth/SignIn/SignInButton.tsx | 17 ++++ src/features/auth/SignIn/SignInText.tsx | 41 ++++++++++ .../auth/{ => SignUp}/RoleSelection.tsx | 0 src/features/auth/SignUp/SignUpText.tsx | 41 ++++++++++ .../auth/SignUp/components/RoleModal.tsx | 37 +++++++++ .../components/RoleSelector/index.config.tsx | 0 .../components/RoleSelector/index.tsx | 31 ++++--- src/features/auth/components/RoleModal.tsx | 34 -------- .../auth/components/RoleSelection.tsx | 16 ---- src/features/home/Employer.tsx | 38 ++++----- src/features/home/RecruitmentList.tsx | 29 +++---- src/features/home/components/Banner.tsx | 27 +++--- .../components/RecruitmentCard/Button.tsx | 11 ++- .../RecruitmentCard/CompanyImage.tsx | 37 ++++----- .../RecruitmentCard/CompanyName.tsx | 23 +++--- .../components/RecruitmentCard/Detail.tsx | 23 +++--- .../RecruitmentCard/RecruitmentCard.tsx | 26 +++--- .../components/RecruitmentCard/Salary.tsx | 4 +- .../home/components/RecruitmentCard/Title.tsx | 25 +++--- .../home/components/RecruitmentHeader.tsx | 57 ------------- .../RecruitmentHeader/index.styles.ts | 33 ++++++++ .../components/RecruitmentHeader/index.tsx | 17 ++++ src/pages/auth/SignIn/index.styles.ts | 20 +++++ src/pages/auth/SignIn/index.tsx | 82 ++----------------- src/pages/auth/SignUp/index.tsx | 52 ++---------- src/pages/auth/index.ts | 2 - src/pages/home/index.tsx | 4 +- src/routes/router.tsx | 3 +- 31 files changed, 372 insertions(+), 425 deletions(-) delete mode 100644 src/features/auth/RoleModal.tsx create mode 100644 src/features/auth/SignIn/SignInButton.tsx create mode 100644 src/features/auth/SignIn/SignInText.tsx rename src/features/auth/{ => SignUp}/RoleSelection.tsx (100%) create mode 100644 src/features/auth/SignUp/SignUpText.tsx create mode 100644 src/features/auth/SignUp/components/RoleModal.tsx rename src/features/auth/{ => SignUp}/components/RoleSelector/index.config.tsx (100%) rename src/features/auth/{ => SignUp}/components/RoleSelector/index.tsx (63%) delete mode 100644 src/features/auth/components/RoleModal.tsx delete mode 100644 src/features/auth/components/RoleSelection.tsx delete mode 100644 src/features/home/components/RecruitmentHeader.tsx create mode 100644 src/features/home/components/RecruitmentHeader/index.styles.ts create mode 100644 src/features/home/components/RecruitmentHeader/index.tsx create mode 100644 src/pages/auth/SignIn/index.styles.ts delete mode 100644 src/pages/auth/index.ts diff --git a/src/components/common/InnerContainer/index.tsx b/src/components/common/InnerContainer/index.tsx index 5240543..5a5253f 100644 --- a/src/components/common/InnerContainer/index.tsx +++ b/src/components/common/InnerContainer/index.tsx @@ -2,28 +2,27 @@ import { breakpoints } from '@assets/styles/global/breakpoints'; import { responsiveStyle } from '@utils/responsive'; import { HTMLAttributes, ReactNode } from 'react'; +const containerStyle = responsiveStyle({ + default: { + maxWidth: '1300px', + margin: '0 auto', + }, + tablet: { + maxWidth: breakpoints.tablet, + padding: '0 12px', + }, + mobile: { + maxWidth: breakpoints.mobile, + }, +}); + type Props = { children: ReactNode; } & HTMLAttributes; export default function InnerContainer({ children, ...rest }: Props) { return ( -
+
{children}
); diff --git a/src/components/common/List/index.tsx b/src/components/common/List/index.tsx index 78f0ec8..ba0efc0 100644 --- a/src/components/common/List/index.tsx +++ b/src/components/common/List/index.tsx @@ -6,5 +6,5 @@ interface Props { } export default function List({ items, renderItem }: Props) { - return <>{items.map((item) => renderItem(item))}; + return <>{items.map(renderItem)}; } diff --git a/src/features/auth/RoleModal.tsx b/src/features/auth/RoleModal.tsx deleted file mode 100644 index 52e9cac..0000000 --- a/src/features/auth/RoleModal.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Modal, Typo, Flex, Button } from '@components/common'; -import { ReactNode } from 'react'; - -type Props = { - content: ReactNode; - onClose: () => void; -}; - -export default function RoleModal({ content, onClose }: Props) { - return ( - - - 정보를 입력해주세요.
-
- {content} -
-
- * 추후 마이페이지에서 수정 할 수 있습니다. -
-
-
- } - buttonChildren={ - - - - - } - onClose={onClose} - /> - ); -} diff --git a/src/features/auth/SignIn/SignInButton.tsx b/src/features/auth/SignIn/SignInButton.tsx new file mode 100644 index 0000000..0dde11a --- /dev/null +++ b/src/features/auth/SignIn/SignInButton.tsx @@ -0,0 +1,17 @@ +import { Flex, Typo, Button, Icon } from '@components/common'; + +const FLEX_GAP_CONFIG = { x: '12px' }; +const BUTTON_STYLE = { fontWeight: '300' }; + +export function SignInButton() { + return ( + + ); +} diff --git a/src/features/auth/SignIn/SignInText.tsx b/src/features/auth/SignIn/SignInText.tsx new file mode 100644 index 0000000..cdcfd42 --- /dev/null +++ b/src/features/auth/SignIn/SignInText.tsx @@ -0,0 +1,41 @@ +import { Flex, Typo } from '@components/common'; +import { responsiveStyle } from '@utils/responsive'; + +const flexStyle = responsiveStyle({ + default: { + marginBottom: '72px', + }, + tablet: { + marginBottom: '56px', + }, + mobile: { + marginBottom: '42px', + alignItems: 'center', + }, +}); + +const headingTypoStyle = responsiveStyle({ + default: { + marginBottom: '24px', + }, + tablet: { fontSize: '32px' }, + mobile: { fontSize: '28px' }, +}); + +const paragraphTypoStyle = responsiveStyle({ + tablet: { fontSize: '16px' }, + mobile: { fontSize: '14px' }, +}); + +export function SignInText() { + return ( + + + 지금 바로 시작하세요. 🚀 + + + 안정적이고 투명한 고용 관계의 시작, 지금 바로 경험해보세요! + + + ); +} diff --git a/src/features/auth/RoleSelection.tsx b/src/features/auth/SignUp/RoleSelection.tsx similarity index 100% rename from src/features/auth/RoleSelection.tsx rename to src/features/auth/SignUp/RoleSelection.tsx diff --git a/src/features/auth/SignUp/SignUpText.tsx b/src/features/auth/SignUp/SignUpText.tsx new file mode 100644 index 0000000..9ae4c27 --- /dev/null +++ b/src/features/auth/SignUp/SignUpText.tsx @@ -0,0 +1,41 @@ +import { Flex, Typo } from '@/components/common'; +import { responsiveStyle } from '@/utils/responsive'; + +const titleStyle = responsiveStyle({ + default: { + marginBottom: '38px', + }, + tablet: { + marginBottom: '28px', + }, + mobile: { + marginBottom: '20px', + fontSize: '20px', + }, +}); + +const descriptionTitle = responsiveStyle({ + default: { + marginBottom: '38px', + }, + tablet: { + marginBottom: '28px', + }, + mobile: { + marginBottom: '20px', + fontSize: '16px', + }, +}); + +export default function SignUpText() { + return ( + + + 가입자 정보 선택 + + + 대상에 해당하는 가입자 정보를 선택해주세요. + + + ); +} diff --git a/src/features/auth/SignUp/components/RoleModal.tsx b/src/features/auth/SignUp/components/RoleModal.tsx new file mode 100644 index 0000000..d2a0d33 --- /dev/null +++ b/src/features/auth/SignUp/components/RoleModal.tsx @@ -0,0 +1,37 @@ +import { Modal, Typo, Flex, Button } from '@components/common'; +import { ReactNode } from 'react'; + +const DEFAULT_CSS = { marginBottom: '12px' }; +const FLEX_GAP_CONFIG = { x: '16px' }; + +type Props = { + content: ReactNode; + onClose: () => void; +}; + +export default function RoleModal({ content, onClose }: Props) { + return ( + + + 정보를 입력해주세요. + + + {content} + + + * 추후 마이페이지에서 수정 할 수 있습니다. + + + } + buttonChildren={ + + + + + } + onClose={onClose} + /> + ); +} diff --git a/src/features/auth/components/RoleSelector/index.config.tsx b/src/features/auth/SignUp/components/RoleSelector/index.config.tsx similarity index 100% rename from src/features/auth/components/RoleSelector/index.config.tsx rename to src/features/auth/SignUp/components/RoleSelector/index.config.tsx diff --git a/src/features/auth/components/RoleSelector/index.tsx b/src/features/auth/SignUp/components/RoleSelector/index.tsx similarity index 63% rename from src/features/auth/components/RoleSelector/index.tsx rename to src/features/auth/SignUp/components/RoleSelector/index.tsx index 610d12f..6fb6cc6 100644 --- a/src/features/auth/components/RoleSelector/index.tsx +++ b/src/features/auth/SignUp/components/RoleSelector/index.tsx @@ -4,6 +4,18 @@ import { bounceAnimation } from '@assets/styles/animations'; import { ReactNode } from 'react'; import { responsiveStyle } from '@utils/responsive'; +const cardStyle = responsiveStyle({ + default: { padding: '60px 120px', cursor: 'pointer' }, + mobile: { padding: '16px 32px' }, +}); + +const iconStyle = responsiveStyle({ + default: { marginBottom: '24px' }, + mobile: { + marginBottom: '10px', + }, +}); + type Props = { role: 'employer' | 'worker'; onClick: (modalContent: ReactNode) => void; @@ -14,26 +26,11 @@ export default function RoleSelector({ role, onClick }: Props) { onClick(roleConfig[role].modalContent)} > -
- {roleConfig[role].icon} -
+
{roleConfig[role].icon}
{roleConfig[role].text} diff --git a/src/features/auth/components/RoleModal.tsx b/src/features/auth/components/RoleModal.tsx deleted file mode 100644 index 52e9cac..0000000 --- a/src/features/auth/components/RoleModal.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Modal, Typo, Flex, Button } from '@components/common'; -import { ReactNode } from 'react'; - -type Props = { - content: ReactNode; - onClose: () => void; -}; - -export default function RoleModal({ content, onClose }: Props) { - return ( - - - 정보를 입력해주세요.
-
- {content} -
-
- * 추후 마이페이지에서 수정 할 수 있습니다. -
-
- - } - buttonChildren={ - - - - - } - onClose={onClose} - /> - ); -} diff --git a/src/features/auth/components/RoleSelection.tsx b/src/features/auth/components/RoleSelection.tsx deleted file mode 100644 index 4037afb..0000000 --- a/src/features/auth/components/RoleSelection.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Flex } from '@components/common'; -import RoleSelector from './RoleSelector'; -import { ReactNode } from 'react'; - -type Props = { - onRoleSelect: (modalContent: ReactNode) => void; -}; - -export default function RoleSelection({ onRoleSelect }: Props) { - return ( - - - - - ); -} diff --git a/src/features/home/Employer.tsx b/src/features/home/Employer.tsx index 61815c1..4bef18a 100644 --- a/src/features/home/Employer.tsx +++ b/src/features/home/Employer.tsx @@ -3,32 +3,28 @@ import Banner from './components/Banner'; import { images } from '@pages/home/data/index.mock'; import { responsiveStyle } from '@utils/responsive'; +const headerStyle = responsiveStyle({ + default: { + marginBottom: '40px', + whiteSpace: 'pre-line', + textAlign: 'center', + }, + tablet: { + fontSize: '36px', + marginBottom: '32px', + }, + mobile: { + fontSize: '28px', + marginBottom: '28px', + }, +}); + export default function Employer() { return ( <> - + {`사장님,\n 공고 등록은 하셨나요? 🤔`} diff --git a/src/features/home/RecruitmentList.tsx b/src/features/home/RecruitmentList.tsx index 3ff2d0f..863b9ef 100644 --- a/src/features/home/RecruitmentList.tsx +++ b/src/features/home/RecruitmentList.tsx @@ -3,28 +3,25 @@ import RecruitmentCard from './components/RecruitmentCard/RecruitmentCard'; import { RecruitmentItem } from '@/types'; import { responsiveStyle } from '@utils/responsive'; +const listContainerStyle = responsiveStyle({ + default: { + gap: '32px', + }, + tablet: { + gap: '26px', + }, + mobile: { + gap: '18px', + }, +}); + type Props = { recruitmentList: RecruitmentItem[]; }; export default function RecruitmentList({ recruitmentList }: Props) { return ( - + ( diff --git a/src/features/home/components/Banner.tsx b/src/features/home/components/Banner.tsx index c6e1188..e48782d 100644 --- a/src/features/home/components/Banner.tsx +++ b/src/features/home/components/Banner.tsx @@ -6,11 +6,7 @@ import 'slick-carousel/slick/slick-theme.css'; import styled from '@emotion/styled'; import { BannerItem } from '@/types'; -type Props = { - images: BannerItem[]; - isSlider?: boolean; - children?: ReactNode; -}; +const BANNER_SIZE_CONFIG = { width: '100%', height: '400px' }; const settings = { infinite: true, @@ -21,27 +17,32 @@ const settings = { autoplaySpeed: 3000, }; +type Props = { + images: BannerItem[]; + isSlider?: boolean; + children?: ReactNode; +}; + export default function Banner({ images, isSlider = false, children }: Props) { return ( -
+
{isSlider ? ( {images.map((image) => ( - + ))} ) : ( - + )} {children && {children}} -
+
); } -const bannerImageSize = { - width: '100%', - height: '400px', -}; +const Section = styled.section` + position: relative; +`; const ChildrenContent = styled.div` position: absolute; diff --git a/src/features/home/components/RecruitmentCard/Button.tsx b/src/features/home/components/RecruitmentCard/Button.tsx index 5750f5d..e3825fd 100644 --- a/src/features/home/components/RecruitmentCard/Button.tsx +++ b/src/features/home/components/RecruitmentCard/Button.tsx @@ -1,12 +1,17 @@ import { Typo, Icon, Flex } from '@components/common'; -export default function Detail() { +const FLEX_GAP_CONFIG = { x: '8px' }; +const BUTTON_CONTAINER_STYLE = { cursor: 'pointer' }; + +export default function Button() { return ( - + Read More - +
+ +
); } diff --git a/src/features/home/components/RecruitmentCard/CompanyImage.tsx b/src/features/home/components/RecruitmentCard/CompanyImage.tsx index d1b210f..3486647 100644 --- a/src/features/home/components/RecruitmentCard/CompanyImage.tsx +++ b/src/features/home/components/RecruitmentCard/CompanyImage.tsx @@ -2,27 +2,24 @@ import { Image } from '@components/common'; import { useRecruitmentCardContext } from './RecruitmentCard.context'; import { responsiveStyle } from '@utils/responsive'; +const IMAGE_SIZE_CONFIG = { + width: '350px', + height: '275px', +}; + +const companyImageStyle = responsiveStyle({ + default: { + marginBottom: '24px', + }, + mobile: { + marginBottom: '18px', + minWidth: '300px', + minHeight: '250px', + }, +}); + export default function CompanyImage() { const { recruitment } = useRecruitmentCardContext(); - return ( - - ); + return ; } diff --git a/src/features/home/components/RecruitmentCard/CompanyName.tsx b/src/features/home/components/RecruitmentCard/CompanyName.tsx index fdefd9e..f6df543 100644 --- a/src/features/home/components/RecruitmentCard/CompanyName.tsx +++ b/src/features/home/components/RecruitmentCard/CompanyName.tsx @@ -2,23 +2,20 @@ import { Typo } from '@components/common'; import { useRecruitmentCardContext } from './RecruitmentCard.context'; import { responsiveStyle } from '@utils/responsive'; +const companyNameStyle = responsiveStyle({ + default: { + marginBottom: '4px', + }, + mobile: { + fontSize: '12px', + }, +}); + export default function CompanyName() { const { recruitment } = useRecruitmentCardContext(); return ( - + {recruitment.companyName} ); diff --git a/src/features/home/components/RecruitmentCard/Detail.tsx b/src/features/home/components/RecruitmentCard/Detail.tsx index 4b00214..ae2ead5 100644 --- a/src/features/home/components/RecruitmentCard/Detail.tsx +++ b/src/features/home/components/RecruitmentCard/Detail.tsx @@ -2,23 +2,20 @@ import { Typo } from '@components/common'; import { useRecruitmentCardContext } from './RecruitmentCard.context'; import { responsiveStyle } from '@utils/responsive'; +const detailStyle = responsiveStyle({ + default: { + marginBottom: '16px', + }, + mobile: { + fontSize: '14px', + }, +}); + export default function Detail() { const { recruitment } = useRecruitmentCardContext(); return ( - + {recruitment.area} / {recruitment.workHours} ); diff --git a/src/features/home/components/RecruitmentCard/RecruitmentCard.tsx b/src/features/home/components/RecruitmentCard/RecruitmentCard.tsx index d1f98a8..b247f24 100644 --- a/src/features/home/components/RecruitmentCard/RecruitmentCard.tsx +++ b/src/features/home/components/RecruitmentCard/RecruitmentCard.tsx @@ -6,6 +6,16 @@ import { RecruitmentCardContextProvider } from './RecruitmentCard.context'; import { Title, Button, CompanyName, CompanyImage, Detail, Salary } from '.'; import { responsiveStyle } from '@utils/responsive'; +const recruitmentCardStyle = responsiveStyle({ + default: { + padding: '24px', + cursor: 'pointer', + }, + mobile: { + padding: '16px', + }, +}); + type Props = { recruitment: RecruitmentItem; children: ReactNode; @@ -14,21 +24,7 @@ type Props = { export default function RecruitmentCard({ recruitment, children }: Props) { return ( - + {children} diff --git a/src/features/home/components/RecruitmentCard/Salary.tsx b/src/features/home/components/RecruitmentCard/Salary.tsx index 2808423..a26328b 100644 --- a/src/features/home/components/RecruitmentCard/Salary.tsx +++ b/src/features/home/components/RecruitmentCard/Salary.tsx @@ -1,11 +1,13 @@ import { Typo } from '@components/common'; import { useRecruitmentCardContext } from './RecruitmentCard.context'; +const SALARY_STYLE = { marginBottom: '4px' }; + export default function Salary() { const { recruitment } = useRecruitmentCardContext(); return ( - + {recruitment.salary} ); diff --git a/src/features/home/components/RecruitmentCard/Title.tsx b/src/features/home/components/RecruitmentCard/Title.tsx index 6efeffa..13e27d6 100644 --- a/src/features/home/components/RecruitmentCard/Title.tsx +++ b/src/features/home/components/RecruitmentCard/Title.tsx @@ -2,24 +2,21 @@ import { Typo } from '@components/common'; import { useRecruitmentCardContext } from './RecruitmentCard.context'; import { responsiveStyle } from '@utils/responsive'; +const titleStyle = responsiveStyle({ + default: { + marginBottom: '12px', + }, + mobile: { + marginBottom: '8px', + fontSize: '16px', + }, +}); + export default function Title() { const { recruitment } = useRecruitmentCardContext(); return ( - + {recruitment.koreanTitle} / {recruitment.vietnameseTitle} ); diff --git a/src/features/home/components/RecruitmentHeader.tsx b/src/features/home/components/RecruitmentHeader.tsx deleted file mode 100644 index 7c16b52..0000000 --- a/src/features/home/components/RecruitmentHeader.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Flex, Typo } from '@components/common'; -import { responsiveStyle } from '@utils/responsive'; - -export default function RecruitmentHeader() { - return ( - -
- - 어떤 일자리를 구하시나요? - - - 조건을 선택하고 원하는 일자리를 골라보세요. - -
-
- ); -} diff --git a/src/features/home/components/RecruitmentHeader/index.styles.ts b/src/features/home/components/RecruitmentHeader/index.styles.ts new file mode 100644 index 0000000..cf7af1b --- /dev/null +++ b/src/features/home/components/RecruitmentHeader/index.styles.ts @@ -0,0 +1,33 @@ +import { responsiveStyle } from '@utils/responsive'; + +export const flexStyle = responsiveStyle({ + default: { + marginBottom: '60px', + }, + mobile: { + marginBottom: '32px', + justifyContent: 'center', + }, +}); + +export const divStyle = responsiveStyle({ + mobile: { + textAlign: 'center', + }, +}); + +export const headerTypoStyle = responsiveStyle({ + default: { + marginBottom: '16px', + }, + mobile: { + marginBottom: '12px', + fontSize: '28px', + }, +}); + +export const subheaderTypoStyle = responsiveStyle({ + mobile: { + fontSize: '18px', + }, +}); diff --git a/src/features/home/components/RecruitmentHeader/index.tsx b/src/features/home/components/RecruitmentHeader/index.tsx new file mode 100644 index 0000000..f07a692 --- /dev/null +++ b/src/features/home/components/RecruitmentHeader/index.tsx @@ -0,0 +1,17 @@ +import { Flex, Typo } from '@components/common'; +import { flexStyle, divStyle, headerTypoStyle, subheaderTypoStyle } from './index.styles'; + +export default function RecruitmentHeader() { + return ( + +
+ + 어떤 일자리를 구하시나요? + + + 조건을 선택하고 원하는 일자리를 골라보세요. + +
+
+ ); +} diff --git a/src/pages/auth/SignIn/index.styles.ts b/src/pages/auth/SignIn/index.styles.ts new file mode 100644 index 0000000..a5e045d --- /dev/null +++ b/src/pages/auth/SignIn/index.styles.ts @@ -0,0 +1,20 @@ +import theme from '@/assets/theme'; +import { responsiveStyle, responsiveSectionPadding } from '@/utils/responsive'; + +export const sectionStyle = { + backgroundColor: theme.palettes.backgroundGray, + ...responsiveStyle(responsiveSectionPadding), +}; + +export const innerContainerStyle = responsiveStyle({ + mobile: { + flexDirection: 'column', + }, +}); + +export const catchphraseContainerStyle = responsiveStyle({ + default: { + marginRight: '24px', + }, + mobile: { marginRight: '0', alignItems: 'center', marginBottom: '32px' }, +}); diff --git a/src/pages/auth/SignIn/index.tsx b/src/pages/auth/SignIn/index.tsx index 0bb9029..2443d9a 100644 --- a/src/pages/auth/SignIn/index.tsx +++ b/src/pages/auth/SignIn/index.tsx @@ -1,83 +1,19 @@ -import { InnerContainer, Flex, Typo, Icon, Button } from '@components/common'; +import { InnerContainer, Flex } from '@components/common'; import Layout from '@features/layout'; -import theme from '@/assets/theme'; import Illustration from '@assets/images/signin-Illustration.svg?react'; -import { responsiveSectionPadding, responsiveStyle } from '@utils/responsive'; +import { sectionStyle, innerContainerStyle, catchphraseContainerStyle } from './index.styles'; +import { SignInText } from '@/features/auth/SignIn/SignInText'; +import { SignInButton } from '@/features/auth/SignIn/SignInButton'; export default function SignIn() { return ( -
+
- - - - - 지금 바로 시작하세요. 🚀 - - - 안정적이고 투명한 고용 관계의 시작, 지금 바로 경험해보세요! - - - + + + + diff --git a/src/pages/auth/SignUp/index.tsx b/src/pages/auth/SignUp/index.tsx index 3ae46c0..112d641 100644 --- a/src/pages/auth/SignUp/index.tsx +++ b/src/pages/auth/SignUp/index.tsx @@ -1,10 +1,13 @@ import { ReactNode, useState } from 'react'; import Layout from '@features/layout'; -import { Flex, Typo, InnerContainer } from '@components/common'; +import { InnerContainer } from '@components/common'; import { responsiveStyle, responsiveSectionPadding } from '@utils/responsive'; -import RoleSelection from '@/features/auth/RoleSelection'; -import RoleModal from '@/features/auth/RoleModal'; +import RoleSelection from '@/features/auth/SignUp/RoleSelection'; +import RoleModal from '@/features/auth/SignUp/components/RoleModal'; import useToggle from '@hooks/useToggle'; +import SignUpText from '@/features/auth/SignUp/SignUpText'; + +const sectionStyle = responsiveStyle(responsiveSectionPadding); export default function SignUp() { const [isToggle, toggle] = useToggle(); @@ -17,48 +20,9 @@ export default function SignUp() { return ( -
+
- - - 가입자 정보 선택 - - - 대상에 해당하는 가입자 정보를 선택해주세요. - - +
diff --git a/src/pages/auth/index.ts b/src/pages/auth/index.ts deleted file mode 100644 index 46ddd03..0000000 --- a/src/pages/auth/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as SignIn } from './SignIn'; -export { default as SignUp } from './SignUp'; diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index 61143ca..7bb9cf1 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -7,12 +7,14 @@ import Employer from '@features/home/Employer'; import RecruitmentHeader from '@features/home/components/RecruitmentHeader'; import RecruitmentList from '@features/home/RecruitmentList'; +const sectionStyle = responsiveStyle(responsiveSectionPadding); + export default function Home() { return ( {/* */} -
+
diff --git a/src/routes/router.tsx b/src/routes/router.tsx index a38be75..6f80f22 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -1,6 +1,7 @@ import { createBrowserRouter } from 'react-router-dom'; import ROUTE_PATH from './path'; -import { SignIn, SignUp } from '@pages/auth'; +import SignIn from '@pages/auth/SignIn'; +import SignUp from '@pages/auth/SignUp'; import App from '@/App'; import Recruit from '@/pages/recruit'; import VisaRegistration from '@/pages/employee/visaRegistration'; From 8355b2574d2db461484139eccd90d392263b5f68 Mon Sep 17 00:00:00 2001 From: Kim Jian <81233665+KimJi-An@users.noreply.github.com> Date: Wed, 16 Oct 2024 20:09:35 +0900 Subject: [PATCH 002/120] =?UTF-8?q?Feat/#42,=20#43=20=EC=A7=80=EC=9B=90?= =?UTF-8?q?=EC=9E=90=20=EB=AA=A9=EB=A1=9D=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=B0=8F=20=ED=8C=9D=EC=97=85=20=EA=B5=AC=ED=98=84=20(#51)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 지원자 목록 페이지 구현 * feat: 지원자 목록 페이지 스토리북 생성 * refactor: ApplicantList 테이블 컴포넌트 분리 * feat: Applicants path 설정 * feat: 지원자 목록 페이지에 계약 관련 팝업 추가 * fix: 이미지 경로 수정 및 불필요한 태그 제거 --- package-lock.json | 11 +- src/assets/icons/recruitmentInfo/area.svg | 4 + src/assets/icons/recruitmentInfo/salary.svg | 11 ++ .../CompanyInfo => assets/images}/coupang.png | Bin .../ApplicantList/ApplicantsTable.tsx | 134 +++++++++++++++++ .../ApplicantList/ContractModal/ModalText.tsx | 50 +++++++ .../ApplicantList/ContractModal/index.tsx | 52 +++++++ .../applicants/ApplicantList/index.tsx | 31 ++++ .../applicants/RecruitmentInfo/index.tsx | 139 ++++++++++++++++++ src/features/employer/CompanyInfo/index.tsx | 4 +- src/pages/applicants/index.stories.tsx | 14 ++ src/pages/applicants/index.tsx | 57 +++++++ src/pages/employer/myAccount/index.tsx | 2 +- src/routes/path.ts | 1 + src/routes/router.tsx | 2 + 15 files changed, 499 insertions(+), 13 deletions(-) create mode 100644 src/assets/icons/recruitmentInfo/area.svg create mode 100644 src/assets/icons/recruitmentInfo/salary.svg rename src/{features/employer/CompanyInfo => assets/images}/coupang.png (100%) create mode 100644 src/features/applicants/ApplicantList/ApplicantsTable.tsx create mode 100644 src/features/applicants/ApplicantList/ContractModal/ModalText.tsx create mode 100644 src/features/applicants/ApplicantList/ContractModal/index.tsx create mode 100644 src/features/applicants/ApplicantList/index.tsx create mode 100644 src/features/applicants/RecruitmentInfo/index.tsx create mode 100644 src/pages/applicants/index.stories.tsx create mode 100644 src/pages/applicants/index.tsx diff --git a/package-lock.json b/package-lock.json index 462ba8b..98bf3a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3006,7 +3006,7 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "devOptional": true + "dev": true }, "node_modules/@types/qs": { "version": "6.9.16", @@ -3024,7 +3024,7 @@ "version": "18.3.5", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz", "integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==", - "devOptional": true, + "dev": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -5884,13 +5884,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", - "dev": true, - "peer": true - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/src/assets/icons/recruitmentInfo/area.svg b/src/assets/icons/recruitmentInfo/area.svg new file mode 100644 index 0000000..71ba9d1 --- /dev/null +++ b/src/assets/icons/recruitmentInfo/area.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/recruitmentInfo/salary.svg b/src/assets/icons/recruitmentInfo/salary.svg new file mode 100644 index 0000000..63504a7 --- /dev/null +++ b/src/assets/icons/recruitmentInfo/salary.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/features/employer/CompanyInfo/coupang.png b/src/assets/images/coupang.png similarity index 100% rename from src/features/employer/CompanyInfo/coupang.png rename to src/assets/images/coupang.png diff --git a/src/features/applicants/ApplicantList/ApplicantsTable.tsx b/src/features/applicants/ApplicantList/ApplicantsTable.tsx new file mode 100644 index 0000000..335782a --- /dev/null +++ b/src/features/applicants/ApplicantList/ApplicantsTable.tsx @@ -0,0 +1,134 @@ +import { palettes } from '@/assets/styles/global/palettes'; +import { Button, Flex, List } from '@/components/common'; +import { responsiveStyle } from '@/utils/responsive'; +import { css } from '@emotion/react'; +import styled from '@emotion/styled'; +import { useState } from 'react'; +import ContractModal from './ContractModal'; + +interface ApplicantProps { + userId: number; + name: string; + resumeId: number; + applyId: number; + applicantNation: string; + korean: string; +} + +interface ApplicantsTableProps { + applicantList: ApplicantProps[]; +} + +export default function ApplicantsTable({ applicantList }: ApplicantsTableProps) { + const [isModalOpen, setIsModalOpen] = useState(false); + + const handleOpenModal = () => { + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + }; + + return ( + <> + + + + + + + + + + + ( + + + + + + + )} + /> + +
이름국적한국어 실력
{applicant.name}{applicant.applicantNation}{applicant.korean} + + + + + +
+ + + ); +} + +const Table = styled.table` + ${responsiveStyle({ + default: { + width: '100%', + fontSize: '16px', + borderCollapse: 'collapse', + wordWrap: 'break-word', + }, + tablet: { + fontSize: '15px', + }, + })} +`; + +const Th = styled.th` + padding: 10px 30px; + background-color: ${palettes.backgroundGray}; + border: none; + border-top: 1px solid ${palettes.black}; + border-bottom: 1px solid ${palettes.black}; + text-align: left; +`; + +const Td = styled.td` + padding: 20px 30px; + border: none; + border-bottom: 1px solid ${palettes.borderGray}; + text-align: left; +`; + +const buttonsCellStyle = css` + ${responsiveStyle({ + default: { + width: '600px', + }, + tablet: { + width: '280px', + }, + mobile: { + width: '200px', + }, + })} +`; + +const buttonGroupStyle = css` + ${responsiveStyle({ + tablet: { + flexDirection: 'column', + alignItems: 'stretch', + gap: '10px', + }, + })} +`; + +const buttonStyle = css` + ${responsiveStyle({ + default: { + whiteSpace: 'nowrap', + }, + mobile: { + fontSize: '15px', + }, + })} +`; diff --git a/src/features/applicants/ApplicantList/ContractModal/ModalText.tsx b/src/features/applicants/ApplicantList/ContractModal/ModalText.tsx new file mode 100644 index 0000000..fccf6e7 --- /dev/null +++ b/src/features/applicants/ApplicantList/ContractModal/ModalText.tsx @@ -0,0 +1,50 @@ +import { palettes } from '@/assets/styles/global/palettes'; +import { Typo } from '@/components/common'; + +interface ForeignerInfoProps { + foreignerIdNumber: string; + visaGenerateDate: string; +} + +export default function ModalText({ foreignerIdNumber, visaGenerateDate }: ForeignerInfoProps) { + return ( + <> + + ✅ 고용주님께 드리는 주의사항 + + + 불법 체류자를 고용할 시 최대 200만원의 범칙금이 부과될 수 있습니다. + +
+ + 지원자 정보 + + + 외국인 등록 번호 : {foreignerIdNumber} +
+ 비자 발급 일자 : {visaGenerateDate} +
+
이 지원자의 정보를 활용하여  + + 하이코리아 + + 에서 지원자에 대한 +
+ 불법 체류 여부를 검증할 수 있습니다. +
+
+ 안전한 고용을 위해 확인 후 진행하는 것을 권장합니다. +
+ + ); +} + +const titleStyle = { + fontWeight: 'bold', + marginBottom: '20px', +}; diff --git a/src/features/applicants/ApplicantList/ContractModal/index.tsx b/src/features/applicants/ApplicantList/ContractModal/index.tsx new file mode 100644 index 0000000..7eb2d9a --- /dev/null +++ b/src/features/applicants/ApplicantList/ContractModal/index.tsx @@ -0,0 +1,52 @@ +import { Button, Flex, Icon, Modal, Typo } from '@/components/common'; +import ModalText from './ModalText'; +import { css } from '@emotion/react'; +import { palettes } from '@/assets/styles/global/palettes'; + +const initialData = { + foreignerIdNumber: '123456-1234567', + visaGenerateDate: '2000-00-00', + visaExpiryDate: '2000-00-00', +}; + +interface ContractModalProps { + isOpen: boolean; + onClose: () => void; +} + +export default function ContractModal({ isOpen, onClose }: ContractModalProps) { + return ( + <> + {isOpen && ( + + } + buttonChildren={ + + + + + } + onClose={onClose} + style={{ padding: '15px' }} + /> + )} + + ); +} + +const customButtonStyle = css` + background-color: ${palettes.blue}; + color: ${palettes.white}; +`; diff --git a/src/features/applicants/ApplicantList/index.tsx b/src/features/applicants/ApplicantList/index.tsx new file mode 100644 index 0000000..24ebdb9 --- /dev/null +++ b/src/features/applicants/ApplicantList/index.tsx @@ -0,0 +1,31 @@ +import { Flex, Typo } from '@/components/common'; +import ApplicantsTable from './ApplicantsTable'; + +interface ApplicantProps { + userId: number; + name: string; + resumeId: number; + applyId: number; + applicantNation: string; + korean: string; +} + +interface ApplicantListProps { + applicantList: ApplicantProps[]; +} + +export default function ApplicantList({ applicantList }: ApplicantListProps) { + return ( + + + + 지원자 목록 + + + 총 {applicantList.length}건 + + + + + ); +} diff --git a/src/features/applicants/RecruitmentInfo/index.tsx b/src/features/applicants/RecruitmentInfo/index.tsx new file mode 100644 index 0000000..db264f5 --- /dev/null +++ b/src/features/applicants/RecruitmentInfo/index.tsx @@ -0,0 +1,139 @@ +import { Button, Flex, Icon, Image, Typo } from '@/components/common'; +import { responsiveStyle } from '@/utils/responsive'; +import { css } from '@emotion/react'; +import AreaIcon from '@assets/icons/recruitmentInfo/area.svg?react'; +import SalaryIcon from '@assets/icons/recruitmentInfo/salary.svg?react'; +import styled from '@emotion/styled'; +import theme from '@/assets/theme'; +import { palettes } from '@/assets/styles/global/palettes'; + +interface RecruitmentProps { + companyImage: string; + companyName: string; + koreanTitle: string; + area: string; + salary: number; +} + +export default function RecruitmentInfo({ companyImage, companyName, koreanTitle, area, salary }: RecruitmentProps) { + return ( + + + + + + {companyName} + + {koreanTitle} + + + + + {area} + + + + 시급 {salary} + + + + + + ); +} + +const recruitmentFlexStyle = css` + ${responsiveStyle({ + default: { + gap: '100px', + border: `1px solid ${theme.palettes.borderGray}`, + borderRadius: '8px', + padding: '15px 30px', + }, + tablet: { + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + padding: '20px 30px', + gap: '30px', + }, + mobile: { + padding: '30px', + }, + })} +`; + +const ImageWrapper = styled.div` + width: 280px; + height: 120px; +`; + +const imageStyle = css` + height: 100%; + + ${responsiveStyle({ + tablet: { + margin: '0 auto', + width: '50%', + }, + mobile: { + width: '70%', + }, + })} +`; + +const imageSize = { + width: '277px', + height: 'auto', +}; + +const infoFlexStyle = css` + ${responsiveStyle({ + default: { + flexDirection: 'column', + justifyContent: 'space-between', + gap: '10px', + }, + tablet: { + width: '80%', + alignItems: 'center', + }, + mobile: { + gap: '15px', + }, + })} +`; + +const infoGroupStyle = css` + ${responsiveStyle({ + default: { + alignItems: 'center', + gap: '30px', + }, + tablet: { + width: '80%', + gap: '20px', + justifyContent: 'center', + }, + mobile: { + flexDirection: 'column', + gap: '10px', + }, + })} +`; + +const buttonStyle = css` + background-color: ${palettes.blue}; +`; + +const buttonTextStyle = { + fontWeight: '600', + whiteSpace: 'nowrap', +}; diff --git a/src/features/employer/CompanyInfo/index.tsx b/src/features/employer/CompanyInfo/index.tsx index 1d92db4..155ee32 100644 --- a/src/features/employer/CompanyInfo/index.tsx +++ b/src/features/employer/CompanyInfo/index.tsx @@ -47,9 +47,7 @@ export default function CompanyInfo({ company, industryOccupation, brand, revenu 회사 정보 수정하기 -
- -
+ diff --git a/src/pages/applicants/index.stories.tsx b/src/pages/applicants/index.stories.tsx new file mode 100644 index 0000000..3182219 --- /dev/null +++ b/src/pages/applicants/index.stories.tsx @@ -0,0 +1,14 @@ +import { Meta, StoryObj } from '@storybook/react'; +import Applicants from '.'; + +const meta: Meta = { + title: 'pages/Applicants', + component: Applicants, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/pages/applicants/index.tsx b/src/pages/applicants/index.tsx new file mode 100644 index 0000000..398705f --- /dev/null +++ b/src/pages/applicants/index.tsx @@ -0,0 +1,57 @@ +import { Flex, InnerContainer } from '@/components/common'; +import ApplicantList from '@/features/applicants/ApplicantList'; +import RecruitmentsInfo from '@/features/applicants/RecruitmentInfo'; +import Layout from '@/features/layout'; +import styled from '@emotion/styled'; + +const initialRecruitmentData = { + companyImage: 'src/assets/images/coupang.png', + companyName: '쿠팡 유성점', + koreanTitle: '쿠팡 유성점에서 아르바이트 모집합니다.', + area: '대전 유성구', + salary: 50000000, +}; + +const initialApplicantListData = [ + { + userId: 1, + name: '이름1', + resumeId: 1, + applyId: 1, + applicantNation: '베트남', + korean: '중급', + }, + { + userId: 2, + name: '이름2', + resumeId: 2, + applyId: 2, + applicantNation: '베트남', + korean: '고급', + }, +]; + +export default function Applicants() { + return ( + + + + + + + + + + + ); +} + +const MainContainer = styled.div` + padding: 40px 0 80px 0; +`; diff --git a/src/pages/employer/myAccount/index.tsx b/src/pages/employer/myAccount/index.tsx index 2b66591..f37d9a8 100644 --- a/src/pages/employer/myAccount/index.tsx +++ b/src/pages/employer/myAccount/index.tsx @@ -1,5 +1,5 @@ import Layout from '@/features/layout'; -import CompanyLogo from '@/features/employer/CompanyInfo/coupang.png'; +import CompanyLogo from '@assets/images/coupang.png'; import CompanyInfo from '@/features/employer/CompanyInfo'; import styled from '@emotion/styled'; import { Flex, InnerContainer } from '@/components/common'; diff --git a/src/routes/path.ts b/src/routes/path.ts index 2333738..e5fff2b 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -22,6 +22,7 @@ const ROUTE_PATH = { POST_NOTICE: '/post-notice', APPLY, AUTH, + APPLICANTS: '/applicants', EMPLOYER, EMPLOYEE, } as const; diff --git a/src/routes/router.tsx b/src/routes/router.tsx index 6f80f22..6f4b7f4 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -10,6 +10,7 @@ import Home from '@/pages/home'; import ApplyGuide from '@/pages/apply/applyguide/ApplyGuide'; import ApplyPage from '@/pages/apply/applypage/ApplyPage'; import EmployerMyAccount from '@/pages/employer/myAccount'; +import Applicants from '@/pages/applicants'; export const router = createBrowserRouter([ { @@ -30,6 +31,7 @@ export const router = createBrowserRouter([ { path: ROUTE_PATH.EMPLOYEE.VISA_REGISTRATION, element: }, { path: ROUTE_PATH.POST_NOTICE, element: }, { path: ROUTE_PATH.EMPLOYER.MY_ACCOUNT, element: }, + { path: ROUTE_PATH.APPLICANTS, element: }, ], }, ]); From 89d90656ebd93382a7b2c6c7d100e97d3e89667e Mon Sep 17 00:00:00 2001 From: KimJi-An Date: Thu, 17 Oct 2024 00:01:23 +0900 Subject: [PATCH 003/120] =?UTF-8?q?refactor:=20MyAccount=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20CompanyRecruitments=EB=A1=9C=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 MyAccount 페이지를 CompanyRecruitments로 이름 변경 - 새로운 MyAccount 페이지 구현을 위해 기존 페이지의 역할 변경 --- .../CompanyInfo/index.tsx | 0 .../MyRecruitments/index.tsx | 0 src/pages/companyRecruitments/index.stories.tsx | 14 ++++++++++++++ .../myAccount => companyRecruitments}/index.tsx | 6 +++--- src/pages/employer/myAccount/index.stories.tsx | 14 -------------- src/routes/path.ts | 6 +----- src/routes/router.tsx | 4 ++-- 7 files changed, 20 insertions(+), 24 deletions(-) rename src/features/{employer => companyRecruitments}/CompanyInfo/index.tsx (100%) rename src/features/{employer => companyRecruitments}/MyRecruitments/index.tsx (100%) create mode 100644 src/pages/companyRecruitments/index.stories.tsx rename src/pages/{employer/myAccount => companyRecruitments}/index.tsx (88%) delete mode 100644 src/pages/employer/myAccount/index.stories.tsx diff --git a/src/features/employer/CompanyInfo/index.tsx b/src/features/companyRecruitments/CompanyInfo/index.tsx similarity index 100% rename from src/features/employer/CompanyInfo/index.tsx rename to src/features/companyRecruitments/CompanyInfo/index.tsx diff --git a/src/features/employer/MyRecruitments/index.tsx b/src/features/companyRecruitments/MyRecruitments/index.tsx similarity index 100% rename from src/features/employer/MyRecruitments/index.tsx rename to src/features/companyRecruitments/MyRecruitments/index.tsx diff --git a/src/pages/companyRecruitments/index.stories.tsx b/src/pages/companyRecruitments/index.stories.tsx new file mode 100644 index 0000000..e539b2c --- /dev/null +++ b/src/pages/companyRecruitments/index.stories.tsx @@ -0,0 +1,14 @@ +import { Meta, StoryObj } from '@storybook/react'; +import CompanyRecruitments from '.'; + +const meta: Meta = { + title: 'pages/CompanyRecruitments', + component: CompanyRecruitments, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/pages/employer/myAccount/index.tsx b/src/pages/companyRecruitments/index.tsx similarity index 88% rename from src/pages/employer/myAccount/index.tsx rename to src/pages/companyRecruitments/index.tsx index f37d9a8..88223d9 100644 --- a/src/pages/employer/myAccount/index.tsx +++ b/src/pages/companyRecruitments/index.tsx @@ -1,9 +1,9 @@ import Layout from '@/features/layout'; import CompanyLogo from '@assets/images/coupang.png'; -import CompanyInfo from '@/features/employer/CompanyInfo'; +import CompanyInfo from '@/features/companyRecruitments/CompanyInfo'; import styled from '@emotion/styled'; import { Flex, InnerContainer } from '@/components/common'; -import MyRecruitments from '@/features/employer/MyRecruitments'; +import MyRecruitments from '@/features/companyRecruitments/MyRecruitments'; const initialCompanyData = { company: '쿠팡 유성점', @@ -31,7 +31,7 @@ const initialRecruitmentsData = [ }, ]; -export default function EmployerMyAccount() { +export default function CompanyRecruitments() { return ( diff --git a/src/pages/employer/myAccount/index.stories.tsx b/src/pages/employer/myAccount/index.stories.tsx deleted file mode 100644 index a89a309..0000000 --- a/src/pages/employer/myAccount/index.stories.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import EmployerMyAccount from '../../employer/myAccount'; - -const meta: Meta = { - title: 'pages/Employer/MyAccount', - component: EmployerMyAccount, - tags: ['autodocs'], -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = {}; diff --git a/src/routes/path.ts b/src/routes/path.ts index e5fff2b..c02eaf1 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -8,10 +8,6 @@ export const APPLY = { APPLYPAGE: '/apply', }; -export const EMPLOYER = { - MY_ACCOUNT: '/employer-my-account', -} as const; - export const EMPLOYEE = { VISA_REGISTRATION: '/visa-registration', } as const; @@ -23,7 +19,7 @@ const ROUTE_PATH = { APPLY, AUTH, APPLICANTS: '/applicants', - EMPLOYER, + COMPANY_RECRUITMENTS: '/company-recruitments', EMPLOYEE, } as const; diff --git a/src/routes/router.tsx b/src/routes/router.tsx index 6f4b7f4..c7f9d2b 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -9,7 +9,7 @@ import PostNotice from '@/pages/employer/postNotice/PostNotice'; import Home from '@/pages/home'; import ApplyGuide from '@/pages/apply/applyguide/ApplyGuide'; import ApplyPage from '@/pages/apply/applypage/ApplyPage'; -import EmployerMyAccount from '@/pages/employer/myAccount'; +import CompanyRecruitments from '@/pages/companyRecruitments'; import Applicants from '@/pages/applicants'; export const router = createBrowserRouter([ @@ -30,7 +30,7 @@ export const router = createBrowserRouter([ { path: ROUTE_PATH.RECRUIT, element: }, { path: ROUTE_PATH.EMPLOYEE.VISA_REGISTRATION, element: }, { path: ROUTE_PATH.POST_NOTICE, element: }, - { path: ROUTE_PATH.EMPLOYER.MY_ACCOUNT, element: }, + { path: ROUTE_PATH.COMPANY_RECRUITMENTS, element: }, { path: ROUTE_PATH.APPLICANTS, element: }, ], }, From 55ba78b28545aa7a2e2723569c8ab834ee49a22c Mon Sep 17 00:00:00 2001 From: KimJi-An Date: Thu, 17 Oct 2024 00:09:23 +0900 Subject: [PATCH 004/120] =?UTF-8?q?refactor:=20visaRegistration=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=ED=8C=8C=EC=9D=BC=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - visaRegistration 페이지를 src/pages/employee에서 src/pages로 이동 - 관련 기능을 src/features/employee/visaRegistration에서 src/features/visaRegistration으로 이동 --- src/features/{employee => }/visaRegistration/index.tsx | 0 src/pages/{employee => }/visaRegistration/index.stories.tsx | 0 src/pages/{employee => }/visaRegistration/index.tsx | 2 +- src/routes/path.ts | 6 +----- src/routes/router.tsx | 4 ++-- 5 files changed, 4 insertions(+), 8 deletions(-) rename src/features/{employee => }/visaRegistration/index.tsx (100%) rename src/pages/{employee => }/visaRegistration/index.stories.tsx (100%) rename src/pages/{employee => }/visaRegistration/index.tsx (94%) diff --git a/src/features/employee/visaRegistration/index.tsx b/src/features/visaRegistration/index.tsx similarity index 100% rename from src/features/employee/visaRegistration/index.tsx rename to src/features/visaRegistration/index.tsx diff --git a/src/pages/employee/visaRegistration/index.stories.tsx b/src/pages/visaRegistration/index.stories.tsx similarity index 100% rename from src/pages/employee/visaRegistration/index.stories.tsx rename to src/pages/visaRegistration/index.stories.tsx diff --git a/src/pages/employee/visaRegistration/index.tsx b/src/pages/visaRegistration/index.tsx similarity index 94% rename from src/pages/employee/visaRegistration/index.tsx rename to src/pages/visaRegistration/index.tsx index 4258d59..4ead089 100644 --- a/src/pages/employee/visaRegistration/index.tsx +++ b/src/pages/visaRegistration/index.tsx @@ -1,7 +1,7 @@ import { responsiveStyle } from '@utils/responsive'; import { Flex, InnerContainer } from '@/components/common'; import Layout from '@/features/layout'; -import VisaRegistrationForm from '@/features/employee/visaRegistration'; +import VisaRegistrationForm from '@/features/visaRegistration'; import styled from '@emotion/styled'; export default function VisaRegistration() { diff --git a/src/routes/path.ts b/src/routes/path.ts index c02eaf1..a72846b 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -8,10 +8,6 @@ export const APPLY = { APPLYPAGE: '/apply', }; -export const EMPLOYEE = { - VISA_REGISTRATION: '/visa-registration', -} as const; - const ROUTE_PATH = { HOME: '/', RECRUIT: '/recruit', @@ -20,7 +16,7 @@ const ROUTE_PATH = { AUTH, APPLICANTS: '/applicants', COMPANY_RECRUITMENTS: '/company-recruitments', - EMPLOYEE, + VISA_REGISTRATION: '/visa-registration', } as const; export default ROUTE_PATH; diff --git a/src/routes/router.tsx b/src/routes/router.tsx index c7f9d2b..88d9b0b 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -4,7 +4,7 @@ import SignIn from '@pages/auth/SignIn'; import SignUp from '@pages/auth/SignUp'; import App from '@/App'; import Recruit from '@/pages/recruit'; -import VisaRegistration from '@/pages/employee/visaRegistration'; +import VisaRegistration from '@/pages/visaRegistration'; import PostNotice from '@/pages/employer/postNotice/PostNotice'; import Home from '@/pages/home'; import ApplyGuide from '@/pages/apply/applyguide/ApplyGuide'; @@ -28,7 +28,7 @@ export const router = createBrowserRouter([ { path: ROUTE_PATH.APPLY.GUIDE, element: }, { path: ROUTE_PATH.APPLY.APPLYPAGE, element: }, { path: ROUTE_PATH.RECRUIT, element: }, - { path: ROUTE_PATH.EMPLOYEE.VISA_REGISTRATION, element: }, + { path: ROUTE_PATH.VISA_REGISTRATION, element: }, { path: ROUTE_PATH.POST_NOTICE, element: }, { path: ROUTE_PATH.COMPANY_RECRUITMENTS, element: }, { path: ROUTE_PATH.APPLICANTS, element: }, From 8923cea3fe723a5a3f9490462964e52f51ac1996 Mon Sep 17 00:00:00 2001 From: KimJi-An Date: Thu, 17 Oct 2024 23:38:37 +0900 Subject: [PATCH 005/120] =?UTF-8?q?feat:=20Table=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Table/index.stories.tsx | 38 +++++++++++++++++++ src/components/common/Table/index.style.ts | 33 ++++++++++++++++ src/components/common/Table/index.tsx | 38 +++++++++++++++++++ src/components/common/index.ts | 1 + 4 files changed, 110 insertions(+) create mode 100644 src/components/common/Table/index.stories.tsx create mode 100644 src/components/common/Table/index.style.ts create mode 100644 src/components/common/Table/index.tsx diff --git a/src/components/common/Table/index.stories.tsx b/src/components/common/Table/index.stories.tsx new file mode 100644 index 0000000..19a068e --- /dev/null +++ b/src/components/common/Table/index.stories.tsx @@ -0,0 +1,38 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Table, Td, Th } from '.'; + +const meta: Meta = { + title: 'common/Table', + component: Table, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: (args) => ( + + + + + + + + + + + + + + + + + + + + +
heading 1heading 2heading 3
data 1data 2data 3
data 4data 5data 6
+ ), +}; diff --git a/src/components/common/Table/index.style.ts b/src/components/common/Table/index.style.ts new file mode 100644 index 0000000..163f117 --- /dev/null +++ b/src/components/common/Table/index.style.ts @@ -0,0 +1,33 @@ +import { palettes } from '@/assets/styles/global/palettes'; +import { responsiveStyle } from '@/utils/responsive'; +import { css } from '@emotion/react'; + +export const TableStyle = css` + ${responsiveStyle({ + default: { + width: '100%', + fontSize: '16px', + borderCollapse: 'collapse', + wordWrap: 'break-word', + }, + tablet: { + fontSize: '15px', + }, + })} +`; + +export const ThStyle = css` + padding: 10px 30px; + background-color: ${palettes.backgroundGray}; + border: none; + border-top: 1px solid ${palettes.black}; + border-bottom: 1px solid ${palettes.black}; + text-align: left; +`; + +export const TdStyle = css` + padding: 20px 30px; + border: none; + border-bottom: 1px solid ${palettes.borderGray}; + text-align: left; +`; diff --git a/src/components/common/Table/index.tsx b/src/components/common/Table/index.tsx new file mode 100644 index 0000000..b7654c1 --- /dev/null +++ b/src/components/common/Table/index.tsx @@ -0,0 +1,38 @@ +import { HTMLAttributes, ReactNode } from 'react'; +import { TableStyle, TdStyle, ThStyle } from './index.style'; + +type TableProps = { + children: ReactNode; +} & HTMLAttributes; + +type ThProps = { + children: ReactNode; +} & HTMLAttributes; + +type TdProps = { + children: ReactNode; +} & HTMLAttributes; + +export function Table({ children, ...rest }: TableProps) { + return ( + + {children} +
+ ); +} + +export function Th({ children, ...rest }: ThProps) { + return ( + + {children} + + ); +} + +export function Td({ children, ...rest }: TdProps) { + return ( + + {children} + + ); +} diff --git a/src/components/common/index.ts b/src/components/common/index.ts index cfae363..e59168c 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -8,3 +8,4 @@ export { default as Typo } from './Typo'; export { default as Icon } from './Icon'; export { default as List } from './List'; export { default as Image } from './Image'; +export { Table, Th, Td } from './Table'; From 88e063acfd78d3c92a66b0641abf1a91e32b4e23 Mon Sep 17 00:00:00 2001 From: KimJi-An Date: Fri, 18 Oct 2024 00:00:15 +0900 Subject: [PATCH 006/120] =?UTF-8?q?feat:=20=EB=B3=80=EA=B2=BD=EB=90=9C=20?= =?UTF-8?q?=EA=B3=A0=EC=9A=A9=EC=A3=BC=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/arrow/big-right-blue.svg | 3 + src/components/common/Icon/Arrow.ts | 2 + .../CompanyList/CompaniesTable.tsx | 89 +++++++++++++++++++ .../MyCompanies/CompanyList/index.tsx | 31 +++++++ src/pages/companyRecruitments/index.tsx | 2 +- .../myAccount/employer/index.stories.tsx | 14 +++ src/pages/myAccount/employer/index.tsx | 44 +++++++++ src/types/index.d.ts | 9 ++ 8 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/assets/icons/arrow/big-right-blue.svg create mode 100644 src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx create mode 100644 src/features/myAccount/employer/MyCompanies/CompanyList/index.tsx create mode 100644 src/pages/myAccount/employer/index.stories.tsx create mode 100644 src/pages/myAccount/employer/index.tsx diff --git a/src/assets/icons/arrow/big-right-blue.svg b/src/assets/icons/arrow/big-right-blue.svg new file mode 100644 index 0000000..6fdba45 --- /dev/null +++ b/src/assets/icons/arrow/big-right-blue.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/common/Icon/Arrow.ts b/src/components/common/Icon/Arrow.ts index e7a5bcd..1a7d62a 100644 --- a/src/components/common/Icon/Arrow.ts +++ b/src/components/common/Icon/Arrow.ts @@ -1,9 +1,11 @@ import RightWhite from '@assets/icons/arrow/right-white.svg?react'; import RightBlue from '@assets/icons/arrow/right-blue.svg?react'; +import BigRightBlue from '@assets/icons/arrow/big-right-blue.svg?react'; const Arrow = { RightWhite, RightBlue, + BigRightBlue, }; export default Arrow; diff --git a/src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx b/src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx new file mode 100644 index 0000000..0d132c8 --- /dev/null +++ b/src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx @@ -0,0 +1,89 @@ +import { Button, Flex, Icon, List, Typo, Image, Table, Th, Td } from '@/components/common'; +import { responsiveStyle } from '@/utils/responsive'; +import IndustryIcon from '@assets/icons/companyInfo/industry.svg?react'; +import BrandIcon from '@assets/icons/companyInfo/brand.svg?react'; +import RevenueIcon from '@assets/icons/companyInfo/revenue.svg?react'; +import { CompanyItem } from '@/types'; +import { css } from '@emotion/react'; + +type Props = { + companyList: CompanyItem[]; +}; + +export default function CompaniesTable({ companyList }: Props) { + return ( + + + + + + + + + ( + + + + + )} + /> + +
이미지회사 정보
+ + + + + + {company.name} + + + + + + {company.industryOccupation} + + + + + + {company.brand} + + + + + + {company.revenuePerYear} 원 + + + + + + +
+ ); +} + +const infoGroupStyle = css` + ${responsiveStyle({ + tablet: { + flexDirection: 'row', + justifyContent: 'center', + width: '80%', + gap: '20px', + }, + mobile: { + flexDirection: 'column', + alignItems: 'center', + gap: '10px', + }, + })} +`; + +const infoStyle = { + color: '#474C54', + whiteSpace: 'nowrap', +}; diff --git a/src/features/myAccount/employer/MyCompanies/CompanyList/index.tsx b/src/features/myAccount/employer/MyCompanies/CompanyList/index.tsx new file mode 100644 index 0000000..4f207d7 --- /dev/null +++ b/src/features/myAccount/employer/MyCompanies/CompanyList/index.tsx @@ -0,0 +1,31 @@ +import { Flex, Typo } from '@/components/common'; +import CompaniesTable from './CompaniesTable'; + +interface MyCompanyProps { + id: number; + name: string; + industryOccupation: string; + brand: string; + revenuePerYear: number; + logoImage: string; +} + +interface MyCompanyListProps { + companyList: MyCompanyProps[]; +} + +export default function CompanyList({ companyList }: MyCompanyListProps) { + return ( + + + + 내 회사 + + + 총 {companyList.length}곳 + + + + + ); +} diff --git a/src/pages/companyRecruitments/index.tsx b/src/pages/companyRecruitments/index.tsx index 88223d9..3a403dc 100644 --- a/src/pages/companyRecruitments/index.tsx +++ b/src/pages/companyRecruitments/index.tsx @@ -53,5 +53,5 @@ export default function CompanyRecruitments() { } const MainContainer = styled.div` - padding: 60px 0; + padding: 60px; `; diff --git a/src/pages/myAccount/employer/index.stories.tsx b/src/pages/myAccount/employer/index.stories.tsx new file mode 100644 index 0000000..3f5ba5d --- /dev/null +++ b/src/pages/myAccount/employer/index.stories.tsx @@ -0,0 +1,14 @@ +import { Meta, StoryObj } from '@storybook/react'; +import EmployerMyAccount from '.'; + +const meta: Meta = { + title: 'pages/MyAccount/Employer', + component: EmployerMyAccount, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/pages/myAccount/employer/index.tsx b/src/pages/myAccount/employer/index.tsx new file mode 100644 index 0000000..48050b1 --- /dev/null +++ b/src/pages/myAccount/employer/index.tsx @@ -0,0 +1,44 @@ +import { Flex, InnerContainer, Typo } from '@/components/common'; +import Layout from '@/features/layout'; +import CompanyList from '@/features/myAccount/employer/MyCompanies/CompanyList'; +import styled from '@emotion/styled'; + +const initialData = [ + { + id: 1, + name: '쿠팡 유성점', + industryOccupation: '온라인 소매', + brand: '쿠팡', + revenuePerYear: 1000000, + logoImage: 'src/assets/images/coupang.png', + }, + { + id: 2, + name: '쿠팡 유성점', + industryOccupation: '온라인 소매', + brand: '쿠팡', + revenuePerYear: 1000000, + logoImage: 'src/assets/images/coupang.png', + }, +]; + +export default function EmployerMyAccount() { + return ( + + + + + + 사장님, 안녕하세요! + + + + + + + ); +} + +const MainContainer = styled.div` + padding: 60px 0; +`; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index af7a4dd..d6cdc8b 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -13,3 +13,12 @@ export type RecruitmentItem = { workHours: string; area: string; }; + +export type CompanyItem = { + id: number; + name: string; + industryOccupation: string; + brand: string; + revenuePerYear: number; + logoImage: string; +}; From 073a3890ba7e106f6e8cd060485958c10f0043e8 Mon Sep 17 00:00:00 2001 From: KimJi-An Date: Fri, 18 Oct 2024 01:49:29 +0900 Subject: [PATCH 007/120] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=82=AC=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B3=B5=ED=86=B5=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9D=84=20features/companies=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EB=B0=8F=20CompanyInfo=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../companies/CompanyInfo/index.styles.ts | 38 +++++ src/features/companies/CompanyInfo/index.tsx | 32 +++++ .../MyRecruitments/index.tsx | 0 .../companyRecruitments/CompanyInfo/index.tsx | 136 ------------------ .../CompanyList/CompaniesTable.tsx | 60 ++------ src/pages/companyRecruitments/index.mock.ts | 27 ++++ src/pages/companyRecruitments/index.styles.ts | 40 ++++++ src/pages/companyRecruitments/index.tsx | 72 ++++------ 8 files changed, 172 insertions(+), 233 deletions(-) create mode 100644 src/features/companies/CompanyInfo/index.styles.ts create mode 100644 src/features/companies/CompanyInfo/index.tsx rename src/features/{companyRecruitments => companies}/MyRecruitments/index.tsx (100%) delete mode 100644 src/features/companyRecruitments/CompanyInfo/index.tsx create mode 100644 src/pages/companyRecruitments/index.mock.ts create mode 100644 src/pages/companyRecruitments/index.styles.ts diff --git a/src/features/companies/CompanyInfo/index.styles.ts b/src/features/companies/CompanyInfo/index.styles.ts new file mode 100644 index 0000000..3f2a71d --- /dev/null +++ b/src/features/companies/CompanyInfo/index.styles.ts @@ -0,0 +1,38 @@ +import { responsiveStyle } from '@/utils/responsive'; +import { css } from '@emotion/react'; + +export const infoWrapperStyle = css` + ${responsiveStyle({ + default: { + maxWidth: '60%', + flexDirection: 'column', + justifyContent: 'space-between', + gap: '15px', + }, + tablet: { + alignItems: 'center', + margin: '10px 0 20px 0', + width: '70%', + }, + })} +`; + +export const infoStyle = css` + ${responsiveStyle({ + default: { + alignItems: 'center', + gap: '30px', + }, + tablet: { + flexDirection: 'row', + justifyContent: 'center', + width: '80%', + gap: '20px', + }, + mobile: { + flexDirection: 'column', + alignItems: 'center', + gap: '10px', + }, + })} +`; diff --git a/src/features/companies/CompanyInfo/index.tsx b/src/features/companies/CompanyInfo/index.tsx new file mode 100644 index 0000000..fd5f37f --- /dev/null +++ b/src/features/companies/CompanyInfo/index.tsx @@ -0,0 +1,32 @@ +import { Flex, Typo } from '@/components/common'; +import { CompanyItem } from '@/types'; +import IndustryIcon from '@assets/icons/companyInfo/industry.svg?react'; +import BrandIcon from '@assets/icons/companyInfo/brand.svg?react'; +import RevenueIcon from '@assets/icons/companyInfo/revenue.svg?react'; +import { infoStyle, infoWrapperStyle } from './index.styles'; + +type Props = Pick; + +export default function CompanyInfo({ name, industryOccupation, brand, revenuePerYear }: Props) { + return ( + + + {name} + + + + + {industryOccupation} + + + + {brand} + + + + {revenuePerYear} 원 + + + + ); +} diff --git a/src/features/companyRecruitments/MyRecruitments/index.tsx b/src/features/companies/MyRecruitments/index.tsx similarity index 100% rename from src/features/companyRecruitments/MyRecruitments/index.tsx rename to src/features/companies/MyRecruitments/index.tsx diff --git a/src/features/companyRecruitments/CompanyInfo/index.tsx b/src/features/companyRecruitments/CompanyInfo/index.tsx deleted file mode 100644 index 155ee32..0000000 --- a/src/features/companyRecruitments/CompanyInfo/index.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { Button, Flex, Typo, Icon } from '@/components/common'; -import styled from '@emotion/styled'; -import IndustryIcon from '@assets/icons/companyInfo/industry.svg?react'; -import BrandIcon from '@assets/icons/companyInfo/brand.svg?react'; -import RevenueIcon from '@assets/icons/companyInfo/revenue.svg?react'; -import { responsiveStyle } from '@utils/responsive'; - -interface CompanyInfoProps { - company: string; - industryOccupation: string; - brand: string; - revenuePerYear: string; - logo: string; -} - -export default function CompanyInfo({ company, industryOccupation, brand, revenuePerYear, logo }: CompanyInfoProps) { - return ( - - - - - {company} - - - - - - {industryOccupation} - - - - - - {brand} - - - - - - {revenuePerYear} 원 - - - - - - - ); -} - -const CompanyFlex = styled(Flex)` - ${responsiveStyle({ - default: { - justifyContent: 'space-between', - alignItems: 'center', - gap: '100px', - }, - tablet: { - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - gap: '15px', - }, - mobile: { - flexDirection: 'column', - }, - })} -`; - -const Logo = styled.img` - width: 280px; - height: auto; - - ${responsiveStyle({ - tablet: { - margin: '0 auto', - width: '50%', - }, - mobile: { - width: '70%', - }, - })} -`; - -const InfoFlex = styled(Flex)` - ${responsiveStyle({ - default: { - flexDirection: 'column', - justifyContent: 'space-between', - gap: '10px', - }, - tablet: { - alignItems: 'center', - margin: '10px 0 20px 0', - width: '70%', - }, - })} -`; - -const InfoGroup = styled(Flex)` - ${responsiveStyle({ - default: { - alignItems: 'center', - gap: '30px', - }, - tablet: { - flexDirection: 'row', - justifyContent: 'center', - width: '80%', - gap: '20px', - }, - mobile: { - flexDirection: 'column', - alignItems: 'center', - gap: '10px', - }, - })} -`; - -const infoStyle = { - color: '#474C54', - whiteSpace: 'nowrap', -}; - -const customButtonStyle = { - backgroundColor: '#0A65CC', - color: '#fff', - borderRadius: '4px', - whiteSpace: 'nowrap', -}; diff --git a/src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx b/src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx index 0d132c8..8d95628 100644 --- a/src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx +++ b/src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx @@ -1,10 +1,6 @@ -import { Button, Flex, Icon, List, Typo, Image, Table, Th, Td } from '@/components/common'; -import { responsiveStyle } from '@/utils/responsive'; -import IndustryIcon from '@assets/icons/companyInfo/industry.svg?react'; -import BrandIcon from '@assets/icons/companyInfo/brand.svg?react'; -import RevenueIcon from '@assets/icons/companyInfo/revenue.svg?react'; +import { Button, Flex, Icon, List, Image, Table, Th, Td } from '@/components/common'; import { CompanyItem } from '@/types'; -import { css } from '@emotion/react'; +import CompanyInfo from '@/features/companies/CompanyInfo'; type Props = { companyList: CompanyItem[]; @@ -29,31 +25,12 @@ export default function CompaniesTable({ companyList }: Props) { - - - {company.name} - - - - - - {company.industryOccupation} - - - - - - {company.brand} - - - - - - {company.revenuePerYear} 원 - - - - + @@ -66,24 +43,3 @@ export default function CompaniesTable({ companyList }: Props) { ); } - -const infoGroupStyle = css` - ${responsiveStyle({ - tablet: { - flexDirection: 'row', - justifyContent: 'center', - width: '80%', - gap: '20px', - }, - mobile: { - flexDirection: 'column', - alignItems: 'center', - gap: '10px', - }, - })} -`; - -const infoStyle = { - color: '#474C54', - whiteSpace: 'nowrap', -}; diff --git a/src/pages/companyRecruitments/index.mock.ts b/src/pages/companyRecruitments/index.mock.ts new file mode 100644 index 0000000..4d093af --- /dev/null +++ b/src/pages/companyRecruitments/index.mock.ts @@ -0,0 +1,27 @@ +import CompanyLogo from '@assets/images/coupang.png'; + +export const company = { + name: '쿠팡 유성점', + industryOccupation: '온라인 소매', + brand: '쿠팡', + revenuePerYear: 10000000, + logoImage: CompanyLogo, +}; + +export const recruitments = [ + { + koreanTitle: '제목1', + area: '대전 유성구', + koreanDetailedDescription: '쿠팡 유성점에서 아르바이트 모집합니다.', + }, + { + koreanTitle: '제목2', + area: '대전 유성구', + koreanDetailedDescription: '쿠팡 유성점에서 아르바이트 모집합니다.', + }, + { + koreanTitle: '제목3', + area: '대전 유성구', + koreanDetailedDescription: '쿠팡 유성점에서 아르바이트 모집합니다.', + }, +]; diff --git a/src/pages/companyRecruitments/index.styles.ts b/src/pages/companyRecruitments/index.styles.ts new file mode 100644 index 0000000..76d00d9 --- /dev/null +++ b/src/pages/companyRecruitments/index.styles.ts @@ -0,0 +1,40 @@ +import { palettes } from '@/assets/styles/global/palettes'; +import { responsiveStyle } from '@/utils/responsive'; +import { css } from '@emotion/react'; + +export const companyWrapperStyle = css` + ${responsiveStyle({ + tablet: { + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + gap: '15px', + }, + mobile: { + flexDirection: 'column', + }, + })} +`; + +export const imageStyle = css` + ${responsiveStyle({ + default: { + width: '280px', + height: 'auto', + }, + tablet: { + margin: '0 auto', + width: '50%', + }, + mobile: { + width: '70%', + }, + })} +`; + +export const buttonStyle = css` + background-color: ${palettes.blue}; + color: ${palettes.white}; + border-radius: 4px; + white-space: nowrap; +`; diff --git a/src/pages/companyRecruitments/index.tsx b/src/pages/companyRecruitments/index.tsx index 3a403dc..12edaf8 100644 --- a/src/pages/companyRecruitments/index.tsx +++ b/src/pages/companyRecruitments/index.tsx @@ -1,57 +1,39 @@ import Layout from '@/features/layout'; +import { Flex, InnerContainer, Image, Typo, Button, Icon } from '@/components/common'; import CompanyLogo from '@assets/images/coupang.png'; -import CompanyInfo from '@/features/companyRecruitments/CompanyInfo'; -import styled from '@emotion/styled'; -import { Flex, InnerContainer } from '@/components/common'; -import MyRecruitments from '@/features/companyRecruitments/MyRecruitments'; - -const initialCompanyData = { - company: '쿠팡 유성점', - industryOccupation: '온라인 소매', - brand: '쿠팡', - revenuePerYear: '15조', - logo: CompanyLogo, -}; - -const initialRecruitmentsData = [ - { - koreanTitle: '제목1', - area: '대전 유성구', - koreanDetailedDescription: '쿠팡 유성점에서 아르바이트 모집합니다.', - }, - { - koreanTitle: '제목2', - area: '대전 유성구', - koreanDetailedDescription: '쿠팡 유성점에서 아르바이트 모집합니다.', - }, - { - koreanTitle: '제목3', - area: '대전 유성구', - koreanDetailedDescription: '쿠팡 유성점에서 아르바이트 모집합니다.', - }, -]; +import CompanyInfo from '@/features/companies/CompanyInfo'; +import MyRecruitments from '@/features/companies/MyRecruitments'; +import { company, recruitments } from '@/pages/companyRecruitments/index.mock'; +import { palettes } from '@/assets/styles/global/palettes'; +import { buttonStyle, imageStyle, companyWrapperStyle } from './index.styles'; export default function CompanyRecruitments() { return ( - - +
+ - - + + + + + + - +
); } - -const MainContainer = styled.div` - padding: 60px; -`; From 26156cd6f0be13d28fc975f2a067776f8a7d04d0 Mon Sep 17 00:00:00 2001 From: KimJi-An Date: Fri, 18 Oct 2024 01:59:12 +0900 Subject: [PATCH 008/120] =?UTF-8?q?refactor:=20CompanyRecruitments=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9D=B4=EB=A6=84=EC=9D=84=20MyC?= =?UTF-8?q?ompany=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/companyRecruitments/index.stories.tsx | 14 -------------- .../index.mock.ts | 0 src/pages/myCompany/index.stories.tsx | 14 ++++++++++++++ .../index.styles.ts | 0 .../{companyRecruitments => myCompany}/index.tsx | 4 ++-- src/routes/path.ts | 2 +- src/routes/router.tsx | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 src/pages/companyRecruitments/index.stories.tsx rename src/pages/{companyRecruitments => myCompany}/index.mock.ts (100%) create mode 100644 src/pages/myCompany/index.stories.tsx rename src/pages/{companyRecruitments => myCompany}/index.styles.ts (100%) rename src/pages/{companyRecruitments => myCompany}/index.tsx (92%) diff --git a/src/pages/companyRecruitments/index.stories.tsx b/src/pages/companyRecruitments/index.stories.tsx deleted file mode 100644 index e539b2c..0000000 --- a/src/pages/companyRecruitments/index.stories.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import CompanyRecruitments from '.'; - -const meta: Meta = { - title: 'pages/CompanyRecruitments', - component: CompanyRecruitments, - tags: ['autodocs'], -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = {}; diff --git a/src/pages/companyRecruitments/index.mock.ts b/src/pages/myCompany/index.mock.ts similarity index 100% rename from src/pages/companyRecruitments/index.mock.ts rename to src/pages/myCompany/index.mock.ts diff --git a/src/pages/myCompany/index.stories.tsx b/src/pages/myCompany/index.stories.tsx new file mode 100644 index 0000000..96fdee8 --- /dev/null +++ b/src/pages/myCompany/index.stories.tsx @@ -0,0 +1,14 @@ +import { Meta, StoryObj } from '@storybook/react'; +import MyCompany from '.'; + +const meta: Meta = { + title: 'pages/MyCompany', + component: MyCompany, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/pages/companyRecruitments/index.styles.ts b/src/pages/myCompany/index.styles.ts similarity index 100% rename from src/pages/companyRecruitments/index.styles.ts rename to src/pages/myCompany/index.styles.ts diff --git a/src/pages/companyRecruitments/index.tsx b/src/pages/myCompany/index.tsx similarity index 92% rename from src/pages/companyRecruitments/index.tsx rename to src/pages/myCompany/index.tsx index 12edaf8..3898106 100644 --- a/src/pages/companyRecruitments/index.tsx +++ b/src/pages/myCompany/index.tsx @@ -3,11 +3,11 @@ import { Flex, InnerContainer, Image, Typo, Button, Icon } from '@/components/co import CompanyLogo from '@assets/images/coupang.png'; import CompanyInfo from '@/features/companies/CompanyInfo'; import MyRecruitments from '@/features/companies/MyRecruitments'; -import { company, recruitments } from '@/pages/companyRecruitments/index.mock'; +import { company, recruitments } from '@/pages/myCompany/index.mock'; import { palettes } from '@/assets/styles/global/palettes'; import { buttonStyle, imageStyle, companyWrapperStyle } from './index.styles'; -export default function CompanyRecruitments() { +export default function MyCompany() { return (
diff --git a/src/routes/path.ts b/src/routes/path.ts index a72846b..43296f0 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -15,7 +15,7 @@ const ROUTE_PATH = { APPLY, AUTH, APPLICANTS: '/applicants', - COMPANY_RECRUITMENTS: '/company-recruitments', + MY_COMPANY: '/my-company', VISA_REGISTRATION: '/visa-registration', } as const; diff --git a/src/routes/router.tsx b/src/routes/router.tsx index 88d9b0b..eb9e58a 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -9,7 +9,7 @@ import PostNotice from '@/pages/employer/postNotice/PostNotice'; import Home from '@/pages/home'; import ApplyGuide from '@/pages/apply/applyguide/ApplyGuide'; import ApplyPage from '@/pages/apply/applypage/ApplyPage'; -import CompanyRecruitments from '@/pages/companyRecruitments'; +import MyCompany from '@/pages/myCompany'; import Applicants from '@/pages/applicants'; export const router = createBrowserRouter([ @@ -30,7 +30,7 @@ export const router = createBrowserRouter([ { path: ROUTE_PATH.RECRUIT, element: }, { path: ROUTE_PATH.VISA_REGISTRATION, element: }, { path: ROUTE_PATH.POST_NOTICE, element: }, - { path: ROUTE_PATH.COMPANY_RECRUITMENTS, element: }, + { path: ROUTE_PATH.MY_COMPANY, element: }, { path: ROUTE_PATH.APPLICANTS, element: }, ], }, From 7925d217a2770f776e7ece5f9ffe81a20cd4339d Mon Sep 17 00:00:00 2001 From: KimJi-An Date: Fri, 18 Oct 2024 02:07:14 +0900 Subject: [PATCH 009/120] =?UTF-8?q?feat:=20EmployerMyAccount=20path=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/path.ts | 5 +++++ src/routes/router.tsx | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/routes/path.ts b/src/routes/path.ts index 43296f0..486f93b 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -8,6 +8,10 @@ export const APPLY = { APPLYPAGE: '/apply', }; +export const MY_ACCOUNT = { + EMPLOYER: '/employer-my-account', +}; + const ROUTE_PATH = { HOME: '/', RECRUIT: '/recruit', @@ -17,6 +21,7 @@ const ROUTE_PATH = { APPLICANTS: '/applicants', MY_COMPANY: '/my-company', VISA_REGISTRATION: '/visa-registration', + MY_ACCOUNT, } as const; export default ROUTE_PATH; diff --git a/src/routes/router.tsx b/src/routes/router.tsx index eb9e58a..62362de 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -11,6 +11,7 @@ import ApplyGuide from '@/pages/apply/applyguide/ApplyGuide'; import ApplyPage from '@/pages/apply/applypage/ApplyPage'; import MyCompany from '@/pages/myCompany'; import Applicants from '@/pages/applicants'; +import EmployerMyAccount from '@/pages/myAccount/employer'; export const router = createBrowserRouter([ { @@ -32,6 +33,7 @@ export const router = createBrowserRouter([ { path: ROUTE_PATH.POST_NOTICE, element: }, { path: ROUTE_PATH.MY_COMPANY, element: }, { path: ROUTE_PATH.APPLICANTS, element: }, + { path: ROUTE_PATH.MY_ACCOUNT.EMPLOYER, element: }, ], }, ]); From 018882d3f25198bbd155a487aff56ee8c16de4c3 Mon Sep 17 00:00:00 2001 From: KimJi-An Date: Fri, 18 Oct 2024 03:14:07 +0900 Subject: [PATCH 010/120] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F?= =?UTF-8?q?=20=ED=8F=B4=EB=8D=94=EB=AA=85=20=EC=9D=BC=EA=B4=80=EC=84=B1=20?= =?UTF-8?q?=EC=9E=88=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CompanyList/CompaniesTable.tsx | 0 .../CompanyList/index.tsx | 18 +++++------------- .../RecruitmentInfo/index.tsx | 0 .../RecruitmentList}/index.tsx | 2 +- src/pages/applicants/index.tsx | 2 +- src/pages/myCompany/index.mock.ts | 2 +- src/pages/myCompany/index.tsx | 6 +++--- 7 files changed, 11 insertions(+), 19 deletions(-) rename src/features/{myAccount/employer/MyCompanies => companies}/CompanyList/CompaniesTable.tsx (100%) rename src/features/{myAccount/employer/MyCompanies => companies}/CompanyList/index.tsx (64%) rename src/features/{applicants => recruitments}/RecruitmentInfo/index.tsx (100%) rename src/features/{companies/MyRecruitments => recruitments/RecruitmentList}/index.tsx (97%) diff --git a/src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx b/src/features/companies/CompanyList/CompaniesTable.tsx similarity index 100% rename from src/features/myAccount/employer/MyCompanies/CompanyList/CompaniesTable.tsx rename to src/features/companies/CompanyList/CompaniesTable.tsx diff --git a/src/features/myAccount/employer/MyCompanies/CompanyList/index.tsx b/src/features/companies/CompanyList/index.tsx similarity index 64% rename from src/features/myAccount/employer/MyCompanies/CompanyList/index.tsx rename to src/features/companies/CompanyList/index.tsx index 4f207d7..85e33b3 100644 --- a/src/features/myAccount/employer/MyCompanies/CompanyList/index.tsx +++ b/src/features/companies/CompanyList/index.tsx @@ -1,20 +1,12 @@ import { Flex, Typo } from '@/components/common'; import CompaniesTable from './CompaniesTable'; +import { CompanyItem } from '@/types'; -interface MyCompanyProps { - id: number; - name: string; - industryOccupation: string; - brand: string; - revenuePerYear: number; - logoImage: string; -} - -interface MyCompanyListProps { - companyList: MyCompanyProps[]; -} +type Props = { + companyList: CompanyItem[]; +}; -export default function CompanyList({ companyList }: MyCompanyListProps) { +export default function CompanyList({ companyList }: Props) { return ( diff --git a/src/features/applicants/RecruitmentInfo/index.tsx b/src/features/recruitments/RecruitmentInfo/index.tsx similarity index 100% rename from src/features/applicants/RecruitmentInfo/index.tsx rename to src/features/recruitments/RecruitmentInfo/index.tsx diff --git a/src/features/companies/MyRecruitments/index.tsx b/src/features/recruitments/RecruitmentList/index.tsx similarity index 97% rename from src/features/companies/MyRecruitments/index.tsx rename to src/features/recruitments/RecruitmentList/index.tsx index 0ad8140..e37c1b8 100644 --- a/src/features/companies/MyRecruitments/index.tsx +++ b/src/features/recruitments/RecruitmentList/index.tsx @@ -12,7 +12,7 @@ interface RecruitmentsListProps { recruitmentsList: RecruitmentProps[]; } -export default function MyRecruitments({ recruitmentsList }: RecruitmentsListProps) { +export default function RecruitmentList({ recruitmentsList }: RecruitmentsListProps) { return ( diff --git a/src/pages/applicants/index.tsx b/src/pages/applicants/index.tsx index 398705f..121efce 100644 --- a/src/pages/applicants/index.tsx +++ b/src/pages/applicants/index.tsx @@ -1,6 +1,6 @@ import { Flex, InnerContainer } from '@/components/common'; import ApplicantList from '@/features/applicants/ApplicantList'; -import RecruitmentsInfo from '@/features/applicants/RecruitmentInfo'; +import RecruitmentsInfo from '@/features/recruitments/RecruitmentInfo'; import Layout from '@/features/layout'; import styled from '@emotion/styled'; diff --git a/src/pages/myCompany/index.mock.ts b/src/pages/myCompany/index.mock.ts index 4d093af..c8b38ef 100644 --- a/src/pages/myCompany/index.mock.ts +++ b/src/pages/myCompany/index.mock.ts @@ -8,7 +8,7 @@ export const company = { logoImage: CompanyLogo, }; -export const recruitments = [ +export const recruitmentList = [ { koreanTitle: '제목1', area: '대전 유성구', diff --git a/src/pages/myCompany/index.tsx b/src/pages/myCompany/index.tsx index 3898106..8f37638 100644 --- a/src/pages/myCompany/index.tsx +++ b/src/pages/myCompany/index.tsx @@ -2,8 +2,8 @@ import Layout from '@/features/layout'; import { Flex, InnerContainer, Image, Typo, Button, Icon } from '@/components/common'; import CompanyLogo from '@assets/images/coupang.png'; import CompanyInfo from '@/features/companies/CompanyInfo'; -import MyRecruitments from '@/features/companies/MyRecruitments'; -import { company, recruitments } from '@/pages/myCompany/index.mock'; +import RecruitmentList from '@/features/recruitments/RecruitmentList'; +import { company, recruitmentList } from '@/pages/myCompany/index.mock'; import { palettes } from '@/assets/styles/global/palettes'; import { buttonStyle, imageStyle, companyWrapperStyle } from './index.styles'; @@ -30,7 +30,7 @@ export default function MyCompany() { - +
From a20fddc958b2b6fe4fceb5484d243a1b40779757 Mon Sep 17 00:00:00 2001 From: kangkibong Date: Fri, 18 Oct 2024 20:47:04 +0900 Subject: [PATCH 011/120] =?UTF-8?q?Feat/#50=20Select=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84=20(#53)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add Select component * feat: add useGlobalSelect and useSelect * refactor: move directory --- eslint.config.js | 1 + src/assets/icons/arrow/down-blue.svg | 3 + src/components/common/Icon/Arrow.ts | 2 + .../common/Select/hooks/useGlobalSelect.ts | 25 ++++ .../common/Select/hooks/useSelect.ts | 20 ++++ .../common/Select/index.context.tsx | 35 ++++++ .../common/Select/index.stories.tsx | 109 ++++++++++++++++++ src/components/common/Select/index.tsx | 13 +++ .../common/Select/sub-components/Content.tsx | 19 +++ .../common/Select/sub-components/Option.tsx | 36 ++++++ .../common/Select/sub-components/Root.tsx | 15 +++ .../common/Select/sub-components/Trigger.tsx | 26 +++++ src/components/common/index.ts | 1 + .../SignIn/{ => components}/SignInButton.tsx | 0 .../SignIn/{ => components}/SignInText.tsx | 0 .../SignUp/{ => components}/RoleSelection.tsx | 2 +- .../SignUp/{ => components}/SignUpText.tsx | 0 .../components/{ => common}/RoleModal.tsx | 0 .../RoleSelector/index.config.tsx | 0 .../{ => common}/RoleSelector/index.tsx | 0 .../home/{ => components}/Employer.tsx | 2 +- src/features/home/{ => components}/Worker.tsx | 2 +- .../home/components/{ => common}/Banner.tsx | 0 .../RecruitmentCard/index.context.tsx} | 0 .../RecruitmentCard/index.tsx} | 4 +- .../sub-components}/Button.tsx | 0 .../sub-components}/CompanyImage.tsx | 2 +- .../sub-components}/CompanyName.tsx | 2 +- .../sub-components}/Detail.tsx | 2 +- .../sub-components}/Salary.tsx | 2 +- .../RecruitmentCard/sub-components}/Title.tsx | 2 +- .../RecruitmentCard/sub-components}/index.ts | 0 .../components/common/RecruitmentFilter.tsx | 45 ++++++++ .../RecruitmentHeader/index.styles.ts | 0 .../{ => common}/RecruitmentHeader/index.tsx | 0 .../common}/RecruitmentList.tsx | 2 +- .../Header/components/LanguageFilter.tsx | 40 +++++++ src/features/layout/Header/index.tsx | 15 +-- src/pages/auth/SignIn/index.tsx | 4 +- src/pages/auth/SignUp/index.tsx | 6 +- src/pages/home/index.tsx | 14 ++- src/store/index.ts | 0 src/store/selectStore.ts | 22 ++++ src/types/select.ts | 5 + 44 files changed, 444 insertions(+), 34 deletions(-) create mode 100644 src/assets/icons/arrow/down-blue.svg create mode 100644 src/components/common/Select/hooks/useGlobalSelect.ts create mode 100644 src/components/common/Select/hooks/useSelect.ts create mode 100644 src/components/common/Select/index.context.tsx create mode 100644 src/components/common/Select/index.stories.tsx create mode 100644 src/components/common/Select/index.tsx create mode 100644 src/components/common/Select/sub-components/Content.tsx create mode 100644 src/components/common/Select/sub-components/Option.tsx create mode 100644 src/components/common/Select/sub-components/Root.tsx create mode 100644 src/components/common/Select/sub-components/Trigger.tsx rename src/features/auth/SignIn/{ => components}/SignInButton.tsx (100%) rename src/features/auth/SignIn/{ => components}/SignInText.tsx (100%) rename src/features/auth/SignUp/{ => components}/RoleSelection.tsx (89%) rename src/features/auth/SignUp/{ => components}/SignUpText.tsx (100%) rename src/features/auth/SignUp/components/{ => common}/RoleModal.tsx (100%) rename src/features/auth/SignUp/components/{ => common}/RoleSelector/index.config.tsx (100%) rename src/features/auth/SignUp/components/{ => common}/RoleSelector/index.tsx (100%) rename src/features/home/{ => components}/Employer.tsx (95%) rename src/features/home/{ => components}/Worker.tsx (76%) rename src/features/home/components/{ => common}/Banner.tsx (100%) rename src/features/home/components/{RecruitmentCard/RecruitmentCard.context.tsx => common/RecruitmentCard/index.context.tsx} (100%) rename src/features/home/components/{RecruitmentCard/RecruitmentCard.tsx => common/RecruitmentCard/index.tsx} (91%) rename src/features/home/components/{RecruitmentCard => common/RecruitmentCard/sub-components}/Button.tsx (100%) rename src/features/home/components/{RecruitmentCard => common/RecruitmentCard/sub-components}/CompanyImage.tsx (88%) rename src/features/home/components/{RecruitmentCard => common/RecruitmentCard/sub-components}/CompanyName.tsx (86%) rename src/features/home/components/{RecruitmentCard => common/RecruitmentCard/sub-components}/Detail.tsx (86%) rename src/features/home/components/{RecruitmentCard => common/RecruitmentCard/sub-components}/Salary.tsx (81%) rename src/features/home/components/{RecruitmentCard => common/RecruitmentCard/sub-components}/Title.tsx (87%) rename src/features/home/components/{RecruitmentCard => common/RecruitmentCard/sub-components}/index.ts (100%) create mode 100644 src/features/home/components/common/RecruitmentFilter.tsx rename src/features/home/components/{ => common}/RecruitmentHeader/index.styles.ts (100%) rename src/features/home/components/{ => common}/RecruitmentHeader/index.tsx (100%) rename src/features/home/{ => components/common}/RecruitmentList.tsx (92%) create mode 100644 src/features/layout/Header/components/LanguageFilter.tsx delete mode 100644 src/store/index.ts create mode 100644 src/store/selectStore.ts create mode 100644 src/types/select.ts diff --git a/eslint.config.js b/eslint.config.js index e9c92e0..936c4c8 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -21,6 +21,7 @@ export default tseslint.config( ...reactHooks.configs.recommended.rules, 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], 'react-refresh/only-export-components': 'off', + 'react-hooks/rules-of-hooks': 'off', }, }, ); diff --git a/src/assets/icons/arrow/down-blue.svg b/src/assets/icons/arrow/down-blue.svg new file mode 100644 index 0000000..4d0f94d --- /dev/null +++ b/src/assets/icons/arrow/down-blue.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/common/Icon/Arrow.ts b/src/components/common/Icon/Arrow.ts index e7a5bcd..bf56a74 100644 --- a/src/components/common/Icon/Arrow.ts +++ b/src/components/common/Icon/Arrow.ts @@ -1,9 +1,11 @@ import RightWhite from '@assets/icons/arrow/right-white.svg?react'; import RightBlue from '@assets/icons/arrow/right-blue.svg?react'; +import DownBlue from '@assets/icons/arrow/down-blue.svg?react'; const Arrow = { RightWhite, RightBlue, + DownBlue, }; export default Arrow; diff --git a/src/components/common/Select/hooks/useGlobalSelect.ts b/src/components/common/Select/hooks/useGlobalSelect.ts new file mode 100644 index 0000000..41e22fc --- /dev/null +++ b/src/components/common/Select/hooks/useGlobalSelect.ts @@ -0,0 +1,25 @@ +import { useSelectStore } from '@/store/selectStore'; +import { SelectOptionType } from '@/types/select'; +import { useEffect } from 'react'; + +const useGlobalSelect = (initialOption: SelectOptionType) => { + const { selectedOption, setSelectedOption, initializeOption } = useSelectStore(); + + useEffect(() => { + if (!selectedOption) { + initializeOption(initialOption); + } + }, [selectedOption, initializeOption, initialOption]); + + const handleSelect = (option: SelectOptionType) => { + setSelectedOption(option); + option.action(); + }; + + return { + selectedOption: selectedOption || initialOption, + handleSelect, + }; +}; + +export default useGlobalSelect; diff --git a/src/components/common/Select/hooks/useSelect.ts b/src/components/common/Select/hooks/useSelect.ts new file mode 100644 index 0000000..be47d81 --- /dev/null +++ b/src/components/common/Select/hooks/useSelect.ts @@ -0,0 +1,20 @@ +import { SelectOptionType } from '@/types/select'; +import { useState } from 'react'; + +const useSelect = (defaultOption: SelectOptionType) => { + const [selectedOption, setSelectedOption] = useState(defaultOption); + + const handleSelect = (option: SelectOptionType) => { + if (option.value !== selectedOption.value) { + setSelectedOption(option); + option.action(); + } + }; + + return { + selectedOption, + handleSelect, + }; +}; + +export default useSelect; diff --git a/src/components/common/Select/index.context.tsx b/src/components/common/Select/index.context.tsx new file mode 100644 index 0000000..8b1207f --- /dev/null +++ b/src/components/common/Select/index.context.tsx @@ -0,0 +1,35 @@ +import useToggle from '@/hooks/useToggle'; +import { createContext, PropsWithChildren, useContext, useState } from 'react'; + +interface SelectContextProps { + isOpen: boolean; + toggle: () => void; + selectedValue?: string; + onItemSelect: (value: string) => void; +} + +const SelectContext = createContext(undefined); + +export const useSelectContext = () => { + const context = useContext(SelectContext); + if (!context) { + throw new Error('useSelectContext must be used within a useSelectContext'); + } + return context; +}; + +export const SelectProvider = ({ children }: PropsWithChildren) => { + const [isOpen, toggle] = useToggle(); + const [selectedValue, setSelectedValue] = useState(undefined); + + const handleItemSelect = (value: string) => { + setSelectedValue(value); + toggle(); + }; + + return ( + + {children} + + ); +}; diff --git a/src/components/common/Select/index.stories.tsx b/src/components/common/Select/index.stories.tsx new file mode 100644 index 0000000..0775338 --- /dev/null +++ b/src/components/common/Select/index.stories.tsx @@ -0,0 +1,109 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import Select from '.'; +import { SelectOptionType } from '@/types/select'; +import useGlobalSelect from './hooks/useGlobalSelect'; +import { Icon } from '@/components/common'; + +const options: SelectOptionType[] = [ + { value: 'korean', text: '한국어', action: () => console.log('한국어 선택') }, + { value: 'english', text: '영어', action: () => console.log('영어 선택') }, + { value: 'vietnamese', text: '베트남어', action: () => console.log('베트남어 선택') }, +]; + +const meta: Meta = { + title: 'common/Select', + component: Select, + tags: ['autodocs'], + argTypes: { + icon: { + control: 'boolean', + description: '아이콘을 표시할지 여부를 결정', + }, + options: { + control: 'object', + description: '선택할 수 있는 옵션 목록', + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: (args) => { + const { selectedOption, handleSelect } = useGlobalSelect(options[0]); + + return ( + + }> + {selectedOption.text} + + + {options.map((option) => ( + handleSelect(option)}> + {option.text} + + ))} + + + ); + }, + args: { + icon: true, + options, + }, +}; + +export const NoIcon: Story = { + render: (args) => { + const { selectedOption, handleSelect } = useGlobalSelect(options[0]); + + return ( + + {selectedOption.text} + + {options.map((option) => ( + handleSelect(option)}> + {option.text} + + ))} + + + ); + }, + args: { + icon: false, + options, + }, +}; + +export const WithMultipleOptions: Story = { + render: (args) => { + const { selectedOption, handleSelect } = useGlobalSelect(options[0]); + + return ( + + }> + {selectedOption.text} + + + {options.map((option) => ( + handleSelect(option)}> + {option.text} + + ))} + + + ); + }, + args: { + icon: true, + options: [ + { value: 'korean', text: '한국어', action: () => console.log('한국어 선택') }, + { value: 'english', text: '영어', action: () => console.log('영어 선택') }, + { value: 'vietnamese', text: '베트남어', action: () => console.log('베트남어 선택') }, + { value: 'japanese', text: '일본어', action: () => console.log('일본어 선택') }, + ], + }, +}; diff --git a/src/components/common/Select/index.tsx b/src/components/common/Select/index.tsx new file mode 100644 index 0000000..6c9f845 --- /dev/null +++ b/src/components/common/Select/index.tsx @@ -0,0 +1,13 @@ +import { SelectRoot as Root } from './sub-components/Root'; +import { SelectTrigger as Trigger } from './sub-components/Trigger'; +import { SelectContent as Content } from './sub-components/Content'; +import { SelectOption as Option } from './sub-components/Option'; + +const Select = Object.assign({ + Root, + Trigger, + Content, + Option, +}); + +export default Select; diff --git a/src/components/common/Select/sub-components/Content.tsx b/src/components/common/Select/sub-components/Content.tsx new file mode 100644 index 0000000..e0cfbed --- /dev/null +++ b/src/components/common/Select/sub-components/Content.tsx @@ -0,0 +1,19 @@ +import styled from '@emotion/styled'; +import { useSelectContext } from '../index.context'; + +export const SelectContent = ({ children }: { children: React.ReactNode }) => { + const { isOpen } = useSelectContext(); + + return {children}; +}; + +export const Content = styled.div<{ isOpen: boolean }>` + position: absolute; + top: 100%; + left: 0; + background: ${({ theme }) => theme.palettes.white}; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + display: ${({ isOpen }) => (isOpen ? 'block' : 'none')}; + min-width: 160px; + z-index: 1000; +`; diff --git a/src/components/common/Select/sub-components/Option.tsx b/src/components/common/Select/sub-components/Option.tsx new file mode 100644 index 0000000..aef7a87 --- /dev/null +++ b/src/components/common/Select/sub-components/Option.tsx @@ -0,0 +1,36 @@ +import { PropsWithChildren } from 'react'; +import { useSelectContext } from '../index.context'; +import styled from '@emotion/styled'; + +type Props = { + value: string; + onClick?: () => void; +} & PropsWithChildren; + +export const SelectOption = ({ children, value, onClick, ...rest }: Props) => { + const { selectedValue, onItemSelect } = useSelectContext(); + + const handleOptionClick = () => { + if (onClick) onClick(); + onItemSelect(value); + }; + + return ( + + ); +}; + +export const Option = styled.div<{ isSelected: boolean }>` + padding: 8px 12px; + cursor: pointer; + color: ${({ theme, isSelected }) => (isSelected ? theme.palettes.blue : theme.palettes.black)}; + font-weight: ${({ isSelected }) => (isSelected ? 700 : 400)}; + + &:hover { + background-color: #f1f1f1; + color: ${({ theme }) => theme.palettes.blue}; + font-weight: 700; + } +`; diff --git a/src/components/common/Select/sub-components/Root.tsx b/src/components/common/Select/sub-components/Root.tsx new file mode 100644 index 0000000..e1c6736 --- /dev/null +++ b/src/components/common/Select/sub-components/Root.tsx @@ -0,0 +1,15 @@ +import styled from '@emotion/styled'; +import { SelectProvider } from '../index.context'; + +export const SelectRoot = ({ children }: { children: React.ReactNode }) => { + return ( + + {children} + + ); +}; + +export const Root = styled.div` + position: relative; + display: inline-block; +`; diff --git a/src/components/common/Select/sub-components/Trigger.tsx b/src/components/common/Select/sub-components/Trigger.tsx new file mode 100644 index 0000000..e67dcb2 --- /dev/null +++ b/src/components/common/Select/sub-components/Trigger.tsx @@ -0,0 +1,26 @@ +import { Flex } from '@components/common'; +import { useSelectContext } from '../index.context'; +import { PropsWithChildren, ReactNode } from 'react'; +import styled from '@emotion/styled'; + +type Props = { + icon?: ReactNode; +} & PropsWithChildren; + +export const SelectTrigger = ({ icon, children, ...rest }: Props) => { + const { toggle } = useSelectContext(); + + return ( + + ); +}; + +const Icon = styled.div` + display: flex; + align-items: center; +`; diff --git a/src/components/common/index.ts b/src/components/common/index.ts index cfae363..1cea0c3 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -8,3 +8,4 @@ export { default as Typo } from './Typo'; export { default as Icon } from './Icon'; export { default as List } from './List'; export { default as Image } from './Image'; +export { default as Select } from './Select'; diff --git a/src/features/auth/SignIn/SignInButton.tsx b/src/features/auth/SignIn/components/SignInButton.tsx similarity index 100% rename from src/features/auth/SignIn/SignInButton.tsx rename to src/features/auth/SignIn/components/SignInButton.tsx diff --git a/src/features/auth/SignIn/SignInText.tsx b/src/features/auth/SignIn/components/SignInText.tsx similarity index 100% rename from src/features/auth/SignIn/SignInText.tsx rename to src/features/auth/SignIn/components/SignInText.tsx diff --git a/src/features/auth/SignUp/RoleSelection.tsx b/src/features/auth/SignUp/components/RoleSelection.tsx similarity index 89% rename from src/features/auth/SignUp/RoleSelection.tsx rename to src/features/auth/SignUp/components/RoleSelection.tsx index 55a16ec..39918f6 100644 --- a/src/features/auth/SignUp/RoleSelection.tsx +++ b/src/features/auth/SignUp/components/RoleSelection.tsx @@ -1,5 +1,5 @@ import { Flex } from '@components/common'; -import RoleSelector from './components/RoleSelector'; +import RoleSelector from './common/RoleSelector'; import { ReactNode } from 'react'; type Props = { diff --git a/src/features/auth/SignUp/SignUpText.tsx b/src/features/auth/SignUp/components/SignUpText.tsx similarity index 100% rename from src/features/auth/SignUp/SignUpText.tsx rename to src/features/auth/SignUp/components/SignUpText.tsx diff --git a/src/features/auth/SignUp/components/RoleModal.tsx b/src/features/auth/SignUp/components/common/RoleModal.tsx similarity index 100% rename from src/features/auth/SignUp/components/RoleModal.tsx rename to src/features/auth/SignUp/components/common/RoleModal.tsx diff --git a/src/features/auth/SignUp/components/RoleSelector/index.config.tsx b/src/features/auth/SignUp/components/common/RoleSelector/index.config.tsx similarity index 100% rename from src/features/auth/SignUp/components/RoleSelector/index.config.tsx rename to src/features/auth/SignUp/components/common/RoleSelector/index.config.tsx diff --git a/src/features/auth/SignUp/components/RoleSelector/index.tsx b/src/features/auth/SignUp/components/common/RoleSelector/index.tsx similarity index 100% rename from src/features/auth/SignUp/components/RoleSelector/index.tsx rename to src/features/auth/SignUp/components/common/RoleSelector/index.tsx diff --git a/src/features/home/Employer.tsx b/src/features/home/components/Employer.tsx similarity index 95% rename from src/features/home/Employer.tsx rename to src/features/home/components/Employer.tsx index 4bef18a..c9878a0 100644 --- a/src/features/home/Employer.tsx +++ b/src/features/home/components/Employer.tsx @@ -1,5 +1,5 @@ import { Flex, Typo, Button } from '@/components/common'; -import Banner from './components/Banner'; +import Banner from './common/Banner'; import { images } from '@pages/home/data/index.mock'; import { responsiveStyle } from '@utils/responsive'; diff --git a/src/features/home/Worker.tsx b/src/features/home/components/Worker.tsx similarity index 76% rename from src/features/home/Worker.tsx rename to src/features/home/components/Worker.tsx index f709d60..3f7e929 100644 --- a/src/features/home/Worker.tsx +++ b/src/features/home/components/Worker.tsx @@ -1,4 +1,4 @@ -import Banner from './components/Banner'; +import Banner from './common/Banner'; import { images } from '@/pages/home/data/index.mock'; export default function Worker() { diff --git a/src/features/home/components/Banner.tsx b/src/features/home/components/common/Banner.tsx similarity index 100% rename from src/features/home/components/Banner.tsx rename to src/features/home/components/common/Banner.tsx diff --git a/src/features/home/components/RecruitmentCard/RecruitmentCard.context.tsx b/src/features/home/components/common/RecruitmentCard/index.context.tsx similarity index 100% rename from src/features/home/components/RecruitmentCard/RecruitmentCard.context.tsx rename to src/features/home/components/common/RecruitmentCard/index.context.tsx diff --git a/src/features/home/components/RecruitmentCard/RecruitmentCard.tsx b/src/features/home/components/common/RecruitmentCard/index.tsx similarity index 91% rename from src/features/home/components/RecruitmentCard/RecruitmentCard.tsx rename to src/features/home/components/common/RecruitmentCard/index.tsx index b247f24..1dd5d3b 100644 --- a/src/features/home/components/RecruitmentCard/RecruitmentCard.tsx +++ b/src/features/home/components/common/RecruitmentCard/index.tsx @@ -2,8 +2,8 @@ import { RecruitmentItem } from '@/types'; import { bounceAnimation } from '@assets/styles/animations'; import { Card } from '@components/common'; import { ReactNode } from 'react'; -import { RecruitmentCardContextProvider } from './RecruitmentCard.context'; -import { Title, Button, CompanyName, CompanyImage, Detail, Salary } from '.'; +import { RecruitmentCardContextProvider } from './index.context'; +import { Title, Button, CompanyName, CompanyImage, Detail, Salary } from './sub-components'; import { responsiveStyle } from '@utils/responsive'; const recruitmentCardStyle = responsiveStyle({ diff --git a/src/features/home/components/RecruitmentCard/Button.tsx b/src/features/home/components/common/RecruitmentCard/sub-components/Button.tsx similarity index 100% rename from src/features/home/components/RecruitmentCard/Button.tsx rename to src/features/home/components/common/RecruitmentCard/sub-components/Button.tsx diff --git a/src/features/home/components/RecruitmentCard/CompanyImage.tsx b/src/features/home/components/common/RecruitmentCard/sub-components/CompanyImage.tsx similarity index 88% rename from src/features/home/components/RecruitmentCard/CompanyImage.tsx rename to src/features/home/components/common/RecruitmentCard/sub-components/CompanyImage.tsx index 3486647..fb4cef9 100644 --- a/src/features/home/components/RecruitmentCard/CompanyImage.tsx +++ b/src/features/home/components/common/RecruitmentCard/sub-components/CompanyImage.tsx @@ -1,5 +1,5 @@ import { Image } from '@components/common'; -import { useRecruitmentCardContext } from './RecruitmentCard.context'; +import { useRecruitmentCardContext } from '../index.context'; import { responsiveStyle } from '@utils/responsive'; const IMAGE_SIZE_CONFIG = { diff --git a/src/features/home/components/RecruitmentCard/CompanyName.tsx b/src/features/home/components/common/RecruitmentCard/sub-components/CompanyName.tsx similarity index 86% rename from src/features/home/components/RecruitmentCard/CompanyName.tsx rename to src/features/home/components/common/RecruitmentCard/sub-components/CompanyName.tsx index f6df543..7875f4f 100644 --- a/src/features/home/components/RecruitmentCard/CompanyName.tsx +++ b/src/features/home/components/common/RecruitmentCard/sub-components/CompanyName.tsx @@ -1,5 +1,5 @@ import { Typo } from '@components/common'; -import { useRecruitmentCardContext } from './RecruitmentCard.context'; +import { useRecruitmentCardContext } from '../index.context'; import { responsiveStyle } from '@utils/responsive'; const companyNameStyle = responsiveStyle({ diff --git a/src/features/home/components/RecruitmentCard/Detail.tsx b/src/features/home/components/common/RecruitmentCard/sub-components/Detail.tsx similarity index 86% rename from src/features/home/components/RecruitmentCard/Detail.tsx rename to src/features/home/components/common/RecruitmentCard/sub-components/Detail.tsx index ae2ead5..26ca3e6 100644 --- a/src/features/home/components/RecruitmentCard/Detail.tsx +++ b/src/features/home/components/common/RecruitmentCard/sub-components/Detail.tsx @@ -1,5 +1,5 @@ import { Typo } from '@components/common'; -import { useRecruitmentCardContext } from './RecruitmentCard.context'; +import { useRecruitmentCardContext } from '../index.context'; import { responsiveStyle } from '@utils/responsive'; const detailStyle = responsiveStyle({ diff --git a/src/features/home/components/RecruitmentCard/Salary.tsx b/src/features/home/components/common/RecruitmentCard/sub-components/Salary.tsx similarity index 81% rename from src/features/home/components/RecruitmentCard/Salary.tsx rename to src/features/home/components/common/RecruitmentCard/sub-components/Salary.tsx index a26328b..e48d31b 100644 --- a/src/features/home/components/RecruitmentCard/Salary.tsx +++ b/src/features/home/components/common/RecruitmentCard/sub-components/Salary.tsx @@ -1,5 +1,5 @@ import { Typo } from '@components/common'; -import { useRecruitmentCardContext } from './RecruitmentCard.context'; +import { useRecruitmentCardContext } from '../index.context'; const SALARY_STYLE = { marginBottom: '4px' }; diff --git a/src/features/home/components/RecruitmentCard/Title.tsx b/src/features/home/components/common/RecruitmentCard/sub-components/Title.tsx similarity index 87% rename from src/features/home/components/RecruitmentCard/Title.tsx rename to src/features/home/components/common/RecruitmentCard/sub-components/Title.tsx index 13e27d6..f2eb19a 100644 --- a/src/features/home/components/RecruitmentCard/Title.tsx +++ b/src/features/home/components/common/RecruitmentCard/sub-components/Title.tsx @@ -1,5 +1,5 @@ import { Typo } from '@components/common'; -import { useRecruitmentCardContext } from './RecruitmentCard.context'; +import { useRecruitmentCardContext } from '../index.context'; import { responsiveStyle } from '@utils/responsive'; const titleStyle = responsiveStyle({ diff --git a/src/features/home/components/RecruitmentCard/index.ts b/src/features/home/components/common/RecruitmentCard/sub-components/index.ts similarity index 100% rename from src/features/home/components/RecruitmentCard/index.ts rename to src/features/home/components/common/RecruitmentCard/sub-components/index.ts diff --git a/src/features/home/components/common/RecruitmentFilter.tsx b/src/features/home/components/common/RecruitmentFilter.tsx new file mode 100644 index 0000000..300b652 --- /dev/null +++ b/src/features/home/components/common/RecruitmentFilter.tsx @@ -0,0 +1,45 @@ +import theme from '@/assets/theme'; +import { Select, Icon, List } from '@/components/common'; +import useSelect from '@/components/common/Select/hooks/useSelect'; + +const filterOptions = [ + { + value: 'all', + text: '전체', + action: () => console.log('All clicked'), + }, + { + value: 'age', + text: '나이', + action: () => console.log('Age clicked'), + }, + { + value: 'area', + text: '지역', + action: () => console.log('Area clicked'), + }, +]; + +const triggerStyle = { minWidth: '80px', fontSize: '16px', fontWeight: '700', color: theme.palettes.blue }; + +export default function RecruitmentFilter() { + const { selectedOption, handleSelect } = useSelect(filterOptions[0]); + + return ( + + } css={triggerStyle}> + {selectedOption.text} + + + ( + handleSelect(option)}> + {option.text} + + )} + /> + + + ); +} diff --git a/src/features/home/components/RecruitmentHeader/index.styles.ts b/src/features/home/components/common/RecruitmentHeader/index.styles.ts similarity index 100% rename from src/features/home/components/RecruitmentHeader/index.styles.ts rename to src/features/home/components/common/RecruitmentHeader/index.styles.ts diff --git a/src/features/home/components/RecruitmentHeader/index.tsx b/src/features/home/components/common/RecruitmentHeader/index.tsx similarity index 100% rename from src/features/home/components/RecruitmentHeader/index.tsx rename to src/features/home/components/common/RecruitmentHeader/index.tsx diff --git a/src/features/home/RecruitmentList.tsx b/src/features/home/components/common/RecruitmentList.tsx similarity index 92% rename from src/features/home/RecruitmentList.tsx rename to src/features/home/components/common/RecruitmentList.tsx index 863b9ef..120b38a 100644 --- a/src/features/home/RecruitmentList.tsx +++ b/src/features/home/components/common/RecruitmentList.tsx @@ -1,5 +1,5 @@ import { List, Flex } from '@/components/common'; -import RecruitmentCard from './components/RecruitmentCard/RecruitmentCard'; +import RecruitmentCard from './RecruitmentCard'; import { RecruitmentItem } from '@/types'; import { responsiveStyle } from '@utils/responsive'; diff --git a/src/features/layout/Header/components/LanguageFilter.tsx b/src/features/layout/Header/components/LanguageFilter.tsx new file mode 100644 index 0000000..8882c5a --- /dev/null +++ b/src/features/layout/Header/components/LanguageFilter.tsx @@ -0,0 +1,40 @@ +import theme from '@/assets/theme'; +import { Select, Icon, List } from '@/components/common'; +import useGlobalSelect from '@/components/common/Select/hooks/useGlobalSelect'; + +const triggerStyle = { minWidth: '80px', fontSize: '16px', fontWeight: '700', color: theme.palettes.blue }; + +const languageOptions = [ + { + value: 'korean', + text: '한국어', + action: () => console.log('한국어'), + }, + { + value: 'vietnamese', + text: '베트남어', + action: () => console.log('베트남어'), + }, +]; + +export default function LanguageFilter() { + const { selectedOption, handleSelect } = useGlobalSelect(languageOptions[0]); + + return ( + + } css={triggerStyle}> + {selectedOption.text} + + + ( + handleSelect(option)}> + {option.text} + + )} + /> + + + ); +} diff --git a/src/features/layout/Header/index.tsx b/src/features/layout/Header/index.tsx index 1649f15..e39913e 100644 --- a/src/features/layout/Header/index.tsx +++ b/src/features/layout/Header/index.tsx @@ -6,6 +6,7 @@ import Button from '@components/common/Button'; import { Flex } from '@/components/common'; import { responsiveStyle } from '@utils/responsive'; import useToggle from '@/hooks/useToggle'; +import LanguageFilter from './components/LanguageFilter'; interface NavProps { open: boolean; @@ -20,10 +21,7 @@ export default function Header() { {menuOpen ? : }