Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type ExperienceType = ExperienceTypeCode;
export interface ExperienceUpsertBody {
title: string;

type: ExperienceType | null;
type: string | null;

startAt: string | null;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { EXPERIENCE_TYPE } from "@/shared/config/experience";
import {
EXPERIENCE_TYPE,
type ExperienceTypeCode,
} from "@/shared/config/experience";
import { parseYMD } from "@/shared/lib/format-date";
import { ModalBasic, Tooltip } from "@/shared/ui";
import { Button } from "@/shared/ui/button/button";
Expand Down Expand Up @@ -40,7 +43,10 @@ const ExperienceViewer = () => {
);
}

const typeLabel = current.type ? EXPERIENCE_TYPE[current.type] : "미지정";
const typeLabel =
current.type && current.type in EXPERIENCE_TYPE
? EXPERIENCE_TYPE[current.type as ExperienceTypeCode]
: "미지정";

return (
<main className={s.page}>
Expand Down
5 changes: 2 additions & 3 deletions src/features/experience/api/use-experience-list.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { api } from "@/shared/api/axios-instance";
import { experienceQueryKey } from "@/shared/api/config/query-key";

import type { ExperienceList } from "../type/experience";
import type { ExperienceTypeCode } from "@/shared/config";

export const getExperienceList = async ({
type,
page,
}: {
type?: ExperienceTypeCode | undefined;
type?: string;
page: number;
}) => {
const response = await api.experiences.getSummaryExperienceList({
Expand All @@ -24,7 +23,7 @@ export const useGetExperienceList = ({
type,
page,
}: {
type: ExperienceTypeCode | null;
type?: string | null;
page: number;
}) => {
return useQuery({
Expand Down
33 changes: 21 additions & 12 deletions src/pages/experience/experience-page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useSearchParams, useNavigate } from "react-router-dom";

import { ROUTES } from "@/app/routes/paths";
import { useGetExperienceList } from "@/features/experience/api/use-experience-list.query";
Expand All @@ -9,24 +9,33 @@ import { ExperienceFilter } from "@/widgets";
import * as styles from "./experience-page.css";
import { ExperienceListContainer } from "./ui/experience-list-container";

import type { ExperienceTypeCode } from "@/shared/config/experience";

const ExperiencePage = () => {
const [filter, setFilter] = useState<ExperienceTypeCode | null>(null);
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();

const currentPage = Number(searchParams.get("page")) || 1;
const type = searchParams.get("type") || "";

const [isExpTouched, setIsExpTouched] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const navigate = useNavigate();

const { data } = useGetExperienceList({
type: filter,
type,
page: currentPage,
});

const handleFilterChange = (value: ExperienceTypeCode | null) => {
const handleFilterChange = (value: string) => {
setIsExpTouched(true);
setFilter(value);
setCurrentPage(1);
setSearchParams({
type: value,
page: "1",
});
};

const handlePageChange = (page: number) => {
setSearchParams({
type: type ?? "",
page: String(page),
});
};

return (
Expand All @@ -53,15 +62,15 @@ const ExperiencePage = () => {
</button>

<ExperienceFilter
value={filter}
value={type}
onChange={handleFilterChange}
isTouched={isExpTouched}
hasTotal={true}
/>
</div>
</section>

<ExperienceListContainer data={data} onPageChange={setCurrentPage} />
<ExperienceListContainer data={data} onPageChange={handlePageChange} />
</div>
);
};
Expand Down
91 changes: 58 additions & 33 deletions src/pages/home/search-section/search-section.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import { useSearchParams } from "react-router-dom";

import { useGetCompanies } from "@/features/home";
import { ScaleFilter, IndustryFilter } from "@/features/home/ui";
Expand All @@ -11,42 +12,66 @@ import * as styles from "./search-section.css";

import type { IndustryCode, ScaleCode } from "@/shared/config";

interface CompanySearchParamsType {
keyword?: string;
industry?: IndustryCode;
scale?: ScaleCode;
sort?: string;
page?: number;
isRecruited?: boolean;
}

const SearchSection = () => {
const [params, setParams] = useState<CompanySearchParamsType>({
page: 1,
isRecruited: true,
});
const [searchParams, setSearchParams] = useSearchParams();

const keyword = searchParams.get("keyword") || "";
const industry = (searchParams.get("industry") as IndustryCode) || undefined;
const scale = (searchParams.get("scale") as ScaleCode) || undefined;
const page = Number(searchParams.get("page")) || 1;
const isRecruited = searchParams.get("isRecruited") !== "false";

const params = {
keyword,
industry,
scale,
page,
isRecruited,
};

const { data, isLoading, isPlaceholderData } = useGetCompanies(params);
const content = data?.content || [];
const hasResult = content.length > 0;
const [searchValue, setSearchValue] = useState("");
const currentPage = params.page ?? 1;

const [searchValue, setSearchValue] = useState(keyword);

const [isScaleTouched, setIsScaleTouched] = useState(false);
const [isIndustryTouched, setIsIndustryTouched] = useState(false);

const updateParams = (patch: Partial<CompanySearchParamsType>) => {
setParams((prev) => ({
...prev,
...patch,
}));
const updateSearchParams = (
patch: Record<string, string | number | boolean | undefined>
) => {
const newParams = new URLSearchParams(searchParams);

Object.entries(patch).forEach(([key, value]) => {
if (value === undefined || value === "") {
newParams.delete(key);
} else {
newParams.set(key, String(value));
}
});

if (!patch.page) {
newParams.set("page", "1");
}

setSearchParams(newParams);
};

const handlePageChange = (newPage: number) => {
if (isPlaceholderData) return;
updateParams({ page: newPage });
updateSearchParams({ page: newPage });
};

const handleSearch = (newKeyword: string) => {
updateSearchParams({ keyword: newKeyword });
};

// 검색값 유지
useEffect(() => {
setSearchValue(keyword);
}, [keyword]);

return (
<>
<section
Expand All @@ -68,7 +93,7 @@ const SearchSection = () => {
placeholder="지원하고 싶은 기업을 검색해보세요"
value={searchValue}
onChange={setSearchValue}
onSearch={(keyword) => updateParams({ keyword, page: 1 })}
onSearch={handleSearch}
/>
</div>
</div>
Expand All @@ -78,20 +103,20 @@ const SearchSection = () => {
<div className={styles.container}>
<div className={styles.filterWrapper}>
<IndustryFilter
value={params.industry ?? null}
value={industry ?? null}
isTouched={isIndustryTouched}
onChange={(industry) => {
onChange={(newIndustry) => {
setIsIndustryTouched(true);
updateParams({ industry, page: 1 });
updateSearchParams({ industry: newIndustry });
}}
/>

<ScaleFilter
value={params.scale}
value={scale}
isTouched={isScaleTouched}
onChange={(scale) => {
onChange={(newScale) => {
setIsScaleTouched(true);
updateParams({ scale, page: 1 });
updateSearchParams({ scale: newScale });
}}
/>

Expand All @@ -100,9 +125,9 @@ const SearchSection = () => {
</p>

<Toggle
checked={params.isRecruited ?? true}
onCheckedChange={(isRecruited) =>
updateParams({ isRecruited, page: 1 })
checked={isRecruited}
onCheckedChange={(checked) =>
updateSearchParams({ isRecruited: checked })
}
/>
</div>
Expand All @@ -122,7 +147,7 @@ const SearchSection = () => {
))}
</div>
<Pagination
currentPage={currentPage}
currentPage={page}
totalPage={data?.totalPage ?? 1}
onPageChange={handlePageChange}
/>
Expand Down
45 changes: 26 additions & 19 deletions src/pages/matching-list/matching-list-page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import { useSearchParams } from "react-router-dom";

import { useGetAiReportList } from "@/features/matching-list/api/use-get-matching-list";
import { ICON_MATCH, ERROR } from "@/shared/assets/images";
Expand All @@ -7,39 +8,45 @@ import { Search } from "@/shared/ui";
import { ListSection } from "./list-section/list-section";
import * as styles from "./matching-list-page.css";

interface MatchingListParams {
keyword?: string;
page: number;
}
const MatchingListPage = () => {
const [params, setParams] = useState<MatchingListParams>({
keyword: "",
page: 1,
});
const [searchParams, setSearchParams] = useSearchParams();
const currentPage = Number(searchParams.get("page")) || 1;
const keyword = searchParams.get("keyword") || "";

const { data, isLoading } = useGetAiReportList(params);
const { content = [], currentPage = 1, totalPage = 1 } = data ?? {};
const { data, isLoading } = useGetAiReportList({
page: currentPage,
keyword,
});
const { content = [], totalPage = 1 } = data ?? {};

const showEmptyState = !isLoading && content.length === 0;
const showList = content.length > 0;

const [searchValue, setSearchValue] = useState("");
const [searchValue, setSearchValue] = useState(keyword);

const handleSearch = (keyword: string) => {
setParams({ keyword, page: 1 });
const handleSearch = (newKeyword: string) => {
setSearchParams({
keyword: newKeyword,
page: "1",
});
};

const handlePageChange = (page: number) => {
setParams((prev) => ({
...prev,
page,
}));
setSearchParams({
keyword,
page: String(page),
});
};

const handleSearchChange = (keyword: string) => {
setSearchValue(keyword);
};

// 검색값 유지
useEffect(() => {
setSearchValue(keyword);
}, [keyword]);

return (
<main className={styles.container}>
{/* header 섹션 */}
Expand Down Expand Up @@ -84,7 +91,7 @@ const MatchingListPage = () => {
/>
<p className={styles.emptyTitle}>"검색 결과가 없습니다"</p>
<p className={styles.emptyDescription}>
{params.keyword
{keyword
? "다른 검색어로 다시 시도해보세요."
: "경험 등록하기 버튼을 눌러 경험을 등록해보세요."}
</p>
Expand Down
4 changes: 2 additions & 2 deletions src/shared/api/generate/http-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export interface ExperienceRequestDto {
*/
title: string;
/** @example "INTERNSHIP" */
type: "INTERNSHIP" | "PROJECT" | "EDUCATION" | "ETC";
type: string;
/**
* @format date
* @example "2025-12-23"
Expand Down Expand Up @@ -812,7 +812,7 @@ export class Api<
*/
getSummaryExperienceList: (
query?: {
type?: "INTERNSHIP" | "PROJECT" | "EDUCATION" | "ETC";
type?: string;
/**
* @format int32
* @default 1
Expand Down
Loading
Loading