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: 대시보드 이벤트 기본 정보, 상세와 사진 페이지 퍼블리싱 #44

Merged
merged 12 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions design-system/stories/ChoiceChip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default meta;

export const TwoOptions: Story = {
args: {
label: '',
options: ['선착순', '주최자 선별'],
onSelect: (selected: string) => {
console.log(`Selected option: ${selected}`);
Expand All @@ -37,6 +38,7 @@ export const TwoOptions: Story = {

export const ThreeOptions: Story = {
args: {
label: '',
options: ['객관식', '주관식', '여러 개 선택'],
onSelect: (selected: string) => {
console.log(`Selected option: ${selected}`);
Expand Down
5 changes: 0 additions & 5 deletions design-system/stories/textFields/DefaultTextField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export const Default: Story = {
detail: '',
onChange: e => console.log(e.target.value),
placeholder: '입력해주세요',
className: 'h-12',
labelClassName: 'sm:text-base md:text-lg',
},
};
Expand All @@ -54,7 +53,6 @@ export const WithTitleTextField: Story = {
leftText: '받는',
onChange: e => console.log(e.target.value),
placeholder: '입력해주세요',
className: 'h-12',
labelClassName: 'sm:text-base md:text-lg',
},
};
Expand All @@ -69,7 +67,6 @@ export const WithIconButtonTextField: Story = {
),
onChange: e => console.log(e.target.value),
placeholder: '입력해주세요',
className: 'h-12',
labelClassName: 'sm:text-base md:text-lg',
},
};
Expand All @@ -79,7 +76,6 @@ export const WithLabelTextField: Story = {
detail: '',
onChange: e => console.log(e.target.value),
placeholder: '입력해주세요',
className: 'h-12',
labelClassName: 'sm:text-base md:text-lg',
},
};
Expand All @@ -89,7 +85,6 @@ export const WithLabelDetailTextField: Story = {
detail: 'detail',
onChange: e => console.log(e.target.value),
placeholder: '입력해주세요',
className: 'h-12',
labelClassName: 'sm:text-base md:text-lg',
},
};
27 changes: 16 additions & 11 deletions design-system/ui/ChoiceChip.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useState } from 'react';

interface ChoiceChipProps {
label?: string;
options: string[];
onSelect: (selected: string) => void;
className?: string;
labelClassName?: string;
}

