- Replace Clerk with self-hosted JWT auth (register/login/verify, bcrypt passwords, Gmail OTP with console fallback) - Add lib/db.ts pg pool + transaction helpers; seed script migrates legacy Clerk-era schema (drop clerk_id, enforce UUID ids and unique email) - Add owner-gated admin API: stats, users, drivers CRUD, rides - Add dashboard/ Vite React owner dashboard (login, overview, users, fleet, rides) with dev-server proxy to avoid Expo CORS middleware - Add scripts/set-owner.mjs for role management
35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
// Fare model tuned to the Lebanese market:
|
||
// - Distance-based with a base fare (like CTaxi/local taxis), not time-only.
|
||
// - Typical Beirut rides land in the $3–8 range riders expect.
|
||
// - Prices are quoted in USD (the de facto ride-hailing currency) with an
|
||
// L.B.P. equivalent shown for cash settlement.
|
||
|
||
export const FARE = {
|
||
base: 1.5, // USD, flag drop
|
||
perKm: 0.55, // USD per kilometer of the trip
|
||
perMin: 0.15, // USD per minute of the trip
|
||
minimum: 3.0, // USD minimum fare
|
||
} as const;
|
||
|
||
// Parallel market rate used for the L.B.P. cash equivalent shown in-app.
|
||
export const LBP_RATE = 89500;
|
||
|
||
export const calculateFare = ({
|
||
distanceMeters,
|
||
durationSeconds,
|
||
}: {
|
||
distanceMeters: number;
|
||
durationSeconds: number;
|
||
}): string => {
|
||
const km = distanceMeters / 1000;
|
||
const minutes = durationSeconds / 60;
|
||
|
||
const fare = FARE.base + km * FARE.perKm + minutes * FARE.perMin;
|
||
|
||
return Math.max(fare, FARE.minimum).toFixed(2);
|
||
};
|
||
|
||
// Rounds to the nearest 1,000 L.B.P. — the smallest practical cash note.
|
||
export const formatLBP = (usd: number): string =>
|
||
`${(Math.round((usd * LBP_RATE) / 1000) * 1000).toLocaleString("en-US")} L.B.P.`;
|