Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/GU-99/grow-up-fe into fe…
Browse files Browse the repository at this point in the history
…ature/#165-team-update-modal
  • Loading branch information
ice-bear98 committed Oct 3, 2024
2 parents 63bade4 + 70aadd7 commit 1db6772
Show file tree
Hide file tree
Showing 25 changed files with 396 additions and 202 deletions.
35 changes: 35 additions & 0 deletions src/components/common/DescriptionTextarea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useFormContext } from 'react-hook-form';
import type { RegisterOptions } from 'react-hook-form';

type DescriptionTextareaProps = {
id: string;
label: string;
fieldName: string;
validationRole?: RegisterOptions;
placeholder?: string;
errors?: string;
};

export default function DescriptionTextarea({
id,
label,
fieldName,
placeholder,
validationRole,
errors,
}: DescriptionTextareaProps) {
const { register } = useFormContext();

return (
<label htmlFor={id}>
<h3 className="text-large">{label}</h3>
<textarea
id={id}
className="h-100 w-full rounded-md border border-input p-10 text-regular placeholder:text-xs"
placeholder={placeholder}
{...(validationRole ? register(fieldName, validationRole) : register(fieldName))}
/>
<div className={`my-5 h-10 text-xs text-error ${errors ? 'visible' : 'invisible'}`}>{errors}</div>
</label>
);
}
15 changes: 8 additions & 7 deletions src/components/common/SearchUserInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,23 @@ export default function SearchUserInput({

abortControllerRef.current = new AbortController();
const { signal } = abortControllerRef.current;

const { type, searchCallback } = searchCallbackInfo;
if (type !== 'ALL' && searchId === undefined) {
console.error(`${type} 인원 검색을 위해 searchId가 필요합니다.`);
return;
}

switch (type) {
case 'ALL':
searchCallback(keyword, { signal });
break;
case 'TEAM':
searchCallback(searchId!, keyword, { signal });
if (searchId === undefined) {
return console.error(`${type} 인원 검색을 위해 searchId가 필요합니다.`);
}
searchCallback(searchId, keyword, { signal });
break;
case 'PROJECT':
searchCallback(searchId!, keyword, { signal });
if (searchId === undefined) {
return console.error(`${type} 인원 검색을 위해 searchId가 필요합니다.`);
}
searchCallback(searchId, keyword, { signal });
break;
default:
exhaustiveCheck(type, '사용자 검색 범위가 올바르지 않습니다.');
Expand Down
51 changes: 51 additions & 0 deletions src/components/common/UserRoleSelectBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { IoMdCloseCircle } from 'react-icons/io';
import type { User } from '@/types/UserType';
import type { RoleName, TeamRoleName } from '@/types/RoleType';
import { PROJECT_ROLES, TEAM_ROLES } from '@/constants/role';

type CheckTeamRole<T> = T extends TeamRoleName ? 'MATE' : 'ASSIGNEE';
type UserRoleSelectBoxProps<T extends RoleName> = {
userId: User['userId'];
nickname: User['nickname'];
defaultValue: CheckTeamRole<T>;
roles: typeof TEAM_ROLES | typeof PROJECT_ROLES;
onRoleChange: (userId: number, roleName: T) => void;
onRemoveUser: (userId: number) => void;
};

export default function UserRoleSelectBox<T extends RoleName>({
userId,
nickname,
defaultValue,
roles,
onRoleChange,
onRemoveUser,
}: UserRoleSelectBoxProps<T>) {
const handleRoleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
onRoleChange(userId, event.target.value as T);
};

return (
<div className="ml-4 mt-4 flex items-center text-sm">
<select
onChange={handleRoleChange}
className="mr-2 appearance-none rounded-l-lg border-none bg-gray-200 py-2 pl-4 pr-2"
defaultValue={defaultValue}
>
{roles.map((role) => (
<option key={role} value={role}>
{role}
</option>
))}
</select>

<div className="flex items-center justify-between rounded-r-lg bg-gray-200 p-2">
<span>{nickname}</span>
<button type="button" className="ml-2" onClick={() => onRemoveUser(userId)} aria-label="유저 제거">
<IoMdCloseCircle className="size-10 cursor-pointer text-close hover:text-[#DF0000]" />
</button>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion src/components/modal/ModalButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function ModalButton({ formId, backgroundColor, onClick, children
<button
type={formId ? 'submit' : 'button'}
form={formId}
className={`h-full w-full rounded-md px-10 text-white outline-none ${backgroundColor} hover:brightness-90`}
className={`h-25 w-full rounded-md px-10 text-white outline-none ${backgroundColor} hover:brightness-90`}
onClick={handleClick}
>
{children}
Expand Down
17 changes: 0 additions & 17 deletions src/components/modal/ModalFormButton.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ModalLayout from '@layouts/ModalLayout';
import ModalPortal from '@components/modal/ModalPortal';
import ModalButton from '@components/modal/ModalButton';
import ModalProjectStatusForm from '@components/modal/project-status/ModalProjectStatusForm';
import ModalFormButton from '@components/modal/ModalFormButton';

import type { SubmitHandler } from 'react-hook-form';
import type { Project } from '@/types/ProjectType';
Expand All @@ -14,6 +14,7 @@ type CreateModalProjectStatusProps = {
};

export default function CreateModalProjectStatus({ project, onClose: handleClose }: CreateModalProjectStatusProps) {
const createStatusFormId = 'createStatusForm';
const statusMutation = useCreateStatus(project.projectId);

// ToDo: Error 처리 추가할 것
Expand All @@ -25,8 +26,10 @@ export default function CreateModalProjectStatus({ project, onClose: handleClose
return (
<ModalPortal>
<ModalLayout onClose={handleClose}>
<ModalProjectStatusForm formId="createStatusForm" project={project} onSubmit={handleSubmit} />
<ModalFormButton formId="createStatusForm" isCreate onClose={handleClose} />
<ModalProjectStatusForm formId={createStatusFormId} project={project} onSubmit={handleSubmit} />
<ModalButton formId={createStatusFormId} backgroundColor="bg-main">
등록
</ModalButton>
</ModalLayout>
</ModalPortal>
);
Expand Down
56 changes: 44 additions & 12 deletions src/components/modal/project-status/UpdateModalProjectStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import ModalLayout from '@layouts/ModalLayout';
import ModalPortal from '@components/modal/ModalPortal';
import ModalButton from '@components/modal/ModalButton';
import ModalProjectStatusForm from '@components/modal/project-status/ModalProjectStatusForm';
import ModalFormButton from '@components/modal/ModalFormButton';
import { useUpdateStatus } from '@hooks/query/useStatusQuery';
import Spinner from '@components/common/Spinner';
import useToast from '@hooks/useToast';
import { useReadStatusTasks } from '@hooks/query/useTaskQuery';
import { useDeleteStatus, useUpdateStatus } from '@hooks/query/useStatusQuery';

import type { SubmitHandler } from 'react-hook-form';
import type { Project } from '@/types/ProjectType';
Expand All @@ -19,25 +22,54 @@ export default function UpdateModalProjectStatus({
statusId,
onClose: handleClose,
}: UpdateModalProjectStatusProps) {
const updateMutation = useUpdateStatus(project.projectId, statusId);
const updateStatusFormId = 'updateStatusForm';

const { statusTaskList, isTaskLoading } = useReadStatusTasks(project.projectId);
const { mutate: updateStatusMutate } = useUpdateStatus(project.projectId, statusId);
const { mutate: deleteStatusMutate } = useDeleteStatus(project.projectId);
const { toastWarn } = useToast();

// ToDo: Error 처리 추가
const handleSubmit: SubmitHandler<ProjectStatusForm> = async (data) => {
updateMutation.mutate(data);
updateMutation.reset();
updateStatusMutate(data);
handleClose();
};

// ToDo: 유저 권한 확인하는 로직 추가할 것
const handleDeleteClick = (statusId: ProjectStatus['statusId']) => {
try {
const statusTasks = statusTaskList.find((statusTask) => statusTask.statusId === statusId);
if (!statusTasks) throw new Error('일치하는 프로젝트 상태가 없습니다.');
if (statusTasks.tasks.length > 0) return toastWarn('프로젝트 상태에 일정이 등록되어 있습니다.');
} catch (error) {
if (error instanceof Error) console.error(`${error.name}:${error.message}`);
}
deleteStatusMutate(statusId);
};

return (
<ModalPortal>
<ModalLayout onClose={handleClose}>
<ModalProjectStatusForm
formId="updateStatusForm"
project={project}
statusId={statusId}
onSubmit={handleSubmit}
/>
<ModalFormButton formId="updateStatusForm" isCreate={false} onClose={handleClose} />
{isTaskLoading ? (
<Spinner />
) : (
<>
<ModalProjectStatusForm
formId={updateStatusFormId}
project={project}
statusId={statusId}
onSubmit={handleSubmit}
/>
<div className="flex min-h-25 w-4/5 gap-10">
<ModalButton formId={updateStatusFormId} backgroundColor="bg-main">
수정
</ModalButton>
<ModalButton backgroundColor="bg-delete" onClick={() => handleDeleteClick(statusId)}>
삭제
</ModalButton>
</div>
</>
)}
</ModalLayout>
</ModalPortal>
);
Expand Down
10 changes: 7 additions & 3 deletions src/components/modal/project/CreateModalProject.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ModalPortal from '@components/modal/ModalPortal';
import ModalLayout from '@layouts/ModalLayout';
import ModalButton from '@components/modal/ModalButton';
import ModalProjectForm from '@components/modal/project/ModalProjectForm';
import ModalFormButton from '@components/modal/ModalFormButton';

import type { SubmitHandler } from 'react-hook-form';
import type { Project } from '@/types/ProjectType';
Expand All @@ -11,6 +11,8 @@ type CreateModalProjectProps = {
};

export default function CreateModalProject({ onClose: handleClose }: CreateModalProjectProps) {
const createProjectFormId = 'createProjectForm';

const handleSubmit: SubmitHandler<Project> = async (data) => {
console.log('프로젝트 생성 폼 제출');
console.log(data);
Expand All @@ -19,8 +21,10 @@ export default function CreateModalProject({ onClose: handleClose }: CreateModal
return (
<ModalPortal>
<ModalLayout onClose={handleClose}>
<ModalProjectForm formId="createProjectForm" onSubmit={handleSubmit} />
<ModalFormButton formId="createProjectForm" isCreate onClose={handleClose} />
<ModalProjectForm formId={createProjectFormId} onSubmit={handleSubmit} />
<ModalButton formId={createProjectFormId} backgroundColor="bg-main">
등록
</ModalButton>
</ModalLayout>
</ModalPortal>
);
Expand Down
14 changes: 11 additions & 3 deletions src/components/modal/project/UpdateModalProject.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ModalPortal from '@components/modal/ModalPortal';
import ModalLayout from '@layouts/ModalLayout';
import ModalButton from '@components/modal/ModalButton';
import ModalProjectForm from '@components/modal/project/ModalProjectForm';
import ModalFormButton from '@components/modal/ModalFormButton';

import type { SubmitHandler } from 'react-hook-form';
import type { Project } from '@/types/ProjectType';
Expand All @@ -12,16 +12,24 @@ type UpdateModalProjectProps = {
};

export default function UpdateModalProject({ projectId, onClose: handleClose }: UpdateModalProjectProps) {
const updateProjectFormId = 'updateProjectForm';

const handleSubmit: SubmitHandler<Project> = async (data) => {
console.log('프로젝트 생성 폼 제출');
console.log(data);
handleClose();
};

// ToDo: 프로젝트 수정 API 작업시 작성할 것
const handleUpdateClick = () => {};

return (
<ModalPortal>
<ModalLayout onClose={handleClose}>
<ModalProjectForm formId="updateProjectForm" projectId={projectId} onSubmit={handleSubmit} />
<ModalFormButton formId="updateProjectForm" isCreate={false} onClose={handleClose} />
<ModalProjectForm formId={updateProjectFormId} projectId={projectId} onSubmit={handleSubmit} />
<ModalButton formId={updateProjectFormId} backgroundColor="bg-main" onClick={handleUpdateClick}>
수정
</ModalButton>
</ModalLayout>
</ModalPortal>
);
Expand Down
11 changes: 7 additions & 4 deletions src/components/modal/task/CreateModalTask.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useQueryClient } from '@tanstack/react-query';
import ModalLayout from '@layouts/ModalLayout';
import ModalPortal from '@components/modal/ModalPortal';
import ModalButton from '@components/modal/ModalButton';
import ModalTaskForm from '@components/modal/task/ModalTaskForm';
import ModalFormButton from '@components/modal/ModalFormButton';
import useToast from '@hooks/useToast';
import { useCreateStatusTask, useReadStatusTasks, useUploadTaskFile } from '@hooks/query/useTaskQuery';

import type { SubmitHandler } from 'react-hook-form';
import type { Task, TaskForm } from '@/types/TaskType';
import type { Project } from '@/types/ProjectType';
import type { Task, TaskForm } from '@/types/TaskType';
import type { ProjectStatus } from '@/types/ProjectStatusType';
import type { FileUploadFailureResult, FileUploadSuccessResult } from '@/types/FileType';

Expand All @@ -18,6 +18,7 @@ type CreateModalTaskProps = {
};

export default function CreateModalTask({ project, onClose: handleClose }: CreateModalTaskProps) {
const createTaskFormId = 'createTaskForm';
const { toastSuccess, toastError } = useToast();
const { mutateAsync: createTaskInfoMutateAsync } = useCreateStatusTask(project.projectId);
const { mutateAsync: createTaskFileMutateAsync } = useUploadTaskFile(project.projectId);
Expand Down Expand Up @@ -73,8 +74,10 @@ export default function CreateModalTask({ project, onClose: handleClose }: Creat
return (
<ModalPortal>
<ModalLayout onClose={handleClose}>
<ModalTaskForm formId="createTaskForm" project={project} onSubmit={handleSubmit} />
<ModalFormButton formId="createTaskForm" isCreate onClose={handleClose} />
<ModalTaskForm formId={createTaskFormId} project={project} onSubmit={handleSubmit} />
<ModalButton formId={createTaskFormId} backgroundColor="bg-main">
등록
</ModalButton>
</ModalLayout>
</ModalPortal>
);
Expand Down
Loading

0 comments on commit 1db6772

Please sign in to comment.