fix signin signout and apply the new style

This commit is contained in:
root
2026-05-24 23:58:54 -04:00
parent bf97a072dd
commit 9bd0938951
68 changed files with 851 additions and 200 deletions
+101 -1
View File
@@ -8,6 +8,9 @@ type Props = {
vehicleId: string
companySlug: string
dailyRate: number
pickupLocations: string[]
allowDifferentDropoff: boolean
dropoffLocations: string[]
}
const copy = {
@@ -17,6 +20,11 @@ const copy = {
lastName: 'Last name',
email: 'Email',
phone: 'Phone',
pickupLocation: 'Pick-up location',
returnLocation: 'Drop-off location',
sameDropoff: 'Same drop-off',
differentDropoff: 'Different drop-off',
sameAsPickup: 'Return to the same location',
startDate: 'Pick-up date',
endDate: 'Return date',
notes: 'Notes (optional)',
@@ -30,6 +38,7 @@ const copy = {
estimatedTotal: 'Estimated total',
days: 'day(s)',
genericError: 'Something went wrong. Please try again.',
locationRequired: 'Please select the required pick-up and drop-off locations.',
},
fr: {
title: 'Réserver ce véhicule',
@@ -37,6 +46,11 @@ const copy = {
lastName: 'Nom',
email: 'E-mail',
phone: 'Téléphone',
pickupLocation: 'Lieu de départ',
returnLocation: 'Lieu de retour',
sameDropoff: 'Même retour',
differentDropoff: 'Retour différent',
sameAsPickup: 'Retour au même lieu',
startDate: 'Date de départ',
endDate: 'Date de retour',
notes: 'Notes (optionnelles)',
@@ -50,6 +64,7 @@ const copy = {
estimatedTotal: 'Total estimé',
days: 'jour(s)',
genericError: 'Une erreur est survenue. Veuillez réessayer.',
locationRequired: 'Veuillez sélectionner les lieux de départ et de retour requis.',
},
ar: {
title: 'احجز هذه السيارة',
@@ -57,6 +72,11 @@ const copy = {
lastName: 'اسم العائلة',
email: 'البريد الإلكتروني',
phone: 'الهاتف',
pickupLocation: 'موقع الاستلام',
returnLocation: 'موقع الإرجاع',
sameDropoff: 'نفس موقع الإرجاع',
differentDropoff: 'موقع إرجاع مختلف',
sameAsPickup: 'الإرجاع في نفس موقع الاستلام',
startDate: 'تاريخ الاستلام',
endDate: 'تاريخ الإرجاع',
notes: 'ملاحظات (اختيارية)',
@@ -70,18 +90,31 @@ const copy = {
estimatedTotal: 'الإجمالي التقديري',
days: 'يوم',
genericError: 'حدث خطأ ما. يرجى المحاولة مرة أخرى.',
locationRequired: 'يرجى اختيار مواقع الاستلام والإرجاع المطلوبة.',
},
} as const
export default function BookingForm({ vehicleId, companySlug, dailyRate }: Props) {
export default function BookingForm({
vehicleId,
companySlug,
dailyRate,
pickupLocations,
allowDifferentDropoff,
dropoffLocations,
}: Props) {
const { language } = useMarketplacePreferences()
const t = copy[language]
const pickupOptions = Array.isArray(pickupLocations) ? pickupLocations : []
const dropoffOptions = Array.isArray(dropoffLocations) ? dropoffLocations : []
const [firstName, setFirstName] = useState('')
const [lastName, setLastName] = useState('')
const [email, setEmail] = useState('')
const [phone, setPhone] = useState('')
const [pickupLocation, setPickupLocation] = useState(pickupOptions[0] ?? '')
const [dropoffMode, setDropoffMode] = useState<'same' | 'different'>('same')
const [returnLocation, setReturnLocation] = useState(dropoffOptions[0] ?? '')
const [startDate, setStartDate] = useState('')
const [endDate, setEndDate] = useState('')
const [notes, setNotes] = useState('')
@@ -102,6 +135,10 @@ export default function BookingForm({ vehicleId, companySlug, dailyRate }: Props
setError(t.required)
return
}
if ((pickupOptions.length > 0 && !pickupLocation) || (dropoffMode === 'different' && dropoffOptions.length > 0 && !returnLocation)) {
setError(t.locationRequired)
return
}
const start = new Date(startDate)
const end = new Date(endDate)
@@ -121,6 +158,8 @@ export default function BookingForm({ vehicleId, companySlug, dailyRate }: Props
phone: phone.trim(),
startDate: start.toISOString(),
endDate: end.toISOString(),
pickupLocation: pickupLocation || undefined,
returnLocation: dropoffMode === 'different' ? (returnLocation || undefined) : (pickupLocation || undefined),
notes: notes.trim() || undefined,
language,
})
@@ -194,6 +233,67 @@ export default function BookingForm({ vehicleId, companySlug, dailyRate }: Props
/>
</div>
{pickupOptions.length > 0 ? (
<div className="space-y-1">
<label className="text-xs font-medium text-stone-600 dark:text-stone-400">{t.pickupLocation} <span className="text-red-500">*</span></label>
<select
value={pickupLocation}
onChange={(e) => setPickupLocation(e.target.value)}
className="w-full rounded-xl border border-stone-200 bg-white px-3 py-2 text-sm text-stone-900 outline-none focus:border-stone-400 dark:border-blue-800 dark:bg-[#162038] dark:text-stone-100 dark:focus:border-stone-500"
>
{pickupOptions.map((location) => (
<option key={location} value={location}>{location}</option>
))}
</select>
</div>
) : null}
{allowDifferentDropoff ? (
<div className="space-y-3 rounded-2xl border border-stone-200 bg-stone-50 p-4 dark:border-blue-800 dark:bg-[#0d1b38]">
<div className="inline-flex rounded-full border border-stone-200 dark:border-blue-800 bg-white dark:bg-[#162038] p-1">
<button
type="button"
onClick={() => setDropoffMode('same')}
className={`rounded-full px-3 py-1.5 text-xs font-semibold transition ${
dropoffMode === 'same'
? 'bg-stone-900 text-white dark:bg-orange-400 dark:text-stone-900'
: 'text-stone-500 dark:text-stone-400'
}`}
>
{t.sameDropoff}
</button>
<button
type="button"
onClick={() => setDropoffMode('different')}
className={`rounded-full px-3 py-1.5 text-xs font-semibold transition ${
dropoffMode === 'different'
? 'bg-stone-900 text-white dark:bg-orange-400 dark:text-stone-900'
: 'text-stone-500 dark:text-stone-400'
}`}
>
{t.differentDropoff}
</button>
</div>
{dropoffMode === 'different' && dropoffOptions.length > 0 ? (
<div className="space-y-1">
<label className="text-xs font-medium text-stone-600 dark:text-stone-400">{t.returnLocation} <span className="text-red-500">*</span></label>
<select
value={returnLocation}
onChange={(e) => setReturnLocation(e.target.value)}
className="w-full rounded-xl border border-stone-200 bg-white px-3 py-2 text-sm text-stone-900 outline-none focus:border-stone-400 dark:border-blue-800 dark:bg-[#162038] dark:text-stone-100 dark:focus:border-stone-500"
>
{dropoffOptions.map((location) => (
<option key={location} value={location}>{location}</option>
))}
</select>
</div>
) : (
<p className="text-sm text-stone-500 dark:text-stone-400">{pickupLocation || t.sameAsPickup}</p>
)}
</div>
) : null}
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1">
<label className="text-xs font-medium text-stone-600 dark:text-stone-400">{t.startDate} <span className="text-red-500">*</span></label>
@@ -120,7 +120,7 @@ export default function MarketplaceHeader({
</Link>
{companyName ? (
<Link
href={`${dashboardUrl}/dashboard`}
href={dashboardUrl}
className="ml-1 flex items-center gap-1.5 rounded-full bg-orange-600 px-3 py-1 text-[12px] font-semibold text-white transition hover:bg-orange-700 dark:bg-orange-500 dark:hover:bg-orange-400 sm:ml-2 sm:gap-2 sm:px-4 sm:py-2 sm:text-sm"
>
<span className="inline-flex h-5 w-5 items-center justify-center rounded-full bg-white/20 text-[10px] font-black dark:bg-[#07101e]/20">
@@ -88,7 +88,7 @@ export default function RenterShell({ children }: { children: React.ReactNode })
function signOut() {
clearRenterSession()
router.push('/renter/sign-in')
router.push('/')
}
const isActive = (item: (typeof NAV_ITEMS)[number]) => {
@@ -25,7 +25,7 @@ function getDefaultFramePath(target: FrameId) {
.find((c) => c.startsWith('employee_token='))
if (target === 'sign-in' && employeeToken) {
return '/dashboard/dashboard'
return '/dashboard'
}
return frameConfig[target].path
@@ -60,12 +60,30 @@ export default function WorkspaceFrame({ target }: { target: FrameId }) {
setFramePath(getDefaultFramePath(target))
}, [target])
useEffect(() => {
if (target !== 'sign-in') return
const employeeToken = document.cookie
.split(';')
.map((c) => c.trim())
.find((c) => c.startsWith('employee_token='))
if (employeeToken) {
window.location.replace('/dashboard')
}
}, [target])
useEffect(() => {
function handleFrameMessage(event: MessageEvent) {
if (!event.data || typeof event.data !== 'object') return
const message = event.data as { type?: string; path?: string }
if (target === 'sign-in' && message.type === 'rentaldrivego:employee-login' && typeof message.path === 'string') {
window.location.replace(message.path)
return
}
if ((message.type === 'rentaldrivego:embedded-path' || message.type === 'rentaldrivego:employee-login') && typeof message.path === 'string') {
setFramePath(message.path)
}
@@ -73,7 +91,7 @@ export default function WorkspaceFrame({ target }: { target: FrameId }) {
window.addEventListener('message', handleFrameMessage)
return () => window.removeEventListener('message', handleFrameMessage)
}, [])
}, [target])
useEffect(() => {
const nextUrl = new URL(buildFrameUrl(config.appUrl, framePath))