Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[FEAT-8] 헤더 세부 기능 구현 #20

Merged
merged 10 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/assets/svg/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/svg/hamburger.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/assets/svg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export { default as SendIcon } from '@assets/svg/send.svg?react';
export { default as CheckTrueIcon } from '@assets/svg/check-true.svg?react';
export { default as CheckFalseIcon } from '@assets/svg/check-false.svg?react';
export { default as WarningIcon } from '@assets/svg/warning.svg?react';
export { default as HamburgerIcon } from '@assets/svg/hamburger.svg?react';
export { default as CloseIcon } from '@assets/svg/close.svg?react';
2 changes: 1 addition & 1 deletion src/components/chip/chip.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
function Chip({ label }: { label: string }) {
return (
<div className="bg-primary-egg rounded-2xl px-2 py-1">
<div className="flex max-h-6 items-center rounded-2xl bg-primary-egg px-2 py-1">
<span className="text-label font-semibold text-primary">{label}</span>
</div>
);
Expand Down
34 changes: 34 additions & 0 deletions src/components/header/admission-quick-link-tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useState } from 'react';
import PresetButton from '@/components/preset-button/preset-button';
import ADMISSION_QUICK_LINK from '@/constants/admission-quick-link';
import { AdmissionType } from '@/types/admission-type';
import { ADDMISSION } from '@/types/admission-type';

function AdmissionQuickLinkTabs({ initialAdmissionType }: { initialAdmissionType: AdmissionType | null }) {
const [selectedAdmissionType, setSelectedAdmissionType] = useState(initialAdmissionType ?? 'SUSI');
Copy link
Member

Choose a reason for hiding this comment

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

진짜 사소한거긴한데 저는 해당 경우에 아래 방법처럼 기본값을 주는 방법을 선호하거든요...! 혹시 해당 방법에 대해서는 어떻게 생각하시나요?

Suggested change
function AdmissionQuickLinkTabs({ initialAdmissionType }: { initialAdmissionType: AdmissionType | null }) {
const [selectedAdmissionType, setSelectedAdmissionType] = useState(initialAdmissionType ?? 'SUSI');
function AdmissionQuickLinkTabs({ initialAdmissionType='SUSI' }: { initialAdmissionType: AdmissionType}) {
const [selectedAdmissionType, setSelectedAdmissionType] = useState(initialAdmissionType);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

좋은 의견 감사합니다! 다만 제안해주신 개선 방안이 기존 코드를 완벽히 대체 하지 못할 거 같아요 ㅠㅠ..
이유는 다음과 같습니다!

initialAdmissionTypenull값을 허용해야만 하는 상황입니다(사용자가 선택하기 전 admissionType 전역상태에서 null 값으로 초기화),
이 상황에서 매개변수 기본값 (="SUSI")는 예상대로 작동하지 않습니다.

  • 매개변수 기본 값은 undefined 일 때만 작동하고, null이 전달되면 null이 useState에 전달되기 때문입니다

만약 제안해주신 방법을 사용하기 위해서는 부모 컴포넌트에서 AdmissionQuickLinkTabs 컴포넌트에서 props를 전달할 때 null값일 시 props를 전달하지 않는 방법으로 수정할 수 있을거 같지만 개인적으로 해당 방법보다 기존 방법이 괜찮을거 같은데 어떻게 생각하시나용??

아니면 혹시 제가 제안 주신 부분을 잘못 이해하고 있다면 다시 한번 설명해주시면 감사하겠습니다 😢

Copy link
Member

Choose a reason for hiding this comment

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

그러네요...! 너무 단순히 보이는 부분만 생각해서 말씀드린 것 같습니다! 기존 방법이 괜찮을 것 같네요!


return (
<div>
<div className="flex gap-2">
{Object.entries(ADDMISSION).map(([type, label]) => (
<PresetButton
key={type}
selected={type === selectedAdmissionType}
onClick={() => setSelectedAdmissionType(type as AdmissionType)}
>
{label}
</PresetButton>
))}
</div>
<div className="mt-6 flex flex-col gap-6 text-headline">
{ADMISSION_QUICK_LINK[selectedAdmissionType].map((link) => (
<a key={link.id} className="cursor-pointer" href={link.link} target="_blank">
{link.label}
</a>
))}
</div>
</div>
);
}

export default AdmissionQuickLinkTabs;
33 changes: 33 additions & 0 deletions src/components/header/contact.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
interface ContactItemProps {
title: string;
department: string;
numbers: number[];
}
function ContactItem({ title, department, numbers }: ContactItemProps) {
return (
<div className="flex text-label text-gray-500">
<span className="w-1/2">{title}</span>
<span className="flex-1 whitespace-nowrap">
{department} :{' '}
<a href={`tel:02-300-${numbers[0]}`} className="underline underline-offset-4">
02)300-{numbers[0]}
</a>
,{' '}
<a href={`tel:02-300-${numbers[1]}`} className="underline underline-offset-4">
{numbers[1]}
</a>
</span>
</div>
);
}

function Contact() {
return (
<div className="flex flex-col gap-3">
<ContactItem title="학생부교과, 실기/실적 위주 문의" department="입학관리팀" numbers={[1799, 1800]} />
<ContactItem title="학생부종합 문의" department="인재발굴팀" numbers={[1794, 1844]} />
</div>
);
}

export default Contact;
45 changes: 36 additions & 9 deletions src/components/header/header.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
import { ReloadIcon } from '@/assets/svg';
import { CloseIcon, HamburgerIcon, ReloadIcon } from '@/assets/svg';
import BottomSheet from '@/components/bottom-sheet/bottom-sheet';
import Chip from '@/components/chip/chip';
import AdmissionQuickLinkTabs from '@/components/header/admission-quick-link-tabs';
import Contact from '@/components/header/contact';
import IconButton from '@/components/icon-button/icon-button';
import CHIP_LABEL from '@/constants/header-chip-labels';
import { useBottomSheet } from '@/hooks/use-bottom-sheet-hooks';
import useAdmissionStore from '@/stores/store/admission-store';

function Header() {
const { admissionType } = useAdmissionStore();
const { open, onOpen, onClose } = useBottomSheet();

return (
<header className="sticky top-0 z-10 h-16 w-full bg-white">
<div className="flex h-full items-center justify-center px-4">
<h1 className="text-primary text-title flex-1 text-center">명지대 입학처 챗봇</h1>
<IconButton aria-label="새로고침">
<ReloadIcon />
</IconButton>
</div>
</header>
<>
<header className="sticky top-0 z-10 h-16 w-full bg-white">
<div className="flex h-full items-center justify-between px-4">
<IconButton aria-label="새로고침" onClick={() => window.location.reload()}>
<ReloadIcon />
</IconButton>
<div className="flex items-center gap-2">
<h1 className="text-center text-headline text-primary">명지대 입학처 챗봇</h1>
{admissionType && <Chip label={CHIP_LABEL[admissionType]} />}
</div>
<IconButton aria-label="메뉴" onClick={onOpen}>
<HamburgerIcon />
</IconButton>
</div>
</header>
<BottomSheet open={open} onClose={onClose}>
<div className="flex h-full w-full flex-col justify-between gap-3">
<IconButton onClick={onClose} className="absolute right-10 top-10" aria-label="닫기 버튼">
<CloseIcon />
</IconButton>
<AdmissionQuickLinkTabs initialAdmissionType={admissionType} />
<Contact />
</div>
</BottomSheet>
</>
);
}

Expand Down
6 changes: 4 additions & 2 deletions src/components/preset-button/preset-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import { cn } from '@/utils/style';

interface PresetButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
children: React.ReactNode;
selected?: boolean;
}

