11import React , { useState , useEffect } from 'react' ;
22import DynamicInputs from './DynamicInputs' ;
3- import * as Calc from '../utils/financialCalculation ' ; // Importa todas as funções de cálculo
3+ import * as Calc from '../utils/financialCalculations ' ; // Importa todas as funções de cálculo
44
55const CalculatorForm = ( { selectedOption, onOptionChange, selicRate, ipcaRate, setResults } ) => {
66 // Estado interno para os inputs do formulário
77 const [ formInputs , setFormInputs ] = useState ( { } ) ;
8- const [ isJurosVisible , setIsJurosVisible ] = useState ( false ) ;
8+ const [ isJurosVisible , setIsJurosVisible ] = useState ( false ) ; // Para controlar a visibilidade dos juros na Opção 1
99
1010 // Limpa o estado dos inputs quando a opção principal muda
1111 useEffect ( ( ) => {
1212 setFormInputs ( { } ) ;
13+ setIsJurosVisible ( false ) ; // Reseta a visibilidade dos juros
1314 } , [ selectedOption ] ) ;
1415
16+ // Lida com a mudança em qualquer input do formulário
1517 const handleInputChange = ( event ) => {
1618 const { id, value, type, checked } = event . target ;
1719 setFormInputs ( prevInputs => ( {
@@ -72,29 +74,21 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
7274 // Elas leem do estado do formulário e usam as funções do módulo `financialCalculations`.
7375
7476 function calculateOption1 ( inputs , selicRate , ipcaRate ) {
75- const valorTotal = parseFloat ( inputs . valorTotal ) ;
76- const parcelas = parseInt ( inputs . parcelas ) ;
77- const descontoVista = parseFloat ( inputs . descontoVista ) / 100 || 0 ;
77+ const valorTotal = Calc . getNumericInputValue ( inputs , " valorTotal" ) ;
78+ const parcelas = Calc . getIntInputValue ( inputs , " parcelas" ) ;
79+ const descontoVista = Calc . getNumericInputValue ( inputs , " descontoVista" ) / 100 || 0 ;
7880 const temJurosParcelado = inputs . temJurosParcelado === 'S' ;
79- const tipoTaxa = inputs . rendimentoTipoTaxa ;
80- const valorTaxa = parseFloat ( inputs . rendimentoValorTaxa ) ;
81- const considerarIR = inputs . rendimentoConsiderarIR === 'S' ;
8281
8382 let valorVista = valorTotal * ( 1 - descontoVista ) ;
8483 let valorParceladoComJuros = valorTotal ;
8584
8685 if ( temJurosParcelado ) {
8786 const tipoJurosParcelado = inputs . tipoJurosParcelado ;
88- const taxaJurosParcelado = parseFloat ( inputs . taxaJurosParcelado ) / 100 ;
87+ const taxaJurosParcelado = Calc . getNumericInputValue ( inputs , " taxaJurosParcelado" ) / 100 ;
8988 valorParceladoComJuros = Calc . calcularValorParceladoComJuros ( valorTotal , parcelas , taxaJurosParcelado , tipoJurosParcelado ) ;
9089 }
9190
92- const valorParcela = valorParceladoComJuros / parcelas ;
93- const taxaRendimentoAjustada = Calc . ajustarTaxaParaIR (
94- Calc . getConvertedMonthlyRate ( tipoTaxa , valorTaxa , selicRate , ipcaRate , inputs . rendimentoIndiceBase ) ,
95- parcelas ,
96- considerarIR ? 'S' : 'N'
97- ) ;
91+ const { taxaMensal : taxaRendimentoAjustada , considerarIR : irConsiderado } = getAdjustedYieldRateFromInputs ( 'rendimento' , inputs , parcelas , selicRate , ipcaRate ) ;
9892
9993 const { ganho : rendimentosAcumulados , simulacaoDetalhada } = Calc . simularRendimento ( parcelas , valorParcela , taxaRendimentoAjustada ) ;
10094 const valorEfetivoParcelado = valorParceladoComJuros - rendimentosAcumulados ;
@@ -104,7 +98,7 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
10498 <p>Valor total da compra: R$ ${ valorTotal . toFixed ( 2 ) } </p>
10599 <p>Valor pagando à vista (com desconto): R$ ${ valorVista . toFixed ( 2 ) } </p>
106100 <p>Valor pagando parcelado (com juros, se houver): R$ ${ valorParceladoComJuros . toFixed ( 2 ) } </p>
107- <p>Taxa de rendimento utilizada (após IR${ considerarIR ? ' SIM' : ' NÃO' } ): ${ ( taxaRendimentoAjustada * 100 ) . toFixed ( 4 ) } % ao mês</p>
101+ <p>Taxa de rendimento utilizada (após IR${ irConsiderado === 'S' ? ' SIM' : ' NÃO' } ): ${ ( taxaRendimentoAjustada * 100 ) . toFixed ( 4 ) } % ao mês</p>
108102 <p>Rendimentos acumulados (se investir o que não foi gasto à vista): R$ ${ rendimentosAcumulados . toFixed ( 2 ) } </p>
109103 <p>Valor efetivo pago parcelando (descontando rendimentos): R$ ${ valorEfetivoParcelado . toFixed ( 2 ) } </p>
110104 ${ simulacaoDetalhada }
@@ -113,27 +107,21 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
113107 }
114108
115109 function calculateOption2 ( inputs , selicRate , ipcaRate ) {
116- const valorVista = parseFloat ( inputs . valorVista ) ;
117- const parcelas = parseInt ( inputs . parcelas ) ;
118- const valorParcela = parseFloat ( inputs . valorParcela ) ;
119- const tipoTaxa = inputs . rendimentoTipoTaxa ;
120- const valorTaxa = parseFloat ( inputs . rendimentoValorTaxa ) ;
121- const considerarIR = inputs . rendimentoConsiderarIR === 'S' ;
110+ const valorVista = Calc . getNumericInputValue ( inputs , "valorVista" ) ;
111+ const parcelas = Calc . getIntInputValue ( inputs , "parcelas" ) ;
112+ const valorParcela = Calc . getNumericInputValue ( inputs , "valorParcela" ) ;
122113
123114 const totalParcelado = parcelas * valorParcela ;
124- const taxaRendimentoAjustada = Calc . ajustarTaxaParaIR (
125- Calc . getConvertedMonthlyRate ( tipoTaxa , valorTaxa , selicRate , ipcaRate , inputs . rendimentoIndiceBase ) ,
126- parcelas ,
127- considerarIR ? 'S' : 'N'
128- ) ;
115+ const { taxaMensal : taxaRendimentoAjustada , considerarIR : irConsiderado } = getAdjustedYieldRateFromInputs ( 'rendimento' , inputs , parcelas , selicRate , ipcaRate ) ;
116+
129117 const { ganho : rendimentosAcumulados , simulacaoDetalhada } = Calc . simularRendimento ( parcelas , valorParcela , taxaRendimentoAjustada ) ;
130118 const valorEfetivoParcelado = totalParcelado - rendimentosAcumulados ;
131119
132120 return `
133121 <h3>[2] À Vista vs. Parcelas:</h3>
134122 <p>Valor pagando à vista: R$ ${ valorVista . toFixed ( 2 ) } </p>
135123 <p>Valor pagando parcelado: R$ ${ totalParcelado . toFixed ( 2 ) } </p>
136- <p>Taxa de rendimento utilizada (após IR${ considerarIR ? ' SIM' : ' NÃO' } ): ${ ( taxaRendimentoAjustada * 100 ) . toFixed ( 4 ) } % ao mês</p>
124+ <p>Taxa de rendimento utilizada (após IR${ irConsiderado === 'S' ? ' SIM' : ' NÃO' } ): ${ ( taxaRendimentoAjustada * 100 ) . toFixed ( 4 ) } % ao mês</p>
137125 <p>Rendimentos acumulados (se investir o que não foi gasto à vista): R$ ${ rendimentosAcumulados . toFixed ( 2 ) } </p>
138126 <p>Valor efetivo pago parcelando (descontando rendimentos): R$ ${ valorEfetivoParcelado . toFixed ( 2 ) } </p>
139127 ${ simulacaoDetalhada }
@@ -142,20 +130,13 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
142130 }
143131
144132 function calculateOption3 ( inputs , selicRate , ipcaRate ) {
145- const entrada = parseFloat ( inputs . entrada ) ;
146- const parcelas = parseInt ( inputs . parcelas ) ;
147- const valorParcela = parseFloat ( inputs . valorParcela ) ;
148- const valorVista = parseFloat ( inputs . valorVista ) ;
133+ const entrada = Calc . getNumericInputValue ( inputs , " entrada" ) ;
134+ const parcelas = Calc . getIntInputValue ( inputs , " parcelas" ) ;
135+ const valorParcela = Calc . getNumericInputValue ( inputs , " valorParcela" ) ;
136+ const valorVista = Calc . getNumericInputValue ( inputs , " valorVista" ) ;
149137 const totalParcelado = entrada + parcelas * valorParcela ;
150- const tipoTaxa = inputs . rendimentoTipoTaxa ;
151- const valorTaxa = parseFloat ( inputs . rendimentoValorTaxa ) ;
152- const considerarIR = inputs . rendimentoConsiderarIR === 'S' ;
153-
154- const taxaRendimentoAjustada = Calc . ajustarTaxaParaIR (
155- Calc . getConvertedMonthlyRate ( tipoTaxa , valorTaxa , selicRate , ipcaRate , inputs . rendimentoIndiceBase ) ,
156- parcelas ,
157- considerarIR ? 'S' : 'N'
158- ) ;
138+
139+ const { taxaMensal : taxaRendimentoAjustada , considerarIR : irConsiderado } = getAdjustedYieldRateFromInputs ( 'rendimento' , inputs , parcelas , selicRate , ipcaRate ) ;
159140
160141 let saldoInvestimento = valorVista ;
161142 let rendimentoTotalAcumulado = 0 ;
@@ -169,7 +150,7 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
169150 rendimentoTotalAcumulado += rendimentoMes ;
170151
171152 let valorPagoNoMes = valorParcela ;
172- if ( i === 1 ) {
153+ if ( i === 1 ) { // A entrada é paga no mês 1
173154 valorPagoNoMes += entrada ;
174155 }
175156 saldoInvestimento -= valorPagoNoMes ;
@@ -187,7 +168,7 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
187168 <p>Número de parcelas: ${ parcelas } </p>
188169 <p>Total nominal parcelado (entrada + parcelas): R$ ${ totalParcelado . toFixed ( 2 ) } </p>
189170 <p>Valor da compra à vista: R$ ${ valorVista . toFixed ( 2 ) } </p>
190- <p>Taxa de rendimento utilizada (após IR${ considerarIR ? ' SIM' : ' NÃO' } ): ${ ( taxaRendimentoAjustada * 100 ) . toFixed ( 4 ) } % ao mês</p>
171+ <p>Taxa de rendimento utilizada (após IR${ irConsiderado === 'S' ? ' SIM' : ' NÃO' } ): ${ ( taxaRendimentoAjustada * 100 ) . toFixed ( 4 ) } % ao mês</p>
191172 <p>Rendimento total gerado pelo investimento do valor à vista: R$ ${ rendimentoTotalAcumulado . toFixed ( 2 ) } </p>
192173 <p>Saldo final do investimento (após pagar entrada e parcelas): R$ ${ saldoInvestimento . toFixed ( 2 ) } </p>
193174 <p>Custo efetivo do parcelamento com entrada (considerando rendimentos): R$ ${ valorEfetivoParceladoComEntrada . toFixed ( 2 ) } </p>
@@ -197,12 +178,14 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
197178 }
198179
199180 function calculateOption4 ( inputs ) {
200- const parcelas1 = parseInt ( inputs . parcelas1 ) ;
201- const valorParcela1 = parseFloat ( inputs . valorParcela1 ) ;
202- const parcelas2 = parseInt ( inputs . parcelas2 ) ;
203- const valorParcela2 = parseFloat ( inputs . valorParcela2 ) ;
181+ const parcelas1 = Calc . getIntInputValue ( inputs , "parcelas1" ) ;
182+ const valorParcela1 = Calc . getNumericInputValue ( inputs , "valorParcela1" ) ;
183+ const parcelas2 = Calc . getIntInputValue ( inputs , "parcelas2" ) ;
184+ const valorParcela2 = Calc . getNumericInputValue ( inputs , "valorParcela2" ) ;
185+
204186 const total1 = parcelas1 * valorParcela1 ;
205187 const total2 = parcelas2 * valorParcela2 ;
188+
206189 return `
207190 <h3>[4] Comparar Duas Opções de Parcelamento:</h3>
208191 <p>Total da primeira opção: R$ ${ total1 . toFixed ( 2 ) } </p>
@@ -212,29 +195,32 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
212195 }
213196
214197 function calculateOption5 ( inputs ) {
215- const valorParcelaOriginal = parseFloat ( inputs . valorParcelaOriginal ) ;
216- const diasAtraso = parseInt ( inputs . diasAtraso ) ;
217- const multa = parseFloat ( inputs . multa ) / 100 ;
218- const jurosDiarios = parseFloat ( inputs . jurosDiarios ) / 100 ;
198+ const valorParcelaOriginal = Calc . getNumericInputValue ( inputs , "valorParcelaOriginal" ) ;
199+ const diasAtraso = Calc . getIntInputValue ( inputs , "diasAtraso" ) ;
200+ const multa = Calc . getNumericInputValue ( inputs , "multa" ) / 100 ;
201+ const jurosDiarios = Calc . getNumericInputValue ( inputs , "jurosDiarios" ) / 100 ;
202+
219203 const valorCorrigido = valorParcelaOriginal * ( 1 + multa + jurosDiarios * diasAtraso ) ;
204+
220205 return `
221206 <h3>[5] Impacto de Atrasos em Parcelas:</h3>
222207 <p>Valor com atraso: R$ ${ valorCorrigido . toFixed ( 2 ) } </p>
223208 ` ;
224209 }
225210
226211 function calculateOption6 ( inputs , selicRate , ipcaRate ) {
227- const parcelas = parseInt ( inputs . parcelas ) ;
228- const valorParcela = parseFloat ( inputs . valorParcela ) ;
229- const tipoTaxa = inputs . inflacaoTipoTaxa ;
230- const valorTaxa = parseFloat ( inputs . inflacaoValorTaxa ) ;
231-
232- const inflacaoMensalAjustada = Calc . getConvertedMonthlyRate ( tipoTaxa , valorTaxa , selicRate , ipcaRate , inputs . inflacaoIndiceBase ) ;
212+ const parcelas = Calc . getIntInputValue ( inputs , "parcelas" ) ;
213+ const valorParcela = Calc . getNumericInputValue ( inputs , "valorParcela" ) ;
233214
215+ // Para inflação, a função getAdjustedYieldRate com prefixo 'inflacao'
216+ // já retorna a taxa mensal que queremos usar como taxa de desconto/inflação.
217+ const { taxaMensal : inflacaoMensalAjustada } = getAdjustedYieldRateFromInputs ( 'inflacao' , inputs , parcelas , selicRate , ipcaRate ) ;
218+
234219 let valorTotalInflacao = 0 ;
235220 for ( let i = 1 ; i <= parcelas ; i ++ ) {
236221 valorTotalInflacao += valorParcela / Math . pow ( 1 + inflacaoMensalAjustada , i ) ;
237222 }
223+
238224 return `
239225 <h3>[6] Simulação com Inflação:</h3>
240226 <p>Valor de cada parcela: R$ ${ valorParcela . toFixed ( 2 ) } </p>
@@ -245,28 +231,30 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
245231 }
246232
247233 function calculateOption7 ( inputs , selicRate , ipcaRate ) {
248- const valorVista = parseFloat ( inputs . valorVista ) ;
249- const parcelas = parseInt ( inputs . parcelas ) ;
250- const valorParcela = parseFloat ( inputs . valorParcela ) ;
251- const tipoTaxa = inputs . investimentoTipoTaxa ;
252- const valorTaxa = parseFloat ( inputs . investimentoValorTaxa ) ;
253- const considerarIR = inputs . investimentoConsiderarIR === 'S' ;
234+ const valorVista = Calc . getNumericInputValue ( inputs , "valorVista" ) ;
235+ const parcelas = Calc . getIntInputValue ( inputs , "parcelas" ) ;
236+ const valorParcela = Calc . getNumericInputValue ( inputs , "valorParcela" ) ;
254237
255- const taxaInvestimentoAjustada = Calc . ajustarTaxaParaIR (
256- Calc . getConvertedMonthlyRate ( tipoTaxa , valorTaxa , selicRate , ipcaRate , inputs . investimentoIndiceBase ) ,
257- parcelas ,
258- considerarIR ? 'S' : 'N'
259- ) ;
238+ const { taxaMensal : taxaInvestimentoAjustada , considerarIR : irConsiderado } = getAdjustedYieldRateFromInputs ( 'investimento' , inputs , parcelas , selicRate , ipcaRate ) ;
260239
261240 let saldoInvestimento = valorVista ;
241+
262242 let tabelaDetalhada = '<p>Detalhes do Investimento:</p><table><thead><tr><th>Mês</th><th>Saldo Inicial (R$)</th><th>Rendimento (R$)</th><th>Parcela Paga (R$)</th><th>Saldo Final (R$)</th></tr></thead><tbody>' ;
263243
264244 for ( let i = 1 ; i <= parcelas ; i ++ ) {
265245 const rendimento = saldoInvestimento * taxaInvestimentoAjustada ;
266246 const saldoInicialMes = saldoInvestimento ;
247+
267248 saldoInvestimento += rendimento ;
268249 saldoInvestimento -= valorParcela ;
269- tabelaDetalhada += `<tr><td>${ i } </td><td>${ saldoInicialMes . toFixed ( 2 ) } </td><td>${ rendimento . toFixed ( 2 ) } </td><td>${ valorParcela . toFixed ( 2 ) } </td><td>${ saldoInvestimento . toFixed ( 2 ) } </td></tr>` ;
250+
251+ tabelaDetalhada += `<tr>
252+ <td>${ i } </td>
253+ <td>${ saldoInicialMes . toFixed ( 2 ) } </td>
254+ <td>${ rendimento . toFixed ( 2 ) } </td>
255+ <td>${ valorParcela . toFixed ( 2 ) } </td>
256+ <td>${ saldoInvestimento . toFixed ( 2 ) } </td>
257+ </tr>` ;
270258 }
271259 tabelaDetalhada += '</tbody></table>' ;
272260
@@ -275,13 +263,40 @@ const CalculatorForm = ({ selectedOption, onOptionChange, selicRate, ipcaRate, s
275263 <p>Valor da compra à vista: R$ ${ valorVista . toFixed ( 2 ) } </p>
276264 <p>Valor de cada parcela: R$ ${ valorParcela . toFixed ( 2 ) } </p>
277265 <p>Número de parcelas: ${ parcelas } </p>
278- <p>Taxa de investimento utilizada (após IR${ considerarIR ? ' SIM' : ' NÃO' } ): ${ ( taxaInvestimentoAjustada * 100 ) . toFixed ( 4 ) } % ao mês</p>
266+ <p>Taxa de investimento utilizada (após IR${ irConsiderado === 'S' ? ' SIM' : ' NÃO' } ): ${ ( taxaInvestimentoAjustada * 100 ) . toFixed ( 4 ) } % ao mês</p>
279267 <p>Saldo final se você investir o valor à vista e pagar em parcelas: R$ ${ saldoInvestimento . toFixed ( 2 ) } </p>
280268 ${ tabelaDetalhada }
281269 <strong>${ saldoInvestimento > 0 ? "Investir e parcelar é vantajoso (você termina com dinheiro extra)." : "Pagar à vista é mais seguro (evita dívidas ou perdas)." } </strong>
282270 ` ;
283271 }
284272
273+ /**
274+ * Helper para obter a taxa de rendimento convertida e ajustada para IR,
275+ * lendo os valores do objeto `inputs` do formulário.
276+ * @param {string } prefix - O prefixo dos IDs dos campos de taxa ('rendimento', 'inflacao', 'investimento').
277+ * @param {object } inputs - O objeto `formInputs` do estado do componente.
278+ * @param {number } numMeses - O número total de meses/parcelas.
279+ * @param {number } selicRate - A taxa SELIC atual.
280+ * @param {number } ipcaRate - A taxa IPCA atual.
281+ * @returns {{taxaMensal: number, considerarIR: string} } Objeto com a taxa mensal ajustada e se IR foi considerado ('S' ou 'N').
282+ */
283+ function getAdjustedYieldRateFromInputs ( prefix , inputs , numMeses , selicRate , ipcaRate ) {
284+ const tipoTaxa = inputs [ `${ prefix } TipoTaxa` ] ;
285+ const valorTaxa = inputs [ `${ prefix } ValorTaxa` ] ;
286+ const considerarIR = inputs [ `${ prefix } ConsiderarIR` ] || 'N' ; // Default 'N' se não houver ou não for selecionado
287+
288+ let indiceBase = '' ;
289+ if ( tipoTaxa === 'indice-percentual' ) {
290+ indiceBase = inputs [ `${ prefix } IndiceBase` ] ;
291+ }
292+
293+ let taxaMensalDecimal = Calc . getConvertedMonthlyRate ( tipoTaxa , valorTaxa , selicRate , ipcaRate , indiceBase ) ;
294+ taxaMensalDecimal = Calc . ajustarTaxaParaIR ( taxaMensalDecimal , numMeses , considerarIR ) ;
295+
296+ return { taxaMensal : taxaMensalDecimal , considerarIR : considerarIR } ;
297+ }
298+
299+
285300 return (
286301 < form id = "form-simulador" >
287302 < fieldset className = "form-section" >
0 commit comments