add first files
This commit is contained in:
@@ -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)
|
||||
}
|
||||
@@ -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',
|
||||
}
|
||||
@@ -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: 'الوقود مشمول: تكلفة الوقود مشمولة في سعر الإيجار.',
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './damage'
|
||||
export * from './fuel'
|
||||
export * from './api'
|
||||
Reference in New Issue
Block a user