Skip to content

Commit 483fcb6

Browse files
authored
Merge pull request #229 from privexlabs/fix/dashboard-remove-simulated-transactions
fix(dashboard): remove simulated deposits, withdrawals, and transaction history
2 parents b4b323d + 7b5bff0 commit 483fcb6

2 files changed

Lines changed: 268 additions & 250 deletions

File tree

components/dashboard/funds-management.tsx

Lines changed: 143 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client"
22

3-
import { useState } from "react"
3+
import { useCallback, useEffect, useState } from "react"
44
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
55
import { Button } from "@/components/ui/button"
66
import { Input } from "@/components/ui/input"
@@ -31,57 +31,46 @@ import {
3131
Zap,
3232
} from "lucide-react"
3333

34+
/** Canonical money envelope from the API. See docs/api-conventions.md. */
35+
interface Money {
36+
currency: string
37+
amountMinor: number
38+
amountMajor: number
39+
}
40+
3441
interface Transaction {
3542
id: string
36-
type: "deposit" | "withdrawal" | "investment" | "return"
37-
amount: number
38-
status: "completed" | "pending" | "failed"
43+
type: string
44+
amount: Money
45+
status: string
3946
date: string
4047
description: string
41-
method?: string
48+
method?: string | null
49+
}
50+
51+
interface WalletSummaryPayload {
52+
wallet: {
53+
internalBalance: Money
54+
walletAddress: string | null
55+
}
56+
transactions: Array<{
57+
id: string
58+
type: string
59+
amount: Money
60+
status: string
61+
method: string | null
62+
description: string
63+
reference: string | null
64+
timestamp: string
65+
}>
4266
}
4367

4468
interface FundsManagementProps {
4569
currentBalance: number
4670
onBalanceUpdate: (newBalance: number) => void
4771
}
4872

49-
const mockTransactions: Transaction[] = [
50-
{
51-
id: "1",
52-
type: "deposit",
53-
amount: 5000,
54-
status: "completed",
55-
date: "2024-12-20",
56-
description: "Bank transfer deposit",
57-
method: "Bank Transfer",
58-
},
59-
{
60-
id: "2",
61-
type: "investment",
62-
amount: 2000,
63-
status: "completed",
64-
date: "2024-12-19",
65-
description: "Investment in Toyota Corolla 2020",
66-
},
67-
{
68-
id: "3",
69-
type: "return",
70-
amount: 150,
71-
status: "completed",
72-
date: "2024-12-18",
73-
description: "Monthly return from Honda Civic",
74-
},
75-
{
76-
id: "4",
77-
type: "withdrawal",
78-
amount: 1000,
79-
status: "pending",
80-
date: "2024-12-17",
81-
description: "Withdrawal to bank account",
82-
method: "Bank Transfer",
83-
},
84-
]
73+
const CREDIT_TYPES = new Set(["deposit", "wallet_funding"])
8574

