feat(WEB): 입력 컴포넌트 공통화 및 UI 개선
- 숫자/통화/전화번호/사업자번호 등 특수 입력 컴포넌트 추가 - MobileCard 컴포넌트 통합 (ListMobileCard 제거) - IntegratedListTemplateV2 페이지네이션 버그 수정 (NaN 이슈) - IntegratedDetailTemplate 타이틀 중복 수정 - 문서 시스템 컴포넌트 추가 - 헤더 벨 아이콘 포커스 스타일 개선 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,11 @@ import { Plus, X, FileText, Receipt, CreditCard, Upload, Download, Trash2 } from
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { PhoneInput } from '@/components/ui/phone-input';
|
||||
import { BusinessNumberInput } from '@/components/ui/business-number-input';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { CurrencyInput } from '@/components/ui/currency-input';
|
||||
import { NumberInput } from '@/components/ui/number-input';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import {
|
||||
@@ -377,25 +381,58 @@ export function BadDebtDetail({ mode, recordId, initialData }: BadDebtDetailProp
|
||||
value: string | number,
|
||||
options?: {
|
||||
required?: boolean;
|
||||
type?: 'text' | 'tel' | 'email' | 'number';
|
||||
type?: 'text' | 'tel' | 'email' | 'number' | 'phone' | 'businessNumber';
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
) => {
|
||||
const { required, type = 'text', placeholder, disabled } = options || {};
|
||||
const isDisabled = isViewMode || disabled;
|
||||
const stringValue = value !== null && value !== undefined ? String(value) : '';
|
||||
|
||||
const renderInput = () => {
|
||||
switch (type) {
|
||||
case 'phone':
|
||||
return (
|
||||
<PhoneInput
|
||||
value={stringValue}
|
||||
onChange={(v) => handleChange(field, v)}
|
||||
placeholder={placeholder}
|
||||
disabled={isDisabled}
|
||||
className="bg-white"
|
||||
/>
|
||||
);
|
||||
case 'businessNumber':
|
||||
return (
|
||||
<BusinessNumberInput
|
||||
value={stringValue}
|
||||
onChange={(v) => handleChange(field, v)}
|
||||
placeholder={placeholder}
|
||||
disabled={isDisabled}
|
||||
showValidation
|
||||
className="bg-white"
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<Input
|
||||
type={type === 'tel' ? 'tel' : type}
|
||||
value={value}
|
||||
onChange={(e) => handleChange(field, type === 'number' ? Number(e.target.value) : e.target.value)}
|
||||
placeholder={placeholder}
|
||||
disabled={isDisabled}
|
||||
className="bg-white"
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm font-medium text-gray-700">
|
||||
{label} {required && <span className="text-red-500">*</span>}
|
||||
</Label>
|
||||
<Input
|
||||
type={type}
|
||||
value={value}
|
||||
onChange={(e) => handleChange(field, type === 'number' ? Number(e.target.value) : e.target.value)}
|
||||
placeholder={placeholder}
|
||||
disabled={isViewMode || disabled}
|
||||
className="bg-white"
|
||||
/>
|
||||
{renderInput()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -409,7 +446,7 @@ export function BadDebtDetail({ mode, recordId, initialData }: BadDebtDetailProp
|
||||
<CardTitle className="text-lg">기본 정보</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{renderField('사업자등록번호', 'businessNumber', formData.businessNumber, { required: true, placeholder: '000-00-00000', disabled: true })}
|
||||
{renderField('사업자등록번호', 'businessNumber', formData.businessNumber, { required: true, type: 'businessNumber', placeholder: '000-00-00000', disabled: true })}
|
||||
{renderField('거래처 코드', 'vendorCode', formData.vendorCode, { disabled: true })}
|
||||
{renderField('거래처명', 'vendorName', formData.vendorName, { required: true })}
|
||||
{renderField('대표자명', 'representativeName', formData.representativeName)}
|
||||
@@ -492,9 +529,9 @@ export function BadDebtDetail({ mode, recordId, initialData }: BadDebtDetailProp
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{renderField('전화번호', 'phone', formData.phone, { type: 'tel', placeholder: '02-0000-0000' })}
|
||||
{renderField('모바일', 'mobile', formData.mobile, { type: 'tel', placeholder: '010-0000-0000' })}
|
||||
{renderField('팩스', 'fax', formData.fax, { type: 'tel', placeholder: '02-0000-0000' })}
|
||||
{renderField('전화번호', 'phone', formData.phone, { type: 'phone', placeholder: '02-0000-0000' })}
|
||||
{renderField('모바일', 'mobile', formData.mobile, { type: 'phone', placeholder: '010-0000-0000' })}
|
||||
{renderField('팩스', 'fax', formData.fax, { type: 'phone', placeholder: '02-0000-0000' })}
|
||||
{renderField('이메일', 'email', formData.email, { type: 'email' })}
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -507,7 +544,7 @@ export function BadDebtDetail({ mode, recordId, initialData }: BadDebtDetailProp
|
||||
</CardHeader>
|
||||
<CardContent className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{renderField('담당자명', 'contactName', formData.contactName)}
|
||||
{renderField('담당자 전화', 'contactPhone', formData.contactPhone, { type: 'tel' })}
|
||||
{renderField('담당자 전화', 'contactPhone', formData.contactPhone, { type: 'phone' })}
|
||||
{renderField('시스템 관리자', 'systemManager', formData.systemManager, { disabled: true })}
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -799,10 +836,9 @@ export function BadDebtDetail({ mode, recordId, initialData }: BadDebtDetailProp
|
||||
{/* 미수금 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm font-medium text-gray-700">미수금</Label>
|
||||
<Input
|
||||
type="number"
|
||||
<CurrencyInput
|
||||
value={formData.debtAmount}
|
||||
onChange={(e) => handleChange('debtAmount', Number(e.target.value))}
|
||||
onChange={(value) => handleChange('debtAmount', value ?? 0)}
|
||||
disabled={isViewMode}
|
||||
className="bg-white"
|
||||
/>
|
||||
@@ -831,12 +867,12 @@ export function BadDebtDetail({ mode, recordId, initialData }: BadDebtDetailProp
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm font-medium text-gray-700">연체일수</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
<NumberInput
|
||||
value={formData.overdueDays}
|
||||
onChange={(e) => handleChange('overdueDays', Number(e.target.value))}
|
||||
onChange={(value) => handleChange('overdueDays', value ?? 0)}
|
||||
disabled={isViewMode}
|
||||
className="bg-white w-[100px]"
|
||||
min={0}
|
||||
/>
|
||||
<span className="text-sm text-gray-500">일</span>
|
||||
</div>
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { MobileCard } from '@/components/molecules/MobileCard';
|
||||
import { MobileCard } from '@/components/organisms/MobileCard';
|
||||
import {
|
||||
UniversalListPage,
|
||||
type UniversalListConfig,
|
||||
|
||||
Reference in New Issue
Block a user