function PresetButton({ children, ...props }: PresetButtonProps) {
function PresetButton({ children, selected, ...props }: PresetButtonProps) {
const buttonClasses = cn(
'cursor-pointer rounded-lg border border-category_border bg-white px-4 py-3 text-black transition-colors text-sm',
'hover:border-primary hover:text-primary',
'hover:bg-primary hover:text-white',
'disabled:cursor-not-allowed disabled:bg-gray-100 disabled:text-gray-400',
'disabled:hover:border-gray-200 disabled:hover:text-gray-400',
selected && 'bg-primary text-white',
);

return (
Expand Down
43 changes: 43 additions & 0 deletions src/constants/admission-quick-link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const ADMISSION_QUICK_LINK = {
SUSI: [
{
id: 'faq',
label: '수시 FAQ 바로가기',
link: 'https://iphak.mju.ac.kr/pages/?p=33&b=B_1_5&cate=%EC%88%98%EC%8B%9C',
},
{
id: 'results',
label: '수시 입시결과 바로가기',
link: 'https://iphak.mju.ac.kr/pages/?p=11&b=B_1_2&cate=%EC%88%98%EC%8B%9C',
},
{ id: 'guide', label: '수시 모집요강 바로가기', link: 'https://iphak.mju.ac.kr/pages/?p=10&mj=01' },
],
JEONGSI: [
{
id: 'faq',
label: '정시 FAQ 바로가기',
link: 'https://iphak.mju.ac.kr/pages/?p=33&b=B_1_5&cate=%EC%A0%95%EC%8B%9C',
},
{
id: 'results',
label: '정시 입시결과 바로가기',
link: 'https://iphak.mju.ac.kr/pages/?p=17&b=B_1_2&cate=%EC%A0%95%EC%8B%9C',
},
{ id: 'guide', label: '정시 모집요강 바로가기', link: 'https://iphak.mju.ac.kr/pages/?p=16&mj=02' },
],
PYEONIP: [
{
id: 'faq',
label: '편입 FAQ 바로가기',
link: 'https://iphak.mju.ac.kr/pages/?p=33&b=B_1_5&cate=%ED%8E%B8%EC%9E%85%ED%95%99',
},
{
id: 'results',
label: '편입 입시결과 바로가기',
link: 'https://iphak.mju.ac.kr/pages/?p=27&b=B_1_2&cate=%ED%8E%B8%EC%9E%85%ED%95%99',
},
{ id: 'guide', label: '편입 모집요강 바로가기', link: 'https://iphak.mju.ac.kr/pages/?p=26&mj=04' },
],
};

export default ADMISSION_QUICK_LINK;
7 changes: 7 additions & 0 deletions src/constants/header-chip-labels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const CHIP_LABEL = {
SUSI: '수시 질문중',
JEONGSI: '정시 질문중',
PYEONIP: '편입 질문중',
};

export default CHIP_LABEL;