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

[WRFE-48] 래플/이벤트 수정 페이지 #50

Open
wants to merge 18 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 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
67 changes: 67 additions & 0 deletions apps/front/wraffle-webview/app/products/[id]/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use client';

import {
createRaffleSchema,
type CreateRafflePayload,
} from '@/entities/product/model';
import {Header} from '@/shared/ui';
import GenericForm from '@/shared/ui/form/GenericForm';
import {EditList} from '@/widgets/product-list/edit/ui';
import {zodResolver} from '@hookform/resolvers/zod';
import {Typography} from '@wraffle/ui';

// 조회 api 연결시 삭제할 코드 입니다
const product = {
title: 'test Title',
categoryId: '1',
tagIds: [1, 2],
images: ['/1', '/2', '/3'],
price: '999999',
startDate: new Date(),
endDate: new Date(),
announceAt: new Date(),
winnerCount: '99',
etc: 'test ETC',
};

const Edit = ({
params: {id},
searchParams: {type},
}: {
params: {id: string};
searchParams: {type: 'raffle' | 'event'};
}) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

혹시 interface를 따로 선언하지 않는 이유가 따로 있으신가요?
저는 보통

interface Params {
 id : string;
}

interface SearchParams {
 type : 'raffle' | 'event'
}

interface EditProps {
 params : Params;
 searchParams : SearchParams;
}

요런식으로 썼는데 interface 파일만 읽더라도 이 컴포넌트에서 대충 어느게 필요하겠구나에 대한
생각을 분리할 수 있어서 좋은 것 같았어요
이 부분에 대한 장현님의 생각은 어떠신가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

interface를 따로 선언하지 않는 이유는

  1. 나누지 않는게 더 직관적이다 생각하고,
  2. 개인적으로 코드를 읽을 때 아래 ->위 (왼 -> 오)로 읽는게 좋아서,
  3. 코드양이 굳이 늘아난다는 느낌을 가지고 있었습니다.

인터페이스로 분리할 때는 가독성이 떨어진다 느껴질 때 (ex. props로 받아오는게 많다거나, 복잡한 관계라던가..) 분리를 해서 사용해왔었는데,
'생각을 분리해 볼 수 있다' 와 같은 생각은 못해봤던 접근이어서 한번 생각해보겠습니다!
(이렇게 적었는데 밑에 훅 보니까 분리해서 사용했네요 ; 3개가 많다 생각하진 않는데)

Copy link
Contributor

Choose a reason for hiding this comment

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

그럼 통일되는 편이 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

825710c
수정 커밋입니다!
다른 코드를 보았을 때, interface로 분리된 코드가 많아서 통일시키는편이 좋을거 같아서 분리시켜두었습니다!

const onSubmit = (data: CreateRafflePayload) => {
console.log(data);
};

return (
<div>
<div className='my-5'>
<Header withUnderline>
<Header.Left>
<Header.BackButton />
</Header.Left>
<Header.Middle>
<Typography className='text-sm font-semibold text-[#191F28]'>
래플 수정
</Typography>
</Header.Middle>
</Header>
</div>

<GenericForm
onSubmit={onSubmit}
formOptions={{
mode: 'onSubmit',
resolver: zodResolver(createRaffleSchema),
defaultValues: product,
}}
>
<EditList type={type} />
</GenericForm>
</div>
);
};

