| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- 'use client';
- import { useState, useEffect, useMemo } from 'react';
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
- import { faCircleCheck, faTriangleExclamation } from '@fortawesome/free-solid-svg-icons';
- import { fetchApi } from '@/lib/utils/client';
- import type { SettlementAccountResponse, SettlementAccountItem } from '@/types/response/settlement/account';
- import { BANK_LIST } from '../constants';
- import Loading from '@/app/component/Loading';
- const MAX_ACCOUNTS = 8;
- export default function SettlementAccountPage() {
- const [loading, setLoading] = useState(true);
- const [submitting, setSubmitting] = useState(false);
- const [accounts, setAccounts] = useState<SettlementAccountItem[]>([]);
- const [mode, setMode] = useState<'list'|'add'|'edit'>('list');
- const [editTarget, setEditTarget] = useState<SettlementAccountItem|null>(null);
- const [bankCode, setBankCode] = useState('');
- const [accountNumber, setAccountNumber] = useState('');
- const [accountHolder, setAccountHolder] = useState('');
- const fetchAccounts = () => {
- setLoading(true);
- fetchApi<SettlementAccountResponse>('/api/studio/settlement/account')
- .then(res => {
- if (res.data) {
- setAccounts(res.data.accounts);
- }
- })
- .catch(() => {})
- .finally(() => setLoading(false));
- };
- useEffect(() => {
- fetchAccounts();
- }, []);
- const canSubmit = useMemo(() => {
- return (
- bankCode !== '' &&
- /^\d{7,16}$/.test(accountNumber) &&
- accountHolder.trim().length >= 2 &&
- !submitting
- );
- }, [bankCode, accountNumber, accountHolder, submitting]);
- const resetForm = () => {
- setBankCode('');
- setAccountNumber('');
- setAccountHolder('');
- setEditTarget(null);
- };
- const handleAdd = () => {
- resetForm();
- setMode('add');
- };
- const handleEdit = (item: SettlementAccountItem) => {
- setEditTarget(item);
- setBankCode(item.bankCode);
- setAccountNumber('');
- setAccountHolder(item.accountHolder);
- setMode('edit');
- };
- const handleCancel = () => {
- resetForm();
- setMode('list');
- };
- const handleDelete = async (item: SettlementAccountItem) => {
- if (!confirm(`${item.bankName} ${item.accountNumber} 계좌를 삭제하시겠습니까?`)) {
- return;
- }
- try {
- await fetchApi(`/api/studio/settlement/account/${item.id}`, { method: 'DELETE' });
- fetchAccounts();
- } catch (err: unknown) {
- alert(err instanceof Error ? err.message : '계좌 삭제에 실패했습니다.');
- }
- };
- const handleSubmit = async () => {
- if (!canSubmit) {
- return;
- }
- setSubmitting(true);
- try {
- await fetchApi('/api/studio/settlement/account', {
- method: 'POST',
- body: {
- accountID: editTarget?.id ?? null,
- bankCode,
- accountNumber,
- accountHolder,
- },
- });
- alert(editTarget ? '계좌가 수정되었습니다.' : '계좌가 등록되었습니다.');
- resetForm();
- setMode('list');
- fetchAccounts();
- } catch (err: unknown) {
- alert(err instanceof Error ? err.message : '계좌 등록에 실패했습니다.');
- } finally {
- setSubmitting(false);
- }
- };
- if (loading) {
- return <Loading />;
- }
- return (
- <div className="studio-page settlement">
- <div className="studio-page__header">
- <h1 className="studio-page__title">계좌 관리</h1>
- </div>
- {/* 계좌 추가/수정 폼 */}
- {mode !== 'list' && (
- <div className="settlement__account-box">
- <p className="settlement__account-form-title">
- {mode === 'edit' ? '계좌 수정' : '계좌 추가'}
- </p>
- <div className="settlement__form">
- <div className="settlement__field">
- <label className="settlement__label" htmlFor="bank-select">은행</label>
- <select
- id="bank-select"
- className="settlement__select"
- value={bankCode}
- onChange={e => setBankCode(e.target.value)}
- >
- <option value="">은행을 선택하세요</option>
- {BANK_LIST.map(bank => (
- <option key={bank.code} value={bank.code}>{bank.name}</option>
- ))}
- </select>
- </div>
- <div className="settlement__field">
- <label className="settlement__label" htmlFor="account-number">계좌번호</label>
- <input
- id="account-number"
- type="text"
- inputMode="numeric"
- className="settlement__input"
- placeholder="숫자만 입력 (7~16자리)"
- value={accountNumber}
- onChange={e => setAccountNumber(e.target.value.replace(/\D/g, ''))}
- maxLength={16}
- />
- </div>
- <div className="settlement__field">
- <label className="settlement__label" htmlFor="account-holder">예금주</label>
- <input
- id="account-holder"
- type="text"
- className="settlement__input"
- placeholder="예금주명을 입력하세요"
- value={accountHolder}
- onChange={e => setAccountHolder(e.target.value)}
- />
- </div>
- <ul className="settlement__notice">
- <li>본인 명의 계좌만 등록 가능합니다.</li>
- <li>출금 시 등록된 계좌로 입금됩니다.</li>
- </ul>
- <div className="settlement__account-actions">
- <button
- type="button"
- className="settlement__btn settlement__btn--primary"
- disabled={!canSubmit}
- onClick={handleSubmit}
- >
- {submitting ? '저장 중...' : (mode === 'edit' ? '수정하기' : '등록하기')}
- </button>
- <button
- type="button"
- className="settlement__btn settlement__btn--cancel"
- onClick={handleCancel}
- >
- 취소
- </button>
- </div>
- </div>
- </div>
- )}
- {/* 계좌 목록 */}
- {mode === 'list' && (
- <>
- <div className="settlement__account-header">
- <span className="settlement__account-count">등록 계좌 {accounts.length}/{MAX_ACCOUNTS}</span>
- {accounts.length < MAX_ACCOUNTS && (
- <button
- type="button"
- className="settlement__btn settlement__btn--primary"
- onClick={handleAdd}
- >
- + 계좌 추가
- </button>
- )}
- </div>
- {accounts.length === 0 ? (
- <div className="settlement__account-empty">
- 등록된 계좌가 없습니다. 출금을 위해 계좌를 등록해 주세요.
- </div>
- ) : (
- <div className="settlement__account-list">
- {accounts.map(item => (
- <div key={item.id} className="settlement__account-card">
- <div className="settlement__account-info">
- <span className="settlement__account-bank">
- {item.bankName} {item.accountNumber}
- </span>
- <span className="settlement__account-detail">
- 예금주: {item.accountHolder}
- </span>
- <span className={`settlement__account-status${item.isVerified ? ' settlement__account-status--verified' : ' settlement__account-status--unverified'}`}>
- {item.isVerified ? (
- <>
- <FontAwesomeIcon icon={faCircleCheck} />
- 인증 완료
- </>
- ) : (
- <>
- <FontAwesomeIcon icon={faTriangleExclamation} />
- 미인증
- </>
- )}
- <span className="settlement__account-detail">
- · 등록일 {item.registeredAt.slice(0, 10).replace(/-/g, '.')}
- </span>
- </span>
- </div>
- <div className="settlement__account-actions">
- <button
- type="button"
- className="settlement__btn"
- onClick={() => handleEdit(item)}
- >
- 수정
- </button>
- <button
- type="button"
- className="settlement__btn settlement__btn--danger"
- onClick={() => handleDelete(item)}
- >
- 삭제
- </button>
- </div>
- </div>
- ))}
- </div>
- )}
- </>
- )}
- </div>
- );
- }
|