UNPKG

lumpsum-sip-calculator

Version:

A reusable Lumpsum and SIP calculator component with customizable theming

244 lines (234 loc) 12.6 kB
'use strict'; var React = require('react'); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var defaultTheme = { primary: "#0C875E", secondary: "#108E66", accent: "#D6F5E8", background: "#FAFAFA", textPrimary: "#333333", textSecondary: "#666666" }; var LumpsumSIPCalculator = function (_a) { var _b = _a.theme, theme = _b === void 0 ? {} : _b; var calculatorTheme = __assign(__assign({}, defaultTheme), theme); var _c = React.useState({ lumpsumPrincipal: "", lumpsumRate: "", sipAmount: "", sipRate: "", years: "", }), inputs = _c[0], setInputs = _c[1]; var _d = React.useState("Annually"), lumpsumFrequency = _d[0], setLumpsumFrequency = _d[1]; var _e = React.useState({}), errors = _e[0], setErrors = _e[1]; var _f = React.useState(null), results = _f[0], setResults = _f[1]; var _g = React.useState(false), isCalculating = _g[0], setIsCalculating = _g[1]; var _h = React.useState(null), calculationTimer = _h[0], setCalculationTimer = _h[1]; React.useEffect(function () { return function () { if (calculationTimer) clearTimeout(calculationTimer); }; }, [calculationTimer]); var handleInputChange = function (e) { var _a = e.target, name = _a.name, value = _a.value; setInputs(function (prev) { var _a; return (__assign(__assign({}, prev), (_a = {}, _a[name] = value, _a))); }); }; var handleFrequencyChange = function (e) { setLumpsumFrequency(e.target.value); }; var validateInputs = function () { var newErrors = {}; var isValid = true; // Validate required fields Object.entries(inputs).forEach(function (_a) { var key = _a[0], value = _a[1]; if (!value) { newErrors[key] = 'This field is required'; isValid = false; } }); // Validate numeric ranges var numInputs = { lumpsumPrincipal: { min: 1, max: 1000000000 }, lumpsumRate: { min: 0, max: 100 }, sipAmount: { min: 1, max: 1000000 }, sipRate: { min: 0, max: 100 }, years: { min: 1, max: 50 } }; Object.entries(numInputs).forEach(function (_a) { var key = _a[0], _b = _a[1], min = _b.min, max = _b.max; var value = parseFloat(inputs[key]); if (isNaN(value) || value < min || value > max) { newErrors[key] = "Value must be between ".concat(min, " and ").concat(max); isValid = false; } }); setErrors(newErrors); return isValid; }; var handleCalculate = function () { if (!validateInputs()) return; setIsCalculating(true); setResults(null); var P_lump = parseFloat(inputs.lumpsumPrincipal); var r_lump_annual = parseFloat(inputs.lumpsumRate) / 100; var nMap = { Annually: 1, "Semi-Annually": 2, Quarterly: 4, Monthly: 12 }; var n_lump_compound = nMap[lumpsumFrequency]; var t = parseFloat(inputs.years); var P_sip = parseFloat(inputs.sipAmount); var r_sip_annual = parseFloat(inputs.sipRate) / 100; var r_sip_monthly = r_sip_annual / 12; var n_sip_months = t * 12; var timer = setTimeout(function () { // Lumpsum Calculation var lumpsumFutureValue = P_lump * Math.pow(1 + r_lump_annual / n_lump_compound, n_lump_compound * t); // SIP Calculation var sipFutureValue = P_sip * ((Math.pow(1 + r_sip_monthly, n_sip_months) - 1) / r_sip_monthly) * (1 + r_sip_monthly); var lumpsumInvested = P_lump; var sipInvested = P_sip * n_sip_months; var totalInvested = lumpsumInvested + sipInvested; var combinedFutureValue = lumpsumFutureValue + sipFutureValue; var totalWealthGained = combinedFutureValue - totalInvested; setResults({ lumpsumFutureValue: lumpsumFutureValue, sipFutureValue: sipFutureValue, lumpsumInvested: lumpsumInvested, sipInvested: sipInvested, totalInvested: totalInvested, combinedFutureValue: combinedFutureValue, totalWealthGained: totalWealthGained }); setIsCalculating(false); }, 500); setCalculationTimer(timer); }; return (React.createElement("div", { style: { backgroundColor: calculatorTheme.background, color: calculatorTheme.textPrimary, padding: '20px', borderRadius: '8px', maxWidth: '800px', margin: '0 auto' } }, React.createElement("h2", { style: { color: calculatorTheme.primary } }, "Lumpsum + SIP Calculator"), React.createElement("div", { style: { marginBottom: '20px' } }, React.createElement("div", { style: { marginBottom: '15px' } }, React.createElement("label", null, "Lumpsum Investment (\u20B9)"), React.createElement("input", { type: "number", name: "lumpsumPrincipal", value: inputs.lumpsumPrincipal, onChange: handleInputChange, style: { width: '100%', padding: '8px', border: "1px solid ".concat(errors.lumpsumPrincipal ? 'red' : calculatorTheme.accent), borderRadius: '4px' } }), errors.lumpsumPrincipal && (React.createElement("span", { style: { color: 'red', fontSize: '12px' } }, errors.lumpsumPrincipal))), React.createElement("div", { style: { marginBottom: '15px' } }, React.createElement("label", null, "Lumpsum Annual Return (%)"), React.createElement("input", { type: "number", name: "lumpsumRate", value: inputs.lumpsumRate, onChange: handleInputChange, style: { width: '100%', padding: '8px', border: "1px solid ".concat(errors.lumpsumRate ? 'red' : calculatorTheme.accent), borderRadius: '4px' } }), errors.lumpsumRate && (React.createElement("span", { style: { color: 'red', fontSize: '12px' } }, errors.lumpsumRate))), React.createElement("div", { style: { marginBottom: '15px' } }, React.createElement("label", null, "Compounding Frequency"), React.createElement("select", { value: lumpsumFrequency, onChange: handleFrequencyChange, style: { width: '100%', padding: '8px', border: "1px solid ".concat(calculatorTheme.accent), borderRadius: '4px' } }, React.createElement("option", { value: "Annually" }, "Annually"), React.createElement("option", { value: "Semi-Annually" }, "Semi-Annually"), React.createElement("option", { value: "Quarterly" }, "Quarterly"), React.createElement("option", { value: "Monthly" }, "Monthly"))), React.createElement("div", { style: { marginBottom: '15px' } }, React.createElement("label", null, "Monthly SIP Amount (\u20B9)"), React.createElement("input", { type: "number", name: "sipAmount", value: inputs.sipAmount, onChange: handleInputChange, style: { width: '100%', padding: '8px', border: "1px solid ".concat(errors.sipAmount ? 'red' : calculatorTheme.accent), borderRadius: '4px' } }), errors.sipAmount && (React.createElement("span", { style: { color: 'red', fontSize: '12px' } }, errors.sipAmount))), React.createElement("div", { style: { marginBottom: '15px' } }, React.createElement("label", null, "SIP Annual Return (%)"), React.createElement("input", { type: "number", name: "sipRate", value: inputs.sipRate, onChange: handleInputChange, style: { width: '100%', padding: '8px', border: "1px solid ".concat(errors.sipRate ? 'red' : calculatorTheme.accent), borderRadius: '4px' } }), errors.sipRate && (React.createElement("span", { style: { color: 'red', fontSize: '12px' } }, errors.sipRate))), React.createElement("div", { style: { marginBottom: '15px' } }, React.createElement("label", null, "Investment Duration (Years)"), React.createElement("input", { type: "number", name: "years", value: inputs.years, onChange: handleInputChange, style: { width: '100%', padding: '8px', border: "1px solid ".concat(errors.years ? 'red' : calculatorTheme.accent), borderRadius: '4px' } }), errors.years && (React.createElement("span", { style: { color: 'red', fontSize: '12px' } }, errors.years)))), React.createElement("button", { onClick: handleCalculate, disabled: isCalculating, style: { backgroundColor: calculatorTheme.primary, color: 'white', padding: '10px 20px', border: 'none', borderRadius: '4px', cursor: isCalculating ? 'not-allowed' : 'pointer', opacity: isCalculating ? 0.7 : 1 } }, isCalculating ? 'Calculating...' : 'Calculate'), results && (React.createElement("div", { style: { marginTop: '20px', padding: '20px', backgroundColor: calculatorTheme.accent, borderRadius: '4px' } }, React.createElement("h3", { style: { color: calculatorTheme.primary } }, "Results"), React.createElement("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px' } }, React.createElement("div", null, React.createElement("p", null, "Lumpsum Future Value: \u20B9", results.lumpsumFutureValue.toLocaleString()), React.createElement("p", null, "SIP Future Value: \u20B9", results.sipFutureValue.toLocaleString()), React.createElement("p", null, "Total Invested: \u20B9", results.totalInvested.toLocaleString())), React.createElement("div", null, React.createElement("p", null, "Combined Future Value: \u20B9", results.combinedFutureValue.toLocaleString()), React.createElement("p", null, "Total Wealth Gained: \u20B9", results.totalWealthGained.toLocaleString()))))))); }; exports.LumpsumSIPCalculator = LumpsumSIPCalculator; //# sourceMappingURL=index.js.map