feat(v3): restructure project + add complete frontend
- Restructure: move backend from new_project/ to backend/ - Add full React/TypeScript frontend (37 pages, 17 services, 16 type defs, 11 query hooks) - Add docs/ with SRS specs, user stories, and workflow documentation - Update .gitignore for new directory layout Workflows implemented: WF1 User Signup, WF2 Placement Test, WF3 Exam Configuration, WF4 General English Exam, WF5 Course Generation, WF6 Entity Student Onboarding, AI Course Generation, Adaptive Learning Engine UI, White-Label Branding, Score Release Made-with: Cursor
This commit is contained in:
120
src/pages/PaymentRecordPage.tsx
Normal file
120
src/pages/PaymentRecordPage.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { useState } from "react";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { Plus, Download } from "lucide-react";
|
||||
import AiTipBanner from "@/components/ai/AiTipBanner";
|
||||
import AiReportNarrative from "@/components/ai/AiReportNarrative";
|
||||
|
||||
const payments = [
|
||||
{ id: "PAY-001", corporate: "Acme Corp", manager: "John Admin", amount: 5000, currency: "USD", paid: true, date: "2025-01-15", type: "Corporate" },
|
||||
{ id: "PAY-002", corporate: "Global Ltd", manager: "HR Global", amount: 8500, currency: "USD", paid: true, date: "2025-02-01", type: "Corporate" },
|
||||
{ id: "PAY-003", corporate: "Tech Co", manager: "Tech Admin", amount: 2000, currency: "USD", paid: false, date: "2025-03-01", type: "Commission" },
|
||||
];
|
||||
|
||||
const paymobOrders = [
|
||||
{ id: "PMB-1001", status: "Paid", user: "Sarah Johnson", email: "sarah.j@email.com", amount: 199.00 },
|
||||
{ id: "PMB-1002", status: "Pending", user: "Ahmed Hassan", email: "ahmed.h@email.com", amount: 149.00 },
|
||||
{ id: "PMB-1003", status: "Paid", user: "Li Wei", email: "li.w@email.com", amount: 199.00 },
|
||||
{ id: "PMB-1004", status: "Failed", user: "Emma Brown", email: "emma.b@email.com", amount: 99.00 },
|
||||
];
|
||||
|
||||
export default function PaymentRecordPage() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold tracking-tight">Payment Record</h1>
|
||||
<p className="text-muted-foreground">Manage payments, commissions, and Paymob orders.</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm"><Download className="h-4 w-4 mr-1" /> Export CSV</Button>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm"><Plus className="h-4 w-4 mr-1" /> New Payment</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader><DialogTitle>Create Payment Record</DialogTitle></DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2"><Label>Corporate</Label><Select><SelectTrigger><SelectValue placeholder="Select" /></SelectTrigger><SelectContent><SelectItem value="acme">Acme Corp</SelectItem></SelectContent></Select></div>
|
||||
<div className="space-y-2"><Label>Amount (USD)</Label><Input type="number" placeholder="5000" /></div>
|
||||
<div className="space-y-2"><Label>Type</Label><Select><SelectTrigger><SelectValue placeholder="Type" /></SelectTrigger><SelectContent><SelectItem value="corporate">Corporate</SelectItem><SelectItem value="commission">Commission</SelectItem></SelectContent></Select></div>
|
||||
<Button className="w-full">Create</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AiTipBanner tip="PAY-003 (Tech Co) is unpaid and overdue. PMB-1004 failed — AI recommends sending an automated retry notification to Emma Brown." variant="recommendation" />
|
||||
|
||||
<Tabs defaultValue="payments">
|
||||
<TabsList>
|
||||
<TabsTrigger value="payments">Payments</TabsTrigger>
|
||||
<TabsTrigger value="paymob">Paymob</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="payments" className="mt-4 space-y-4">
|
||||
<AiReportNarrative narrative="Total revenue collected: $13,500 from 2 corporate payments. One commission of $2,000 remains unpaid. Collection rate: 67%. Trend: Q1 payments are on track but Tech Co requires follow-up." />
|
||||
<Card className="border-0 shadow-sm">
|
||||
<CardContent className="p-0">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>ID</TableHead><TableHead>Corporate</TableHead><TableHead>Manager</TableHead>
|
||||
<TableHead>Amount</TableHead><TableHead>Type</TableHead><TableHead>Paid</TableHead><TableHead>Date</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{payments.map((p) => (
|
||||
<TableRow key={p.id}>
|
||||
<TableCell className="font-mono text-xs">{p.id}</TableCell>
|
||||
<TableCell>{p.corporate}</TableCell>
|
||||
<TableCell>{p.manager}</TableCell>
|
||||
<TableCell className="font-semibold">${p.amount.toLocaleString()}</TableCell>
|
||||
<TableCell><Badge variant="outline">{p.type}</Badge></TableCell>
|
||||
<TableCell><Badge variant={p.paid ? "default" : "destructive"}>{p.paid ? "Paid" : "Unpaid"}</Badge></TableCell>
|
||||
<TableCell>{p.date}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="paymob" className="mt-4">
|
||||
<Card className="border-0 shadow-sm">
|
||||
<CardContent className="p-0">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Order ID</TableHead><TableHead>Status</TableHead><TableHead>User</TableHead>
|
||||
<TableHead>Email</TableHead><TableHead>Amount</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{paymobOrders.map((o) => (
|
||||
<TableRow key={o.id}>
|
||||
<TableCell className="font-mono text-xs">{o.id}</TableCell>
|
||||
<TableCell><Badge variant={o.status === "Paid" ? "default" : o.status === "Pending" ? "secondary" : "destructive"}>{o.status}</Badge></TableCell>
|
||||
<TableCell>{o.user}</TableCell>
|
||||
<TableCell>{o.email}</TableCell>
|
||||
<TableCell className="font-semibold">${o.amount.toFixed(2)}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user