main
tsx 241 lines 8.27 KB
Raw
1 import { useState, useEffect } from "react";
2 import { useNavigate, useLocation } from "react-router-dom";
3 import Layout from "@/components/Layout";
4 import { Card } from "@/components/ui/card";
5 import { Input } from "@/components/ui/input";
6 import { Button } from "@/components/ui/button";
7 import { Label } from "@/components/ui/label";
8 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
9 import { ArrowRight, CheckCircle, Loader2 } from "lucide-react";
10 import { transactionService } from "@/services/transactionService";
11 import { Currency } from "@/types/transaction";
12 import { toast } from "@/hooks/use-toast";
13
14 const SendMoney = () => {
15 const navigate = useNavigate();
16 const location = useLocation();
17 const [step, setStep] = useState<"form" | "processing" | "success">("form");
18 const [amount, setAmount] = useState("");
19 const [currency, setCurrency] = useState<Currency>("USD");
20 const [recipient, setRecipient] = useState("");
21 const [recipientName, setRecipientName] = useState("");
22 const [description, setDescription] = useState("");
23 const [transactionId, setTransactionId] = useState("");
24
25 // Pre-fill recipient data if passed from Recipients page
26 useEffect(() => {
27 if (location.state?.recipient) {
28 const { name, email } = location.state.recipient;
29 setRecipientName(name);
30 setRecipient(email);
31 }
32 }, [location]);
33
34 const fee = amount ? transactionService.calculateFee(parseFloat(amount)) : 0;
35 const total = amount ? parseFloat(amount) + fee : 0;
36
37 const handleSend = async () => {
38 if (!amount || !recipient || !recipientName) {
39 toast({
40 title: "Missing Information",
41 description: "Please fill in all required fields",
42 variant: "destructive",
43 });
44 return;
45 }
46
47 setStep("processing");
48
49 try {
50 const transaction = await transactionService.sendMoney(
51 parseFloat(amount),
52 currency,
53 recipient,
54 recipientName,
55 description
56 );
57
58 setTransactionId(transaction.id);
59 setStep("success");
60 } catch (error) {
61 toast({
62 title: "Transaction Failed",
63 description: "Unable to process payment. Please try again.",
64 variant: "destructive",
65 });
66 setStep("form");
67 }
68 };
69
70 if (step === "processing") {
71 return (
72 <Layout title="Sending">
73 <div className="min-h-[60vh] flex items-center justify-center p-4">
74 <Card className="p-12 border-0 shadow-lg text-center max-w-md w-full">
75 <Loader2 className="h-16 w-16 text-primary animate-spin mx-auto mb-6" />
76 <h3 className="text-2xl font-bold mb-3">Processing Payment</h3>
77 <p className="text-muted-foreground font-medium">
78 Please wait while we securely process your transaction...
79 </p>
80 </Card>
81 </div>
82 </Layout>
83 );
84 }
85
86 if (step === "success") {
87 return (
88 <Layout title="Success">
89 <div className="min-h-[60vh] flex items-center justify-center p-4">
90 <Card className="p-12 border-0 shadow-lg text-center max-w-md w-full space-y-6">
91 <CheckCircle className="h-20 w-20 text-expense-positive mx-auto" />
92 <div>
93 <h3 className="text-2xl font-bold mb-3">Payment Sent!</h3>
94 <p className="text-muted-foreground font-medium mb-2">
95 Your payment has been successfully processed
96 </p>
97 <p className="text-sm text-muted-foreground">
98 Transaction ID: {transactionId}
99 </p>
100 </div>
101 <div className="space-y-3 pt-4">
102 <Button className="w-full" onClick={() => navigate("/")}>
103 View Transactions
104 </Button>
105 <Button
106 variant="outline"
107 className="w-full"
108 onClick={() => {
109 setStep("form");
110 setAmount("");
111 setRecipient("");
112 setRecipientName("");
113 setDescription("");
114 }}
115 >
116 Send Another Payment
117 </Button>
118 </div>
119 </Card>
120 </div>
121 </Layout>
122 );
123 }
124
125 return (
126 <Layout title="Send Money">
127 <div className="p-4 space-y-6">
128 <Card className="p-6 border-0 shadow-lg">
129 <div className="space-y-6">
130 <div className="space-y-2">
131 <Label htmlFor="amount" className="text-base font-semibold">
132 Amount
133 </Label>
134 <div className="flex gap-2">
135 <Input
136 id="amount"
137 type="number"
138 placeholder="0.00"
139 value={amount}
140 onChange={(e) => setAmount(e.target.value)}
141 className="text-2xl h-14 font-bold"
142 />
143 <Select value={currency} onValueChange={(val) => setCurrency(val as Currency)}>
144 <SelectTrigger className="w-28 h-14">
145 <SelectValue />
146 </SelectTrigger>
147 <SelectContent>
148 <SelectItem value="USD">USD</SelectItem>
149 <SelectItem value="EUR">EUR</SelectItem>
150 <SelectItem value="GBP">GBP</SelectItem>
151 <SelectItem value="NGN">NGN</SelectItem>
152 <SelectItem value="KES">KES</SelectItem>
153 <SelectItem value="GHS">GHS</SelectItem>
154 </SelectContent>
155 </Select>
156 </div>
157 </div>
158
159 <div className="space-y-2">
160 <Label htmlFor="recipientName" className="text-base font-semibold">
161 Recipient Name
162 </Label>
163 <Input
164 id="recipientName"
165 placeholder="John Doe"
166 value={recipientName}
167 onChange={(e) => setRecipientName(e.target.value)}
168 className="h-12"
169 />
170 </div>
171
172 <div className="space-y-2">
173 <Label htmlFor="recipient" className="text-base font-semibold">
174 Email Address
175 </Label>
176 <Input
177 id="recipient"
178 type="email"
179 placeholder="recipient@email.com"
180 value={recipient}
181 onChange={(e) => setRecipient(e.target.value)}
182 className="h-12"
183 />
184 </div>
185
186 <div className="space-y-2">
187 <Label htmlFor="description" className="text-base font-semibold">
188 Description (Optional)
189 </Label>
190 <Input
191 id="description"
192 placeholder="What's this payment for?"
193 value={description}
194 onChange={(e) => setDescription(e.target.value)}
195 className="h-12"
196 />
197 </div>
198 </div>
199 </Card>
200
201 {amount && (
202 <Card className="p-6 border-0 shadow-md space-y-4">
203 <h3 className="font-bold text-lg">Payment Summary</h3>
204 <div className="space-y-3">
205 <div className="flex justify-between text-base">
206 <span className="text-muted-foreground">Amount</span>
207 <span className="font-semibold">
208 {currency} {parseFloat(amount).toFixed(2)}
209 </span>
210 </div>
211 <div className="flex justify-between text-base">
212 <span className="text-muted-foreground">Fee</span>
213 <span className="font-semibold">
214 {currency} {fee.toFixed(2)}
215 </span>
216 </div>
217 <div className="border-t pt-3 flex justify-between text-lg">
218 <span className="font-bold">Total</span>
219 <span className="font-bold">
220 {currency} {total.toFixed(2)}
221 </span>
222 </div>
223 </div>
224 </Card>
225 )}
226
227 <Button
228 size="lg"
229 className="w-full"
230 onClick={handleSend}
231 disabled={!amount || !recipient || !recipientName}
232 >
233 Send Payment
234 <ArrowRight className="ml-2 h-5 w-5" />
235 </Button>
236 </div>
237 </Layout>
238 );
239 };
240
241 export default SendMoney;