feat: integrate ai jars into budget, rename tabs, and fix dashboard navigation

This commit is contained in:
CycroftX
2026-02-16 12:45:06 +05:30
parent 3d95b99502
commit 9dbfb70dc2
21 changed files with 643 additions and 68 deletions

70
NAVIGATION_AUDIT.md Normal file
View File

@@ -0,0 +1,70 @@
# Navigation & Route Audit
Last Updated: 2026-02-16
## ✅ Working Routes
| Page/Component | Element | Route/Action | Status |
|----------------|---------|--------------|--------|
| Layout | "Home", "Portfolio", "Budget", etc. | `onSectionChange` (State) | ✅ Working |
| Layout | "Logout" | `onLogout` (Auth Hook) | ✅ Working |
| Profile | "Theme Switcher" | `setTheme` (Context) | ✅ Working |
| Savings | "Calculator" (Sliders/Input) | Local State | ✅ Working |
| Dashboard | "HeroStats" (Cards) | Display Only | ✅ Working |
| Portfolio | "Risk Analysis" (Cards) | Display Only | ✅ Working |
## ❌ Non-Functional Elements
These elements are visually present but lack `onClick` handlers or backend integration.
| Page/Component | Element | Expected Action | Issue |
|----------------|---------|-----------------|-------|
| **Dashboard** | | | |
| `TransactionsList` | "View All Transactions" button | `onSectionChange('budget')` or route | No handler |
| `GoalsList` | "Manage Goals" button | `onSectionChange('goals')` | No handler |
| `QuickActions` | "New Investment" card | Open Modal / Navigate | No handler |
| `QuickActions` | "Set Goals" card | Open Modal / Navigate | No handler |
| `QuickActions` | "View Reports" card | Open Modal / Navigate | No handler |
| `QuickActions` | "Savings Plan" card | Navigate to `savings` | No handler |
| **Portfolio** | | | |
| `QuickInvestmentForm` | "Buy Asset" button | Execute Trade / Modal | No handler |
| `QuickInvestmentForm` | "Sell Asset" button | Execute Trade / Modal | No handler |
| `HoldingsTable` | "+" / "-" Action buttons | Modify Position | No handler |
| **Budget** | | | |
| `AddExpenseForm` | "Add Expense" button | Submit Form | No handler |
| `SetBudgetForm` | "Set Budget" button | Submit Form | No handler |
| **Savings** | | | |
| `SavingsGoalsGrid` | "+1K", "+5K", "Custom" buttons | Add Funds | No handler |
| `SavingsAccountsTable` | "Settings" (Gear icon) | Open Settings | No handler |
| `AddGoalForm` | "Create Savings Goal" button | Submit Form | No handler |
| **Credit** | | | |
| `CreditCardsList` | "Pay Custom" button | Payment Modal | No handler |
| `CreditCardsList` | "Pay Min" button | Payment Modal | No handler |
| `CreditCardsList` | "More" (Three dots) button | Menu / Details | No handler |
| **Commitments** | | | |
| `UpcomingCommitments` | "Mark Paid" (Check) button | Update Status | No handler |
| `UpcomingCommitments` | "Delete" (Trash) button | Remove Item | No handler |
| `UpcomingCommitments` | "View All History" button | Navigate / Modal | No handler |
| `CommitmentAITips` | "View Credit Impact" button | Navigate / Modal | No handler |
| `CommitmentCalendar` | "Mark Paid" / "Delete" buttons | Update/Remove | No handler |
| `AddCommitmentForm` | "Add Commitment" button | Submit Form | No handler |
## 🚧 Placeholder Buttons (No Action)
| Page/Component | Element | Notes |
|----------------|---------|-------|
| Dashboard | Hero Stat Cards | Could link to respective modules (e.g., Portfolio Value -> Portfolio) |
| Dashboard | "Recent Transactions" Items | Could broaden transaction details modal |
| Savings | "Savings Accounts" Items | Could open account details |
| Credit | "Credit Cards" Items | Could open card details/statements |
## 📋 Recommended Actions
**High Priority:**
- [ ] **Dashboard Navigation:** Wire up `QuickActions` to navigate to respective modules (e.g., "New Investment" -> Portfolio, "Savings Plan" -> Savings).
- [ ] **View All buttons:** Connect "View All Transactions" to the specific transaction history view (or Budget module).
- [ ] **Forms:** Implement `onSubmit` handlers (even if just `console.log` + toast) for "Add Expense", "Set Budget", "Add Commitment", and "Add Goal".
**Medium Priority:**
- [ ] **Interactive Actions:** Implement "Pay Min/Custom" logic in Credit Manager (show a payment success toast).
- [ ] **List Actions:** Implementation delete/mark-paid logic for Commitments (update local state).
- [ ] **Investment:** Add basic validation/toast for "Buy/Sell" in Portfolio.
**Low Priority:**
- [ ] **Deep Linking:** Check/Trash buttons in tables.
- [ ] **Settings:** Account-level settings in Savings module.

Binary file not shown.

View File

