86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import type { GameDTO } from '$lib/api/schema-helpers';
|
|
|
|
/**
|
|
* The shape the game editor binds to. Every field is present and non-null so the
|
|
* inputs never see `undefined`, and `POST /api/Game` always receives a whole DTO —
|
|
* `AddOrUpdate` replaces every column, so a partial body would blank the rest.
|
|
*
|
|
* `id` 0 marks an unsaved game: the API inserts on 0 and updates otherwise.
|
|
*/
|
|
export interface Draft {
|
|
id: number;
|
|
name: string;
|
|
longName: string;
|
|
/** Null while the number input sits empty; `Game.Order` is a non-nullable int. */
|
|
order: number | null;
|
|
imgUrl: string;
|
|
wordPressTag: string;
|
|
wordPressTagOs: string;
|
|
smashId: number | null;
|
|
}
|
|
|
|
export const blankDraft: Draft = {
|
|
id: 0,
|
|
name: '',
|
|
longName: '',
|
|
order: 0,
|
|
imgUrl: '',
|
|
wordPressTag: '',
|
|
wordPressTagOs: '',
|
|
smashId: null
|
|
};
|
|
|
|
export function toDraft(game: GameDTO): Draft {
|
|
return {
|
|
id: game.id ?? 0,
|
|
name: game.name ?? '',
|
|
longName: game.longName ?? '',
|
|
order: game.order ?? 0,
|
|
imgUrl: game.imgUrl ?? '',
|
|
wordPressTag: game.wordPressTag ?? '',
|
|
wordPressTagOs: game.wordPressTagOs ?? '',
|
|
smashId: game.smashId ?? null
|
|
};
|
|
}
|
|
|
|
/** Blank text is stored as NULL rather than as an empty string. */
|
|
export function toDto(draft: Draft): GameDTO {
|
|
const text = (value: string) => (value.trim() === '' ? null : value.trim());
|
|
|
|
return {
|
|
id: draft.id,
|
|
name: text(draft.name),
|
|
longName: text(draft.longName),
|
|
order: draft.order ?? 0,
|
|
imgUrl: text(draft.imgUrl),
|
|
wordPressTag: text(draft.wordPressTag),
|
|
wordPressTagOs: text(draft.wordPressTagOs),
|
|
smashId: draft.smashId
|
|
};
|
|
}
|
|
|
|
/** A new game sorts after the current last one. */
|
|
export function nextOrder(games: GameDTO[]): number {
|
|
return games.reduce((max, game) => Math.max(max, game.order ?? 0), 0) + 1;
|
|
}
|
|
|
|
/**
|
|
* Whether the editor holds unsaved changes.
|
|
*
|
|
* Field by field rather than by comparing `JSON.stringify` output, which is
|
|
* key-order dependent: it would report a clean draft as dirty the moment
|
|
* `blankDraft` and `toDraft` listed their keys in a different order.
|
|
*/
|
|
export function isDirty(a: Draft, b: Draft): boolean {
|
|
return (
|
|
a.id !== b.id ||
|
|
a.name !== b.name ||
|
|
a.longName !== b.longName ||
|
|
a.order !== b.order ||
|
|
a.imgUrl !== b.imgUrl ||
|
|
a.wordPressTag !== b.wordPressTag ||
|
|
a.wordPressTagOs !== b.wordPressTagOs ||
|
|
a.smashId !== b.smashId
|
|
);
|
|
}
|