refactor(WEB): WorkerScreen 코드 정리 및 최적화
- 중복 로직 제거 및 구조 개선 (-103줄) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -232,14 +232,37 @@ interface SidebarOrder {
|
||||
quantity: number;
|
||||
shutterCount: number;
|
||||
priority: 'urgent' | 'priority' | 'normal';
|
||||
subType?: 'slat' | 'jointbar' | 'bending' | 'wip';
|
||||
}
|
||||
|
||||
const MOCK_SIDEBAR_ORDERS: SidebarOrder[] = [
|
||||
{ id: 'order-1', siteName: '현장명', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'urgent' },
|
||||
{ id: 'order-2', siteName: '현장명', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'priority' },
|
||||
{ id: 'order-3', siteName: '현장명', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'normal' },
|
||||
{ id: 'order-4', siteName: '현장명', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'normal' },
|
||||
];
|
||||
// 스크린: subType 없음 / 슬랫: slat|jointbar / 절곡: bending|wip
|
||||
const MOCK_SIDEBAR_ORDERS: Record<ProcessTab, SidebarOrder[]> = {
|
||||
screen: [
|
||||
{ id: 'order-s1', siteName: '현장명', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'urgent' },
|
||||
{ id: 'order-s2', siteName: '현장명', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'priority' },
|
||||
{ id: 'order-s3', siteName: '현장명', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'normal' },
|
||||
{ id: 'order-s4', siteName: '현장명', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'normal' },
|
||||
],
|
||||
slat: [
|
||||
{ id: 'order-l1', siteName: '현장명A', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'urgent', subType: 'slat' },
|
||||
{ id: 'order-l2', siteName: '현장명B', date: '2024-09-24', quantity: 3, shutterCount: 2, priority: 'priority', subType: 'jointbar' },
|
||||
{ id: 'order-l3', siteName: '현장명C', date: '2024-09-24', quantity: 5, shutterCount: 4, priority: 'normal', subType: 'slat' },
|
||||
{ id: 'order-l4', siteName: '현장명D', date: '2024-09-24', quantity: 4, shutterCount: 3, priority: 'normal', subType: 'jointbar' },
|
||||
],
|
||||
bending: [
|
||||
{ id: 'order-b1', siteName: '현장명A', date: '2024-09-24', quantity: 7, shutterCount: 5, priority: 'urgent', subType: 'bending' },
|
||||
{ id: 'order-b2', siteName: '현장명B', date: '2024-09-24', quantity: 3, shutterCount: 2, priority: 'priority', subType: 'wip' },
|
||||
{ id: 'order-b3', siteName: '현장명C', date: '2024-09-24', quantity: 5, shutterCount: 4, priority: 'normal', subType: 'bending' },
|
||||
{ id: 'order-b4', siteName: '현장명D', date: '2024-09-24', quantity: 4, shutterCount: 3, priority: 'normal', subType: 'wip' },
|
||||
],
|
||||
};
|
||||
|
||||
const SUB_TYPE_TAGS: Record<string, { label: string; className: string }> = {
|
||||
slat: { label: '슬랫', className: 'bg-blue-100 text-blue-700' },
|
||||
jointbar: { label: '조인트바', className: 'bg-purple-100 text-purple-700' },
|
||||
bending: { label: '절곡', className: 'bg-amber-100 text-amber-700' },
|
||||
wip: { label: '재공품', className: 'bg-orange-100 text-orange-700' },
|
||||
};
|
||||
|
||||
const PRIORITY_GROUPS = [
|
||||
{ key: 'urgent' as const, label: '긴급', color: 'text-red-600' },
|
||||
@@ -811,13 +834,11 @@ export default function WorkerScreen() {
|
||||
<div className="mt-2 p-3 border rounded-lg bg-white max-h-[300px] overflow-y-auto">
|
||||
<SidebarContent
|
||||
tab={tab}
|
||||
slatSubMode={slatSubMode}
|
||||
setSlatSubMode={setSlatSubMode}
|
||||
bendingSubMode={bendingSubMode}
|
||||
setBendingSubMode={setBendingSubMode}
|
||||
selectedOrderId={selectedSidebarOrderId}
|
||||
onSelectOrder={(id) => {
|
||||
onSelectOrder={(id, subType) => {
|
||||
setSelectedSidebarOrderId(id);
|
||||
if (subType === 'slat' || subType === 'jointbar') setSlatSubMode(subType === 'jointbar' ? 'jointbar' : 'normal');
|
||||
if (subType === 'bending' || subType === 'wip') setBendingSubMode(subType === 'wip' ? 'wip' : 'normal');
|
||||
setIsSidebarOpen(false);
|
||||
}}
|
||||
/>
|
||||
@@ -833,12 +854,12 @@ export default function WorkerScreen() {
|
||||
<CardContent className="p-4">
|
||||
<SidebarContent
|
||||
tab={tab}
|
||||
slatSubMode={slatSubMode}
|
||||
setSlatSubMode={setSlatSubMode}
|
||||
bendingSubMode={bendingSubMode}
|
||||
setBendingSubMode={setBendingSubMode}
|
||||
selectedOrderId={selectedSidebarOrderId}
|
||||
onSelectOrder={setSelectedSidebarOrderId}
|
||||
onSelectOrder={(id, subType) => {
|
||||
setSelectedSidebarOrderId(id);
|
||||
if (subType === 'slat' || subType === 'jointbar') setSlatSubMode(subType === 'jointbar' ? 'jointbar' : 'normal');
|
||||
if (subType === 'bending' || subType === 'wip') setBendingSubMode(subType === 'wip' ? 'wip' : 'normal');
|
||||
}}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -1072,110 +1093,58 @@ export default function WorkerScreen() {
|
||||
// ===== 사이드바 컨텐츠 =====
|
||||
interface SidebarContentProps {
|
||||
tab: ProcessTab;
|
||||
slatSubMode: 'normal' | 'jointbar';
|
||||
setSlatSubMode: (mode: 'normal' | 'jointbar') => void;
|
||||
bendingSubMode: 'normal' | 'wip';
|
||||
setBendingSubMode: (mode: 'normal' | 'wip') => void;
|
||||
selectedOrderId: string;
|
||||
onSelectOrder: (id: string) => void;
|
||||
onSelectOrder: (id: string, subType?: SidebarOrder['subType']) => void;
|
||||
}
|
||||
|
||||
function SidebarContent({
|
||||
tab,
|
||||
slatSubMode,
|
||||
setSlatSubMode,
|
||||
bendingSubMode,
|
||||
setBendingSubMode,
|
||||
selectedOrderId,
|
||||
onSelectOrder,
|
||||
}: SidebarContentProps) {
|
||||
const orders = MOCK_SIDEBAR_ORDERS[tab];
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-sm font-semibold text-gray-900">작업 목록</h3>
|
||||
|
||||
{/* 서브 탭: 슬랫 */}
|
||||
{tab === 'slat' && (
|
||||
<div className="flex items-center gap-1 p-1 bg-gray-100 rounded-lg">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSlatSubMode('normal')}
|
||||
className={`flex-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${
|
||||
slatSubMode === 'normal'
|
||||
? 'bg-white text-gray-900 shadow-sm'
|
||||
: 'text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
슬랫
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSlatSubMode('jointbar')}
|
||||
className={`flex-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${
|
||||
slatSubMode === 'jointbar'
|
||||
? 'bg-blue-500 text-white shadow-sm'
|
||||
: 'text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
조인트바
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 서브 탭: 절곡 */}
|
||||
{tab === 'bending' && (
|
||||
<div className="flex items-center gap-1 p-1 bg-gray-100 rounded-lg">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setBendingSubMode('normal')}
|
||||
className={`flex-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${
|
||||
bendingSubMode === 'normal'
|
||||
? 'bg-white text-gray-900 shadow-sm'
|
||||
: 'text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
절곡
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setBendingSubMode('wip')}
|
||||
className={`flex-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${
|
||||
bendingSubMode === 'wip'
|
||||
? 'bg-orange-500 text-white shadow-sm'
|
||||
: 'text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
재공품
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 우선순위별 작업지시 카드 */}
|
||||
{/* 우선순위별 작업지시 카드 + 태그 */}
|
||||
{PRIORITY_GROUPS.map((group) => {
|
||||
const orders = MOCK_SIDEBAR_ORDERS.filter((o) => o.priority === group.key);
|
||||
if (orders.length === 0) return null;
|
||||
const groupOrders = orders.filter((o) => o.priority === group.key);
|
||||
if (groupOrders.length === 0) return null;
|
||||
return (
|
||||
<div key={group.key}>
|
||||
<p className={`text-xs font-semibold mb-1.5 ${group.color}`}>{group.label}</p>
|
||||
<div className="space-y-1.5">
|
||||
{orders.map((order) => (
|
||||
<button
|
||||
key={order.id}
|
||||
type="button"
|
||||
onClick={() => onSelectOrder(order.id)}
|
||||
className={cn(
|
||||
'w-full text-left p-2.5 rounded-lg border transition-colors text-xs',
|
||||
selectedOrderId === order.id
|
||||
? 'border-primary bg-primary/5 ring-1 ring-primary/20'
|
||||
: 'border-gray-200 hover:border-gray-300 hover:bg-gray-50'
|
||||
)}
|
||||
>
|
||||
<p className="font-medium text-gray-900">{order.siteName}</p>
|
||||
<div className="flex items-center justify-between mt-1 text-gray-500">
|
||||
<span>{order.date}</span>
|
||||
<span>{order.quantity}/{order.shutterCount}소</span>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
{groupOrders.map((order) => {
|
||||
const tag = order.subType ? SUB_TYPE_TAGS[order.subType] : null;
|
||||
return (
|
||||
<button
|
||||
key={order.id}
|
||||
type="button"
|
||||
onClick={() => onSelectOrder(order.id, order.subType)}
|
||||
className={cn(
|
||||
'w-full text-left p-2.5 rounded-lg border transition-colors text-xs',
|
||||
selectedOrderId === order.id
|
||||
? 'border-primary bg-primary/5 ring-1 ring-primary/20'
|
||||
: 'border-gray-200 hover:border-gray-300 hover:bg-gray-50'
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="font-medium text-gray-900">{order.siteName}</p>
|
||||
{tag && (
|
||||
<span className={`px-1.5 py-0.5 rounded text-[10px] font-semibold ${tag.className}`}>
|
||||
{tag.label}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center justify-between mt-1 text-gray-500">
|
||||
<span>{order.date}</span>
|
||||
<span>{order.quantity}/{order.shutterCount}소</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user