Skip to content

Commit

Permalink
feat: 면접기록/지원현황 페이지 검색 기능 (#240)
Browse files Browse the repository at this point in the history
  • Loading branch information
2yunseong authored Mar 1, 2025
2 parents 96b436f + d33a357 commit a8d14cc
Show file tree
Hide file tree
Showing 21 changed files with 330 additions and 357 deletions.
6 changes: 2 additions & 4 deletions frontend/app/(WithNavbar)/applicant/[generation]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import ApplicantBoard from "@/components/applicant/Board";
import ApplicantPageNavbar from "@/components/applicant/PageNavbar";
import SortList from "@/components/common/SortList";
import Search from "@/components/common/Search";
import { ORDER_MENU } from "@/src/constants";
import ApplicantList from "@/components/applicant/ApplicantList";

interface ApplicantPageProps {
params: {
Expand All @@ -19,8 +18,7 @@ const ApplicantPage = ({ params }: ApplicantPageProps) => {
<Search />
<SortList sortList={ORDER_MENU.APPLICANT} />
</div>
<ApplicantBoard generation={generation} />
<ApplicantPageNavbar generation={generation} />
<ApplicantList generation={generation} />
</div>
);
};
Expand Down
6 changes: 2 additions & 4 deletions frontend/app/(WithNavbar)/interview/[generation]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import SortList from "@/components/common/SortList";
import InterviewBoard from "@/components/interview/Board";
import InterviewPageNavbar from "@/components/interview/PageNavbar";
import Search from "@/components/common/Search";
import { ORDER_MENU } from "@/src/constants";
import InterviewerList from "@/components/interview/InterviewerList";

interface InterviewPageProps {
params: {
Expand All @@ -17,8 +16,7 @@ const InterviewPage = ({ params: { generation } }: InterviewPageProps) => {
<Search />
<SortList sortList={ORDER_MENU.INTERVIEW} />
</div>
<InterviewBoard generation={generation} />
<InterviewPageNavbar generation={generation} />
<InterviewerList generation={generation} />
</div>
);
};
Expand Down
51 changes: 51 additions & 0 deletions frontend/components/applicant/ApplicantList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client";

import { useQuery } from "@tanstack/react-query";
import useApplicantPaginationParams from "../../src/hooks/applicant/useApplicantPaginationParams";
import { getApplicantByPageWithGeneration } from "../../src/apis/applicant";
import LoadingSpinner from "../common/LoadingSpinner";
import ApplicantBoard from "./Board";
import ApplicantPageNavbar from "./PageNavbar";

interface ApplicantListProps {
generation: string;
}

const ApplicantList = ({ generation }: ApplicantListProps) => {
const { pageIndex, order, searchKeyword } = useApplicantPaginationParams();
const { data: applicants, status } = useQuery(
["allApplicant", { generation, order, pageIndex, searchKeyword }],
() =>
getApplicantByPageWithGeneration(
+pageIndex,
generation,
order,
searchKeyword
),
{
enabled: !!generation,
}
);

if (status === "loading") {
return <LoadingSpinner size="s" />;
}
if (status === "error") {
return <div>에러 발생</div>;
}

return (
<>
<ApplicantBoard
generation={generation}
applicants={applicants.applicants}
/>
<ApplicantPageNavbar
generation={generation}
maxPage={applicants.maxPage}
/>
</>
);
};

export default ApplicantList;
95 changes: 37 additions & 58 deletions frontend/components/applicant/Board.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,26 @@
"use client";

import Board from "@/components/common/board/Board";
import { getApplicantByPageWithGeneration } from "@/src/apis/applicant";
import ApplicantDetailRight from "./DetailRight.component";
import { useState } from "react";
import { ApplicantReq } from "@/src/apis/application";
import { applicantDataFinder } from "@/src/functions/finder";
import { useQuery } from "@tanstack/react-query";
import { useSearchParams } from "next/navigation";
import { ORDER_MENU } from "@/src/constants";
import { useSearchQuery } from "@/src/hooks/useSearchQuery";
import { type ApplicantPassState } from "../../src/apis/kanban";
import ApplicantDetailLeft from "./_applicant/ApplicantDetailLeft";
import { findApplicantState } from "@/src/utils/applicant";
import BoardTable from "../common/board/BoardTable";
import useModalState from "../../src/hooks/useModalState";
import BoardModal from "../common/board/BoardModal";

interface ApplicantBoardProps {
generation: string;
applicants: ApplicantReq[][];
}

const ApplicantBoard = ({ generation }: ApplicantBoardProps) => {
const [data, setData] = useState<ApplicantReq[]>([]);
const searchParams = useSearchParams();
const pageIndex = searchParams.get("page") || "1";
const order = searchParams.get("order") || ORDER_MENU.APPLICANT[0].type;
const { createSearchData } = useSearchQuery(pageIndex);

const onClick = (id: string) => {
if (!allData) return;
setData(
applicants?.filter((value) => applicantDataFinder(value, "id") === id)[0]
);
};

const {
data: allData,
isLoading,
isError,
} = useQuery(
["allApplicant", pageIndex, order],
() => getApplicantByPageWithGeneration(+pageIndex, generation, order),
{
enabled: !!generation,
}
const ApplicantBoard = ({ generation, applicants }: ApplicantBoardProps) => {
const [selectedApplicant, setSelectedApplicant] = useState<ApplicantReq[]>(
[]
);

if (!allData || isLoading) {
return <div>로딩중...</div>;
}

if (isError) {
return <div>에러 발생</div>;
}

const { applicants } = allData;
const { isOpen, openModal, closeModal } = useModalState();

const boardData = applicants.map((value) => ({
id: applicantDataFinder(value, "id"),
Expand Down Expand Up @@ -81,27 +49,38 @@ const ApplicantBoard = ({ generation }: ApplicantBoardProps) => {
)}` as ApplicantPassState,
}));

const handleModalOpen = (id: string) => () => {
openModal();
setSelectedApplicant(
applicants.filter((value) => applicantDataFinder(value, "id") === id)[0]
);
};

return (
<Board
wrapperClassName="divide-x"
boardData={createSearchData(true) ?? boardData}
onClick={onClick}
>
<div className="flex flex-1">
<div className="flex-1 overflow-auto px-12 min-w-[40rem]">
<ApplicantDetailLeft
cardId={-1}
data={data}
generation={generation}
/>
<>
<BoardTable boardRows={boardData} handleModalOpen={handleModalOpen} />
<BoardModal
isOpen={isOpen}
onRequestClose={closeModal}
ariaHideApp={false}
wrapperClassName="divide-x"
>
<div className="flex flex-1">
<div className="flex-1 overflow-auto px-12 min-w-[40rem]">
<ApplicantDetailLeft
cardId={-1}
data={selectedApplicant}
generation={generation}
/>
</div>
</div>
</div>
<div className="flex flex-1 min-h-0">
<div className="flex-1 overflow-auto px-12">
<ApplicantDetailRight data={data} />
<div className="flex flex-1 min-h-0">
<div className="flex-1 overflow-auto px-12">
<ApplicantDetailRight data={selectedApplicant} />
</div>
</div>
</div>
</Board>
</BoardModal>
</>
);
};

Expand Down
49 changes: 12 additions & 37 deletions frontend/components/applicant/PageNavbar.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,29 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import PageNavbarComponent from "../common/PageNavbar.component";
import { useSearchParams } from "next/navigation";
import { getApplicantByPageWithGeneration } from "@/src/apis/applicant";
import { ORDER_MENU } from "@/src/constants";
import { useSearchQuery } from "@/src/hooks/useSearchQuery";
import { useCreateQueryString } from "@/src/hooks/useCreateQueryString";
import useApplicantPaginationParams from "../../src/hooks/applicant/useApplicantPaginationParams";

type ApplicantPageNavbarProps = {
generation: string;
maxPage: number;
};

const ApplicantPageNavbar = ({ generation }: ApplicantPageNavbarProps) => {
const searchParams = useSearchParams();
const pageIndex = searchParams.get("page") || "1";
const type = searchParams.get("type") ?? "list";
const order = searchParams.get("order") ?? ORDER_MENU.APPLICANT[0].type;
const page = searchParams.get("page") ?? "1";
const search = searchParams.get("search") || "";
const ApplicantPageNavbar = ({
generation,
maxPage,
}: ApplicantPageNavbarProps) => {
const { pageIndex, type, order, searchKeyword } =
useApplicantPaginationParams();

const { searchEndPage } = useSearchQuery(pageIndex);
const queryParams = { search: searchKeyword, type, order };

const queryParams = { search, type, order };
const { createQueryString } = useCreateQueryString();

const {
data: allData,
isLoading,
isError,
} = useQuery(
["allApplicant", generation],
() => getApplicantByPageWithGeneration(+pageIndex, generation, order),
{
enabled: !!generation,
}
);

if (!allData || isLoading) {
return <div>로딩중...</div>;
}

if (isError) {
return <div>에러 발생</div>;
}

const { maxPage } = allData;
// Search 넣어야 함!!!
return (
<PageNavbarComponent
maxLength={searchEndPage ?? maxPage}
page={+page}
maxLength={maxPage}
page={+pageIndex}
url={`/applicant/${generation}?${createQueryString(
Object.keys(queryParams),
Object.values(queryParams)
Expand Down
50 changes: 50 additions & 0 deletions frontend/components/common/LoadingSpinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { cn } from "../../src/utils/cn";

interface LoadingSpinnerProps {
size?: "s" | "m" | "l" | "xl";
}

const getSize = (size: "s" | "m" | "l" | "xl") => {
switch (size) {
case "s":
return cn("w-6", "h-6");
case "m":
return cn("w-12", "h-12");
case "l":
return cn("w-18", "h-18");
case "xl":
return cn("w-24 h-24");
default:
throw new Error(
"Error: Loading Spinner의 `size` Props는 s, m, l, xl 중 하나 입니다."
);
}
};

const LoadingSpinner = ({ size = "s" }: LoadingSpinnerProps) => {
return (
<div className={getSize(size)}>
<svg
className="mr-3 -ml-1 size-5 animate-spin text-black"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
</div>
);
};

export default LoadingSpinner;
2 changes: 1 addition & 1 deletion frontend/components/common/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const Search = () => {
params.delete("search");
}

replace(`${pathname}?${params.toString()}`);
replace(`${pathname}?${params}`);
});
}, [debouncedSearchTerm, pathname]);

Expand Down
51 changes: 0 additions & 51 deletions frontend/components/common/board/Board.tsx

This file was deleted.

Loading

0 comments on commit a8d14cc

Please sign in to comment.