diff --git a/public/fonts/hakgyo/HakgyoansimDunggeunmisoTTF-B.woff2 b/public/fonts/hakgyo/HakgyoansimDunggeunmisoTTF-B.woff2 new file mode 100644 index 00000000..367e885a Binary files /dev/null and b/public/fonts/hakgyo/HakgyoansimDunggeunmisoTTF-B.woff2 differ diff --git a/public/fonts/hakgyo/HakgyoansimDunggeunmisoTTF-R.woff2 b/public/fonts/hakgyo/HakgyoansimDunggeunmisoTTF-R.woff2 new file mode 100644 index 00000000..bf8de10a Binary files /dev/null and b/public/fonts/hakgyo/HakgyoansimDunggeunmisoTTF-R.woff2 differ diff --git a/public/fonts/nexon/NexonLv1GothicOTF-B.woff b/public/fonts/nexon/NexonLv1GothicOTF-B.woff new file mode 100644 index 00000000..b67a1f1f Binary files /dev/null and b/public/fonts/nexon/NexonLv1GothicOTF-B.woff differ diff --git a/public/fonts/nexon/NexonLv1GothicOTF-R.woff b/public/fonts/nexon/NexonLv1GothicOTF-R.woff new file mode 100644 index 00000000..b948f930 Binary files /dev/null and b/public/fonts/nexon/NexonLv1GothicOTF-R.woff differ diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index c159138b..5438c29a 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -1,4 +1,5 @@ "use client"; +import Button from "@/app/components/button/default/Button"; import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner"; import { useLogin } from "@/hooks/queries/auth/useLogin"; import { type LoginSchema, loginSchema } from "@/schemas/authSchema"; @@ -6,26 +7,56 @@ import { zodResolver } from "@hookform/resolvers/zod"; import Image from "next/image"; import Link from "next/link"; import { useForm } from "react-hook-form"; +import { UserRole, userRoles } from "@/constants/userRoles"; export default function LoginPage() { + // 로그인 훅과 로딩 상태 관리 const { login, isPending } = useLogin(); + + // 폼 유효성 검사 및 상태 관리 const { register, handleSubmit, formState: { errors }, + setValue, } = useForm({ resolver: zodResolver(loginSchema), }); + // 일반 로그인 제출 핸들러 const onSubmit = (data: LoginSchema) => { login(data); }; + // 테스트 계정 로그인 핸들러 - 폼 유효성 검사 통과 + const handleTestLogin = (role: UserRole) => { + const testCredentials = { + // 지원자 테스트 계정 정보 + [userRoles.APPLICANT]: { + email: process.env.NEXT_PUBLIC_TEST_APPLICANT_ID as string, + password: process.env.NEXT_PUBLIC_TEST_APPLICANT_PASSWORD as string, + }, + // 사장님 테스트 계정 정보 + [userRoles.OWNER]: { + email: process.env.NEXT_PUBLIC_TEST_OWNER_ID as string, + password: process.env.NEXT_PUBLIC_TEST_OWNER_PASSWORD as string, + }, + }; + + // setValue를 통해 폼 값을 직접 설정 + const credentials = testCredentials[role]; + setValue("email", credentials.email); + setValue("password", credentials.password); + + // 설정된 값으로 폼 제출 + handleSubmit((data) => login(data))(); + }; + return (
-

로그인

+
로그인

