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

feat: 합/불 상태관리 페이지 추가 #205

Merged
merged 22 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6f7ace8
feat: 합불 관리 페이지 추가
geongyu09 Sep 13, 2024
96a5372
feat: 합불 요청 api 추가
geongyu09 Sep 13, 2024
410a1c9
feat: 합불 상태관리 네브바 추가
geongyu09 Sep 15, 2024
289604c
feat: pass state관련 api 로직 추가
geongyu09 Sep 15, 2024
023a3d4
design: 레이아웃 수정
geongyu09 Sep 15, 2024
bd64439
feat: 분야별 정렬 기능 추가
geongyu09 Sep 15, 2024
38890af
feat: TODO 작성
geongyu09 Sep 15, 2024
0c4a80c
refactor: 유틸 함수 function으로 옮김
geongyu09 Sep 15, 2024
9738a23
fix: 빌드 버그 수정
geongyu09 Sep 15, 2024
7cae5fa
fix: tailwind가 동적으로 적용이 되지 않던 버그 수정
geongyu09 Sep 15, 2024
192cb56
refactor: url을 기존 코딩 스타일에 맞추어 변경
geongyu09 Sep 16, 2024
7ec8cc1
refactor: 불필요한 조건문 제거
geongyu09 Sep 16, 2024
10af5ee
refactor: searchParams를 삼항연산자가 아닌 URLSearchParams로 변경
geongyu09 Sep 16, 2024
c6a4cd3
fix: query 문의 loading상태를 보여주도록 수정
geongyu09 Sep 16, 2024
ebb1b9a
refactor: 올바르게 카멜케이스가 되어있지 않던 부분 수정
geongyu09 Sep 16, 2024
26a4913
feat: query문 불필요한 추상화 제거
geongyu09 Sep 16, 2024
325aa41
refactor: 기존에 정의해둔 tailwind custom styles 사용
geongyu09 Sep 16, 2024
8d852bb
refactor: getApplicantPassState 유틸 함수에 불필요하게 적용된 switch-case 문을 객체로 변경
geongyu09 Sep 16, 2024
c522277
refactor: 합격 상태에 따른 비교 계층 변경
geongyu09 Sep 16, 2024
836ca3d
refactor: 불필요하게applicants에 조건문을 사용하던 부분 수정
geongyu09 Sep 16, 2024
e266f6a
fix: 분야별 정렬 부분에 들어가는 이미지에 alt 추가
geongyu09 Sep 16, 2024
46c03d1
feat: 목 데이터를 지우고 실제 서버와 통신하도록 수정
geongyu09 Sep 18, 2024
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
61 changes: 61 additions & 0 deletions frontend/app/(WithNavbar)/pass-state/[generation]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import Txt from "@/components/common/Txt.component";
import ApplicantsList from "@/components/passState/ApplicantsList";
import { CURRENT_GENERATION } from "@/src/constants";
import Image from "next/image";
import Link from "next/link";

interface PassStatePageProps {
searchParams: {
sortedBy?: "field";
};
}
Comment on lines +7 to +11
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next를 쓰고 있다는게 새삼스럽게 느껴지네요 ㅋㅋㅋ


const PassStatePage = ({ searchParams: { sortedBy } }: PassStatePageProps) => {
return (
<div className="flex-1 ml-32 min-w-[46rem] mb-12">
<div className="mt-20" />
<Txt typography="h3">
{CURRENT_GENERATION}기 지원자 합격 상태 관리 페이지
</Txt>
<div className="mt-8" />
{sortedBy && sortedBy === "field" && (
2yunseong marked this conversation as resolved.
Show resolved Hide resolved
<Link href={`/pass-state/${CURRENT_GENERATION}`}>
<Txt typography="h5" className="text-secondary-200">
현재 분야별로 정렬되어 있습니다. (WEB - APP - AI - GAME)
</Txt>
<div className="mt-8" />
</Link>
)}
<div className="grid grid-cols-[8fr_8fr_4fr_3fr] gap-4">
<Txt typography="h6" className="text-left text-secondary-100">
지원자 이름
</Txt>
<Link
href={`/pass-state/${CURRENT_GENERATION}${
sortedBy ? "" : "?sortedBy=field"
}`}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삼항 연산 없이

Suggested change
href={`/pass-state/${CURRENT_GENERATION}${
sortedBy ? "" : "?sortedBy=field"
}`}
href={`/pass-state/${CURRENT_GENERATION}?${new URLSearchParams(searchParams)}`}

로도 쓸 수 있을 것 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋네요! 이것도 수정해보겠습니다!

className="text-start flex justify-between pr-4 items-center"
>
<Txt typography="h6" className="text-left text-secondary-100">
분야
</Txt>
<Image
src={"/icons/chevron-down.svg"}
alt=""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

물론 우리는 눈이 잘 안보인다거나 그런 사람은 없지만, 코딩하는 습관은 들면 좋죠?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하하.... 제가 어제 왜이렇게 급했는지 모르겠네요.. 이번 pr은 실수 투성이네요
실수를 찾아주시는 모든 팀원분들께 감사의 말씀 드리고 싶습니다.

width={16}
height={16}
/>
</Link>
<Txt typography="h6" className="text-left text-secondary-100">
합격 상태
</Txt>
</div>
<div className="mt-2" />
<hr />
<div className="mt-4" />
<ApplicantsList sortedBy={sortedBy} />
</div>
);
};

