feat(WEB): 회계/설정/카드 관리 페이지 대규모 기능 추가 및 리팩토링
- 일반전표입력, 상품권관리, 세금계산서 발행/조회 신규 페이지 추가 - 바로빌 연동 설정 페이지 추가 - 카드관리/계좌관리 리스트 UniversalListPage 공통 구조로 전환 - 카드거래조회/은행거래조회 리팩토링 (모달 분리, 액션 확장) - 계좌 상세 폼(AccountDetailForm) 신규 구현 - 카드 상세(CardDetail) 신규 구현 + CardNumberInput 적용 - DateRangeSelector, StatCards, IntegratedListTemplateV2 공통 컴포넌트 개선 - 레거시 파일 정리 (CardManagementUnified, cardConfig, _legacy 등) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
210
src/components/settings/BarobillIntegration/SignupModal.tsx
Normal file
210
src/components/settings/BarobillIntegration/SignupModal.tsx
Normal file
@@ -0,0 +1,210 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { FormField } from '@/components/molecules/FormField';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogFooter,
|
||||
} from '@/components/ui/dialog';
|
||||
import type { BarobillSignupFormData } from './types';
|
||||
import { registerBarobillSignup } from './actions';
|
||||
|
||||
interface SignupModalProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onSuccess: () => void;
|
||||
}
|
||||
|
||||
const initialFormData: BarobillSignupFormData = {
|
||||
businessNumber: '',
|
||||
companyName: '',
|
||||
ceoName: '',
|
||||
businessType: '',
|
||||
businessCategory: '',
|
||||
address: '',
|
||||
barobillId: '',
|
||||
password: '',
|
||||
managerName: '',
|
||||
managerPhone: '',
|
||||
managerEmail: '',
|
||||
};
|
||||
|
||||
export function SignupModal({ open, onOpenChange, onSuccess }: SignupModalProps) {
|
||||
const [formData, setFormData] = useState<BarobillSignupFormData>(initialFormData);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const handleOpenChange = useCallback((isOpen: boolean) => {
|
||||
if (isOpen) setFormData(initialFormData);
|
||||
onOpenChange(isOpen);
|
||||
}, [onOpenChange]);
|
||||
|
||||
const handleChange = useCallback((key: keyof BarobillSignupFormData, value: string) => {
|
||||
setFormData(prev => ({ ...prev, [key]: value }));
|
||||
}, []);
|
||||
|
||||
const handleSubmit = useCallback(async () => {
|
||||
if (!formData.businessNumber) {
|
||||
toast.error('사업자등록번호를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
if (!formData.companyName) {
|
||||
toast.error('상호명을 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
if (!formData.ceoName) {
|
||||
toast.error('대표자명을 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
if (!formData.barobillId) {
|
||||
toast.error('바로빌 아이디를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
if (!formData.password) {
|
||||
toast.error('비밀번호를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
const result = await registerBarobillSignup(formData);
|
||||
if (result.success) {
|
||||
toast.success('바로빌 회원가입 정보가 등록되었습니다.');
|
||||
onOpenChange(false);
|
||||
onSuccess();
|
||||
} else {
|
||||
toast.error(result.error || '등록에 실패했습니다.');
|
||||
}
|
||||
} catch {
|
||||
toast.error('등록 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
}, [formData, onOpenChange, onSuccess]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="sm:max-w-[560px] max-h-[90vh] overflow-y-auto" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>바로빌 회원가입 정보 등록</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4 py-2">
|
||||
{/* 사업자등록번호 + 상호명 */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<FormField
|
||||
type="businessNumber"
|
||||
label="사업자등록번호"
|
||||
required
|
||||
value={formData.businessNumber}
|
||||
onChange={(v) => handleChange('businessNumber', v)}
|
||||
placeholder="123-12-12345"
|
||||
/>
|
||||
<FormField
|
||||
label="상호명"
|
||||
required
|
||||
value={formData.companyName}
|
||||
onChange={(v) => handleChange('companyName', v)}
|
||||
placeholder="(주)회사명"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 대표자명 + 업태 + 업종 */}
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<FormField
|
||||
label="대표자명"
|
||||
required
|
||||
value={formData.ceoName}
|
||||
onChange={(v) => handleChange('ceoName', v)}
|
||||
placeholder="홍길동"
|
||||
/>
|
||||
<FormField
|
||||
label="업태"
|
||||
value={formData.businessType}
|
||||
onChange={(v) => handleChange('businessType', v)}
|
||||
placeholder="업태"
|
||||
/>
|
||||
<FormField
|
||||
label="업종"
|
||||
value={formData.businessCategory}
|
||||
onChange={(v) => handleChange('businessCategory', v)}
|
||||
placeholder="업종"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 주소 */}
|
||||
<FormField
|
||||
label="주소"
|
||||
value={formData.address}
|
||||
onChange={(v) => handleChange('address', v)}
|
||||
placeholder="서울특별시 강남구"
|
||||
/>
|
||||
|
||||
{/* 바로빌 아이디 + 비밀번호 */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<FormField
|
||||
label="바로빌 아이디"
|
||||
required
|
||||
value={formData.barobillId}
|
||||
onChange={(v) => handleChange('barobillId', v)}
|
||||
placeholder="Barobill_id"
|
||||
/>
|
||||
<FormField
|
||||
type="password"
|
||||
label="비밀번호"
|
||||
required
|
||||
value={formData.password}
|
||||
onChange={(v) => handleChange('password', v)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 담당자명 + 담당자 연락처 */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<FormField
|
||||
label="담당자명"
|
||||
value={formData.managerName}
|
||||
onChange={(v) => handleChange('managerName', v)}
|
||||
placeholder="홍길동"
|
||||
/>
|
||||
<FormField
|
||||
type="phone"
|
||||
label="담당자 연락처"
|
||||
value={formData.managerPhone}
|
||||
onChange={(v) => handleChange('managerPhone', v)}
|
||||
placeholder="010-1234-1234"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 담당자 이메일 */}
|
||||
<FormField
|
||||
label="담당자 이메일"
|
||||
value={formData.managerEmail}
|
||||
onChange={(v) => handleChange('managerEmail', v)}
|
||||
placeholder="manager@email.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DialogFooter className="gap-3">
|
||||
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={isSubmitting}>
|
||||
취소
|
||||
</Button>
|
||||
<Button onClick={handleSubmit} disabled={isSubmitting}>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
등록 중...
|
||||
</>
|
||||
) : (
|
||||
'등록하기'
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user