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

refactor: 생년월일 입력 - 변경된 디자인 적용 및 리팩터링 #233

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
85cdf20
chore: DATE_SAPARATOR를 constants화 해서 사용
Doeunnkimm Mar 26, 2024
eb57da4
refactor: 변경된 디자인 적용 및 기능 리팩터링
Doeunnkimm Mar 26, 2024
ec42fab
chore: 정보수정 페이지에서 생년월일 부분 반영
Doeunnkimm Mar 26, 2024
484ad32
chore: default값으로 인해 붙는 separator를 예외시키기 위해 filter 메서드 추가
Doeunnkimm Mar 26, 2024
27c5939
fix: formattedValue가 format과 일치하는지 검사하는 검증 추가
Doeunnkimm Mar 26, 2024
e32c85e
feat: member/new/birth에서 유효성 검증 추가
Doeunnkimm Mar 26, 2024
5dbf066
feat: 타임라인 조회 api 반영 (#231)
newminkyung Mar 27, 2024
c7470ee
feat: 댓글 기능 api 연동 및 ios에서 키패드 이슈 대응 (#223)
Doeunnkimm Mar 29, 2024
1042a1e
refactor: 오류 페이지 컴포넌트 리팩터링 (#236)
Doeunnkimm Apr 2, 2024
4645efa
fix: 존재하지 않는 유저 지도 접근시 에러 처리 (#237)
Doeunnkimm Apr 2, 2024
a55e0c7
feat: 응원한 사람 조회 api 응답 값 수정 반영 / 응원하기 성공 시에도 에러 토스트가 뜨는 버그 수정 (#232)
newminkyung Apr 2, 2024
0264c2f
feat: 피드 이모지 추가/삭제시 낙관적 업데이트 적용 (#234)
hjy0951 Apr 2, 2024
c360db8
feat: 목표 수정 기능 개발 (#192)
deepbig Apr 2, 2024
0f7f44b
fix: 타임라인 조회 쿼리키 수정 (#238)
newminkyung Apr 2, 2024
4afb2d9
fix: 피드 페이지에서 댓글 API 요청시 누락된 목표 ID 추가 (#239)
hjy0951 Apr 2, 2024
d5f69b6
chore: DATE_SAPARATOR를 constants화 해서 사용
Doeunnkimm Mar 26, 2024
87f1f66
refactor: 변경된 디자인 적용 및 기능 리팩터링
Doeunnkimm Mar 26, 2024
f11ca1b
chore: 정보수정 페이지에서 생년월일 부분 반영
Doeunnkimm Mar 26, 2024
9b97ac6
chore: default값으로 인해 붙는 separator를 예외시키기 위해 filter 메서드 추가
Doeunnkimm Mar 26, 2024
b9200f5
fix: formattedValue가 format과 일치하는지 검사하는 검증 추가
Doeunnkimm Mar 26, 2024
cf4542e
feat: member/new/birth에서 유효성 검증 추가
Doeunnkimm Mar 26, 2024
288018c
Merge branch 'chore/dateInput' of https://github.com/depromeet/amazin…
Doeunnkimm Apr 2, 2024
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: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
"source.fixAll.stylelint": "explicit",
"source.addMissingImports": "explicit"
},
"editor.formatOnSave": true
"editor.formatOnSave": true,
"cSpell.words": ["bandiboodi", "bandi", "boodi"]
}
4 changes: 2 additions & 2 deletions src/app/error/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ErrorPageLayout } from '@/features/customErrors/components';
import { DefaultErrorPage } from '@/features/customErrors/components';

const ErrorPage = () => {
return <ErrorPageLayout statusCode={500} />;
return <DefaultErrorPage statusCode={500} />;
};

export default ErrorPage;
2 changes: 1 addition & 1 deletion src/app/goal/detail/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { PropsWithChildren } from 'react';

const layout = ({ children }: PropsWithChildren) => {
return <main className="relative h-screen">{children}</main>;
return <main className="relative h-[100dvh]">{children}</main>;
};

export default layout;
2 changes: 1 addition & 1 deletion src/app/goal/new/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import CreateGoalFormProvider from '@/features/goal/contexts/CreateGoalFormProvi
const Layout = ({ children }: PropsWithChildren) => {
return (
<CreateGoalFormProvider>
<div className="w-full h-screen bg-gradient1 relative">
<div className="w-full h-[100dvh] bg-gradient1 relative">
<SpeechBubble className="absolute top-[-4%] w-full" />
<Stars className="absolute top-[28%] left-1/4 w-1/2" />
<Image
Expand Down
29 changes: 29 additions & 0 deletions src/app/goal/update/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use client';

import { useEffect } from 'react';
import { useRouter } from 'next/navigation';

import GoalUpdateForm from '@/features/goal/components/update/GoalUpdateForm';
import { useGetGoal } from '@/hooks/reactQuery/goal';

interface ParamsProps {
params: {
id: string;
};
}

const UpdateGoalPage = ({ params }: ParamsProps) => {
const goalId = +params['id'];
const { data: goal } = useGetGoal({ goalId });
const router = useRouter();

useEffect(() => {
if (goal?.isMyGoal === false) {
router.push(`/goal/detail/${goalId}`);
}
}, [goal, goalId, router]);

return goal?.isMyGoal && <GoalUpdateForm goalId={goalId} goal={goal} />;
};

export default UpdateGoalPage;
9 changes: 9 additions & 0 deletions src/app/goal/update/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client';

import type { PropsWithChildren } from 'react';

const UpdateGoalLayout = ({ children }: PropsWithChildren) => {
return <div className="w-full bg-[#F8FBFF]">{children}</div>;
};

export default UpdateGoalLayout;
25 changes: 22 additions & 3 deletions src/app/home/[username]/error.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
'use client';

import { ErrorPageLayout } from '@/features/customErrors/components';
import Image from 'next/image';
import type { AxiosError } from 'axios';

const Error = ({ error }: { error: Error & { digest?: string } }) => {
return <ErrorPageLayout statusCode={403} />;
import NullUserErrorImage from '@/assets/images/error/close.png';
import { DefaultErrorPage } from '@/features/customErrors/components';
import { ErrorPageLayout } from '@/features/customErrors/components/errorPageLayout';
import { ResetButton } from '@/features/customErrors/components/errorPageLayout/ResetButton';

const ERROR_STATUS_CODE = {
public: 403,
nullUser: 404,
};

const Error = ({ error }: { error: AxiosError & { digest?: string } }) => {
if (error.status === ERROR_STATUS_CODE.public) return <DefaultErrorPage statusCode={403} />;
if (error.status === ERROR_STATUS_CODE.nullUser)
return (
<ErrorPageLayout
TopComponent={<Image src={NullUserErrorImage} width={146} height={189} alt="null_user_error" />}
title={`앗, 존재하지 않는 인생지도에요. \n 페이지 주소를 다시 확인해주세요.`}
footer={<ResetButton statusCode={403} />}
/>
);
};

export default Error;
4 changes: 2 additions & 2 deletions src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ErrorPageLayout } from '@/features/customErrors/components';
import { DefaultErrorPage } from '@/features/customErrors/components';

const NotFoundPage = () => {
return <ErrorPageLayout statusCode={404} />;
return <DefaultErrorPage statusCode={404} />;
};

export default NotFoundPage;
Binary file added src/assets/images/error/close.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 2 additions & 4 deletions src/components/atoms/bottomSheet/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@
}

[data-rsbs-header] {
text-align: left;
padding-bottom: 0;
box-shadow: none;
@apply text-left pb-0 shadow-none px-xs;
}

[data-rsbs-footer] {
box-shadow: none;
@apply shadow-none px-xs;
}
2 changes: 1 addition & 1 deletion src/components/atoms/input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
<input
className={inputVariants({ className })}
ref={ref}
{...props}
onFocus={handleFocus}
onBlur={handleBlur}
{...props}
/>
{includeSubmitButton && (
<div className="w-[32px] h-[32px]">
Expand Down
5 changes: 2 additions & 3 deletions src/components/atoms/textarea/Textarea.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { HTMLAttributes } from 'react';
import { forwardRef } from 'react';
import { forwardRef, type TextareaHTMLAttributes } from 'react';
import type { VariantProps } from 'class-variance-authority';
import { cva } from 'class-variance-authority';

Expand All @@ -9,7 +8,7 @@ const textareaVariants = cva(
focus-visible:outline-none resize-none',
);

interface TextareaProps extends HTMLAttributes<HTMLTextAreaElement>, VariantProps<typeof textareaVariants> {}
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, VariantProps<typeof textareaVariants> {}

export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }: TextareaProps, ref) => {
Expand Down
6 changes: 3 additions & 3 deletions src/components/molecules/comment/Comment.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ type Story = StoryObj<typeof Comment>;

export const Basic: Story = {
args: {
user: {
url: 'https://github.com/depromeet/amazing3-fe/assets/112946860/8ee0540f-4c8f-4d9e-80f4-671e60c292e8',
commenter: {
image: 'https://github.com/depromeet/amazing3-fe/assets/112946860/8ee0540f-4c8f-4d9e-80f4-671e60c292e8',
nickname: '산타할아버지',
username: 'BANDIBOODI-6',
},
content: '엄청나다! 너의 목표',
createdAt: '2024-02-29T07:34:58.356Z',
writtenAt: '2024-02-29T07:34:58.356Z',
},
};

Expand Down
35 changes: 23 additions & 12 deletions src/components/molecules/comment/Comment.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
'use client';

import Image from 'next/image';
import Link from 'next/link';
import { m } from 'framer-motion';

import TrashIcon from '@/assets/icons/trash-icon.svg';
import { Typography } from '@/components';
import { convertTimeToElapsedTime } from '@/utils/date';

interface CommentProps {
user: {
url: string;
commenter: {
image: string;
nickname: string;
username: string;
};
content: string;
createdAt: string;
writtenAt: string;
isDeletable?: boolean;
onDelete?: VoidFunction;
}

export const Comment = ({ user, content, createdAt, isDeletable, onDelete }: CommentProps) => {
export const Comment = ({ commenter, content, writtenAt, isDeletable, onDelete }: CommentProps) => {
return (
<div className="flex gap-4xs">
<Link href={{ pathname: `/home/${user.username}` }}>
<Image src={user.url} width={50} height={50} alt="user_profile_image" className="rounded-full" />
<m.div className="flex gap-4xs" {...animate}>
<Link href={{ pathname: `/home/${commenter.username}` }}>
<Image src={commenter.image} width={50} height={50} alt="user_profile_image" className="rounded-full" />
</Link>
<div className="w-full flex flex-col justify-between">
<div className="w-full flex justify-between">
<div className="flex gap-6xs items-center">
<Link href={{ pathname: `/home/${user.username}` }}>
<Typography type="body3">{user.nickname}</Typography>
<Link href={{ pathname: `/home/${commenter.username}` }}>
<Typography type="body3">{commenter.nickname}</Typography>
</Link>
{/* TODO: 시간 정책 맞게 변환해주는 유틸 함수 래핑 */}
<Typography type="caption1" className="text-gray-40">
{createdAt}
{convertTimeToElapsedTime(writtenAt)}
</Typography>
</div>
{isDeletable && (
Expand All @@ -41,6 +44,14 @@ export const Comment = ({ user, content, createdAt, isDeletable, onDelete }: Com
</div>
<Typography type="body2">{content}</Typography>
</div>
</div>
</m.div>
);
};

const animate = {
layout: true,
initial: { y: -20 },
animate: { y: 0 },
exit: { opacity: 0, y: -20, height: 0, overflow: 'hidden', transition: { duration: 0.3 } },
transition: { duration: 0.3 },
};
108 changes: 108 additions & 0 deletions src/components/molecules/reactHookForm/RHFDateField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { type InputHTMLAttributes, useEffect, useState } from 'react';
import { Controller, useFormContext } from 'react-hook-form';

import { Input, Typography } from '@/components/atoms';

export interface DateFieldProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
helperText?: string;
isDayIncluded?: boolean;
}

export const RHFDateField = ({ label, helperText, isDayIncluded = false }: DateFieldProps) => {
return (
<div className="space-y-5xs">
{label && <Label label={label} />}
<div className="grid grid-cols-3 gap-2">
<YearField />
<MonthField />
{isDayIncluded && <DayField />}
{helperText && <HelperText text={helperText} />}
</div>
</div>
);
};

RHFDateField.displayName = 'RHFDateField';

const Label = ({ label }: { label: string }) => (
<div className="flex justify-between items-center">
<Typography type="title3" className="text-gray-50">
{label}
</Typography>
</div>
);

const YearField = () => {
const { control } = useFormContext();

return (
<Controller
name="year"
control={control}
rules={{ required: 'Year is required' }}
render={({ field, fieldState: { error } }) => (
<Input {...field} type="number" id="year" placeholder="YYYY" aria-invalid={error ? 'true' : 'false'} />
)}
/>
);
};

const MonthField = () => {
const { control } = useFormContext();

return (
<Controller
name="month"
control={control}
rules={{ required: 'Month is required', min: 1, max: 12 }}
render={({ field, fieldState: { error } }) => (
<Input {...field} type="number" id="month" placeholder="MM" aria-invalid={error ? 'true' : 'false'} />
)}
/>
);
};

const DayField = () => {
const { control, watch, setValue, getValues } = useFormContext();
const year = watch('year');
const month = watch('month');

// State to hold the maximum number of days for the current month/year
const [maxDays, setMaxDays] = useState(31);

useEffect(() => {
if (!year || !month) return;

// Calculate the maximum number of days in the given month/year
const daysInMonth = new Date(year, month, 0).getDate();
setMaxDays(daysInMonth);
}, [year, month]);

return (
<Controller
name="day"
control={control}
rules={{ required: 'Day is required', min: 1, max: maxDays }}
render={({ field, fieldState: { error } }) => (
<Input
{...field}
type="number"
id="day"
placeholder="DD"
min="1"
max={maxDays}
aria-invalid={error ? 'true' : 'false'}
/>
)}
/>
);
};

const HelperText = ({ text }: { text: string }) => (
<div className="flex flex-col justify-center px-5xs">
<Typography type="body3" className="text-gray-40">
{text}
</Typography>
</div>
);
Loading
Loading