fix: landing list crash — title is now LocaleDict, not string

- Update LandingListItem.title type to LocaleDict
- Add resolveLocaleDisplay() helper for extracting display string
- Use resolveLocaleDisplay() in landing list and delete confirm
This commit is contained in:
Fringg
2026-03-06 17:00:05 +03:00
parent 6a92814ce2
commit 6755c1dc45
2 changed files with 13 additions and 4 deletions

View File

@@ -108,7 +108,7 @@ export interface AdminLandingFeature {
export interface LandingListItem { export interface LandingListItem {
id: number; id: number;
slug: string; slug: string;
title: string; title: LocaleDict;
is_active: boolean; is_active: boolean;
display_order: number; display_order: number;
gift_enabled: boolean; gift_enabled: boolean;
@@ -167,6 +167,13 @@ export type LandingUpdateRequest = Partial<LandingCreateRequest>;
* If it's a string, wraps it as `{ ru: value }`. * If it's a string, wraps it as `{ ru: value }`.
* If null/undefined, returns the fallback. * If null/undefined, returns the fallback.
*/ */
/** Extract best display string from a LocaleDict: ru → en → first available → '' */
export function resolveLocaleDisplay(dict: LocaleDict | string | null | undefined): string {
if (!dict) return '';
if (typeof dict === 'string') return dict;
return dict.ru || dict.en || Object.values(dict).find((v) => v?.trim()) || '';
}
export function toLocaleDict( export function toLocaleDict(
value: string | LocaleDict | null | undefined, value: string | LocaleDict | null | undefined,
fallback: LocaleDict = {}, fallback: LocaleDict = {},

View File

@@ -2,7 +2,7 @@ import { useState, useCallback, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { adminLandingsApi, LandingListItem } from '../api/landings'; import { adminLandingsApi, LandingListItem, resolveLocaleDisplay } from '../api/landings';
import { useNotify } from '@/platform'; import { useNotify } from '@/platform';
import { copyToClipboard } from '../utils/clipboard'; import { copyToClipboard } from '../utils/clipboard';
import { getApiErrorMessage } from '../utils/api-error'; import { getApiErrorMessage } from '../utils/api-error';
@@ -137,7 +137,9 @@ function SortableLandingCard({
{/* Content */} {/* Content */}
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="mb-1 flex items-center gap-2"> <div className="mb-1 flex items-center gap-2">
<h3 className="truncate font-medium text-dark-100">{landing.title}</h3> <h3 className="truncate font-medium text-dark-100">
{resolveLocaleDisplay(landing.title)}
</h3>
<span className="rounded bg-dark-800 px-2 py-0.5 text-xs text-dark-400"> <span className="rounded bg-dark-800 px-2 py-0.5 text-xs text-dark-400">
{landing.slug} {landing.slug}
</span> </span>
@@ -204,7 +206,7 @@ function SortableLandingCard({
)} )}
title={ title={
isPendingDelete isPendingDelete
? t('admin.landings.deleteConfirm', { title: landing.title }) ? t('admin.landings.deleteConfirm', { title: resolveLocaleDisplay(landing.title) })
: t('common.delete') : t('common.delete')
} }
> >