export default Edit;
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const EventCreate = () => {
return (
<div>
{funnel.index < EventTotalStepIndex && (
<div className='py-5'>
<div className='my-5'>
<Header>
<Header.Left>
<Header.BackButton onClick={() => funnel.history.back()} />
Expand Down

This file was deleted.

This file was deleted.

2 changes: 2 additions & 0 deletions apps/front/wraffle-webview/src/features/image-handle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export {AddItemCard} from './ui/AddItemCard';
export {ImageCardWithDelete} from './ui/ImageCardWithDelete';
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client';

import clsx from 'clsx';

export const AddItemCard = ({
label,
onClick,
className,
}: {
label: string;
onClick: () => void;
className: string;
}) => (
<button
className={clsx(
'relative flex aspect-square items-center justify-center rounded-lg border border-solid border-[#F5F5F7] bg-[#FAFAFB] text-sm font-medium text-[#ADB5BD]',
className,
)}
onClick={onClick}
>
{label}
</button>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client';

import clsx from 'clsx';
import Image from 'next/image';

export const ImageCardWithDelete = ({
url,
onClick,
className,
}: {
url: string;
onClick: () => void;
className: string;
}) => (
<div
className={clsx(
'relative flex-none overflow-hidden rounded-lg bg-slate-100',
className,
)}
>
<button type='button' className='absolute right-2 top-2' onClick={onClick}>
<Image src={'/icons/ic_close.svg'} alt='close' width={12} height={12} />
</button>
<Image
alt='thumbnail'
width={160}
height={160}
src={url}
className='h-full w-full object-cover'
/>
</div>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const STARTDATE_IS_OVER_ENDDATE = {
title: '유효하지 않은 날짜입니다.',
description: '응모 시작 일정은 응모 마감 일정 이후로 설정해주세요.',
duration: 5000,
variant: 'warning',
};

export const ENDDATE_IS_OVER_ANNOUNCEAT = {
title: '유효하지 않은 날짜입니다.',
description: '응모 마감 일정은 당첨자 발표 일정 이후로 설정해주세요.',
duration: 5000,
variant: 'warning',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const validateDate = (
Copy link
Contributor

Choose a reason for hiding this comment

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

validateDate 보다는 이 날짜가 이전 날짜 보다 큰지를 보여주도록 함수 명에서 드러나면 좋을 것 같아요
isDateBefore 같은 느낌이 되면 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

17b7a0f
수정 커밋입니다!

date: Date | undefined,
referenceDate: Date | undefined,
) => {
if (!date || !referenceDate) return true;
if (date > referenceDate) {
return false;
}
return true;
};
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
'use client';

import type {CreateEventPayload} from '../../../entities/product/model';
import {ENDDATE_IS_OVER_ANNOUNCEAT} from '../config/const';
import {validateDate} from '../config/validateDate';
import {useFormContext} from 'react-hook-form';
import {FormControl, FormField, FormItem, FormLabel} from '@/shared/ui';
import {CalendarForm, useToast} from '@wraffle/ui';

export const EndDateForm = ({
defaultValue,
fromDate: startDate,
referenceDate: announceAt,
}: {
defaultValue: Date;
defaultValue: Date | undefined;
fromDate: Date;
referenceDate: Date | undefined;
}) => {
const {control} = useFormContext<CreateEventPayload>();
const {toast} = useToast();

return (
<FormField
control={control}
Expand All @@ -25,7 +30,13 @@ export const EndDateForm = ({
<CalendarForm
dateLabel='응모 마감 시간을 입력해주세요.'
selected={defaultValue}
setSelected={field.onChange}
onSelect={date => {
if (validateDate(date, announceAt)) {
field.onChange(date);
} else {
toast(ENDDATE_IS_OVER_ANNOUNCEAT);
}
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

ui에서 이 로직을 담당하는 것 보다는 onSelect를 외부에서 받아서 관리하는 방식이 좋아보일 것 같아요!
추후에 이 로직을 수정하기 위해서는 ui에 해당하는 이 onSelect까지 와야 한다는 사실을 알기 어려울 것 같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

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

1ff0234
수정 커밋입니다!

fromDate={startDate}
onClick={e => {
if (!startDate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const PriceForm = ({
<FormControl>
<div className='relative w-full'>
<Input
className='border-[#F5F5F7] bg-[#FAFAFB] pr-10 placeholder:text-[#ADB5BD]'
className='border-[#F5F5F7] bg-[#FAFAFB] pr-10 text-right text-base font-medium placeholder:text-left placeholder:text-[#ADB5BD]'
id='price'
type='text'
inputMode='numeric'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
'use client';

import type {CreateEventPayload} from '../../../entities/product/model';
import {STARTDATE_IS_OVER_ENDDATE} from '../config/const';
import {validateDate} from '../config/validateDate';
import {useFormContext} from 'react-hook-form';
import {FormControl, FormField, FormItem, FormLabel} from '@/shared/ui';
import {CalendarForm} from '@wraffle/ui';
import {CalendarForm, useToast} from '@wraffle/ui';

export const StartDateForm = ({defaultValue}: {defaultValue: Date}) => {
export const StartDateForm = ({
defaultValue,
referenceDate: endDate,
}: {
defaultValue: Date | undefined;
referenceDate: Date | undefined;
}) => {
const {control} = useFormContext<CreateEventPayload>();
const {toast} = useToast();
return (
<FormField
control={control}
Expand All @@ -18,7 +27,13 @@ export const StartDateForm = ({defaultValue}: {defaultValue: Date}) => {
<CalendarForm
dateLabel='응모 시작 시간을 입력해주세요.'
selected={defaultValue}
setSelected={field.onChange}
onSelect={date => {
if (validateDate(date, endDate)) {
field.onChange(date);
} else {
toast(STARTDATE_IS_OVER_ENDDATE);
}
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분도 위와 동일 합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

1ff0234
수정 커밋입니다!

fromDate={new Date()}
/>
</FormControl>
Expand Down
3 changes: 3 additions & 0 deletions apps/front/wraffle-webview/src/shared/ui/divider/Divider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const Divider = () => {
return <div className='h-1 w-full bg-[#F9FAFB]' />;
};
1 change: 1 addition & 0 deletions apps/front/wraffle-webview/src/shared/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './form';
export * from './header/Header';
export * from './progress/Progress';
export * from './Timer';
export * from './divider/Divider';
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

import {useDateValidationWithToast} from '../../lib/hooks';
import {useEffect} from 'react';
import {useFormContext, useWatch} from 'react-hook-form';
import type {CreateEventPayload} from '@/entities/product/model';
Expand All @@ -10,7 +11,7 @@ import {
WinnerCountForm,
} from '@/features/product-form/ui';
import {getTypeText} from '@/shared/util';
import {Button, Toaster, Typography, useToast} from '@wraffle/ui';
import {Button, Toaster, Typography} from '@wraffle/ui';

export const DateStep = ({
type,
Expand All @@ -26,42 +27,29 @@ export const DateStep = ({
}) => {
const eventOrRaffleText = getTypeText(type);

const {setValue, control} = useFormContext<CreateEventPayload>();
const {control, setValue} = useFormContext<CreateEventPayload>();

const [startDate, endDate, announceAt, winnerCount] = useWatch({
control,
name: ['startDate', 'endDate', 'announceAt', 'winnerCount'],
});

const {toast} = useToast();

const disabled = !startDate || !endDate || !announceAt || !winnerCount;

useDateValidationWithToast({startDate, endDate, announceAt});

useEffect(() => {
if (endDate < startDate) {
setValue('endDate', startDate);
toast({
title: '응모 마감 일정은',
description: '응모 시작 일정 이후로 설정해주세요.',
duration: 10000,
variant: 'warning',
});
}

if (announceAt < endDate) {
setValue('announceAt', endDate);
toast({
title: '당첨자 발표 일정은',
description: '응모 마감 일정 이후로 설정해주세요.',
duration: 10000,
variant: 'warning',
});
}
}, [startDate, endDate, announceAt]);
}, [startDate, endDate]);

return (
<div className='flex h-full flex-col gap-5 px-5 pb-20'>
<div className='fixed top-5'>
<div className='fixed top-5 z-10'>
<Toaster />
</div>
<div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ThumbnailCard} from '@/entities/product/ui';
import {AddItemCard, ImageCardWithDelete} from '@/features/image-handle';
import {Button, Label, Typography} from '@wraffle/ui';

// TODO
Expand Down Expand Up @@ -26,16 +26,21 @@ export const ImageStep = ({onNext}: {onNext: (images: string[]) => void}) => {
</Label>
</div>

<div className='grid w-full max-w-[21rem] grid-cols-2 gap-4 sm:max-w-[55rem] sm:grid-cols-4'>
{images.map((url, i) => (
<ThumbnailCard key={i} url={url} />
<div className='flex flex-wrap gap-4'>
{images.map(url => (
<ImageCardWithDelete
key={url}
url={url}
onClick={() => {}}
className='h-40 w-40'
/>
))}
{images.length < 4 && (
<div className='relative flex aspect-square max-h-40 w-full max-w-40 rounded-lg border border-solid border-[#F5F5F7] bg-[#FAFAFB] sm:max-h-52 sm:max-w-52'>
<div className='flex h-full w-full items-center justify-center rounded-lg text-center text-sm font-medium text-[#ADB5BD]'>
이미지 추가
</div>
</div>
<AddItemCard
label='이미지 추가'
onClick={() => {}}
className='h-40 w-40'
/>
)}
</div>

Expand Down
Loading