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)}
+
+
+
+
+
+
+
+
+
+
+
+
+ - Envelopes
+ - {envelopes.length}
+
+
+
+
+
+
+
+
+
+
+
+ - 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) => (
+
+
+
+
+
+
+
+
+ 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 */}