Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
File renamed without changes
File renamed without changes
7 changes: 7 additions & 0 deletions src/assets/icons/seeat_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions src/components/common/ProgressBar/ProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
interface ProgressBarProps {
currentStep: number;
totalSteps: number;
}

const ProgressBar = ({ currentStep, totalSteps }: ProgressBarProps) => {
const percentage = (currentStep / totalSteps) * 100;

return (
<>
{/* 진행도 바 */}
<div className="mt-6 mb-2">
<div className="h-2 w-full bg-gray-800 relative">
<div
className="absolute left-0 top-0 h-full bg-red-400"
style={{ width: `${percentage}%` }}
/>
</div>
</div>

{/* 진행 텍스트 */}
<div className="text-title-1 text-white mb-3 px-6">
{`${currentStep}/${totalSteps}`}
</div>
</>
);
};

export default ProgressBar;
14 changes: 7 additions & 7 deletions src/components/common/ToggleTab/ToggleTab.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { ToggleTabProps } from './ToggleTab.types';

const ToggleTab = ({ options, selected, onSelect }: ToggleTabProps) => {
const selectedIndex = options.findIndex((option) => option === selected);
const selectedIndex = options.findIndex((option) => option.value === selected);

return (
<div className="relative flex flex-col gap-5 p-4 bg-transparent w-full">
<div className="relative flex w-full max-w-[335px] h-12 bg-[rgba(66,66,66,0.3)] rounded-[12px] px-1 py-1 gap-[10px]">
<div className="relative flex flex-col gap-5 bg-transparent w-full">
<div className="relative flex w-full h-12 bg-[rgba(66,66,66,0.3)] rounded-[12px] px-1 py-1">
{/* Slider */}
<div
className="absolute top-2 h-[calc(100%-16px)] w-[calc(50%-14px)] border-[1.5px] border-gray-500 rounded-[8px] transition-all duration-300 z-10"
Expand All @@ -17,13 +17,13 @@ const ToggleTab = ({ options, selected, onSelect }: ToggleTabProps) => {
{/* Buttons */}
{options.map((option) => (
<button
key={option}
onClick={() => onSelect(option)}
key={option.value}
onClick={() => onSelect(option.value)}
className={`flex-1 z-20 text-body-1 py-[10px] transition-colors duration-200 whitespace-nowrap overflow-hidden text-ellipsis ${
option === selected ? 'text-[#E0E0E0]' : 'text-[#616161]'
option.value === selected ? 'text-[#E0E0E0]' : 'text-[#616161]'
}`}
>
{option}
{option.label}
</button>
))}
</div>
Expand Down
8 changes: 7 additions & 1 deletion src/components/common/ToggleTab/ToggleTab.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export interface ToggleOption {
label: string;
value: string;
}

export interface ToggleTabProps {
options: string[];
options: ToggleOption[];
selected: string;
onSelect: (option: string) => void;
className?: string;
}
1 change: 1 addition & 0 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import TagSection from '@/components/review/TagSection';
import Modal from '@/components/common/Modal/Modal';
import Header from '@/components/common/Header/Header';
import ImagePreviewItem from './common/ImagePreview/ImagePreviewItem';

export {
InputField,
Button,
Expand Down
88 changes: 66 additions & 22 deletions src/pages/onboarding/OnboardingGenrePage.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,81 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import ToggleTab from '@/components/common/ToggleTab/ToggleTab';
import { useOnboardingStore } from '@/store/useOnboardingStore';
import { Button, Header } from '@/components';
import { genreOptions } from '@/types/onboarding';
import type { GenreType } from '@/types/onboarding';

const genreOptions: GenreType[] = ['액션', '로맨스'];
import ProgressBar from '@/components/common/ProgressBar/ProgressBar';

const OnboardingGenrePage = () => {
const navigate = useNavigate();
const { setGenre } = useOnboardingStore();
const [selectedGenre, setSelectedGenre] = useState<GenreType | ''>('');
const [selectedGenres, setSelectedGenres] = useState<GenreType[]>([]);

const handleNext = () => {
if (!selectedGenre) {
alert('하나 이상의 장르를 선택해주세요!');
return;
const toggleGenre = (genre: GenreType) => {
const isSelected = selectedGenres.includes(genre);
if (isSelected) {
setSelectedGenres(selectedGenres.filter((g) => g !== genre));
} else {
if (selectedGenres.length >= 5) return;
setSelectedGenres([...selectedGenres, genre]);
}
};

const handleBack = () => {
navigate(-1);
};

setGenre([selectedGenre]);
navigate('/signup/onboarding/theater');
const handleNext = () => {
if (selectedGenres.length === 0) return;
navigate('/onboarding/theater');
};

return (
<div className="flex h-screen w-full flex-col items-center justify-center gap-8 px-6 py-8">
<ToggleTab
options={genreOptions}
selected={selectedGenre}
onSelect={(genre) => setSelectedGenre(genre as GenreType)} // optional
/>

<button onClick={handleNext} className="w-full max-w-sm bg-white text-black hover:opacity-90">
다음
</button>
<div className="min-h-screen bg-gray-900 text-white w-full max-w-[375px] mx-auto relative pb-32">
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

말씀드렸듯이, 이 부분에서도 배경색, 너비, 높이 관련 속성은 제거해주셔도 괜찮을 것 같아요~~

{/* 상단 헤더 */}
<Header title="" onBackClick={handleBack} showLike={false} showBookmark={false} />

{/* 진행도 바 */}
<ProgressBar currentStep={2} totalSteps={3} />

{/* 콘텐츠 영역 */}
<div className="px-6 mt-6">
{/* 타이틀 */}
<h1 className="text-title-2 text-white mb-1">좋아하는 장르를 선택해주세요</h1>
<p className="text-caption-2 text-red-300 mb-6">최대 5개까지 추가할 수 있어요.</p>

{/* 장르 선택 버튼 */}
<div className="flex flex-wrap gap-3 mb-20">
{genreOptions.map((genre) => {
const isSelected = selectedGenres.includes(genre);
return (
<Button
key={genre}
variant="secondary-assistive"
selected={isSelected}
onClick={() => toggleGenre(genre)}
fontType="body-1"
className="px-4 py-1"
>
{genre}
</Button>
);
})}
</div>
</div>

{/* 하단 버튼 */}
<div className="fixed bottom-8 left-1/2 -translate-x-1/2 w-full max-w-[375px] px-6">
<Button
onClick={handleNext}
disabled={selectedGenres.length === 0}
variant="primary"
color="red"
size="lg"
fontType="title-3"
className="w-full"
>
다음
</Button>
</div>
</div>
);
};
Expand Down
87 changes: 57 additions & 30 deletions src/pages/onboarding/OnboardingNicknamePage.tsx
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

온보딩 페이지에서 공통되는 속성들이 많은데 지민님이 올려주신 pr #23 에 제가 남겼던 리뷰 참고해서 라우팅 방식을 수정하는 것도 좋을 것 같다는 생각이 듭니다~~ 참고해주시면 좋을 것 같아요~

Original file line number Diff line number Diff line change
@@ -1,43 +1,70 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useOnboardingStore } from '@/store/useOnboardingStore';
import { Button, Header } from '@/components';
import Input from '@/components/common/Input/Input';
import ProgressBar from '@/components/common/ProgressBar/ProgressBar';

const OnboardingNicknamePage = () => {
const [nickname, setNickname] = useState('');
const { setNickname: saveNickname } = useOnboardingStore();
const [input, setInput] = useState('');
const navigate = useNavigate();

const handleNext = () => {
if (!nickname.trim()) return;
saveNickname(nickname);
navigate('/signup/genre'); // 다음 단계로 이동
navigate('/onboarding/genre');
};

const handleBack = () => {
navigate(-1);
};

return (
<div className="h-screen bg-[#121212] text-white flex flex-col items-center px-6 pt-20">
<p className="text-[#E31221] text-sm mb-2">1/3</p>
<h1 className="text-xl font-semibold mb-2">닉네임을 입력해주세요</h1>
<p className="text-sm text-gray-400 mb-8">다른 유저에게 보여질 이름이에요</p>

<input
type="text"
value={nickname}
onChange={(e) => setNickname(e.target.value)}
placeholder="닉네임을 입력하세요"
className="w-full max-w-sm px-4 py-3 rounded-md bg-[#1E1E1E] text-white border border-gray-600 placeholder-gray-500 focus:outline-none mb-6"
/>

<button
onClick={handleNext}
disabled={!nickname.trim()}
className={`w-full max-w-sm py-3 rounded-md font-semibold ${
nickname.trim()
? 'bg-[#E31221] text-white'
: 'bg-gray-600 text-gray-400 cursor-not-allowed'
}`}
>
다음
</button>
<div className="min-h-screen bg-gray-900 text-white w-full max-w-[375px] mx-auto relative pb-32">
{/* 상단 헤더 */}
<Header title="" onBackClick={handleBack} showLike={false} showBookmark={false} />

{/* 진행도 바 */}
<ProgressBar currentStep={1} totalSteps={3} />

{/* 콘텐츠 영역 */}
<div className="px-6 mt-6">
{/* 타이틀 */}
<h1 className="text-title-2 mb-10">프로필을 만들어주세요</h1>

{/* 프로필 이미지 (예시용 박스) */}
<div className="flex justify-center mb-10">
<div className="w-36 h-36 rounded-full bg-gray-100 flex items-center justify-center text-black text-sm">
갤러리 아이콘
</div>
</div>

{/* 닉네임 입력 */}
<div className="mb-2">
<Input
label=""
value={input}
onChange={setInput}
placeholder="닉네임을 입력해주세요"
placeholderColorType="gray"
showBackground={true}
/>
</div>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Input 컴포넌트도 제가 onClickPlus prop을 전달받지 않으면 + 버튼 랜더링 되지 않도록 수정해두었습니다! pull하신 후에 잘 적용되는지 한 번 확인해주세요 🙌🙌


<p className="text-caption-3 text-gray-500 ml-1">10자 이내로 작성해주세요.</p>
</div>

{/* 하단 버튼 */}
<div className="fixed bottom-8 left-1/2 -translate-x-1/2 w-full max-w-[375px] px-6">
<Button
onClick={handleNext}
disabled={!input.trim()}
variant="primary"
color="red"
size="lg"
fontType="title-3"
className="w-full"
>
다음
</Button>
</div>
</div>
);
};
Expand Down
Loading