Files
edr-platform/apps/edr-passenger-web/backoffice/generate-pages.js
2026-05-31 13:15:44 +03:00

301 lines
14 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const pages = [
{
name: 'payments',
title: 'Payments',
description: 'Manage payment transactions and refunds',
api: 'paymentsApi',
columns: `[
{ key: 'reference', label: 'Reference', render: (payment: any) => <span className="font-mono">{payment.reference || payment.id?.substring(0, 8)}</span> },
{ key: 'booking', label: 'Booking', render: (payment: any) => payment.booking?.bookingRef || 'N/A' },
{ key: 'amount', label: 'Amount', render: (payment: any) => formatCurrency(payment.amountMinor, payment.currency) },
{ key: 'method', label: 'Method', render: (payment: any) => <Badge>{payment.method}</Badge> },
{ key: 'status', label: 'Status', render: (payment: any) => <Badge variant="status" status={payment.status}>{payment.status}</Badge> },
{ key: 'createdAt', label: 'Created', render: (payment: any) => formatDateTime(payment.createdAt) },
]`,
filters: `{ search: '', status: '', method: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
<div>
<label className="label">Status</label>
<select className="input" value={filters.status} onChange={(e) => setFilters({ ...filters, status: e.target.value })}>
<option value="">All Status</option>
<option value="PENDING">Pending</option>
<option value="COMPLETED">Completed</option>
<option value="FAILED">Failed</option>
</select>
</div>
`
},
{
name: 'loyalty',
title: 'Loyalty Program',
description: 'Manage loyalty accounts and rewards',
api: 'loyaltyApi',
columns: `[
{ key: 'passenger', label: 'Passenger', render: (account: any) => account.passenger?.fullName || 'N/A' },
{ key: 'tier', label: 'Tier', render: (account: any) => <Badge>{account.tier}</Badge> },
{ key: 'pointsBalance', label: 'Points', render: (account: any) => account.pointsBalance?.toLocaleString() || 0 },
{ key: 'lifetimePoints', label: 'Lifetime Points', render: (account: any) => account.lifetimePoints?.toLocaleString() || 0 },
]`,
filters: `{ search: '', tier: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
<div>
<label className="label">Tier</label>
<select className="input" value={filters.tier} onChange={(e) => setFilters({ ...filters, tier: e.target.value })}>
<option value="">All Tiers</option>
<option value="BRONZE">Bronze</option>
<option value="SILVER">Silver</option>
<option value="GOLD">Gold</option>
<option value="PLATINUM">Platinum</option>
</select>
</div>
`
},
{
name: 'wallet',
title: 'Wallet Management',
description: 'Manage passenger wallet accounts',
api: 'walletApi',
columns: `[
{ key: 'passenger', label: 'Passenger', render: (account: any) => account.passenger?.fullName || 'N/A' },
{ key: 'balanceMinor', label: 'Balance', render: (account: any) => formatCurrency(account.balanceMinor, 'ETB') },
{ key: 'status', label: 'Status', render: (account: any) => <Badge variant="status" status={account.isActive ? 'CONFIRMED' : 'CANCELLED'}>{account.isActive ? 'Active' : 'Inactive'}</Badge> },
]`,
filters: `{ search: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
`
},
{
name: 'support',
title: 'Support Center',
description: 'Manage customer support conversations',
api: 'supportApi',
columns: `[
{ key: 'subject', label: 'Subject', render: (conv: any) => conv.subject || 'No Subject' },
{ key: 'passenger', label: 'Passenger', render: (conv: any) => conv.passenger?.fullName || 'N/A' },
{ key: 'status', label: 'Status', render: (conv: any) => <Badge variant="status" status={conv.status}>{conv.status}</Badge> },
{ key: 'createdAt', label: 'Created', render: (conv: any) => formatDateTime(conv.createdAt) },
]`,
filters: `{ search: '', status: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
<div>
<label className="label">Status</label>
<select className="input" value={filters.status} onChange={(e) => setFilters({ ...filters, status: e.target.value })}>
<option value="">All Status</option>
<option value="OPEN">Open</option>
<option value="IN_PROGRESS">In Progress</option>
<option value="RESOLVED">Resolved</option>
<option value="CLOSED">Closed</option>
</select>
</div>
`
},
{
name: 'verifayda',
title: 'Verifayda Integration',
description: 'Ethiopian national ID verification logs',
api: 'verifaydaApi',
columns: `[
{ key: 'nationalId', label: 'National ID', render: (ver: any) => <span className="font-mono">{ver.nationalId}</span> },
{ key: 'fullName', label: 'Name', render: (ver: any) => ver.fullName || 'N/A' },
{ key: 'verified', label: 'Status', render: (ver: any) => <Badge variant="status" status={ver.verified ? 'CONFIRMED' : 'CANCELLED'}>{ver.verified ? 'Verified' : 'Failed'}</Badge> },
{ key: 'createdAt', label: 'Verified At', render: (ver: any) => formatDateTime(ver.createdAt) },
]`,
filters: `{ search: '', verified: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search by National ID..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
<div>
<label className="label">Status</label>
<select className="input" value={filters.verified} onChange={(e) => setFilters({ ...filters, verified: e.target.value })}>
<option value="">All</option>
<option value="true">Verified</option>
<option value="false">Failed</option>
</select>
</div>
`
},
{
name: 'food',
title: 'Food & Dining',
description: 'Manage food orders and menu items',
api: 'foodApi',
columns: `[
{ key: 'orderNumber', label: 'Order #', render: (order: any) => <span className="font-mono">{order.orderNumber || order.id?.substring(0, 8)}</span> },
{ key: 'passenger', label: 'Passenger', render: (order: any) => order.passenger?.fullName || 'N/A' },
{ key: 'items', label: 'Items', render: (order: any) => order.items?.length || 0 },
{ key: 'totalMinor', label: 'Total', render: (order: any) => formatCurrency(order.totalMinor, 'ETB') },
{ key: 'status', label: 'Status', render: (order: any) => <Badge variant="status" status={order.status}>{order.status}</Badge> },
]`,
filters: `{ search: '', status: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
<div>
<label className="label">Status</label>
<select className="input" value={filters.status} onChange={(e) => setFilters({ ...filters, status: e.target.value })}>
<option value="">All Status</option>
<option value="PENDING">Pending</option>
<option value="PREPARING">Preparing</option>
<option value="READY">Ready</option>
<option value="DELIVERED">Delivered</option>
</select>
</div>
`
},
{
name: 'schedules',
title: 'Schedules',
description: 'Manage train schedules and trips',
api: 'schedulesApi',
columns: `[
{ key: 'train', label: 'Train', render: (schedule: any) => schedule.train?.name || 'N/A' },
{ key: 'route', label: 'Route', render: (schedule: any) => \`\${schedule.originStation?.name || 'N/A'} → \${schedule.destinationStation?.name || 'N/A'}\` },
{ key: 'departureAt', label: 'Departure', render: (schedule: any) => formatDateTime(schedule.departureAt) },
{ key: 'status', label: 'Status', render: (schedule: any) => <Badge variant="status" status={schedule.status}>{schedule.status}</Badge> },
]`,
filters: `{ search: '', status: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
<div>
<label className="label">Status</label>
<select className="input" value={filters.status} onChange={(e) => setFilters({ ...filters, status: e.target.value })}>
<option value="">All Status</option>
<option value="SCHEDULED">Scheduled</option>
<option value="ACTIVE">Active</option>
<option value="COMPLETED">Completed</option>
<option value="CANCELLED">Cancelled</option>
</select>
</div>
`
},
{
name: 'seat-classes',
title: 'Seat Classes',
description: 'Manage seat class configurations',
api: 'seatClassesApi',
columns: `[
{ key: 'name', label: 'Name', render: (cls: any) => <span className="font-medium">{cls.name}</span> },
{ key: 'description', label: 'Description', render: (cls: any) => cls.description || 'N/A' },
{ key: 'basePrice', label: 'Base Price', render: (cls: any) => formatCurrency(cls.basePrice, 'ETB') },
{ key: 'isActive', label: 'Status', render: (cls: any) => <Badge variant="status" status={cls.isActive ? 'CONFIRMED' : 'CANCELLED'}>{cls.isActive ? 'Active' : 'Inactive'}</Badge> },
]`,
filters: `{ search: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
`
},
{
name: 'operational-reports',
title: 'Operational Reports',
description: 'View operational reports and analytics',
api: 'reportsApi',
columns: `[
{ key: 'reportType', label: 'Type', render: (report: any) => <Badge>{report.reportType}</Badge> },
{ key: 'period', label: 'Period', render: (report: any) => report.period || 'N/A' },
{ key: 'generatedBy', label: 'Generated By', render: (report: any) => report.generatedBy?.fullName || 'System' },
{ key: 'createdAt', label: 'Generated', render: (report: any) => formatDateTime(report.createdAt) },
]`,
filters: `{ search: '', reportType: '' }`,
filterInputs: `
<div>
<label className="label">Search</label>
<input type="text" placeholder="Search..." className="input" value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} />
</div>
<div>
<label className="label">Report Type</label>
<select className="input" value={filters.reportType} onChange={(e) => setFilters({ ...filters, reportType: e.target.value })}>
<option value="">All Types</option>
<option value="REVENUE">Revenue</option>
<option value="OCCUPANCY">Occupancy</option>
<option value="PERFORMANCE">Performance</option>
</select>
</div>
`
}
];
const template = (page) => `'use client';
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Download } from 'lucide-react';
import DataTable from '@/components/ui/DataTable';
import Badge from '@/components/ui/Badge';
import ActionButton from '@/components/ui/ActionButton';
import { ${page.api} } from '@/lib/api';
import { formatDateTime, formatCurrency } from '@/lib/utils';
export default function ${page.name.charAt(0).toUpperCase() + page.name.slice(1).replace(/-/g, '')}Page() {
const [filters, setFilters] = useState(${page.filters});
const { data, isLoading } = useQuery({
queryKey: ['${page.name}', filters],
queryFn: () => ${page.api}.${page.name === 'seat-classes' ? 'getAll()' : page.name === 'operational-reports' ? 'getOperationalReports(filters)' : `get${page.name === 'support' ? 'Conversations' : page.name === 'loyalty' ? 'Accounts' : page.name === 'wallet' ? 'Accounts' : page.name === 'verifayda' ? 'Verifications' : page.name === 'food' ? 'Orders' : 'All'}(filters)`},
});
const columns = ${page.columns};
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold text-foreground">${page.title}</h1>
<p className="text-muted-foreground">${page.description}</p>
</div>
<ActionButton icon={Download} variant="secondary">Export</ActionButton>
</div>
<div className="card">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
${page.filterInputs}
</div>
</div>
<DataTable
data={data?.items || data || []}
columns={columns}
loading={isLoading}
emptyMessage="No ${page.title.toLowerCase()} found"
/>
</div>
);
}
`;
pages.forEach(page => {
const filePath = path.join(__dirname, 'src', 'app', page.name, 'page.tsx');
fs.writeFileSync(filePath, template(page));
console.log(`✅ Created ${page.name}/page.tsx`);
});
console.log('\\n✅ All pages created successfully!');