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
66 changes: 18 additions & 48 deletions src/app/(pages)/(albaform)/addform/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -43,7 +44,6 @@ export default function AddFormPage() {
description: "",
title: "",
imageUrls: [],
imageFiles: [],
},
});

Expand All @@ -57,12 +57,9 @@ export default function AddFormPage() {
const currentValues: SubmitFormDataType = methods.watch();

// 이미지 업로드 api 처리를 위해 별도 변수에 할당
const imageFiles = currentValues.imageFiles;
const [, setSelectedOption] = useState<string>("");
const [showTempDataModal, setShowTempDataModal] = useState(false);

const { uploadImages } = useUploadImages();

// 각각의 탭 작성중 여부
const { isEditingRecruitContent, isEditingRecruitCondition, isEditingWorkCondition } = useEditing(currentValues);

Expand All @@ -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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
};

Expand All @@ -177,7 +133,7 @@ export default function AddFormPage() {
"모집 조건": "recruit-condition",
"근무 조건": "work-condition",
}[option];
router.push(`/addform?tab=${params}`);
router.replace(`/addform?tab=${params}`);
};

useEffect(() => {
Expand Down Expand Up @@ -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 <LoadingSpinner />;
}

return (
<FormProvider {...methods}>
<div className="relative pb-10 lg:pb-0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ImageInputType[]>([]);

//훅폼 하위 컴포넌트에서는 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]);
Expand All @@ -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]";

Expand Down Expand Up @@ -88,10 +131,11 @@ export default function RecruitContentSection() {
<Label>이미지 첨부</Label>
<div>
<ImageInput
{...register("imageUrls", { required: "이미지는 필수입니다." })}
{...register("imageUrls")}
onChange={(files: File[]) => {
handleChangeImages(files);
}}
onDelete={(id) => handleDeleteImage(id)}
initialImageList={initialImageList}
/>
{errors.imageUrls && <p className={cn(errorTextStyle, "")}>{errors.imageUrls.message as string}</p>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export default function FormDetails({ albaFormDetailData }: FormDetailsProps) {
return (
<>
<div className="mb-4 flex items-end gap-4">
<span className="text-lg text-black-400 underline lg:text-2xl">{albaFormDetailData.storeName || "가게명"}</span>
<span className="min-w-[120px] text-lg text-black-400 underline lg:text-2xl">
{albaFormDetailData.storeName || "가게명"}
</span>
<span className="text-md text-grayscale-500 lg:text-xl">{albaFormDetailData.location || "위치"}</span>
</div>
<p className="text-3xl font-bold">{albaFormDetailData.title}</p>
Expand All @@ -25,7 +27,7 @@ export default function FormDetails({ albaFormDetailData }: FormDetailsProps) {
</div>
<div className="flex space-x-5 text-2xl">
<p>{albaFormDetailData.location}</p>
<button type="button" className="text-xl text-primary-orange-300" onClick={handleCopyLocation}>
<button type="button" className="w-[60px] text-xl text-primary-orange-300" onClick={handleCopyLocation}>
복사
</button>
</div>
Expand Down
Loading
Loading