feat: enhance location handling and localization; improve fallback mechanisms and unify type definitions

This commit is contained in:
Nati
2026-08-18 14:44:24 +00:00
parent 03e2b2b8a4
commit 99eb55c366
18 changed files with 194 additions and 101 deletions

View File

@@ -140,7 +140,10 @@ export function LocationForm({
placeholder={t('location.selectType')}
data={allAtLevel.map((lt) => ({
value: lt.id,
label: lt.names[locale],
// Not every locale is filled in on every row, and an option
// with no label is unpickable — fall back to English, then the
// code, which always exists.
label: lt.names[locale] || lt.names.en || lt.code,
}))}
{...form.getInputProps('locationTypeId')}
size="sm"

View File

@@ -177,7 +177,7 @@ export function LocationTree({
if (!search) return tree;
const matches = (loc: Location): boolean => {
const nameMatch = loc.names.en
const nameMatch = (loc.names.en ?? '')
.toLowerCase()
.includes(search.toLowerCase());
const childMatch =

View File

@@ -26,7 +26,10 @@ export function locationTypeColumns(
},
{
header: t('location.name'),
cell: ({ row }) => row.original.names[locale],
// Falls back like the type Select: a row missing this locale shows its
// English name, then its code, rather than an empty cell.
cell: ({ row }) =>
row.original.names[locale] || row.original.names.en || row.original.code,
},
];
}

View File

@@ -18,6 +18,7 @@ import {
useDeleteLocationTypeMutation,
} from '../../api/location-api';
import { AdvancedTable, notify, useErrorHandler, useServerTable } from '@ema-platform/ui';
import type { LocationType } from '../../types/location';
import { locationTypeColumns } from './columns';
import { locationTypeColumnActions } from './actions';
@@ -68,12 +69,14 @@ export function LocationTypeModal({ opened, onClose }: { opened: boolean; onClos
setShowForm(false);
};
const handleEdit = (type: { id: string; code: string; names: { en: string; am: string }; level: number }) => {
const handleEdit = (type: LocationType) => {
setEditingId(type.id);
form.setValues({
code: type.code,
namesEn: type.names.en,
namesAm: type.names.am,
// The form's inputs are controlled strings; a locale the row never had
// must edit as empty rather than reading back "undefined".
namesEn: type.names.en ?? '',
namesAm: type.names.am ?? '',
level: type.level,
});
setShowForm(true);

View File

@@ -1,37 +1,24 @@
export interface NamePair {
en: string;
am: string;
}
/**
* Re-exported from the shared contract so both apps read one definition.
*
* See the portal's copy of this file: the two apps each maintained their own
* `Location`/`LocationType` and drifted. The payload types below stay here —
* only the backoffice writes locations.
*/
export type {
Location,
LocationType,
ListResponse,
} from '@ema-platform/api';
export interface LocationType {
id: string;
code: string;
names: NamePair;
level: number;
createdAt: string;
updatedAt: string;
}
import type { Bilingual } from '@ema-platform/api';
export interface Location {
id: string;
code: string;
names: NamePair;
locationTypeId: string;
parentId: string | null;
locationType?: LocationType;
children?: Location[];
createdAt: string;
updatedAt: string;
}
export interface ListResponse<T> {
count: number;
items: T[];
}
/** @deprecated Use `Bilingual` from `@ema-platform/api` — it carries om/so too. */
export type NamePair = Bilingual;
export interface CreateLocationTypePayload {
code: string;
names: NamePair;
names: Bilingual;
level: number;
}
@@ -41,7 +28,7 @@ export interface UpdateLocationTypePayload extends CreateLocationTypePayload {
export interface CreateLocationPayload {
code: string;
names: NamePair;
names: Bilingual;
locationTypeId: string;
parentId?: string | null;
}