fix type errors in import pages

This commit is contained in:
Justin Edmund 2025-12-02 00:08:55 -08:00
parent 64e50e1b50
commit 9ace2eb1e2
3 changed files with 111 additions and 88 deletions

View file

@ -2,12 +2,8 @@
<script lang="ts"> <script lang="ts">
import { goto } from '$app/navigation' import { goto } from '$app/navigation'
import { import { entityAdapter, type CharacterSuggestions } from '$lib/api/adapters/entity.adapter'
entityAdapter, import { getCharacterImage } from '$lib/utils/images'
type CharacterSuggestions,
type BatchPreviewResult
} from '$lib/api/adapters/entity.adapter'
import { getCharacterGridImageUrl } from '$lib/utils/images'
// Components // Components
import CharacterUncapSection from '$lib/features/database/characters/sections/CharacterUncapSection.svelte' import CharacterUncapSection from '$lib/features/database/characters/sections/CharacterUncapSection.svelte'
@ -26,6 +22,15 @@
import type { PageData } from './$types' import type { PageData } from './$types'
// Internal entity state including loading status
interface EntityState {
wikiPage: string
status: 'loading' | 'success' | 'error'
granblueId?: string
suggestions?: CharacterSuggestions
error?: string
}
let { data }: { data: PageData } = $props() let { data }: { data: PageData } = $props()
// Input phase // Input phase
@ -34,7 +39,7 @@
let fetchError = $state<string | null>(null) let fetchError = $state<string | null>(null)
// Fetched entities // Fetched entities
let entities = $state<Map<string, BatchPreviewResult<CharacterSuggestions>>>(new Map()) let entities = $state<Map<string, EntityState>>(new Map())
let selectedWikiPage = $state<string | null>(null) let selectedWikiPage = $state<string | null>(null)
// Form data per entity (keyed by wikiPage) // Form data per entity (keyed by wikiPage)
@ -66,8 +71,8 @@
// Get selected entity data // Get selected entity data
const selectedEntity = $derived(selectedWikiPage ? entities.get(selectedWikiPage) : null) const selectedEntity = $derived(selectedWikiPage ? entities.get(selectedWikiPage) : null)
const selectedFormData = $derived(selectedWikiPage ? formDataMap.get(selectedWikiPage) : null) const selectedFormData = $derived(selectedWikiPage ? formDataMap.get(selectedWikiPage) : null)
const selectedDismissed = $derived( const selectedDismissed = $derived<Set<string>>(
selectedWikiPage ? dismissedSuggestionsMap.get(selectedWikiPage) ?? new Set() : new Set() selectedWikiPage ? dismissedSuggestionsMap.get(selectedWikiPage) ?? new Set<string>() : new Set<string>()
) )
// Entity tabs for TabbedEntitySelector // Entity tabs for TabbedEntitySelector
@ -77,7 +82,7 @@
granblueId: entity.granblueId, granblueId: entity.granblueId,
status: entity.status, status: entity.status,
imageUrl: entity.granblueId imageUrl: entity.granblueId
? getCharacterGridImageUrl(entity.granblueId) ? getCharacterImage(entity.granblueId, 'grid')
: '/images/placeholders/placeholder-character-grid.png', : '/images/placeholders/placeholder-character-grid.png',
error: entity.error, error: entity.error,
saved: savedEntities.has(wikiPage) saved: savedEntities.has(wikiPage)
@ -143,11 +148,11 @@
fetchError = null fetchError = null
// Initialize entities as loading // Initialize entities as loading
const newEntities = new Map<string, BatchPreviewResult<CharacterSuggestions>>() const newEntities = new Map<string, EntityState>()
pages.forEach((page) => { pages.forEach((page) => {
newEntities.set(page, { newEntities.set(page, {
wikiPage: page, wikiPage: page,
status: 'loading' as const status: 'loading'
}) })
}) })
entities = newEntities entities = newEntities
@ -157,15 +162,21 @@
const response = await entityAdapter.batchPreviewCharacters(pages) const response = await entityAdapter.batchPreviewCharacters(pages)
// Update entities with results // Update entities with results
const updatedEntities = new Map<string, BatchPreviewResult<CharacterSuggestions>>() const updatedEntities = new Map<string, EntityState>()
response.results.forEach((result) => { response.results.forEach((result) => {
updatedEntities.set(result.wikiPage, result) updatedEntities.set(result.wikiPage, {
wikiPage: result.wikiPage,
status: result.status,
granblueId: result.granblueId,
suggestions: result.suggestions,
error: result.error
})
// Create form data for successful results // Create form data for successful results
if (result.status === 'success') { if (result.status === 'success') {
const formData = createEmptyFormData(result.wikiPage, result.suggestions) const formData = createEmptyFormData(result.wikiPage, result.suggestions)
formDataMap.set(result.wikiPage, formData) formDataMap.set(result.wikiPage, formData)
dismissedSuggestionsMap.set(result.wikiPage, new Set()) dismissedSuggestionsMap.set(result.wikiPage, new Set<string>())
} }
}) })
entities = updatedEntities entities = updatedEntities
@ -208,54 +219,56 @@
// Save current entity // Save current entity
async function saveCurrentEntity() { async function saveCurrentEntity() {
if (!selectedWikiPage || !selectedFormData) return if (!selectedWikiPage) return
const formData = formDataMap.get(selectedWikiPage)
if (!formData) return
isSaving = true isSaving = true
saveError = null saveError = null
try { try {
const payload = { const payload = {
granblue_id: selectedFormData.granblueId, granblue_id: formData.granblueId,
name_en: selectedFormData.name, name_en: formData.name,
name_jp: selectedFormData.nameJp, name_jp: formData.nameJp,
character_id: character_id:
selectedFormData.characterId.trim() === '' formData.characterId.trim() === ''
? [] ? []
: selectedFormData.characterId : formData.characterId
.split(',') .split(',')
.map((id: string) => Number(id.trim())) .map((id: string) => Number(id.trim()))
.filter((id: number) => !isNaN(id)), .filter((id: number) => !isNaN(id)),
rarity: selectedFormData.rarity, rarity: formData.rarity,
element: selectedFormData.element, element: formData.element,
race1: selectedFormData.race1, race1: formData.race1,
race2: selectedFormData.race2, race2: formData.race2,
gender: selectedFormData.gender, gender: formData.gender,
proficiency1: selectedFormData.proficiency1, proficiency1: formData.proficiency1,
proficiency2: selectedFormData.proficiency2, proficiency2: formData.proficiency2,
min_hp: selectedFormData.minHp, min_hp: formData.minHp,
max_hp: selectedFormData.maxHp, max_hp: formData.maxHp,
max_hp_flb: selectedFormData.maxHpFlb, max_hp_flb: formData.maxHpFlb,
max_hp_ulb: selectedFormData.maxHpUlb, max_hp_ulb: formData.maxHpUlb,
min_atk: selectedFormData.minAtk, min_atk: formData.minAtk,
max_atk: selectedFormData.maxAtk, max_atk: formData.maxAtk,
max_atk_flb: selectedFormData.maxAtkFlb, max_atk_flb: formData.maxAtkFlb,
max_atk_ulb: selectedFormData.maxAtkUlb, max_atk_ulb: formData.maxAtkUlb,
base_da: selectedFormData.baseDa, base_da: formData.baseDa,
base_ta: selectedFormData.baseTa, base_ta: formData.baseTa,
ougi_ratio: selectedFormData.ougiRatio, ougi_ratio: formData.ougiRatio,
ougi_ratio_flb: selectedFormData.ougiRatioFlb, ougi_ratio_flb: formData.ougiRatioFlb,
flb: selectedFormData.flb, flb: formData.flb,
ulb: selectedFormData.ulb, ulb: formData.ulb,
special: selectedFormData.special, special: formData.special,
release_date: selectedFormData.releaseDate || null, release_date: formData.releaseDate || null,
flb_date: selectedFormData.flbDate || null, flb_date: formData.flbDate || null,
ulb_date: selectedFormData.ulbDate || null, ulb_date: formData.ulbDate || null,
wiki_en: selectedFormData.wikiEn, wiki_en: formData.wikiEn,
wiki_ja: selectedFormData.wikiJa, wiki_ja: formData.wikiJa,
gamewith: selectedFormData.gamewith, gamewith: formData.gamewith,
kamigame: selectedFormData.kamigame, kamigame: formData.kamigame,
nicknames_en: selectedFormData.nicknamesEn, nicknames_en: formData.nicknamesEn,
nicknames_jp: selectedFormData.nicknamesJp nicknames_jp: formData.nicknamesJp
} }
await entityAdapter.createCharacter(payload) await entityAdapter.createCharacter(payload)
@ -280,12 +293,16 @@
} }
// Can save current entity // Can save current entity
const canSave = $derived( const canSave = $derived.by(() => {
selectedFormData && if (!selectedWikiPage) return false
selectedFormData.name.trim() !== '' && const formData = formDataMap.get(selectedWikiPage)
selectedFormData.granblueId.trim() !== '' && if (!formData) return false
!savedEntities.has(selectedWikiPage ?? '') return (
) formData.name.trim() !== '' &&
formData.granblueId.trim() !== '' &&
!savedEntities.has(selectedWikiPage)
)
})
// All entities saved // All entities saved
const allSaved = $derived( const allSaved = $derived(
@ -363,14 +380,15 @@
<div class="entity-loading"> <div class="entity-loading">
<p>Loading wiki data...</p> <p>Loading wiki data...</p>
</div> </div>
{:else if selectedFormData} {:else if selectedWikiPage && formDataMap.has(selectedWikiPage)}
{@const formData = formDataMap.get(selectedWikiPage)!}
{@const suggestions = selectedEntity.suggestions} {@const suggestions = selectedEntity.suggestions}
{@const dismissed = selectedDismissed} {@const dismissed = dismissedSuggestionsMap.get(selectedWikiPage) ?? new Set<string>()}
<section class="details"> <section class="details">
<DetailsContainer title="Basic Info"> <DetailsContainer title="Basic Info">
<SuggestionDetailItem <SuggestionDetailItem
label="Name (EN)" label="Name (EN)"
bind:value={selectedFormData.name} bind:value={formData.name}
editable={true} editable={true}
type="text" type="text"
placeholder="Character name" placeholder="Character name"
@ -381,7 +399,7 @@
/> />
<SuggestionDetailItem <SuggestionDetailItem
label="Name (JP)" label="Name (JP)"
bind:value={selectedFormData.nameJp} bind:value={formData.nameJp}
editable={true} editable={true}
type="text" type="text"
placeholder="キャラクター名" placeholder="キャラクター名"
@ -393,7 +411,7 @@
<DetailItem <DetailItem
label="Character ID" label="Character ID"
sublabel="Separate multiple IDs with commas" sublabel="Separate multiple IDs with commas"
bind:value={selectedFormData.characterId} bind:value={formData.characterId}
editable={true} editable={true}
type="text" type="text"
placeholder="Character IDs" placeholder="Character IDs"
@ -403,7 +421,7 @@
<CharacterMetadataSection <CharacterMetadataSection
character={emptyCharacter} character={emptyCharacter}
editMode={true} editMode={true}
bind:editData={selectedFormData} bind:editData={formData}
{suggestions} {suggestions}
dismissedSuggestions={dismissed} dismissedSuggestions={dismissed}
onAcceptSuggestion={handleAcceptSuggestion} onAcceptSuggestion={handleAcceptSuggestion}
@ -413,7 +431,7 @@
<CharacterUncapSection <CharacterUncapSection
character={emptyCharacter} character={emptyCharacter}
editMode={true} editMode={true}
bind:editData={selectedFormData} bind:editData={formData}
{suggestions} {suggestions}
dismissedSuggestions={dismissed} dismissedSuggestions={dismissed}
onAcceptSuggestion={handleAcceptSuggestion} onAcceptSuggestion={handleAcceptSuggestion}
@ -423,7 +441,7 @@
<CharacterTaxonomySection <CharacterTaxonomySection
character={emptyCharacter} character={emptyCharacter}
editMode={true} editMode={true}
bind:editData={selectedFormData} bind:editData={formData}
{suggestions} {suggestions}
dismissedSuggestions={dismissed} dismissedSuggestions={dismissed}
onAcceptSuggestion={handleAcceptSuggestion} onAcceptSuggestion={handleAcceptSuggestion}
@ -433,7 +451,7 @@
<CharacterStatsSection <CharacterStatsSection
character={emptyCharacter} character={emptyCharacter}
editMode={true} editMode={true}
bind:editData={selectedFormData} bind:editData={formData}
{suggestions} {suggestions}
dismissedSuggestions={dismissed} dismissedSuggestions={dismissed}
onAcceptSuggestion={handleAcceptSuggestion} onAcceptSuggestion={handleAcceptSuggestion}
@ -442,17 +460,17 @@
<DetailsContainer title="Nicknames"> <DetailsContainer title="Nicknames">
<DetailItem label="Nicknames (EN)"> <DetailItem label="Nicknames (EN)">
<TagInput bind:value={selectedFormData.nicknamesEn} placeholder="Add nickname..." contained /> <TagInput bind:value={formData.nicknamesEn} placeholder="Add nickname..." contained />
</DetailItem> </DetailItem>
<DetailItem label="Nicknames (JP)"> <DetailItem label="Nicknames (JP)">
<TagInput bind:value={selectedFormData.nicknamesJp} placeholder="ニックネーム..." contained /> <TagInput bind:value={formData.nicknamesJp} placeholder="ニックネーム..." contained />
</DetailItem> </DetailItem>
</DetailsContainer> </DetailsContainer>
<DetailsContainer title="Dates"> <DetailsContainer title="Dates">
<SuggestionDetailItem <SuggestionDetailItem
label="Release Date" label="Release Date"
bind:value={selectedFormData.releaseDate} bind:value={formData.releaseDate}
editable={true} editable={true}
type="text" type="text"
placeholder="YYYY-MM-DD" placeholder="YYYY-MM-DD"
@ -461,10 +479,10 @@
onAcceptSuggestion={() => handleAcceptSuggestion('releaseDate', suggestions?.releaseDate)} onAcceptSuggestion={() => handleAcceptSuggestion('releaseDate', suggestions?.releaseDate)}
onDismissSuggestion={() => handleDismissSuggestion('releaseDate')} onDismissSuggestion={() => handleDismissSuggestion('releaseDate')}
/> />
{#if selectedFormData.flb} {#if formData.flb}
<SuggestionDetailItem <SuggestionDetailItem
label="FLB Date" label="FLB Date"
bind:value={selectedFormData.flbDate} bind:value={formData.flbDate}
editable={true} editable={true}
type="text" type="text"
placeholder="YYYY-MM-DD" placeholder="YYYY-MM-DD"
@ -474,10 +492,10 @@
onDismissSuggestion={() => handleDismissSuggestion('flbDate')} onDismissSuggestion={() => handleDismissSuggestion('flbDate')}
/> />
{/if} {/if}
{#if selectedFormData.ulb} {#if formData.ulb}
<SuggestionDetailItem <SuggestionDetailItem
label="ULB Date" label="ULB Date"
bind:value={selectedFormData.ulbDate} bind:value={formData.ulbDate}
editable={true} editable={true}
type="text" type="text"
placeholder="YYYY-MM-DD" placeholder="YYYY-MM-DD"
@ -492,7 +510,7 @@
<DetailsContainer title="Links"> <DetailsContainer title="Links">
<DetailItem <DetailItem
label="Wiki (EN)" label="Wiki (EN)"
bind:value={selectedFormData.wikiEn} bind:value={formData.wikiEn}
editable={true} editable={true}
type="text" type="text"
placeholder="https://gbf.wiki/..." placeholder="https://gbf.wiki/..."
@ -500,7 +518,7 @@
/> />
<DetailItem <DetailItem
label="Wiki (JP)" label="Wiki (JP)"
bind:value={selectedFormData.wikiJa} bind:value={formData.wikiJa}
editable={true} editable={true}
type="text" type="text"
placeholder="https://gbf-wiki.com/..." placeholder="https://gbf-wiki.com/..."
@ -508,7 +526,7 @@
/> />
<SuggestionDetailItem <SuggestionDetailItem
label="Gamewith" label="Gamewith"
bind:value={selectedFormData.gamewith} bind:value={formData.gamewith}
editable={true} editable={true}
type="text" type="text"
placeholder="https://..." placeholder="https://..."
@ -520,7 +538,7 @@
/> />
<SuggestionDetailItem <SuggestionDetailItem
label="Kamigame" label="Kamigame"
bind:value={selectedFormData.kamigame} bind:value={formData.kamigame}
editable={true} editable={true}
type="text" type="text"
placeholder="https://..." placeholder="https://..."

View file

@ -7,7 +7,7 @@
type SummonSuggestions, type SummonSuggestions,
type BatchPreviewResult type BatchPreviewResult
} from '$lib/api/adapters/entity.adapter' } from '$lib/api/adapters/entity.adapter'
import { getSummonGridImageUrl } from '$lib/utils/images' import { getSummonImage } from '$lib/utils/images'
// Components // Components
import SummonUncapSection from '$lib/features/database/summons/sections/SummonUncapSection.svelte' import SummonUncapSection from '$lib/features/database/summons/sections/SummonUncapSection.svelte'
@ -77,7 +77,7 @@
granblueId: entity.granblueId, granblueId: entity.granblueId,
status: entity.status, status: entity.status,
imageUrl: entity.granblueId imageUrl: entity.granblueId
? getSummonGridImageUrl(entity.granblueId) ? getSummonImage(entity.granblueId)
: '/images/placeholders/placeholder-summon-sub.png', : '/images/placeholders/placeholder-summon-sub.png',
error: entity.error, error: entity.error,
saved: savedEntities.has(wikiPage) saved: savedEntities.has(wikiPage)

View file

@ -2,12 +2,8 @@
<script lang="ts"> <script lang="ts">
import { goto } from '$app/navigation' import { goto } from '$app/navigation'
import { import { entityAdapter, type WeaponSuggestions } from '$lib/api/adapters/entity.adapter'
entityAdapter, import { getWeaponImage } from '$lib/utils/images'
type WeaponSuggestions,
type BatchPreviewResult
} from '$lib/api/adapters/entity.adapter'
import { getWeaponGridImageUrl } from '$lib/utils/images'
// Components // Components
import WeaponUncapSection from '$lib/features/database/weapons/sections/WeaponUncapSection.svelte' import WeaponUncapSection from '$lib/features/database/weapons/sections/WeaponUncapSection.svelte'
@ -27,6 +23,15 @@
import type { PageData } from './$types' import type { PageData } from './$types'
// Internal entity state including loading status
interface EntityState {
wikiPage: string
status: 'loading' | 'success' | 'error'
granblueId?: string
suggestions?: WeaponSuggestions
error?: string
}
let { data }: { data: PageData } = $props() let { data }: { data: PageData } = $props()
// Input phase // Input phase
@ -35,7 +40,7 @@
let fetchError = $state<string | null>(null) let fetchError = $state<string | null>(null)
// Fetched entities // Fetched entities
let entities = $state<Map<string, BatchPreviewResult<WeaponSuggestions>>>(new Map()) let entities = $state<Map<string, EntityState>>(new Map())
let selectedWikiPage = $state<string | null>(null) let selectedWikiPage = $state<string | null>(null)
// Form data per entity (keyed by wikiPage) // Form data per entity (keyed by wikiPage)
@ -76,7 +81,7 @@
granblueId: entity.granblueId, granblueId: entity.granblueId,
status: entity.status, status: entity.status,
imageUrl: entity.granblueId imageUrl: entity.granblueId
? getWeaponGridImageUrl(entity.granblueId) ? getWeaponImage(entity.granblueId)
: '/images/placeholders/placeholder-weapon-grid.png', : '/images/placeholders/placeholder-weapon-grid.png',
error: entity.error, error: entity.error,
saved: savedEntities.has(wikiPage) saved: savedEntities.has(wikiPage)