File size: 17,685 Bytes
3e4cfcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Loan Calculator</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        /* Custom scrollbar for schedule */
        .schedule-container::-webkit-scrollbar {
            width: 6px;
            height: 6px;
        }
        .schedule-container::-webkit-scrollbar-track {
            background: #f1f1f1;
        }
        .schedule-container::-webkit-scrollbar-thumb {
            background: #888;
            border-radius: 3px;
        }
        .schedule-container::-webkit-scrollbar-thumb:hover {
            background: #555;
        }
        
        /* Animation for results */
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .fade-in {
            animation: fadeIn 0.5s ease-out forwards;
        }
    </style>
</head>
<body class="bg-gray-100 min-h-screen">
    <div class="flex items-center justify-center min-h-screen">
        <div class="w-full max-w-2xl mx-4">
            <div class="bg-white rounded-xl shadow-xl overflow-hidden">
                <div class="text-center p-6 bg-indigo-700 text-white">
                    <h1 class="text-3xl font-bold mb-2">Loan Calculator</h1>
                    <p class="opacity-90">Calculate your EMI and payment schedule</p>
                </div>

                <div class="p-6">
                <div class="mb-6">
                    <label for="loanAmount" class="block text-gray-700 font-medium mb-2">Loan Amount ($)</label>
                    <div class="relative">
                        <span class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500">$</span>
                        <input type="number" id="loanAmount" class="w-full pl-8 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="10,000" min="1">
                    </div>
                </div>

                <div class="mb-6">
                    <label for="interestRate" class="block text-gray-700 font-medium mb-2">Interest Rate (% p.a.)</label>
                    <div class="relative">
                        <span class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500">%</span>
                        <input type="number" id="interestRate" class="w-full pl-8 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="8.5" step="0.01" min="0">
                    </div>
                </div>

                <div class="mb-6">
                    <label for="loanTerm" class="block text-gray-700 font-medium mb-2">Loan Term</label>
                    <div class="flex gap-4">
                        <div class="flex-1">
                            <input type="number" id="loanTerm" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="5" min="1">
                        </div>
                        <select id="termType" class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
                            <option value="years">Years</option>
                            <option value="months">Months</option>
                        </select>
                    </div>
                </div>

                <div class="mb-6">
                    <label class="block text-gray-700 font-medium mb-2">Payment Type</label>
                    <div class="grid grid-cols-2 gap-3">
                        <button id="emiBtn" class="payment-type-btn bg-indigo-600 text-white py-2 px-4 rounded-lg shadow-sm hover:bg-indigo-700 transition active:bg-indigo-800">
                            <i class="fas fa-calendar-alt mr-2"></i> EMI
                        </button>
                        <button id="otherBtn" class="payment-type-btn bg-gray-200 text-gray-700 py-2 px-4 rounded-lg shadow-sm hover:bg-gray-300 transition" disabled>
                            <i class="fas fa-clock mr-2"></i> Other (Coming Soon)
                        </button>
                    </div>
                </div>

                <button id="calculateBtn" class="w-full bg-indigo-600 text-white py-3 px-4 rounded-lg font-medium hover:bg-indigo-700 transition active:bg-indigo-800 shadow-md">
                    Calculate <i class="fas fa-calculator ml-2"></i>
                </button>
            </div>

                </div>
            </div>
        </div>
    </div>

    <!-- Results Modal -->
    <div id="resultsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 hidden z-50">
        <div class="bg-white rounded-xl shadow-xl w-full max-w-4xl max-h-[90vh] flex flex-col">
            <div class="p-6 bg-indigo-700 text-white flex justify-between items-center">
                <h2 class="text-2xl font-bold">Loan Calculation Results</h2>
                <button id="closeModal" class="text-white hover:text-gray-200 text-2xl">&times;</button>
            </div>
            
            <div class="p-6 overflow-y-auto flex-1">
                <div class="grid grid-cols-2 gap-4 mb-6">
                    <div class="bg-gray-50 p-4 rounded-lg">
                        <p class="text-sm text-gray-500">Monthly Payment</p>
                        <p id="monthlyPayment" class="text-2xl font-bold text-indigo-600">$0</p>
                    </div>
                    <div class="bg-gray-50 p-4 rounded-lg">
                        <p class="text-sm text-gray-500">Total Interest</p>
                        <p id="totalInterest" class="text-2xl font-bold text-indigo-600">$0</p>
                    </div>
                    <div class="bg-gray-50 p-4 rounded-lg">
                        <p class="text-sm text-gray-500">Total Payment</p>
                        <p id="totalPayment" class="text-2xl font-bold text-indigo-600">$0</p>
                    </div>
                    <div class="bg-gray-50 p-4 rounded-lg">
                        <p class="text-sm text-gray-500">Loan Term</p>
                        <p id="loanTermResult" class="text-2xl font-bold text-indigo-600">0 Months</p>
                    </div>
                </div>

                <div class="border-t pt-4">
                    <div class="flex justify-between items-center mb-4">
                        <h3 class="text-lg font-semibold text-gray-800">Payment Schedule</h3>
                        <button id="downloadBtn" class="text-indigo-600 hover:text-indigo-800 flex items-center">
                            <i class="fas fa-download mr-1"></i> Export
                        </button>
                    </div>
                    <div class="schedule-container max-h-96 overflow-y-auto">
                        <table class="w-full text-sm">
                            <thead class="sticky top-0 bg-gray-100">
                                <tr class="text-left text-gray-600 border-b">
                                    <th class="py-2 px-3">#</th>
                                    <th class="py-2 px-3">Payment</th>
                                    <th class="py-2 px-3">Principal</th>
                                    <th class="py-2 px-3">Interest</th>
                                    <th class="py-2 px-3">Balance</th>
                                </tr>
                            </thead>
                            <tbody id="scheduleBody" class="divide-y divide-gray-200">
                                <!-- Schedule will be populated here -->
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const calculateBtn = document.getElementById('calculateBtn');
            const emiBtn = document.getElementById('emiBtn');
            const otherBtn = document.getElementById('otherBtn');
            const resultsSection = document.getElementById('resultsSection');
            const downloadBtn = document.getElementById('downloadBtn');

            // Format currency
            const formatCurrency = (amount) => {
                return new Intl.NumberFormat('en-US', {
                    style: 'currency',
                    currency: 'USD',
                    minimumFractionDigits: 2
                }).format(amount);
            };

            // Calculate EMI
            const calculateEMI = (principal, annualRate, termYears, termType) => {
                let termMonths;
                if (termType === 'years') {
                    termMonths = termYears * 12;
                } else {
                    termMonths = termYears;
                }
                
                const monthlyRate = annualRate / 100 / 12;
                const emi = principal * monthlyRate * Math.pow(1 + monthlyRate, termMonths) / (Math.pow(1 + monthlyRate, termMonths) - 1);
                
                return {
                    emi: emi,
                    termMonths: termMonths,
                    totalPayment: emi * termMonths,
                    totalInterest: (emi * termMonths) - principal
                };
            };

            // Generate payment schedule
            const generateSchedule = (principal, annualRate, termMonths, emi) => {
                const monthlyRate = annualRate / 100 / 12;
                let balance = principal;
                const schedule = [];
                
                for (let i = 1; i <= termMonths; i++) {
                    const interest = balance * monthlyRate;
                    const principalPayment = emi - interest;
                    balance -= principalPayment;
                    
                    // Ensure balance doesn't go negative due to rounding
                    if (i === termMonths && Math.abs(balance) < 0.01) {
                        balance = 0;
                    }
                    
                    schedule.push({
                        month: i,
                        payment: emi,
                        principal: principalPayment,
                        interest: interest,
                        balance: balance > 0 ? balance : 0
                    });
                }
                
                return schedule;
            };

            // Modal elements
            const resultsModal = document.getElementById('resultsModal');
            const closeModal = document.getElementById('closeModal');

            // Close modal handler
            closeModal.addEventListener('click', function() {
                resultsModal.classList.add('hidden');
            });

            // Close modal when clicking outside
            resultsModal.addEventListener('click', function(e) {
                if (e.target === resultsModal) {
                    resultsModal.classList.add('hidden');
                }
            });

            // Calculate button click handler
            calculateBtn.addEventListener('click', function() {
                const loanAmount = parseFloat(document.getElementById('loanAmount').value);
                const interestRate = parseFloat(document.getElementById('interestRate').value);
                const loanTerm = parseFloat(document.getElementById('loanTerm').value);
                const termType = document.getElementById('termType').value;
                
                // Validate inputs
                if (isNaN(loanAmount) || isNaN(interestRate) || isNaN(loanTerm) || loanAmount <= 0 || loanTerm <= 0) {
                    alert('Please enter valid values for all fields');
                    return;
                }
                
                // Calculate EMI
                const result = calculateEMI(loanAmount, interestRate, loanTerm, termType);
                
                // Update summary
                document.getElementById('monthlyPayment').textContent = formatCurrency(result.emi);
                document.getElementById('totalInterest').textContent = formatCurrency(result.totalInterest);
                document.getElementById('totalPayment').textContent = formatCurrency(result.totalPayment);
                document.getElementById('loanTermResult').textContent = `${result.termMonths} Months`;
                
                // Generate and display schedule
                const schedule = generateSchedule(loanAmount, interestRate, result.termMonths, result.emi);
                const scheduleBody = document.getElementById('scheduleBody');
                scheduleBody.innerHTML = '';
                
                schedule.forEach((payment, index) => {
                    const row = document.createElement('tr');
                    row.className = index % 2 === 0 ? 'bg-white' : 'bg-gray-50';
                    row.innerHTML = `
                        <td class="py-2 px-3">${payment.month}</td>
                        <td class="py-2 px-3">${formatCurrency(payment.payment)}</td>
                        <td class="py-2 px-3">${formatCurrency(payment.principal)}</td>
                        <td class="py-2 px-3">${formatCurrency(payment.interest)}</td>
                        <td class="py-2 px-3">${formatCurrency(payment.balance)}</td>
                    `;
                    scheduleBody.appendChild(row);
                });
                
                // Show modal with results
                resultsModal.classList.remove('hidden');
            });

            // Payment type buttons
            emiBtn.addEventListener('click', function() {
                emiBtn.classList.remove('bg-gray-200', 'text-gray-700');
                emiBtn.classList.add('bg-indigo-600', 'text-white');
                otherBtn.classList.remove('bg-indigo-600', 'text-white');
                otherBtn.classList.add('bg-gray-200', 'text-gray-700');
            });

            otherBtn.addEventListener('click', function() {
                alert('Other payment types coming soon! Currently only EMI is available.');
            });

            // Export schedule
            downloadBtn.addEventListener('click', function() {
                const loanAmount = document.getElementById('loanAmount').value;
                const interestRate = document.getElementById('interestRate').value;
                const loanTerm = document.getElementById('loanTerm').value;
                const termType = document.getElementById('termType').value;
                
                if (!resultsSection.classList.contains('hidden')) {
                    // Create CSV content
                    let csv = 'Payment #,Payment,Principal,Interest,Balance\n';
                    const rows = document.querySelectorAll('#scheduleBody tr');
                    
                    rows.forEach(row => {
                        const cols = row.querySelectorAll('td');
                        const rowData = [];
                        
                        cols.forEach(col => {
                            // Remove currency symbols and commas for CSV
                            const text = col.textContent.replace(/[$,]/g, '');
                            rowData.push(text);
                        });
                        
                        csv += rowData.join(',') + '\n';
                    });
                    
                    // Create download link
                    const blob = new Blob([csv], { type: 'text/csv' });
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.setAttribute('hidden', '');
                    a.setAttribute('href', url);
                    a.setAttribute('download', `loan_schedule_${loanAmount}_${interestRate}_${loanTerm}${termType === 'years' ? 'y' : 'm'}.csv`);
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                } else {
                    alert('Please calculate a loan first');
                }
            });

            // Add animation to results when they appear
            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        entry.target.classList.add('fade-in');
                    }
                });
            }, { threshold: 0.1 });

            document.querySelectorAll('#resultsSection > div').forEach(el => {
                observer.observe(el);
            });
        });
    </script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=sombochea/loan-calculator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>