From a71d7f72db4d12db1d85e27726955e8a06b88ddc Mon Sep 17 00:00:00 2001 From: KANGYONGSU23 Date: Thu, 4 Apr 2024 12:07:36 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat=20::=20=EB=A6=AC=EB=B7=B0=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/reviews/index.ts | 44 +++++++++- src/apis/reviews/type.ts | 11 +++ src/app/companies/reviews/create/page.tsx | 90 +++++++++++++++++++ src/app/companies/reviews/page.tsx | 2 +- src/app/globals.css | 4 + src/components/common/Button/FillBtn.tsx | 20 +++++ src/components/common/Button/SendBtn.tsx | 11 --- src/components/common/DropDown.tsx | 2 +- src/components/common/TextFiled.tsx | 2 +- src/components/company/ReviewForm.tsx | 101 ++++++++++++++++++++++ src/components/recruitments/filter.tsx | 10 +-- 11 files changed, 276 insertions(+), 21 deletions(-) create mode 100644 src/app/companies/reviews/create/page.tsx create mode 100644 src/components/common/Button/FillBtn.tsx delete mode 100644 src/components/common/Button/SendBtn.tsx create mode 100644 src/components/company/ReviewForm.tsx diff --git a/src/apis/reviews/index.ts b/src/apis/reviews/index.ts index 6635fdd..1a8d7fd 100644 --- a/src/apis/reviews/index.ts +++ b/src/apis/reviews/index.ts @@ -1,8 +1,11 @@ -import { useQuery } from "@tanstack/react-query"; +import { MutationOptions, useMutation, UseMutationOptions, useQuery } from "@tanstack/react-query"; +import { useToastStore } from "@team-return/design-system"; +import { AxiosError, AxiosResponse } from "axios"; import { instance } from "../axios"; import { getReviewDetailResponseProps, - getReviewListResponseProps + getReviewListResponseProps, + createReviewRequestType, } from "./type"; const router = "/reviews"; @@ -24,3 +27,40 @@ export const useGetReviewDetails = (reviewId: string) => { return data; }); }; + +export const useCreateReviews = (options: Omit, unknown, createReviewRequestType, unknown>, "mutationFn">) => { + const { append } = useToastStore(); + return useMutation( + async (body: createReviewRequestType) => + await instance.post(`${router}`, body), + { + ...options, + onError: (err: AxiosError) => { + const { response } = err; + switch (response?.status) { + case 400: { + append({ + title: "", + message: "입력값은 비어있으면 안됩니다.", + type: "RED", + }); + break; + } + case 404: { + if ( + (response as AxiosResponse<{ message: string }>).data.message === + "Code Not Found" + ) { + append({ + title: "", + message: "질문 분야가 누락되었습니다.", + type: "RED", + }); + } + break; + } + } + }, + } + ); +}; diff --git a/src/apis/reviews/type.ts b/src/apis/reviews/type.ts index dcfe322..8e80a40 100644 --- a/src/apis/reviews/type.ts +++ b/src/apis/reviews/type.ts @@ -18,3 +18,14 @@ export interface getReviewDetailProps { answer: string; area: string; } + +export interface qnaElementsType { + question: string; + answer: string; + code_id: number; +} + +export interface createReviewRequestType { + company_id: number; + qna_elements: qnaElementsType[] +} \ No newline at end of file diff --git a/src/app/companies/reviews/create/page.tsx b/src/app/companies/reviews/create/page.tsx new file mode 100644 index 0000000..fc36510 --- /dev/null +++ b/src/app/companies/reviews/create/page.tsx @@ -0,0 +1,90 @@ +"use client"; + +import { useState } from "react"; +import ReviewForm from "@/components/company/ReviewForm"; +import FillBtn from "@/components/common/Button/FillBtn"; +import { useRouter, useSearchParams } from "next/navigation"; +import { useCreateReviews } from "@/apis/reviews"; +import { qnaElementsType } from "@/apis/reviews/type"; + +export default function CreateReviews() { + const router = useRouter(); + const params = useSearchParams(); + const companyId = Number(params.get('id')) + const [qnaElements, setQnaElements] = useState([ + { question: "", answer: "", code_id: 0 }, + ]); + const mutateOption = { + onSuccess: () => { + router.push(`/companies/reviews/?id=${companyId}`) + } + } + const { mutate: createReviews } = useCreateReviews(mutateOption); + + const handleClickCreateRevies = () => { + createReviews({ + company_id:companyId, + qna_elements: qnaElements + }) + } + + const handleChange = ( + index: number, + name: keyof qnaElementsType, + value: string | number + ) => { + setQnaElements(prev => { + const newReviews = [...prev]; + if (typeof value === "number") { + newReviews[index].code_id = value; + } else if (name !== "code_id") { + newReviews[index][name] = value; + } + return newReviews; + }); + }; + + const removeReviewList = (index: number) => { + setQnaElements(prev=>{ + let newReviews = [...prev]; + newReviews = newReviews.filter((_,idx)=>idx !== index); + return newReviews; + }) + } + + return ( +
+

+ 후기작성 +

+ {qnaElements + .map((qnaElement, idx) => ( + + ))} +
+ { + setQnaElements(prev => ([ + ...prev, + { question: "", answer: "", code_id: 0 } + ])); + }} + > + 면접질문 추가 + +
+ { + router.back(); + }} + > + 이전으로 + + 완료 +
+
+
+ ); +} diff --git a/src/app/companies/reviews/page.tsx b/src/app/companies/reviews/page.tsx index fe30be7..fec1e50 100644 --- a/src/app/companies/reviews/page.tsx +++ b/src/app/companies/reviews/page.tsx @@ -4,7 +4,7 @@ export default function Reviews() { return (

- 면접 후기 + 면접후기


diff --git a/src/app/globals.css b/src/app/globals.css index d1928ca..4f381e5 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -53,6 +53,10 @@ input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; } +textarea { + resize: none; +} + table { width: 100%; border: none; diff --git a/src/components/common/Button/FillBtn.tsx b/src/components/common/Button/FillBtn.tsx new file mode 100644 index 0000000..76f7fb6 --- /dev/null +++ b/src/components/common/Button/FillBtn.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +interface Propstype extends React.ButtonHTMLAttributes { + backgroundColor?: string +} + +export default function FillBtn({ children, backgroundColor, style, ...rest }: Propstype) { + return ( + + ); +} diff --git a/src/components/common/Button/SendBtn.tsx b/src/components/common/Button/SendBtn.tsx deleted file mode 100644 index 5773760..0000000 --- a/src/components/common/Button/SendBtn.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -function SendBtn() { - return ( - <> - <> - - ); -} - -export default React.memo(SendBtn); diff --git a/src/components/common/DropDown.tsx b/src/components/common/DropDown.tsx index 54ffa72..54889a7 100644 --- a/src/components/common/DropDown.tsx +++ b/src/components/common/DropDown.tsx @@ -19,7 +19,7 @@ interface PropsType { function DropDown({ title, items, onClickItem, selected }: PropsType) { const { toggleDropdown, DropDownComponent, closeDropDown } = useDropDown(); - const selectedItemLabel = items.find((item) => item.code === selected); + const selectedItemLabel = items.find((item) => item.code === String(selected)); return (
{label}

)}
void; + setState: React.Dispatch>; + removeReviews: (index:number) => void; +} + +export default function ReviewForm({ + question, + answer, + code_id, + index, + onChange, + setState: setQnaElements, + removeReviews +}: PropsType) { + const textarea = useRef(null); + + const { data: codes } = useGetCode("JOB"); + + const [isFocus, setIsFocus] = useState(false); + + const jobCodeDropdownItems = codes?.codes.map(item => ({ + code: item.code.toString(), + label: item.keyword, + })); + + const handleResizeHeight = () => { + if (textarea?.current) { + textarea.current.style.height = "auto"; + textarea.current.style.height = textarea.current.scrollHeight + "px"; + } + }; + return ( +
+
+ { + onChange(index, "question", e.target.value); + }} + className="flex-1" + /> +
+

+ 질문 분야 +

+ { + setQnaElements(prev => { + const updatedElements = [...prev]; + updatedElements[index].code_id = Number(itemCode); + return updatedElements; + }); + }} + selected={code_id} + /> +
+
+

답변

+