fix: type errors in svelte-main branch (372 -> 217 errors)

- Fix Button variant errors (outlined -> ghost, contained -> primary)
- Fix search.queries.ts import path and property names (snake_case -> camelCase)
- Fix PartyContext export from party.service.ts
- Fix User type missing avatar property
- Fix exactOptionalPropertyTypes violations in Unit components
- Fix MenuItems Props interface
- Fix RequestOptions, SearchParams, SearchFilters types
- Fix UpdateUncapParams type
- Fix Select.ItemIndicator and maxLength errors
- Fix Summon/Weapon hp/atk properties in entity.adapter.ts

Co-Authored-By: Justin Edmund <justin@jedmund.com>
This commit is contained in:
Devin AI 2025-11-28 20:32:38 +00:00
parent 0afa6c5308
commit cab0a84588
16 changed files with 193 additions and 111 deletions

View file

@ -37,6 +37,29 @@ export interface Weapon {
ulbAttack?: number ulbAttack?: number
transcendenceHp?: number transcendenceHp?: number
transcendenceAttack?: number transcendenceAttack?: number
hp?: {
minHp?: number
maxHp?: number
maxHpFlb?: number
maxHpUlb?: number
}
atk?: {
minAtk?: number
maxAtk?: number
maxAtkFlb?: number
maxAtkUlb?: number
}
uncap?: {
flb?: boolean
ulb?: boolean
transcendence?: boolean
}
maxLevel?: number
skillLevelCap?: number
weapon_skills?: Array<{
name?: string
description?: string
}>
awakenings?: Array<{ awakenings?: Array<{
id: string id: string
name: Record<string, string> name: Record<string, string>
@ -109,8 +132,33 @@ export interface Summon {
ulbAttack?: number ulbAttack?: number
transcendenceHp?: number transcendenceHp?: number
transcendenceAttack?: number transcendenceAttack?: number
hp?: {
minHp?: number
maxHp?: number
maxHpFlb?: number
maxHpUlb?: number
maxHpXlb?: number
}
atk?: {
minAtk?: number
maxAtk?: number
maxAtkFlb?: number
maxAtkUlb?: number
maxAtkXlb?: number
}
uncap?: {
flb?: boolean
ulb?: boolean
transcendence?: boolean
}
subaura?: boolean subaura?: boolean
cooldown?: number cooldown?: number
callName?: string
callDescription?: string
auraName?: string
auraDescription?: string
subAuraName?: string
subAuraDescription?: string
} }
/** /**

View file

@ -49,11 +49,11 @@ export interface CreateGridSummonParams {
* Parameters for updating uncap levels * Parameters for updating uncap levels
*/ */
export interface UpdateUncapParams { export interface UpdateUncapParams {
id?: string id?: string | undefined
partyId: string partyId: string
position?: number position?: number | undefined
uncapLevel: number uncapLevel: number
transcendenceStep?: number transcendenceStep?: number | undefined
} }
/** /**

View file

@ -34,28 +34,31 @@ export interface AdapterOptions {
*/ */
export interface RequestOptions extends Omit<RequestInit, 'body' | 'cache'> { export interface RequestOptions extends Omit<RequestInit, 'body' | 'cache'> {
/** Query parameters to append to the URL */ /** Query parameters to append to the URL */
params?: Record<string, any> params?: Record<string, any> | undefined
/** Alternative alias for query parameters */ /** Alternative alias for query parameters */
query?: Record<string, any> query?: Record<string, any> | undefined
/** Request timeout in milliseconds. Overrides the adapter's default timeout */ /** Request timeout in milliseconds. Overrides the adapter's default timeout */
timeout?: number timeout?: number | undefined
/** Number of retry attempts for this specific request */ /** Number of retry attempts for this specific request */
retries?: number retries?: number | undefined
/** Cache duration for this request in milliseconds */ /** Cache duration for this request in milliseconds */
cacheTime?: number cacheTime?: number | undefined
/** Request cache mode */ /** Request cache mode */
cache?: RequestCache cache?: RequestCache | undefined
/** Alternative alias for cache duration */ /** Alternative alias for cache duration */
cacheTTL?: number cacheTTL?: number | undefined
/** Request body. Can be any serializable value */ /** Request body. Can be any serializable value */
body?: any body?: any
/** HTTP headers for the request */
headers?: Record<string, string> | undefined
} }
/** /**
@ -153,28 +156,28 @@ export interface ApiResponse<T> {
*/ */
export interface SearchFilters { export interface SearchFilters {
/** Filter by element IDs */ /** Filter by element IDs */
element?: number[] element?: number[] | undefined
/** Filter by rarity levels */ /** Filter by rarity levels */
rarity?: number[] rarity?: number[] | undefined
/** Filter by primary proficiency (weapons and characters) */ /** Filter by primary proficiency (weapons and characters) */
proficiency1?: number[] proficiency1?: number[] | undefined
/** Filter by secondary proficiency (characters only) */ /** Filter by secondary proficiency (characters only) */
proficiency2?: number[] proficiency2?: number[] | undefined
/** Filter by series */ /** Filter by series */
series?: number[] series?: number[] | undefined
/** Include extra/seasonal variants */ /** Include extra/seasonal variants */
extra?: boolean extra?: boolean | undefined
/** Filter summons with sub-aura */ /** Filter summons with sub-aura */
subaura?: boolean subaura?: boolean | undefined
/** Filter special characters */ /** Filter special characters */
special?: boolean special?: boolean | undefined
/** Custom filters for specific use cases */ /** Custom filters for specific use cases */
[key: string]: any [key: string]: any
@ -188,25 +191,25 @@ export interface SearchParams {
type: 'weapon' | 'character' | 'summon' type: 'weapon' | 'character' | 'summon'
/** Search query string */ /** Search query string */
query?: string query?: string | undefined
/** Filters to apply to the search */ /** Filters to apply to the search */
filters?: SearchFilters filters?: SearchFilters | undefined
/** Page number for pagination (1-indexed) */ /** Page number for pagination (1-indexed) */
page?: number page?: number | undefined
/** Number of items per page */ /** Number of items per page */
perPage?: number perPage?: number | undefined
/** Locale for localized content */ /** Locale for localized content */
locale?: 'en' | 'ja' locale?: 'en' | 'ja' | undefined
/** Items to exclude from results (by ID) */ /** Items to exclude from results (by ID) */
exclude?: string[] exclude?: string[] | undefined
/** AbortSignal for request cancellation */ /** AbortSignal for request cancellation */
signal?: AbortSignal signal?: AbortSignal | undefined
} }
/** /**

View file

@ -9,11 +9,9 @@
import { infiniteQueryOptions } from '@tanstack/svelte-query' import { infiniteQueryOptions } from '@tanstack/svelte-query'
import { import {
searchWeapons, searchAdapter,
searchCharacters,
searchSummons,
type SearchParams type SearchParams
} from '$lib/api/resources/search' } from '$lib/api/adapters/search.adapter'
/** /**
* Filter configuration for search queries * Filter configuration for search queries
@ -33,14 +31,14 @@ export interface SearchFilters {
export interface SearchPageResult { export interface SearchPageResult {
results: Array<{ results: Array<{
id: string id: string
granblue_id: string granblueId: string
name: { en?: string; ja?: string } name: { en?: string; ja?: string }
element?: number element?: number
rarity?: number rarity?: number
proficiency?: number proficiency?: number
series?: number series?: number
image_url?: string imageUrl?: string
searchable_type: 'Weapon' | 'Character' | 'Summon' searchableType: 'Weapon' | 'Character' | 'Summon'
}> }>
page: number page: number
totalPages: number totalPages: number
@ -131,12 +129,12 @@ export const searchQueries = {
queryKey: ['search', 'weapons', query, filters, locale] as const, queryKey: ['search', 'weapons', query, filters, locale] as const,
queryFn: async ({ pageParam }): Promise<SearchPageResult> => { queryFn: async ({ pageParam }): Promise<SearchPageResult> => {
const params = buildSearchParams(query, filters, pageParam, locale) const params = buildSearchParams(query, filters, pageParam, locale)
const response = await searchWeapons(params) const response = await searchAdapter.searchWeapons(params)
return { return {
results: response.results, results: response.results,
page: response.meta?.page ?? response.page ?? pageParam, page: response.meta?.page ?? response.page ?? pageParam,
totalPages: response.meta?.total_pages ?? response.total_pages ?? 1 totalPages: response.meta?.totalPages ?? response.totalPages ?? 1
} }
}, },
initialPageParam: 1, initialPageParam: 1,
@ -163,12 +161,12 @@ export const searchQueries = {
queryKey: ['search', 'characters', query, filters, locale] as const, queryKey: ['search', 'characters', query, filters, locale] as const,
queryFn: async ({ pageParam }): Promise<SearchPageResult> => { queryFn: async ({ pageParam }): Promise<SearchPageResult> => {
const params = buildSearchParams(query, filters, pageParam, locale) const params = buildSearchParams(query, filters, pageParam, locale)
const response = await searchCharacters(params) const response = await searchAdapter.searchCharacters(params)
return { return {
results: response.results, results: response.results,
page: response.meta?.page ?? response.page ?? pageParam, page: response.meta?.page ?? response.page ?? pageParam,
totalPages: response.meta?.total_pages ?? response.total_pages ?? 1 totalPages: response.meta?.totalPages ?? response.totalPages ?? 1
} }
}, },
initialPageParam: 1, initialPageParam: 1,
@ -195,12 +193,12 @@ export const searchQueries = {
queryKey: ['search', 'summons', query, filters, locale] as const, queryKey: ['search', 'summons', query, filters, locale] as const,
queryFn: async ({ pageParam }): Promise<SearchPageResult> => { queryFn: async ({ pageParam }): Promise<SearchPageResult> => {
const params = buildSearchParams(query, filters, pageParam, locale) const params = buildSearchParams(query, filters, pageParam, locale)
const response = await searchSummons(params) const response = await searchAdapter.searchSummons(params)
return { return {
results: response.results, results: response.results,
page: response.meta?.page ?? response.page ?? pageParam, page: response.meta?.page ?? response.page ?? pageParam,
totalPages: response.meta?.total_pages ?? response.total_pages ?? 1 totalPages: response.meta?.totalPages ?? response.totalPages ?? 1
} }
}, },
initialPageParam: 1, initialPageParam: 1,

View file

@ -197,11 +197,11 @@
</div> </div>
<div class="form-actions"> <div class="form-actions">
<Button variant="outlined" onclick={handleClose} disabled={saving}>Cancel</Button> <Button variant="ghost" onclick={handleClose} disabled={saving}>Cancel</Button>
<Button type="submit" variant="contained" disabled={saving}> <Button type="submit" variant="primary" disabled={saving}>
{saving ? 'Saving...' : 'Save Changes'} {saving ? 'Saving...' : 'Save Changes'}
</Button> </Button>
</div> </div>
</form> </form>
{/snippet} {/snippet}

View file

@ -144,7 +144,7 @@
<div class="error-state"> <div class="error-state">
<Icon name="alert-circle" size={32} /> <Icon name="alert-circle" size={32} />
<p>{error}</p> <p>{error}</p>
<Button size="small" on:click={loadJobs}>Retry</Button> <Button size="small" onclick={loadJobs}>Retry</Button>
</div> </div>
{:else if Object.keys(filteredJobs).length === 0} {:else if Object.keys(filteredJobs).length === 0}
<div class="empty-state"> <div class="empty-state">
@ -153,8 +153,8 @@
{#if searchQuery || selectedTiers.size > 0} {#if searchQuery || selectedTiers.size > 0}
<Button <Button
size="small" size="small"
variant="outlined" variant="ghost"
on:click={() => { onclick={() => {
searchQuery = '' searchQuery = ''
selectedTiers = new Set(['4', '5', 'ex2', 'o1']) selectedTiers = new Set(['4', '5', 'ex2', 'o1'])
}} }}

View file

@ -94,7 +94,7 @@
{disabled} {disabled}
{readonly} {readonly}
{required} {required}
{maxLength} maxlength={maxLength}
{...restProps} {...restProps}
/> />
@ -112,16 +112,16 @@
</div> </div>
{:else} {:else}
<input <input
bind:value bind:value
class={inputClasses} class={inputClasses}
{type} {type}
{placeholder} {placeholder}
{disabled} {disabled}
{readonly} {readonly}
{required} {required}
{maxLength} maxlength={maxLength}
{...restProps} {...restProps}
/> />
{/if} {/if}
{#if error} {#if error}
@ -143,7 +143,7 @@
{disabled} {disabled}
{readonly} {readonly}
{required} {required}
{maxLength} maxlength={maxLength}
{...restProps} {...restProps}
/> />
@ -161,16 +161,16 @@
</div> </div>
{:else} {:else}
<input <input
bind:value bind:value
class={inputClasses} class={inputClasses}
{type} {type}
{placeholder} {placeholder}
{disabled} {disabled}
{readonly} {readonly}
{required} {required}
{maxLength} maxlength={maxLength}
{...restProps} {...restProps}
/> />
{/if} {/if}
<style lang="scss"> <style lang="scss">

View file

@ -105,13 +105,17 @@
<SelectPrimitive.Viewport> <SelectPrimitive.Viewport>
{#each options as option} {#each options as option}
<SelectPrimitive.Item value={String(option.value)} disabled={option.disabled} class="item"> <SelectPrimitive.Item value={String(option.value)} disabled={option.disabled} class="item">
{#if option.image} {#snippet children({ selected })}
<img src={option.image} alt={option.label} class="image" /> {#if option.image}
{/if} <img src={option.image} alt={option.label} class="image" />
<span class="text">{option.label}</span> {/if}
<SelectPrimitive.ItemIndicator class="indicator"> <span class="text">{option.label}</span>
<Icon name="check" size={14} /> {#if selected}
</SelectPrimitive.ItemIndicator> <span class="indicator">
<Icon name="check" size={14} />
</span>
{/if}
{/snippet}
</SelectPrimitive.Item> </SelectPrimitive.Item>
{/each} {/each}
</SelectPrimitive.Viewport> </SelectPrimitive.Viewport>
@ -135,14 +139,18 @@
<SelectPrimitive.Content class="content"> <SelectPrimitive.Content class="content">
<SelectPrimitive.Viewport> <SelectPrimitive.Viewport>
{#each options as option} {#each options as option}
<SelectPrimitive.Item value={String(option.value)} disabled={option.disabled} class="item"> <SelectPrimitive.Item value={String(option.value)} disabled={option.disabled} class="item">
{#if option.image} {#snippet children({ selected })}
<img src={option.image} alt={option.label} class="image" /> {#if option.image}
{/if} <img src={option.image} alt={option.label} class="image" />
<span class="text">{option.label}</span> {/if}
<SelectPrimitive.ItemIndicator class="indicator"> <span class="text">{option.label}</span>
<Icon name="check" size={14} /> {#if selected}
</SelectPrimitive.ItemIndicator> <span class="indicator">
<Icon name="check" size={14} />
</span>
{/if}
{/snippet}
</SelectPrimitive.Item> </SelectPrimitive.Item>
{/each} {/each}
</SelectPrimitive.Viewport> </SelectPrimitive.Viewport>

View file

@ -2,14 +2,14 @@
import { ContextMenu, DropdownMenu } from 'bits-ui' import { ContextMenu, DropdownMenu } from 'bits-ui'
interface MenuItemsProps { interface MenuItemsProps {
onViewDetails?: () => void onViewDetails?: (() => void) | undefined
onReplace?: () => void onReplace?: (() => void) | undefined
onRemove?: () => void onRemove?: (() => void | Promise<void>) | undefined
canEdit?: boolean canEdit?: boolean | undefined
variant?: 'context' | 'dropdown' variant?: 'context' | 'dropdown'
viewDetailsLabel?: string viewDetailsLabel?: string | undefined
replaceLabel?: string replaceLabel?: string | undefined
removeLabel?: string removeLabel?: string | undefined
} }
let { let {

View file

@ -16,11 +16,11 @@
import * as m from '$lib/paraglide/messages' import * as m from '$lib/paraglide/messages'
interface Props { interface Props {
item?: GridCharacter item?: GridCharacter | undefined
position: number position: number
mainWeaponElement?: number | null mainWeaponElement?: number | null | undefined
partyElement?: number | null partyElement?: number | null | undefined
job?: Job job?: Job | undefined
} }
let { item, position, mainWeaponElement, partyElement, job }: Props = $props() let { item, position, mainWeaponElement, partyElement, job }: Props = $props()

View file

@ -12,7 +12,7 @@
import * as m from '$lib/paraglide/messages' import * as m from '$lib/paraglide/messages'
interface Props { interface Props {
item?: GridSummon item?: GridSummon | undefined
position: number position: number
} }
@ -24,6 +24,7 @@
canEdit: () => boolean canEdit: () => boolean
getEditKey: () => string | null getEditKey: () => string | null
services: { gridService: any; partyService: any } services: { gridService: any; partyService: any }
openPicker?: (opts: { type: 'weapon' | 'summon' | 'character'; position: number; item?: any }) => void
} }
const ctx = getContext<PartyCtx>('party') const ctx = getContext<PartyCtx>('party')

View file

@ -13,7 +13,7 @@
import * as m from '$lib/paraglide/messages' import * as m from '$lib/paraglide/messages'
interface Props { interface Props {
item?: GridWeapon item?: GridWeapon | undefined
position: number position: number
} }
@ -25,6 +25,7 @@
canEdit: () => boolean canEdit: () => boolean
getEditKey: () => string | null getEditKey: () => string | null
services: { gridService: any; partyService: any } services: { gridService: any; partyService: any }
openPicker?: (opts: { type: 'weapon' | 'summon' | 'character'; position: number; item?: any }) => void
} }
const ctx = getContext<PartyCtx>('party') const ctx = getContext<PartyCtx>('party')

View file

@ -3,6 +3,18 @@ import { partyAdapter } from '$lib/api/adapters/party.adapter'
import { authStore } from '$lib/stores/auth.store' import { authStore } from '$lib/stores/auth.store'
import { browser } from '$app/environment' import { browser } from '$app/environment'
/**
* Context type for party-related operations in components
*/
export interface PartyContext {
getParty: () => Party
updateParty: (p: Party) => void
canEdit: () => boolean
getEditKey: () => string | null
services: { gridService: any; partyService: any }
openPicker?: (opts: { type: 'weapon' | 'summon' | 'character'; position: number; item?: any }) => void
}
export interface EditabilityResult { export interface EditabilityResult {
canEdit: boolean canEdit: boolean
headers?: Record<string, string> headers?: Record<string, string>

View file

@ -194,4 +194,8 @@ export interface User {
role?: string role?: string
createdAt?: string createdAt?: string
updatedAt?: string updatedAt?: string
avatar?: {
picture?: string
element?: string
}
} }

View file

@ -204,20 +204,20 @@
</div> </div>
<div class="form-actions"> <div class="form-actions">
<Button <Button
variant="outlined" variant="ghost"
href="/me" href="/me"
> >
Cancel Cancel
</Button> </Button>
<Button <Button
type="submit" type="submit"
variant="contained" variant="primary"
disabled={saving} disabled={saving}
> >
{saving ? 'Saving...' : 'Save Changes'} {saving ? 'Saving...' : 'Save Changes'}
</Button> </Button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
@ -363,4 +363,4 @@
padding-top: spacing.$unit-2x; padding-top: spacing.$unit-2x;
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);
} }
</style> </style>

View file

@ -98,6 +98,12 @@
if (!partyId && !isCreatingParty && items.length > 0) { if (!partyId && !isCreatingParty && items.length > 0) {
isCreatingParty = true isCreatingParty = true
const firstItem = items[0] const firstItem = items[0]
// Guard against undefined firstItem (shouldn't happen given items.length > 0 check, but TypeScript needs this)
if (!firstItem) {
isCreatingParty = false
return
}
try { try {
// Step 1: Create the party (with local_id only for anonymous users) // Step 1: Create the party (with local_id only for anonymous users)
@ -262,6 +268,7 @@
try { try {
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
const item = items[i] const item = items[i]
if (!item) continue // Skip undefined items
let position = -1 // Default position let position = -1 // Default position
if (activeTab === GridType.Weapon) { if (activeTab === GridType.Weapon) {