fe8ffbeb9f
Build & Push / Pipeline Tests (push) Failing after 59s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Failing after 48s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Carplace Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped
156 lines
7.6 KiB
TypeScript
156 lines
7.6 KiB
TypeScript
import { z } from 'zod'
|
|
import { optionalTextField, optionalTitleCaseAllField, optionalUpperField, optionalEmailField, optionalPhoneField } from '../../lib/zodValidation'
|
|
|
|
export const companySchema = z.object({
|
|
name: optionalTextField('commercialName'),
|
|
email: optionalEmailField(),
|
|
phone: optionalPhoneField(),
|
|
address: z.record(z.unknown()).optional(),
|
|
})
|
|
|
|
export const brandSchema = z.object({
|
|
displayName: z.string().min(1).optional(),
|
|
tagline: z.string().optional(),
|
|
primaryColor: z.string().optional(),
|
|
accentColor: z.string().optional(),
|
|
publicEmail: optionalEmailField(),
|
|
publicPhone: optionalPhoneField(),
|
|
publicAddress: z.string().optional(),
|
|
publicCity: optionalTextField('city'),
|
|
publicCountry: optionalTextField('country'),
|
|
websiteUrl: z.string().url().optional(),
|
|
whatsappNumber: z.string().optional(),
|
|
defaultLocale: z.string().optional(),
|
|
defaultCurrency: z.literal('MAD').optional(),
|
|
isListedOnCarplace: z.boolean().optional(),
|
|
homePageConfig: z.object({
|
|
heroTitle: z.union([z.string(), z.null()]).optional(),
|
|
heroDescription: z.union([z.string(), z.null()]).optional(),
|
|
viewOffersLabel: z.union([z.string(), z.null()]).optional(),
|
|
viewPricingLabel: z.union([z.string(), z.null()]).optional(),
|
|
contactCompanyLabel: z.union([z.string(), z.null()]).optional(),
|
|
activeOffersTitle: z.union([z.string(), z.null()]).optional(),
|
|
seeAllOffersLabel: z.union([z.string(), z.null()]).optional(),
|
|
noActiveOffersLabel: z.union([z.string(), z.null()]).optional(),
|
|
publishedVehiclesTitle: z.union([z.string(), z.null()]).optional(),
|
|
viewVehicleLabel: z.union([z.string(), z.null()]).optional(),
|
|
pricingEyebrow: z.union([z.string(), z.null()]).optional(),
|
|
pricingTitle: z.union([z.string(), z.null()]).optional(),
|
|
pricingDescription: z.union([z.string(), z.null()]).optional(),
|
|
showOffers: z.boolean().optional(),
|
|
showVehicles: z.boolean().optional(),
|
|
showPricing: z.boolean().optional(),
|
|
layout: z.object({
|
|
items: z.array(z.object({
|
|
id: z.string().min(1),
|
|
type: z.enum(['hero', 'offers', 'vehicles', 'pricing']),
|
|
x: z.number().int().min(1),
|
|
y: z.number().int().min(1),
|
|
w: z.number().int().min(1),
|
|
h: z.number().int().min(1),
|
|
})),
|
|
}).optional(),
|
|
}).optional(),
|
|
menuConfig: z.object({
|
|
aboutLabel: z.union([z.string(), z.null()]).optional(),
|
|
vehiclesLabel: z.union([z.string(), z.null()]).optional(),
|
|
offersLabel: z.union([z.string(), z.null()]).optional(),
|
|
pricingLabel: z.union([z.string(), z.null()]).optional(),
|
|
blogLabel: z.union([z.string(), z.null()]).optional(),
|
|
contactLabel: z.union([z.string(), z.null()]).optional(),
|
|
bookCarLabel: z.union([z.string(), z.null()]).optional(),
|
|
siteNavigationLabel: z.union([z.string(), z.null()]).optional(),
|
|
showAbout: z.boolean().optional(),
|
|
showVehicles: z.boolean().optional(),
|
|
showOffers: z.boolean().optional(),
|
|
showPricing: z.boolean().optional(),
|
|
showBlog: z.boolean().optional(),
|
|
showContact: z.boolean().optional(),
|
|
pageSections: z.object({
|
|
home: z.object({
|
|
hero: z.boolean().optional(), offers: z.boolean().optional(),
|
|
vehicles: z.boolean().optional(), pricing: z.boolean().optional(),
|
|
}).optional(),
|
|
about: z.object({
|
|
hero: z.boolean().optional(), highlights: z.boolean().optional(), details: z.boolean().optional(),
|
|
}).optional(),
|
|
offers: z.object({ header: z.boolean().optional(), grid: z.boolean().optional() }).optional(),
|
|
pricing: z.object({
|
|
hero: z.boolean().optional(), plans: z.boolean().optional(),
|
|
payments: z.boolean().optional(), faq: z.boolean().optional(),
|
|
}).optional(),
|
|
vehicles: z.object({
|
|
header: z.boolean().optional(), filters: z.boolean().optional(), grid: z.boolean().optional(),
|
|
}).optional(),
|
|
vehicleDetail: z.object({ gallery: z.boolean().optional(), summary: z.boolean().optional() }).optional(),
|
|
blog: z.object({ hero: z.boolean().optional(), posts: z.boolean().optional() }).optional(),
|
|
contact: z.object({ content: z.boolean().optional() }).optional(),
|
|
booking: z.object({ content: z.boolean().optional() }).optional(),
|
|
bookingConfirmation: z.object({
|
|
hero: z.boolean().optional(), summary: z.boolean().optional(), actions: z.boolean().optional(),
|
|
}).optional(),
|
|
}).optional(),
|
|
}).optional(),
|
|
})
|
|
|
|
export const contractSettingsSchema = z.object({
|
|
legalName: optionalTitleCaseAllField('legalCompanyName'),
|
|
registrationNumber: optionalUpperField('commercialRegistry'),
|
|
taxId: z.string().optional(),
|
|
terms: z.string().optional(),
|
|
fuelPolicy: z.string().optional(),
|
|
depositPolicy: z.string().optional(),
|
|
lateFeePolicy: z.string().optional(),
|
|
damagePolicy: z.string().optional(),
|
|
additionalDriverPolicy: z.string().optional(),
|
|
contractFooterNote: z.string().optional(),
|
|
invoiceFooterNote: z.string().optional(),
|
|
signatureRequired: z.boolean().optional(),
|
|
showTax: z.boolean().optional(),
|
|
taxLabel: z.string().optional(),
|
|
fuelPolicyType: z.enum(['FULL_TO_FULL', 'FULL_TO_EMPTY', 'SAME_TO_SAME', 'PREPAID', 'FREE']).optional(),
|
|
fuelPolicyNote: z.string().optional(),
|
|
fuelChargePerLiter: z.number().int().optional(),
|
|
fuelShortfallFee: z.number().int().optional(),
|
|
lateFeePerHour: z.number().int().optional(),
|
|
additionalDriverCharge: z.enum(['FREE', 'PER_DAY', 'FLAT']).optional(),
|
|
additionalDriverDailyRate: z.number().int().optional(),
|
|
additionalDriverFlatRate: z.number().int().optional(),
|
|
})
|
|
|
|
export const insurancePolicySchema = z.object({
|
|
name: z.string().min(1),
|
|
description: z.string().optional(),
|
|
type: z.enum(['CDW', 'SCDW', 'THEFT', 'THIRD_PARTY', 'FULL', 'BASIC', 'ROADSIDE', 'PERSONAL', 'CUSTOM']),
|
|
chargeType: z.enum(['PER_DAY', 'PER_RENTAL', 'PERCENTAGE_OF_RENTAL']),
|
|
chargeValue: z.number().int().min(0),
|
|
isRequired: z.boolean().default(false),
|
|
isActive: z.boolean().default(true),
|
|
sortOrder: z.number().int().default(0),
|
|
})
|
|
|
|
export const pricingRuleSchema = z.object({
|
|
name: z.string().min(1),
|
|
type: z.enum(['SURCHARGE', 'DISCOUNT']),
|
|
condition: z.enum(['AGE_LESS_THAN', 'AGE_GREATER_THAN', 'LICENSE_YEARS_LESS_THAN', 'LICENSE_YEARS_GREATER_THAN']),
|
|
conditionValue: z.number().int(),
|
|
adjustmentType: z.enum(['PERCENTAGE', 'FLAT_PER_DAY', 'FLAT_TOTAL']),
|
|
adjustmentValue: z.number().int(),
|
|
isActive: z.boolean().default(true),
|
|
description: z.string().optional(),
|
|
})
|
|
|
|
export const accountingSettingsSchema = z.object({
|
|
reportingPeriod: z.enum(['WEEKLY', 'MONTHLY', 'QUARTERLY', 'ANNUAL']).optional(),
|
|
fiscalYearStart: z.number().int().min(1).max(12).optional(),
|
|
currency: z.literal('MAD').optional(),
|
|
accountantEmail: optionalEmailField(),
|
|
accountantName: optionalTextField('name'),
|
|
autoSendReport: z.boolean().optional(),
|
|
reportFormat: z.enum(['PDF', 'CSV', 'BOTH']).optional(),
|
|
})
|
|
|
|
export const subdomainSchema = z.object({ subdomain: z.string().min(3) })
|
|
export const customDomainSchema = z.object({ customDomain: z.string().min(3) })
|
|
export const idParamSchema = z.object({ id: z.string() })
|