From 5ffdb191e547b23cc07326a1250718f38cf8810a Mon Sep 17 00:00:00 2001 From: nmemmert Date: Mon, 27 Oct 2025 10:26:31 -0400 Subject: [PATCH] Fix loading issues and containerize app --- .github/workflows/docker.yml | 45 +++++ Dockerfile | 22 +++ src/app/page.tsx | 348 +++++++++++++++++++++++++++++------ 3 files changed, 361 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/docker.yml create mode 100644 Dockerfile diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..deb0087 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,45 @@ +name: Build and Push Docker Image + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6089b7d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM node:18-alpine + +# Set working directory +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm ci --only=production + +# Copy source code +COPY . . + +# Build the application +RUN npm run build + +# Expose port +EXPOSE 3000 + +# Start the application +CMD ["npm", "start"] \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index d9a9201..89b60f9 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -246,14 +246,10 @@ export default function BudgetDashboard() { setShowAuthModal(false); }; - const handleSetupComplete = (setupData: { - accounts: Account[]; - envelopes: Envelope[]; - transactions: Transaction[]; - }) => { - setAccounts(setupData.accounts); - setEnvelopes(setupData.envelopes); - setTransactions(setupData.transactions); + const handleSetupComplete = (accounts: Account[], envelopes: Envelope[]) => { + setAccounts(accounts); + setEnvelopes(envelopes); + setTransactions([]); setSetupCompleted(true); setShowSetupWizard(false); }; @@ -290,38 +286,293 @@ export default function BudgetDashboard() { setEnvelopes(prevEnvelopes => prevEnvelopes.filter(env => env.id !== envelopeId)); }; - const handleDataExport = (exportData: { accounts: Account[]; envelopes: Envelope[]; transactions: Transaction[] }) => { - // Implement data export logic here (e.g., download CSV, send to server, etc.) - console.log('Exporting data:', exportData); - }; - return ( -
- {/* Render components based on current view */} - {currentView === 'dashboard' &&
Dashboard View
} - {currentView === 'accounts' &&
Accounts View
} - {currentView === 'transactions' &&
Transactions View
} - {currentView === 'envelopes' &&
Envelopes View
} - {currentView === 'settings' &&
Settings View
} +
+ {/* Navigation */} + - {/* Auth modal */} - {showAuthModal && setShowAuthModal(false)} onSuccess={handleAuthSuccess} />} + {/* Main Content */} +
+ {loading ? ( +
Loading...
+ ) : ( + <> + {currentView === 'dashboard' && ( +
+

Dashboard

+
+
+
+
+
+
+ $ +
+
+
+
+
Total Balance
+
+ ${accounts.reduce((sum, acc) => sum + acc.balance, 0).toFixed(2)} +
+
+
+
+
+
+
+
+
+
+
+ E +
+
+
+
+
Envelopes
+
{envelopes.length}
+
+
+
+
+
+
+
+
+
+
+ T +
+
+
+
+
Transactions
+
{transactions.length}
+
+
+
+
+
+
+
+
+

Recent Transactions

+
+
    + {transactions.slice(-5).reverse().map((transaction) => ( +
  • +
    +
    +
    +

    {transaction.description}

    +

    + {transaction.date.toLocaleDateString()} +

    +
    +
    +

    = 0 ? 'text-green-600' : 'text-red-600'}`}> + ${Math.abs(transaction.amount).toFixed(2)} +

    + +
    +
    +
    +
  • + ))} +
+
+
+ )} + {currentView === 'accounts' && ( +
+ +
+ )} + {currentView === 'transactions' && ( +
+

Transactions

+
+
    + {transactions.map((transaction) => ( +
  • +
    +
    +
    +

    {transaction.description}

    +

    + {transaction.date.toLocaleDateString()} • {accounts.find(acc => acc.id === transaction.accountId)?.name} +

    +
    +
    +

    = 0 ? 'text-green-600' : 'text-red-600'}`}> + ${Math.abs(transaction.amount).toFixed(2)} +

    + +
    +
    +
    +
  • + ))} +
+
+
+ )} + {currentView === 'envelopes' && ( +
+

Envelopes

+
+ {envelopes.map((envelope) => ( +
+
+
+
+
+

{envelope.name}

+
+ +
+
+
+ Allocated + ${envelope.allocated.toFixed(2)} +
+
+ Spent + ${envelope.spent.toFixed(2)} +
+
+ Remaining + ${(envelope.allocated - envelope.spent).toFixed(2)} +
+
+
+
+ ))} +
+
+ +
+
+ )} + {currentView === 'settings' && ( +
+

Settings

+ +
+ )} + + )} +
- {/* Setup wizard */} - {showSetupWizard && } - - {/* Data input component */} - { - // Handle imported data (e.g., from CSV) - console.log('Imported data:', importedData); - }} - /> - - {/* Transaction edit component */} + {/* Modals and Components */} + {showAuthModal && setShowAuthModal(false)} onAuthSuccess={handleAuthSuccess} />} + {showSetupWizard && setShowSetupWizard(false)} />} {editingTransaction && ( ({ id: env.id, name: env.name }))} + accounts={accounts.map(acc => ({ id: acc.id, name: acc.name }))} onSave={(updatedTransaction) => { handleTransactionEdit(updatedTransaction); setEditingTransaction(null); @@ -329,45 +580,34 @@ export default function BudgetDashboard() { onCancel={() => setEditingTransaction(null)} /> )} - - {/* Envelope create/edit component */} {showCreateEnvelope && ( { + onEnvelopeCreated={(newEnvelope) => { handleCreateEnvelope(newEnvelope); setShowCreateEnvelope(false); }} onCancel={() => setShowCreateEnvelope(false)} + accounts={accounts.map(acc => ({ id: acc.id, name: acc.name }))} /> )} {editingEnvelope && ( { + onEnvelopeUpdated={(updatedEnvelope) => { handleEnvelopeUpdate(updatedEnvelope); setEditingEnvelope(null); }} onCancel={() => setEditingEnvelope(null)} + accounts={accounts.map(acc => ({ id: acc.id, name: acc.name }))} /> )} - {/* Data export component */} - ({ id: env.id, name: env.name }))} + accounts={accounts.map(acc => ({ id: acc.id, name: acc.name }))} /> - - {/* Account management component */} - - - {/* Get Paid component */}