mirror of
https://github.com/acedanger/finance.git
synced 2025-12-05 22:50:12 -08:00
Fix: Update button remaining disabled in transaction edit mode
This commit resolves an issue where the Update button in the transaction form would remain disabled when attempting to edit a transaction. The problem was in how the transactionStore was managing state updates during transaction editing. Key changes: - Enhanced startEditingTransaction function in transactionStore.ts to ensure proper reactivity - Added clean copy creation of transaction objects to avoid reference issues - Implemented a state update cycle with null value first to force reactivity - Added a small timeout to ensure state changes are properly detected by components The Transaction form now correctly enables the Update button when in edit mode, regardless of account selection state.
This commit is contained in:
61
prisma/migrations/20250505192354_initial/migration.sql
Normal file
61
prisma/migrations/20250505192354_initial/migration.sql
Normal file
@@ -0,0 +1,61 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AccountType" AS ENUM ('CHECKING', 'SAVINGS', 'CREDIT_CARD', 'INVESTMENT', 'OTHER');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AccountStatus" AS ENUM ('ACTIVE', 'CLOSED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TransactionStatus" AS ENUM ('PENDING', 'CLEARED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TransactionType" AS ENUM ('DEPOSIT', 'WITHDRAWAL', 'TRANSFER', 'UNSPECIFIED');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "accounts" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bankName" TEXT NOT NULL,
|
||||
"accountNumber" VARCHAR(6) NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"type" "AccountType" NOT NULL DEFAULT 'CHECKING',
|
||||
"status" "AccountStatus" NOT NULL DEFAULT 'ACTIVE',
|
||||
"currency" TEXT NOT NULL DEFAULT 'USD',
|
||||
"balance" DECIMAL(10,2) NOT NULL DEFAULT 0,
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "accounts_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "transactions" (
|
||||
"id" TEXT NOT NULL,
|
||||
"accountId" TEXT NOT NULL,
|
||||
"date" TIMESTAMP(3) NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"amount" DECIMAL(10,2) NOT NULL,
|
||||
"category" TEXT,
|
||||
"status" "TransactionStatus" NOT NULL DEFAULT 'CLEARED',
|
||||
"type" "TransactionType" NOT NULL DEFAULT 'UNSPECIFIED',
|
||||
"notes" TEXT,
|
||||
"tags" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "transactions_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "accounts_status_idx" ON "accounts"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "transactions_accountId_idx" ON "transactions"("accountId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "transactions_date_idx" ON "transactions"("date");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "transactions_category_idx" ON "transactions"("category");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "transactions" ADD CONSTRAINT "transactions_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "accounts"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
3
prisma/migrations/migration_lock.toml
Normal file
3
prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
||||
@@ -9,13 +9,66 @@ datasource db {
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model BankAccount {
|
||||
id Int @id @default(autoincrement())
|
||||
name String // e.g., "Checking Account", "Savings XYZ"
|
||||
bankName String // e.g., "Chase", "Wells Fargo"
|
||||
accountNumber String @unique // Consider encryption in a real app
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
model Account {
|
||||
id String @id @default(uuid())
|
||||
bankName String
|
||||
accountNumber String @db.VarChar(6) // Last 6 digits
|
||||
name String // Friendly name
|
||||
type AccountType @default(CHECKING)
|
||||
status AccountStatus @default(ACTIVE)
|
||||
currency String @default("USD")
|
||||
balance Decimal @default(0) @db.Decimal(10, 2)
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
transactions Transaction[]
|
||||
|
||||
@@map("bank_accounts") // Optional: specify table name in snake_case
|
||||
@@index([status])
|
||||
@@map("accounts")
|
||||
}
|
||||
|
||||
model Transaction {
|
||||
id String @id @default(uuid())
|
||||
accountId String
|
||||
account Account @relation(fields: [accountId], references: [id])
|
||||
date DateTime
|
||||
description String
|
||||
amount Decimal @db.Decimal(10, 2)
|
||||
category String?
|
||||
status TransactionStatus @default(CLEARED)
|
||||
type TransactionType @default(UNSPECIFIED)
|
||||
notes String?
|
||||
tags String? // Comma-separated values for tags
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([accountId])
|
||||
@@index([date])
|
||||
@@index([category])
|
||||
@@map("transactions")
|
||||
}
|
||||
|
||||
enum AccountType {
|
||||
CHECKING
|
||||
SAVINGS
|
||||
CREDIT_CARD
|
||||
INVESTMENT
|
||||
OTHER
|
||||
}
|
||||
|
||||
enum AccountStatus {
|
||||
ACTIVE
|
||||
CLOSED
|
||||
}
|
||||
|
||||
enum TransactionStatus {
|
||||
PENDING
|
||||
CLEARED
|
||||
}
|
||||
|
||||
enum TransactionType {
|
||||
DEPOSIT
|
||||
WITHDRAWAL
|
||||
TRANSFER
|
||||
UNSPECIFIED
|
||||
}
|
||||
87
prisma/seed.js
Normal file
87
prisma/seed.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('Starting database seeding...');
|
||||
|
||||
// Clear existing data
|
||||
await prisma.transaction.deleteMany({});
|
||||
await prisma.account.deleteMany({});
|
||||
|
||||
console.log('Cleared existing data');
|
||||
|
||||
// Create accounts
|
||||
const checkingAccount = await prisma.account.create({
|
||||
data: {
|
||||
bankName: 'First National Bank',
|
||||
accountNumber: '432198',
|
||||
name: 'Checking Account',
|
||||
type: 'CHECKING',
|
||||
balance: 2500.0,
|
||||
notes: 'Primary checking account',
|
||||
},
|
||||
});
|
||||
|
||||
const savingsAccount = await prisma.account.create({
|
||||
data: {
|
||||
bankName: 'First National Bank',
|
||||
accountNumber: '876543',
|
||||
name: 'Savings Account',
|
||||
type: 'SAVINGS',
|
||||
balance: 10000.0,
|
||||
notes: 'Emergency fund',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('Created accounts:', {
|
||||
checkingAccount: checkingAccount.id,
|
||||
savingsAccount: savingsAccount.id,
|
||||
});
|
||||
|
||||
// Create transactions
|
||||
const transactions = await Promise.all([
|
||||
prisma.transaction.create({
|
||||
data: {
|
||||
accountId: checkingAccount.id,
|
||||
date: new Date('2025-04-20'),
|
||||
description: 'Grocery Store',
|
||||
amount: -75.5,
|
||||
category: 'Groceries',
|
||||
type: 'WITHDRAWAL',
|
||||
},
|
||||
}),
|
||||
prisma.transaction.create({
|
||||
data: {
|
||||
accountId: checkingAccount.id,
|
||||
date: new Date('2025-04-21'),
|
||||
description: 'Salary Deposit',
|
||||
amount: 3000.0,
|
||||
category: 'Income',
|
||||
type: 'DEPOSIT',
|
||||
},
|
||||
}),
|
||||
prisma.transaction.create({
|
||||
data: {
|
||||
accountId: savingsAccount.id,
|
||||
date: new Date('2025-04-22'),
|
||||
description: 'Transfer to Savings',
|
||||
amount: 500.0,
|
||||
category: 'Transfer',
|
||||
type: 'TRANSFER',
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log(`Created ${transactions.length} transactions`);
|
||||
console.log('Seeding completed successfully!');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('Error during seeding:', e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
87
prisma/seed.ts
Normal file
87
prisma/seed.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('Starting database seeding...');
|
||||
|
||||
// Clear existing data
|
||||
await prisma.transaction.deleteMany({});
|
||||
await prisma.account.deleteMany({});
|
||||
|
||||
console.log('Cleared existing data');
|
||||
|
||||
// Create accounts
|
||||
const checkingAccount = await prisma.account.create({
|
||||
data: {
|
||||
bankName: 'First National Bank',
|
||||
accountNumber: '432198',
|
||||
name: 'Checking Account',
|
||||
type: 'CHECKING',
|
||||
balance: 2500.0,
|
||||
notes: 'Primary checking account',
|
||||
},
|
||||
});
|
||||
|
||||
const savingsAccount = await prisma.account.create({
|
||||
data: {
|
||||
bankName: 'First National Bank',
|
||||
accountNumber: '876543',
|
||||
name: 'Savings Account',
|
||||
type: 'SAVINGS',
|
||||
balance: 10000.0,
|
||||
notes: 'Emergency fund',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('Created accounts:', {
|
||||
checkingAccount: checkingAccount.id,
|
||||
savingsAccount: savingsAccount.id,
|
||||
});
|
||||
|
||||
// Create transactions
|
||||
const transactions = await Promise.all([
|
||||
prisma.transaction.create({
|
||||
data: {
|
||||
accountId: checkingAccount.id,
|
||||
date: new Date('2025-04-20'),
|
||||
description: 'Grocery Store',
|
||||
amount: -75.5,
|
||||
category: 'Groceries',
|
||||
type: 'WITHDRAWAL',
|
||||
},
|
||||
}),
|
||||
prisma.transaction.create({
|
||||
data: {
|
||||
accountId: checkingAccount.id,
|
||||
date: new Date('2025-04-21'),
|
||||
description: 'Salary Deposit',
|
||||
amount: 3000.0,
|
||||
category: 'Income',
|
||||
type: 'DEPOSIT',
|
||||
},
|
||||
}),
|
||||
prisma.transaction.create({
|
||||
data: {
|
||||
accountId: savingsAccount.id,
|
||||
date: new Date('2025-04-22'),
|
||||
description: 'Transfer to Savings',
|
||||
amount: 500.0,
|
||||
category: 'Transfer',
|
||||
type: 'TRANSFER',
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log(`Created ${transactions.length} transactions`);
|
||||
console.log('Seeding completed successfully!');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('Error during seeding:', e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user