const ChoiceChip = ({ options, onSelect, className }: ChoiceChipProps) => {
const ChoiceChip = ({ label, options, onSelect, className, labelClassName = '' }: ChoiceChipProps) => {
const [selected, setSelected] = useState(options[0]);

const handleClick = (option: string) => {
Expand All @@ -15,19 +17,22 @@ const ChoiceChip = ({ options, onSelect, className }: ChoiceChipProps) => {
};

return (
<div className={`flex justify-between bg-gray-300 rounded-full p-1 ${className}`}>
{options.map((option, index) => (
<button
key={index}
className={`
<div>
<label className={`block px-1 font-semibold text-gray-700 mb-2 ${labelClassName}`}>{label}</label>
<div className={`flex justify-between bg-gray-300 rounded-full p-1 ${className}`}>
{options.map((option, index) => (
<button
key={index}
className={`
flex justify-center items-center sm:text-xs md:text-sm lg:text-base px-2 rounded-full
${selected === option ? 'bg-white text-black' : 'text-black bg-transparent'}
`}
onClick={() => handleClick(option)}
>
{option}
</button>
))}
onClick={() => handleClick(option)}
>
{option}
</button>
))}
</div>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion design-system/ui/textFields/DefaultTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const DefaultTextField = forwardRef<HTMLInputElement, DefaultTextFieldProps>(
onKeyDown={onKeyDown}
placeholder={placeholder}
{...rest}
className={`w-full h-full border border-placeholderText rounded-[3px] px-2 py-1 outline-none placeholder:text-placeholderText text-xs font-light resize-none`}
className={`w-full h-12 border border-placeholderText rounded-[3px] px-2 py-1 outline-none placeholder:text-placeholderText text-xs font-light resize-none`}
/>
{rightContent && <div className="ml-3">{rightContent}</div>}
</div>
Expand Down
2 changes: 1 addition & 1 deletion public/assets/dashboard/menu/EventInfo(black).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: 1 addition & 1 deletion public/assets/dashboard/menu/EventInfo(pink).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 public/assets/dashboard/menu/Tag(black).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 public/assets/dashboard/menu/Tag(pink).svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/app/routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import HostEditPage from '../../pages/menu/ui/HostEditPage';
import MyPage from '../../pages/menu/ui/MyPage';
import MenuPage from '../../pages/menu/ui/MenuPage';
import DashboardPage from '../../pages/dashboard/ui/DashbaordPage';
import EventInfoPage from '../../pages/dashboard/ui/EventInfoPage';
import EventDetailPage from '../../pages/dashboard/ui/EventDetailPage';
import EventTagPage from '../../pages/dashboard/ui/EventTagPage';

const routesConfig = [
{
Expand Down Expand Up @@ -82,6 +85,21 @@ const routesConfig = [
element: <DashboardPage />,
requiresAuth: false,
},
{
path: DASHBOARD_ROUTES.eventInfo,
element: <EventInfoPage />,
requiresAuth: false,
},
{
path: DASHBOARD_ROUTES.eventDetail,
element: <EventDetailPage />,
requiresAuth: false,
},
{
path: DASHBOARD_ROUTES.eventTag,
element: <EventTagPage />,
requiresAuth: false,
},
];

const router = createBrowserRouter(
Expand Down
3 changes: 3 additions & 0 deletions src/app/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ export const MENU_ROUTES = {

export const DASHBOARD_ROUTES = {
dashboard: `${MAIN_ROUTES.dashbord}`,
eventInfo: `${MAIN_ROUTES.dashbord}/eventInfo`,
eventDetail: `${MAIN_ROUTES.dashbord}/eventDetail`,
eventTag: `${MAIN_ROUTES.dashbord}/eventTag`,
};
32 changes: 17 additions & 15 deletions src/features/event-manage/ui/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import { useEffect, useState } from 'react';
import DatePicker from 'react-datepicker';
import { ko } from 'date-fns/locale';
import 'react-datepicker/dist/react-datepicker.css';
import { useFunnelState } from '../model/FunnelContext';
import { FunnelState } from '../model/FunnelContext';

interface DatePickerProps {
className?: string;
formState?: FunnelState['formState'];
setFormState?: React.Dispatch<React.SetStateAction<FunnelState['formState']>>;
}

const EventDatePicker = ({ className }: DatePickerProps) => {
const { formState, setFormState } = useFunnelState();

const EventDatePicker = ({ className, formState, setFormState }: DatePickerProps) => {
const [startDate, setStartDate] = useState<Date | null>(
formState.startDate ? new Date(formState.startDate) : new Date()
formState?.startDate ? new Date(formState.startDate) : new Date()
);
const [endDate, setEndDate] = useState<Date | null>(formState.endDate ? new Date(formState.endDate) : new Date());
const [startTime, setStartTime] = useState<string>(formState.startTime || '06:00');
const [endTime, setEndTime] = useState<string>(formState.endTime || '23:00');
const [endDate, setEndDate] = useState<Date | null>(formState?.endDate ? new Date(formState.endDate) : new Date());
const [startTime, setStartTime] = useState<string>(formState?.startTime || '06:00');
const [endTime, setEndTime] = useState<string>(formState?.endTime || '23:00');

const generateTimeOptions = () => {
const options = [];
Expand All @@ -41,13 +41,15 @@ const EventDatePicker = ({ className }: DatePickerProps) => {
const timeOptions = generateTimeOptions();

useEffect(() => {
setFormState(prev => ({
...prev,
startDate: startDate ? formatDate(startDate) : undefined,
endDate: endDate ? formatDate(endDate) : undefined,
startTime,
endTime,
}));
if (setFormState) {
setFormState(prev => ({
...prev,
startDate: startDate ? formatDate(startDate) : undefined,
endDate: endDate ? formatDate(endDate) : undefined,
startTime,
endTime,
}));
}
}, [startDate, endDate, startTime, endTime, setFormState]);

return (
Expand Down
24 changes: 15 additions & 9 deletions src/features/event-manage/ui/EventCategory.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { useState } from 'react';
import CategoryButton from '../../../../public/assets/event-manage/BackBtn(black).svg';
import { useFunnelState } from '../model/FunnelContext';
import { FunnelState } from '../model/FunnelContext';

interface Category {
id: string;
name: string;
}

const EventCategory = () => {
const { formState, setFormState } = useFunnelState();
interface EventCategoryProps {
formState?: FunnelState['formState'];
setFormState?: React.Dispatch<React.SetStateAction<FunnelState['formState']>>;
}

const EventCategory = ({ formState, setFormState }: EventCategoryProps) => {
const [open, setOpen] = useState(false);

const categories: Category[] = [
Expand All @@ -21,10 +25,12 @@ const EventCategory = () => {
const handleDropdown = () => setOpen(!open);

const handleSelect = (id: string) => {
setFormState(prev => ({
...prev,
category: id,
}));
if (setFormState) {
setFormState(prev => ({
...prev,
category: id,
}));
}
setOpen(false);
};

Expand All @@ -39,7 +45,7 @@ const EventCategory = () => {
className="flex justify-between p-2 text-left bg-white border border-placeholderText rounded-[2px] focus:outline-none w-full max-w-52"
>
<span>
{formState.category ? categories.find(c => c.id === formState.category)?.name : '이벤트 카테고리 선택'}
{formState?.category ? categories.find(c => c.id === formState.category)?.name : '이벤트 카테고리 선택'}
</span>
<img src={CategoryButton} alt="카테고리 버튼" className="w-6 h-6 -rotate-90" />
</button>
Expand All @@ -50,7 +56,7 @@ const EventCategory = () => {
key={category.id}
onClick={() => handleSelect(category.id)}
className={`p-2 cursor-pointer hover:bg-dropdown transition-colors ${
formState.category === category.id ? 'bg-dropdown' : ''
formState?.category === category.id ? 'bg-dropdown' : ''
}`}
>
{category.name}
Expand Down
40 changes: 25 additions & 15 deletions src/features/event-manage/ui/EventTag.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import { ChangeEvent, KeyboardEvent, useState } from 'react';
import { useFunnelState } from '../model/FunnelContext';
import { FunnelState } from '../model/FunnelContext';
import MultilineTextField from '../../../../design-system/ui/textFields/MultilineTextField';

const EventTag = () => {
const { formState, setFormState } = useFunnelState();
interface EventTagProps {
formState?: FunnelState['formState'];
setFormState?: React.Dispatch<React.SetStateAction<FunnelState['formState']>>;
}

const EventTag = ({ formState, setFormState }: EventTagProps) => {
const [inputValue, setInputValue] = useState('');
const MAX_TAGS = 5;

const handleInputChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
setInputValue(e.target.value);
};

const hashtags = formState?.hashtags || [];

const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter' && inputValue.trim()) {
e.preventDefault();

if (formState.hashtags.length >= MAX_TAGS) {
if (hashtags.length >= MAX_TAGS) {
return;
}

const newTag = inputValue.trim();
if (!formState.hashtags.includes(newTag)) {
setFormState(prev => ({
...prev,
hashtags: [...prev.hashtags, newTag],
}));
if (!formState?.hashtags.includes(newTag)) {
if (setFormState) {
setFormState(prev => ({
...prev,
hashtags: [...prev.hashtags, newTag],
}));
}
setInputValue('');
}
}
};

const removeHashtag = (tagToRemove: string) => {
setFormState(prev => ({
...prev,
hashtags: prev.hashtags.filter(tag => tag !== tagToRemove),
}));
if (setFormState) {
setFormState(prev => ({
...prev,
hashtags: prev.hashtags.filter(tag => tag !== tagToRemove),
}));
}
};

return (
Expand All @@ -49,12 +59,12 @@ const EventTag = () => {
onKeyDown={handleKeyDown}
placeholder="엔터를 이용해 태그를 입력하세요"
className="w-full h-40"
disabled={formState.hashtags.length >= MAX_TAGS}
disabled={hashtags.length >= MAX_TAGS}
/>
</div>

<div className="flex flex-wrap gap-2">
{formState.hashtags.map((tag, index) => (
{formState?.hashtags.map((tag, index) => (
<div key={index} className="inline-flex items-center border border-main bg-dropdown px-3 py-1 rounded-[1px]">
<span className="text-main mr-2">{tag}</span>
<button onClick={() => removeHashtag(tag)} className="text-main focus:outline-none">
Expand Down
Loading
Loading