Localize order modals, add dual logos, and improve admin order tools.

Farsi business order/variation UI, light/dark logo upload on business profile, payment order steps, variation editing, super-admin site links, and checkout/auth fixes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-26 00:21:48 +03:30
co-authored by Cursor
parent dc570c1e7f
commit 5e799eddf9
30 changed files with 779 additions and 169 deletions
+5 -1
View File
@@ -23,7 +23,10 @@ interface AuthContextValue {
user: AuthUser | null
isLoading: boolean
login: (cellNumber: string, password: string) => Promise<void>
loginWithOtp: (cellNumber: string, code: string) => Promise<void>
loginWithOtp: (
cellNumber: string,
code: string,
) => Promise<{ passwordUpdated?: boolean }>
logout: () => void
setUser: (user: AuthUser) => void
}
@@ -130,6 +133,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const data = await loginWithOtpRequest(cellNumber, code, getTenantDomain())
await assertCustomerAccess(data.user)
setUser(data.user)
return { passwordUpdated: data.passwordUpdated }
}, [])
const value = useMemo(
+91 -7
View File
@@ -1,5 +1,13 @@
import { createContext, useCallback, useContext, useMemo, useState, type ReactNode } from 'react'
import {
createContext,
useCallback,
useContext,
useMemo,
useState,
type ReactNode,
} from 'react'
import type { Order } from '../services/orderService'
import { getTenantDomain } from '../lib/config'
export type DeliveryMode = 'delivery' | 'pickup'
@@ -25,23 +33,94 @@ const defaultState: CheckoutState = {
placedOrder: null,
}
function storageKey() {
return `meshkee_checkout:${getTenantDomain()}`
}
function readPersisted(): Pick<CheckoutState, 'deliveryMode' | 'selectedAddressId' | 'discountCode'> {
try {
const raw = sessionStorage.getItem(storageKey())
if (!raw) return {
deliveryMode: defaultState.deliveryMode,
selectedAddressId: defaultState.selectedAddressId,
discountCode: defaultState.discountCode,
}
const parsed = JSON.parse(raw) as {
deliveryMode?: unknown
selectedAddressId?: unknown
discountCode?: unknown
}
return {
deliveryMode:
parsed.deliveryMode === 'pickup' || parsed.deliveryMode === 'delivery'
? parsed.deliveryMode
: defaultState.deliveryMode,
selectedAddressId:
typeof parsed.selectedAddressId === 'string' && parsed.selectedAddressId
? parsed.selectedAddressId
: null,
discountCode:
typeof parsed.discountCode === 'string' ? parsed.discountCode : '',
}
} catch {
return {
deliveryMode: defaultState.deliveryMode,
selectedAddressId: defaultState.selectedAddressId,
discountCode: defaultState.discountCode,
}
}
}
function persistPartial(state: CheckoutState) {
try {
sessionStorage.setItem(
storageKey(),
JSON.stringify({
deliveryMode: state.deliveryMode,
selectedAddressId: state.selectedAddressId,
discountCode: state.discountCode,
}),
)
} catch {
// ignore quota / private mode
}
}
const CheckoutContext = createContext<CheckoutContextValue | null>(null)
export function CheckoutProvider({ children }: { children: ReactNode }) {
const [state, setState] = useState<CheckoutState>(defaultState)
const [state, setState] = useState<CheckoutState>(() => ({
...defaultState,
...readPersisted(),
}))
const setDeliveryMode = useCallback((deliveryMode: DeliveryMode) => {
setState((prev) => ({ ...prev, deliveryMode }))
setState((prev) => {
const next = { ...prev, deliveryMode }
persistPartial(next)
return next
})
}, [])
const setSelectedAddressId = useCallback((selectedAddressId: string | null) => {
setState((prev) =>
prev.selectedAddressId === selectedAddressId ? prev : { ...prev, selectedAddressId },
)
const normalized =
selectedAddressId === null || selectedAddressId === undefined
? null
: String(selectedAddressId)
setState((prev) => {
if (prev.selectedAddressId === normalized) return prev
const next = { ...prev, selectedAddressId: normalized }
persistPartial(next)
return next
})
}, [])
const setDiscountCode = useCallback((discountCode: string) => {
setState((prev) => ({ ...prev, discountCode }))
setState((prev) => {
const next = { ...prev, discountCode }
persistPartial(next)
return next
})
}, [])
const setPlacedOrder = useCallback((placedOrder: Order | null) => {
@@ -50,6 +129,11 @@ export function CheckoutProvider({ children }: { children: ReactNode }) {
const resetCheckout = useCallback(() => {
setState(defaultState)
try {
sessionStorage.removeItem(storageKey())
} catch {
// ignore
}
}, [])
const value = useMemo<CheckoutContextValue>(