diff --git a/src/apis/companies/index.ts b/src/apis/companies/index.ts index 293c0d1..d5c1140 100644 --- a/src/apis/companies/index.ts +++ b/src/apis/companies/index.ts @@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query"; import { useToastStore } from "@team-return/design-system"; import { instance } from "../axios"; import { GetNumberOfPagesType } from "../recruitments/type"; -import { CompaniesDetailsType, CompaniesListResponseType } from "./type"; +import { CompaniesDetailsType, CompaniesListResponseType, GetCompaniesForReviewingResponse } from "./type"; const router = "/companies"; @@ -56,3 +56,13 @@ export const useGetNumberOfCompaniesListPages = (queryString: string) => { ); return data; }; + +export const useGetCompaniesForReviewing = () => { + return useQuery( + ["getCompaniesForReviewing"], + async () => { + const {data} = await instance.get(`${router}/review`); + return data; + } + ) +} \ No newline at end of file diff --git a/src/apis/companies/type.ts b/src/apis/companies/type.ts index c51775b..e704c65 100644 --- a/src/apis/companies/type.ts +++ b/src/apis/companies/type.ts @@ -39,4 +39,13 @@ export interface CompaniesDetailsTable { attachments: any[]; service_name: string; business_area: string; -} \ No newline at end of file +} + +export interface CompaniesForReviewType { + id: number, + name: string, +} + +export interface GetCompaniesForReviewingResponse { + companies : CompaniesForReviewType[] +} diff --git a/src/apis/reviews/index.ts b/src/apis/reviews/index.ts index 6635fdd..60ea24d 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,47 @@ 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: { + switch ((response as AxiosResponse<{ message: string }>).data.message) { + case "Code Not Found": { + append({ + title: "", + message: "질문 분야가 누락되었습니다.", + type: "RED", + }); + break; + } + case 'ApplicationEntity Not Found': { + append({ + title: '', + message: '해당 기업에는 후기를 작성할 수 없습니다.', + type: 'RED', + }) + } + } + + } + } + }, + } + ); +}; 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 ad004b8..7aed9a5 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/app/mypage/page.tsx b/src/app/mypage/page.tsx index 5e633aa..34b309e 100644 --- a/src/app/mypage/page.tsx +++ b/src/app/mypage/page.tsx @@ -1,10 +1,12 @@ import AppliedCompaniesList from "@/components/mypage/AppliedCompaniesList"; import DetailProfile from "@/components/mypage/DetailProfile"; +import CompaniesForReviewing from "@/components/mypage/CompaniesForReviewing"; export default function MyPage() { return (
+
); 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..c80088b 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 === selected.toString()); 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} + /> +
+
+

답변

+