Skip to content

Commit

Permalink
Merge pull request #29 from Team-return/feature/Intern
Browse files Browse the repository at this point in the history
KANGYONGSU23 authored Nov 27, 2023
2 parents 74e0f9c + d74a5f5 commit 9a46df6
Showing 15 changed files with 196 additions and 125 deletions.
19 changes: 9 additions & 10 deletions src/apis/code/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CodeType } from "./type";
import { CodeType, GetCodeType } from "./type";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";

@@ -9,13 +9,12 @@ export const GetCode = (
keyword?: string,
parent_code?: number
) => {
return useQuery(
["GetCode", type, keyword, parent_code],
async () =>
await axios.get(
`${process.env.NEXT_PUBLIC_BASE_URL}${router}?type=${type}&keyword=${
keyword || ""
}&parent_code=${parent_code || ""}`
)
);
return useQuery(["GetCode", type, keyword, parent_code], async () => {
const { data } = await axios.get<GetCodeType>(
`${process.env.NEXT_PUBLIC_BASE_URL}${router}?type=${type}&keyword=${
keyword || ""
}&parent_code=${parent_code || ""}`
);
return data;
});
};
3 changes: 2 additions & 1 deletion src/apis/code/type.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
export interface GetCodeType {
codes: CodeType[];
codes: ResponesType[];
}

export interface ResponesType {
code: number;
keyword: string;
job_type: string;
}