export default PassStatePage;
1 change: 1 addition & 0 deletions frontend/components/common/Txt.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const colorType = {
white: "text-white",
blue: "text-primary",
light_gray: "text-secondary-200",
red: "text-red-500",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

먼가 이전에 잘못 본게 있었지만.... 그래도 우리 나름의 디자인 시스템 있는 것은 아시죠...?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이럴수가.. 수정하도록 하겠습니다!

};

interface TxtProps extends PropsWithChildren {
Expand Down
4 changes: 3 additions & 1 deletion frontend/components/common/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { NavbarOperation } from "./NavbarOperation";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { NavbarGenerationToggle } from "./NavbarGenerationToggle";
import { NavbarManagePassState } from "./NavbarManagePassState";

const CommonNavbar = () => {
const [_, currentType, generation] = usePathname().split("/");
Expand All @@ -31,7 +32,8 @@ const CommonNavbar = () => {
/>
))}
<NavbarGenerationToggle generation={generation} isShort={isShort} />
<NavbarOperation currentType={currentType} />
<NavbarManagePassState currentType={currentType} isShort={isShort} />
<NavbarOperation currentType={currentType} isShort={isShort} />
Comment on lines 34 to +36
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

죄송합니다.. 제가 isShort라는 괴물을 키웠군요...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@loopy-lim ㅋㅋㅋㅋㅋㅋㅋ

</div>
<NavbarUserInfo />
</nav>
Expand Down
38 changes: 38 additions & 0 deletions frontend/components/common/navbar/NavbarManagePassState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use client";

import { useQuery } from "@tanstack/react-query";
import CommonNavbarCell from "./NavbarCell";
import { getMyInfo } from "@/src/apis/interview";
import { usePathname } from "next/navigation";

type NavbarManagePassStateProps = {
isShort: boolean;
currentType: string;
};
export const NavbarManagePassState = ({
currentType,
isShort,
}: NavbarManagePassStateProps) => {
const currentPath = usePathname();
const generation = currentPath.split("/")[2];
const { data: userData } = useQuery(["user"], getMyInfo);
if (!userData) {
return <div></div>;
}

if (userData.role !== "ROLE_OPERATION") {
return <div></div>;
}
2yunseong marked this conversation as resolved.
Show resolved Hide resolved

return (
<CommonNavbarCell
currentType={currentType}
isShort={isShort}
href={`/pass-state/${generation}`}
short_title="합/불 관리"
title="합/불 상태 관리"
target="_self"
type="pass-state"
/>
);
};
8 changes: 6 additions & 2 deletions frontend/components/common/navbar/NavbarOperation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import { usePathname } from "next/navigation";

