Use CMS redirects for support tutorials
This commit is contained in:
@@ -1118,6 +1118,31 @@ html[data-theme] .eversolo-login-logo {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
html[data-theme] .eversolo-admin-logo,
|
||||
html[data-theme] .eversolo-admin-icon {
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, #2f241b, #54402f);
|
||||
color: #fff9f1;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
html[data-theme] .eversolo-admin-logo {
|
||||
min-width: 150px;
|
||||
padding: 13px 18px;
|
||||
font-size: 16px;
|
||||
letter-spacing: 0.24em;
|
||||
}
|
||||
|
||||
html[data-theme] .eversolo-admin-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
html[data-theme] .eversolo-login-card .login__brand {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export function EversoloAdminLogo() {
|
||||
return <span className="eversolo-admin-logo">Eversolo</span>
|
||||
}
|
||||
|
||||
export function EversoloAdminIcon() {
|
||||
return <span className="eversolo-admin-icon">E</span>
|
||||
}
|
||||
@@ -26,6 +26,8 @@ import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864
|
||||
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { HtmlPreviewTextareaField as HtmlPreviewTextareaField_753f6c383200cc3519583a44e0773d61 } from '@/payload/admin/HtmlPreviewTextareaField'
|
||||
import { AdminAvatarMenu as AdminAvatarMenu_709e36c272d83f8e640d7dc687c3a445 } from '@/app/(payload)/admin/_components/admin-avatar-menu'
|
||||
import { EversoloAdminIcon as EversoloAdminIcon_315d959d7586c3df8f4dadece8f5e53b } from '@/app/(payload)/admin/_components/eversolo-admin-logo'
|
||||
import { EversoloAdminLogo as EversoloAdminLogo_315d959d7586c3df8f4dadece8f5e53b } from '@/app/(payload)/admin/_components/eversolo-admin-logo'
|
||||
import { EversoloPasteURLFetchProvider as EversoloPasteURLFetchProvider_a0494b42366ba3cb335226070f16d4b1 } from '@/app/(payload)/admin/_components/eversolo-paste-url-fetch-provider'
|
||||
import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc'
|
||||
|
||||
@@ -59,6 +61,8 @@ export const importMap = {
|
||||
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@/payload/admin/HtmlPreviewTextareaField#HtmlPreviewTextareaField": HtmlPreviewTextareaField_753f6c383200cc3519583a44e0773d61,
|
||||
"@/app/(payload)/admin/_components/admin-avatar-menu#AdminAvatarMenu": AdminAvatarMenu_709e36c272d83f8e640d7dc687c3a445,
|
||||
"@/app/(payload)/admin/_components/eversolo-admin-logo#EversoloAdminIcon": EversoloAdminIcon_315d959d7586c3df8f4dadece8f5e53b,
|
||||
"@/app/(payload)/admin/_components/eversolo-admin-logo#EversoloAdminLogo": EversoloAdminLogo_315d959d7586c3df8f4dadece8f5e53b,
|
||||
"@/app/(payload)/admin/_components/eversolo-paste-url-fetch-provider#EversoloPasteURLFetchProvider": EversoloPasteURLFetchProvider_a0494b42366ba3cb335226070f16d4b1,
|
||||
"@payloadcms/next/rsc#CollectionCards": CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { resolveCmsRedirect } from '@/lib/cms-redirect'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
export const revalidate = 0
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
return resolveCmsRedirect({ request })
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { resolveCmsRedirect } from '@/lib/cms-redirect'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
export const revalidate = 0
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
return resolveCmsRedirect({ request })
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { getPayloadClient } from '@/lib/payload'
|
||||
|
||||
type ResolveCmsRedirectOptions = {
|
||||
locale?: 'any' | 'en' | 'zh'
|
||||
pathname?: string
|
||||
request: NextRequest
|
||||
}
|
||||
|
||||
function isSafeRedirectTarget(value: string) {
|
||||
return value.startsWith('/') && !value.startsWith('//')
|
||||
}
|
||||
|
||||
export async function resolveCmsRedirect({ locale = 'any', pathname, request }: ResolveCmsRedirectOptions) {
|
||||
const payload = await getPayloadClient()
|
||||
const rawPathname = pathname ?? new URL(request.url).pathname
|
||||
|
||||
const redirects = await payload.find({
|
||||
collection: 'redirects',
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
locale: locale === 'any' ? 'en' : locale,
|
||||
where: {
|
||||
and: [
|
||||
{ enabled: { equals: true } },
|
||||
{ from: { equals: rawPathname } },
|
||||
{
|
||||
or: [
|
||||
{ locale: { equals: locale } },
|
||||
{ locale: { equals: 'any' } },
|
||||
{ locale: { exists: false } },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const redirectEntry = redirects.docs[0]
|
||||
|
||||
if (!redirectEntry?.to || !isSafeRedirectTarget(redirectEntry.to)) {
|
||||
return NextResponse.json({ error: 'Redirect not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
return NextResponse.redirect(new URL(redirectEntry.to, request.url), Number(redirectEntry.statusCode))
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { MigrateDownArgs, MigrateUpArgs, sql } from '@payloadcms/db-postgres'
|
||||
|
||||
export async function up({ db }: MigrateUpArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
INSERT INTO "redirects" (
|
||||
"from",
|
||||
"to",
|
||||
"status_code",
|
||||
"match_type",
|
||||
"locale",
|
||||
"notes",
|
||||
"enabled",
|
||||
"updated_at",
|
||||
"created_at"
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
'/Support/tutorial.html',
|
||||
'/en/support/tutorial',
|
||||
'301',
|
||||
'exact',
|
||||
'any',
|
||||
'Legacy support tutorial landing',
|
||||
true,
|
||||
now(),
|
||||
now()
|
||||
),
|
||||
(
|
||||
'/Support/tutorial/target/AjLkU%5Bld%5DqhKb8%3D.html',
|
||||
'/en/support/tutorial',
|
||||
'301',
|
||||
'exact',
|
||||
'any',
|
||||
'Legacy support tutorial detail',
|
||||
true,
|
||||
now(),
|
||||
now()
|
||||
)
|
||||
ON CONFLICT DO NOTHING;
|
||||
`)
|
||||
}
|
||||
|
||||
export async function down({ db }: MigrateDownArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
DELETE FROM "redirects"
|
||||
WHERE "from" IN (
|
||||
'/Support/tutorial.html',
|
||||
'/Support/tutorial/target/AjLkU%5Bld%5DqhKb8%3D.html'
|
||||
)
|
||||
AND "to" = '/en/support/tutorial';
|
||||
`)
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import * as migration_20260427_235500_add_reviews_and_tutorial_page_globals from
|
||||
import * as migration_20260428_001500_remove_video_placeholder_copy from './20260428_001500_remove_video_placeholder_copy';
|
||||
import * as migration_20260428_002500_add_support_tutorial_videos_collection from './20260428_002500_add_support_tutorial_videos_collection';
|
||||
import * as migration_20260428_003500_support_tutorial_media_thumbnails from './20260428_003500_support_tutorial_media_thumbnails';
|
||||
import * as migration_20260428_011500_seed_support_tutorial_redirects from './20260428_011500_seed_support_tutorial_redirects';
|
||||
|
||||
export const migrations = [
|
||||
{
|
||||
@@ -132,4 +133,9 @@ export const migrations = [
|
||||
down: migration_20260428_003500_support_tutorial_media_thumbnails.down,
|
||||
name: '20260428_003500_support_tutorial_media_thumbnails'
|
||||
},
|
||||
{
|
||||
up: migration_20260428_011500_seed_support_tutorial_redirects.up,
|
||||
down: migration_20260428_011500_seed_support_tutorial_redirects.down,
|
||||
name: '20260428_011500_seed_support_tutorial_redirects'
|
||||
},
|
||||
];
|
||||
|
||||
@@ -63,6 +63,16 @@ export default buildConfig({
|
||||
},
|
||||
},
|
||||
components: {
|
||||
graphics: {
|
||||
Icon: {
|
||||
path: '@/app/(payload)/admin/_components/eversolo-admin-logo',
|
||||
exportName: 'EversoloAdminIcon',
|
||||
},
|
||||
Logo: {
|
||||
path: '@/app/(payload)/admin/_components/eversolo-admin-logo',
|
||||
exportName: 'EversoloAdminLogo',
|
||||
},
|
||||
},
|
||||
providers: [
|
||||
{
|
||||
path: '@/app/(payload)/admin/_components/eversolo-paste-url-fetch-provider',
|
||||
|
||||
@@ -31,6 +31,8 @@ const routes = [
|
||||
'/api/health',
|
||||
'/api/admin/captcha',
|
||||
'/favicon.ico',
|
||||
'/Support/tutorial.html',
|
||||
'/Support/tutorial/target/AjLkU%5Bld%5DqhKb8%3D.html',
|
||||
'/Product/index/model/DAC-Z10/target/X4C68nRijzjeq7k9e%5Bld%5D3ulg%3D%3D.html',
|
||||
]
|
||||
|
||||
@@ -46,6 +48,7 @@ async function check(route) {
|
||||
ok:
|
||||
response.status === 200 ||
|
||||
(route === '/admin' && [307, 308].includes(response.status) && Boolean(location?.includes('/admin/login'))) ||
|
||||
(route.startsWith('/Support/tutorial') && [301, 307, 308].includes(response.status) && Boolean(location?.includes('/en/support/tutorial'))) ||
|
||||
(route.includes('/Product/index/model/') && response.status === 301 && Boolean(location)) ||
|
||||
(route === '/' && response.status === 307 && Boolean(location)),
|
||||
}
|
||||
|
||||
@@ -2321,6 +2321,8 @@ async function updateRedirects(payload, report) {
|
||||
{ from: '/Support/support.html', to: '/en/support', locale: 'any', notes: 'Legacy support landing' },
|
||||
{ from: '/Support/downloads.html', to: '/en/downloads', locale: 'any', notes: 'Legacy downloads landing' },
|
||||
{ from: '/Support/faq.html', to: '/en/support/faq', locale: 'any', notes: 'Legacy FAQ landing' },
|
||||
{ from: '/Support/tutorial.html', to: '/en/support/tutorial', locale: 'any', notes: 'Legacy support tutorial landing' },
|
||||
{ from: '/Support/tutorial/target/AjLkU%5Bld%5DqhKb8%3D.html', to: '/en/support/tutorial', locale: 'any', notes: 'Legacy support tutorial detail' },
|
||||
{ from: '/Contact/afterservice.html', to: '/en/support/contact', locale: 'any', notes: 'Legacy after-service form' },
|
||||
{ from: '/Contact/distributor.html', to: '/en/dealers', locale: 'any', notes: 'Legacy distributor page' },
|
||||
{ from: '/Contact/oem.html', to: '/en/dealers', locale: 'any', notes: 'Legacy OEM page' },
|
||||
|
||||
Reference in New Issue
Block a user