- 라우팅 react-router v7, 서버상태 TanStack Query - orval 자동 생성 API 클라이언트(src/api/generated) - 견적/상품/협력사/견적설정 페이지, shadcn UI, 토큰(tokens.css) - 실행: 루트 docker compose (front :3001), README 그에 맞게 정리 - AI Studio 스캐폴드 잔재 제거(metadata.json, 중복 DESIGN_TOKENS.md), 타이틀 NegoData, vite.config 죽은코드 제거 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
131 lines
4.2 KiB
TypeScript
131 lines
4.2 KiB
TypeScript
import { useState } from 'react';
|
|
import { Plus, Upload } from 'lucide-react';
|
|
import { showToast } from '@/lib/notify';
|
|
import { PageContainer } from '@/components/layout/PageContainer';
|
|
import { PageToolbar, SearchInput } from '@/components/layout/PageToolbar';
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
import { Button } from '@/components/ui/button';
|
|
import { usePartners } from '@/features/partners/hooks/usePartners';
|
|
import { usePartnerFilters } from '@/features/partners/hooks/usePartnerFilters';
|
|
import { PartnerTable } from '@/features/partners/components/PartnerTable';
|
|
import { PartnerFormSheet } from '@/features/partners/components/PartnerFormSheet';
|
|
import { ExcelUploadModal } from '@/features/partners/components/ExcelUploadModal';
|
|
import { prioritiesList, type Partner } from '@/features/partners/types';
|
|
|
|
export default function PartnersPage() {
|
|
const { partners, createPartner, updatePartner, deletePartner, bulkCreate } = usePartners();
|
|
const {
|
|
search,
|
|
setSearch,
|
|
priorityFilter,
|
|
setPriorityFilter,
|
|
page,
|
|
setPage,
|
|
paginated,
|
|
totalPages,
|
|
totalCount,
|
|
itemsPerPage,
|
|
} = usePartnerFilters(partners);
|
|
|
|
// 모달 제어 + 폼 컨텍스트
|
|
const [openModal, setOpenModal] = useState<null | 'form' | 'excel'>(null);
|
|
const [formMode, setFormMode] = useState<'create' | 'edit'>('create');
|
|
const [editing, setEditing] = useState<Partner | null>(null);
|
|
|
|
const openCreate = () => {
|
|
setFormMode('create');
|
|
setEditing(null);
|
|
setOpenModal('form');
|
|
};
|
|
const openEdit = (part: Partner) => {
|
|
setFormMode('edit');
|
|
setEditing(part);
|
|
setOpenModal('form');
|
|
};
|
|
|
|
const handleDeletePartner = async (id: string, partnerName: string) => {
|
|
if (confirm(`[${partnerName}] 파트너사를 협력사 목록에서 삭제하시겠습니까?`)) {
|
|
try {
|
|
await deletePartner(id);
|
|
showToast('협력사 정보가 명부에서 제거되었습니다.', 'info');
|
|
} catch (err) {
|
|
showToast(err instanceof Error ? err.message : '협력사 삭제 실패', 'error');
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<PageContainer>
|
|
<PageToolbar
|
|
actions={
|
|
<>
|
|
<Button variant="outline" onClick={() => setOpenModal('excel')}>
|
|
<Upload />
|
|
엑셀 일괄 업로드
|
|
</Button>
|
|
|
|
<Button onClick={openCreate}>
|
|
<Plus />
|
|
신규 협력사 등록
|
|
</Button>
|
|
</>
|
|
}
|
|
>
|
|
<SearchInput
|
|
id="partner-search"
|
|
value={search}
|
|
onChange={(e) => setSearch(e.target.value)}
|
|
placeholder="협력사명, 코드 또는 담당자명으로 추적 검색..."
|
|
/>
|
|
|
|
<Select value={priorityFilter} onValueChange={(v) => setPriorityFilter(v as string)}>
|
|
<SelectTrigger id="partner-priority-filter" className="w-full sm:w-48">
|
|
<SelectValue>
|
|
{(value) => (value === 'ALL' ? '우선순위 가중치 (전체)' : `우선도: ${value}`)}
|
|
</SelectValue>
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{prioritiesList.map((prio) => (
|
|
<SelectItem key={prio} value={prio}>
|
|
{prio === 'ALL' ? '우선순위 가중치 (전체)' : `우선도: ${prio}`}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</PageToolbar>
|
|
|
|
<PartnerTable
|
|
data={paginated}
|
|
onRowClick={openEdit}
|
|
page={page}
|
|
totalPages={totalPages}
|
|
totalCount={totalCount}
|
|
pageSize={itemsPerPage}
|
|
onPageChange={setPage}
|
|
/>
|
|
|
|
{openModal === 'form' && (
|
|
<PartnerFormSheet
|
|
key={`${formMode}-${editing?.supplier_id ?? 'new'}`}
|
|
open
|
|
mode={formMode}
|
|
partner={editing}
|
|
onCreate={createPartner}
|
|
onUpdate={updatePartner}
|
|
onDelete={handleDeletePartner}
|
|
onClose={() => setOpenModal(null)}
|
|
/>
|
|
)}
|
|
|
|
{openModal === 'excel' && (
|
|
<ExcelUploadModal
|
|
open
|
|
partners={partners}
|
|
onConfirm={bulkCreate}
|
|
onClose={() => setOpenModal(null)}
|
|
/>
|
|
)}
|
|
</PageContainer>
|
|
);
|
|
}
|