8675
export function FundsManagement({ currentBalance, onBalanceUpdate }: FundsManagementProps) {
8776
const [isDepositOpen, setIsDepositOpen] = useState(false)
@@ -91,9 +80,43 @@ export function FundsManagement({ currentBalance, onBalanceUpdate }: FundsManage
9180
const [depositMethod, setDepositMethod] = useState("")
9281
const [withdrawMethod, setWithdrawMethod] = useState("")
9382
const [isProcessing, setIsProcessing] = useState(false)
94-
const [transactions, setTransactions] = useState<Transaction[]>(mockTransactions)
83+
const [transactions, setTransactions] = useState<Transaction[]>([])
84+
const [isLoadingTransactions, setIsLoadingTransactions] = useState(true)
85+
const [transactionsError, setTransactionsError] = useState<string | null>(null)
9586
const { toast } = useToast()
9687

88+
const fetchWalletSummary = useCallback(async () => {
89+
setIsLoadingTransactions(true)
90+
setTransactionsError(null)
91+
try {
92+
const response = await fetch("/api/wallet/summary")
93+
const payload = (await response.json()) as WalletSummaryPayload & { message?: string }
94+
if (!response.ok) {
95+
throw new Error(payload.message || "Unable to load wallet activity.")
96+
}
97+
98+
setTransactions(
99+
payload.transactions.map((transaction) => ({
100+
id: transaction.id,
101+
type: transaction.type,
102+
amount: transaction.amount,
103+
status: transaction.status,
104+
date: transaction.timestamp,
105+
description: transaction.description,
106+
method: transaction.method,
107+
})),
108+
)
109+
} catch (error) {
110+
setTransactionsError(error instanceof Error ? error.message : "Unable to load wallet activity.")
111+
} finally {
112+
setIsLoadingTransactions(false)
113+
}
114+
}, [])
115+
116+
useEffect(() => {
117+
void fetchWalletSummary()
118+
}, [fetchWalletSummary])
119+
97120
const handleDeposit = async () => {
98121
if (!depositAmount || !depositMethod) {
99122
toast({
@@ -106,34 +129,27 @@ export function FundsManagement({ currentBalance, onBalanceUpdate }: FundsManage
106129

107130
setIsProcessing(true)
108131
try {
109-
// Simulate API call
110-
await new Promise((resolve) => setTimeout(resolve, 2000))
132+
const response = await fetch("/api/payments/initialize", {
133+
method: "POST",
134+
headers: { "Content-Type": "application/json" },
135+
body: JSON.stringify({ amountNgn: Number.parseFloat(depositAmount) }),
136+
})
111137

112-
const amount = Number.parseFloat(depositAmount)
113-
const newTransaction: Transaction = {
114-
id: Date.now().toString(),
115-
type: "deposit",
116-
amount,
117-
status: "completed",
118-
date: new Date().toISOString().split("T")[0],
119-
description: `${depositMethod} deposit`,
120-
method: depositMethod,
138+
const payload = await response.json()
139+
if (!response.ok) {
140+
throw new Error(payload.message || "Unable to initialize payment.")
121141
}
122142

123-
setTransactions([newTransaction, ...transactions])
124-
onBalanceUpdate(currentBalance + amount)
125-
setDepositAmount("")
126-
setDepositMethod("")
127-
setIsDepositOpen(false)
143+
const redirectUrl = payload?.payment?.authorizationUrl
144+
if (!redirectUrl) {
145+
throw new Error("Missing payment authorization URL.")
146+
}
128147

129-
toast({
130-
title: "Deposit Successful",
131-
description: `$${amount.toLocaleString()} has been added to your account`,
132-
})
148+
window.location.href = redirectUrl
133149
} catch (error) {
134150
toast({
135151
title: "Deposit Failed",
136-
description: "Please try again later",
152+
description: error instanceof Error ? error.message : "Please try again later",
137153
variant: "destructive",
138154
})
139155
} finally {
@@ -161,44 +177,17 @@ export function FundsManagement({ currentBalance, onBalanceUpdate }: FundsManage
161177
return
162178
}
163179

164-
setIsProcessing(true)
165-
try {
166-
// Simulate API call
167-
await new Promise((resolve) => setTimeout(resolve, 2000))
168-
169-
const newTransaction: Transaction = {
170-
id: Date.now().toString(),
171-
type: "withdrawal",
172-
amount,
173-
status: "pending",
174-
date: new Date().toISOString().split("T")[0],
175-
description: `Withdrawal to ${withdrawMethod}`,
176-
method: withdrawMethod,
177-
}
178-
179-
setTransactions([newTransaction, ...transactions])
180-
onBalanceUpdate(currentBalance - amount)
181-
setWithdrawAmount("")
182-
setWithdrawMethod("")
183-
setIsWithdrawOpen(false)
184-
185-
toast({
186-
title: "Withdrawal Initiated",
187-
description: `$${amount.toLocaleString()} withdrawal is being processed`,
188-
})
189-
} catch (error) {
190-
toast({
191-
title: "Withdrawal Failed",
192-
description: "Please try again later",
193-
variant: "destructive",
194-
})
195-
} finally {
196-
setIsProcessing(false)
197-
}
180+
// Withdrawals are not wired up to a payout provider yet, so report the
181+
// real "unavailable" state instead of fabricating a success transition.
182+
toast({
183+
title: "Withdrawals Unavailable",
184+
description: "Withdrawals aren't available yet. Please check back soon.",
185+
variant: "destructive",
186+
})
198187
}
199188

200189
const getStatusIcon = (status: string) => {
201-
switch (status) {
190+
switch (status.toLowerCase()) {
202191
case "completed":
203192
return <CheckCircle className="h-4 w-4 text-green-500" />
204193
case "pending":
@@ -213,29 +202,24 @@ export function FundsManagement({ currentBalance, onBalanceUpdate }: FundsManage
213202
const getTransactionIcon = (type: string) => {
214203
switch (type) {
215204
case "deposit":
205+
case "wallet_funding":
216206
return <ArrowDownLeft className="h-4 w-4 text-green-500" />
217-
case "withdrawal":
207+
case "wallet_debit":
218208
return <ArrowUpRight className="h-4 w-4 text-red-500" />
219-
case "investment":
209+
case "pool_investment":
220210
return <TrendingUp className="h-4 w-4 text-blue-500" />
221-
case "return":
222-
return <DollarSign className="h-4 w-4 text-green-500" />
223211
default:
224212
return <DollarSign className="h-4 w-4 text-gray-500" />
225213
}
226214
}
227215

228-
const totalDeposits = transactions
229-
.filter((t) => t.type === "deposit" && t.status === "completed")
230-
.reduce((sum, t) => sum + t.amount, 0)
231-
232-
const totalWithdrawals = transactions
233-
.filter((t) => t.type === "withdrawal" && t.status === "completed")
234-
.reduce((sum, t) => sum + t.amount, 0)
216+
const totalInvestments = transactions
217+
.filter((t) => t.type === "pool_investment")
218+
.reduce((sum, t) => sum + t.amount.amountMajor, 0)
235219

236-
const totalInvestments = transactions.filter((t) => t.type === "investment").reduce((sum, t) => sum + t.amount, 0)
237-
238-
const totalReturns = transactions.filter((t) => t.type === "return").reduce((sum, t) => sum + t.amount, 0)
220+
const totalReturns = transactions
221+
.filter((t) => t.type === "return")
222+
.reduce((sum, t) => sum + t.amount.amountMajor, 0)
239223

240224
return (
241225
<div className="space-y-6">
@@ -474,41 +458,56 @@ export function FundsManagement({ currentBalance, onBalanceUpdate }: FundsManage
474458
<CardDescription className="text-muted-foreground">Recent account activity</CardDescription>
475459
</CardHeader>
476460
<CardContent>
477-
<div className="space-y-4">
478-
{transactions.slice(0, 5).map((transaction) => (
479-
<div key={transaction.id} className="flex items-center justify-between p-3 bg-muted rounded-lg">
480-
<div className="flex items-center space-x-3">
481-
{getTransactionIcon(transaction.type)}
482-
<div>
483-
<p className="font-medium text-foreground capitalize">{transaction.type}</p>
484-
<p className="text-sm text-muted-foreground">{transaction.description}</p>
485-
<p className="text-xs text-muted-foreground">{transaction.date}</p>
461+
{transactionsError ? (
462+
<div className="flex flex-col items-center justify-center gap-3 py-8 text-center">
463+
<AlertCircle className="h-6 w-6 text-destructive" />
464+
<p className="text-sm text-muted-foreground">{transactionsError}</p>
465+
<Button variant="outline" size="sm" onClick={() => void fetchWalletSummary()}>
466+
Try again
467+
</Button>
468+
</div>
469+
) : isLoadingTransactions ? (
470+
<div className="space-y-3">
471+
{Array.from({ length: 3 }).map((_, index) => (
472+
<div key={index} className="h-16 rounded-lg bg-muted animate-pulse" />
473+
))}
474+
</div>
475+
) : transactions.length === 0 ? (
476+
<div className="py-8 text-center text-sm text-muted-foreground">No transactions yet.</div>
477+
) : (
478+
<div className="space-y-4">
479+
{transactions.slice(0, 5).map((transaction) => (
480+
<div key={transaction.id} className="flex items-center justify-between p-3 bg-muted rounded-lg">
481+
<div className="flex items-center space-x-3">
482+
{getTransactionIcon(transaction.type)}
483+
<div>
484+
<p className="font-medium text-foreground capitalize">
485+
{transaction.type.replace(/_/g, " ")}
486+
</p>
487+
<p className="text-sm text-muted-foreground">{transaction.description}</p>
488+
<p className="text-xs text-muted-foreground">
489+
{new Date(transaction.date).toLocaleDateString()}
490+
</p>
491+
</div>
486492
</div>
487-
</div>
488-
<div className="text-right">
489-
<div className="flex items-center space-x-2">
490-
<span
491-
className={`font-bold ${
492-
transaction.type === "deposit" || transaction.type === "return"
493-
? "text-green-500"
494-
: "text-red-500"
495-
}`}
496-
>
497-
{transaction.type === "deposit" || transaction.type === "return" ? "+" : "-"}$
498-
{transaction.amount.toLocaleString()}
499-
</span>
500-
{getStatusIcon(transaction.status)}
493+
<div className="text-right">
494+
<div className="flex items-center space-x-2">
495+
<span
496+
className={`font-bold ${
497+
CREDIT_TYPES.has(transaction.type) ? "text-green-500" : "text-red-500"
498+
}`}
499+
>
500+
{CREDIT_TYPES.has(transaction.type) ? "+" : "-"}$
501+
{transaction.amount.amountMajor.toLocaleString()}
502+
</span>
503+
{getStatusIcon(transaction.status)}
504+
</div>
505+
{transaction.method && <p className="text-xs text-muted-foreground">{transaction.method}</p>}
501506
</div>
502-
{transaction.method && <p className="text-xs text-muted-foreground">{transaction.method}</p>}
503507
</div>
504-
</div>
505-
))}
506-
</div>
507-
<div className="mt-4 text-center">
508-
<Button variant="outline" className="border-border text-foreground hover:bg-muted">
509-
View All Transactions
510-
</Button>
511-
</div>
508+
))}
509+
</div>
510+
)}
512511
</CardContent>
513512
</Card>
514513
</div>

0 commit comments

Comments
 (0)