Skip to content
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
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState } from 'react'
import { CaretDownIcon } from '@/designs/assets'
import { Button, PlainCombobox } from '@/designs/components'
import { QnaCard } from '@/features/dashboard/my-interviews/components/questions'
import QnaCard from '@/features/dashboard/my-interviews/components/questions/list/qna-card/QnaCard'
import type { InterviewResultStatus } from '@/features/dashboard/my-interviews/constants/constants'
import type { InterviewType } from '@/types/interview'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState } from 'react'
import { CaretDownIcon, FilterIcon } from '@/designs/assets'
import { Button, PlainCombobox } from '@/designs/components'
import type { LabelValueType } from '@/types/global'
import { INTERVIEW_SORT_OPTIONS } from '@/features/dashboard/my-interviews/constants/constants'
import type { InterviewFilter } from '@/types/interview'
import InterviewFilterModal from './InterviewFilterModal'

Expand All @@ -24,12 +24,12 @@ export default function FilterSortControls({ filter, onFilterChange }: FilterSor
</Button>
<PlainCombobox
title="면접 정렬"
options={SORT_OPTIONS}
options={[...INTERVIEW_SORT_OPTIONS]}
value={filter.sort}
onChange={(sort) => onFilterChange({ ...filter, sort })}
trigger={
<Button size="xs" variant="fill-gray-150">
{SORT_OPTIONS.find((o) => o.value === filter.sort)?.label}
{INTERVIEW_SORT_OPTIONS.find((o) => o.value === filter.sort)?.label}
<CaretDownIcon className="h-2 w-2" />
</Button>
}
Expand All @@ -44,10 +44,3 @@ export default function FilterSortControls({ filter, onFilterChange }: FilterSor
</div>
)
}

