add first files

This commit is contained in:
root
2026-04-30 14:59:57 -04:00
parent 2b97c1a04a
commit 695a7f7cc7
92 changed files with 4873 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
// Standard API response shapes
export interface ApiSuccess<T> {
data: T
}
export interface ApiPaginated<T> {
data: T[]
total: number
page: number
pageSize: number
totalPages: number
}
export interface ApiError {
error: string
message: string
statusCode: number
[key: string]: unknown
}
// Plan prices in smallest currency unit
export const PLAN_PRICES: Record<string, Record<string, Record<string, number>>> = {
STARTER: {
MONTHLY: { MAD: 29900, USD: 2900, EUR: 2700 },
ANNUAL: { MAD: 299000, USD: 29000, EUR: 27000 },
},
GROWTH: {
MONTHLY: { MAD: 59900, USD: 5900, EUR: 5400 },
ANNUAL: { MAD: 599000, USD: 59000, EUR: 54000 },
},
PRO: {
MONTHLY: { MAD: 99900, USD: 9900, EUR: 9000 },
ANNUAL: { MAD: 999000, USD: 99000, EUR: 90000 },
},
}
export type Locale = 'en' | 'fr' | 'ar'
export type SupportedCurrency = 'MAD' | 'USD' | 'EUR'
export function formatCurrency(amount: number, currency: SupportedCurrency, locale: Locale = 'en'): string {
const divisor = 100
const value = amount / divisor
const localeMap: Record<Locale, string> = { en: 'en-US', fr: 'fr-FR', ar: 'ar-MA' }
return new Intl.NumberFormat(localeMap[locale], {
style: 'currency',
currency,
minimumFractionDigits: 2,
}).format(value)
}
+53
View File
@@ -0,0 +1,53 @@
export interface DamageZone {
zone: VehicleZone
severity: 'SCRATCH' | 'DENT' | 'CRACK' | 'MISSING' | 'OTHER'
note?: string
}
export type VehicleZone =
| 'hood' | 'roof' | 'trunk'
| 'front-left-door' | 'front-right-door'
| 'rear-left-door' | 'rear-right-door'
| 'front-left-fender' | 'front-right-fender'
| 'rear-left-fender' | 'rear-right-fender'
| 'front-bumper' | 'rear-bumper'
| 'windshield' | 'rear-window'
| 'left-mirror' | 'right-mirror'
| 'front-left-wheel' | 'front-right-wheel'
| 'rear-left-wheel' | 'rear-right-wheel'
| 'interior' | 'under-hood' | 'undercarriage'
export const DAMAGE_ZONE_COORDS: Record<VehicleZone, { x: number; y: number; w: number; h: number }> = {
'hood': { x: 48, y: 8, w: 64, h: 28 },
'roof': { x: 48, y: 52, w: 64, h: 56 },
'trunk': { x: 48, y: 124, w: 64, h: 28 },
'front-bumper': { x: 48, y: 0, w: 64, h: 10 },
'rear-bumper': { x: 48, y: 150, w: 64, h: 10 },
'front-left-fender': { x: 20, y: 10, w: 30, h: 35 },
'front-right-fender': { x: 110, y: 10, w: 30, h: 35 },
'front-left-door': { x: 20, y: 52, w: 30, h: 30 },
'front-right-door': { x: 110, y: 52, w: 30, h: 30 },
'rear-left-door': { x: 20, y: 82, w: 30, h: 30 },
'rear-right-door': { x: 110, y: 82, w: 30, h: 30 },
'rear-left-fender': { x: 20, y: 112, w: 30, h: 35 },
'rear-right-fender': { x: 110, y: 112, w: 30, h: 35 },
'windshield': { x: 52, y: 38, w: 56, h: 18 },
'rear-window': { x: 52, y: 104, w: 56, h: 18 },
'left-mirror': { x: 8, y: 50, w: 14, h: 10 },
'right-mirror': { x: 138, y: 50, w: 14, h: 10 },
'front-left-wheel': { x: 10, y: 24, w: 22, h: 26 },
'front-right-wheel': { x: 128, y: 24, w: 22, h: 26 },
'rear-left-wheel': { x: 10, y: 110, w: 22, h: 26 },
'rear-right-wheel': { x: 128, y: 110, w: 22, h: 26 },
'interior': { x: 55, y: 58, w: 50, h: 44 },
'under-hood': { x: 52, y: 10, w: 56, h: 20 },
'undercarriage': { x: 52, y: 130, w: 56, h: 20 },
}
export const SEVERITY_COLORS: Record<DamageZone['severity'], string> = {
SCRATCH: '#F59E0B',
DENT: '#EF4444',
CRACK: '#8B5CF6',
MISSING: '#374151',
OTHER: '#6B7280',
}
+29
View File
@@ -0,0 +1,29 @@
export type FuelPolicyType = 'FULL_TO_FULL' | 'FULL_TO_EMPTY' | 'SAME_TO_SAME' | 'PREPAID' | 'FREE'
export const FUEL_POLICY_LABELS: Record<FuelPolicyType, Record<'en' | 'fr' | 'ar', string>> = {
FULL_TO_FULL: {
en: 'Full-to-Full: Return vehicle with a full tank. A refueling fee applies if returned with less fuel.',
fr: "Plein-à-Plein: Retournez le véhicule avec le plein. Des frais de carburant s'appliquent sinon.",
ar: 'ممتلئ إلى ممتلئ: يجب إعادة السيارة بخزان ممتلئ. رسوم إضافية في حال الإعادة بمستوى أقل.',
},
FULL_TO_EMPTY: {
en: 'Full-to-Empty: Vehicle is provided with a full tank. No refund for unused fuel upon return.',
fr: 'Plein-à-Vide: Le véhicule est fourni avec un plein. Aucun remboursement pour carburant non utilisé.',
ar: 'ممتلئ إلى فارغ: تُسلَّم السيارة بخزان ممتلئ. لا استرداد للوقود غير المستخدم.',
},
SAME_TO_SAME: {
en: 'Same-to-Same: Return vehicle with the same fuel level as at pickup.',
fr: "Même niveau: Retournez avec le même niveau de carburant qu'au départ.",
ar: 'نفس المستوى: أعد السيارة بنفس مستوى الوقود عند الاستلام.',
},
PREPAID: {
en: 'Prepaid Fuel: You pre-purchase a full tank at a fixed rate. Return at any fuel level.',
fr: "Carburant prépayé: Vous prépayez un plein à tarif fixe. Retour à n'importe quel niveau.",
ar: 'الوقود المدفوع مسبقاً: تدفع مقدماً لخزان كامل بسعر ثابت. العودة بأي مستوى.',
},
FREE: {
en: 'Fuel Included: Fuel cost is included in the rental price.',
fr: 'Carburant inclus: Le coût du carburant est inclus dans le tarif de location.',
ar: 'الوقود مشمول: تكلفة الوقود مشمولة في سعر الإيجار.',
},
}
+3
View File
@@ -0,0 +1,3 @@
export * from './damage'
export * from './fuel'
export * from './api'