273 lines
10 KiB
TypeScript
273 lines
10 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, useCallback } from 'react';
|
|
import { PageLayout } from '@/components/organisms/PageLayout';
|
|
import { PageHeader } from '@/components/organisms/PageHeader';
|
|
import { Link2, Loader2, Pencil, Check } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { toast } from 'sonner';
|
|
import { LoginModal } from './LoginModal';
|
|
import { SignupModal } from './SignupModal';
|
|
import { BankServiceModal } from './BankServiceModal';
|
|
import {
|
|
getIntegrationStatus,
|
|
getAccountLinkUrl,
|
|
getCardLinkUrl,
|
|
getCertificateUrl,
|
|
} from './actions';
|
|
import type { IntegrationStatus } from './types';
|
|
|
|
export function BarobillIntegration() {
|
|
const [status, setStatus] = useState<IntegrationStatus | null>(null);
|
|
const [loginOpen, setLoginOpen] = useState(false);
|
|
const [signupOpen, setSignupOpen] = useState(false);
|
|
const [bankServiceOpen, setBankServiceOpen] = useState(false);
|
|
const [loadingAction, setLoadingAction] = useState<string | null>(null);
|
|
|
|
const loadStatus = useCallback(async () => {
|
|
try {
|
|
const result = await getIntegrationStatus();
|
|
if (result.success && result.data) {
|
|
setStatus(result.data);
|
|
}
|
|
} catch {
|
|
// 상태 조회 실패 시 무시 (페이지 렌더링에 영향 없음)
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
loadStatus();
|
|
}, [loadStatus]);
|
|
|
|
const handleExternalLink = useCallback(async (
|
|
type: 'account' | 'card' | 'certificate',
|
|
) => {
|
|
setLoadingAction(type);
|
|
try {
|
|
const actionMap = {
|
|
account: getAccountLinkUrl,
|
|
card: getCardLinkUrl,
|
|
certificate: getCertificateUrl,
|
|
};
|
|
const result = await actionMap[type]();
|
|
if (result.success && result.data?.url) {
|
|
window.open(result.data.url, '_blank');
|
|
} else {
|
|
toast.error(result.error || '서비스 페이지 URL 조회에 실패했습니다.');
|
|
}
|
|
} catch {
|
|
toast.error('서비스 페이지 URL 조회 중 오류가 발생했습니다.');
|
|
} finally {
|
|
setLoadingAction(null);
|
|
}
|
|
}, []);
|
|
|
|
const hasLogin = !!status?.member?.barobillId;
|
|
|
|
return (
|
|
<PageLayout>
|
|
<PageHeader
|
|
title="바로빌 연동 관리"
|
|
description="바로빌 청구, 장부를 연동합니다."
|
|
icon={Link2}
|
|
/>
|
|
|
|
<div className="space-y-6">
|
|
{/* 바로빌 연동 */}
|
|
<section>
|
|
<h2 className="text-lg font-semibold mb-3">바로빌 연동</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
{/* 바로빌 로그인 정보 */}
|
|
<Card>
|
|
<CardContent className="p-5">
|
|
{hasLogin ? (
|
|
<>
|
|
<h3 className="font-semibold mb-3">바로빌 로그인 정보</h3>
|
|
<div className="space-y-2 mb-4">
|
|
<div className="flex items-center gap-2 text-sm">
|
|
<span className="text-muted-foreground w-16 shrink-0">아이디</span>
|
|
<span className="font-medium">{status?.member?.barobillId}</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-sm">
|
|
<span className="text-muted-foreground w-16 shrink-0">비밀번호</span>
|
|
<span className="font-medium">●●●●●●●●</span>
|
|
<Badge variant="secondary" className="text-xs">
|
|
<Check className="h-3 w-3 mr-1" />설정됨
|
|
</Badge>
|
|
</div>
|
|
</div>
|
|
<Button
|
|
variant="outline"
|
|
className="w-full"
|
|
onClick={() => setLoginOpen(true)}
|
|
>
|
|
<Pencil className="h-4 w-4 mr-2" />
|
|
로그인 정보 수정
|
|
</Button>
|
|
</>
|
|
) : (
|
|
<>
|
|
<h3 className="font-semibold mb-2">바로빌 회원이신가요?</h3>
|
|
<p className="text-sm text-muted-foreground mb-4">
|
|
바로빌 로그인 발급 정보 등록
|
|
</p>
|
|
<Button
|
|
variant="destructive"
|
|
className="w-full"
|
|
onClick={() => setLoginOpen(true)}
|
|
>
|
|
바로빌 로그인 정보 등록
|
|
</Button>
|
|
</>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 바로빌 회원가입 등록 */}
|
|
<Card>
|
|
<CardContent className="p-5">
|
|
<h3 className="font-semibold mb-2">바로빌 회원이 아니신가요?</h3>
|
|
<p className="text-sm text-muted-foreground mb-4">
|
|
바로빌 회원가입 발급 등록 가능
|
|
</p>
|
|
<Button
|
|
variant="destructive"
|
|
className="w-full"
|
|
onClick={() => setSignupOpen(true)}
|
|
>
|
|
바로빌 회원가입 등록
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</section>
|
|
|
|
{/* 계좌 연동 */}
|
|
<section>
|
|
<h2 className="text-lg font-semibold mb-3">계좌 연동</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
{/* 은행 빠른조회 서비스 등록 */}
|
|
<Card>
|
|
<CardContent className="p-5">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<h3 className="font-semibold">은행 빠른조회 서비스 등록</h3>
|
|
{status && status.bankServiceCount > 0 && (
|
|
<Badge variant="secondary">{status.bankServiceCount}개</Badge>
|
|
)}
|
|
</div>
|
|
<ul className="text-sm text-muted-foreground mb-4 space-y-1">
|
|
<li>— 전 은행 인터넷뱅킹가입 필수</li>
|
|
<li>— 빠른조회/공과서비스 가입</li>
|
|
<li>— 조회용 계좌 등록</li>
|
|
</ul>
|
|
<Button
|
|
variant="destructive"
|
|
className="w-full"
|
|
onClick={() => setBankServiceOpen(true)}
|
|
>
|
|
은행 빠른조회 서비스 등록
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 계좌 연동 등록 */}
|
|
<Card>
|
|
<CardContent className="p-5">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<h3 className="font-semibold">계좌 연동 등록</h3>
|
|
{status && status.accountLinkCount > 0 && (
|
|
<Badge variant="secondary">{status.accountLinkCount}개</Badge>
|
|
)}
|
|
</div>
|
|
<ul className="text-sm text-muted-foreground mb-4 space-y-1">
|
|
<li>— 바로빌에 연동되어있는 계좌 등록</li>
|
|
<li>— 조회 가능 (실시간/주기적)</li>
|
|
</ul>
|
|
<Button
|
|
variant="destructive"
|
|
className="w-full"
|
|
onClick={() => handleExternalLink('account')}
|
|
disabled={loadingAction === 'account'}
|
|
>
|
|
{loadingAction === 'account' ? (
|
|
<><Loader2 className="h-4 w-4 mr-2 animate-spin" />이동 중...</>
|
|
) : '계좌 연동 등록'}
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</section>
|
|
|
|
{/* 카드 연동 & 공인인증서 등록 */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
{/* 카드 연동 */}
|
|
<section>
|
|
<h2 className="text-lg font-semibold mb-3">카드 연동</h2>
|
|
<Card>
|
|
<CardContent className="p-5">
|
|
<h3 className="font-semibold mb-2">카드 연동 등록</h3>
|
|
<ul className="text-sm text-muted-foreground mb-4 space-y-1">
|
|
<li>— 바로빌에 연동 카드 정보 등록</li>
|
|
<li>— 카드사/비밀디카번/번호 입력</li>
|
|
</ul>
|
|
<Button
|
|
variant="destructive"
|
|
className="w-full"
|
|
onClick={() => handleExternalLink('card')}
|
|
disabled={loadingAction === 'card'}
|
|
>
|
|
{loadingAction === 'card' ? (
|
|
<><Loader2 className="h-4 w-4 mr-2 animate-spin" />이동 중...</>
|
|
) : '카드 연동 등록'}
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
</section>
|
|
|
|
{/* 공인인증서 등록 */}
|
|
<section>
|
|
<h2 className="text-lg font-semibold mb-3">공인인증서 등록</h2>
|
|
<Card>
|
|
<CardContent className="p-5">
|
|
<h3 className="font-semibold mb-2">세금계산서용 공인인증서 등록</h3>
|
|
<ul className="text-sm text-muted-foreground mb-4 space-y-1">
|
|
<li>— 팩스 세금계산서 연동 등록</li>
|
|
<li>— 범용 공인인증서만 등록 가능 (전자발급용으로도 가능)</li>
|
|
</ul>
|
|
<Button
|
|
variant="destructive"
|
|
className="w-full"
|
|
onClick={() => handleExternalLink('certificate')}
|
|
disabled={loadingAction === 'certificate'}
|
|
>
|
|
{loadingAction === 'certificate' ? (
|
|
<><Loader2 className="h-4 w-4 mr-2 animate-spin" />이동 중...</>
|
|
) : '공인인증서 등록'}
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 모달 */}
|
|
<LoginModal
|
|
open={loginOpen}
|
|
onOpenChange={setLoginOpen}
|
|
onSuccess={loadStatus}
|
|
/>
|
|
<SignupModal
|
|
open={signupOpen}
|
|
onOpenChange={setSignupOpen}
|
|
onSuccess={loadStatus}
|
|
/>
|
|
<BankServiceModal
|
|
open={bankServiceOpen}
|
|
onOpenChange={setBankServiceOpen}
|
|
/>
|
|
</PageLayout>
|
|
);
|
|
}
|