Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge :: 면접 후기 작성 #61

Merged
merged 7 commits into from
Apr 8, 2024
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
12 changes: 11 additions & 1 deletion src/apis/companies/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -56,3 +56,13 @@ export const useGetNumberOfCompaniesListPages = (queryString: string) => {
);
return data;
};

export const useGetCompaniesForReviewing = () => {
return useQuery(
["getCompaniesForReviewing"],
async () => {
const {data} = await instance.get<GetCompaniesForReviewingResponse>(`${router}/review`);
return data;
}
)
}
11 changes: 10 additions & 1 deletion src/apis/companies/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,13 @@ export interface CompaniesDetailsTable {
attachments: any[];
service_name: string;
business_area: string;
}
}

export interface CompaniesForReviewType {
id: number,
name: string,
}

export interface GetCompaniesForReviewingResponse {
companies : CompaniesForReviewType[]
}
51 changes: 49 additions & 2 deletions src/apis/reviews/index.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -24,3 +27,47 @@ export const useGetReviewDetails = (reviewId: string) => {
return data;
});
};

export const useCreateReviews = (options: Omit<UseMutationOptions<AxiosResponse<any, any>, unknown, createReviewRequestType, unknown>, "mutationFn">) => {
const { append } = useToastStore();
jikwan0327 marked this conversation as resolved.
Show resolved Hide resolved
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',
})
}
}

}
}
},
}
);
};
11 changes: 11 additions & 0 deletions src/apis/reviews/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
}
90 changes: 90 additions & 0 deletions src/app/companies/reviews/create/page.tsx
Original file line number Diff line number Diff line change
@@ -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<qnaElementsType[]>([
{ 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 (
<div className="w-2/3 mx-auto my-5">
<p className="py-12 leading-10 text-center text-h4 font-b text-primaryBlue03">
후기작성
</p>
{qnaElements
.map((qnaElement, idx) => (
<ReviewForm key={idx} onChange={handleChange} removeReviews={removeReviewList} setState={setQnaElements} index={idx} {...qnaElement} />
))}
<div className="flex justify-between">
<FillBtn
backgroundColor="#ccc"
onClick={() => {
setQnaElements(prev => ([
...prev,
{ question: "", answer: "", code_id: 0 }
]));
}}
>
면접질문 추가
</FillBtn>
<div className="flex gap-3">
<FillBtn
backgroundColor="#ccc"
onClick={() => {
router.back();
}}
>
이전으로
</FillBtn>
<FillBtn onClick={handleClickCreateRevies}>완료</FillBtn>
</div>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion src/app/companies/reviews/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default function Reviews() {
return (
<div className="w-2/3 mx-auto my-5">
<p className="py-12 leading-10 text-center text-h4 font-b text-primaryBlue03">
면접 후기
면접후기
</p>
<hr className="border-[#135C9D]" />
<ReviewList />
Expand Down
4 changes: 4 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
}

textarea {
resize: none;
}

table {
width: 100%;
border: none;
Expand Down
2 changes: 2 additions & 0 deletions src/app/mypage/page.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="py-[56px] mx-[9vw]">
<DetailProfile />
<CompaniesForReviewing />
<AppliedCompaniesList />
</div>
);
Expand Down
20 changes: 20 additions & 0 deletions src/components/common/Button/FillBtn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";

interface Propstype extends React.ButtonHTMLAttributes<HTMLButtonElement> {
backgroundColor?: string
}

export default function FillBtn({ children, backgroundColor, style, ...rest }: Propstype) {
return (
<button
className='min-w-[122px] h-[48px] py-3 px-4 text-b2 leading-b2 font-b rounded-[8px] text-white'
{...rest}
style={{
backgroundColor: backgroundColor || '#135c9d',
...style,
}}
>
{children}
</button>
);
}
11 changes: 0 additions & 11 deletions src/components/common/Button/SendBtn.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/common/DropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/TextFiled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function TextFiled({
<p className="text-caption text-[#333333] font-m mb-[4px]">{label}</p>
)}
<div
className={`w-full border border-solid rounded-[8px] flex align-center overflow-hidden`}
className={`w-full border border-solid rounded-[8px] flex align-center overflow-hidden`}
style={{
borderColor: focus ? theme.color.liteBlue : "#cccccc",
height: height
Expand Down
101 changes: 101 additions & 0 deletions src/components/company/ReviewForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from "react";
import { useGetCode } from "@/apis/code";
import DropDown from "@/components/common/DropDown";
import TextFiled from "@/components/common/TextFiled";
import useForm from "@/hook/useForm";
import { useRef, useState } from "react";
import { theme } from "@team-return/design-system";
import { qnaElementsType } from "@/apis/reviews/type";

interface PropsType {
question: string;
answer: string;
code_id: number;
index: number;
onChange: (idx: number, name: keyof qnaElementsType, value: string) => void;
setState: React.Dispatch<React.SetStateAction<qnaElementsType[]>>;
removeReviews: (index:number) => void;
}

export default function ReviewForm({
question,
answer,
code_id,
index,
onChange,
setState: setQnaElements,
removeReviews
}: PropsType) {
const textarea = useRef<HTMLTextAreaElement | null>(null);

const { data: codes } = useGetCode("JOB");

const [isFocus, setIsFocus] = useState<boolean>(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 (
<div className="mb-10 relative">
<div className="flex gap-3">
<TextFiled
label="면접 질문"
placeholder="면접 질문 입력"
value={question}
name="question"
onChange={e => {
onChange(index, "question", e.target.value);
}}
className="flex-1"
/>
<div className="w-fit">
<p className="text-caption text-[#333333] font-m mb-[4px]">
질문 분야
</p>
<DropDown
title="분야선택"
items={jobCodeDropdownItems ?? [{ code: "1", label: "" }]}
onClickItem={(itemCode: string) => {
setQnaElements(prev => {
const updatedElements = [...prev];
updatedElements[index].code_id = Number(itemCode);
return updatedElements;
});
}}
selected={code_id}
/>
</div>
</div>
<p className="text-caption text-[#333333] font-m mb-[4px] mt-4">답변</p>
<textarea
ref={textarea}
value={answer}
name="answer"
onChange={e => {
onChange(index, "answer", e.target.value);
handleResizeHeight();
}}
className="border border-solid rounded-[8px] px-4 py-3 text-b3 font-r leading-b3 outline-none w-full min-h-[200px]"
placeholder="질문에 어떻게 답했나요?"
style={{
borderColor: isFocus ? theme.color.liteBlue : "#cccccc",
}}
onFocus={() => {
setIsFocus(true);
}}
onBlur={() => {
setIsFocus(false);
}}
/>
<button onClick={()=>{removeReviews(index)}} className="absolute bottom-1 right-[-8%] text-caption text-[#7f7f7f] font-r p-2">삭제</button>
</div>
);
}
Loading
Loading