export type CodeType = "JOB" | "TECH" | "BUSINESS_AREA";
8 changes: 5 additions & 3 deletions src/apis/recruitments/index.ts
Original file line number Diff line number Diff line change
@@ -13,10 +13,12 @@ export const GetRecruitmentsList = (queryString: string) => {
const { append } = useToastStore();
return useQuery(
["getRecruitmentsList", queryString],
async () =>
await instance.get<RecruitmentsListResponseType>(
async () => {
const { data } = await instance.get<RecruitmentsListResponseType>(
`${router}/student?${queryString}`
),
);
return data;
},
{
onError: () => {
append({
30 changes: 14 additions & 16 deletions src/app/companies/page.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
"use client";

import Pagination from "@/components/common/Pagination";
import TextFiled from "@/components/common/TextFiled";
import useForm from "@/hook/useForm";
import { useEffect, useState } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import CompanyCard from "@/components/company/CompanyCard";
import Pagination from "@/components/common/Pagination";
import useForm from "@/hook/useForm";
import { CompaniesQueryType } from "@/hook/useQueryString/type";
import { useQueryString } from "@/hook/useQueryString/useQueryString";

export default function CompanyListPage() {
const getParams = useSearchParams();
const [page, setPage] = useState(Number(getParams.get("page")));
const navigator = useRouter();
const pathname = usePathname();
const { getQueryString, setQueryString } = useQueryString<CompaniesQueryType>(
{
page: "1",
name: "",
}
);
const { state: searchState, onChange: onChangeSearch } = useForm<{
search: string | undefined;
}>({
search: getParams.get("name")?.toString(),
search: getQueryString("name"),
});

const onSearch = () => {
navigator.push(`${pathname}?page=${page}&name=${searchState.search}`);
};

useEffect(onSearch, [page]);

return (
<div className="w-full my-[68px]">
<div className="flex items-center justify-between w-full py-5">
@@ -37,7 +33,9 @@ export default function CompanyListPage() {
onChange={onChangeSearch}
name="search"
customType="Search"
enterEvent={onSearch}
enterEvent={() => {
setQueryString({ name: searchState.search });
}}
/>
</div>
<CompanyCard />
25 changes: 11 additions & 14 deletions src/components/common/DropDown.tsx
Original file line number Diff line number Diff line change
@@ -4,22 +4,19 @@ import { useDropDown } from "@/hook/useDropDown";
import { Icon } from "@team-return/design-system";
import React from "react";

type DropDownItemsType = {
code: number;
keyword: string;
};
interface DropdownItemsType {
code: string;
label: string;
}

interface PropsType {
title: string;
items?: DropDownItemsType[];
onItemClick: (
itemCode: string | number,
name: "job_code" | "tech_code"
) => void;
items: DropdownItemsType[];
onClickItem: (itemId: string) => void;
selected: number | string;
}

function DropDown({ title, items, onItemClick, selected }: PropsType) {
function DropDown({ title, items, onClickItem, selected }: PropsType) {
const { toggleDropdown, DropDownComponent, closeDropDown } = useDropDown();

return (
@@ -31,11 +28,11 @@ function DropDown({ title, items, onItemClick, selected }: PropsType) {
<Icon icon="Chevron" color="gray60" />
<DropDownComponent className="absolute left-0 min-w-full top-11">
<div className="min-w-full max-h-40 py-2 px-2 bg-white shadow-elevaiton rounded-[8px] overflow-scroll">
{items?.map((item, index) => (
{items?.map((item, idx) => (
<div
key={index}
key={idx}
onClick={() => {
onItemClick(item.code, "job_code");
onClickItem(item.code.toString());
closeDropDown();
}}
className={`text-caption leading-caption ${
@@ -44,7 +41,7 @@ function DropDown({ title, items, onItemClick, selected }: PropsType) {
: "text-[#7f7f7f] font-r"
} hover:text-black py-2 w-full flex flex-col items-center`}
>
{item.keyword}
{item.label}
</div>
))}
</div>
7 changes: 7 additions & 0 deletions src/components/common/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Dropdown() {
return (
<>
<></>
</>
);
}
4 changes: 2 additions & 2 deletions src/components/common/Header.tsx
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ function Header() {
className={`text-[#333333] text-b2 ${
pathname.indexOf("/companies") !== -1 && "font-b"
}`}
href={"/companies?page=1&name="}
href={"/companies?page=1"}
prefetch
>
기업체
@@ -37,7 +37,7 @@ function Header() {
className={`text-[#333333] text-b2 ${
pathname.indexOf("/recruitments") !== -1 && "font-b"
}`}
href={"/recruitments?page=1&job_code=&tech_code=&name="}
href={"/recruitments?page=1"}
>
모집의뢰서
</Link>
40 changes: 28 additions & 12 deletions src/components/common/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -2,28 +2,40 @@

import { GetNumberOfCompaniesListPages } from "@/apis/companies";
import { GetNumberOfRecruitmentRequestListPages } from "@/apis/recruitments";
import { useQueryString } from "@/hook/useQueryString";
import { RecruitmentsQueryType } from "@/hook/useQueryString/type";
import { useQueryString } from "@/hook/useQueryString/useQueryString";
import { Icon, theme } from "@team-return/design-system";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";

export default function Pagination() {
const pathname = usePathname();

const { setQueryString, getQueryString, getQueryStringEntry } = useQueryString({
page: "1",
job_code: "",
tech_code: "",
name: "",
});
const { setQueryString, getQueryString, getQueryStringEntry } =
useQueryString<RecruitmentsQueryType>({
page: "1",
job_code: "",
tech_code: "",
name: "",
winter_intern: "",
});
const currentPageNumber = getQueryString("page");

const recruitmentQuery = [
getQueryStringEntry("job_code"),
getQueryStringEntry("tech_code"),
getQueryStringEntry("name"),
getQueryStringEntry("winter_intern"),
]
.filter((item) => item)
.join("&");

const numberOfPages =
pathname === "/recruitments/"
? GetNumberOfRecruitmentRequestListPages(
`${getQueryStringEntry("job_code")}&${getQueryStringEntry("tech_code")}&${getQueryStringEntry("name")}`
)?.data
: GetNumberOfCompaniesListPages(`${getQueryStringEntry("name")}`)?.data;
? GetNumberOfRecruitmentRequestListPages(recruitmentQuery)?.data
: GetNumberOfCompaniesListPages(
`${getQueryStringEntry("name") ? getQueryStringEntry("name") : ""}`
)?.data;
const [pagesArray, setPagesArray] = useState<number[]>([]);

useEffect(() => {
@@ -73,7 +85,11 @@ export default function Pagination() {
icon="Chevron"
direction="right"
size={16}
color={getQueryString("page") === String(pagesArray.length) ? "gray50" : "gray90"}
color={
getQueryString("page") === String(pagesArray.length)
? "gray50"
: "gray90"
}
/>
</div>
</div>
43 changes: 24 additions & 19 deletions src/components/common/SearchDropDown.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
"use client";

import React, { useEffect, useState } from "react";
import { GetCode } from "@/apis/code";
import { useDropDown } from "@/hook/useDropDown";
import { Icon } from "@team-return/design-system";
import TextFiled from "./TextFiled";
import useForm from "@/hook/useForm";
import Chips from "./Chips";
import { GetCode } from "@/apis/code";
import {
RecruitmentsQueryType
} from "@/hook/useQueryString/type";
import { useQueryString } from "@/hook/useQueryString/useQueryString";
import { TechCodeResponensType } from "@/util/type";
import { Icon } from "@team-return/design-system";
import React, { useEffect, useState } from "react";
import GhostBtn from "./Button/GhostBtn";
import { setQueryStringType, useQueryString } from "@/hook/useQueryString";
import Chips from "./Chips";
import TextFiled from "./TextFiled";

interface PropsType {
title: string;
@@ -18,12 +21,14 @@ interface PropsType {
function SearchDropDown({ title }: PropsType) {
const { DropDownComponent, toggleDropdown, closeDropDown } = useDropDown();

const { setQueryString, getQueryString } = useQueryString({
page: "1",
job_code: "",
tech_code: "",
name: "",
});
const { setQueryString, getQueryString } =
useQueryString<RecruitmentsQueryType>({
page: "1",
job_code: "",
tech_code: "",
name: "",
winter_intern: "",
});

return (
<div
@@ -46,11 +51,11 @@ function SearchDropDown({ title }: PropsType) {
function TechCodeDropDownComponent({
closeDropDown,
setQueryString,
getQueryString
getQueryString,
}: {
closeDropDown: () => void;
setQueryString: (newValue: setQueryStringType) => void;
getQueryString: (key: keyof setQueryStringType) => string;
setQueryString: (newValue: Partial<RecruitmentsQueryType>) => void;
getQueryString: (key: string) => string;
}) {
const [select, setSelect] = useState<TechCodeResponensType[]>([]);
const [searchKeyword, setSearch] = useState<string>("");
@@ -60,20 +65,20 @@ function TechCodeDropDownComponent({
techCodeSearch: "",
});

const { data } = GetCode("TECH", searchKeyword);
const { data:codes } = GetCode("TECH", searchKeyword);

useEffect(() => {
const techArray = getQueryString("tech_code")
.split(",")
.map((item) => Number(item));
setSelect(() => {
return (
data?.data.codes.filter((item: TechCodeResponensType) =>
codes?.codes.filter((item: TechCodeResponensType) =>
techArray?.some((techItem) => item.code === techItem)
) || []
);
});
}, [getQueryString("tech_code"), data?.data.codes]);
}, [getQueryString("tech_code"), codes?.codes]);

return (
<div
@@ -96,7 +101,7 @@ function TechCodeDropDownComponent({
</div>
<div className="flex-1 overflow-hidden">
<Chips
value={data?.data.codes || []}
value={codes?.codes || []}
select={select}
setSelect={setSelect}
/>
16 changes: 4 additions & 12 deletions src/components/recruitments/RecruitmentsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
"use client";

import { Icon } from "@team-return/design-system";
import { SetBookmarks } from "@/apis/bookmarks";
import { GetRecruitmentsList } from "@/apis/recruitments";
import { Icon } from "@team-return/design-system";
import Image from "next/image";
import React, { useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";
import { RecruitmentsListType } from "@/apis/recruitments/type";
import { GetRecruitmentsList } from "@/apis/recruitments";
import React from "react";
import HoverPrefetchLink from "../common/HoverPrefetchLink";
import RecruitmentSkelton from "../common/Skelton/SkeltonElement";

export default function RecruitmentsCard() {
const getParams = useSearchParams();
const [list, setList] = useState<RecruitmentsListType[]>([]);

const { data: recruitmentsList, isLoading } = GetRecruitmentsList(getParams.toString());
useEffect(() => {
setList((prev) => recruitmentsList?.data.recruitments || prev);
}, [recruitmentsList]);

const { mutate: SetBookmarksMutate } = SetBookmarks();

const tagStyle =
"text-caption leading-caption text-lightBlue font-r border rounded-full border-[#135C9D] py-1 px-2";

return (
<div className="w-full mt-5 grid grid-cols-3 md:grid-cols-4 gap-[1.5vw]">
{isLoading && <RecruitmentSkelton />}
{list.map(
{recruitmentsList?.recruitments.map(
(
{
company_profile_url,
54 changes: 37 additions & 17 deletions src/components/recruitments/filter.tsx
Original file line number Diff line number Diff line change
@@ -2,24 +2,29 @@

import { GetCode } from "@/apis/code";
import useForm from "@/hook/useForm";
import { useQueryString } from "@/hook/useQueryString";
import { RecruitmentsQueryType } from "@/hook/useQueryString/type";
import { useQueryString } from "@/hook/useQueryString/useQueryString";
import { internDropdownItems } from "@/util/object/jobCodeDorpdownItems";
import React, { useEffect, useState } from "react";
import DropDown from "../common/DropDown";
import SearchDropDown from "../common/SearchDropDown";
import TextFiled from "../common/TextFiled";

function Filter() {
const { setQueryString, getQueryString } = useQueryString({
page: "1",
job_code: "",
tech_code: "",
name: "",
});
const { setQueryString, getQueryString } =
useQueryString<RecruitmentsQueryType>({
page: "1",
job_code: "",
tech_code: "",
name: "",
winter_intern: "",
});

const [filter, setFilter] = useState({
page: getQueryString("page"),
job_code: getQueryString("job_code"),
tech_code: getQueryString("tech_code"),
winter_intern: getQueryString("winter_intern"),
});
const { state: searchState, onChange: onChangeSearch } = useForm<{
search: string | undefined;
@@ -33,28 +38,44 @@ function Filter() {
job_code: filter.job_code,
tech_code: filter.tech_code,
name: searchState.search,
winter_intern: filter.winter_intern,
});
};

useEffect(onSearch, [filter]);

const onItemClick = (
itemCode: string | number,
name: "job_code" | "tech_code"
jobType: "job_code" | "winter_intern",
itemCode: string
) => {
if (filter[name] === itemCode) {
setFilter((prev) => ({ ...prev, [name]: "" }));
} else setFilter((prev) => ({ ...prev, [name]: itemCode }));
if (filter[jobType] === itemCode) {
setFilter((prev) => ({ ...prev, [jobType]: "" }));
} else setFilter((prev) => ({ ...prev, [jobType]: itemCode }));
};

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

const jobCodeDropdownItems = codes?.codes.map((item) => ({
code: item.code.toString(),
label: item.keyword,
}));

return (
<div className="flex gap-4">
<DropDown
title="모집구분"
items={internDropdownItems}
onClickItem={(itemCode: string) => {
onItemClick("winter_intern", itemCode);
}}
selected={getQueryString("winter_intern") || ""}
/>
<DropDown
title="분야"
items={data?.data.codes}
onItemClick={onItemClick}
items={jobCodeDropdownItems ?? [{ code: "1", label: "" }]}
onClickItem={(itemCode: string) => {
onItemClick("job_code", itemCode);
}}
selected={getQueryString("job_code") || ""}
/>
<SearchDropDown title="기술스택" />
@@ -65,9 +86,8 @@ function Filter() {
name="search"
customType="Search"
enterEvent={onSearch}
width="26vw"
width="20vw"
/>

</div>
);
}
16 changes: 16 additions & 0 deletions src/hook/useQueryString/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export interface QueryStringType {
[key: string]: string;
}

export interface RecruitmentsQueryType extends QueryStringType {
page: string;
job_code: string;
tech_code: string;
name: string;
winter_intern: string;
}

export interface CompaniesQueryType extends QueryStringType {
page: string;
name: string;
}
Original file line number Diff line number Diff line change
@@ -2,19 +2,9 @@

import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import { QueryStringType } from "./type";

interface QueryStringType {
[key: string]: string;
}

export interface setQueryStringType {
page?: string;
job_code?: string;
tech_code?: string;
name?: string;
}

export const useQueryString = (initialState: QueryStringType) => {
export const useQueryString = <T extends QueryStringType>(initialState: T) => {
const pathname = usePathname();
const router = useRouter();
const params = useSearchParams();
@@ -26,13 +16,14 @@ export const useQueryString = (initialState: QueryStringType) => {
}, {} as QueryStringType)
);

const setQueryString = (newValue: setQueryStringType) => {
const setQueryString = (newValue: Partial<T>) => {
setValue((prev) => ({ ...prev, ...newValue }));
};

const refresh = () => {
const queryString = Object.entries(value)
.map(([key, val]) => `${key}=${val}`)
.map(([key, val]) => val && `${key}=${val}`)
.filter((item) => item)
.join("&");
router.push(`${pathname}?${queryString}`);
};
@@ -43,13 +34,16 @@ export const useQueryString = (initialState: QueryStringType) => {
.join("&");
};

const getQueryString = (key: keyof setQueryStringType) => {
const getQueryString = (key: string) => {
return value[key];
};
const getQueryStringEntry = (key: keyof setQueryStringType) => {
return `${Object.keys(value).find((objectKey) => objectKey === key)}=${
value[key]
}`;
const getQueryStringEntry = (key: string) => {
return (
value[key] &&
`${Object.keys(value).find((objectKey) => objectKey === key)}=${
value[key]
}`
);
};

const resetQueryString = () => {
23 changes: 23 additions & 0 deletions src/util/object/jobCodeDorpdownItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { GetCode } from "@/apis/code";

interface PropsType {
setFilter: React.Dispatch<
React.SetStateAction<{
page: string;
job_code: string;
tech_code: string;
winter_intern: string;
}>
>;
}

export const internDropdownItems = [
{
code: "true",
label: "채험형",
},
{
code: "false",
label: "채용형",
},
];
1 change: 1 addition & 0 deletions src/util/type.ts
Original file line number Diff line number Diff line change
@@ -3,3 +3,4 @@ export interface TechCodeResponensType {
keyword: string;
job_type: string | null;
}

0 comments on commit 9a46df6

Please sign in to comment.