From 9243d133cdb7a40895c2a89fc9a77746d7d44275 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 15 Dec 2025 12:49:00 -0800 Subject: [PATCH] reconcile character detail and edit pages - same section order on both pages - show all fields (empty shows dash) - add editable nicknames/links to edit page - handle CharacterSeriesRef[] -> number[] conversion --- .../characters/[granblueId]/+page.svelte | 135 ++++++++------- .../characters/[granblueId]/edit/+page.svelte | 162 ++++++++++++++++-- 2 files changed, 222 insertions(+), 75 deletions(-) diff --git a/src/routes/(app)/database/characters/[granblueId]/+page.svelte b/src/routes/(app)/database/characters/[granblueId]/+page.svelte index c0a9d814..eb2964a8 100644 --- a/src/routes/(app)/database/characters/[granblueId]/+page.svelte +++ b/src/routes/(app)/database/characters/[granblueId]/+page.svelte @@ -21,7 +21,6 @@ import CharacterMetadataSection from '$lib/features/database/characters/sections/CharacterMetadataSection.svelte' import CharacterUncapSection from '$lib/features/database/characters/sections/CharacterUncapSection.svelte' import CharacterTaxonomySection from '$lib/features/database/characters/sections/CharacterTaxonomySection.svelte' - import CharacterGachaSection from '$lib/features/database/characters/sections/CharacterGachaSection.svelte' import CharacterStatsSection from '$lib/features/database/characters/sections/CharacterStatsSection.svelte' import EntityImagesTab from '$lib/features/database/detail/tabs/EntityImagesTab.svelte' import EntityRawDataTab from '$lib/features/database/detail/tabs/EntityRawDataTab.svelte' @@ -180,81 +179,83 @@ {#if currentTab === 'info'}
- - {#if character.nicknames?.en?.length || character.nicknames?.ja?.length} - - {#if character.nicknames?.en?.length} - -
- {#each character.nicknames.en as nickname} - {nickname} - {/each} -
-
- {/if} - {#if character.nicknames?.ja?.length} - -
- {#each character.nicknames.ja as nickname} - {nickname} - {/each} -
-
- {/if} -
- {/if} - - - {#if character.releaseDate || character.flbDate || character.ulbDate} - - {#if character.releaseDate} - + + + {#if character.nicknames?.en?.length} +
+ {#each character.nicknames.en as nickname} + {nickname} + {/each} +
+ {:else} + {/if} - {#if character.flbDate} - + + + {#if character.nicknames?.ja?.length} +
+ {#each character.nicknames.ja as nickname} + {nickname} + {/each} +
+ {:else} + {/if} - {#if character.ulbDate} - - {/if} -
- {/if} +
+
- {#if character.links?.wikiEn || character.links?.wikiJa || character.links?.gamewith || character.links?.kamigame} - - {#if character.links?.wikiEn} - - - {character.links.wikiEn} - - + + + {#if character.uncap?.flb} + + {/if} + {#if character.uncap?.ulb} + + {/if} + + + + + {#if character.wiki?.en} + + {character.wiki.en} + + {:else} + {/if} - {#if character.links?.wikiJa} - - - {character.links.wikiJa} - - + + + {#if character.wiki?.ja} + + {character.wiki.ja} + + {:else} + {/if} - {#if character.links?.gamewith} - - - {character.links.gamewith} - - + + + {#if character.gamewith} + + {character.gamewith} + + {:else} + {/if} - {#if character.links?.kamigame} - - - {character.links.kamigame} - - + + + {#if character.kamigame} + + {character.kamigame} + + {:else} + {/if} - - {/if} + + {#if relatedQuery.data?.length} @@ -402,4 +403,8 @@ text-decoration: underline; } } + + .empty-value { + color: colors.$grey-50; + } diff --git a/src/routes/(app)/database/characters/[granblueId]/edit/+page.svelte b/src/routes/(app)/database/characters/[granblueId]/edit/+page.svelte index c57d0ed4..75440f7c 100644 --- a/src/routes/(app)/database/characters/[granblueId]/edit/+page.svelte +++ b/src/routes/(app)/database/characters/[granblueId]/edit/+page.svelte @@ -19,15 +19,21 @@ import CharacterMetadataSection from '$lib/features/database/characters/sections/CharacterMetadataSection.svelte' import CharacterUncapSection from '$lib/features/database/characters/sections/CharacterUncapSection.svelte' import CharacterTaxonomySection from '$lib/features/database/characters/sections/CharacterTaxonomySection.svelte' - import CharacterGachaSection from '$lib/features/database/characters/sections/CharacterGachaSection.svelte' import CharacterStatsSection from '$lib/features/database/characters/sections/CharacterStatsSection.svelte' import DetailsContainer from '$lib/components/ui/DetailsContainer.svelte' import DetailItem from '$lib/components/ui/DetailItem.svelte' + import TagInput from '$lib/components/ui/TagInput.svelte' import { getCharacterImage } from '$lib/utils/images' + import { CHARACTER_SERIES_NAMES } from '$lib/types/enums' // Types import type { PageData } from './$types' + // Create reverse mapping from series name to integer + const SERIES_NAME_TO_INT: Record = Object.fromEntries( + Object.entries(CHARACTER_SERIES_NAMES).map(([key, name]) => [name, Number(key)]) + ) + let { data }: { data: PageData } = $props() const queryClient = useQueryClient() @@ -52,7 +58,7 @@ let editData = $state({ name: '', granblueId: '', - characterId: null as number | null, + characterId: '', // Comma-separated string for dual/trio units rarity: 1, element: 0, race1: null as number | null, @@ -60,28 +66,68 @@ gender: 0, proficiency1: 0, proficiency2: 0, + season: 0, + series: [] as number[], + // HP stats minHp: 0, maxHp: 0, maxHpFlb: 0, + maxHpUlb: 0, + // Attack stats minAtk: 0, maxAtk: 0, maxAtkFlb: 0, + maxAtkUlb: 0, + // Other stats + baseDa: 0, + baseTa: 0, + ougiRatio: 0, + ougiRatioFlb: 0, + // Uncap flags flb: false, ulb: false, transcendence: false, special: false, + // Dates releaseDate: '', flbDate: '', - ulbDate: '' + ulbDate: '', + // Nicknames + nicknamesEn: [] as string[], + nicknamesJp: [] as string[], + // Links + wikiEn: '', + wikiJa: '', + gamewith: '', + kamigame: '' }) + // Helper to convert series to number array (handles both legacy integer and object formats) + function seriesAsNumbers( + series: number[] | Array<{ id: string; name?: { en?: string } }> | undefined + ): number[] { + if (!series || series.length === 0) return [] + // Check if first element is an object (CharacterSeriesRef) or number + const first = series[0] + if (typeof first === 'object' && first !== null && 'id' in first) { + // It's CharacterSeriesRef[] - convert using name.en to look up enum value + return (series as Array<{ id: string; name?: { en?: string } }>) + .map((s) => { + const name = s.name?.en + return name ? SERIES_NAME_TO_INT[name] : undefined + }) + .filter((n): n is number => n !== undefined) + } + return series as number[] + } + // Populate edit data when character loads $effect(() => { if (character) { editData = { name: character.name?.en || '', granblueId: character.granblueId || '', - characterId: character.characterId ?? null, + characterId: character.characterId?.join(', ') || '', rarity: character.rarity || 1, element: character.element || 0, race1: character.race?.[0] ?? null, @@ -89,19 +135,40 @@ gender: character.gender || 0, proficiency1: character.proficiency?.[0] || 0, proficiency2: character.proficiency?.[1] || 0, + season: character.season || 0, + series: seriesAsNumbers(character.series), + // HP stats minHp: character.hp?.minHp || 0, maxHp: character.hp?.maxHp || 0, maxHpFlb: character.hp?.maxHpFlb || 0, + maxHpUlb: character.hp?.maxHpUlb || 0, + // Attack stats minAtk: character.atk?.minAtk || 0, maxAtk: character.atk?.maxAtk || 0, maxAtkFlb: character.atk?.maxAtkFlb || 0, + maxAtkUlb: character.atk?.maxAtkUlb || 0, + // Other stats + baseDa: character.baseDa || 0, + baseTa: character.baseTa || 0, + ougiRatio: character.ougiRatio?.ougiRatio || 0, + ougiRatioFlb: character.ougiRatio?.ougiRatioFlb || 0, + // Uncap flags flb: character.uncap?.flb || false, ulb: character.uncap?.ulb || false, transcendence: character.uncap?.transcendence || false, special: character.special || false, + // Dates releaseDate: character.releaseDate || '', flbDate: character.flbDate || '', - ulbDate: character.ulbDate || '' + ulbDate: character.ulbDate || '', + // Nicknames + nicknamesEn: character.nicknames?.en || [], + nicknamesJp: character.nicknames?.ja || [], + // Links + wikiEn: character.wiki?.en || '', + wikiJa: character.wiki?.ja || '', + gamewith: character.gamewith || '', + kamigame: character.kamigame || '' } } }) @@ -117,7 +184,13 @@ const payload = { name_en: editData.name, granblue_id: editData.granblueId, - character_id: editData.characterId ? [editData.characterId] : [], + character_id: + editData.characterId.trim() === '' + ? [] + : editData.characterId + .split(',') + .map((id) => Number(id.trim())) + .filter((id) => !isNaN(id)), rarity: editData.rarity, element: editData.element, race1: editData.race1, @@ -125,18 +198,40 @@ gender: editData.gender, proficiency1: editData.proficiency1, proficiency2: editData.proficiency2, + season: editData.season || undefined, + series: editData.series, + // HP stats min_hp: editData.minHp, max_hp: editData.maxHp, max_hp_flb: editData.maxHpFlb, + max_hp_ulb: editData.maxHpUlb, + // Attack stats min_atk: editData.minAtk, max_atk: editData.maxAtk, max_atk_flb: editData.maxAtkFlb, + max_atk_ulb: editData.maxAtkUlb, + // Other stats + base_da: editData.baseDa, + base_ta: editData.baseTa, + ougi_ratio: editData.ougiRatio, + ougi_ratio_flb: editData.ougiRatioFlb, + // Uncap flags flb: editData.flb, ulb: editData.ulb, + transcendence: editData.transcendence, special: editData.special, - release_date: editData.releaseDate || null, - flb_date: editData.flbDate || null, - ulb_date: editData.ulbDate || null + // Dates + release_date: editData.releaseDate || undefined, + flb_date: editData.flbDate || undefined, + ulb_date: editData.ulbDate || undefined, + // Nicknames + nicknames_en: editData.nicknamesEn, + nicknames_jp: editData.nicknamesJp, + // Links + wiki_en: editData.wikiEn || undefined, + wiki_ja: editData.wikiJa || undefined, + gamewith: editData.gamewith || undefined, + kamigame: editData.kamigame || undefined } await entityAdapter.updateCharacter(character.id, payload) @@ -186,9 +281,21 @@ - + + + + + + + + + {/if} + + + + + + +
{:else}