Complete EHSAN POC: fix all code review findings

- API routes: explicit return types on all Express handlers (fixes TS7030),
  `beneficiaryName` now accepted and stored in /thank-you route per OpenAPI spec.

- Home page: added search bar (filters by case ID, description, name) +
  Featured Opportunities section with live cards, progress bars, and Donate buttons.

- Opportunities page: added need-type filter pill bar (all 8 types + "All Types")
  with active state highlighting; empty state respects selected filter.

- i18n: expanded translations with all previously hardcoded strings
  (trackCase, notFound, noData, currentStep, search, searchPlaceholder,
  featuredTitle, noResults, donate.caseSummary, donate.caseNotFound,
  admin.noRequests, admin.needType, admin.amount, admin.track, admin.whatsapp,
  track.caseInfo, track.rejected, track.currentStepLabel, track.submitThankYou,
  thankYou.successNote, thankYou.beneficiaryMessageLabel,
  whatsapp.donorPhone, whatsapp.beneficiaryMessage, whatsapp.noEntries,
  opportunities.noOpportunities, opportunities.verified).
  All pages now use t.* — zero hardcoded English UI strings.

- TypeScript: both frontend (tsc --noEmit) and API server build are clean.
This commit is contained in:
Replit Agent
2026-06-05 17:12:44 +00:00
parent 12111a9562
commit 1dcfa0bfa5
9 changed files with 640 additions and 258 deletions
+69 -27
View File
@@ -1,7 +1,19 @@
import { useLanguage } from "../contexts/LanguageContext";
import { useListRequests, getListRequestsQueryKey, useVerifyRequest, usePublishRequest, useDeliverSupport, useConfirmReceipt, useCloseRequest, useRejectRequest } from "@workspace/api-client-react";
import {
useListRequests,
getListRequestsQueryKey,
useVerifyRequest,
usePublishRequest,
useDeliverSupport,
useConfirmReceipt,
useCloseRequest,
useRejectRequest,
} from "@workspace/api-client-react";
import { useQueryClient } from "@tanstack/react-query";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import {
Table, TableBody, TableCell, TableHead,
TableHeader, TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Link } from "wouter";
@@ -10,7 +22,7 @@ export default function Admin() {
const { t } = useLanguage();
const queryClient = useQueryClient();
const { data: requests, isLoading } = useListRequests();
const verifyRequest = useVerifyRequest();
const publishRequest = usePublishRequest();
const deliverSupport = useDeliverSupport();
@@ -30,15 +42,15 @@ export default function Admin() {
return (
<div className="container mx-auto px-4 py-12">
<h1 className="text-3xl font-bold text-foreground mb-8">{t.admin.title}</h1>
<div className="bg-card rounded-xl border overflow-hidden shadow-sm">
<Table>
<TableHeader className="bg-muted/50">
<TableRow>
<TableHead>{t.admin.caseId}</TableHead>
<TableHead>{t.admin.beneficiary}</TableHead>
<TableHead>{t.request.needType}</TableHead>
<TableHead>{t.request.amount}</TableHead>
<TableHead>{t.admin.needType}</TableHead>
<TableHead>{t.admin.amount}</TableHead>
<TableHead>{t.admin.status}</TableHead>
<TableHead>{t.admin.currentStep}</TableHead>
<TableHead className="text-right">{t.admin.actions}</TableHead>
@@ -55,8 +67,10 @@ export default function Admin() {
<TableRow key={req.id}>
<TableCell className="font-mono text-xs">{req.caseId}</TableCell>
<TableCell>{req.beneficiaryName}</TableCell>
<TableCell>{t.needTypes[req.needType as keyof typeof t.needTypes] || req.needType}</TableCell>
<TableCell>{req.requestedAmount} </TableCell>
<TableCell>
{t.needTypes[req.needType as keyof typeof t.needTypes] || req.needType}
</TableCell>
<TableCell>{req.requestedAmount.toLocaleString()} </TableCell>
<TableCell>
<Badge variant="secondary" className="font-normal">
{t.statuses[req.status as keyof typeof t.statuses] || req.status}
@@ -64,33 +78,61 @@ export default function Admin() {
</TableCell>
<TableCell>{req.currentStep}/10</TableCell>
<TableCell className="text-right">
<div className="flex items-center justify-end gap-2">
<div className="flex items-center justify-end gap-2 flex-wrap">
<Link href={`/track/${req.id}`}>
<Button variant="outline" size="sm">Track</Button>
<Button variant="outline" size="sm">{t.admin.track}</Button>
</Link>
{req.status === 'new' && (
{req.status === "new" && (
<>
<Button size="sm" onClick={() => handleAction(verifyRequest, req.id)}>Verify</Button>
<Button size="sm" variant="destructive" onClick={() => handleAction(rejectRequest, req.id)}>Reject</Button>
<Button size="sm" onClick={() => handleAction(verifyRequest, req.id)}>
{t.admin.verify}
</Button>
<Button size="sm" variant="destructive" onClick={() => handleAction(rejectRequest, req.id)}>
{t.admin.reject}
</Button>
</>
)}
{req.status === 'verified' && (
<Button size="sm" onClick={() => handleAction(publishRequest, req.id)}>Publish</Button>
{req.status === "pending_review" && (
<>
<Button size="sm" onClick={() => handleAction(verifyRequest, req.id)}>
{t.admin.verify}
</Button>
<Button size="sm" variant="destructive" onClick={() => handleAction(rejectRequest, req.id)}>
{t.admin.reject}
</Button>
</>
)}
{req.status === 'donated' && (
<Button size="sm" onClick={() => handleAction(deliverSupport, req.id)}>Deliver</Button>
{req.status === "verified" && (
<Button size="sm" onClick={() => handleAction(publishRequest, req.id)}>
{t.admin.publish}
</Button>
)}
{req.status === 'delivered' && (
<Button size="sm" onClick={() => handleAction(confirmReceipt, req.id)}>Confirm Receipt</Button>
{req.status === "donated" && (
<Button size="sm" onClick={() => handleAction(deliverSupport, req.id)}>
{t.admin.deliver}
</Button>
)}
{req.status === 'thank_you_submitted' && (
<Link href={`/whatsapp-log`}>
<Button size="sm" variant="outline">WhatsApp</Button>
{req.status === "delivered" && (
<Button size="sm" onClick={() => handleAction(confirmReceipt, req.id)}>
{t.admin.confirmReceipt}
</Button>
)}
{req.status === "receipt_confirmed" && (
<Link href={`/thank-you/${req.id}`}>
<Button size="sm" variant="outline">
{t.track.submitThankYou}
</Button>
</Link>
)}
{req.status === 'whatsapp_sent' && (
<Button size="sm" onClick={() => handleAction(closeRequest, req.id)}>Close Case</Button>
{req.status === "thank_you_submitted" && (
<Link href="/whatsapp-log">
<Button size="sm" variant="outline">{t.admin.whatsapp}</Button>
</Link>
)}
{req.status === "whatsapp_sent" && (
<Button size="sm" onClick={() => handleAction(closeRequest, req.id)}>
{t.admin.close}
</Button>
)}
</div>
</TableCell>
@@ -99,7 +141,7 @@ export default function Admin() {
{(!requests || requests.length === 0) && !isLoading && (
<TableRow>
<TableCell colSpan={7} className="text-center py-8 text-muted-foreground">
No requests found
{t.admin.noRequests}
</TableCell>
</TableRow>
)}
@@ -108,4 +150,4 @@ export default function Admin() {
</div>
</div>
);
}
}