refactor(WEB): Server Component → Client Component 전면 마이그레이션

- 53개 페이지를 Server Component에서 Client Component로 변환
- Next.js 15에서 Server Component 렌더링 중 쿠키 수정 불가 이슈 해결
- 폐쇄형 ERP 시스템 특성상 SEO 불필요, Client Component 사용이 적합

주요 변경사항:
- 모든 페이지에 'use client' 지시어 추가
- use(params) 훅으로 async params 처리
- useState + useEffect로 데이터 페칭 패턴 적용
- skipTokenRefresh 옵션 및 관련 코드 제거 (더 이상 필요 없음)

변환된 페이지:
- Settings: 4개 (account-info, notification-settings, permissions, popup-management)
- Accounting: 9개 (vendors, sales, deposits, bills, withdrawals, expected-expenses, bad-debt-collection)
- Sales: 4개 (quote-management, pricing-management)
- Production/Quality/Master-data: 6개
- Material/Outbound: 4개
- Construction: 22개
- Other: 4개 (payment-history, subscription, dev/test-urls)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
byeongcheolryu
2026-01-09 19:19:37 +09:00
parent e4af3232dd
commit 284c19f036
60 changed files with 2280 additions and 1348 deletions

View File

@@ -35,10 +35,10 @@ interface CategorySectionProps {
function CategorySection({ title, enabled, onEnabledChange, children }: CategorySectionProps) {
return (
<div className="bg-gray-800 rounded-lg overflow-hidden">
<div className="bg-gray-100 rounded-lg overflow-hidden">
{/* 카테고리 헤더 */}
<div className="flex items-center justify-between px-4 py-3">
<span className="text-white font-medium">{title}</span>
<div className="flex items-center justify-between px-4 py-3 bg-gray-200">
<span className="text-gray-800 font-medium">{title}</span>
<Switch
checked={enabled}
onCheckedChange={onEnabledChange}
@@ -46,7 +46,7 @@ function CategorySection({ title, enabled, onEnabledChange, children }: Category
/>
</div>
{/* 하위 항목 */}
<div className="bg-gray-700 px-4 py-2 space-y-2">
<div className="bg-gray-50 px-4 py-2 space-y-2">
{children}
</div>
</div>
@@ -64,7 +64,7 @@ interface ItemRowProps {
function ItemRow({ label, checked, onChange, disabled }: ItemRowProps) {
return (
<div className="flex items-center justify-between py-1">
<span className="text-gray-300 text-sm">{label}</span>
<span className="text-gray-600 text-sm">{label}</span>
<Switch
checked={checked}
onCheckedChange={onChange}
@@ -133,17 +133,17 @@ export function ItemSettingsDialog({ isOpen, onClose, settings, onSave }: ItemSe
return (
<Dialog open={isOpen} onOpenChange={handleOpenChange}>
<DialogContent className="!w-[400px] !max-w-[400px] max-h-[80vh] overflow-y-auto p-0 bg-gray-900 border-gray-700">
<DialogContent className="!w-[400px] !max-w-[400px] max-h-[80vh] overflow-y-auto p-0 bg-white border-gray-200">
{/* 헤더 */}
<DialogHeader className="sticky top-0 bg-gray-900 z-10 px-4 py-3 border-b border-gray-700">
<DialogHeader className="sticky top-0 bg-white z-10 px-4 py-3 border-b border-gray-200">
<div className="flex items-center justify-between">
<DialogTitle className="text-white font-medium"> </DialogTitle>
<DialogTitle className="text-gray-900 font-medium"> </DialogTitle>
<button
type="button"
onClick={onClose}
className="p-1 hover:bg-gray-800 rounded transition-colors"
className="p-1 hover:bg-gray-100 rounded transition-colors"
>
<X className="h-5 w-5 text-gray-400" />
<X className="h-5 w-5 text-gray-500" />
</button>
</div>
</DialogHeader>
@@ -315,17 +315,17 @@ export function ItemSettingsDialog({ isOpen, onClose, settings, onSave }: ItemSe
</div>
{/* 하단 버튼 */}
<div className="sticky bottom-0 bg-gray-900 px-4 py-3 border-t border-gray-700 flex justify-center gap-3">
<div className="sticky bottom-0 bg-white px-4 py-3 border-t border-gray-200 flex justify-center gap-3">
<Button
variant="outline"
onClick={onClose}
className="bg-gray-700 border-gray-600 text-white hover:bg-gray-600 min-w-[80px]"
className="bg-gray-100 border-gray-300 text-gray-700 hover:bg-gray-200 min-w-[80px] rounded-full"
>
</Button>
<Button
onClick={handleSave}
className="bg-gray-700 text-white hover:bg-gray-600 min-w-[80px]"
className="bg-gray-500 text-white hover:bg-gray-600 min-w-[80px] rounded-full"
>
</Button>