feat(WEB): 입력 컴포넌트 공통화 및 UI 개선
- 숫자/통화/전화번호/사업자번호 등 특수 입력 컴포넌트 추가 - MobileCard 컴포넌트 통합 (ListMobileCard 제거) - IntegratedListTemplateV2 페이지네이션 버그 수정 (NaN 이슈) - IntegratedDetailTemplate 타이틀 중복 수정 - 문서 시스템 컴포넌트 추가 - 헤더 벨 아이콘 포커스 스타일 개선 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { AccountNumberInput } from '@/components/ui/account-number-input';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import {
|
||||
Select,
|
||||
@@ -282,10 +283,10 @@ export function AccountDetail({ account, mode: initialMode }: AccountDetailProps
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="accountNumber">계좌번호</Label>
|
||||
<Input
|
||||
<AccountNumberInput
|
||||
id="accountNumber"
|
||||
value={formData.accountNumber}
|
||||
onChange={(e) => handleChange('accountNumber', e.target.value)}
|
||||
onChange={(value) => handleChange('accountNumber', value)}
|
||||
placeholder="1234-1234-1234-1234"
|
||||
disabled={isEditMode} // 수정 시 계좌번호는 변경 불가
|
||||
/>
|
||||
|
||||
@@ -31,9 +31,9 @@ export const accountConfig: DetailConfig<Account> = {
|
||||
{
|
||||
key: 'accountNumber',
|
||||
label: '계좌번호',
|
||||
type: 'text',
|
||||
type: 'accountNumber',
|
||||
required: true,
|
||||
placeholder: '1234-1234-1234-1234',
|
||||
placeholder: '0000-0000-0000-0000',
|
||||
// 수정 모드에서 비활성화 (계좌번호 변경 불가)
|
||||
disabled: (mode) => mode === 'edit',
|
||||
},
|
||||
|
||||
@@ -39,7 +39,7 @@ import {
|
||||
type RowClickHandlers,
|
||||
type ListParams,
|
||||
} from '@/components/templates/UniversalListPage';
|
||||
import { ListMobileCard, InfoField } from '@/components/organisms/ListMobileCard';
|
||||
import { ListMobileCard, InfoField } from '@/components/organisms/MobileCard';
|
||||
import type { Account } from './types';
|
||||
import {
|
||||
BANK_LABELS,
|
||||
|
||||
@@ -6,6 +6,8 @@ import { Building2, Plus, Save, Upload, X, Loader2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { BusinessNumberInput } from '@/components/ui/business-number-input';
|
||||
import { AccountNumberInput } from '@/components/ui/account-number-input';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import {
|
||||
Select,
|
||||
@@ -456,10 +458,10 @@ export function CompanyInfoManagement() {
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="businessNumber">사업자등록번호</Label>
|
||||
<Input
|
||||
<BusinessNumberInput
|
||||
id="businessNumber"
|
||||
value={formData.businessNumber}
|
||||
onChange={(e) => handleChange('businessNumber', e.target.value)}
|
||||
onChange={(value) => handleChange('businessNumber', value)}
|
||||
placeholder="123-12-12345"
|
||||
disabled={!isEditMode}
|
||||
/>
|
||||
@@ -488,11 +490,11 @@ export function CompanyInfoManagement() {
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="paymentAccount">계좌</Label>
|
||||
<Input
|
||||
<AccountNumberInput
|
||||
id="paymentAccount"
|
||||
value={formData.paymentAccount}
|
||||
onChange={(e) => handleChange('paymentAccount', e.target.value)}
|
||||
placeholder="123-1231-23-123"
|
||||
onChange={(value) => handleChange('paymentAccount', value)}
|
||||
placeholder="0000-0000-0000-0000"
|
||||
disabled={!isEditMode}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { ContentLoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { QuantityInput } from '@/components/ui/quantity-input';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import {
|
||||
@@ -198,12 +199,11 @@ export function LeavePolicyManagement() {
|
||||
<div className="space-y-2">
|
||||
<Label>기본 연차 일수</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
<QuantityInput
|
||||
min={0}
|
||||
max={100}
|
||||
value={settings.defaultAnnualLeave}
|
||||
onChange={(e) => updateField('defaultAnnualLeave', parseInt(e.target.value) || 0)}
|
||||
onChange={(value) => updateField('defaultAnnualLeave', value ?? 0)}
|
||||
className="w-20"
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">일</span>
|
||||
@@ -214,12 +214,11 @@ export function LeavePolicyManagement() {
|
||||
<div className="space-y-2">
|
||||
<Label>근속년수당 추가 연차</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
<QuantityInput
|
||||
min={0}
|
||||
max={10}
|
||||
value={settings.additionalLeavePerYear}
|
||||
onChange={(e) => updateField('additionalLeavePerYear', parseInt(e.target.value) || 0)}
|
||||
onChange={(value) => updateField('additionalLeavePerYear', value ?? 0)}
|
||||
className="w-20"
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">일</span>
|
||||
@@ -230,12 +229,11 @@ export function LeavePolicyManagement() {
|
||||
<div className="space-y-2">
|
||||
<Label>최대 연차 일수</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
<QuantityInput
|
||||
min={0}
|
||||
max={100}
|
||||
value={settings.maxAnnualLeave}
|
||||
onChange={(e) => updateField('maxAnnualLeave', parseInt(e.target.value) || 0)}
|
||||
onChange={(value) => updateField('maxAnnualLeave', value ?? 0)}
|
||||
className="w-20"
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">일</span>
|
||||
@@ -276,12 +274,11 @@ export function LeavePolicyManagement() {
|
||||
<div className="space-y-2">
|
||||
<Label>최대 이월 일수</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
<QuantityInput
|
||||
min={0}
|
||||
max={100}
|
||||
value={settings.carryOverMaxDays}
|
||||
onChange={(e) => updateField('carryOverMaxDays', parseInt(e.target.value) || 0)}
|
||||
onChange={(value) => updateField('carryOverMaxDays', value ?? 0)}
|
||||
className="w-20"
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">일</span>
|
||||
@@ -292,12 +289,11 @@ export function LeavePolicyManagement() {
|
||||
<div className="space-y-2">
|
||||
<Label>이월 연차 소멸 기간</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
<QuantityInput
|
||||
min={0}
|
||||
max={24}
|
||||
value={settings.carryOverExpiryMonths}
|
||||
onChange={(e) => updateField('carryOverExpiryMonths', parseInt(e.target.value) || 0)}
|
||||
onChange={(value) => updateField('carryOverExpiryMonths', value ?? 0)}
|
||||
className="w-20"
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">개월</span>
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
type RowClickHandlers,
|
||||
type ListParams,
|
||||
} from '@/components/templates/UniversalListPage';
|
||||
import { ListMobileCard, InfoField } from '@/components/organisms/ListMobileCard';
|
||||
import { ListMobileCard, InfoField } from '@/components/organisms/MobileCard';
|
||||
import { getPayments } from './actions';
|
||||
import type { PaymentHistory, SortOption } from './types';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
type UniversalListConfig,
|
||||
type TableColumn,
|
||||
} from '@/components/templates/UniversalListPage';
|
||||
import { ListMobileCard, InfoField } from '@/components/organisms/ListMobileCard';
|
||||
import { ListMobileCard, InfoField } from '@/components/organisms/MobileCard';
|
||||
import type { PaymentHistory, SortOption } from './types';
|
||||
|
||||
interface PaymentHistoryManagementProps {
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
type StatCard,
|
||||
type TabOption,
|
||||
} from '@/components/templates/UniversalListPage';
|
||||
import { ListMobileCard, InfoField } from '@/components/organisms/ListMobileCard';
|
||||
import { ListMobileCard, InfoField } from '@/components/organisms/MobileCard';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { TimePicker } from '@/components/ui/time-picker';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { QuantityInput } from '@/components/ui/quantity-input';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
@@ -261,14 +262,13 @@ export function WorkScheduleManagement() {
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="weekly-hours">주당 기준 근로시간</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
<QuantityInput
|
||||
id="weekly-hours"
|
||||
type="number"
|
||||
min={0}
|
||||
max={52}
|
||||
value={settings.weeklyWorkHours}
|
||||
onChange={(e) =>
|
||||
setSettings(prev => ({ ...prev, weeklyWorkHours: parseInt(e.target.value) || 0 }))
|
||||
onChange={(value) =>
|
||||
setSettings(prev => ({ ...prev, weeklyWorkHours: value ?? 0 }))
|
||||
}
|
||||
className="w-24"
|
||||
/>
|
||||
@@ -278,14 +278,13 @@ export function WorkScheduleManagement() {
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="overtime-hours">주당 연장 근로시간</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
<QuantityInput
|
||||
id="overtime-hours"
|
||||
type="number"
|
||||
min={0}
|
||||
max={52}
|
||||
value={settings.weeklyOvertimeHours}
|
||||
onChange={(e) =>
|
||||
setSettings(prev => ({ ...prev, weeklyOvertimeHours: parseInt(e.target.value) || 0 }))
|
||||
onChange={(value) =>
|
||||
setSettings(prev => ({ ...prev, weeklyOvertimeHours: value ?? 0 }))
|
||||
}
|
||||
className="w-24"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user