@@ -12,7 +12,11 @@ import InvestmentPerformance from './dashboard/InvestmentPerformance';
import AIInsights from './dashboard/AIInsights'; import AIInsights from './dashboard/AIInsights';
import QuickActions from './dashboard/QuickActions'; import QuickActions from './dashboard/QuickActions';
const Dashboard: React.FC = () => { interface DashboardProps {
onNavigate?: (section: string) => void;
}
const Dashboard: React.FC<DashboardProps> = ({ onNavigate }) => {
// Hardcoded Header Data as per Target Design Reference // Hardcoded Header Data as per Target Design Reference
const currentDate = "Sunday, February 15, 2026"; const currentDate = "Sunday, February 15, 2026";
const monthlyWealthGrowth = "425,600"; // AED value const monthlyWealthGrowth = "425,600"; // AED value
@@ -63,12 +67,12 @@ const Dashboard: React.FC = () => {
<section className="grid grid-cols-1 lg:grid-cols-2 gap-6 items-start relative z-10"> <section className="grid grid-cols-1 lg:grid-cols-2 gap-6 items-start relative z-10">
{/* Left Column: Recent Transactions */} {/* Left Column: Recent Transactions */}
<div className="space-y-6"> <div className="space-y-6">
<TransactionsList /> <TransactionsList onNavigate={onNavigate} />
</div> </div>
{/* Right Column: Financial Goals */} {/* Right Column: Financial Goals */}
<div className="space-y-6"> <div className="space-y-6">
<GoalsList /> <GoalsList onNavigate={onNavigate} />
</div> </div>
</section> </section>
@@ -88,7 +92,7 @@ const Dashboard: React.FC = () => {
{/* Footer Actions */} {/* Footer Actions */}
<section className="relative z-10"> <section className="relative z-10">
<h3 className="text-lg font-medium text-slate-700 mb-4 px-1">Quick Actions</h3> <h3 className="text-lg font-medium text-slate-700 mb-4 px-1">Quick Actions</h3>
<QuickActions /> <QuickActions onNavigate={onNavigate} />
</section> </section>
</div> </div>
); );

View File

@@ -7,7 +7,26 @@ import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DirhamIcon } from '@/components/ui/custom-icons'; import { DirhamIcon } from '@/components/ui/custom-icons';
import { toast } from 'sonner';
const AddExpenseForm: React.FC = () => { const AddExpenseForm: React.FC = () => {
const handleAddExpense = () => {
const amount = (document.getElementById('amount') as HTMLInputElement).value;
const desc = (document.getElementById('desc') as HTMLInputElement).value;
const category = (document.getElementById('category') as HTMLButtonElement | null)?.innerText || "Category";
if (!amount || !desc) {
toast.error("Please fill in amount and description");
return;
}
toast.success(`Expense Added: AED ${amount} to ${category}`);
// Clear
(document.getElementById('amount') as HTMLInputElement).value = '';
(document.getElementById('desc') as HTMLInputElement).value = '';
};
return ( return (
<div className="flex justify-center items-center h-[400px]"> <div className="flex justify-center items-center h-[400px]">
<GlassCard className="p-8 w-full max-w-md"> <GlassCard className="p-8 w-full max-w-md">
@@ -45,7 +64,10 @@ const AddExpenseForm: React.FC = () => {
<Input id="desc" placeholder="e.g. Grocery shopping" className="bg-white/50 border-slate-200" /> <Input id="desc" placeholder="e.g. Grocery shopping" className="bg-white/50 border-slate-200" />
</div> </div>
<Button className="w-full mt-4 bg-slate-900 text-white hover:bg-slate-800 shadow-md"> <Button
className="w-full mt-4 bg-slate-900 text-white hover:bg-slate-800 shadow-md"
onClick={handleAddExpense}
>
Add Expense Add Expense
</Button> </Button>
</div> </div>

View File

@@ -0,0 +1,162 @@
import React, { useState } from 'react';
import { GlassCard } from '@/components/ui/GlassCard';
import { Button } from '@/components/ui/button';
import { Switch } from '@/components/ui/switch';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Progress } from '@/components/ui/progress';
import { DirhamIcon } from '@/components/ui/custom-icons';
import { Target, Zap, Plus, Sparkles } from 'lucide-react';
import { toast } from 'sonner';
const BudgetGoalPlanning: React.FC = () => {
// Left Column Data: Active Jars/Goals
const [goals, setGoals] = useState([
{ id: 1, name: 'Rainy Day Fund', current: 4500, target: 10000, color: 'bg-blue-500' },
{ id: 2, name: 'New Laptop', current: 3200, target: 8000, color: 'bg-purple-500' },
{ id: 3, name: 'Holiday Gift Fund', current: 500, target: 2000, color: 'bg-pink-500' },
]);
// Right Column State: AI Config
const [aiEnabled, setAiEnabled] = useState(false);
const handleAddFunds = (name: string) => {
toast.success(`Funds added to ${name}`);
};
const handleActivateAI = () => {
setAiEnabled(!aiEnabled);
if (!aiEnabled) {
toast.success("AI Auto-Save Activated!");
} else {
toast.info("AI Auto-Save Paused");
}
};
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 items-start">
{/* Left Column: Active Jars & Goals */}
<div className="space-y-6">
<div className="flex justify-between items-center">
<h3 className="text-xl font-semibold text-slate-800 flex items-center gap-2">
<Target className="w-5 h-5 text-indigo-500" /> Active Jars & Goals
</h3>
<Button variant="outline" size="sm" className="h-8 border-dashed border-slate-300 text-slate-500 hover:text-indigo-600 hover:border-indigo-300">
<Plus className="w-3 h-3 mr-1" /> New Jar
</Button>
</div>
<div className="grid grid-cols-1 gap-4">
{goals.map((goal) => {
const progress = (goal.current / goal.target) * 100;
return (
<GlassCard key={goal.id} className="p-5 space-y-4 group hover:border-indigo-100 transition-all">
<div className="flex justify-between items-start">
<div>
<h4 className="font-semibold text-slate-800">{goal.name}</h4>
<p className="text-sm text-slate-500 mt-1">
<span className="font-medium text-slate-700"><DirhamIcon className="w-3 h-3 inline" /> {goal.current.toLocaleString()}</span>
<span className="text-slate-400"> / {goal.target.toLocaleString()}</span>
</p>
</div>
<Button
variant="outline"
size="sm"
className="h-7 text-xs border-slate-200 text-slate-600 hover:bg-slate-50"
onClick={() => handleAddFunds(goal.name)}
>
Add Funds
</Button>
</div>
<div className="space-y-1">
<div className="flex justify-between text-xs text-slate-500 mb-1">
<span>{progress.toFixed(0)}% Funded</span>
<span>{Math.max(0, goal.target - goal.current).toLocaleString()} remaining</span>
</div>
<Progress value={progress} className="h-2" indicatorClassName={goal.color} />
</div>
</GlassCard>
);
})}
</div>
</div>
{/* Right Column: AI Auto-Save Configuration */}
<div className="space-y-6">
<h3 className="text-xl font-semibold text-slate-800 flex items-center gap-2">
<Zap className="w-5 h-5 text-yellow-500 fill-yellow-500" /> Automate Your Savings
</h3>
<GlassCard className="p-6 relative overflow-hidden">
{/* Background decoration */}
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-yellow-200/20 to-orange-200/20 rounded-bl-full -z-10" />
<div className="space-y-6">
<div className="flex items-center justify-between pb-4 border-b border-white/20">
<div>
<h4 className="font-semibold text-slate-800">Enable AI Logic</h4>
<p className="text-xs text-slate-500">Allow WealthWise to save while you spend</p>
</div>
<Switch
checked={aiEnabled}
onCheckedChange={handleActivateAI}
className="data-[state=checked]:bg-green-500"
/>
</div>
<div className={`space-y-5 transition-opacity duration-300 ${aiEnabled ? 'opacity-100' : 'opacity-50 pointer-events-none'}`}>
<div className="space-y-2">
<Label className="text-slate-600 text-sm">Smart Rule</Label>
<Select defaultValue="roundup">
<SelectTrigger className="bg-white/50 border-slate-200">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="roundup">Round-up transactions to nearest AED 10</SelectItem>
<SelectItem value="percentage">Save 1% of every purchase</SelectItem>
<SelectItem value="fixed">Auto-transfer AED 5 daily</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label className="text-slate-600 text-sm">Target Jar</Label>
<Select defaultValue="rainy">
<SelectTrigger className="bg-white/50 border-slate-200">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="rainy">Rainy Day Fund</SelectItem>
<SelectItem value="laptop">New Laptop</SelectItem>
<SelectItem value="holiday">Holiday Gift Fund</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="text-slate-600 text-sm">Monthly Cap</Label>
<div className="relative">
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-xs">AED</span>
<Input type="number" defaultValue="500" className="pl-10 bg-white/50 border-slate-200" />
</div>
</div>
</div>
{/* AI Insight Box */}
<div className="bg-indigo-50/50 border border-indigo-100 rounded-lg p-3 flex gap-3 items-start">
<Sparkles className="w-4 h-4 text-indigo-500 mt-0.5 shrink-0" />
<p className="text-xs text-indigo-800 leading-relaxed">
Based on your spending habits, this rule will save approx <span className="font-semibold">AED 340/month</span> without impacting your daily budget needs.
</p>
</div>
</div>
</div>
</GlassCard>
</div>
</div>
);
};
export default BudgetGoalPlanning;

View File

@@ -7,7 +7,24 @@ import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DirhamIcon } from '@/components/ui/custom-icons'; import { DirhamIcon } from '@/components/ui/custom-icons';
import { toast } from 'sonner';
const SetBudgetForm: React.FC = () => { const SetBudgetForm: React.FC = () => {
const handleSetBudget = () => {
const amount = (document.getElementById('budget-amount') as HTMLInputElement).value;
const category = (document.getElementById('category-budget') as HTMLButtonElement | null)?.innerText || "Category";
if (!amount) {
toast.error("Please enter a budget amount");
return;
}
toast.success(`Budget Updated: AED ${amount} for ${category}`);
// Clear
(document.getElementById('budget-amount') as HTMLInputElement).value = '';
};
return ( return (
<div className="flex justify-center items-center h-[400px]"> <div className="flex justify-center items-center h-[400px]">
<GlassCard className="p-8 w-full max-w-md"> <GlassCard className="p-8 w-full max-w-md">
@@ -40,7 +57,10 @@ const SetBudgetForm: React.FC = () => {
</div> </div>
</div> </div>
<Button className="w-full mt-4 bg-gradient-to-r from-blue-600 to-indigo-600 text-white hover:from-blue-700 hover:to-indigo-700 shadow-md"> <Button
className="w-full mt-4 bg-gradient-to-r from-blue-600 to-indigo-600 text-white hover:from-blue-700 hover:to-indigo-700 shadow-md"
onClick={handleSetBudget}
>
Set Budget Set Budget
</Button> </Button>
</div> </div>

View File

@@ -6,7 +6,26 @@ import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Sparkles } from 'lucide-react'; import { Sparkles } from 'lucide-react';
import { toast } from 'sonner';
const AddCommitmentForm: React.FC = () => { const AddCommitmentForm: React.FC = () => {
const handleAdd = () => {
const name = (document.getElementById('comm-name') as HTMLInputElement).value;
const amount = (document.getElementById('comm-amount') as HTMLInputElement).value;
if (!name || !amount) {
toast.error("Please fill in name and amount");
return;
}
toast.success(`Commitment Added: ${name}`);
// Reset
(document.getElementById('comm-name') as HTMLInputElement).value = '';
(document.getElementById('comm-amount') as HTMLInputElement).value = '';
(document.getElementById('comm-type') as HTMLInputElement).value = '';
};
return ( return (
<div className="flex justify-center items-center h-[500px]"> <div className="flex justify-center items-center h-[500px]">
<GlassCard className="p-8 w-full max-w-md"> <GlassCard className="p-8 w-full max-w-md">
@@ -33,7 +52,10 @@ const AddCommitmentForm: React.FC = () => {
<Input id="comm-type" placeholder="e.g. Insurance, Utility" className="bg-white/50 border-slate-200" /> <Input id="comm-type" placeholder="e.g. Insurance, Utility" className="bg-white/50 border-slate-200" />
</div> </div>
<Button className="w-full mt-4 bg-slate-900 text-white hover:bg-slate-800 shadow-md flex items-center gap-2 justify-center"> <Button
className="w-full mt-4 bg-slate-900 text-white hover:bg-slate-800 shadow-md flex items-center gap-2 justify-center"
onClick={handleAdd}
>
<Sparkles className="w-4 h-4 text-yellow-400" /> Add Commitment <Sparkles className="w-4 h-4 text-yellow-400" /> Add Commitment
</Button> </Button>
</div> </div>

View File

@@ -6,6 +6,7 @@ import { Badge } from '@/components/ui/badge';
import { formatAmount } from '@/lib/utils'; import { formatAmount } from '@/lib/utils';
import { DirhamIcon } from '@/components/ui/custom-icons'; import { DirhamIcon } from '@/components/ui/custom-icons';
import { Home, CreditCard, Zap, Trash2, Check } from 'lucide-react'; import { Home, CreditCard, Zap, Trash2, Check } from 'lucide-react';
import { toast } from 'sonner';
const UpcomingCommitmentsList: React.FC = () => { const UpcomingCommitmentsList: React.FC = () => {
const commitments = [ const commitments = [
@@ -63,10 +64,20 @@ const UpcomingCommitmentsList: React.FC = () => {
</div> </div>
<div className="flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity"> <div className="flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
<Button variant="outline" size="sm" className="h-8 border-slate-900 text-slate-900 bg-white hover:bg-slate-50"> <Button
variant="outline"
size="sm"
className="h-8 border-slate-900 text-slate-900 bg-white hover:bg-slate-50"
onClick={() => toast.success(`Marked as Paid: ${item.title}`)}
>
<Check className="w-3 h-3 mr-1" /> Mark Paid <Check className="w-3 h-3 mr-1" /> Mark Paid
</Button> </Button>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0 text-red-500 hover:text-red-600 hover:bg-red-50"> <Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0 text-red-500 hover:text-red-600 hover:bg-red-50"
onClick={() => toast.success(`Commitment Deleted: ${item.title}`)}
>
<Trash2 className="w-4 h-4" /> <Trash2 className="w-4 h-4" />
</Button> </Button>
</div> </div>

View File

@@ -6,6 +6,7 @@ import { Badge } from '@/components/ui/badge';
import { formatAmount } from '@/lib/utils'; import { formatAmount } from '@/lib/utils';
import { DirhamIcon } from '@/components/ui/custom-icons'; import { DirhamIcon } from '@/components/ui/custom-icons';
import { MoreHorizontal } from 'lucide-react'; import { MoreHorizontal } from 'lucide-react';
import { toast } from 'sonner';
const CreditCardsList: React.FC = () => { const CreditCardsList: React.FC = () => {
@@ -108,10 +109,17 @@ const CreditCardsList: React.FC = () => {
</p> </p>
</div> </div>
<div className="flex gap-3 w-full sm:w-auto"> <div className="flex gap-3 w-full sm:w-auto">
<Button variant="outline" className="flex-1 sm:flex-none border-slate-200 text-slate-700 hover:bg-slate-50"> <Button
variant="outline"
className="flex-1 sm:flex-none border-slate-200 text-slate-700 hover:bg-slate-50"
onClick={() => toast.info("Custom payment flow would open here")}
>
Pay Custom Pay Custom
</Button> </Button>
<Button className="flex-1 sm:flex-none bg-black text-white hover:bg-slate-800"> <Button
className="flex-1 sm:flex-none bg-black text-white hover:bg-slate-800"
onClick={() => toast.success(`Payment Processed: AED ${card.minDue} for ${card.name}`)}
>
Pay Min Pay Min
</Button> </Button>
</div> </div>

View File

@@ -5,7 +5,11 @@ import { Button } from '@/components/ui/button';
import { Progress } from '@/components/ui/progress'; import { Progress } from '@/components/ui/progress';
import { Target } from 'lucide-react'; import { Target } from 'lucide-react';
const GoalsList: React.FC = () => { interface GoalsListProps {
onNavigate?: (section: string) => void;
}
const GoalsList: React.FC<GoalsListProps> = ({ onNavigate }) => {
const goals = [ const goals = [
{ {
name: 'Emergency Fund', name: 'Emergency Fund',
@@ -53,7 +57,10 @@ const GoalsList: React.FC = () => {
))} ))}
</div> </div>
<Button className="w-full mt-6 bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-700 hover:to-indigo-700 text-white shadow-md"> <Button
className="w-full mt-6 bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-700 hover:to-indigo-700 text-white shadow-md"
onClick={() => onNavigate?.('budget')} // Now part of Budget Manager
>
Manage Goals Manage Goals
</Button> </Button>
</GlassCard> </GlassCard>

View File

@@ -1,14 +1,18 @@
import React from 'react'; import React from 'react';
import { GlassCard } from '@/components/ui/GlassCard'; import { GlassCard } from '@/components/ui/GlassCard';
import { HoverPreview } from '@/components/ui/HoverPreview'; // Import HoverPreview
import { DirhamIcon } from '@/components/ui/custom-icons'; import { DirhamIcon } from '@/components/ui/custom-icons';
import { import {
TrendingUp, TrendingUp,
DollarSign, DollarSign,
PieChart, PieChart,
Shield Shield,
ArrowUpRight,
ArrowDownRight,
CheckCircle2
} from 'lucide-react'; } from 'lucide-react';
import { formatAmount } from '@/lib/utils'; // Keep import for potential reuse, though hardcoded values requested for now import { Progress } from '@/components/ui/progress'; // Assuming we have Progress for risk or charts
// import { formatAmount } from '@/lib/utils'; // Keep import for potential reuse
const HeroStats: React.FC = () => { const HeroStats: React.FC = () => {
// Hardcoded data as per Target Design Reference // Hardcoded data as per Target Design Reference
@@ -20,7 +24,26 @@ const HeroStats: React.FC = () => {
isPositive: true, isPositive: true,
icon: <TrendingUp className="h-6 w-6 text-white" />, icon: <TrendingUp className="h-6 w-6 text-white" />,
color: 'from-purple-500 to-indigo-600', color: 'from-purple-500 to-indigo-600',
iconBg: 'bg-white/20' iconBg: 'bg-white/20',
preview: (
<div className="space-y-3">
<h4 className="text-sm font-semibold text-slate-800">Top Holdings</h4>
<div className="space-y-2">
{[
{ name: 'Apple (AAPL)', change: '+1.4%', up: true },
{ name: 'Bitcoin (BTC)', change: '+5.2%', up: true },
{ name: 'Dubai Real Estate', change: '+0.8%', up: true },
].map((item, i) => (
<div key={i} className="flex justify-between items-center text-sm">
<span className="text-slate-600">{item.name}</span>
<span className="flex items-center text-green-600 font-medium text-xs">
<ArrowUpRight className="w-3 h-3 mr-1" /> {item.change}
</span>
</div>
))}
</div>
</div>
)
}, },
{ {
label: 'Monthly Contributions', label: 'Monthly Contributions',
@@ -29,7 +52,26 @@ const HeroStats: React.FC = () => {
isPositive: true, isPositive: true,
icon: <DollarSign className="h-6 w-6 text-white" />, icon: <DollarSign className="h-6 w-6 text-white" />,
color: 'from-blue-500 to-cyan-600', color: 'from-blue-500 to-cyan-600',
iconBg: 'bg-white/20' iconBg: 'bg-white/20',
preview: (
<div className="space-y-3">
<h4 className="text-sm font-semibold text-slate-800">Recent Deposits</h4>
<div className="space-y-2">
{[
{ source: 'Salary', amount: '15k', date: '15th Feb' },
{ source: 'Freelance', amount: '2.5k', date: '10th Feb' },
].map((item, i) => (
<div key={i} className="flex justify-between items-center text-sm">
<div>
<span className="text-slate-700 block font-medium">{item.source}</span>
<span className="text-xs text-slate-400">{item.date}</span>
</div>
<span className="text-green-600 font-medium">+{item.amount}</span>
</div>
))}
</div>
</div>
)
}, },
{ {
label: 'Annual Returns', label: 'Annual Returns',
@@ -39,24 +81,83 @@ const HeroStats: React.FC = () => {
icon: <PieChart className="h-6 w-6 text-white" />, icon: <PieChart className="h-6 w-6 text-white" />,
color: 'from-emerald-500 to-teal-600', color: 'from-emerald-500 to-teal-600',
iconBg: 'bg-white/20', iconBg: 'bg-white/20',
isPercentage: true isPercentage: true,
preview: (
<div className="space-y-3">
<h4 className="text-sm font-semibold text-slate-800">Monthly Performance</h4>
<div className="flex items-end gap-2 h-16 pt-2">
{/* Simple CSS Bar Chart Simulation */}
{[
{ month: 'J', val: 70, color: 'bg-emerald-500' },
{ month: 'F', val: 90, color: 'bg-emerald-600' },
{ month: 'M', val: 40, color: 'bg-red-400' }, // Negative dip example
{ month: 'A', val: 60, color: 'bg-emerald-500' },
{ month: 'M', val: 80, color: 'bg-emerald-500' },
{ month: 'J', val: 50, color: 'bg-emerald-400' },
].map((d, i) => (
<div key={i} className="flex-1 flex flex-col justify-end items-center gap-1 group">
<div
className={`w-full rounded-t-sm transition-all group-hover:opacity-80 ${d.color}`}
style={{ height: `${d.val}%` }}
/>
<span className="text-[10px] text-slate-400 uppercase">{d.month}</span>
</div>
))}
</div>
<div className="flex justify-between text-xs text-slate-500 mt-1">
<span>Jan (+2%)</span>
<span>Feb (+3.1%)</span>
<span>Mar (-0.5%)</span>
</div>
</div>
)
}, },
{ {
label: 'Risk Score', label: 'Risk Score',
value: '3.2/10', value: '3.2/10',
change: '-0.3', change: '-0.3',
isPositive: true, // Lower risk score change might be positive contextually, but design shows -0.3. Assuming red for negative change generally unless specified. Design says (-0.3). isPositive: true,
icon: <Shield className="h-6 w-6 text-white" />, icon: <Shield className="h-6 w-6 text-white" />,
color: 'from-orange-500 to-red-600', color: 'from-orange-500 to-red-600',
iconBg: 'bg-white/20', iconBg: 'bg-white/20',
isScore: true isScore: true,
preview: (
<div className="space-y-3">
<h4 className="text-sm font-semibold text-slate-800">Risk Factors</h4>
<div className="space-y-2">
{[
{ label: 'Volatility', status: 'Low', color: 'text-green-600', bg: 'bg-green-100' },
{ label: 'Diversification', status: 'High', color: 'text-green-600', bg: 'bg-green-100' },
{ label: 'Sector Exposure', status: 'Balanced', color: 'text-blue-600', bg: 'bg-blue-100' },
].map((item, i) => (
<div key={i} className="flex justify-between items-center text-sm">
<span className="text-slate-600">{item.label}</span>
<span className={`flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium ${item.bg} ${item.color}`}>
<CheckCircle2 className="w-3 h-3" /> {item.status}
</span>
</div>
))}
</div>
<div className="mt-2 pt-2 border-t border-slate-100">
<div className="flex justify-between text-xs text-slate-500 mb-1">
<span>Conservative</span>
<span>Aggressive</span>
</div>
<Progress value={32} className="h-1.5" indicatorClassName="bg-gradient-to-r from-green-500 to-orange-500" />
</div>
</div>
)
} }
]; ];
return ( return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{stats.map((stat, idx) => ( {stats.map((stat, idx) => (
<GlassCard key={idx} className="p-6 relative overflow-hidden group"> <HoverPreview
key={idx}
trigger={
<div className="h-full"> {/* Wrap in div to avoid ref issues with functional components if any, though GlassCard should handle it, explicit div is safer for trigger */}
<GlassCard className="p-6 relative overflow-hidden group cursor-pointer h-full transition-transform hover:-translate-y-1 block">
<div className="relative z-10"> <div className="relative z-10">
<div className="flex justify-between items-start mb-4"> <div className="flex justify-between items-start mb-4">
<div className={`p-3 rounded-xl bg-gradient-to-br ${stat.color} shadow-lg`}> <div className={`p-3 rounded-xl bg-gradient-to-br ${stat.color} shadow-lg`}>
@@ -77,6 +178,10 @@ const HeroStats: React.FC = () => {
{/* Decorative background element */} {/* Decorative background element */}
<div className={`absolute -right-6 -bottom-6 w-24 h-24 rounded-full bg-gradient-to-br ${stat.color} opacity-10 blur-xl group-hover:opacity-20 transition-opacity duration-500`} /> <div className={`absolute -right-6 -bottom-6 w-24 h-24 rounded-full bg-gradient-to-br ${stat.color} opacity-10 blur-xl group-hover:opacity-20 transition-opacity duration-500`} />
</GlassCard> </GlassCard>
</div>
}
content={stat.preview}
/>
))} ))}
</div> </div>
); );

View File

@@ -4,27 +4,35 @@ import { GlassCard } from '@/components/ui/GlassCard';
import { PlusCircle, Target, FileText, PiggyBank } from 'lucide-react'; import { PlusCircle, Target, FileText, PiggyBank } from 'lucide-react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
const QuickActions: React.FC = () => { interface QuickActionsProps {
onNavigate?: (section: string) => void;
}
const QuickActions: React.FC<QuickActionsProps> = ({ onNavigate }) => {
const actions = [ const actions = [
{ {
label: 'New Investment', label: 'New Investment',
icon: <PlusCircle className="w-5 h-5 mb-2" />, icon: <PlusCircle className="w-5 h-5 mb-2" />,
color: 'hover:border-green-200 hover:bg-green-50/50 hover:text-green-700' color: 'hover:border-green-200 hover:bg-green-50/50 hover:text-green-700',
action: () => onNavigate?.('portfolio') // Default to overview
}, },
{ {
label: 'Set Goals', label: 'Set Goals',
icon: <Target className="w-5 h-5 mb-2" />, icon: <Target className="w-5 h-5 mb-2" />,
color: 'hover:border-blue-200 hover:bg-blue-50/50 hover:text-blue-700' color: 'hover:border-blue-200 hover:bg-blue-50/50 hover:text-blue-700',
action: () => onNavigate?.('budget') // Now part of Budget Manager
}, },
{ {
label: 'View Reports', label: 'View Reports',
icon: <FileText className="w-5 h-5 mb-2" />, icon: <FileText className="w-5 h-5 mb-2" />,
color: 'hover:border-purple-200 hover:bg-purple-50/50 hover:text-purple-700' color: 'hover:border-purple-200 hover:bg-purple-50/50 hover:text-purple-700',
action: () => onNavigate?.('budget')
}, },
{ {
label: 'Savings Plan', label: 'Savings Plan',
icon: <PiggyBank className="w-5 h-5 mb-2" />, icon: <PiggyBank className="w-5 h-5 mb-2" />,
color: 'hover:border-pink-200 hover:bg-pink-50/50 hover:text-pink-700' color: 'hover:border-pink-200 hover:bg-pink-50/50 hover:text-pink-700',
action: () => onNavigate?.('savings')
} }
]; ];
@@ -35,6 +43,7 @@ const QuickActions: React.FC = () => {
key={idx} key={idx}
className={`p-4 flex flex-col items-center justify-center cursor-pointer transition-all active:scale-95 ${action.color} group`} className={`p-4 flex flex-col items-center justify-center cursor-pointer transition-all active:scale-95 ${action.color} group`}
hoverEffect hoverEffect
onClick={action.action}
> >
<div className="p-3 rounded-full bg-white shadow-sm mb-2 group-hover:scale-110 transition-transform"> <div className="p-3 rounded-full bg-white shadow-sm mb-2 group-hover:scale-110 transition-transform">
{action.icon} {action.icon}

View File

@@ -5,7 +5,11 @@ import { Button } from '@/components/ui/button';
import { DirhamIcon } from '@/components/ui/custom-icons'; import { DirhamIcon } from '@/components/ui/custom-icons';
import { ArrowUpRight, ArrowDownRight, Clock } from 'lucide-react'; import { ArrowUpRight, ArrowDownRight, Clock } from 'lucide-react';
const TransactionsList: React.FC = () => { interface TransactionsListProps {
onNavigate?: (section: string) => void;
}
const TransactionsList: React.FC<TransactionsListProps> = ({ onNavigate }) => {
const transactions = [ const transactions = [
{ {
id: 1, id: 1,
@@ -80,7 +84,11 @@ const TransactionsList: React.FC = () => {
))} ))}
</div> </div>
<Button variant="outline" className="w-full mt-6 text-slate-600 hover:text-purple-600 hover:border-purple-200"> <Button
variant="outline"
className="w-full mt-6 text-slate-600 hover:text-purple-600 hover:border-purple-200"
onClick={() => onNavigate?.('budget')}
>
View All Transactions View All Transactions
</Button> </Button>
</GlassCard> </GlassCard>

View File

@@ -12,6 +12,8 @@ import FullExpensesTable from '@/components/budget/FullExpensesTable';
import AddExpenseForm from '@/components/budget/AddExpenseForm'; import AddExpenseForm from '@/components/budget/AddExpenseForm';
import SetBudgetForm from '@/components/budget/SetBudgetForm'; import SetBudgetForm from '@/components/budget/SetBudgetForm';
import BudgetGoalPlanning from '@/components/budget/BudgetGoalPlanning'; // Import new component
export default function BudgetManager() { export default function BudgetManager() {
return ( return (
<div className="space-y-6 animate-fade-in text-slate-800 pb-10"> <div className="space-y-6 animate-fade-in text-slate-800 pb-10">
@@ -43,6 +45,7 @@ export default function BudgetManager() {
<TabsTrigger value="overview" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Overview</TabsTrigger> <TabsTrigger value="overview" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Overview</TabsTrigger>
<TabsTrigger value="budgets" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Budgets</TabsTrigger> <TabsTrigger value="budgets" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Budgets</TabsTrigger>
<TabsTrigger value="expenses" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Expenses</TabsTrigger> <TabsTrigger value="expenses" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Expenses</TabsTrigger>
<TabsTrigger value="goal-planning" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Goal Planning</TabsTrigger>
<TabsTrigger value="add-expense" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Add Expense</TabsTrigger> <TabsTrigger value="add-expense" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Add Expense</TabsTrigger>
<TabsTrigger value="set-budget" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Set Budget</TabsTrigger> <TabsTrigger value="set-budget" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Set Budget</TabsTrigger>
</TabsList> </TabsList>
@@ -65,12 +68,17 @@ export default function BudgetManager() {
<FullExpensesTable /> <FullExpensesTable />
</TabsContent> </TabsContent>
{/* Tab 4: Add Expense */} {/* Tab 4: Goal Planning */}
<TabsContent value="goal-planning" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500">
<BudgetGoalPlanning />
</TabsContent>
{/* Tab 5: Add Expense */}
<TabsContent value="add-expense" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500"> <TabsContent value="add-expense" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500">
<AddExpenseForm /> <AddExpenseForm />
</TabsContent> </TabsContent>
{/* Tab 5: Set Budget */} {/* Tab 6: Set Budget */}
<TabsContent value="set-budget" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500"> <TabsContent value="set-budget" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500">
<SetBudgetForm /> <SetBudgetForm />
</TabsContent> </TabsContent>

View File

@@ -45,7 +45,7 @@ export default function SavingsBooster() {
<TabsTrigger value="goals" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Goals</TabsTrigger> <TabsTrigger value="goals" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Goals</TabsTrigger>
<TabsTrigger value="accounts" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Accounts</TabsTrigger> <TabsTrigger value="accounts" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Accounts</TabsTrigger>
<TabsTrigger value="calculator" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Calculator</TabsTrigger> <TabsTrigger value="calculator" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Calculator</TabsTrigger>
<TabsTrigger value="add-goal" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Add Goal</TabsTrigger> <TabsTrigger value="manual-goal" className="rounded-xl px-4 lg:px-6 py-2.5 text-sm font-medium data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm text-slate-500 transition-all">Manual Goal</TabsTrigger>
</TabsList> </TabsList>
{/* Tab 1: Overview */} {/* Tab 1: Overview */}
@@ -61,18 +61,18 @@ export default function SavingsBooster() {
<SavingsGoalsGrid /> <SavingsGoalsGrid />
</TabsContent> </TabsContent>
{/* Tab 3: Accounts */} {/* Tab 4: Accounts */}
<TabsContent value="accounts" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500"> <TabsContent value="accounts" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500">
<SavingsAccountsTable /> <SavingsAccountsTable />
</TabsContent> </TabsContent>
{/* Tab 4: Calculator */} {/* Tab 5: Calculator */}
<TabsContent value="calculator" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500"> <TabsContent value="calculator" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500">
<CompoundInterestCalculator /> <CompoundInterestCalculator />
</TabsContent> </TabsContent>
{/* Tab 5: Add Goal */} {/* Tab 6: Manual Goal (Renamed) */}
<TabsContent value="add-goal" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500"> <TabsContent value="manual-goal" className="outline-none animate-in fade-in slide-in-from-bottom-2 duration-500">
<AddGoalForm /> <AddGoalForm />
</TabsContent> </TabsContent>

View File

@@ -15,6 +15,8 @@ import {
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { toast } from 'sonner';
interface HoldingsTableProps { interface HoldingsTableProps {
holdings: Array<{ holdings: Array<{
name: string; name: string;
@@ -30,6 +32,10 @@ interface HoldingsTableProps {
} }
const HoldingsTable: React.FC<HoldingsTableProps> = ({ holdings }) => { const HoldingsTable: React.FC<HoldingsTableProps> = ({ holdings }) => {
const handleAction = (type: 'increase' | 'decrease', symbol: string) => {
toast.success(`Position ${type === 'increase' ? 'Increased' : 'Reduced'}: ${symbol}`);
};
return ( return (
<GlassCard className="overflow-hidden"> <GlassCard className="overflow-hidden">
<Table> <Table>
@@ -71,10 +77,20 @@ const HoldingsTable: React.FC<HoldingsTableProps> = ({ holdings }) => {
</TableCell> </TableCell>
<TableCell> <TableCell>
<div className="flex items-center justify-center gap-2"> <div className="flex items-center justify-center gap-2">
<Button size="icon" variant="outline" className="h-7 w-7 rounded-lg hover:bg-slate-100 text-slate-600"> <Button
size="icon"
variant="outline"
className="h-7 w-7 rounded-lg hover:bg-slate-100 text-slate-600"
onClick={() => handleAction('decrease', holding.symbol)}
>
<Minus className="w-3 h-3" /> <Minus className="w-3 h-3" />
</Button> </Button>
<Button size="icon" variant="outline" className="h-7 w-7 rounded-lg hover:bg-slate-100 text-slate-600"> <Button
size="icon"
variant="outline"
className="h-7 w-7 rounded-lg hover:bg-slate-100 text-slate-600"
onClick={() => handleAction('increase', holding.symbol)}
>
<Plus className="w-3 h-3" /> <Plus className="w-3 h-3" />
</Button> </Button>
</div> </div>

View File

@@ -7,11 +7,28 @@ import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DirhamIcon } from '@/components/ui/custom-icons'; import { DirhamIcon } from '@/components/ui/custom-icons';
import { toast } from 'sonner';
interface QuickInvestmentFormProps { interface QuickInvestmentFormProps {
holdings: Array<{ symbol: string; name: string }>; holdings: Array<{ symbol: string; name: string }>;
} }
const QuickInvestmentForm: React.FC<QuickInvestmentFormProps> = ({ holdings }) => { const QuickInvestmentForm: React.FC<QuickInvestmentFormProps> = ({ holdings }) => {
const handleTrade = (type: 'buy' | 'sell') => {
const symbol = (document.getElementById('holding') as HTMLButtonElement | null)?.innerText || 'Asset';
const amount = (document.getElementById('amount') as HTMLInputElement | null)?.value;
if (!amount) {
toast.error("Please enter an amount");
return;
}
toast.success(`Order Placed: ${type === 'buy' ? 'Bought' : 'Sold'} AED ${amount} of ${symbol}`);
// Reset form (simple dom reset for now)
if (document.getElementById('amount')) (document.getElementById('amount') as HTMLInputElement).value = '';
};
return ( return (
<GlassCard className="p-6 h-full flex flex-col justify-center"> <GlassCard className="p-6 h-full flex flex-col justify-center">
<h3 className="text-lg font-semibold text-slate-800 mb-6">Quick Investment</h3> <h3 className="text-lg font-semibold text-slate-800 mb-6">Quick Investment</h3>
@@ -41,10 +58,18 @@ const QuickInvestmentForm: React.FC<QuickInvestmentFormProps> = ({ holdings }) =
</div> </div>
<div className="grid grid-cols-2 gap-4 pt-4"> <div className="grid grid-cols-2 gap-4 pt-4">
<Button variant="outline" className="text-green-600 border-green-200 hover:bg-green-50 hover:text-green-700 w-full"> <Button
variant="outline"
className="text-green-600 border-green-200 hover:bg-green-50 hover:text-green-700 w-full"
onClick={() => handleTrade('buy')}
>
Buy Asset Buy Asset
</Button> </Button>
<Button variant="outline" className="text-red-600 border-red-200 hover:bg-red-50 hover:text-red-700 w-full"> <Button
variant="outline"
className="text-red-600 border-red-200 hover:bg-red-50 hover:text-red-700 w-full"
onClick={() => handleTrade('sell')}
>
Sell Asset Sell Asset
</Button> </Button>
</div> </div>

View File

@@ -11,9 +11,28 @@ import { format } from 'date-fns';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { Calendar as CalendarComponent } from '@/components/ui/calendar'; // Assuming shadcn Calendar exists import { Calendar as CalendarComponent } from '@/components/ui/calendar'; // Assuming shadcn Calendar exists
import { toast } from 'sonner';
const AddGoalForm: React.FC = () => { const AddGoalForm: React.FC = () => {
const [date, setDate] = React.useState<Date>(); const [date, setDate] = React.useState<Date>();
const handleCreateGoal = () => {
const name = (document.getElementById('goal-name') as HTMLInputElement).value;
const amount = (document.getElementById('target-amount') as HTMLInputElement).value;
if (!name || !amount) {
toast.error("Please fill in goal name and target amount");
return;
}
toast.success(`Goal Created: ${name}`);
// Reset
(document.getElementById('goal-name') as HTMLInputElement).value = '';
(document.getElementById('target-amount') as HTMLInputElement).value = '';
setDate(undefined);
};
return ( return (
<div className="flex justify-center items-center h-[450px]"> <div className="flex justify-center items-center h-[450px]">
<GlassCard className="p-8 w-full max-w-md"> <GlassCard className="p-8 w-full max-w-md">
@@ -60,7 +79,10 @@ const AddGoalForm: React.FC = () => {
</Popover> </Popover>
</div> </div>
<Button className="w-full mt-4 bg-slate-900 text-white hover:bg-slate-800 shadow-md"> <Button
className="w-full mt-4 bg-slate-900 text-white hover:bg-slate-800 shadow-md"
onClick={handleCreateGoal}
>
Create Savings Goal Create Savings Goal
</Button> </Button>
</div> </div>

View File

@@ -8,6 +8,8 @@ import { Progress } from '@/components/ui/progress';
import { Clock, Plus } from 'lucide-react'; import { Clock, Plus } from 'lucide-react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { toast } from 'sonner';
const SavingsGoalsGrid: React.FC = () => { const SavingsGoalsGrid: React.FC = () => {
const goals = [ const goals = [
@@ -18,6 +20,14 @@ const SavingsGoalsGrid: React.FC = () => {
{ name: 'Home Downpayment', saved: 125000, target: 200000, daysLeft: 730, color: 'bg-indigo-500' }, { name: 'Home Downpayment', saved: 125000, target: 200000, daysLeft: 730, color: 'bg-indigo-500' },
]; ];
const handleAddSavings = (amount: number | 'custom', goalName: string) => {
if (amount === 'custom') {
toast.info("Custom amount feature pending: Enter amount manually soon.");
} else {
toast.success(`Ajded AED ${amount} to ${goalName}`);
}
};
return ( return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{goals.map((goal, index) => { {goals.map((goal, index) => {
@@ -49,13 +59,27 @@ const SavingsGoalsGrid: React.FC = () => {
</div> </div>
<div className="grid grid-cols-3 gap-2"> <div className="grid grid-cols-3 gap-2">
<Button variant="outline" size="sm" className="h-8 text-xs border-slate-200 hover:bg-slate-50 hover:text-slate-900"> <Button
variant="outline"
size="sm"
className="h-8 text-xs border-slate-200 hover:bg-slate-50 hover:text-slate-900"
onClick={() => handleAddSavings(1000, goal.name)}
>
+1K +1K
</Button> </Button>
<Button variant="outline" size="sm" className="h-8 text-xs border-slate-200 hover:bg-slate-50 hover:text-slate-900"> <Button
variant="outline"
size="sm"
className="h-8 text-xs border-slate-200 hover:bg-slate-50 hover:text-slate-900"
onClick={() => handleAddSavings(5000, goal.name)}
>
+5K +5K
</Button> </Button>
<Button size="sm" className="h-8 text-xs bg-black text-white hover:bg-slate-800"> <Button
size="sm"
className="h-8 text-xs bg-black text-white hover:bg-slate-800"
onClick={() => handleAddSavings('custom', goal.name)}
>
Custom Custom
</Button> </Button>
</div> </div>

View File

@@ -0,0 +1,33 @@
import React, { ReactNode } from 'react';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
interface HoverPreviewProps {
trigger: ReactNode;
content: ReactNode;
openDelay?: number;
side?: "top" | "right" | "bottom" | "left";
align?: "start" | "center" | "end";
}
export const HoverPreview: React.FC<HoverPreviewProps> = ({
trigger,
content,
openDelay = 200,
side = "bottom",
align = "start"
}) => {
return (
<HoverCard openDelay={openDelay}>
<HoverCardTrigger asChild>
{trigger}
</HoverCardTrigger>
<HoverCardContent
side={side}
align={align}
className="w-80 p-4 bg-white/90 backdrop-blur-xl border border-white/20 rounded-2xl shadow-2xl z-50"
>
{content}
</HoverCardContent>
</HoverCard>
);
};

View File

@@ -42,7 +42,7 @@ const Index = () => {
const renderContent = () => { const renderContent = () => {
switch (activeSection) { switch (activeSection) {
case 'dashboard': case 'dashboard':
return <Dashboard />; return <Dashboard onNavigate={setActiveSection} />;
case 'analyze': case 'analyze':
return <WealthAssistant />; return <WealthAssistant />;
@@ -65,8 +65,7 @@ const Index = () => {
case 'insurance': case 'insurance':
return <InsuranceAdvisor />; return <InsuranceAdvisor />;
case 'goals': // Goals case removed as it is now part of BudgetManager
return <GoalPlanning />;
case 'advisor': case 'advisor':
return <Advisor />; return <Advisor />;