ui.* catalog and the dialogs: error dialogs, confirm and paper dialogs keyed

Establishes the ui.* namespace for phases 2 and 3. Both catalogs complete, so the
key-parity test holds. Two English copy defects fixed while keying, because the
Portuguese must not inherit them: 'Your are not authorized' -> 'You are', and
'Please Signin again' -> 'Please sign in again'.

The server's own message in ServerError/CustomError stays verbatim — it is a
response, not UI copy (D1).
This commit is contained in:
2026-08-23 04:10:27 +00:00
parent a444280cb4
commit 339d31f05c
8 changed files with 183 additions and 22 deletions
@@ -2,9 +2,11 @@ import { Dialog, DialogContent, DialogDescription } from '@/components/ui/dialog
import { DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Ban } from 'lucide-react';
import { useTranslation } from '@/components/locales';
import type { ErrorDialogsProps } from './index';
export const CustomErrorDialog = ({ apiError, setApiError }: ErrorDialogsProps) => {
const { t } = useTranslation();
const onOpenChange = (value: boolean) => {
if (!value) {
setApiError(null);
@@ -16,14 +18,15 @@ export const CustomErrorDialog = ({ apiError, setApiError }: ErrorDialogsProps)
<DialogHeader>
<DialogTitle className="flex items-center gap-10">
<Ban className="h-12 w-12 text-red-500" />
Server Error
{t('error.server.title')}
</DialogTitle>
<DialogDescription className="flex flex-col gap-4 py-5">{apiError?.uuid}</DialogDescription>
</DialogHeader>
{/* The server's own message, shown verbatim — it is a response, not UI copy (see D1). */}
<p>{apiError?.message}</p>
<DialogFooter>
<Button type="submit" onClick={() => onOpenChange(false)}>
Ok
{t('button.ok')}
</Button>
</DialogFooter>
</DialogContent>
@@ -2,9 +2,11 @@ import { Dialog, DialogContent, DialogDescription } from '@/components/ui/dialog
import { DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Ban } from 'lucide-react';
import { useTranslation } from '@/components/locales';
import type { ErrorDialogsProps } from './index';
export const ForbiddenDialog = ({ setApiError }: ErrorDialogsProps) => {
const { t } = useTranslation();
const onOpenChange = (value: boolean) => {
if (!value) {
setApiError(null);
@@ -16,16 +18,14 @@ export const ForbiddenDialog = ({ setApiError }: ErrorDialogsProps) => {
<DialogHeader>
<DialogTitle className="flex items-center gap-10">
<Ban className="h-12 w-12 text-red-500" />
Unauthorized Access
{t('error.forbidden.title')}
</DialogTitle>
<DialogDescription className="flex flex-col gap-4 py-5">
Your are not authorized to perform this action.
</DialogDescription>
<DialogDescription className="flex flex-col gap-4 py-5">{t('error.forbidden.description')}</DialogDescription>
</DialogHeader>
<p>If you think this is an error, please contact your manager.</p>
<p>{t('error.forbidden.hint')}</p>
<DialogFooter>
<Button type="submit" onClick={() => onOpenChange(false)}>
Ok
{t('button.ok')}
</Button>
</DialogFooter>
</DialogContent>
@@ -2,9 +2,11 @@ import { Dialog, DialogContent, DialogDescription } from '@/components/ui/dialog
import { DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Ban } from 'lucide-react';
import { useTranslation } from '@/components/locales';
import type { ErrorDialogsProps } from './index';
export const ServerErrorDialog = ({ apiError, setApiError }: ErrorDialogsProps) => {
const { t } = useTranslation();
const onOpenChange = (value: boolean) => {
if (!value) {
setApiError(null);
@@ -16,14 +18,15 @@ export const ServerErrorDialog = ({ apiError, setApiError }: ErrorDialogsProps)
<DialogHeader>
<DialogTitle className="flex items-center gap-10">
<Ban className="h-12 w-12 text-red-500" />
Server Error
{t('error.server.title')}
</DialogTitle>
<DialogDescription className="flex flex-col gap-4 py-5">{apiError?.uuid}</DialogDescription>
</DialogHeader>
{/* The server's own message, shown verbatim — it is a response, not UI copy (see D1). */}
<p>{apiError?.message}</p>
<DialogFooter>
<Button type="submit" onClick={() => onOpenChange(false)}>
Ok
{t('button.ok')}
</Button>
</DialogFooter>
</DialogContent>
@@ -3,10 +3,12 @@ import { DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Button } from '@/components/ui/button';
import { Ban } from 'lucide-react';
import { useAuth } from 'hooks/useAuth';
import { useTranslation } from '@/components/locales';
import type { ErrorDialogsProps } from './index';
export const UnauthorizedDialog = ({ setApiError }: ErrorDialogsProps) => {
const { signout } = useAuth();
const { t } = useTranslation();
const onOpenChange = (value: boolean) => {
if (!value) {
setApiError(null);
@@ -20,14 +22,16 @@ export const UnauthorizedDialog = ({ setApiError }: ErrorDialogsProps) => {
<DialogHeader>
<DialogTitle className="flex items-center gap-10">
<Ban className="h-12 w-12 text-red-500" />
Invalid Credentials
{t('error.unauthorized.title')}
</DialogTitle>
<DialogDescription className="flex flex-col gap-4 py-5">Your access token has expired</DialogDescription>
<DialogDescription className="flex flex-col gap-4 py-5">
{t('error.unauthorized.description')}
</DialogDescription>
</DialogHeader>
<p>Please Signin again</p>
<p>{t('error.unauthorized.hint')}</p>
<DialogFooter>
<Button type="submit" onClick={() => onOpenChange(false)}>
Ok
{t('button.ok')}
</Button>
</DialogFooter>
</DialogContent>