- Redesigned category create/edit modal with elegant wizard-style UI - Redesigned batch categorization modal with visual cards and better preview - Added missing i18n translations (common.continue, creating, remove) - Added budgets.general and wizard translations for ES, PT-BR, EN - Fixed 3 demo user transactions that were missing categories
833 lines
33 KiB
JavaScript
833 lines
33 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { accountService, liabilityAccountService, assetAccountService } from '../services/api';
|
|
import { useToast } from './Toast';
|
|
|
|
const AccountWizard = ({ isOpen, onClose, onSuccess, account = null }) => {
|
|
const toast = useToast();
|
|
const [step, setStep] = useState(1);
|
|
const [loading, setLoading] = useState(false);
|
|
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
|
|
const isEditMode = !!account;
|
|
|
|
// Tipo de destino: 'account', 'asset' ou 'liability'
|
|
const [destinationType, setDestinationType] = useState('account');
|
|
|
|
// Form data unificado
|
|
const [formData, setFormData] = useState({
|
|
// Tipo de conta (etapa 1)
|
|
account_type: '', // checking, savings, credit_card, cash
|
|
|
|
// Dados básicos (etapa 2)
|
|
name: '',
|
|
description: '',
|
|
currency: 'EUR',
|
|
color: '#3B82F6',
|
|
icon: 'bi-bank',
|
|
|
|
// Dados financeiros (etapa 3)
|
|
initial_balance: '',
|
|
credit_limit: '', // Para cartão de crédito
|
|
|
|
// Dados bancários (etapa 4) - opcional
|
|
bank_name: '',
|
|
account_number: '',
|
|
|
|
// Configurações
|
|
is_active: true,
|
|
include_in_total: true,
|
|
|
|
// Para poupança (ativo)
|
|
interest_rate: '',
|
|
|
|
// Para cartão de crédito (passivo)
|
|
closing_day: '',
|
|
due_day: '',
|
|
annual_interest_rate: '',
|
|
});
|
|
|
|
// Definição dos tipos de conta
|
|
const accountTypes = {
|
|
checking: {
|
|
name: 'Cuenta Corriente',
|
|
description: 'Cuenta bancaria para operaciones diarias',
|
|
icon: 'bi-bank',
|
|
color: '#3B82F6',
|
|
destination: 'account',
|
|
},
|
|
savings: {
|
|
name: 'Cuenta de Ahorro',
|
|
description: 'Dinero guardado que genera intereses',
|
|
icon: 'bi-piggy-bank',
|
|
color: '#10B981',
|
|
destination: 'asset', // Poupança vira ativo
|
|
},
|
|
credit_card: {
|
|
name: 'Tarjeta de Crédito',
|
|
description: 'Línea de crédito rotativo',
|
|
icon: 'bi-credit-card',
|
|
color: '#EF4444',
|
|
destination: 'liability', // Cartão vira passivo
|
|
},
|
|
cash: {
|
|
name: 'Efectivo',
|
|
description: 'Dinero en mano o caja chica',
|
|
icon: 'bi-cash-stack',
|
|
color: '#F59E0B',
|
|
destination: 'account',
|
|
},
|
|
};
|
|
|
|
useEffect(() => {
|
|
const handleResize = () => setIsMobile(window.innerWidth < 768);
|
|
window.addEventListener('resize', handleResize);
|
|
return () => window.removeEventListener('resize', handleResize);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
if (account) {
|
|
loadAccountData(account);
|
|
} else {
|
|
resetForm();
|
|
}
|
|
}
|
|
}, [isOpen, account]);
|
|
|
|
// Atualizar destino quando tipo muda
|
|
useEffect(() => {
|
|
if (formData.account_type && accountTypes[formData.account_type]) {
|
|
const typeConfig = accountTypes[formData.account_type];
|
|
setDestinationType(typeConfig.destination);
|
|
|
|
// Atualizar ícone e cor padrão
|
|
if (!isEditMode) {
|
|
setFormData(prev => ({
|
|
...prev,
|
|
icon: typeConfig.icon,
|
|
color: typeConfig.color,
|
|
}));
|
|
}
|
|
}
|
|
}, [formData.account_type]);
|
|
|
|
const loadAccountData = (accountData) => {
|
|
// Determinar o tipo baseado nos dados
|
|
let accountType = accountData.type || accountData.account_type || 'checking';
|
|
|
|
// Se for um ativo de investimento/poupança
|
|
if (accountData.asset_type === 'cash' || accountData.investment_type === 'savings') {
|
|
accountType = 'savings';
|
|
}
|
|
|
|
// Se for um passivo de cartão
|
|
if (accountData.contract_type === 'credit_card') {
|
|
accountType = 'credit_card';
|
|
}
|
|
|
|
setStep(2);
|
|
setFormData({
|
|
account_type: accountType,
|
|
name: accountData.name || '',
|
|
description: accountData.description || '',
|
|
currency: accountData.currency || 'EUR',
|
|
color: accountData.color || '#3B82F6',
|
|
icon: accountData.icon || 'bi-bank',
|
|
initial_balance: accountData.initial_balance || accountData.current_balance || accountData.current_value || '',
|
|
credit_limit: accountData.credit_limit || accountData.principal_amount || '',
|
|
bank_name: accountData.bank_name || accountData.creditor || '',
|
|
account_number: accountData.account_number || accountData.contract_number || '',
|
|
is_active: accountData.is_active !== false,
|
|
include_in_total: accountData.include_in_total !== false,
|
|
interest_rate: accountData.interest_rate || '',
|
|
closing_day: accountData.closing_day || '',
|
|
due_day: accountData.due_day || '',
|
|
annual_interest_rate: accountData.annual_interest_rate || '',
|
|
});
|
|
};
|
|
|
|
const resetForm = () => {
|
|
setStep(1);
|
|
setDestinationType('account');
|
|
setFormData({
|
|
account_type: '',
|
|
name: '',
|
|
description: '',
|
|
currency: 'EUR',
|
|
color: '#3B82F6',
|
|
icon: 'bi-bank',
|
|
initial_balance: '',
|
|
credit_limit: '',
|
|
bank_name: '',
|
|
account_number: '',
|
|
is_active: true,
|
|
include_in_total: true,
|
|
interest_rate: '',
|
|
closing_day: '',
|
|
due_day: '',
|
|
annual_interest_rate: '',
|
|
});
|
|
};
|
|
|
|
const handleChange = (e) => {
|
|
const { name, value, type, checked } = e.target;
|
|
setFormData(prev => ({
|
|
...prev,
|
|
[name]: type === 'checkbox' ? checked : value,
|
|
}));
|
|
};
|
|
|
|
const selectAccountType = (type) => {
|
|
setFormData(prev => ({ ...prev, account_type: type }));
|
|
setStep(2);
|
|
};
|
|
|
|
const validateStep = () => {
|
|
switch (step) {
|
|
case 1:
|
|
return !!formData.account_type;
|
|
case 2:
|
|
return !!formData.name?.trim();
|
|
case 3:
|
|
if (destinationType === 'liability') {
|
|
return formData.credit_limit > 0;
|
|
}
|
|
return true; // Saldo inicial pode ser 0
|
|
case 4:
|
|
return true; // Dados bancários são opcionais
|
|
default:
|
|
return true;
|
|
}
|
|
};
|
|
|
|
const nextStep = () => {
|
|
if (validateStep()) {
|
|
setStep(prev => Math.min(prev + 1, 4));
|
|
}
|
|
};
|
|
|
|
const prevStep = () => {
|
|
setStep(prev => Math.max(prev - 1, 1));
|
|
};
|
|
|
|
const handleSubmit = async () => {
|
|
setLoading(true);
|
|
try {
|
|
let response;
|
|
|
|
if (destinationType === 'asset') {
|
|
// Criar como Ativo (Poupança)
|
|
const assetData = {
|
|
asset_type: 'cash', // Tipo cash para poupança
|
|
investment_type: 'savings',
|
|
name: formData.name,
|
|
description: formData.description,
|
|
currency: formData.currency,
|
|
color: formData.color,
|
|
acquisition_value: parseFloat(formData.initial_balance) || 0,
|
|
current_value: parseFloat(formData.initial_balance) || 0,
|
|
acquisition_date: new Date().toISOString().split('T')[0],
|
|
institution: formData.bank_name,
|
|
account_number: formData.account_number,
|
|
interest_rate: parseFloat(formData.interest_rate) || 0,
|
|
};
|
|
|
|
if (isEditMode && account) {
|
|
response = await assetAccountService.update(account.id, assetData);
|
|
} else {
|
|
response = await assetAccountService.createWithWizard(assetData);
|
|
}
|
|
} else if (destinationType === 'liability') {
|
|
// Criar como Passivo (Cartão de Crédito)
|
|
const liabilityData = {
|
|
contract_type: 'credit_card',
|
|
name: formData.name,
|
|
description: formData.description,
|
|
currency: formData.currency,
|
|
color: formData.color,
|
|
icon: formData.icon,
|
|
creditor: formData.bank_name,
|
|
contract_number: formData.account_number,
|
|
principal_amount: parseFloat(formData.credit_limit) || 0,
|
|
total_pending: parseFloat(formData.initial_balance) || 0,
|
|
annual_interest_rate: parseFloat(formData.annual_interest_rate) || 0,
|
|
amortization_system: 'revolving',
|
|
start_date: new Date().toISOString().split('T')[0],
|
|
closing_day: parseInt(formData.closing_day) || null,
|
|
due_day: parseInt(formData.due_day) || null,
|
|
};
|
|
|
|
if (isEditMode && account) {
|
|
response = await liabilityAccountService.update(account.id, liabilityData);
|
|
} else {
|
|
response = await liabilityAccountService.storeWithWizard(liabilityData);
|
|
}
|
|
} else {
|
|
// Criar como Conta Normal
|
|
const accountData = {
|
|
type: formData.account_type,
|
|
name: formData.name,
|
|
description: formData.description,
|
|
currency: formData.currency,
|
|
color: formData.color,
|
|
icon: formData.icon,
|
|
bank_name: formData.bank_name,
|
|
account_number: formData.account_number,
|
|
initial_balance: parseFloat(formData.initial_balance) || 0,
|
|
credit_limit: formData.account_type === 'credit_card' ? parseFloat(formData.credit_limit) || null : null,
|
|
is_active: formData.is_active,
|
|
include_in_total: formData.include_in_total,
|
|
};
|
|
|
|
if (isEditMode && account) {
|
|
response = await accountService.update(account.id, accountData);
|
|
} else {
|
|
response = await accountService.create(accountData);
|
|
}
|
|
}
|
|
|
|
if (response.success) {
|
|
onSuccess?.(response.data, destinationType);
|
|
onClose();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error saving account:', error);
|
|
toast.error(error.response?.data?.message || 'Error al guardar la cuenta');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const getTotalSteps = () => {
|
|
return 4;
|
|
};
|
|
|
|
if (!isOpen) return null;
|
|
|
|
return (
|
|
<div className="modal fade show d-block" style={{ backgroundColor: 'rgba(0,0,0,0.8)' }}>
|
|
<div className={`modal-dialog ${isMobile ? 'modal-fullscreen' : 'modal-lg'} modal-dialog-centered modal-dialog-scrollable`}>
|
|
<div className="modal-content" style={{ background: isMobile ? '#0f172a' : '#1e293b', border: '1px solid #334155' }}>
|
|
{/* Header */}
|
|
<div className={`modal-header border-0 ${isMobile ? 'py-2' : ''}`} style={{ backgroundColor: '#334155' }}>
|
|
<h5 className={`modal-title text-white ${isMobile ? 'fs-6' : ''}`}>
|
|
<i className={`bi ${isEditMode ? 'bi-pencil' : 'bi-plus-circle'} me-2`}></i>
|
|
{isEditMode ? 'Editar Cuenta' : 'Nueva Cuenta'} - Paso {step}/{getTotalSteps()}
|
|
</h5>
|
|
<button type="button" className="btn-close btn-close-white" onClick={onClose}></button>
|
|
</div>
|
|
|
|
{/* Progress */}
|
|
<div className="progress" style={{ height: '4px', borderRadius: 0 }}>
|
|
<div
|
|
className="progress-bar bg-primary"
|
|
style={{ width: `${(step / getTotalSteps()) * 100}%` }}
|
|
></div>
|
|
</div>
|
|
|
|
{/* Body */}
|
|
<div className={`modal-body ${isMobile ? 'p-3' : 'p-4'}`} style={{ color: '#fff' }}>
|
|
|
|
{/* Step 1: Tipo de Conta */}
|
|
{step === 1 && (
|
|
<div>
|
|
<h5 className="mb-4">
|
|
<i className="bi bi-wallet2 me-2"></i>
|
|
¿Qué tipo de cuenta deseas crear?
|
|
</h5>
|
|
|
|
<div className="row g-3">
|
|
{Object.entries(accountTypes).map(([key, config]) => (
|
|
<div key={key} className="col-md-6">
|
|
<div
|
|
className={`card h-100 cursor-pointer ${formData.account_type === key ? 'border-primary' : 'border-secondary'}`}
|
|
style={{
|
|
backgroundColor: formData.account_type === key ? config.color + '20' : '#0f172a',
|
|
cursor: 'pointer',
|
|
transition: 'all 0.2s',
|
|
}}
|
|
onClick={() => selectAccountType(key)}
|
|
>
|
|
<div className="card-body text-center p-4">
|
|
<div
|
|
className="rounded-circle d-inline-flex align-items-center justify-content-center mb-3"
|
|
style={{
|
|
width: '60px',
|
|
height: '60px',
|
|
backgroundColor: config.color + '30',
|
|
}}
|
|
>
|
|
<i className={`bi ${config.icon} fs-3`} style={{ color: config.color }}></i>
|
|
</div>
|
|
<h6 className="text-white mb-2">{config.name}</h6>
|
|
<small className="text-slate-400">{config.description}</small>
|
|
|
|
{/* Badge indicando destino */}
|
|
<div className="mt-3">
|
|
{config.destination === 'asset' && (
|
|
<span className="badge bg-success">
|
|
<i className="bi bi-graph-up me-1"></i>
|
|
Se registra como Activo
|
|
</span>
|
|
)}
|
|
{config.destination === 'liability' && (
|
|
<span className="badge bg-danger">
|
|
<i className="bi bi-graph-down me-1"></i>
|
|
Se registra como Pasivo
|
|
</span>
|
|
)}
|
|
{config.destination === 'account' && (
|
|
<span className="badge bg-primary">
|
|
<i className="bi bi-wallet2 me-1"></i>
|
|
Cuenta Estándar
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Step 2: Dados Básicos */}
|
|
{step === 2 && (
|
|
<div>
|
|
<h5 className="mb-4">
|
|
<i className={`bi ${accountTypes[formData.account_type]?.icon || 'bi-info-circle'} me-2`}></i>
|
|
Información Básica
|
|
</h5>
|
|
|
|
<div className="row g-3">
|
|
<div className="col-12">
|
|
<label className="form-label">
|
|
Nombre de la Cuenta <span className="text-danger">*</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="name"
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={formData.name}
|
|
onChange={handleChange}
|
|
placeholder={`Ej: ${accountTypes[formData.account_type]?.name || 'Mi cuenta'}`}
|
|
autoFocus
|
|
/>
|
|
</div>
|
|
|
|
<div className="col-md-6">
|
|
<label className="form-label">Moneda</label>
|
|
<select
|
|
name="currency"
|
|
className="form-select bg-dark text-white border-secondary"
|
|
value={formData.currency}
|
|
onChange={handleChange}
|
|
>
|
|
<option value="EUR">EUR - Euro</option>
|
|
<option value="USD">USD - Dólar</option>
|
|
<option value="BRL">BRL - Real</option>
|
|
<option value="GBP">GBP - Libra</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div className="col-md-6">
|
|
<label className="form-label">Color</label>
|
|
<div className="d-flex gap-2 flex-wrap">
|
|
{['#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#06B6D4', '#6B7280'].map(color => (
|
|
<div
|
|
key={color}
|
|
className={`rounded-circle ${formData.color === color ? 'ring ring-white' : ''}`}
|
|
style={{
|
|
width: '32px',
|
|
height: '32px',
|
|
backgroundColor: color,
|
|
cursor: 'pointer',
|
|
border: formData.color === color ? '3px solid white' : '2px solid transparent',
|
|
}}
|
|
onClick={() => setFormData(prev => ({ ...prev, color }))}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="col-12">
|
|
<label className="form-label">Descripción (opcional)</label>
|
|
<textarea
|
|
name="description"
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={formData.description}
|
|
onChange={handleChange}
|
|
rows={2}
|
|
placeholder="Descripción o notas adicionales..."
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Step 3: Dados Financeiros */}
|
|
{step === 3 && (
|
|
<div>
|
|
<h5 className="mb-4">
|
|
<i className="bi bi-currency-euro me-2"></i>
|
|
Información Financiera
|
|
</h5>
|
|
|
|
<div className="row g-3">
|
|
{/* Saldo/Valor Inicial */}
|
|
<div className="col-md-6">
|
|
<label className="form-label">
|
|
{destinationType === 'liability' ? 'Deuda Actual' : 'Saldo Inicial'}
|
|
{destinationType === 'liability' && <span className="text-danger">*</span>}
|
|
</label>
|
|
<div className="input-group">
|
|
<span className="input-group-text bg-dark text-white border-secondary">
|
|
{formData.currency === 'EUR' ? '€' : formData.currency === 'USD' ? '$' : 'R$'}
|
|
</span>
|
|
<input
|
|
type="number"
|
|
name="initial_balance"
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={formData.initial_balance}
|
|
onChange={handleChange}
|
|
placeholder="0.00"
|
|
step="0.01"
|
|
/>
|
|
</div>
|
|
<small className="text-slate-400">
|
|
{destinationType === 'liability'
|
|
? 'Monto que debes actualmente en esta tarjeta'
|
|
: 'Saldo actual de la cuenta'}
|
|
</small>
|
|
</div>
|
|
|
|
{/* Limite de Crédito (só para cartão) */}
|
|
{(formData.account_type === 'credit_card' || destinationType === 'liability') && (
|
|
<div className="col-md-6">
|
|
<label className="form-label">
|
|
Límite de Crédito <span className="text-danger">*</span>
|
|
</label>
|
|
<div className="input-group">
|
|
<span className="input-group-text bg-dark text-white border-secondary">
|
|
{formData.currency === 'EUR' ? '€' : formData.currency === 'USD' ? '$' : 'R$'}
|
|
</span>
|
|
<input
|
|
type="number"
|
|
name="credit_limit"
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={formData.credit_limit}
|
|
onChange={handleChange}
|
|
placeholder="5000.00"
|
|
step="0.01"
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Taxa de Juros (para poupança ou cartão) */}
|
|
{(destinationType === 'asset' || destinationType === 'liability') && (
|
|
<div className="col-md-6">
|
|
<label className="form-label">
|
|
Tasa de Interés Anual (%)
|
|
</label>
|
|
<div className="input-group">
|
|
<input
|
|
type="number"
|
|
name={destinationType === 'asset' ? 'interest_rate' : 'annual_interest_rate'}
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={destinationType === 'asset' ? formData.interest_rate : formData.annual_interest_rate}
|
|
onChange={handleChange}
|
|
placeholder={destinationType === 'asset' ? '2.5' : '18.99'}
|
|
step="0.01"
|
|
/>
|
|
<span className="input-group-text bg-dark text-white border-secondary">%</span>
|
|
</div>
|
|
<small className="text-slate-400">
|
|
{destinationType === 'asset'
|
|
? 'Rendimiento anual de la cuenta'
|
|
: 'Tasa de interés por financiamiento'}
|
|
</small>
|
|
</div>
|
|
)}
|
|
|
|
{/* Dias de fechamento e vencimento (cartão) */}
|
|
{destinationType === 'liability' && (
|
|
<>
|
|
<div className="col-md-6">
|
|
<label className="form-label">Día de Cierre</label>
|
|
<input
|
|
type="number"
|
|
name="closing_day"
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={formData.closing_day}
|
|
onChange={handleChange}
|
|
placeholder="15"
|
|
min="1"
|
|
max="31"
|
|
/>
|
|
<small className="text-slate-400">Día del mes que cierra la factura</small>
|
|
</div>
|
|
<div className="col-md-6">
|
|
<label className="form-label">Día de Vencimiento</label>
|
|
<input
|
|
type="number"
|
|
name="due_day"
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={formData.due_day}
|
|
onChange={handleChange}
|
|
placeholder="25"
|
|
min="1"
|
|
max="31"
|
|
/>
|
|
<small className="text-slate-400">Día de pago de la factura</small>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Step 4: Dados Bancários */}
|
|
{step === 4 && (
|
|
<div>
|
|
<h5 className="mb-4">
|
|
<i className="bi bi-building me-2"></i>
|
|
Información Bancaria (Opcional)
|
|
</h5>
|
|
|
|
<div className="row g-3">
|
|
<div className="col-md-6">
|
|
<label className="form-label">
|
|
{destinationType === 'liability' ? 'Emisor de la Tarjeta' : 'Nombre del Banco'}
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="bank_name"
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={formData.bank_name}
|
|
onChange={handleChange}
|
|
placeholder={destinationType === 'liability' ? 'Ej: BBVA, Santander' : 'Ej: Santander, BBVA'}
|
|
/>
|
|
</div>
|
|
|
|
<div className="col-md-6">
|
|
<label className="form-label">
|
|
{destinationType === 'liability' ? 'Últimos 4 Dígitos' : 'Número de Cuenta'}
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="account_number"
|
|
className="form-control bg-dark text-white border-secondary"
|
|
value={formData.account_number}
|
|
onChange={handleChange}
|
|
placeholder={destinationType === 'liability' ? '****1234' : 'ES00 0000 0000 0000'}
|
|
/>
|
|
</div>
|
|
|
|
{destinationType === 'account' && (
|
|
<>
|
|
<div className="col-12">
|
|
<hr className="border-secondary my-4" />
|
|
<h6 className="text-white mb-3">
|
|
<i className="bi bi-gear me-2"></i>
|
|
Configuración
|
|
</h6>
|
|
</div>
|
|
|
|
<div className="col-md-6">
|
|
<div className="form-check form-switch">
|
|
<input
|
|
type="checkbox"
|
|
name="is_active"
|
|
className="form-check-input"
|
|
checked={formData.is_active}
|
|
onChange={handleChange}
|
|
id="is_active"
|
|
/>
|
|
<label className="form-check-label text-white" htmlFor="is_active">
|
|
Cuenta Activa
|
|
</label>
|
|
</div>
|
|
<small className="text-slate-400">Cuentas inactivas no aparecen en transacciones</small>
|
|
</div>
|
|
|
|
<div className="col-md-6">
|
|
<div className="form-check form-switch">
|
|
<input
|
|
type="checkbox"
|
|
name="include_in_total"
|
|
className="form-check-input"
|
|
checked={formData.include_in_total}
|
|
onChange={handleChange}
|
|
id="include_in_total"
|
|
/>
|
|
<label className="form-check-label text-white" htmlFor="include_in_total">
|
|
Incluir en Total
|
|
</label>
|
|
</div>
|
|
<small className="text-slate-400">Suma el saldo al patrimonio total</small>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* Resumen */}
|
|
<div className="mt-4 p-3 rounded" style={{ backgroundColor: '#0f172a' }}>
|
|
<h6 className="text-white mb-3">
|
|
<i className="bi bi-check-circle me-2"></i>
|
|
Resumen
|
|
</h6>
|
|
<div className="row g-2">
|
|
<div className="col-6">
|
|
<small className="text-slate-400">Tipo:</small>
|
|
<div className="text-white">{accountTypes[formData.account_type]?.name}</div>
|
|
</div>
|
|
<div className="col-6">
|
|
<small className="text-slate-400">Nombre:</small>
|
|
<div className="text-white">{formData.name || '-'}</div>
|
|
</div>
|
|
<div className="col-6">
|
|
<small className="text-slate-400">
|
|
{destinationType === 'liability' ? 'Deuda:' : 'Saldo:'}
|
|
</small>
|
|
<div className="text-white">
|
|
{formData.currency === 'EUR' ? '€' : formData.currency === 'USD' ? '$' : 'R$'}
|
|
{parseFloat(formData.initial_balance || 0).toFixed(2)}
|
|
</div>
|
|
</div>
|
|
{formData.credit_limit && (
|
|
<div className="col-6">
|
|
<small className="text-slate-400">Límite:</small>
|
|
<div className="text-white">
|
|
{formData.currency === 'EUR' ? '€' : formData.currency === 'USD' ? '$' : 'R$'}
|
|
{parseFloat(formData.credit_limit).toFixed(2)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
<div className="col-12">
|
|
<small className="text-slate-400">Se guardará como:</small>
|
|
<div>
|
|
{destinationType === 'asset' && (
|
|
<span className="badge bg-success">
|
|
<i className="bi bi-graph-up me-1"></i>
|
|
Activo Financiero
|
|
</span>
|
|
)}
|
|
{destinationType === 'liability' && (
|
|
<span className="badge bg-danger">
|
|
<i className="bi bi-graph-down me-1"></i>
|
|
Pasivo (Deuda)
|
|
</span>
|
|
)}
|
|
{destinationType === 'account' && (
|
|
<span className="badge bg-primary">
|
|
<i className="bi bi-wallet2 me-1"></i>
|
|
Cuenta Estándar
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
<div className={`modal-footer border-0 ${isMobile ? 'flex-column' : ''}`}>
|
|
{isMobile ? (
|
|
<>
|
|
{step === getTotalSteps() && (
|
|
<button
|
|
type="button"
|
|
className="btn btn-primary w-100 mb-2"
|
|
onClick={handleSubmit}
|
|
disabled={loading || !validateStep()}
|
|
>
|
|
{loading ? (
|
|
<>
|
|
<span className="spinner-border spinner-border-sm me-2"></span>
|
|
Guardando...
|
|
</>
|
|
) : (
|
|
<>
|
|
<i className="bi bi-check-lg me-1"></i>
|
|
{isEditMode ? 'Guardar Cambios' : 'Crear Cuenta'}
|
|
</>
|
|
)}
|
|
</button>
|
|
)}
|
|
<div className="d-flex gap-2 w-100">
|
|
{step > 1 && (
|
|
<button type="button" className="btn btn-outline-secondary flex-fill" onClick={prevStep}>
|
|
<i className="bi bi-arrow-left me-1"></i>
|
|
Anterior
|
|
</button>
|
|
)}
|
|
{step < getTotalSteps() && (
|
|
<button
|
|
type="button"
|
|
className="btn btn-primary flex-fill"
|
|
onClick={nextStep}
|
|
disabled={!validateStep()}
|
|
>
|
|
Siguiente
|
|
<i className="bi bi-arrow-right ms-1"></i>
|
|
</button>
|
|
)}
|
|
<button type="button" className="btn btn-outline-secondary flex-fill" onClick={onClose}>
|
|
Cancelar
|
|
</button>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<>
|
|
<button type="button" className="btn btn-secondary" onClick={onClose}>
|
|
Cancelar
|
|
</button>
|
|
{step > 1 && (
|
|
<button type="button" className="btn btn-outline-light" onClick={prevStep}>
|
|
<i className="bi bi-arrow-left me-1"></i>
|
|
Anterior
|
|
</button>
|
|
)}
|
|
{step < getTotalSteps() ? (
|
|
<button
|
|
type="button"
|
|
className="btn btn-primary"
|
|
onClick={nextStep}
|
|
disabled={!validateStep()}
|
|
>
|
|
Siguiente
|
|
<i className="bi bi-arrow-right ms-1"></i>
|
|
</button>
|
|
) : (
|
|
<button
|
|
type="button"
|
|
className="btn btn-success"
|
|
onClick={handleSubmit}
|
|
disabled={loading || !validateStep()}
|
|
>
|
|
{loading ? (
|
|
<>
|
|
<span className="spinner-border spinner-border-sm me-2"></span>
|
|
Guardando...
|
|
</>
|
|
) : (
|
|
<>
|
|
<i className="bi bi-check-lg me-1"></i>
|
|
{isEditMode ? 'Guardar Cambios' : 'Crear Cuenta'}
|
|
</>
|
|
)}
|
|
</button>
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AccountWizard;
|