diff --git a/apps/nestjs-backend/src/types/i18n.generated.ts b/apps/nestjs-backend/src/types/i18n.generated.ts index 0309408c26..69a5998fa1 100644 --- a/apps/nestjs-backend/src/types/i18n.generated.ts +++ b/apps/nestjs-backend/src/types/i18n.generated.ts @@ -2971,6 +2971,7 @@ export type I18nTranslations = { "system": { "notFound": { "title": string; + "description": string; }; "links": { "backToHome": string; @@ -2983,6 +2984,10 @@ export type I18nTranslations = { "title": string; "description": string; }; + "error": { + "title": string; + "description": string; + }; }; "table": { "toolbar": { diff --git a/apps/nextjs-app/public/images/layout/error-dark.png b/apps/nextjs-app/public/images/layout/error-dark.png new file mode 100644 index 0000000000..2db90b5b82 Binary files /dev/null and b/apps/nextjs-app/public/images/layout/error-dark.png differ diff --git a/apps/nextjs-app/public/images/layout/error-light.png b/apps/nextjs-app/public/images/layout/error-light.png new file mode 100644 index 0000000000..572ca5860d Binary files /dev/null and b/apps/nextjs-app/public/images/layout/error-light.png differ diff --git a/apps/nextjs-app/public/images/layout/not-found-dark.png b/apps/nextjs-app/public/images/layout/not-found-dark.png new file mode 100644 index 0000000000..b4746243b8 Binary files /dev/null and b/apps/nextjs-app/public/images/layout/not-found-dark.png differ diff --git a/apps/nextjs-app/public/images/layout/not-found-light.png b/apps/nextjs-app/public/images/layout/not-found-light.png new file mode 100644 index 0000000000..35c36b913f Binary files /dev/null and b/apps/nextjs-app/public/images/layout/not-found-light.png differ diff --git a/apps/nextjs-app/public/images/layout/permission-dark.png b/apps/nextjs-app/public/images/layout/permission-dark.png new file mode 100644 index 0000000000..1c0dff1c69 Binary files /dev/null and b/apps/nextjs-app/public/images/layout/permission-dark.png differ diff --git a/apps/nextjs-app/public/images/layout/permission-light.png b/apps/nextjs-app/public/images/layout/permission-light.png new file mode 100644 index 0000000000..48f0d118e2 Binary files /dev/null and b/apps/nextjs-app/public/images/layout/permission-light.png differ diff --git a/apps/nextjs-app/public/images/layout/upgrade-dark.png b/apps/nextjs-app/public/images/layout/upgrade-dark.png new file mode 100644 index 0000000000..517746b08c Binary files /dev/null and b/apps/nextjs-app/public/images/layout/upgrade-dark.png differ diff --git a/apps/nextjs-app/public/images/layout/upgrade-light.png b/apps/nextjs-app/public/images/layout/upgrade-light.png new file mode 100644 index 0000000000..511c19ee07 Binary files /dev/null and b/apps/nextjs-app/public/images/layout/upgrade-light.png differ diff --git a/apps/nextjs-app/src/features/system/pages/ErrorPage.tsx b/apps/nextjs-app/src/features/system/pages/ErrorPage.tsx index 1b1b700a9f..88323282cb 100644 --- a/apps/nextjs-app/src/features/system/pages/ErrorPage.tsx +++ b/apps/nextjs-app/src/features/system/pages/ErrorPage.tsx @@ -1,5 +1,7 @@ -import Head from 'next/head'; +import { useTranslation } from 'next-i18next'; import type { FC } from 'react'; +import { systemConfig } from '@/features/i18n/system.config'; +import { IllustrationPage } from './IllustrationPage'; type Props = { statusCode?: number | null; @@ -11,26 +13,36 @@ type Props = { export const ErrorPage: FC = (props) => { const { error, errorId, message, statusCode } = props; + const { t } = useTranslation(systemConfig.i18nNamespaces); return ( - <> - - Error {statusCode} - -
-
-

Woops !

-

- Something went wrong. Please try again later. -

+
+ +
+
+ Code: + {statusCode}
-
-

Code: {statusCode}

-

Message: {message}

-

Error id: {errorId}

-

ErrorMessage: {error?.message}

+
+ Message: + {message} +
+
+ Error id: + {errorId} +
+
+ ErrorMessage: + {error?.message}
- +
); }; diff --git a/apps/nextjs-app/src/features/system/pages/ForbiddenPage.tsx b/apps/nextjs-app/src/features/system/pages/ForbiddenPage.tsx index 78140a9fb5..afb8653328 100644 --- a/apps/nextjs-app/src/features/system/pages/ForbiddenPage.tsx +++ b/apps/nextjs-app/src/features/system/pages/ForbiddenPage.tsx @@ -1,32 +1,26 @@ -import { Button } from '@teable/ui-lib/shadcn'; -import Head from 'next/head'; import { useTranslation } from 'next-i18next'; import type { FC } from 'react'; import { systemConfig } from '@/features/i18n/system.config'; +import type { IButtonConfig } from './IllustrationPage'; +import { IllustrationPage } from './IllustrationPage'; -type Props = { +type ForbiddenPageProps = { title?: string; - children?: never; + description?: string; + button?: IButtonConfig; }; -export const ForbiddenPage: FC = (props) => { +export const ForbiddenPage: FC = ({ title, description, button }) => { const { t } = useTranslation(systemConfig.i18nNamespaces); - const title = props.title ?? t('system:forbidden.title'); return ( - <> - - {title} - -
-

- {title} -

-

{t('system:forbidden.description')}

- -
- + ); }; diff --git a/apps/nextjs-app/src/features/system/pages/IllustrationPage.tsx b/apps/nextjs-app/src/features/system/pages/IllustrationPage.tsx new file mode 100644 index 0000000000..6f1d53b172 --- /dev/null +++ b/apps/nextjs-app/src/features/system/pages/IllustrationPage.tsx @@ -0,0 +1,63 @@ +import { useTheme } from '@teable/next-themes'; +import { Button } from '@teable/ui-lib/shadcn'; +import Head from 'next/head'; +import Image from 'next/image'; +import type { FC } from 'react'; + +export interface IButtonConfig { + label: string; + href: string; + variant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'link' | 'destructive'; +} + +export interface IIllustrationPageProps { + /** Light theme image path */ + imageLightSrc: string; + /** Dark theme image path */ + imageDarkSrc: string; + /** Image alt text */ + imageAlt?: string; + /** Page title (also used for document title) */ + title: string; + /** Page description */ + description?: string; + /** Button config */ + button: IButtonConfig; +} + +export const IllustrationPage: FC = ({ + imageLightSrc, + imageDarkSrc, + imageAlt = 'Illustration', + title, + description, + button, +}) => { + const { resolvedTheme } = useTheme(); + + const imageSrc = resolvedTheme === 'dark' ? imageDarkSrc : imageLightSrc; + + return ( + <> + + {title} + +
+ {imageAlt} +
+

+ {title} +

+ {description && ( +

+ {description} +

+ )} +
+ +
+ + ); +}; diff --git a/apps/nextjs-app/src/features/system/pages/NotFoundPage.tsx b/apps/nextjs-app/src/features/system/pages/NotFoundPage.tsx index cfefb553cd..666f3ac6ae 100644 --- a/apps/nextjs-app/src/features/system/pages/NotFoundPage.tsx +++ b/apps/nextjs-app/src/features/system/pages/NotFoundPage.tsx @@ -1,32 +1,26 @@ -import { Button } from '@teable/ui-lib/shadcn'; -import Head from 'next/head'; import { useTranslation } from 'next-i18next'; import type { FC } from 'react'; - import { systemConfig } from '@/features/i18n/system.config'; +import type { IButtonConfig } from './IllustrationPage'; +import { IllustrationPage } from './IllustrationPage'; -type Props = { +type NotFoundPageProps = { title?: string; - children?: never; + description?: string; + button?: IButtonConfig; }; -export const NotFoundPage: FC = (props) => { +export const NotFoundPage: FC = ({ title, description, button }) => { const { t } = useTranslation(systemConfig.i18nNamespaces); - const title = props.title ?? t('system:notFound.title'); return ( - <> - - {title} - -
-

- {title} -

- -
- + ); }; diff --git a/apps/nextjs-app/src/features/system/pages/PaymentRequired.tsx b/apps/nextjs-app/src/features/system/pages/PaymentRequired.tsx index f5cb803827..545c307922 100644 --- a/apps/nextjs-app/src/features/system/pages/PaymentRequired.tsx +++ b/apps/nextjs-app/src/features/system/pages/PaymentRequired.tsx @@ -1,34 +1,30 @@ -import { Button } from '@teable/ui-lib/shadcn'; -import Head from 'next/head'; -import { Trans, useTranslation } from 'next-i18next'; +import { useTranslation } from 'next-i18next'; import type { FC } from 'react'; import { systemConfig } from '@/features/i18n/system.config'; +import type { IButtonConfig } from './IllustrationPage'; +import { IllustrationPage } from './IllustrationPage'; -type Props = { +type PaymentRequiredPageProps = { title?: string; - children?: never; + description?: string; + button?: IButtonConfig; }; -export const PaymentRequiredPage: FC = (props) => { +export const PaymentRequiredPage: FC = ({ + title, + description, + button, +}) => { const { t } = useTranslation(systemConfig.i18nNamespaces); - const title = props.title ?? t('system:paymentRequired.title'); return ( - <> - - {title} - -
-

- {title} -

-

- }} /> -

- -
- + ); }; diff --git a/apps/nextjs-app/src/features/system/pages/index.ts b/apps/nextjs-app/src/features/system/pages/index.ts index 5ec79ffb4e..fdc14142a8 100644 --- a/apps/nextjs-app/src/features/system/pages/index.ts +++ b/apps/nextjs-app/src/features/system/pages/index.ts @@ -1,3 +1,5 @@ +export { IllustrationPage } from './IllustrationPage'; +export type { IButtonConfig, IIllustrationPageProps } from './IllustrationPage'; export { NotFoundPage } from './NotFoundPage'; export { ErrorPage } from './ErrorPage'; export { ForbiddenPage } from './ForbiddenPage'; diff --git a/packages/common-i18n/src/locales/de/system.json b/packages/common-i18n/src/locales/de/system.json index 9793e9523f..6724c32cb3 100644 --- a/packages/common-i18n/src/locales/de/system.json +++ b/packages/common-i18n/src/locales/de/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Seite wurde nicht gefunden" + "title": "Seite nicht gefunden", + "description": "Der Link, dem Sie gefolgt sind, ist möglicherweise fehlerhaft oder die Seite wurde verschoben." }, "links": { - "backToHome": "Zurück zum Anfang" + "backToHome": "Zurück zur Startseite" }, "forbidden": { - "title": "403 - Verboten", - "description": "Sie haben keine Berechtigung, auf diese Seite zuzugreifen." + "title": "Zugriff eingeschränkt", + "description": "Sie benötigen eine Berechtigung, um auf diese Ressource zuzugreifen.\nBitte wenden Sie sich an Ihren Administrator." }, "paymentRequired": { - "title": "402 - Upgrade des Abonnements erforderlich", - "description": "Your current subscription does not support access to this feature.

Please upgrade your subscription to continue." + "title": "Premium-Funktion freischalten", + "description": "Diese Funktion ist in erweiterten Plänen verfügbar.\nUpgraden Sie, um Ihre Möglichkeiten zu erweitern." + }, + "error": { + "title": "Etwas ist schief gelaufen", + "description": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut." } } diff --git a/packages/common-i18n/src/locales/en/system.json b/packages/common-i18n/src/locales/en/system.json index ed78ed585c..54a91c6f3d 100644 --- a/packages/common-i18n/src/locales/en/system.json +++ b/packages/common-i18n/src/locales/en/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Page not found" + "title": "Page not found", + "description": "The link you followed may be broken, or the page has been moved." }, "links": { "backToHome": "Back to home" }, "forbidden": { - "title": "403 - Forbidden", - "description": "You don't have permission to access this page." + "title": "Access restricted", + "description": "You need permission to access this resource.\nPlease contact your admin." }, "paymentRequired": { - "title": "402 - Subscription upgrade required", - "description": "Your current subscription does not support access to this feature.

Please upgrade your subscription to continue." + "title": "Unlock premium feature", + "description": "This feature is available on advanced plans.\nUpgrade to expand your capabilities." + }, + "error": { + "title": "Something went wrong", + "description": "An unexpected issue occurred. Please try again later." } } diff --git a/packages/common-i18n/src/locales/es/system.json b/packages/common-i18n/src/locales/es/system.json index 5cea9b9d36..5e63d398e6 100644 --- a/packages/common-i18n/src/locales/es/system.json +++ b/packages/common-i18n/src/locales/es/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Página No Encontrada" + "title": "Página no encontrada", + "description": "El enlace que seguiste puede estar roto o la página ha sido movida." }, "links": { "backToHome": "Volver al inicio" }, "forbidden": { - "title": "403 - Acceso Denegado", - "description": "No tienes permiso para acceder a esta página." + "title": "Acceso restringido", + "description": "Necesitas permiso para acceder a este recurso.\nPor favor, contacta con tu administrador." }, "paymentRequired": { - "title": "402 - Se Requiere Actualizar la Suscripción", - "description": "Tu suscripción actual no permite acceder a esta función.

Por favor, actualiza tu suscripción para continuar." + "title": "Desbloquear función Premium", + "description": "Esta función está disponible en planes avanzados.\nActualiza para ampliar tus capacidades." + }, + "error": { + "title": "Algo salió mal", + "description": "Ocurrió un error inesperado. Por favor, inténtalo de nuevo más tarde." } } diff --git a/packages/common-i18n/src/locales/fr/system.json b/packages/common-i18n/src/locales/fr/system.json index d78f84bbe0..a94fad65d8 100644 --- a/packages/common-i18n/src/locales/fr/system.json +++ b/packages/common-i18n/src/locales/fr/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Page non trouvée" + "title": "Page non trouvée", + "description": "Le lien que vous avez suivi est peut-être rompu ou la page a été déplacée." }, "links": { "backToHome": "Retour à l'accueil" }, "forbidden": { - "title": "403 - Accès interdit", - "description": "Vous n'avez pas la permission d'accéder à cette page." + "title": "Accès restreint", + "description": "Vous avez besoin d'une autorisation pour accéder à cette ressource.\nVeuillez contacter votre administrateur." }, "paymentRequired": { - "title": "402 - Mise à niveau de l'abonnement requise", - "description": "Votre abonnement actuel ne permet pas d'accéder à cette fonctionnalité.

Veuillez mettre à niveau votre abonnement pour continuer." + "title": "Débloquer la fonctionnalité Premium", + "description": "Cette fonctionnalité est disponible dans les forfaits avancés.\nPassez à un forfait supérieur pour étendre vos capacités." + }, + "error": { + "title": "Une erreur s'est produite", + "description": "Une erreur inattendue s'est produite. Veuillez réessayer plus tard." } } diff --git a/packages/common-i18n/src/locales/it/system.json b/packages/common-i18n/src/locales/it/system.json index e547ff7a78..4e89ecc1cd 100644 --- a/packages/common-i18n/src/locales/it/system.json +++ b/packages/common-i18n/src/locales/it/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Pagina Non Trovata" + "title": "Pagina non trovata", + "description": "Il link che hai seguito potrebbe essere non valido o la pagina è stata spostata." }, "links": { "backToHome": "Torna alla home" }, "forbidden": { - "title": "403 - Accesso negato", - "description": "Non hai il permesso di accedere a questa pagina." + "title": "Accesso limitato", + "description": "Hai bisogno dell'autorizzazione per accedere a questa risorsa.\nContatta il tuo amministratore." }, "paymentRequired": { - "title": "402 - Richiesto Aggiornamento del tuo Abbonamento", - "description": "Il tuo abbonamento attuale non supporta l'accesso a questa funzione.

Per favore, aggiorna il tuo abbonamento per continuare." + "title": "Sblocca funzionalità Premium", + "description": "Questa funzionalità è disponibile nei piani avanzati.\nEffettua l'upgrade per espandere le tue capacità." + }, + "error": { + "title": "Qualcosa è andato storto", + "description": "Si è verificato un errore imprevisto. Riprova più tardi." } } diff --git a/packages/common-i18n/src/locales/ja/system.json b/packages/common-i18n/src/locales/ja/system.json index 618f0a4747..a179458267 100644 --- a/packages/common-i18n/src/locales/ja/system.json +++ b/packages/common-i18n/src/locales/ja/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - ページが見つかりません" + "title": "ページが見つかりません", + "description": "お探しのリンクは無効であるか、ページが移動された可能性があります。" }, "links": { "backToHome": "ホームへ戻る" }, "forbidden": { - "title": "403 - Forbidden", - "description": "このページにアクセスする権限がありません。" + "title": "アクセス制限", + "description": "このリソースにアクセスするには権限が必要です。\n管理者にお問い合わせください。" }, "paymentRequired": { - "title": "402 - 契約プランのアップグレードが必要です", - "description": "現在の契約プランではこの機能にアクセスできません。

続行するには契約プランをアップグレードしてください。" + "title": "プレミアム機能のロック解除", + "description": "この機能は上位プランでご利用いただけます。\nアップグレードして機能を拡張しましょう。" + }, + "error": { + "title": "エラーが発生しました", + "description": "予期しないエラーが発生しました。後でもう一度お試しください。" } } diff --git a/packages/common-i18n/src/locales/ru/system.json b/packages/common-i18n/src/locales/ru/system.json index 87ce370538..a6dcc60e1f 100644 --- a/packages/common-i18n/src/locales/ru/system.json +++ b/packages/common-i18n/src/locales/ru/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Страница не найдена" + "title": "Страница не найдена", + "description": "Ссылка, по которой вы перешли, может быть недействительной, или страница была перемещена." }, "links": { "backToHome": "Вернуться на главную" }, "forbidden": { - "title": "403 - Доступ запрещен", - "description": "У вас нет разрешения для доступа к этой странице." + "title": "Доступ ограничен", + "description": "Для доступа к этому ресурсу требуется разрешение.\nПожалуйста, обратитесь к администратору." }, "paymentRequired": { - "title": "402 - Требуется обновление подписки", - "description": "Ваша текущая подписка не поддерживает доступ к этой функции.

Пожалуйста, обновите подписку, чтобы продолжить." + "title": "Разблокировать премиум-функцию", + "description": "Эта функция доступна в расширенных тарифах.\nОбновите план, чтобы расширить возможности." + }, + "error": { + "title": "Что-то пошло не так", + "description": "Произошла непредвиденная ошибка. Пожалуйста, попробуйте позже." } } diff --git a/packages/common-i18n/src/locales/tr/system.json b/packages/common-i18n/src/locales/tr/system.json index d39ba695b3..c569f42d09 100644 --- a/packages/common-i18n/src/locales/tr/system.json +++ b/packages/common-i18n/src/locales/tr/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Sayfa Bulunamadı" + "title": "Sayfa bulunamadı", + "description": "Takip ettiğiniz bağlantı bozuk olabilir veya sayfa taşınmış olabilir." }, "links": { "backToHome": "Ana sayfaya dön" }, "forbidden": { - "title": "403 - Erişim Yasak", - "description": "Bu sayfaya erişim izniniz yok." + "title": "Erişim kısıtlı", + "description": "Bu kaynağa erişmek için izne ihtiyacınız var.\nLütfen yöneticinizle iletişime geçin." }, "paymentRequired": { - "title": "402 - Abonelik Yükseltmesi Gerekli", - "description": "Mevcut aboneliğiniz bu özelliğe erişimi desteklemiyor.

Devam etmek için lütfen aboneliğinizi yükseltin." + "title": "Premium özelliğin kilidini aç", + "description": "Bu özellik gelişmiş planlarda kullanılabilir.\nYeteneklerinizi genişletmek için yükseltin." + }, + "error": { + "title": "Bir şeyler yanlış gitti", + "description": "Beklenmeyen bir hata oluştu. Lütfen daha sonra tekrar deneyin." } } diff --git a/packages/common-i18n/src/locales/uk/system.json b/packages/common-i18n/src/locales/uk/system.json index b0bd8d195d..18c74b688a 100644 --- a/packages/common-i18n/src/locales/uk/system.json +++ b/packages/common-i18n/src/locales/uk/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Сторінку не знайдено" + "title": "Сторінку не знайдено", + "description": "Посилання, за яким ви перейшли, може бути недійсним, або сторінку переміщено." }, "links": { - "backToHome": "Додому" + "backToHome": "Повернутися на головну" }, "forbidden": { - "title": "403 - Заборонено.", - "description": "Ви не маєте дозволу на доступ до цієї сторінки." + "title": "Доступ обмежено", + "description": "Вам потрібен дозвіл для доступу до цього ресурсу.\nБудь ласка, зверніться до адміністратора." }, "paymentRequired": { - "title": "402 - Необхідно оновити підписку", - "description": "Ваша поточна підписка не підтримує доступ до цієї функції.

Оновіть свою підписку, щоб продовжити." + "title": "Розблокувати преміум-функцію", + "description": "Ця функція доступна в розширених тарифах.\nОновіть план, щоб розширити можливості." + }, + "error": { + "title": "Щось пішло не так", + "description": "Сталася неочікувана помилка. Будь ласка, спробуйте пізніше." } } diff --git a/packages/common-i18n/src/locales/zh/system.json b/packages/common-i18n/src/locales/zh/system.json index f0c3e79a1a..b90c910ff3 100644 --- a/packages/common-i18n/src/locales/zh/system.json +++ b/packages/common-i18n/src/locales/zh/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - 找不到页面" + "title": "页面未找到", + "description": "您访问的链接可能已失效或已被移动。" }, "links": { - "backToHome": "返回主页" + "backToHome": "返回首页" }, "forbidden": { - "title": "403 - 禁止访问", - "description": "您没有权限访问此页面" + "title": "访问受限", + "description": "您需要权限才能访问此资源。\n请联系管理员。" }, "paymentRequired": { - "title": "402 - 需要升级订阅", - "description": "您当前的订阅计划不支持访问此功能,请升级您的订阅以继续使用" + "title": "解锁高级功能", + "description": "此功能仅在高级计划中可用。\n升级以扩展您的能力。" + }, + "error": { + "title": "出错了", + "description": "发生了意外错误,请稍后重试。" } }