fixing platform admin

This commit is contained in:
root
2026-05-06 22:58:23 -04:00
parent 695a7f7cc7
commit 750ae56a29
175 changed files with 31249 additions and 328 deletions
@@ -0,0 +1,264 @@
'use client'
import Image from 'next/image'
import Link from 'next/link'
import { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react'
import { usePathname, useRouter } from 'next/navigation'
import { MARKETPLACE_LANGUAGE_COOKIE, isMarketplaceLanguage, type MarketplaceLanguage } from '@/lib/i18n'
type Theme = 'light' | 'dark'
type Dictionary = {
marketplace: string
companyWorkspace: string
platformOperations: string
explore: string
ownerSignIn: string
language: string
theme: string
light: string
dark: string
preferences: string
}
const dictionaries: Record<MarketplaceLanguage, Dictionary> = {
en: {
marketplace: 'Marketplace',
companyWorkspace: 'Company Workspace',
platformOperations: 'Platform Operations',
explore: 'Explore',
ownerSignIn: 'Owner sign in',
language: 'Language',
theme: 'Theme',
light: 'Light',
dark: 'Dark',
preferences: 'Marketplace preferences',
},
fr: {
marketplace: 'Marketplace',
companyWorkspace: 'Espace entreprise',
platformOperations: 'Opérations plateforme',
explore: 'Explorer',
ownerSignIn: 'Connexion proprietaire',
language: 'Langue',
theme: 'Mode',
light: 'Clair',
dark: 'Sombre',
preferences: 'Préférences marketplace',
},
ar: {
marketplace: 'السوق',
companyWorkspace: 'مساحة الشركة',
platformOperations: 'عمليات المنصة',
explore: 'استكشاف',
ownerSignIn: 'دخول المالك',
language: 'اللغة',
theme: 'الوضع',
light: 'فاتح',
dark: 'داكن',
preferences: 'تفضيلات السوق',
},
}
type PreferencesContextValue = {
language: MarketplaceLanguage
theme: Theme
dict: Dictionary
setLanguage: (language: MarketplaceLanguage) => void
setTheme: (theme: Theme) => void
}
const PreferencesContext = createContext<PreferencesContextValue | null>(null)
function SegmentedControl<T extends string>({
label,
value,
options,
onChange,
}: {
label: string
value: T
options: { value: T; label: string }[]
onChange: (value: T) => void
}) {
return (
<div className="flex items-center gap-2 rounded-full border border-stone-200/70 bg-white/90 px-2 py-1 shadow-sm dark:border-stone-700 dark:bg-stone-900/80">
<span className="px-2 text-[11px] font-semibold uppercase tracking-[0.16em] text-stone-500 dark:text-stone-400">
{label}
</span>
<div className="flex items-center gap-1">
{options.map((option) => {
const active = option.value === value
return (
<button
key={option.value}
type="button"
onClick={() => onChange(option.value)}
className={`rounded-full px-3 py-1.5 text-xs font-semibold transition ${
active
? 'bg-stone-900 text-white dark:bg-amber-400 dark:text-stone-950'
: 'text-stone-600 hover:bg-stone-100 dark:text-stone-300 dark:hover:bg-stone-800'
}`}
>
{option.label}
</button>
)
})}
</div>
</div>
)
}
export function useMarketplacePreferences() {
const context = useContext(PreferencesContext)
if (!context) throw new Error('useMarketplacePreferences must be used within MarketplaceShell')
return context
}
export default function MarketplaceShell({ children }: { children: React.ReactNode }) {
const pathname = usePathname()
const router = useRouter()
const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3001'
const [language, setLanguage] = useState<MarketplaceLanguage>('en')
const [theme, setTheme] = useState<Theme>('light')
const [hydrated, setHydrated] = useState(false)
const previousLanguage = useRef<MarketplaceLanguage>('en')
useEffect(() => {
const storedLanguage = window.localStorage.getItem('marketplace-language')
const storedTheme = window.localStorage.getItem('marketplace-theme') as Theme | null
if (isMarketplaceLanguage(storedLanguage)) {
setLanguage(storedLanguage)
}
if (storedTheme === 'light' || storedTheme === 'dark') {
setTheme(storedTheme)
}
setHydrated(true)
}, [])
useEffect(() => {
document.documentElement.lang = language
document.documentElement.dir = language === 'ar' ? 'rtl' : 'ltr'
document.documentElement.classList.toggle('dark', theme === 'dark')
document.body.dataset.theme = theme
window.localStorage.setItem('marketplace-language', language)
window.localStorage.setItem('marketplace-theme', theme)
document.cookie = `${MARKETPLACE_LANGUAGE_COOKIE}=${language}; path=/; max-age=31536000; SameSite=Lax`
if (hydrated && previousLanguage.current !== language) {
router.refresh()
}
previousLanguage.current = language
}, [hydrated, language, router, theme])
const dict = dictionaries[language]
const isEmbeddedWorkspace =
pathname === '/company-workspace' ||
pathname === '/platform-operations' ||
pathname === '/branded-website'
const hideHeader = pathname === '/company-workspace'
const value = useMemo(
() => ({ language, theme, dict, setLanguage, setTheme }),
[dict, language, theme],
)
return (
<PreferencesContext.Provider value={value}>
<div className="min-h-screen bg-stone-50 text-stone-900 transition-colors dark:bg-stone-950 dark:text-stone-100">
{!hideHeader ? (
<header className="sticky top-0 z-50 border-b border-stone-200 bg-white/80 backdrop-blur-md transition-colors dark:border-stone-800 dark:bg-stone-950/80">
<div className="shell flex min-h-14 flex-col gap-3 py-3 lg:flex-row lg:items-center lg:justify-between lg:py-2">
<div className="flex items-center justify-between gap-4">
<Link href="/" className="flex items-center gap-3 text-sm font-bold uppercase tracking-[0.2em] text-stone-900 dark:text-stone-100">
<Image
src="/rentalcardrive.png"
alt="RentalDriveGo"
width={36}
height={36}
className="h-9 w-9 rounded-md object-contain"
/>
<span>RentalDriveGo</span>
</Link>
</div>
<div className="flex flex-col gap-3 lg:flex-row lg:items-center">
<nav className="flex items-center gap-1 overflow-x-auto">
<Link
href="/"
className="rounded-full px-4 py-2 text-sm font-medium text-stone-600 transition hover:bg-stone-100 hover:text-stone-900 dark:text-stone-300 dark:hover:bg-stone-800 dark:hover:text-stone-100"
>
{dict.marketplace}
</Link>
<Link
href="/company-workspace"
className="rounded-full px-4 py-2 text-sm font-medium text-stone-600 transition hover:bg-stone-100 hover:text-stone-900 dark:text-stone-300 dark:hover:bg-stone-800 dark:hover:text-stone-100"
>
{dict.companyWorkspace}
</Link>
<Link
href="/platform-operations"
className="rounded-full px-4 py-2 text-sm font-medium text-stone-600 transition hover:bg-stone-100 hover:text-stone-900 dark:text-stone-300 dark:hover:bg-stone-800 dark:hover:text-stone-100"
>
{dict.platformOperations}
</Link>
<Link
href="/explore"
className="rounded-full px-4 py-2 text-sm font-medium text-stone-600 transition hover:bg-stone-100 hover:text-stone-900 dark:text-stone-300 dark:hover:bg-stone-800 dark:hover:text-stone-100"
>
{dict.explore}
</Link>
<Link
href={`${dashboardUrl}/sign-in`}
className="ml-2 rounded-full bg-stone-900 px-5 py-2 text-sm font-semibold text-white transition hover:bg-stone-700 dark:bg-amber-400 dark:text-stone-950 dark:hover:bg-amber-300"
>
{dict.ownerSignIn}
</Link>
</nav>
</div>
</div>
</header>
) : null}
<div className="flex min-h-[calc(100vh-57px)] flex-col">
<div className="flex-1">
{children}
</div>
{!isEmbeddedWorkspace ? (
<footer className="border-t border-stone-200 bg-white/90 px-4 py-4 backdrop-blur-md transition-colors dark:border-stone-800 dark:bg-stone-950/90">
<div className="shell flex flex-col items-center justify-between gap-3 lg:flex-row">
<p className="text-xs font-medium uppercase tracking-[0.16em] text-stone-400 dark:text-stone-500">
{dict.preferences}
</p>
<div className="flex flex-col items-center gap-3 sm:flex-row">
<SegmentedControl
label={dict.language}
value={language}
options={[
{ value: 'en', label: 'EN' },
{ value: 'fr', label: 'FR' },
{ value: 'ar', label: 'AR' },
]}
onChange={setLanguage}
/>
<SegmentedControl
label={dict.theme}
value={theme}
options={[
{ value: 'light', label: dict.light },
{ value: 'dark', label: dict.dark },
]}
onChange={setTheme}
/>
</div>
</div>
</footer>
) : null}
</div>
</div>
</PreferencesContext.Provider>
)
}