아직 계정이 없으신가요?{" "} @@ -55,14 +86,10 @@ export default function LoginPage() {

-
- +

@@ -85,6 +112,33 @@ export default function LoginPage() { 카카오 로그인
+
+
+ 테스트 계정으로 로그인하기 +
+
+
+ + +
diff --git a/src/app/(auth)/signup/applicant/page.tsx b/src/app/(auth)/signup/applicant/page.tsx index 6b6b606a..80929c34 100644 --- a/src/app/(auth)/signup/applicant/page.tsx +++ b/src/app/(auth)/signup/applicant/page.tsx @@ -8,6 +8,7 @@ import Link from "next/link"; import { useForm } from "react-hook-form"; import Image from "next/image"; import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner"; +import Button from "@/app/components/button/default/Button"; export default function ApplicantSignupPage() { const { signup, isPending } = useSignup(); @@ -32,7 +33,7 @@ export default function ApplicantSignupPage() {
-

지원자 회원가입

+
지원자 회원가입

이미 계정이 있으신가요?{" "} @@ -98,14 +99,10 @@ export default function ApplicantSignupPage() { {errors.phoneNumber &&

{errors.phoneNumber.message}

}
-
- +

diff --git a/src/app/(auth)/signup/owner/page.tsx b/src/app/(auth)/signup/owner/page.tsx index 1eb89131..2ec13431 100644 --- a/src/app/(auth)/signup/owner/page.tsx +++ b/src/app/(auth)/signup/owner/page.tsx @@ -8,6 +8,7 @@ import Link from "next/link"; import { useForm } from "react-hook-form"; import Image from "next/image"; import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner"; +import Button from "@/app/components/button/default/Button"; export default function OwnerSignupPage() { const { signup, isPending } = useSignup(); @@ -34,7 +35,7 @@ export default function OwnerSignupPage() {
-

사장님 회원가입

+
사장님 회원가입

이미 계정이 있으신가요?{" "} @@ -120,14 +121,10 @@ export default function OwnerSignupPage() { {errors.location &&

{errors.location.message}

}
-
- +

diff --git a/src/app/(home)/page.tsx b/src/app/(home)/page.tsx index 4e1290ce..c2955774 100644 --- a/src/app/(home)/page.tsx +++ b/src/app/(home)/page.tsx @@ -4,6 +4,7 @@ import { useEffect, useState, useRef } from "react"; import Link from "next/link"; import Image from "next/image"; import { useUser } from "@/hooks/queries/user/me/useUser"; +import LinkBtn from "../components/button/default/LinkBtn"; export default function Home() { const [visibleSections, setVisibleSections] = useState(new Set()); @@ -16,16 +17,27 @@ export default function Home() { observer.current = new IntersectionObserver( (entries) => { entries.forEach((entry) => { - if (entry.isIntersecting) { - const element = entry.target as HTMLElement; - const id = element.dataset.id ?? ""; // 기본값 설정 - if (id) { + const element = entry.target as HTMLElement; + const id = element.dataset.id ?? ""; + if (id) { + if (entry.isIntersecting) { + // 요소가 보일 때 애니메이션 적용 setVisibleSections((prev) => new Set(prev).add(id)); + } else { + // 요소가 보이지 않을 때 애니메이션 제거 + setVisibleSections((prev) => { + const newSet = new Set(prev); + newSet.delete(id); + return newSet; + }); } } }); }, - { threshold: 0.5 } + { + threshold: 0.2, // 임계값을 낮춰서 더 일찍 감지 + rootMargin: "50px", // 여유 공간 추가 + } ); // 감시할 요소 선택 및 등록 @@ -59,11 +71,9 @@ export default function Home() { 한 곳에서 관리하는 알바 구인 플랫폼

{user ? ( - -

- 알바 둘러보기 -

- + + 알바 둘러보기 + ) : (

diff --git a/src/app/(pages)/(albaform)/addform/page.tsx b/src/app/(pages)/(albaform)/addform/page.tsx index e9269d06..5bc6da6b 100644 --- a/src/app/(pages)/(albaform)/addform/page.tsx +++ b/src/app/(pages)/(albaform)/addform/page.tsx @@ -15,7 +15,8 @@ import { SubmitFormDataType } from "@/types/addform"; import CustomFormModal from "@/app/components/modal/modals/confirm/CustomFormModal"; import tempSave from "@/utils/tempSave"; import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner"; -import useUploadImages from "@/hooks/queries/user/me/useImageUpload"; +import { useUser } from "@/hooks/queries/user/me/useUser"; +import LoadingSpinner from "@/app/components/loading-spinner/LoadingSpinner"; export default function AddFormPage() { const router = useRouter(); @@ -43,7 +44,6 @@ export default function AddFormPage() { description: "", title: "", imageUrls: [], - imageFiles: [], }, }); @@ -57,12 +57,9 @@ export default function AddFormPage() { const currentValues: SubmitFormDataType = methods.watch(); // 이미지 업로드 api 처리를 위해 별도 변수에 할당 - const imageFiles = currentValues.imageFiles; const [, setSelectedOption] = useState(""); const [showTempDataModal, setShowTempDataModal] = useState(false); - const { uploadImages } = useUploadImages(); - // 각각의 탭 작성중 여부 const { isEditingRecruitContent, isEditingRecruitCondition, isEditingWorkCondition } = useEditing(currentValues); @@ -77,32 +74,8 @@ export default function AddFormPage() { const mutation = useMutation({ mutationFn: async () => { setLoading(true); - // 이미지 필수 체크 - if (!imageFiles || imageFiles.length === 0) { - toast.error("이미지를 첨부해주세요."); - throw new Error("이미지는 필수입니다."); - } - // 이미지 업로드 처리 - let uploadedUrls: string[] = []; - try { - if (currentValues.imageUrls.length !== currentValues.imageFiles.length) { - uploadedUrls = await uploadImages(Array.from(imageFiles)); - } else { - uploadedUrls = currentValues.imageUrls; - } - if (!uploadedUrls.length) { - toast.error("이미지 업로드에 실패했습니다."); - throw new Error("이미지 업로드 실패"); - } - setValue("imageUrls", uploadedUrls); - } catch (error) { - console.error("이미지 업로드 중 오류 발생:", error); - toast.error("이미지 업로드 중 오류가 발생했습니다."); - throw error; - } - - const excludedKeys = ["displayDate", "workDateRange", "recruitDateRange", "imageFiles"]; + const excludedKeys = ["displayDate", "workDateRange", "recruitDateRange"]; // 원하는 필드만 포함된 새로운 객체 만들기 const filteredData = Object.entries(currentValues) @@ -113,9 +86,6 @@ export default function AddFormPage() { } else if (key === "hourlyWage") { // 문자열이면 콤마 제거 후 숫자로 변환 acc[key] = typeof value === "string" ? String(Number(value.replace(/,/g, ""))) : String(Number(value)); - } else if (key === "imageUrls") { - // 업로드된 이미지 URL 사용 - acc[key] = uploadedUrls; } else { acc[key as keyof SubmitFormDataType] = value; } @@ -149,20 +119,6 @@ export default function AddFormPage() { // 폼데이터 임시 저장 함수 const onTempSave = async () => { - // 이미지 처리 로직 - if (currentValues.imageUrls.length !== currentValues.imageFiles.length) { - try { - const uploadedUrls = await uploadImages(Array.from(imageFiles)); - if (uploadedUrls && uploadedUrls.length > 0) { - setValue("imageUrls", [...uploadedUrls]); - } else { - setValue("imageUrls", [...currentValues.imageUrls]); - } - } catch (error) { - console.error("임시저장 - 이미지 업로드 중 오류 발생:", error); - setValue("imageUrls", []); - } - } tempSave("addformData", currentValues); }; @@ -177,7 +133,7 @@ export default function AddFormPage() { "모집 조건": "recruit-condition", "근무 조건": "work-condition", }[option]; - router.push(`/addform?tab=${params}`); + router.replace(`/addform?tab=${params}`); }; useEffect(() => { @@ -265,6 +221,20 @@ export default function AddFormPage() { setShowTempDataModal(false); }; + // 유저 권한 확인 + const { user, isLoading } = useUser(); + + useEffect(() => { + if (user?.role !== "OWNER") { + toast.error("사장님만 알바폼을 작성할 수 있습니다."); + router.push("/alba-list"); + } + }, [user, router]); + + if (isLoading) { + return ; + } + return (

diff --git a/src/app/(pages)/(albaform)/addform/section/RecruitContentSection.tsx b/src/app/(pages)/(albaform)/addform/section/RecruitContentSection.tsx index 95d1ad02..2a8f5050 100644 --- a/src/app/(pages)/(albaform)/addform/section/RecruitContentSection.tsx +++ b/src/app/(pages)/(albaform)/addform/section/RecruitContentSection.tsx @@ -5,21 +5,78 @@ import ImageInput from "@/app/components/input/file/ImageInput/ImageInput"; import DatePickerInput from "@/app/components/input/dateTimeDaypicker/DatePickerInput"; import { cn } from "@/lib/tailwindUtil"; import { useFormContext } from "react-hook-form"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import Label from "../../component/Label"; +import { ImageInputType } from "@/types/addform"; +import useUploadImages from "@/hooks/queries/user/me/useImageUpload"; // 알바폼 만들기 - 사장님 - 1-모집내용 export default function RecruitContentSection() { // 이미지 파일을 로컬 상태에 저장 - const [initialImageList, setInitialImageList] = useState<{ file: File; url: string; id: string }[]>([]); + const [initialImageList, setInitialImageList] = useState([]); //훅폼 하위 컴포넌트에서는 useFormcontext에서 메서드 호출 const { + watch, register, setValue, formState: { errors }, } = useFormContext(); + const { uploadImages } = useUploadImages(); + + const imageUrlsData: string[] = watch("imageUrls"); + + // 이미지 파일 change핸들러 + const handleChangeImages = async (files: File[]) => { + let uploadedUrls: string[] = []; + //파일 선택 시 업로드 api 요청 + try { + uploadedUrls = await uploadImages(files); + console.log("이미지 파일 change 핸들러 - 이미지 업로드 성공"); + } catch (err) { + console.log("이미지 파일 체인지 핸들러 - 이미지 업로드 실패"); + console.error(err); + } + // 선택한 이미지 업데이트 + const updatedImageList = + uploadedUrls.map((url) => ({ + url, + id: crypto.randomUUID(), + })) || []; + + // 기존 이미지 포함하기 + const originalImageList = + imageUrlsData.map((url) => ({ + url, + id: crypto.randomUUID(), + })) || []; + + const allImageList = [...originalImageList, ...updatedImageList]; + const submitImageList = [...imageUrlsData, ...uploadedUrls]; + + // prop으로 전달 + setInitialImageList(allImageList); + // 훅폼 데이터에 세팅 + setValue("imageUrls", submitImageList, { shouldDirty: true }); + }; + + const handleDeleteImage = (url: string) => { + const newImageList = initialImageList.filter((item) => item.url !== url); + setInitialImageList(newImageList); + const urls = newImageList.map((item) => item.url); + setValue("imageUrls", urls, { shouldDirty: true }); + }; + // 초기 이미지 데이터 로딩 + useEffect(() => { + if (imageUrlsData?.length > 0) { + const originalUrls = imageUrlsData.map((url) => ({ + url, + id: crypto.randomUUID(), + })); + setInitialImageList(originalUrls); + } + }, [imageUrlsData]); // 날짜 선택 const [recruitmentDateRange, setRecruitmentDateRange] = useState<[Date | null, Date | null]>([null, null]); @@ -29,20 +86,6 @@ export default function RecruitContentSection() { if (start) setValue("recruitmentStartDate", start.toISOString()); if (end) setValue("recruitmentEndDate", end.toISOString()); }; - - // 이미지 파일 change핸들러 - const handleChangeImages = (files: File[]) => { - setValue("imageFiles", files); - - const newImages = files.map((file: File) => ({ - file, - url: URL.createObjectURL(file), - id: crypto.randomUUID(), - })); - - setInitialImageList(newImages); - }; - const errorTextStyle = "absolute -bottom-[26px] right-1 text-[13px] text-sm font-medium leading-[22px] text-state-error lg:text-base lg:leading-[26px]"; @@ -88,10 +131,11 @@ export default function RecruitContentSection() {
{ handleChangeImages(files); }} + onDelete={(id) => handleDeleteImage(id)} initialImageList={initialImageList} /> {errors.imageUrls &&

{errors.imageUrls.message as string}

} diff --git a/src/app/(pages)/(albaform)/alba/[formId]/components/FormActions.tsx b/src/app/(pages)/(albaform)/alba/[formId]/components/FormActions.tsx index 150f7d5c..2c9fb711 100644 --- a/src/app/(pages)/(albaform)/alba/[formId]/components/FormActions.tsx +++ b/src/app/(pages)/(albaform)/alba/[formId]/components/FormActions.tsx @@ -1,18 +1,18 @@ "use client"; -import React, { useState } from "react"; // useState 추가 +import React, { useState } from "react"; import Link from "next/link"; import { useUser } from "@/hooks/queries/user/me/useUser"; import { FormDetailResponse } from "@/types/response/form"; import FloatingBtn from "@/app/components/button/default/FloatingBtn"; import { FaEdit } from "react-icons/fa"; import { MdDeleteForever } from "react-icons/md"; -import { CiMemoPad } from "react-icons/ci"; import axios from "axios"; import toast from "react-hot-toast"; import { useRouter } from "next/navigation"; import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner"; import { HiMail } from "react-icons/hi"; import { HiDocumentText } from "react-icons/hi"; +import { useMyApplications } from "@/hooks/queries/user/me/useMyApplications"; interface FormActionsProps { formId: string | number; albaFormDetailData: FormDetailResponse; @@ -20,6 +20,7 @@ interface FormActionsProps { export default function FormActions({ formId, albaFormDetailData }: FormActionsProps) { const { user } = useUser(); + const { data: applicantData } = useMyApplications(); const router = useRouter(); const isMyAlbaForm = user?.id === albaFormDetailData.ownerId; const isOwnerRole = user?.role === "OWNER"; @@ -66,15 +67,26 @@ export default function FormActions({ formId, albaFormDetailData }: FormActionsP ); } + // 이미 지원한 공고인지 확인 + const hasApplied = applicantData?.pages + ?.flatMap((page) => page.data) // 1차원 배열로 변환 + .some((applicant) => applicant.form?.id === formId); // 일치하는 항목을 찾으면 즉시 true를 반환 + // 사장님이 아니면 지원하기/내 지원내역 보기 버튼 if (!isOwnerRole) { return (
- - }> - {isLoading ? : "지원하기"} + {hasApplied ? ( + } disabled> + {isLoading ? : "이미 지원한 공고"} - + ) : ( + + }> + {isLoading ? : "지원하기"} + + + )} }> {isLoading ? : "내 지원내역 보기"} diff --git a/src/app/(pages)/(albaform)/alba/[formId]/components/FormDetail.tsx b/src/app/(pages)/(albaform)/alba/[formId]/components/FormDetail.tsx index a766e461..5b3d4e02 100644 --- a/src/app/(pages)/(albaform)/alba/[formId]/components/FormDetail.tsx +++ b/src/app/(pages)/(albaform)/alba/[formId]/components/FormDetail.tsx @@ -15,7 +15,9 @@ export default function FormDetails({ albaFormDetailData }: FormDetailsProps) { return ( <>
- {albaFormDetailData.storeName || "가게명"} + + {albaFormDetailData.storeName || "가게명"} + {albaFormDetailData.location || "위치"}

{albaFormDetailData.title}

@@ -25,7 +27,7 @@ export default function FormDetails({ albaFormDetailData }: FormDetailsProps) {

{albaFormDetailData.location}

-
diff --git a/src/app/(pages)/(albaform)/alba/[formId]/components/RecruitInformation.tsx b/src/app/(pages)/(albaform)/alba/[formId]/components/RecruitInformation.tsx index c346ef01..f2c9d67a 100644 --- a/src/app/(pages)/(albaform)/alba/[formId]/components/RecruitInformation.tsx +++ b/src/app/(pages)/(albaform)/alba/[formId]/components/RecruitInformation.tsx @@ -22,7 +22,7 @@ export default function RecruitInformation({ albaFormDetailData, formId }: Recru }; return ( -
+
diff --git a/src/app/(pages)/(albaform)/alba/[formId]/edit/page.tsx b/src/app/(pages)/(albaform)/alba/[formId]/edit/page.tsx index 8e319f06..b1938682 100644 --- a/src/app/(pages)/(albaform)/alba/[formId]/edit/page.tsx +++ b/src/app/(pages)/(albaform)/alba/[formId]/edit/page.tsx @@ -8,8 +8,7 @@ import axios from "axios"; import TabMenuDropdown from "@/app/components/button/dropdown/TabMenuDropdown"; import Button from "@/app/components/button/default/Button"; import { toast } from "react-hot-toast"; -import { useMutation } from "@tanstack/react-query"; -import { useUpdateProfile } from "@/hooks/queries/user/me/useUpdateProfile"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import RecruitContentSection from "../../../addform/section/RecruitContentSection"; import RecruitConditionSection from "../../../addform/section/RecruitConditionSection"; import WorkConditionSection from "../../../addform/section/WorkConditionSection"; @@ -19,6 +18,7 @@ import useFormDetail from "@/hooks/queries/form/detail/useFormDetail"; import LoadingSpinner from "@/app/components/loading-spinner/LoadingSpinner"; import formatMoney from "@/utils/formatMoney"; import tempSave from "@/utils/tempSave"; +import { useUser } from "@/hooks/queries/user/me/useUser"; export default function EditFormPage() { const router = useRouter(); @@ -40,18 +40,16 @@ export default function EditFormPage() { const { reset, - setValue, handleSubmit, - formState: { isDirty, isValid }, + formState: { isDirty }, } = methods; + const queryClient = useQueryClient(); + // 훅폼에서 관리하는 전체 데이터를 가져오는 함수 const currentValues: SubmitFormDataType = methods.watch(); - const imageFiles = currentValues.imageFiles; // 탭 선택 옵션 관리 const [selectedOption, setSelectedOption] = useState("모집 내용"); - // 이미지 업로드 훅 - const { uploadImageMutation } = useUpdateProfile(); // 각각의 탭 작성중 여부 const { isEditingRecruitContent, isEditingRecruitCondition, isEditingWorkCondition } = useEditing(currentValues); @@ -60,20 +58,20 @@ export default function EditFormPage() { if (albaFormDetailData) { reset({ isPublic: albaFormDetailData.isPublic, - hourlyWage: formatMoney(String(albaFormDetailData.hourlyWage)), // 쉼표 추가하기 + hourlyWage: formatMoney(String(albaFormDetailData.hourlyWage)), isNegotiableWorkDays: albaFormDetailData.isNegotiableWorkDays, workDays: albaFormDetailData.workDays, workEndTime: albaFormDetailData.workEndTime, workStartTime: albaFormDetailData.workStartTime, - workEndDate: albaFormDetailData.workEndDate, // display값에 반영하기 + workEndDate: albaFormDetailData.workEndDate, // display & value 값에 반영하기 workStartDate: albaFormDetailData.workStartDate, location: albaFormDetailData.location, - preferred: albaFormDetailData.preferred, //value 반영하기 - age: albaFormDetailData.age, //value 반영하기 - education: albaFormDetailData.education, //value 반영하기 - gender: albaFormDetailData.gender, //value 반영하기 - numberOfPositions: albaFormDetailData.numberOfPositions, //value 반영하기 - recruitmentEndDate: albaFormDetailData.recruitmentEndDate, // display값에 반영하기 + preferred: albaFormDetailData.preferred, + age: albaFormDetailData.age, + education: albaFormDetailData.education, + gender: albaFormDetailData.gender, + numberOfPositions: albaFormDetailData.numberOfPositions, + recruitmentEndDate: albaFormDetailData.recruitmentEndDate, // display & value 값에 반영하기 recruitmentStartDate: albaFormDetailData.recruitmentStartDate, description: albaFormDetailData.description, title: albaFormDetailData.title, @@ -82,59 +80,15 @@ export default function EditFormPage() { } }, [albaFormDetailData, reset]); - // 이미지 업로드 api - const uploadImages = async (files: File[]) => { - if (currentValues.imageUrls.length !== currentValues.imageFiles.length) { - const uploadedUrls: string[] = []; - - // 전체 파일 배열을 순회하면서 업로드 로직 진행 - for (const file of files) { - // 파일 크기 체크 - const maxSize = 5 * 1024 * 1024; // 5MB - if (file.size > maxSize) { - toast.error(`5MB 이상의 파일은 업로드할 수 없습니다.`); - continue; - } - const formData = new FormData(); - formData.append("image", file); - try { - const uploadResponse = await uploadImageMutation.mutateAsync(file); - if (uploadResponse?.url) { - uploadedUrls.push(uploadResponse.url); - } - } catch (uploadError) { - console.error(`파일 ${file.name} 업로드 실패:`, uploadError); - } - } - return uploadedUrls; - } else { - return currentValues.imageUrls; - } - }; - // 폼데이터 임시 저장 함수 const onTempSave = async () => { - // 이미지 처리 로직 - if (imageFiles && imageFiles.length > 0) { - try { - const uploadedUrls = await uploadImages(Array.from(imageFiles)); - if (uploadedUrls && uploadedUrls.length > 0) { - setValue("imageUrls", [...uploadedUrls]); - } else { - setValue("imageUrls", [...currentValues.imageUrls]); - } - } catch (error) { - console.error("임시저장 - 이미지 업로드 중 오류 발생:", error); - setValue("imageUrls", []); - } - } tempSave("addformData", currentValues); }; // 수정된 폼 제출 리액트쿼리 const mutation = useMutation({ mutationFn: async () => { - const excludedKeys = ["displayDate", "workDateRange", "recruitDateRange", "imageFiles"]; + const excludedKeys = ["displayDate", "workDateRange", "recruitDateRange"]; // 원하는 필드만 포함된 새로운 객체 만들기 const filteredData = Object.entries(currentValues) @@ -152,6 +106,7 @@ export default function EditFormPage() { return acc; }, {}); await axios.patch(`/api/forms/${formId}`, filteredData); + console.log("filteredData", filteredData); }, onSuccess: () => { if (typeof window !== "undefined") { @@ -159,9 +114,14 @@ export default function EditFormPage() { } toast.success("알바폼을 수정했습니다."); router.push(`/alba/${formId}`); + // 쿼리 무효화 + queryClient.invalidateQueries({ + queryKey: ["formDetail", formId], + }); }, onError: (error) => { console.error("에러가 발생했습니다.", error); + console.log("currentValues", currentValues); toast.error("에러가 발생했습니다."); }, }); @@ -183,7 +143,7 @@ export default function EditFormPage() { "모집 조건": "recruit-condition", "근무 조건": "work-condition", }[option]; - router.push(`/alba/${formId}/edit?tab=${params}`); + router.replace(`/alba/${formId}/edit?tab=${params}`); }; const renderChildren = () => { @@ -199,12 +159,19 @@ export default function EditFormPage() { } }; - if (isLoading) - return ( -
- -
- ); + // 유저 권한 확인 + const { user } = useUser(); + + useEffect(() => { + if (user?.role !== "OWNER") { + toast.error("사장님만 알바폼을 작성할 수 있습니다."); + router.push("/alba-list"); + } + }, [user, router]); + + if (isLoading) { + return ; + } if (error) { return
Error: 데이터를 불러오는데 문제가 발생했습니다.
; @@ -226,14 +193,14 @@ export default function EditFormPage() { onChange={handleOptionChange} currentParam={currentParam || ""} /> -
+