refactor: rename marketplace to storefront across the entire monorepo
Build & Deploy / Build & Push Docker Image (push) Successful in 1m2s
Test / Type Check (all packages) (push) Failing after 28s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Storefront 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
Build & Deploy / Deploy to VPS (push) Successful in 3s
Build & Deploy / Build & Push Docker Image (push) Successful in 1m2s
Test / Type Check (all packages) (push) Failing after 28s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Storefront 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
Build & Deploy / Deploy to VPS (push) Successful in 3s
Comprehensive rename of all marketplace references to storefront: - API module: apps/api/src/modules/marketplace/ → storefront/ - Components: MarketplaceHeader → StorefrontHeader, MarketplaceShell → StorefrontShell, MarketplaceFooter → StorefrontFooter - Types: marketplace-homepage.ts → storefront-homepage.ts - Test files: employee-marketplace-* → employee-storefront-* - All source code identifiers, imports, route paths, and strings - Documentation (docs/), CI config (.gitlab-ci.yml), scripts - Dashboard, admin, storefront workspace references - Prisma field names preserved (isListedOnMarketplace, marketplaceRating, marketplaceFunnelEvent) as they map to database schema Validation: - API type-check: 0 errors - Storefront type-check: 0 errors - Dashboard type-check: 0 errors - Full monorepo type-check: only pre-existing admin TS18046
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { formatCurrency } from '@rentaldrivego/types'
|
||||
import { MarketplaceApiError, marketplaceFetch, marketplacePost } from '@/lib/api'
|
||||
import { useMarketplacePreferences } from '@/components/MarketplaceShell'
|
||||
import { StorefrontApiError, storefrontFetch, storefrontPost } from '@/lib/api'
|
||||
import { useStorefrontPreferences } from '@/components/StorefrontShell'
|
||||
|
||||
type Props = {
|
||||
vehicleId: string
|
||||
@@ -314,7 +314,7 @@ function formatLocalizedDate(value: string, language: 'en' | 'fr' | 'ar') {
|
||||
function getBookingSessionId() {
|
||||
if (typeof window === 'undefined') return 'server'
|
||||
|
||||
const existing = window.sessionStorage.getItem('marketplace-booking-session-id')
|
||||
const existing = window.sessionStorage.getItem('storefront-booking-session-id')
|
||||
if (existing) return existing
|
||||
|
||||
const created =
|
||||
@@ -322,7 +322,7 @@ function getBookingSessionId() {
|
||||
? window.crypto.randomUUID()
|
||||
: `booking-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
||||
|
||||
window.sessionStorage.setItem('marketplace-booking-session-id', created)
|
||||
window.sessionStorage.setItem('storefront-booking-session-id', created)
|
||||
return created
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ export default function BookingForm({
|
||||
allowDifferentDropoff,
|
||||
dropoffLocations,
|
||||
}: Props) {
|
||||
const { language } = useMarketplacePreferences()
|
||||
const { language } = useStorefrontPreferences()
|
||||
const t = copy[language]
|
||||
const pickupOptions = Array.isArray(pickupLocations) ? pickupLocations : []
|
||||
const dropoffOptions = Array.isArray(dropoffLocations) ? dropoffLocations : []
|
||||
@@ -400,7 +400,7 @@ export default function BookingForm({
|
||||
}
|
||||
|
||||
async function trackEvent(eventName: FunnelEventName, metadata?: Record<string, string | number | boolean | null>) {
|
||||
await marketplacePost('/marketplace/events', {
|
||||
await storefrontPost('/storefront/events', {
|
||||
eventName,
|
||||
companySlug,
|
||||
vehicleId,
|
||||
@@ -413,8 +413,8 @@ export default function BookingForm({
|
||||
async function checkAvailability(startDate: string, endDate: string, signal?: AbortSignal) {
|
||||
const start = new Date(startDate)
|
||||
const end = new Date(endDate)
|
||||
const result = await marketplaceFetch<AvailabilityResponse>(
|
||||
`/marketplace/${companySlug}/vehicles/${vehicleId}/availability?startDate=${encodeURIComponent(start.toISOString())}&endDate=${encodeURIComponent(end.toISOString())}`,
|
||||
const result = await storefrontFetch<AvailabilityResponse>(
|
||||
`/storefront/${companySlug}/vehicles/${vehicleId}/availability?startDate=${encodeURIComponent(start.toISOString())}&endDate=${encodeURIComponent(end.toISOString())}`,
|
||||
signal ? { signal } : undefined,
|
||||
)
|
||||
|
||||
@@ -471,7 +471,7 @@ export default function BookingForm({
|
||||
|
||||
void checkAvailability(fields.startDate, fields.endDate, controller.signal).catch((err) => {
|
||||
if (controller.signal.aborted) return
|
||||
if (err instanceof MarketplaceApiError && err.code === 'invalid_dates') {
|
||||
if (err instanceof StorefrontApiError && err.code === 'invalid_dates') {
|
||||
setAvailability({ status: 'idle', nextAvailableAt: null })
|
||||
return
|
||||
}
|
||||
@@ -520,7 +520,7 @@ export default function BookingForm({
|
||||
return
|
||||
}
|
||||
|
||||
const booking = await marketplacePost<BookingResponse>('/marketplace/reservations', {
|
||||
const booking = await storefrontPost<BookingResponse>('/storefront/reservations', {
|
||||
vehicleId,
|
||||
companySlug,
|
||||
firstName: fields.firstName.trim(),
|
||||
@@ -546,7 +546,7 @@ export default function BookingForm({
|
||||
elapsedMs: Date.now() - startedAtRef.current,
|
||||
})
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof MarketplaceApiError && err.code === 'unavailable') {
|
||||
if (err instanceof StorefrontApiError && err.code === 'unavailable') {
|
||||
setAvailability({ status: 'unavailable', nextAvailableAt: err.nextAvailableAt ?? null })
|
||||
setError(buildUnavailableMessage(err.nextAvailableAt ?? null))
|
||||
} else {
|
||||
@@ -554,7 +554,7 @@ export default function BookingForm({
|
||||
}
|
||||
|
||||
void trackEvent('booking_request_failed', {
|
||||
reason: err instanceof MarketplaceApiError ? err.code ?? 'request_failed' : 'request_failed',
|
||||
reason: err instanceof StorefrontApiError ? err.code ?? 'request_failed' : 'request_failed',
|
||||
})
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
|
||||
@@ -3,8 +3,8 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const preferenceState = vi.hoisted(() => ({ language: 'en' as 'en' | 'fr' | 'ar' }))
|
||||
|
||||
vi.mock('@/components/MarketplaceShell', () => ({
|
||||
useMarketplacePreferences: () => ({ language: preferenceState.language, theme: 'light' }),
|
||||
vi.mock('@/components/StorefrontShell', () => ({
|
||||
useStorefrontPreferences: () => ({ language: preferenceState.language, theme: 'light' }),
|
||||
}))
|
||||
|
||||
import FooterContentPage from './FooterContentPage'
|
||||
@@ -29,7 +29,7 @@ describe('FooterContentPage', () => {
|
||||
preferenceState.language = 'en'
|
||||
})
|
||||
|
||||
it('uses the current marketplace language when no forced language is provided', () => {
|
||||
it('uses the current storefront language when no forced language is provided', () => {
|
||||
preferenceState.language = 'fr'
|
||||
const page = FooterContentPage({ slug: 'contact-sales' })
|
||||
const text = collectText(page).join(' ')
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import { useMarketplacePreferences } from '@/components/MarketplaceShell'
|
||||
import { useStorefrontPreferences } from '@/components/StorefrontShell'
|
||||
import { type FooterPageSlug, getFooterPageContent } from '@/lib/footerContent'
|
||||
import { type MarketplaceLanguage } from '@/lib/i18n'
|
||||
import { type StorefrontLanguage } from '@/lib/i18n'
|
||||
|
||||
const pageMeta = {
|
||||
en: {
|
||||
@@ -53,8 +53,8 @@ function renderParagraphText(paragraph: string) {
|
||||
})
|
||||
}
|
||||
|
||||
export default function FooterContentPage({ slug, forcedLanguage }: { slug: FooterPageSlug; forcedLanguage?: MarketplaceLanguage }) {
|
||||
const { language } = useMarketplacePreferences()
|
||||
export default function FooterContentPage({ slug, forcedLanguage }: { slug: FooterPageSlug; forcedLanguage?: StorefrontLanguage }) {
|
||||
const { language } = useStorefrontPreferences()
|
||||
const activeLanguage = forcedLanguage ?? language
|
||||
const content = getFooterPageContent(activeLanguage, slug)
|
||||
const meta = pageMeta[activeLanguage]
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
Car,
|
||||
} from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useMarketplacePreferences } from '@/components/MarketplaceShell'
|
||||
import { useStorefrontPreferences } from '@/components/StorefrontShell'
|
||||
import { clearRenterSession, loadRenterProfile } from '@/lib/renter'
|
||||
|
||||
const NAV_ITEMS = [
|
||||
@@ -63,7 +63,7 @@ function computeInitials(name: string): string {
|
||||
export default function RenterShell({ children }: { children: React.ReactNode }) {
|
||||
const pathname = usePathname()
|
||||
const router = useRouter()
|
||||
const { language } = useMarketplacePreferences()
|
||||
const { language } = useStorefrontPreferences()
|
||||
const dict = dicts[language]
|
||||
const isRtl = language === 'ar'
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ type FooterItem = {
|
||||
href?: string
|
||||
}
|
||||
|
||||
export default function MarketplaceFooter({
|
||||
export default function StorefrontFooter({
|
||||
primaryItems,
|
||||
secondaryItems,
|
||||
localeLabel,
|
||||
+2
-2
@@ -4,9 +4,9 @@ import {
|
||||
companyInitial,
|
||||
localeMenuPositionClass,
|
||||
ownerWorkspaceHref,
|
||||
} from './MarketplaceHeader'
|
||||
} from './StorefrontHeader'
|
||||
|
||||
describe('MarketplaceHeader helpers', () => {
|
||||
describe('StorefrontHeader helpers', () => {
|
||||
it('builds dashboard sign-in links with language and theme query parameters', () => {
|
||||
expect(buildDashboardSignInHref('https://app.example.com/dashboard', 'fr', 'dark')).toBe(
|
||||
'https://app.example.com/dashboard/sign-in?lang=fr&theme=dark'
|
||||
+3
-3
@@ -9,7 +9,7 @@ export type Theme = 'light' | 'dark'
|
||||
export type Language = 'en' | 'fr' | 'ar'
|
||||
|
||||
type Dictionary = {
|
||||
marketplace: string
|
||||
storefront: string
|
||||
explore: string
|
||||
signIn: string
|
||||
ownerSignIn: string
|
||||
@@ -44,7 +44,7 @@ export function companyInitial(companyName: string): string {
|
||||
return companyName.trim().charAt(0).toUpperCase()
|
||||
}
|
||||
|
||||
export default function MarketplaceHeader({
|
||||
export default function StorefrontHeader({
|
||||
dict,
|
||||
theme,
|
||||
setTheme,
|
||||
@@ -124,7 +124,7 @@ export default function MarketplaceHeader({
|
||||
href="/"
|
||||
className="rounded-full px-2.5 py-1 text-[12px] font-medium text-stone-600 transition hover:bg-stone-100 hover:text-stone-900 dark:text-stone-300 dark:hover:bg-blue-900/40 dark:hover:text-stone-100 sm:px-4 sm:py-2 sm:text-sm"
|
||||
>
|
||||
{dict.marketplace}
|
||||
{dict.storefront}
|
||||
</Link>
|
||||
<Link
|
||||
href="/explore"
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { clearCachedEmployeeProfile, hasCachedEmployeeProfile } from './MarketplaceShell'
|
||||
import { clearCachedEmployeeProfile, hasCachedEmployeeProfile } from './StorefrontShell'
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
describe('MarketplaceShell auth helpers', () => {
|
||||
describe('StorefrontShell auth helpers', () => {
|
||||
it('does not report an employee profile when the browser cache is empty', () => {
|
||||
vi.stubGlobal('window', {
|
||||
localStorage: {
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { getFooterContent, localeOptions } from './MarketplaceShell'
|
||||
import { getFooterContent, localeOptions } from './StorefrontShell'
|
||||
|
||||
describe('MarketplaceShell footer content registry', () => {
|
||||
it('exposes exactly the supported marketplace locales in selector order', () => {
|
||||
describe('StorefrontShell footer content registry', () => {
|
||||
it('exposes exactly the supported storefront locales in selector order', () => {
|
||||
expect(localeOptions.map((option) => option.value)).toEqual(['en', 'ar', 'fr'])
|
||||
expect(localeOptions.every((option) => option.label.length > 0 && option.flag.length > 0)).toBe(true)
|
||||
})
|
||||
+39
-39
@@ -3,13 +3,13 @@
|
||||
import { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import { appPrivacyHref, footerPageHref } from '@/lib/footerContent'
|
||||
import { MARKETPLACE_LANGUAGE_COOKIE, SHARED_LANGUAGE_COOKIE, isMarketplaceLanguage, type MarketplaceLanguage } from '@/lib/i18n'
|
||||
import { MARKETPLACE_LANGUAGE_COOKIE, SHARED_LANGUAGE_COOKIE, isStorefrontLanguage, type StorefrontLanguage } from '@/lib/i18n'
|
||||
import { SHARED_LANGUAGE_KEY, SHARED_THEME_KEY, readCurrentUserScopedPreference, readScopedPreference, writeScopedPreference } from '@/lib/preferences'
|
||||
|
||||
type Theme = 'light' | 'dark'
|
||||
|
||||
type Dictionary = {
|
||||
marketplace: string
|
||||
storefront: string
|
||||
explore: string
|
||||
signIn: string
|
||||
ownerSignIn: string
|
||||
@@ -20,31 +20,31 @@ type Dictionary = {
|
||||
preferences: string
|
||||
}
|
||||
|
||||
const dictionaries: Record<MarketplaceLanguage, Dictionary> = {
|
||||
const dictionaries: Record<StorefrontLanguage, Dictionary> = {
|
||||
en: {
|
||||
marketplace: 'Home',
|
||||
explore: 'Marketplace',
|
||||
storefront: 'Home',
|
||||
explore: 'Storefront',
|
||||
signIn: 'Sign in',
|
||||
ownerSignIn: 'Create Agency Space',
|
||||
language: 'Language',
|
||||
theme: 'Theme',
|
||||
light: 'Light',
|
||||
dark: 'Dark',
|
||||
preferences: 'Marketplace preferences',
|
||||
preferences: 'Storefront preferences',
|
||||
},
|
||||
fr: {
|
||||
marketplace: 'Accueil',
|
||||
explore: 'Marketplace',
|
||||
storefront: 'Accueil',
|
||||
explore: 'Storefront',
|
||||
signIn: 'Connexion',
|
||||
ownerSignIn: "Créer un espace d'agence",
|
||||
language: 'Langue',
|
||||
theme: 'Mode',
|
||||
light: 'Clair',
|
||||
dark: 'Sombre',
|
||||
preferences: 'Préférences marketplace',
|
||||
preferences: 'Préférences storefront',
|
||||
},
|
||||
ar: {
|
||||
marketplace: 'الرئيسية',
|
||||
storefront: 'الرئيسية',
|
||||
explore: 'السوق',
|
||||
signIn: 'تسجيل الدخول',
|
||||
ownerSignIn: 'إنشاء مساحة الوكالة',
|
||||
@@ -58,13 +58,13 @@ const dictionaries: Record<MarketplaceLanguage, Dictionary> = {
|
||||
|
||||
const EMPLOYEE_PROFILE_KEY = 'employee_profile'
|
||||
|
||||
export const localeOptions: Array<{ value: MarketplaceLanguage; label: string; flag: string }> = [
|
||||
export const localeOptions: Array<{ value: StorefrontLanguage; label: string; flag: string }> = [
|
||||
{ value: 'en', label: 'Global (English)', flag: '🇺🇸' },
|
||||
{ value: 'ar', label: 'North Africa (Arabic)', flag: '🇲🇦' },
|
||||
{ value: 'fr', label: 'Europe (French)', flag: '🇫🇷' },
|
||||
]
|
||||
|
||||
export function getFooterContent(language: MarketplaceLanguage): {
|
||||
export function getFooterContent(language: StorefrontLanguage): {
|
||||
primary: Array<{ label: string; href?: string }>
|
||||
secondary: Array<{ label: string; href?: string }>
|
||||
localeLabel: string
|
||||
@@ -158,50 +158,50 @@ function detectBrowserLanguage(): string | null {
|
||||
}
|
||||
|
||||
type PreferencesContextValue = {
|
||||
language: MarketplaceLanguage
|
||||
language: StorefrontLanguage
|
||||
theme: Theme
|
||||
dict: Dictionary
|
||||
companyName: string | null
|
||||
setLanguage: (language: MarketplaceLanguage) => void
|
||||
setLanguage: (language: StorefrontLanguage) => void
|
||||
setTheme: (theme: Theme) => void
|
||||
}
|
||||
|
||||
const PreferencesContext = createContext<PreferencesContextValue | null>(null)
|
||||
|
||||
export function useMarketplacePreferences() {
|
||||
export function useStorefrontPreferences() {
|
||||
const context = useContext(PreferencesContext)
|
||||
if (!context) throw new Error('useMarketplacePreferences must be used within MarketplaceShell')
|
||||
if (!context) throw new Error('useStorefrontPreferences must be used within StorefrontShell')
|
||||
return context
|
||||
}
|
||||
|
||||
export default function MarketplaceShell({
|
||||
export default function StorefrontShell({
|
||||
children,
|
||||
initialLanguage = 'en',
|
||||
initialTheme = 'light',
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
initialLanguage?: MarketplaceLanguage
|
||||
initialLanguage?: StorefrontLanguage
|
||||
initialTheme?: Theme
|
||||
}) {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const apiUrl = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000/api/v1'
|
||||
const [language, setLanguageState] = useState<MarketplaceLanguage>(initialLanguage)
|
||||
const [language, setLanguageState] = useState<StorefrontLanguage>(initialLanguage)
|
||||
const [theme, setThemeState] = useState<Theme>(initialTheme)
|
||||
const [hydrated, setHydrated] = useState(false)
|
||||
const previousLanguage = useRef<MarketplaceLanguage>(initialLanguage)
|
||||
const previousLanguage = useRef<StorefrontLanguage>(initialLanguage)
|
||||
const [companyName, setCompanyName] = useState<string | null>(null)
|
||||
|
||||
function applyLanguage(nextLanguage: MarketplaceLanguage) {
|
||||
function applyLanguage(nextLanguage: StorefrontLanguage) {
|
||||
if (nextLanguage === language) return
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
document.documentElement.lang = nextLanguage
|
||||
document.documentElement.dir = nextLanguage === 'ar' ? 'rtl' : 'ltr'
|
||||
try {
|
||||
sessionStorage.setItem('marketplace-language', nextLanguage)
|
||||
sessionStorage.setItem('storefront-language', nextLanguage)
|
||||
} catch {}
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, nextLanguage, ['marketplace-language'])
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, nextLanguage, ['storefront-language'])
|
||||
}
|
||||
|
||||
setLanguageState(nextLanguage)
|
||||
@@ -214,7 +214,7 @@ export default function MarketplaceShell({
|
||||
document.documentElement.classList.toggle('dark', nextTheme === 'dark')
|
||||
document.documentElement.style.colorScheme = nextTheme === 'light' ? 'light' : 'dark'
|
||||
document.body.dataset.theme = nextTheme
|
||||
writeScopedPreference(SHARED_THEME_KEY, nextTheme, ['marketplace-theme'])
|
||||
writeScopedPreference(SHARED_THEME_KEY, nextTheme, ['storefront-theme'])
|
||||
}
|
||||
|
||||
setThemeState(nextTheme)
|
||||
@@ -247,10 +247,10 @@ export default function MarketplaceShell({
|
||||
}
|
||||
}
|
||||
|
||||
function readSessionLanguage(): MarketplaceLanguage | null {
|
||||
function readSessionLanguage(): StorefrontLanguage | null {
|
||||
try {
|
||||
const val = sessionStorage.getItem('marketplace-language')
|
||||
return isMarketplaceLanguage(val) ? val : null
|
||||
const val = sessionStorage.getItem('storefront-language')
|
||||
return isStorefrontLanguage(val) ? val : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
@@ -262,7 +262,7 @@ export default function MarketplaceShell({
|
||||
if (sessionLang !== language) setLanguageState(sessionLang)
|
||||
} else {
|
||||
const scopedLanguage = readCurrentUserScopedPreference(SHARED_LANGUAGE_KEY)
|
||||
if (isMarketplaceLanguage(scopedLanguage) && scopedLanguage !== language) {
|
||||
if (isStorefrontLanguage(scopedLanguage) && scopedLanguage !== language) {
|
||||
setLanguageState(scopedLanguage)
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@ export default function MarketplaceShell({
|
||||
if ((scopedTheme === 'light' || scopedTheme === 'dark') && scopedTheme !== theme) {
|
||||
setThemeState(scopedTheme)
|
||||
} else {
|
||||
writeScopedPreference(SHARED_THEME_KEY, theme, ['marketplace-theme'])
|
||||
writeScopedPreference(SHARED_THEME_KEY, theme, ['storefront-theme'])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,22 +279,22 @@ export default function MarketplaceShell({
|
||||
const sessionLang = readSessionLanguage()
|
||||
if (sessionLang) {
|
||||
setLanguageState(sessionLang)
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, sessionLang, ['marketplace-language'])
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, sessionLang, ['storefront-language'])
|
||||
} else {
|
||||
const storedLanguage = readScopedPreference(SHARED_LANGUAGE_KEY, ['marketplace-language'])
|
||||
if (isMarketplaceLanguage(storedLanguage)) {
|
||||
const storedLanguage = readScopedPreference(SHARED_LANGUAGE_KEY, ['storefront-language'])
|
||||
if (isStorefrontLanguage(storedLanguage)) {
|
||||
setLanguageState(storedLanguage)
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, storedLanguage, ['marketplace-language'])
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, storedLanguage, ['storefront-language'])
|
||||
} else {
|
||||
const detected = detectBrowserLanguage()
|
||||
if (isMarketplaceLanguage(detected)) {
|
||||
if (isStorefrontLanguage(detected)) {
|
||||
setLanguageState(detected)
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, detected, ['marketplace-language'])
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, detected, ['storefront-language'])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const storedTheme = readScopedPreference(SHARED_THEME_KEY, ['marketplace-theme']) as Theme | null
|
||||
const storedTheme = readScopedPreference(SHARED_THEME_KEY, ['storefront-theme']) as Theme | null
|
||||
if (storedTheme === 'light' || storedTheme === 'dark') {
|
||||
setThemeState(storedTheme)
|
||||
}
|
||||
@@ -337,8 +337,8 @@ export default function MarketplaceShell({
|
||||
|
||||
if (!hydrated) return
|
||||
|
||||
try { sessionStorage.setItem('marketplace-language', language) } catch {}
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, language, ['marketplace-language'])
|
||||
try { sessionStorage.setItem('storefront-language', language) } catch {}
|
||||
writeScopedPreference(SHARED_LANGUAGE_KEY, language, ['storefront-language'])
|
||||
|
||||
if (previousLanguage.current !== language && pathname !== '/sign-in') {
|
||||
router.refresh()
|
||||
@@ -351,7 +351,7 @@ export default function MarketplaceShell({
|
||||
document.documentElement.style.colorScheme = theme === 'dark' ? 'dark' : 'light'
|
||||
document.body.dataset.theme = theme
|
||||
if (hydrated) {
|
||||
writeScopedPreference(SHARED_THEME_KEY, theme, ['marketplace-theme'])
|
||||
writeScopedPreference(SHARED_THEME_KEY, theme, ['storefront-theme'])
|
||||
}
|
||||
}, [theme, hydrated])
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('WorkspaceFrame helpers', () => {
|
||||
})
|
||||
|
||||
it('keeps unauthenticated visitors on the embedded sign-in path', () => {
|
||||
stubBrowser({ cookie: 'marketplace-language=fr' })
|
||||
stubBrowser({ cookie: 'storefront-language=fr' })
|
||||
|
||||
expect(getDefaultFramePath('sign-in')).toBe('/dashboard/sign-in')
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { resolveBrowserAppUrl } from '@/lib/appUrls'
|
||||
import { useMarketplacePreferences } from './MarketplaceShell'
|
||||
import { useStorefrontPreferences } from './StorefrontShell'
|
||||
|
||||
export type FrameId = 'sign-in'
|
||||
|
||||
@@ -37,7 +37,7 @@ export function buildFrameUrl(appUrl: string, path: string) {
|
||||
export const FRAME_HEIGHT = 'calc(100vh - 56px)'
|
||||
|
||||
export default function WorkspaceFrame({ target }: { target: FrameId }) {
|
||||
const { language, theme } = useMarketplacePreferences()
|
||||
const { language, theme } = useStorefrontPreferences()
|
||||
const [src, setSrc] = useState('')
|
||||
const [framePath, setFramePath] = useState(() => getDefaultFramePath(target))
|
||||
const config = frameConfig[target]
|
||||
|
||||
Reference in New Issue
Block a user