Build EHSAN Closed Donation Loop POC — full bilingual Arabic/English app

- Backend (api-server): Complete in-memory mock DB with 11 seed cases, 5 eligible
  beneficiaries, 3 donors, and WhatsApp log. All 14 API routes implemented across
  requests, donors, stats, and whatsapp-log. OpenClaw integration with OPENCLAW_SIMULATE
  toggle. UUID-based IDs. Full status machine (new → closed, 10 steps).

- Frontend (ehsan-poc): 8 pages fully implemented using all generated API hooks:
  Home (stats counters, 10-step workflow diagram), Request (form with eligibility
  result), Opportunities (card grid with progress bars), Donate (case summary +
  donor form), Admin (full data table with contextual action buttons), Track
  (10-step visual timeline in green), ThankYou (message form), WhatsApp Log
  (WhatsApp bubble preview + OpenClaw send button).

- Bilingual LanguageContext (AR/EN) with RTL/LTR toggle, localStorage persistence.
  EHSAN green palette (HSL 143), Tajawal font, fully responsive.
  TypeScript clean — zero errors.
This commit is contained in:
Replit Agent
2026-06-05 17:05:27 +00:00
parent 2da838bb66
commit 12111a9562
117 changed files with 12366 additions and 81 deletions
+487 -6
View File
@@ -1,16 +1,497 @@
/**
* Generated by orval v8.5.3 🍺
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* API specification
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
import * as zod from "zod";
import * as zod from 'zod';
/**
* Returns server health status
* @summary Health check
*/
export const HealthCheckResponse = zod.object({
status: zod.string(),
});
"status": zod.string()
})
/**
* @summary List all donation requests
*/
export const ListRequestsQueryParams = zod.object({
"status": zod.coerce.string().optional(),
"needType": zod.coerce.string().optional()
})
export const ListRequestsResponseItem = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
export const ListRequestsResponse = zod.array(ListRequestsResponseItem)
/**
* @summary Submit a new beneficiary request
*/
export const CreateRequestBody = zod.object({
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"description": zod.string()
})
/**
* @summary List new (unreviewed) requests
*/
export const ListNewRequestsResponseItem = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
export const ListNewRequestsResponse = zod.array(ListNewRequestsResponseItem)
/**
* @summary List published donation opportunities (public)
*/
export const ListPublishedRequestsResponseItem = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
export const ListPublishedRequestsResponse = zod.array(ListPublishedRequestsResponseItem)
/**
* @summary Get a single request by ID
*/
export const GetRequestParams = zod.object({
"id": zod.coerce.string()
})
export const GetRequestResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary Verify a request (admin)
*/
export const VerifyRequestParams = zod.object({
"id": zod.coerce.string()
})
export const VerifyRequestResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary Publish a verified request as a donation opportunity
*/
export const PublishRequestParams = zod.object({
"id": zod.coerce.string()
})
export const PublishRequestResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary Simulate a donation to a published request
*/
export const DonateToRequestParams = zod.object({
"id": zod.coerce.string()
})
export const DonateToRequestBody = zod.object({
"donorName": zod.string(),
"donorPhone": zod.string(),
"donorEmail": zod.string().nullish(),
"amount": zod.number()
})
export const DonateToRequestResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary Mark support as delivered
*/
export const DeliverSupportParams = zod.object({
"id": zod.coerce.string()
})
export const DeliverSupportResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary Confirm beneficiary received support
*/
export const ConfirmReceiptParams = zod.object({
"id": zod.coerce.string()
})
export const ConfirmReceiptResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary Submit beneficiary thank-you message
*/
export const SubmitThankYouParams = zod.object({
"id": zod.coerce.string()
})
export const SubmitThankYouBody = zod.object({
"beneficiaryName": zod.string(),
"message": zod.string()
})
export const SubmitThankYouResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary Send thank-you WhatsApp to donor via OpenClaw
*/
export const SendWhatsappParams = zod.object({
"id": zod.coerce.string()
})
export const SendWhatsappResponse = zod.object({
"success": zod.boolean(),
"message": zod.string(),
"simulated": zod.boolean(),
"sentAt": zod.string().nullish()
})
/**
* @summary Close the case
*/
export const CloseRequestParams = zod.object({
"id": zod.coerce.string()
})
export const CloseRequestResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary Reject a request
*/
export const RejectRequestParams = zod.object({
"id": zod.coerce.string()
})
export const RejectRequestBody = zod.object({
"reason": zod.string().optional()
})
export const RejectRequestResponse = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"beneficiaryName": zod.string(),
"nationalId": zod.string(),
"phone": zod.string(),
"source": zod.enum(['beneficiary', 'charity', 'official']),
"sourceName": zod.string(),
"needType": zod.enum(['electricity', 'water', 'food', 'health', 'housing', 'refrigerator', 'air_conditioner', 'court_order']),
"requestedAmount": zod.number(),
"collectedAmount": zod.number(),
"description": zod.string(),
"status": zod.enum(['new', 'pending_review', 'verified', 'published', 'donated', 'delivered', 'receipt_confirmed', 'thank_you_submitted', 'whatsapp_sent', 'closed', 'rejected']),
"currentStep": zod.number(),
"donorId": zod.string().nullish(),
"donorName": zod.string().nullish(),
"thankYouMessage": zod.string().nullish(),
"whatsappStatus": zod.union([zod.literal('pending'),zod.literal('sent'),zod.literal('failed'),zod.literal(null)]).nullish(),
"whatsappSentAt": zod.string().nullish(),
"rejectionReason": zod.string().nullish(),
"createdAt": zod.string(),
"updatedAt": zod.string()
})
/**
* @summary List all donors
*/
export const ListDonorsResponseItem = zod.object({
"id": zod.string(),
"name": zod.string(),
"phone": zod.string(),
"email": zod.string().nullish(),
"totalDonated": zod.number(),
"donationCount": zod.number()
})
export const ListDonorsResponse = zod.array(ListDonorsResponseItem)
/**
* @summary Dashboard statistics summary
*/
export const GetStatsResponse = zod.object({
"totalRequests": zod.number(),
"totalDonated": zod.number(),
"totalCollected": zod.number(),
"totalClosed": zod.number(),
"pendingVerification": zod.number().optional(),
"activeOpportunities": zod.number().optional(),
"byStatus": zod.array(zod.object({
"status": zod.string(),
"count": zod.number()
})),
"byNeedType": zod.array(zod.object({
"needType": zod.string(),
"count": zod.number(),
"totalAmount": zod.number()
}))
})
/**
* @summary List all WhatsApp message log entries
*/
export const ListWhatsappLogResponseItem = zod.object({
"id": zod.string(),
"caseId": zod.string(),
"donorName": zod.string(),
"donorPhone": zod.string(),
"beneficiaryMessage": zod.string(),
"whatsappMessage": zod.string(),
"status": zod.enum(['pending', 'sent', 'failed']),
"sentAt": zod.string().nullish(),
"createdAt": zod.string()
})
export const ListWhatsappLogResponse = zod.array(ListWhatsappLogResponseItem)
@@ -0,0 +1,15 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export interface DonationInput {
donorName: string;
donorPhone: string;
/** @nullable */
donorEmail?: string | null;
amount: number;
}
@@ -0,0 +1,41 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
import type { DonationRequestNeedType } from './donationRequestNeedType';
import type { DonationRequestSource } from './donationRequestSource';
import type { DonationRequestStatus } from './donationRequestStatus';
import type { DonationRequestWhatsappStatus } from './donationRequestWhatsappStatus';
export interface DonationRequest {
id: string;
caseId: string;
beneficiaryName: string;
nationalId: string;
phone: string;
source: DonationRequestSource;
sourceName: string;
needType: DonationRequestNeedType;
requestedAmount: number;
collectedAmount: number;
description: string;
status: DonationRequestStatus;
currentStep: number;
/** @nullable */
donorId?: string | null;
/** @nullable */
donorName?: string | null;
/** @nullable */
thankYouMessage?: string | null;
/** @nullable */
whatsappStatus?: DonationRequestWhatsappStatus;
/** @nullable */
whatsappSentAt?: string | null;
/** @nullable */
rejectionReason?: string | null;
createdAt: string;
updatedAt: string;
}
@@ -0,0 +1,20 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
import type { DonationRequestInputNeedType } from './donationRequestInputNeedType';
import type { DonationRequestInputSource } from './donationRequestInputSource';
export interface DonationRequestInput {
beneficiaryName: string;
nationalId: string;
phone: string;
source: DonationRequestInputSource;
sourceName: string;
needType: DonationRequestInputNeedType;
requestedAmount: number;
description: string;
}
@@ -0,0 +1,21 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export type DonationRequestInputNeedType = typeof DonationRequestInputNeedType[keyof typeof DonationRequestInputNeedType];
export const DonationRequestInputNeedType = {
electricity: 'electricity',
water: 'water',
food: 'food',
health: 'health',
housing: 'housing',
refrigerator: 'refrigerator',
air_conditioner: 'air_conditioner',
court_order: 'court_order',
} as const;
@@ -0,0 +1,16 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export type DonationRequestInputSource = typeof DonationRequestInputSource[keyof typeof DonationRequestInputSource];
export const DonationRequestInputSource = {
beneficiary: 'beneficiary',
charity: 'charity',
official: 'official',
} as const;
@@ -0,0 +1,21 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export type DonationRequestNeedType = typeof DonationRequestNeedType[keyof typeof DonationRequestNeedType];
export const DonationRequestNeedType = {
electricity: 'electricity',
water: 'water',
food: 'food',
health: 'health',
housing: 'housing',
refrigerator: 'refrigerator',
air_conditioner: 'air_conditioner',
court_order: 'court_order',
} as const;
@@ -0,0 +1,16 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export type DonationRequestSource = typeof DonationRequestSource[keyof typeof DonationRequestSource];
export const DonationRequestSource = {
beneficiary: 'beneficiary',
charity: 'charity',
official: 'official',
} as const;
@@ -0,0 +1,24 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export type DonationRequestStatus = typeof DonationRequestStatus[keyof typeof DonationRequestStatus];
export const DonationRequestStatus = {
new: 'new',
pending_review: 'pending_review',
verified: 'verified',
published: 'published',
donated: 'donated',
delivered: 'delivered',
receipt_confirmed: 'receipt_confirmed',
thank_you_submitted: 'thank_you_submitted',
whatsapp_sent: 'whatsapp_sent',
closed: 'closed',
rejected: 'rejected',
} as const;
@@ -0,0 +1,19 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
/**
* @nullable
*/
export type DonationRequestWhatsappStatus = typeof DonationRequestWhatsappStatus[keyof typeof DonationRequestWhatsappStatus] | null;
export const DonationRequestWhatsappStatus = {
pending: 'pending',
sent: 'sent',
failed: 'failed',
} as const;
+17
View File
@@ -0,0 +1,17 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export interface Donor {
id: string;
name: string;
phone: string;
/** @nullable */
email?: string | null;
totalDonated: number;
donationCount: number;
}
@@ -1,8 +1,8 @@
/**
* Generated by orval v8.5.3 🍺
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* API specification
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
+22 -3
View File
@@ -1,9 +1,28 @@
/**
* Generated by orval v8.5.3 🍺
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* API specification
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export * from "./healthStatus";
export * from './donationInput';
export * from './donationRequest';
export * from './donationRequestInput';
export * from './donationRequestInputNeedType';
export * from './donationRequestInputSource';
export * from './donationRequestNeedType';
export * from './donationRequestSource';
export * from './donationRequestStatus';
export * from './donationRequestWhatsappStatus';
export * from './donor';
export * from './healthStatus';
export * from './listRequestsParams';
export * from './needTypeCount';
export * from './rejectInput';
export * from './stats';
export * from './statusCount';
export * from './thankYouInput';
export * from './whatsappLogEntry';
export * from './whatsappLogEntryStatus';
export * from './whatsappResult';
@@ -0,0 +1,12 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export type ListRequestsParams = {
status?: string;
needType?: string;
};
@@ -0,0 +1,13 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export interface NeedTypeCount {
needType: string;
count: number;
totalAmount: number;
}
@@ -0,0 +1,11 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export interface RejectInput {
reason?: string;
}
+20
View File
@@ -0,0 +1,20 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
import type { NeedTypeCount } from './needTypeCount';
import type { StatusCount } from './statusCount';
export interface Stats {
totalRequests: number;
totalDonated: number;
totalCollected: number;
totalClosed: number;
pendingVerification?: number;
activeOpportunities?: number;
byStatus: StatusCount[];
byNeedType: NeedTypeCount[];
}
@@ -0,0 +1,12 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export interface StatusCount {
status: string;
count: number;
}
@@ -0,0 +1,12 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export interface ThankYouInput {
beneficiaryName: string;
message: string;
}
@@ -0,0 +1,21 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
import type { WhatsappLogEntryStatus } from './whatsappLogEntryStatus';
export interface WhatsappLogEntry {
id: string;
caseId: string;
donorName: string;
donorPhone: string;
beneficiaryMessage: string;
whatsappMessage: string;
status: WhatsappLogEntryStatus;
/** @nullable */
sentAt?: string | null;
createdAt: string;
}
@@ -0,0 +1,16 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export type WhatsappLogEntryStatus = typeof WhatsappLogEntryStatus[keyof typeof WhatsappLogEntryStatus];
export const WhatsappLogEntryStatus = {
pending: 'pending',
sent: 'sent',
failed: 'failed',
} as const;
@@ -0,0 +1,15 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* EHSAN Closed Donation Loop API
* OpenAPI spec version: 0.1.0
*/
export interface WhatsappResult {
success: boolean;
message: string;
simulated: boolean;
/** @nullable */
sentAt?: string | null;
}