feat: 다중 도메인 UI 개선 및 컴포넌트 리팩토링
- 게시판, HR, 설정, 차량관리, 건설, 견적 등 전반적 UI 개선 - FormField, TabChip, Select 등 공통 컴포넌트 개선 - 가격배분 edit 페이지 제거 및 상세 페이지 통합 - 체크리스트, 근태, 급여, 권한 관리 등 폼 개선 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import { useDeleteDialog } from '@/hooks/useDeleteDialog';
|
||||
import { PageLayout } from '@/components/organisms/PageLayout';
|
||||
import { PageHeader } from '@/components/organisms/PageHeader';
|
||||
import { toast } from 'sonner';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import type { Account, AccountFormData, AccountStatus } from './types';
|
||||
import {
|
||||
BANK_OPTIONS,
|
||||
@@ -39,6 +40,7 @@ interface AccountDetailProps {
|
||||
export function AccountDetail({ account, mode: initialMode }: AccountDetailProps) {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed);
|
||||
const [mode, setMode] = useState(initialMode);
|
||||
const deleteDialog = useDeleteDialog({
|
||||
onDelete: async (id) => deleteBankAccount(Number(id)),
|
||||
@@ -185,22 +187,28 @@ export function AccountDetail({ account, mode: initialMode }: AccountDetailProps
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 버튼 영역 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Button variant="outline" onClick={handleBack}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
목록으로
|
||||
</div>
|
||||
|
||||
{/* 하단 액션 버튼 (sticky) */}
|
||||
<div className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'} flex items-center justify-between`}>
|
||||
<Button variant="outline" onClick={handleBack} size="sm" className="md:size-default">
|
||||
<ArrowLeft className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">목록으로</span>
|
||||
</Button>
|
||||
<div className="flex items-center gap-1 md:gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => account?.id && deleteDialog.single.open(String(account.id))}
|
||||
size="sm"
|
||||
className="text-destructive hover:bg-destructive hover:text-destructive-foreground md:size-default"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">삭제</span>
|
||||
</Button>
|
||||
<Button onClick={handleEdit} size="sm" className="md:size-default">
|
||||
<Edit className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">수정</span>
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" onClick={() => account?.id && deleteDialog.single.open(String(account.id))} className="text-destructive hover:bg-destructive hover:text-destructive-foreground">
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
삭제
|
||||
</Button>
|
||||
<Button onClick={handleEdit}>
|
||||
<Edit className="w-4 h-4 mr-2" />
|
||||
수정
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -330,17 +338,18 @@ export function AccountDetail({ account, mode: initialMode }: AccountDetailProps
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 버튼 영역 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Button variant="outline" onClick={handleCancel}>
|
||||
<X className="w-4 h-4 mr-2" />
|
||||
취소
|
||||
</Button>
|
||||
<Button onClick={handleSubmit}>
|
||||
<Save className="w-4 h-4 mr-2" />
|
||||
{isCreateMode ? '등록' : '저장'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 하단 액션 버튼 (sticky) */}
|
||||
<div className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'} flex items-center justify-between`}>
|
||||
<Button variant="outline" onClick={handleCancel} size="sm" className="md:size-default">
|
||||
<X className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">취소</span>
|
||||
</Button>
|
||||
<Button onClick={handleSubmit} size="sm" className="md:size-default">
|
||||
<Save className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">{isCreateMode ? '등록' : '저장'}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</PageLayout>
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Landmark, Save, Trash2, ArrowLeft } from 'lucide-react';
|
||||
import { Landmark, Save, Trash2, ArrowLeft, Edit } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@@ -20,6 +20,7 @@ import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
import { PageLayout } from '@/components/organisms/PageLayout';
|
||||
import { PageHeader } from '@/components/organisms/PageHeader';
|
||||
import { FormField } from '@/components/molecules/FormField';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import type { Account, AccountCategory, AccountFormData } from './types';
|
||||
import {
|
||||
ACCOUNT_CATEGORY_OPTIONS,
|
||||
@@ -98,6 +99,7 @@ export function AccountDetailForm({
|
||||
isLoading,
|
||||
}: AccountDetailFormProps) {
|
||||
const router = useRouter();
|
||||
const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed);
|
||||
const [mode, setMode] = useState(initialMode);
|
||||
const [formData, setFormData] = useState<AccountFormData>(() => getInitialFormData(initialData));
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@@ -216,7 +218,7 @@ export function AccountDetailForm({
|
||||
icon={Landmark}
|
||||
/>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-6 pb-20">
|
||||
{/* ===== 기본 정보 ===== */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
@@ -321,26 +323,30 @@ export function AccountDetailForm({
|
||||
<InsuranceAccountSection formData={formData} onChange={handleChange} disabled={disabled} />
|
||||
)}
|
||||
|
||||
{/* ===== 하단 버튼 ===== */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Button variant="outline" onClick={handleBack}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
목록으로
|
||||
{/* ===== 하단 버튼 (sticky) ===== */}
|
||||
<div className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'} flex items-center justify-between`}>
|
||||
<Button variant="outline" onClick={handleBack} size="sm" className="md:size-default">
|
||||
<ArrowLeft className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">목록으로</span>
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-1 md:gap-2">
|
||||
{isViewMode ? (
|
||||
<>
|
||||
{onDelete && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setShowDeleteDialog(true)}
|
||||
className="text-destructive hover:bg-destructive hover:text-destructive-foreground"
|
||||
size="sm"
|
||||
className="text-destructive hover:bg-destructive hover:text-destructive-foreground md:size-default"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
삭제
|
||||
<Trash2 className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">삭제</span>
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={handleEdit}>수정</Button>
|
||||
<Button onClick={handleEdit} size="sm" className="md:size-default">
|
||||
<Edit className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">수정</span>
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -348,15 +354,16 @@ export function AccountDetailForm({
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setShowDeleteDialog(true)}
|
||||
className="text-destructive hover:bg-destructive hover:text-destructive-foreground"
|
||||
size="sm"
|
||||
className="text-destructive hover:bg-destructive hover:text-destructive-foreground md:size-default"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
삭제
|
||||
<Trash2 className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">삭제</span>
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={handleSubmit} disabled={isSaving}>
|
||||
<Save className="w-4 h-4 mr-2" />
|
||||
{isCreateMode ? '등록' : '저장'}
|
||||
<Button onClick={handleSubmit} disabled={isSaving} size="sm" className="md:size-default">
|
||||
<Save className="h-4 w-4 md:mr-2" />
|
||||
<span className="hidden md:inline">{isCreateMode ? '등록' : '저장'}</span>
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -344,6 +344,7 @@ export function AccountManagement() {
|
||||
{ACCOUNT_STATUS_LABELS[item.status]}
|
||||
</Badge>
|
||||
}
|
||||
showCheckbox={false}
|
||||
isSelected={false}
|
||||
onToggleSelection={() => {}}
|
||||
onClick={() => handleRowClick(item)}
|
||||
|
||||
Reference in New Issue
Block a user