fix signin signout and apply the new style
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { redirect } from 'next/navigation'
|
||||
|
||||
export default function CompanyWorkspacePage() {
|
||||
redirect('/sign-in')
|
||||
redirect('/')
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ type ExploreSearchFormDict = {
|
||||
searchTitle: string
|
||||
pickupLocation: string
|
||||
dropoffLocation: string
|
||||
sameDropoff: string
|
||||
differentDropoff: string
|
||||
sameAsPickup: string
|
||||
pickupDate: string
|
||||
returnDate: string
|
||||
hour: string
|
||||
@@ -29,6 +32,7 @@ const selectBase = 'w-full border-0 bg-white dark:bg-[#162038] py-4 text-sm text
|
||||
export default function ExploreSearchForm({
|
||||
pickupLocation,
|
||||
dropoffLocation,
|
||||
dropoffMode,
|
||||
pickupDate,
|
||||
pickupTime,
|
||||
returnDate,
|
||||
@@ -40,6 +44,7 @@ export default function ExploreSearchForm({
|
||||
}: {
|
||||
pickupLocation: string
|
||||
dropoffLocation: string
|
||||
dropoffMode: 'same' | 'different'
|
||||
pickupDate: string
|
||||
pickupTime: string
|
||||
returnDate: string
|
||||
@@ -55,6 +60,7 @@ export default function ExploreSearchForm({
|
||||
const [filters, setFilters] = useState({
|
||||
pickupLocation,
|
||||
dropoffLocation,
|
||||
dropoffMode,
|
||||
pickupDate,
|
||||
pickupTime: pickupTime || '10:00',
|
||||
returnDate,
|
||||
@@ -73,14 +79,19 @@ export default function ExploreSearchForm({
|
||||
|
||||
const query = new URLSearchParams()
|
||||
const normalizedPickup = filters.pickupLocation.trim()
|
||||
const normalizedDropoff = filters.dropoffLocation.trim()
|
||||
const normalizedDropoff = filters.dropoffMode === 'different'
|
||||
? filters.dropoffLocation.trim()
|
||||
: normalizedPickup
|
||||
const normalizedPromo = filters.promoCode.trim()
|
||||
|
||||
if (normalizedPickup) {
|
||||
query.set('pickupLocation', normalizedPickup)
|
||||
query.set('city', normalizedPickup)
|
||||
}
|
||||
if (normalizedDropoff) query.set('dropoffLocation', normalizedDropoff)
|
||||
query.set('dropoffMode', filters.dropoffMode)
|
||||
if (filters.dropoffMode === 'different' && normalizedDropoff) {
|
||||
query.set('dropoffLocation', normalizedDropoff)
|
||||
}
|
||||
if (filters.pickupDate) query.set('pickupDate', filters.pickupDate)
|
||||
if (filters.pickupTime) query.set('pickupTime', filters.pickupTime)
|
||||
if (filters.returnDate) query.set('returnDate', filters.returnDate)
|
||||
@@ -116,20 +127,56 @@ export default function ExploreSearchForm({
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="flex items-center gap-3 bg-white dark:bg-[#162038] px-4">
|
||||
<MapPin className="h-5 w-5 text-stone-300 dark:text-stone-500" />
|
||||
<select
|
||||
name="dropoffLocation"
|
||||
value={filters.dropoffLocation}
|
||||
onChange={(event) => updateFilter('dropoffLocation', event.target.value)}
|
||||
className={selectBase}
|
||||
>
|
||||
<option value="">{dict.dropoffLocation}</option>
|
||||
{cityOptions.map((city) => (
|
||||
<option key={`dropoff-${city}`} value={city}>{city}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<div className="bg-white dark:bg-[#162038] px-4 py-3">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<span className="text-xs font-semibold uppercase tracking-[0.14em] text-stone-400 dark:text-stone-500">{dict.dropoffLocation}</span>
|
||||
<div className="inline-flex rounded-full border border-stone-200 dark:border-blue-800 bg-stone-100 dark:bg-[#0d1b38] p-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setFilters((current) => ({ ...current, dropoffMode: 'same', dropoffLocation: '' }))}
|
||||
className={`rounded-full px-3 py-1.5 text-xs font-semibold transition ${
|
||||
filters.dropoffMode === 'same'
|
||||
? 'bg-stone-900 text-white dark:bg-orange-400 dark:text-stone-900'
|
||||
: 'text-stone-500 dark:text-stone-400'
|
||||
}`}
|
||||
>
|
||||
{dict.sameDropoff}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setFilters((current) => ({ ...current, dropoffMode: 'different' }))}
|
||||
className={`rounded-full px-3 py-1.5 text-xs font-semibold transition ${
|
||||
filters.dropoffMode === 'different'
|
||||
? 'bg-stone-900 text-white dark:bg-orange-400 dark:text-stone-900'
|
||||
: 'text-stone-500 dark:text-stone-400'
|
||||
}`}
|
||||
>
|
||||
{dict.differentDropoff}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{filters.dropoffMode === 'different' ? (
|
||||
<label className="mt-3 flex items-center gap-3">
|
||||
<MapPin className="h-5 w-5 text-stone-300 dark:text-stone-500" />
|
||||
<select
|
||||
name="dropoffLocation"
|
||||
value={filters.dropoffLocation}
|
||||
onChange={(event) => updateFilter('dropoffLocation', event.target.value)}
|
||||
className={selectBase}
|
||||
>
|
||||
<option value="">{dict.dropoffLocation}</option>
|
||||
{cityOptions.map((city) => (
|
||||
<option key={`dropoff-${city}`} value={city}>{city}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
) : (
|
||||
<div className="mt-3 flex items-center gap-3 rounded-2xl bg-stone-50 px-4 py-4 text-sm font-medium text-stone-500 dark:bg-[#0d1b38] dark:text-stone-300">
|
||||
<MapPin className="h-5 w-5 text-stone-300 dark:text-stone-500" />
|
||||
<span>{filters.pickupLocation || dict.sameAsPickup}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-px overflow-hidden rounded-[1.35rem] border border-stone-200 dark:border-blue-800 bg-stone-200 dark:bg-stone-700 md:grid-cols-4">
|
||||
|
||||
@@ -16,6 +16,9 @@ interface VehicleDetail {
|
||||
features: string[]
|
||||
dailyRate: number
|
||||
photos: string[]
|
||||
pickupLocations: string[]
|
||||
allowDifferentDropoff: boolean
|
||||
dropoffLocations: string[]
|
||||
availability: boolean
|
||||
availabilityStatus: 'AVAILABLE' | 'RESERVED' | 'MAINTENANCE' | 'UNAVAILABLE'
|
||||
nextAvailableAt: string | null
|
||||
@@ -259,6 +262,9 @@ export default async function VehicleDetailPage({ params }: { params: { slug: st
|
||||
vehicleId={vehicle.id}
|
||||
companySlug={params.slug}
|
||||
dailyRate={vehicle.dailyRate}
|
||||
pickupLocations={vehicle.pickupLocations}
|
||||
allowDifferentDropoff={vehicle.allowDifferentDropoff}
|
||||
dropoffLocations={vehicle.dropoffLocations}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ interface Vehicle {
|
||||
category: string
|
||||
dailyRate: number
|
||||
photos: string[]
|
||||
pickupLocations: string[]
|
||||
allowDifferentDropoff: boolean
|
||||
dropoffLocations: string[]
|
||||
availability?: boolean | null
|
||||
availabilityStatus?: 'AVAILABLE' | 'RESERVED' | 'MAINTENANCE' | 'UNAVAILABLE'
|
||||
nextAvailableAt?: string | null
|
||||
@@ -73,6 +76,9 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
|
||||
searchTitle: 'Find a vehicle',
|
||||
pickupLocation: 'Pick-up location',
|
||||
dropoffLocation: 'Drop-off location',
|
||||
sameDropoff: 'Same drop-off',
|
||||
differentDropoff: 'Different drop-off',
|
||||
sameAsPickup: 'Return to the same location',
|
||||
pickupDate: 'Start date',
|
||||
returnDate: 'Return date',
|
||||
hour: 'Hour',
|
||||
@@ -116,6 +122,9 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
|
||||
searchTitle: 'Trouver un véhicule',
|
||||
pickupLocation: 'Lieu de départ',
|
||||
dropoffLocation: "Lieu de retour",
|
||||
sameDropoff: 'Même retour',
|
||||
differentDropoff: 'Retour différent',
|
||||
sameAsPickup: 'Retour au même lieu',
|
||||
pickupDate: 'Date de départ',
|
||||
returnDate: 'Date de retour',
|
||||
hour: 'Heure',
|
||||
@@ -159,6 +168,9 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
|
||||
searchTitle: 'احجز سيارة',
|
||||
pickupLocation: 'موقع الاستلام',
|
||||
dropoffLocation: 'موقع الإرجاع',
|
||||
sameDropoff: 'نفس موقع الإرجاع',
|
||||
differentDropoff: 'موقع إرجاع مختلف',
|
||||
sameAsPickup: 'الإرجاع في نفس موقع الاستلام',
|
||||
pickupDate: 'تاريخ البدء',
|
||||
returnDate: 'تاريخ الإرجاع',
|
||||
hour: 'الساعة',
|
||||
@@ -200,6 +212,7 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
|
||||
const city = typeof searchParams?.city === 'string' ? searchParams.city : ''
|
||||
const pickupLocation = typeof searchParams?.pickupLocation === 'string' ? searchParams.pickupLocation : city
|
||||
const dropoffLocation = typeof searchParams?.dropoffLocation === 'string' ? searchParams.dropoffLocation : ''
|
||||
const dropoffMode = searchParams?.dropoffMode === 'different' ? 'different' : 'same'
|
||||
const pickupDate = typeof searchParams?.pickupDate === 'string' ? searchParams.pickupDate : ''
|
||||
const pickupTime = typeof searchParams?.pickupTime === 'string' ? searchParams.pickupTime : '10:00'
|
||||
const returnDate = typeof searchParams?.returnDate === 'string' ? searchParams.returnDate : ''
|
||||
@@ -215,6 +228,9 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
|
||||
|
||||
const query = new URLSearchParams()
|
||||
if (pickupLocation) query.set('city', pickupLocation)
|
||||
if (pickupLocation) query.set('pickupLocation', pickupLocation)
|
||||
query.set('dropoffMode', dropoffMode)
|
||||
if (dropoffMode === 'different' && dropoffLocation) query.set('dropoffLocation', dropoffLocation)
|
||||
if (startDate) query.set('startDate', startDate)
|
||||
if (endDate) query.set('endDate', endDate)
|
||||
if (category) query.set('category', category)
|
||||
@@ -246,6 +262,7 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
|
||||
<ExploreSearchForm
|
||||
pickupLocation={pickupLocation}
|
||||
dropoffLocation={dropoffLocation}
|
||||
dropoffMode={dropoffMode}
|
||||
pickupDate={pickupDate}
|
||||
pickupTime={pickupTime}
|
||||
returnDate={returnDate}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redirect } from 'next/navigation'
|
||||
|
||||
export default function PlatformOperationsPage() {
|
||||
redirect('/sign-in')
|
||||
redirect('/')
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ const copy = {
|
||||
perMonth: '/mo',
|
||||
billedAs: 'Billed as',
|
||||
getStarted: 'Get started',
|
||||
footer: 'All plans include a 14-day free trial. No credit card required.',
|
||||
footer: 'All plans include a 90-day free trial. No credit card required.',
|
||||
},
|
||||
fr: {
|
||||
monthly: 'Mensuel',
|
||||
@@ -94,7 +94,7 @@ const copy = {
|
||||
perMonth: '/mois',
|
||||
billedAs: 'Facturé à',
|
||||
getStarted: 'Commencer',
|
||||
footer: "Toutes les formules incluent un essai gratuit de 14 jours. Aucune carte bancaire n'est requise.",
|
||||
footer: "Toutes les formules incluent un essai gratuit de 90 jours. Aucune carte bancaire n'est requise.",
|
||||
},
|
||||
ar: {
|
||||
monthly: 'شهري',
|
||||
|
||||
@@ -7,7 +7,7 @@ const copy = {
|
||||
en: {
|
||||
kicker: 'Pricing',
|
||||
title: 'One platform, every fleet size.',
|
||||
body: 'Start free for 14 days, then choose the plan that grows with your business. Switch plans or cancel at any time.',
|
||||
body: 'Start free for 90 days, then choose the plan that grows with your business. Switch plans or cancel at any time.',
|
||||
faq: 'Frequently asked',
|
||||
items: [
|
||||
['Can I change plans later?', 'Yes. Upgrade or downgrade at any time — changes take effect on your next billing cycle.'],
|
||||
@@ -19,7 +19,7 @@ const copy = {
|
||||
fr: {
|
||||
kicker: 'Tarifs',
|
||||
title: 'Une seule plateforme pour toutes les tailles de flotte.',
|
||||
body: 'Commencez gratuitement pendant 14 jours, puis choisissez la formule qui accompagne votre activité. Vous pouvez changer de formule ou annuler à tout moment.',
|
||||
body: 'Commencez gratuitement pendant 90 jours, puis choisissez la formule qui accompagne votre activité. Vous pouvez changer de formule ou annuler à tout moment.',
|
||||
faq: 'Questions fréquentes',
|
||||
items: [
|
||||
['Puis-je changer de formule plus tard ?', 'Oui. Vous pouvez passer à une formule supérieure ou inférieure à tout moment. Les changements prennent effet au cycle de facturation suivant.'],
|
||||
|
||||
@@ -115,7 +115,7 @@ export default function RenterDashboardPage() {
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem('renter_token')
|
||||
if (!token) {
|
||||
router.replace('/renter/sign-in')
|
||||
router.replace('/')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ export default function RenterDashboardPage() {
|
||||
if (!res.ok) {
|
||||
if (res.status === 401) {
|
||||
localStorage.removeItem('renter_token')
|
||||
router.replace('/renter/sign-in')
|
||||
router.replace('/')
|
||||
} else {
|
||||
setErrorMsg(json?.message ?? dict.loadProfile)
|
||||
setStatus('error')
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function RenterNotificationsPage() {
|
||||
.then((items) => setNotifications(items))
|
||||
.catch((err) => {
|
||||
if (err instanceof RenterAuthError) {
|
||||
router.replace('/renter/sign-in')
|
||||
router.replace('/')
|
||||
return
|
||||
}
|
||||
setErrorMsg(err instanceof Error ? err.message : dict.load)
|
||||
|
||||
@@ -126,7 +126,7 @@ export default function RenterProfilePage() {
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err instanceof RenterAuthError) {
|
||||
router.replace('/renter/sign-in')
|
||||
router.replace('/')
|
||||
return
|
||||
}
|
||||
setErrorMsg(err instanceof Error ? err.message : dict.loadFailed)
|
||||
|
||||
@@ -50,7 +50,7 @@ export default function RenterSavedCompaniesPage() {
|
||||
.then((profile) => setCompanies(profile.savedCompanies ?? []))
|
||||
.catch((err) => {
|
||||
if (err instanceof RenterAuthError) {
|
||||
router.replace('/renter/sign-in')
|
||||
router.replace('/')
|
||||
return
|
||||
}
|
||||
setErrorMsg(err instanceof Error ? err.message : dict.load)
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user