Migrate from Firebase to file-based storage system

- Remove Firebase dependency and all Firebase code
- Implement local file-based storage with encryption
- Create custom authentication system with password hashing
- Add API routes for auth (register/login) and data operations
- Create FileStorageService for server-side file I/O
- Add AuthService for client-side authentication wrapper
- Update all components to use new storage system
- Add comprehensive documentation (FILE_STORAGE.md, MIGRATION_SUMMARY.md)
- Improve security with AES-GCM encryption and SHA-256 password hashing
- Add ErrorBoundary component for better error handling
- Fix multiple bugs: date serialization, transaction deletion, envelope calculations
This commit is contained in:
Nate Emmert committed 2025-11-08 14:03:26 -05:00
1 parent 174b247c6d
commit 959249ab22
22 files changed
+1538 -1157

No files matched your search

+2 -48
View File
@@ -107,7 +107,7 @@ export default function GetPaid({ accounts, envelopes, onIncomeAdded, onAccountU
// Add the main paycheck transaction to the account
transactions.push({
id: `paycheck-${Date.now()}`,
id: crypto.randomUUID(),
amount: paycheckAmount,
description: description || 'Paycheck',
date: new Date(),
@@ -118,7 +118,7 @@ export default function GetPaid({ accounts, envelopes, onIncomeAdded, onAccountU
Object.entries(distribution).forEach(([envelopeId, allocatedAmount]) => {
if (allocatedAmount > 0) {
transactions.push({
id: `allocation-${envelopeId}-${Date.now()}`,
id: crypto.randomUUID(),
envelopeId,
amount: allocatedAmount,
description: `Paycheck allocation - ${envelopes.find(e => e.id === envelopeId)?.name}`,
@@ -374,52 +374,6 @@ export default function GetPaid({ accounts, envelopes, onIncomeAdded, onAccountU
</>
)}
{/* Default Amount */}
{selectedAccountId && (
<div>
<button
type="button"
onClick={() => setShowDefaultAmountField(!showDefaultAmountField)}
className="text-sm text-blue-600 hover:underline mb-2"
>
{showDefaultAmountField ? 'Hide' : 'Set'} Default Paycheck Amount
</button>
{showDefaultAmountField && (
<div className="bg-gray-50 rounded-lg p-4 mb-4">
<h4 className="font-medium text-gray-900 mb-3">Default Paycheck Amount</h4>
<div className="flex items-center space-x-2">
<input
type="number"
step="0.01"
value={defaultAmountInput}
onChange={(e) => setDefaultAmountInput(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="0.00"
/>
<button
type="button"
onClick={handleSetDefaultAmount}
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
>
Set Default
</button>
</div>
<div className="mt-3">
<button
type="button"
onClick={handleUseDefaultAmount}
className="w-full px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700"
>
Use Default Amount
</button>
</div>
</div>
)}
</div>
)}
{/* Actions */}
<div className="flex justify-end space-x-3 pt-4 border-t">
<button