Skip to content
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
6 changes: 2 additions & 4 deletions components/ui/progress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ const Progress = React.forwardRef<
const [progress, setProgress] = React.useState(0);

React.useEffect(() => {
if (value) {
const timer = setTimeout(() => setProgress(value), 500);
return () => clearTimeout(timer);
}
const timer = setTimeout(() => setProgress(value || 0), 200);
return () => clearTimeout(timer);
}, [value]);

return (
Expand Down
26 changes: 17 additions & 9 deletions src/app/(authorized)/todo-all/page.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
'use client';

import { EMPTY_TASK_MESSAGE, FILTER_MAPPING } from '@constant/task';
import { useGetTasks } from '@hooks/task/useGetTasks';
import { usePostTask } from '@hooks/task/usePostTask';
import { TTaskScope } from '@model/task.model';
import { useModalStore } from '@store/modal.store';
import TaskList from '@ui/card/taskCard/TaskList';
import EmptyMessage from '@ui/common/EmptyMessage';
import FilterButton from '@ui/common/FilterButton';
import FilterButton, { TFilterType } from '@ui/common/FilterButton';
import NavTitle from '@ui/common/NavTitle';
import TodoModal from '@ui/Modal/TodoModal';
import { AllTodoPageSkeleton } from '@ui/skeleton/Skeletons';
import AddTaskButton from '@ui/trip/tripTask/AddTaskButton';
import { useState } from 'react';

export default function TodoAllPage() {
const [taskScope, setTaskScope] = useState<TTaskScope | null>(null);
const params = {
const [activeFilter, setActiveFilter] = useState<TFilterType>('All');
const [params, setParams] = useState({
taskSeq: 0,
all: true,
...(taskScope ? { taskScope } : {}),
};
});

const { showModal } = useModalStore();
const postTask = usePostTask();
const handleAddTaskClick = () => {
Expand All @@ -29,9 +29,14 @@ export default function TodoAllPage() {
});
};
const { data: tasks, isLoading: isTasksLoading } = useGetTasks(params);
const handleTaskFilterClick = (filter: string) => {

const handleTaskFilterClick = (filter: TFilterType) => {
setActiveFilter(filter);
const scope = FILTER_MAPPING[filter];
setTaskScope(scope);
setParams((prev) => ({
...prev,
taskScope: scope || null,
}));
};

if (isTasksLoading) {
Expand All @@ -50,7 +55,10 @@ export default function TodoAllPage() {
</nav>
<div className="flex flex-1 flex-col">
<div className="flex flex-1 flex-col gap-7 rounded-xl border border-slate-100 bg-white p-6">
<FilterButton onClick={handleTaskFilterClick} />
<FilterButton
activeFilter={activeFilter}
onClick={(filter) => handleTaskFilterClick(filter)}
/>
{tasks?.result && tasks?.result.length > 0 ? (
<TaskList tasks={tasks?.result ? tasks.result : []} />
) : (
Expand Down
7 changes: 4 additions & 3 deletions src/app/(unauthorized)/signin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import Image from 'next/image';
// import Image from 'next/image';
import Link from 'next/link';
import { SubmitHandler, useForm } from 'react-hook-form';
import { AUTH_VALIDATION_REGEX } from '@constant/auth';
Expand Down Expand Up @@ -98,7 +98,8 @@ export default function SignInPage({
>
로그인하기
</Button>
<Button
{/* TODO: 2차 개발에 추가 */}
{/* <Button
size="large"
fullWidth={true}
className="border-[#FEE500] bg-[#FEE500] text-slate-800 hover:border-[#FEE500] hover:bg-[#FEE500] active:border-[#FEE500] active:bg-[#FEE500]"
Expand All @@ -110,7 +111,7 @@ export default function SignInPage({
alt="카카오 아이콘"
/>
카카오톡으로 로그인하기
</Button>
</Button> */}
</div>
<div className="flex h-5 gap-1">
<div className="text-sm font-medium leading-tight">
Expand Down
8 changes: 4 additions & 4 deletions src/app/(unauthorized)/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ interface ISignUpFormInputs {
passwordConfirm: string;
}
export default function SignUpPage({
searchParams: redirectTo,
searchParams,
}: {
searchParams: string;
searchParams: { redirectTo?: string };
}) {
const {
register,
Expand All @@ -44,8 +44,8 @@ export default function SignUpPage({
redirect: false,
});
if (res?.ok) {
if (redirectTo) {
router.push(redirectTo);
if (searchParams.redirectTo) {
router.push(searchParams.redirectTo);
} else {
router.push('/');
}
Expand Down
8 changes: 1 addition & 7 deletions src/hooks/task/usePutCompleteTask.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { tasksQueryKeys } from '@constant/queryKeyFactory';
import { putCompleteTask } from '@lib/api/service/task.api';
import { TPutCompleteTaskRequest } from '@model/task.model';
import { useMutation, useQueryClient } from '@tanstack/react-query';
Expand All @@ -12,13 +11,8 @@ export const usePutCompleteTask = () => {
},
onSuccess: (response) => {
if (response.success) {
const props = {
tripId: response.result.tripId,
taskSeq: 0,
all: true,
};
queryClient.invalidateQueries({
queryKey: tasksQueryKeys.list(props).queryKey,
queryKey: ['tasks', 'list'],
});
}
},
Expand Down
31 changes: 18 additions & 13 deletions src/ui/box/TripBox.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import Subtitle from '@ui/common/Subtitle';
import FilterButton from '@ui/common/FilterButton';
import FilterButton, { TFilterType } from '@ui/common/FilterButton';
import TaskCarousel from '@ui/carousel/TaskCarousel';
import ShowAllTasksButton from '@ui/trip/tripTask/ShowAllTasksButton';
import AddTaskButton from '@ui/trip/tripTask/AddTaskButton';
import { TTaskScope } from '@model/task.model';
import { useRouter } from 'next/navigation';
import { useModalStore } from '@store/modal.store';
import { FILTER_MAPPING } from '@constant/task';
Expand All @@ -12,28 +11,31 @@ import { useGetTasks } from '@hooks/task/useGetTasks';
import TodoModal from '@ui/Modal/TodoModal';
import { usePostTask } from '@hooks/task/usePostTask';

/* eslint-disable @typescript-eslint/no-unused-vars */

interface ITripCardProps {
id: number;
name: string;
}

export default function TripBox({ id, name }: ITripCardProps) {
const [taskScope, setTaskScope] = useState<TTaskScope | null>(null);
const params = {
const [activeFilter, setActiveFilter] = useState<TFilterType>('All');
const [params, setParams] = useState({
tripId: id,
taskSeq: 0,
all: true,
...(taskScope ? { taskScope } : {}),
};
});

const postTask = usePostTask();
const { data: tasks } = useGetTasks(params);
const navigate = useRouter();
const { showModal } = useModalStore();
const handleTaskFilterClick = (filter: string) => {

const handleTaskFilterClick = (filter: TFilterType) => {
setActiveFilter(filter);
const scope = FILTER_MAPPING[filter];
setTaskScope(scope);
setParams((prev) => ({
...prev,
taskScope: scope || null,
}));
};

const handleAddTaskClick = () => {
Expand All @@ -51,14 +53,17 @@ export default function TripBox({ id, name }: ITripCardProps) {
<div className="flex justify-between">
<Subtitle
title={name}
icon="whiteflag"
iconBg="bg-blue-500"
icon="trip-dark"
iconBg="bg-slate-800"
link="#"
/>
<ShowAllTasksButton onClick={handleMoveTrip} />
</div>
<div className="flex items-center justify-between">
<FilterButton onClick={handleTaskFilterClick} />
<FilterButton
activeFilter={activeFilter}
onClick={(filter) => handleTaskFilterClick(filter)}
/>
<AddTaskButton onClick={handleAddTaskClick} />
</div>
</div>
Expand Down
8 changes: 5 additions & 3 deletions src/ui/common/DropdownMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ export default function DropdownMenu({
className,
)}
>
{/* 아이콘이나 텍스트 */}
{children}
<div className="pointer-events-none">
{/* 아이콘이나 텍스트 */}
{children}
</div>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuContent align="end" className="z-50">
{items?.map((item, index) => (
<DropdownMenuItem
key={index}
Expand Down
23 changes: 10 additions & 13 deletions src/ui/common/FilterButton.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
'use client';

import { useState } from 'react';
import { twMerge } from 'tailwind-merge';

const FILTERS = ['All', '공통', '개인'];
export const FILTERS = ['All', '공통', '개인'] as const;
export type TFilterType = (typeof FILTERS)[number];

interface IFilterButtonProps {
onClick: (filter: string) => void; // 클릭 이벤트 핸들러
activeFilter: TFilterType; // 필터 상태
onClick: (filter: TFilterType) => void; // 클릭 이벤트 핸들러
}

export default function FilterButton({ onClick }: IFilterButtonProps) {
const [activeFilter, setActiveFilter] = useState<string>('All');

const handleFilterClick = (filter: string) => {
setActiveFilter(filter);
onClick(filter);
};

export default function FilterButton({
activeFilter,
onClick,
}: IFilterButtonProps) {
return (
<div className="inline-flex gap-2.5">
{FILTERS.map((filter) => (
<button
key={filter}
onClick={() => handleFilterClick(filter)}
onClick={() => onClick(filter)}
className={twMerge(
'rounded-[17px] border px-3 py-1 text-sm font-medium leading-tight',
'rounded-[17px] border px-3 py-1 text-sm font-medium leading-tight transition-colors duration-200 ease-in-out',
filter === activeFilter
? 'bg-primary text-white'
: 'bg-white text-slate-800',
Expand Down
22 changes: 8 additions & 14 deletions src/ui/skeleton/Skeletons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,20 +190,14 @@ export function TripInfoSkeleton() {

export function TripTaskSkeleton() {
return (
<div className="section-box flex flex-1 flex-col gap-5 pr-0">
<div className="flex flex-col gap-5 pr-6">
<h4 className="text-lg font-semibold leading-7 text-slate-800">Todo</h4>
</div>
<div className="flex w-full flex-col gap-4 rounded-xl bg-white py-6">
<div className="flex h-[500px] gap-[22px]">
{/* 기본 (mobile): 1개 */}
<Skeleton className="h-full w-full" />
{/* tablet: 2개 (1개는 반만 보여줌) */}
<Skeleton className="hidden h-full tablet:block tablet:w-1/2 desktop:hidden" />
{/* desktop: 정확히 3개 */}
<Skeleton className="hidden h-full desktop:block desktop:w-full" />
<Skeleton className="hidden h-full desktop:block desktop:w-full" />
</div>
<div className="flex w-full flex-col gap-4 rounded-xl bg-white px-6 tablet:pl-6 tablet:pr-0">
<div className="flex h-[500px] gap-[22px]">
{/* 기본 (mobile): 1개 */}
<Skeleton className="h-full w-full rounded-3xl" />
{/* tablet: 2개 (1개는 반만 보여줌) */}
<Skeleton className="hidden h-full rounded-3xl tablet:block tablet:rounded-br-none tablet:rounded-tr-none desktop:w-full desktop:rounded-3xl" />
{/* desktop: 정확히 3개 */}
<Skeleton className="hidden h-full rounded-3xl desktop:block desktop:w-full" />
</div>
</div>
);
Expand Down
47 changes: 26 additions & 21 deletions src/ui/trip/TripTask.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
'use client';

import TaskCarousel from '@ui/carousel/TaskCarousel';
import FilterButton from '@ui/common/FilterButton';
import FilterButton, { TFilterType } from '@ui/common/FilterButton';
import AddTaskButton from './tripTask/AddTaskButton';
import { useGetTasks } from '@hooks/task/useGetTasks';
import { TTrip } from '@model/trip.model';
import { useState } from 'react';
import { TTaskScope } from '@model/task.model';
import { FILTER_MAPPING } from '@constant/task';
import { useModalStore } from '@store/modal.store';
import TodoModal from '@ui/Modal/TodoModal';
Expand All @@ -16,14 +15,13 @@ import { TripTaskSkeleton } from '@ui/skeleton/Skeletons';
type TTripTaskProps = Pick<TTrip, 'id'>;

export default function TripTask({ id }: TTripTaskProps) {
const [taskScope, setTaskScope] = useState<TTaskScope | null>(null);

const params = {
const [activeFilter, setActiveFilter] = useState<TFilterType>('All');
const [params, setParams] = useState({
tripId: id,
taskSeq: 0,
all: true,
...(taskScope ? { taskScope } : {}),
};
});

const { data, isLoading } = useGetTasks(params);

const { showModal } = useModalStore();
Expand All @@ -35,32 +33,39 @@ export default function TripTask({ id }: TTripTaskProps) {
});
};

const handleTaskFilterClick = (filter: string) => {
const handleTaskFilterClick = (filter: TFilterType) => {
setActiveFilter(filter);
const scope = FILTER_MAPPING[filter];
setTaskScope(scope);
setParams((prev) => ({
...prev,
taskScope: scope || null,
}));
};

if (isLoading) {
return <TripTaskSkeleton />;
}

return (
// <div className="flex w-full flex-col gap-4 rounded-xl bg-white py-6 desktop:px-6"></div>
<div className="section-box flex flex-1 flex-col gap-5 px-0 pr-0 desktop:px-6">
<div className="flex flex-col gap-5 px-6 desktop:px-0">
<h4 className="text-lg font-semibold leading-7 text-slate-800">Todo</h4>
<div className="flex items-center justify-between">
<FilterButton onClick={handleTaskFilterClick} />
<FilterButton
activeFilter={activeFilter}
onClick={(filter) => handleTaskFilterClick(filter)}
/>
<AddTaskButton onClick={handleAddTaskClick} />
</div>
</div>
<div className="px-4 tablet:px-0">
<TaskCarousel
tripId={id}
tasks={data?.success ? data?.result : []}
height="500px"
/>
</div>
{isLoading ? (
<TripTaskSkeleton />
) : (
<div className="px-4 tablet:px-0">
<TaskCarousel
tripId={id}
tasks={data?.success ? data?.result : []}
height="500px"
/>
</div>
)}
</div>
);
}
Loading