fix: attempt to use user locale preference when not set as query param (#6761)
Fixes https://github.com/payloadcms/payload/issues/6619 Attempt to use user preference if available when loading view data instead of always relying on query param when loading view data.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { I18nClient } from '@payloadcms/translations'
|
||||
import type { Locale } from 'payload/config'
|
||||
import type { InitPageResult, PayloadRequestWithData, VisibleEntities } from 'payload/types'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
@@ -22,7 +23,6 @@ export const initPage = async ({
|
||||
searchParams,
|
||||
}: Args): Promise<InitPageResult> => {
|
||||
const headers = getHeaders()
|
||||
const localeParam = searchParams?.locale as string
|
||||
const payload = await getPayloadHMR({ config: configPromise })
|
||||
|
||||
const {
|
||||
@@ -34,10 +34,6 @@ export const initPage = async ({
|
||||
} = payload.config
|
||||
|
||||
const queryString = `${qs.stringify(searchParams ?? {}, { addQueryPrefix: true })}`
|
||||
const defaultLocale =
|
||||
localization && localization.defaultLocale ? localization.defaultLocale : 'en'
|
||||
const localeCode = localeParam || defaultLocale
|
||||
const locale = localization && findLocaleFromCode(localization, localeCode)
|
||||
const cookies = parseCookies(headers)
|
||||
const language = getRequestLanguage({ config: payload.config, cookies, headers })
|
||||
|
||||
@@ -64,7 +60,6 @@ export const initPage = async ({
|
||||
const req = await createLocalReq(
|
||||
{
|
||||
fallbackLocale: null,
|
||||
locale: locale.code,
|
||||
req: {
|
||||
host: headers.get('host'),
|
||||
i18n,
|
||||
@@ -79,9 +74,53 @@ export const initPage = async ({
|
||||
)
|
||||
|
||||
const { permissions, user } = await payload.auth({ headers, req })
|
||||
|
||||
req.user = user
|
||||
|
||||
const localeParam = searchParams?.locale as string
|
||||
let locale: Locale
|
||||
|
||||
if (localization) {
|
||||
const defaultLocaleCode = localization.defaultLocale ? localization.defaultLocale : 'en'
|
||||
let localeCode: string = localeParam
|
||||
|
||||
if (!localeCode) {
|
||||
try {
|
||||
localeCode = await payload
|
||||
.find({
|
||||
collection: 'payload-preferences',
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
user,
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
'user.relationTo': {
|
||||
equals: payload.config.admin.user,
|
||||
},
|
||||
},
|
||||
{
|
||||
'user.value': {
|
||||
equals: user.id,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: {
|
||||
equals: 'locale',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
?.then((res) => res.docs?.[0]?.value as string)
|
||||
} catch (error) {} // eslint-disable-line no-empty
|
||||
}
|
||||
|
||||
locale = findLocaleFromCode(localization, localeCode)
|
||||
|
||||
if (!locale) locale = findLocaleFromCode(localization, defaultLocaleCode)
|
||||
req.locale = locale.code
|
||||
}
|
||||
|
||||
const visibleEntities: VisibleEntities = {
|
||||
collections: collections
|
||||
.map(({ slug, admin: { hidden } }) => (!isEntityHidden({ hidden, user }) ? slug : null))
|
||||
|
||||
@@ -91,7 +91,7 @@ export const Account: React.FC<AdminViewProps> = async ({
|
||||
initialParams={{
|
||||
depth: 0,
|
||||
'fallback-locale': 'null',
|
||||
locale: locale.code,
|
||||
locale: locale?.code,
|
||||
uploadEdits: undefined,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -26,7 +26,7 @@ export const getDocumentData = async (args: {
|
||||
id,
|
||||
collectionSlug: collectionConfig?.slug,
|
||||
globalSlug: globalConfig?.slug,
|
||||
locale: locale.code,
|
||||
locale: locale?.code,
|
||||
operation: (collectionConfig && id) || globalConfig ? 'update' : 'create',
|
||||
schemaPath: collectionConfig?.slug || globalConfig?.slug,
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ import { EditDepthProvider } from '@payloadcms/ui/providers/EditDepth'
|
||||
import { FormQueryParamsProvider } from '@payloadcms/ui/providers/FormQueryParams'
|
||||
import { isEditing as getIsEditing } from '@payloadcms/ui/utilities/isEditing'
|
||||
import { notFound, redirect } from 'next/navigation.js'
|
||||
import QueryString from 'qs'
|
||||
import React from 'react'
|
||||
|
||||
import type { GenerateEditViewMetadata } from './getMetaBySegment.js'
|
||||
@@ -85,10 +86,14 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
}
|
||||
|
||||
action = `${serverURL}${apiRoute}/${collectionSlug}${isEditing ? `/${id}` : ''}`
|
||||
|
||||
apiURL = `${serverURL}${apiRoute}/${collectionSlug}/${id}?locale=${locale.code}${
|
||||
collectionConfig.versions?.drafts ? '&draft=true' : ''
|
||||
}`
|
||||
const apiQueryParams = QueryString.stringify(
|
||||
{
|
||||
draft: collectionConfig.versions?.drafts ? 'true' : undefined,
|
||||
locale: locale?.code,
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
)
|
||||
apiURL = `${serverURL}${apiRoute}/${collectionSlug}/${id}${apiQueryParams}`
|
||||
|
||||
const editConfig = collectionConfig?.admin?.components?.views?.Edit
|
||||
ViewOverride = typeof editConfig === 'function' ? editConfig : null
|
||||
@@ -118,9 +123,14 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
|
||||
action = `${serverURL}${apiRoute}/globals/${globalSlug}`
|
||||
|
||||
apiURL = `${serverURL}${apiRoute}/${globalSlug}?locale=${locale.code}${
|
||||
globalConfig.versions?.drafts ? '&draft=true' : ''
|
||||
}`
|
||||
const apiQueryParams = QueryString.stringify(
|
||||
{
|
||||
draft: globalConfig.versions?.drafts ? 'true' : undefined,
|
||||
locale: locale?.code,
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
)
|
||||
apiURL = `${serverURL}${apiRoute}/${globalSlug}${apiQueryParams}`
|
||||
|
||||
const editConfig = globalConfig?.admin?.components?.views?.Edit
|
||||
ViewOverride = typeof editConfig === 'function' ? editConfig : null
|
||||
@@ -161,7 +171,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
depth: 0,
|
||||
draft: true,
|
||||
fallbackLocale: null,
|
||||
locale: locale.code,
|
||||
locale: locale?.code,
|
||||
req,
|
||||
user,
|
||||
})
|
||||
@@ -206,12 +216,15 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
/>
|
||||
)}
|
||||
<HydrateClientUser permissions={permissions} user={user} />
|
||||
<EditDepthProvider depth={1} key={`${collectionSlug || globalSlug}-${locale.code}`}>
|
||||
<EditDepthProvider
|
||||
depth={1}
|
||||
key={`${collectionSlug || globalSlug}${locale?.code ? `-${locale?.code}` : ''}`}
|
||||
>
|
||||
<FormQueryParamsProvider
|
||||
initialParams={{
|
||||
depth: 0,
|
||||
'fallback-locale': 'null',
|
||||
locale: locale.code,
|
||||
locale: locale?.code,
|
||||
uploadEdits: undefined,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -42,7 +42,7 @@ export type InitPageResult = {
|
||||
docID?: string
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
languageOptions: LanguageOptions
|
||||
locale: Locale
|
||||
locale?: Locale
|
||||
permissions: Permissions
|
||||
req: PayloadRequestWithData
|
||||
translations: ClientTranslationsObject
|
||||
|
||||
@@ -48,7 +48,7 @@ export const DocumentDrawerContent: React.FC<DocumentDrawerProps> = ({
|
||||
const { Edit } = componentMap[`${collectionSlug ? 'collections' : 'globals'}`][collectionSlug]
|
||||
const isEditing = Boolean(docID)
|
||||
const apiURL = docID
|
||||
? `${serverURL}${apiRoute}/${collectionSlug}/${docID}?locale=${locale.code}`
|
||||
? `${serverURL}${apiRoute}/${collectionSlug}/${docID}${locale?.code ? `?locale=${locale.code}` : ''}`
|
||||
: null
|
||||
const action = `${serverURL}${apiRoute}/${collectionSlug}${
|
||||
isEditing ? `/${docID}` : ''
|
||||
|
||||
@@ -53,14 +53,17 @@ export const DuplicateDocument: React.FC<Props> = ({ id, slug, singularLabel })
|
||||
return
|
||||
}
|
||||
await requests
|
||||
.post(`${serverURL}${api}/${slug}/${id}/duplicate?locale=${locale.code}`, {
|
||||
body: JSON.stringify({}),
|
||||
headers: {
|
||||
'Accept-Language': i18n.language,
|
||||
'Content-Type': 'application/json',
|
||||
credentials: 'include',
|
||||
.post(
|
||||
`${serverURL}${api}/${slug}/${id}/duplicate${locale?.code ? `?locale=${locale.code}` : ''}`,
|
||||
{
|
||||
body: JSON.stringify({}),
|
||||
headers: {
|
||||
'Accept-Language': i18n.language,
|
||||
'Content-Type': 'application/json',
|
||||
credentials: 'include',
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
.then(async (res) => {
|
||||
const { doc, errors, message } = await res.json()
|
||||
if (res.status < 400) {
|
||||
@@ -69,7 +72,9 @@ export const DuplicateDocument: React.FC<Props> = ({ id, slug, singularLabel })
|
||||
t('general:successfullyDuplicated', { label: getTranslation(singularLabel, i18n) }),
|
||||
)
|
||||
setModified(false)
|
||||
router.push(`${admin}/collections/${slug}/${doc.id}?locale=${locale.code}`)
|
||||
router.push(
|
||||
`${admin}/collections/${slug}/${doc.id}${locale?.code ? `?locale=${locale.code}` : ''}`,
|
||||
)
|
||||
} else {
|
||||
toast.error(
|
||||
errors?.[0].message ||
|
||||
|
||||
@@ -46,12 +46,14 @@ export const FormQueryParamsProvider: React.FC<{
|
||||
const locale = useLocale()
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatchFormQueryParams({
|
||||
type: 'SET',
|
||||
params: {
|
||||
locale: locale.code,
|
||||
},
|
||||
})
|
||||
if (locale?.code) {
|
||||
dispatchFormQueryParams({
|
||||
type: 'SET',
|
||||
params: {
|
||||
locale: locale.code,
|
||||
},
|
||||
})
|
||||
}
|
||||
}, [locale.code])
|
||||
|
||||
return (
|
||||
|
||||
@@ -221,6 +221,19 @@ describe('Localization', () => {
|
||||
await expect(page.locator('.id-label')).not.toContainText(originalID)
|
||||
})
|
||||
})
|
||||
|
||||
describe('locale preference', () => {
|
||||
test('ensure preference is used when query param is not', async () => {
|
||||
await page.goto(url.create)
|
||||
await changeLocale(page, spanishLocale)
|
||||
await expect(page.locator('#field-title')).toBeEmpty()
|
||||
await fillValues({ title: spanishTitle })
|
||||
await saveDocAndAssert(page)
|
||||
await page.goto(url.admin)
|
||||
await page.goto(url.list)
|
||||
await expect(page.locator('.row-1 .cell-title')).toContainText(spanishTitle)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
async function fillValues(data: Partial<LocalizedPost>) {
|
||||
|
||||
Reference in New Issue
Block a user