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
26 changes: 17 additions & 9 deletions src/app/(pages)/(albaform)/addform/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import { useEffect, useState } from "react";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import { FormProvider, useForm } from "react-hook-form";
import axios from "axios";
import TabMenuDropdown from "@/app/components/button/dropdown/TabMenuDropdown";
Expand All @@ -17,13 +17,13 @@ import CustomFormModal from "@/app/components/modal/modals/confirm/CustomFormMod

export default function AddFormPage() {
const router = useRouter();
const formId = useParams().formId;
// 리액트 훅폼에서 관리할 데이터 타입 지정 및 메서드 호출 (상위 컴���트 = useForm 사용)
const [formId, setFormId] = useState<number | undefined>(undefined);
// 리액트 훅폼에서 관리할 데이터 타입 지정 및 메서드 호출 (상위 컴포넌트 = useForm 사용)
const methods = useForm<SubmitFormDataType>({
mode: "onChange",
defaultValues: {
isPublic: false,
hourlyWage: 0,
isPublic: true,
hourlyWage: "10,030",
isNegotiableWorkDays: false,
workDays: [],
workEndTime: "",
Expand Down Expand Up @@ -92,7 +92,7 @@ export default function AddFormPage() {
acc[key] = Number(value);
} else if (key === "hourlyWage") {
// 문자열이면 콤마 제거 후 숫자로 변환
acc[key] = typeof value === "string" ? Number(value.replace(/,/g, "")) : Number(value);
acc[key] = typeof value === "string" ? String(Number(value.replace(/,/g, ""))) : String(Number(value));
} else if (key === "imageUrls") {
// 업로드된 이미지 URL 사용
acc[key] = uploadedUrls;
Expand All @@ -102,14 +102,16 @@ export default function AddFormPage() {
return acc;
}, {});

await axios.post("/api/forms", filteredData);
const response = await axios.post("/api/forms", filteredData);
const id = response.data.id;
setFormId(id);
},
onSuccess: () => {
if (typeof window !== "undefined") {
window.localStorage.removeItem("tempAddFormData");
}
toast.success("알바폼을 등록했습니다.");
router.push(`/alba/${formId}`);
// if (formId) router.push(`/alba/${formId}`);
},
onError: (error) => {
console.error("에러가 발생했습니다.", error);
Expand All @@ -118,6 +120,12 @@ export default function AddFormPage() {
},
});

useEffect(() => {
if (formId) {
router.push(`/alba/${formId}`);
}
}, [formId]);

// tab 선택 시 Url params 수정 & 하위 폼 데이터 임시저장
const searchParams = useSearchParams();
const currentParam = searchParams.get("tab");
Expand Down Expand Up @@ -277,7 +285,7 @@ export default function AddFormPage() {
options={[
{
label: "모집 내용",
isEditing: isEditingRecruitContent || initialLoad || currentParam === "recruit-content",
isEditing: isEditingRecruitContent || currentParam === "recruit-content",
},
{ label: "모집 조건", isEditing: isEditingRecruitCondition || currentParam === "recruit-condition" },
{ label: "근무 조건", isEditing: isEditingWorkCondition || currentParam === "work-condition" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export default function RecruitContentSection() {
const {
register,
setValue,
getValues,
formState: { errors },
} = useFormContext();

Expand Down
47 changes: 27 additions & 20 deletions src/app/(pages)/(albaform)/addform/section/WorkConditionSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export default function WorkConditionSection() {
const {
register,
setValue,
getValues,
trigger,
watch,
formState: { errors },
Expand All @@ -40,6 +39,7 @@ export default function WorkConditionSection() {

//근무 요일 지정
const [selectedWorkDays, setSelectedWorkDays] = useState<string[]>([]);
const negotiable = watch("isNegotiableWorkDays");

const handleClickDay = (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
Expand All @@ -54,6 +54,9 @@ export default function WorkConditionSection() {
setValue("workDays", [...selectedWorkDays, day]);
trigger("workDays");
}
if (negotiable) {
setSelectedWorkDays([]);
}
};

// 최저시급 상수 수정 (2025년 기준)
Expand Down Expand Up @@ -100,7 +103,7 @@ export default function WorkConditionSection() {
<div className="relative">
<Script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js" strategy="afterInteractive" />

<form className="my-8 flex flex-col gap-4">
<form className="my-8 flex flex-col gap-8">
<Label>근무 위치</Label>
<div className="relative">
<LocationInput
Expand Down Expand Up @@ -151,35 +154,39 @@ export default function WorkConditionSection() {
))}
</div>

{/* 요일 협의 가능하다면 근무요일은 선택하지 않아도 됨 */}
<div className="flex flex-col gap-4">
<Label>근무 요일</Label>
<DayPickerList workDays={selectedWorkDays} onClick={handleClickDay} />
<DayPickerList workDays={selectedWorkDays} onClick={handleClickDay} disabled={negotiable} />

<div className="relative flex flex-col pl-[14px]">
<CheckBtn
label="요일 협의 가능"
checked={watch("isNegotiableWorkDays")}
{...register("isNegotiableWorkDays")}
/>
{selectedWorkDays.length === 0 && <p className={cn(errorTextStyle, "")}>근무 요일을 선택해주세요.</p>}
{selectedWorkDays.length === 0 && !negotiable && (
<p className={cn(errorTextStyle, "")}>근무 요일을 선택해주세요.</p>
)}
</div>
</div>

<Label>시급</Label>
<BaseInput
{...register("hourlyWage", {
required: "시급을 작성해주세요.",
min: {
value: MINIMUM_WAGE,
message: `최저시급(${formatMoney(MINIMUM_WAGE.toString())}원) 이상을 입력해주세요.`,
},
})}
value={displayWage}
onChange={handleWageChange}
variant="white"
afterString="원"
errormessage={errors.hourlyWage?.message as string}
/>
<div className="flex flex-col gap-4">
<Label>시급</Label>
<BaseInput
{...register("hourlyWage", {
required: "시급을 작성해주세요.",
min: {
value: MINIMUM_WAGE,
message: `최저시급(${formatMoney(MINIMUM_WAGE.toString())}원) 이상을 입력해주세요.`,
},
})}
value={displayWage}
onChange={handleWageChange}
variant="white"
afterString="원"
errormessage={errors.hourlyWage?.message as string}
/>
</div>

<div className="relative flex flex-col gap-4">
<Label>공개 설정</Label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function FormDetails({ albaFormDetailData }: FormDetailsProps) {
</div>
<p className="text-3xl font-bold">{albaFormDetailData.title}</p>
<div className="space-y-32">
<div className="text-2xl">{albaFormDetailData.description}</div>
<div className="whitespace-pre-wrap text-2xl">{albaFormDetailData.description}</div>
<p className="text-3xl font-bold">근무 지역</p>
</div>
<div className="flex space-x-5 text-2xl">
Expand Down
5 changes: 3 additions & 2 deletions src/app/(pages)/(albaform)/alba/[formId]/edit/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import WorkConditionSection from "../../../addform/section/WorkConditionSection"
import { SubmitFormDataType } from "@/types/addform";
import useEditing from "@/hooks/useEditing";
import useFormDetail from "@/hooks/queries/form/detail/useFormDetail";
import formatMoney from "@/utils/formatMoney";

export default function EditFormPage() {
const router = useRouter();
Expand Down Expand Up @@ -57,7 +58,7 @@ export default function EditFormPage() {
if (albaFormDetailData) {
reset({
isPublic: albaFormDetailData.isPublic,
hourlyWage: albaFormDetailData.hourlyWage, // 쉼표 추가하기
hourlyWage: formatMoney(String(albaFormDetailData.hourlyWage)), // 쉼표 추가하기
isNegotiableWorkDays: albaFormDetailData.isNegotiableWorkDays,
workDays: albaFormDetailData.workDays,
workEndTime: albaFormDetailData.workEndTime,
Expand Down Expand Up @@ -146,7 +147,7 @@ export default function EditFormPage() {
acc[key] = Number(value);
} else if (key === "hourlyWage") {
// hourlyWage는 쉼표를 제거하고 숫자형으로 변환
if (value.includes(",")) acc[key] = Number(value.replaceAll(/,/g, "")); // 쉼표 제거 후 숫자형 변환
if (value.includes(",")) acc[key] = String(Number(value.replaceAll(/,/g, ""))); // 쉼표 제거 후 숫자형 변환
} else {
acc[key as keyof SubmitFormDataType] = value; // 나머지 값은 그대로 추가
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import { useParams } from "next/navigation";
import React, { useEffect, useState } from "react";
import { useUser } from "@/hooks/queries/user/me/useUser";
import FormHeader from "../components/FormHeader";
import FormDetails from "../components/FormDetail";
import RecruitInformation from "../components/RecruitInfomation";
import ApplicationStatus from "../components/ApplicationStatus";
import { useFormDetail } from "@/hooks/queries/form/detail/useFormDetail";
import { Map, MapMarker, useKakaoLoader } from "react-kakao-maps-sdk";
import Script from "next/script";
import FormHeader from "./edit/components/FormHeader";
import FormDetails from "./edit/components/FormDetail";
import RecruitInformation from "./edit/components/RecruitInfomation";
import ApplicationStatus from "./edit/components/ApplicationStatus";

interface Coords {
lat: number;
Expand Down
87 changes: 50 additions & 37 deletions src/app/(pages)/(albaform)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,62 @@ import useModalStore from "@/store/modalStore";
import { usePathname, useRouter } from "next/navigation";

export default function Layout({ children }: { children: ReactNode }) {
const { openModal } = useModalStore();
const router = useRouter();
const pathname = usePathname();
const title = pathname.split("/").includes("apply") ? "알바폼 지원하기" : "알바폼 만들기";

const { openModal } = useModalStore();
const formPath = ["edit", "addform", "apply"];
//formPath 배열의 원소 중 포함되는게 있는지 여부 확인

const isForm: boolean = pathname.split("/").some((path) => formPath.includes(path));
const isFormWithTab: boolean = pathname.split("/").some((path) => path === "addform" || path === "edit");
const title = pathname.split("/").includes("apply") && isForm ? "알바폼 지원하기" : "알바폼 만들기";

// 폼 작성 페이지 레이아웃
const FormStyle = cn(
"mx-auto my-10 w-[327px] pb-[70px] lg:w-[680px] lg:pb-0 lg:pl-10",
isFormWithTab ? "lg:ml-[600px]" : ""
);

// 상세 페이지 레이아웃
const DetailStyle = "mx-auto max-w-screen-2xl px-4 py-4 sm:px-6 md:py-8";

return (
<div
className={cn(
"mx-auto my-10 w-[327px] pb-[70px] lg:w-[680px] lg:pb-0 lg:pl-10",
title === "알바폼 만들기" ? "lg:ml-[600px]" : ""
<div className={cn(isForm ? FormStyle : DetailStyle)}>
{isForm && (
<ApplyHeader
title={title}
onCancel={() =>
openModal("customForm", {
isOpen: true,
title: "폼 작성 취소",
content: "작성을 취소하시겠습니까?",
onConfirm: () => {
openModal("customForm", {
isOpen: false,
title: "",
content: "",
onConfirm: () => {},
onCancel: () => {},
});
router.back();
},
onCancel: () => {
openModal("customForm", {
isOpen: false,
title: "",
content: "",
onConfirm: () => {},
onCancel: () => {},
});
},
})
}
/>
)}
>
<ApplyHeader
title={title}
onCancel={() =>
openModal("customForm", {
isOpen: true,
title: "폼 작성 취소",
content: "작성을 취소하시겠습니까?",
onConfirm: () => {
openModal("customForm", {
isOpen: false,
title: "",
content: "",
onConfirm: () => {},
onCancel: () => {},
});
router.back();
},
onCancel: () => {
openModal("customForm", {
isOpen: false,
title: "",
content: "",
onConfirm: () => {},
onCancel: () => {},
});
},
})
}
/>
<Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
<Suspense fallback={<div className="flex h-[calc(100vh-200px)] items-center justify-center">Loading...</div>}>
{children}
</Suspense>
</div>
);
}
File renamed without changes.
4 changes: 2 additions & 2 deletions src/app/components/button/default/CheckBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ interface CheckBtnProps extends InputHTMLAttributes<HTMLInputElement> {
}

const CheckBtn = forwardRef<HTMLInputElement, CheckBtnProps>(
({ label, name, checked = false, disabled = false, onChange, className, ...props }, ref) => {
({ label, name, checked = true, disabled = false, onChange, className, ...props }, ref) => {
return (
<label
htmlFor={name}
className={cn(
"flex items-center gap-[10px] rounded-lg text-sm",
"flex items-center gap-[10px] rounded-lg text-sm lg:text-base",
disabled ? "cursor-not-allowed text-grayscale-400" : "text-black cursor-pointer",
className
)}
Expand Down
18 changes: 17 additions & 1 deletion src/app/components/input/dateTimeDaypicker/DayPickerBtn.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
import { cn } from "@/lib/tailwindUtil";
import { MouseEvent } from "react";
import toast from "react-hot-toast";

const DayPickerBtn = ({
selected,
value,
onClick,
disabled,
}: {
selected: boolean;
value: string;
onClick: (e: MouseEvent<HTMLButtonElement>) => void;
disabled?: boolean;
}) => {
const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
if (disabled) {
toast.error("요일 협의가 가능한 경우 근무 요일을 선택하실 수 없습니다.");
}
onClick(e);
};
const defaultStyle = "bg-background-200 text-grayscale-500";
const activeStyle = "bg-primary-orange-300 text-white";
const disabledStyle = "bg-grayscale-200 text-grayscale-500";
const textStyle =
"placeholder:text-base placeholder:leading-[26px] lg:placeholder:text-xl lg:placeholder:leading-8 lg:text-xl font-normal lg:leading-8 text-base leading-[26px]";

return (
<div>
<button
onClick={handleClick}
className={`h-12 w-[38px] rounded-xl bg-background-200 focus:outline-none lg:h-[64px] lg:w-[50px] lg:rounded-2xl ${selected ? activeStyle : defaultStyle}`}
disabled={disabled}
className={cn(
"h-12 w-[38px] rounded-xl bg-background-200 focus:outline-none lg:h-[64px] lg:w-[50px] lg:rounded-2xl",
textStyle,
selected ? activeStyle : defaultStyle,
disabled ? disabledStyle : ""
)}
>
{value}
</button>
Expand Down
Loading
Loading