type NavbarOperationProps = {
currentType: string;
isShort: boolean;
};
export const NavbarOperation = ({ currentType }: NavbarOperationProps) => {
export const NavbarOperation = ({
currentType,
isShort,
}: NavbarOperationProps) => {
const currentPath = usePathname();
const generation = currentPath.split("/")[2];
const { data: userData } = useQuery(["user"], getMyInfo);
Expand All @@ -23,7 +27,7 @@ export const NavbarOperation = ({ currentType }: NavbarOperationProps) => {
return (
<CommonNavbarCell
currentType={currentType}
isShort={false}
isShort={isShort}
href={`/admin/${generation}`}
short_title="관리자"
title="관리자 페이지"
Expand Down
151 changes: 151 additions & 0 deletions frontend/components/passState/ApplicantsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"use client";

import {
Answer,
useAllApplicantsWithPassState,
usePostApplicantPassState,
} from "@/src/apis/passState";
import { CURRENT_GENERATION } from "@/src/constants";
import { usePathname } from "next/navigation";
import Txt from "../common/Txt.component";
import { getApplicantPassState } from "@/src/functions/formatter";

function sortApplicantsByField1(applicants: Answer[]) {
const passStateOrder = {
"final-passed": 0,
"first-passed": 1,
"non-passed": 2,
"non-processed": 3,
};

const field1Order = {
WEB: 0,
APP: 1,
AI: 2,
GAME: 3,
};

return applicants.sort((a, b) => {
if (
passStateOrder[a.state.passState] !== passStateOrder[b.state.passState]
) {
return (
passStateOrder[a.state.passState] - passStateOrder[b.state.passState]
);
}
return field1Order[a.field1] - field1Order[b.field1];
});
}
Comment on lines +17 to +42
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나중에 시간이 되신다면 함수형으로 다시 작성해보는 것도 이쁘지 않을까 라는 생각이 듭니다. 특히 filter에 대한 좋은 방법론들이 많기 때문에 해보는 것을 추천드립니다.(먼가 힘들다 싶으면 backend친구들에게 요청해보세요. 그들은 filter전문가들이에요)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 해당 부분도 고려해보겠습니다!!


interface ApplicantsListProps {
sortedBy?: "position" | "field";
}
const ApplicantsList = ({ sortedBy }: ApplicantsListProps) => {
const selectedGeneration = usePathname().split("/")[2];

const {
data: allApplicants,
isLoading,
isError,
} = useAllApplicantsWithPassState({
generation: `${CURRENT_GENERATION}`,
});
const { mutate: updateApplicantPassState } = usePostApplicantPassState({
generation: `${CURRENT_GENERATION}`,
});

{
if (+selectedGeneration !== CURRENT_GENERATION) {
return <div>현재 지원중인 기수만 확인 가능합니다.</div>;
}

if (isLoading) {
return <div>Loading...</div>;
}

if (isError) {
return <div>Error</div>;
}

if (!allApplicants) {
return <div>아직은 지원자가 없습니다 🥲</div>;
}
}

const onChangeapplicantsPassState = (
applicantName: string,
params: {
applicantsId: string;
afterState: "pass" | "non-pass";
}
) => {
const ok = confirm(
`${applicantName}님을 ${params.afterState} 처리하시겠습니까?`
);
if (!ok) return;
updateApplicantPassState(params);
};

let { answers: applicants } = allApplicants;

if (sortedBy === "field") applicants = sortApplicantsByField1(applicants);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if를 사용하는 것 부터 시작해서, 함수 내부 구현 방식까지 너무 급하게 만들어진 함수, 기능이 아닌가 라는 생각이 드는 코딩이라서 잠시 심호흡을 하고 나서 구현해봐요!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 한번 이 부분도 수정해보겠습니다!


return (
<ul className="flex flex-col gap-4">
{applicants.map(
({ state: { passState }, field, field1, field2, id, name }) => (
<li
key={id}
className="grid grid-cols-[8fr_8fr_4fr_3fr] gap-4 items-center"
>
Comment on lines +107 to +110
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

먼가 마스터한 자의 css가 보이는 듯 하다....ㄷㄷㄷ

<Txt typography="h6" className="text-left truncate">
{`[${field}] ${name}`}
</Txt>
<Txt
className="text-left truncate"
color="gray"
>{`${field1}/${field2}`}</Txt>
<Txt
className="text-left truncate"
color={
getApplicantPassState(passState) === "최종 합격"
? "blue"
: getApplicantPassState(passState) === "탈락"
? "red"
: "gray"
2yunseong marked this conversation as resolved.
Show resolved Hide resolved
}
>
{getApplicantPassState(passState)}
2yunseong marked this conversation as resolved.
Show resolved Hide resolved
</Txt>
<div className="flex justify-between">
<button
className="border px-4 py-2 rounded-lg truncate hover:bg-primary-100"
onClick={() =>
onChangeapplicantsPassState(name, {
applicantsId: id,
afterState: "pass",
})
}
>
합격
</button>
<button
className="border px-4 rounded-lg truncate hover:bg-primary-100"
onClick={() =>
onChangeapplicantsPassState(name, {
applicantsId: id,
afterState: "non-pass",
})
}
>
불합격
</button>
</div>
</li>
)
)}
</ul>
);
};

export default ApplicantsList;
Loading