const SORT_OPTIONS: LabelValueType[] = [
{ label: '면접 일시 최신순', value: 'date-latest' },
{ label: '면접 일시 오래된순', value: 'date-oldest' },
{ label: '최신 업데이트순', value: 'updated' },
{ label: '가나다순', value: 'alphabetical' },
]
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ type InterviewFilterModalProps = {
export default function InterviewFilterModalContent({ open, filter, onApply, onClose }: InterviewFilterModalProps) {
const [draft, setDraft] = useState<InterviewFilter>(filter)

const toggleItem = (key: keyof Pick<InterviewFilter, 'interviewType' | 'resultStatus'>, value: string) => {
const toggleItem = <K extends 'interviewType' | 'resultStatus'>(key: K, value: InterviewFilter[K][number]) => {
setDraft((prev) => {
const list = prev[key]
const list = prev[key] as string[]
const updated = list.includes(value) ? list.filter((v) => v !== value) : [...list, value]
return { ...prev, [key]: updated }
})
}

const handleReset = () => setDraft(EMPTY_FILTER)
const handleReset = () => setDraft((prev) => ({ ...EMPTY_FILTER, keyword: prev.keyword }))

const handleApply = () => {
onApply(draft)
Expand All @@ -37,14 +37,14 @@ export default function InterviewFilterModalContent({ open, filter, onApply, onC
items={INTERVIEW_TYPE_OPTIONS}
columns={3}
selected={draft.interviewType}
onToggle={(v) => toggleItem('interviewType', v)}
onToggle={(v) => toggleItem('interviewType', v as InterviewFilter['interviewType'][number])}
/>
<CheckboxGroup
label="합불 상태"
items={RESULT_STATUS_ITEMS}
columns={3}
selected={draft.resultStatus}
onToggle={(v) => toggleItem('resultStatus', v)}
onToggle={(v) => toggleItem('resultStatus', v as InterviewFilter['resultStatus'][number])}
/>
<div className="flex flex-col gap-2">
<span className="caption-l-medium">기간</span>
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useState } from 'react'
import { FilterSortControls, SearchBar, SearchResultBar } from '@/features/dashboard/my-interviews/components/filter'
import DraftSection from '@/features/dashboard/my-interviews/components/interviews/draft/DraftSection'
import InterviewListSection from '@/features/dashboard/my-interviews/components/interviews/list/InterviewListSection'
import { EMPTY_FILTER } from '@/features/dashboard/my-interviews/constants/constants'
import type { InterviewFilter } from '@/types/interview'

export default function InterviewsTab() {
const [filter, setFilter] = useState<InterviewFilter>(EMPTY_FILTER)
const isSearching = filter.keyword.length > 0

return (
<>
<div className="absolute top-0 right-0">
<SearchBar keyword={filter.keyword} onSearch={(keyword) => setFilter((prev) => ({ ...prev, keyword }))} />
</div>
{!isSearching && (
<section className="flex flex-col gap-3">
<h2 className="title-s-bold">임시저장 항목</h2>
<div className="flex gap-4">
<DraftSection interviewDraftType="LOGGING" />
<DraftSection interviewDraftType="REVIEWING" />
</div>
</section>
)}
<section className="flex flex-col gap-3">
<div className="flex items-center justify-between">
{isSearching ? (
<SearchResultBar query={filter.keyword} onClose={() => setFilter((prev) => ({ ...prev, keyword: '' }))} />
) : (
<h2 className="title-s-bold">내가 복기 완료한 면접</h2>
)}
<FilterSortControls filter={filter} onFilterChange={setFilter} />
</div>
<InterviewListSection filter={filter} />
</section>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { useState } from 'react'
import { useNavigate } from 'react-router'
import { useGetMyInterviewDrafts } from '@/apis/generated/interview-my-api/interview-my-api'
import type { GetMyInterviewDraftsInterviewDraftType } from '@/apis/generated/refit-api.schemas'
import { getInterviewNavigationPath } from '@/constants/interviewReviewStatusRoutes'
import { INTERVIEW_TYPE_LABEL } from '@/constants/interviews'
import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/designs/components'
import { mapDraftInterviewRow } from '@/features/dashboard/my-interviews/components/interviews/mappers'
import DraftListModal from './draft-list-modal/DraftListModal'

type DraftSectionProps = {
interviewDraftType: GetMyInterviewDraftsInterviewDraftType
}

export default function DraftSection({ interviewDraftType }: DraftSectionProps) {
const navigate = useNavigate()
const [isModalOpen, setIsModalOpen] = useState(false)
const { data: items = [], isPending } = useGetMyInterviewDrafts(
{ interviewDraftType, page: 0, size: 5 },
{
query: {
select: (response) => (response.result?.content ?? []).map(mapDraftInterviewRow),
},
},
)
const draftType = interviewDraftType === 'LOGGING' ? '기록' : '회고'

return (
<>
<div className="bg-gray-white relative flex flex-1 flex-col rounded-lg p-5">
<div className="absolute right-5">
<Button size="xs" className="text-gray-400" onClick={() => setIsModalOpen(true)}>
전체보기
</Button>
</div>
<h3 className="body-l-semibold mb-5">임시저장한 {draftType}</h3>
<Table>
<TableHeader>
<TableRow>
<TableHead>응시일</TableHead>
<TableHead>회사</TableHead>
<TableHead>직무</TableHead>
<TableHead>면접 유형</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{isPending ? (
<TableRow>
<TableCell className="body-s-regular text-gray-300" colSpan={4}>
로딩중...
</TableCell>
</TableRow>
) : items.length === 0 ? (
<TableRow>
<TableCell
className="body-s-regular hover:transparent pointer-events-none h-20 text-center text-gray-300"
colSpan={4}
>
임시저장한 {draftType} 데이터가 아직 없어요.
</TableCell>
</TableRow>
) : (
items.map(
({ interviewId, interviewReviewStatus, interviewStartAt, company, jobCategoryName, interviewType }) => (
<TableRow
key={interviewId}
className="cursor-pointer hover:bg-gray-50"
onClick={() => navigate(getInterviewNavigationPath(interviewId, interviewReviewStatus))}
>
<TableCell className="body-s-regular text-gray-300">{interviewStartAt}</TableCell>
<TableCell className="body-s-semibold">{company}</TableCell>
<TableCell>{jobCategoryName}</TableCell>
<TableCell>{INTERVIEW_TYPE_LABEL[interviewType]}</TableCell>
</TableRow>
),
)
)}
</TableBody>
</Table>
</div>
<DraftListModal
open={isModalOpen}
onClose={() => setIsModalOpen(false)}
interviewDraftType={interviewDraftType}
/>
</>
)
}
Loading