complete handleSave for weapon modifiers, update key select to use slug
This commit is contained in:
parent
c5f6963ca7
commit
a251240331
3 changed files with 137 additions and 45 deletions
|
|
@ -10,6 +10,7 @@
|
|||
import AxSkillSelect from './edit/AxSkillSelect.svelte'
|
||||
import Button from '$lib/components/ui/Button.svelte'
|
||||
import { getElementIcon } from '$lib/utils/images'
|
||||
import { seriesHasWeaponKeys, getSeriesSlug } from '$lib/utils/weaponSeries'
|
||||
|
||||
interface Props {
|
||||
weapon: GridWeapon
|
||||
|
|
@ -42,23 +43,24 @@
|
|||
// Weapon data shortcuts
|
||||
const weaponData = $derived(weapon.weapon)
|
||||
const canChangeElement = $derived(weaponData?.element === 0)
|
||||
const series = $derived(weaponData?.series ?? 0)
|
||||
const series = $derived(weaponData?.series)
|
||||
const seriesSlug = $derived(getSeriesSlug(series))
|
||||
const transcendenceStep = $derived(weapon.transcendenceStep ?? 0)
|
||||
|
||||
// Weapon key config keyed by WEAPON series
|
||||
// Maps weapon.series → { slots, keySeries } where keySeries is what weapon_keys API expects
|
||||
const WEAPON_KEY_SERIES: Record<number, { name: string; slots: number; keySeries: number }> = {
|
||||
2: { name: 'Dark Opus', slots: 2, keySeries: 3 }, // Pendulum (slot 0) + Chain/Pendulum (slot 1)
|
||||
3: { name: 'Ultima', slots: 3, keySeries: 13 }, // Gauph Key (slot 0) + Ultima Key (slot 1) + Gate (slot 2)
|
||||
17: { name: 'Draconic', slots: 2, keySeries: 27 }, // Teluma (slot 0) + Teluma (slot 1)
|
||||
22: { name: 'Astral', slots: 1, keySeries: 19 }, // Emblem (slot 0)
|
||||
34: { name: 'Superlative', slots: 2, keySeries: 40 } // Teluma (slot 0) + Teluma (slot 1)
|
||||
// Weapon key slot configuration by series slug
|
||||
// Maps series slug → number of weapon key slots
|
||||
const WEAPON_KEY_SLOTS: Record<string, number> = {
|
||||
'dark-opus': 2, // Pendulum (slot 0) + Chain/Pendulum (slot 1)
|
||||
'ultima': 3, // Gauph Key (slot 0) + Ultima Key (slot 1) + Gate (slot 2)
|
||||
'draconic': 2, // Teluma (slot 0) + Teluma (slot 1)
|
||||
'draconic-providence': 2, // Same as Draconic
|
||||
'superlative': 2, // Teluma (slot 0) + Teluma (slot 1)
|
||||
// Add more as needed
|
||||
}
|
||||
|
||||
const weaponKeyConfig = $derived(WEAPON_KEY_SERIES[series])
|
||||
const hasWeaponKeys = $derived(!!weaponKeyConfig)
|
||||
const keySlotCount = $derived(weaponKeyConfig?.slots ?? 0)
|
||||
const keySeries = $derived(weaponKeyConfig?.keySeries ?? 0)
|
||||
// Check if series has weapon keys using the utility (handles both formats)
|
||||
const hasWeaponKeys = $derived(seriesHasWeaponKeys(series))
|
||||
const keySlotCount = $derived(seriesSlug ? (WEAPON_KEY_SLOTS[seriesSlug] ?? 2) : 0)
|
||||
|
||||
const hasAxSkills = $derived(weaponData?.ax === true)
|
||||
const axType = $derived(weaponData?.axType ?? 1)
|
||||
|
|
@ -95,16 +97,92 @@
|
|||
return '—'
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
const updates: Partial<GridWeapon> = {}
|
||||
// Build the update payload for the API
|
||||
// Uses flat key IDs rather than nested arrays, as expected by the API
|
||||
interface WeaponUpdatePayload {
|
||||
element?: number
|
||||
weaponKey1Id?: string | null
|
||||
weaponKey2Id?: string | null
|
||||
weaponKey3Id?: string | null
|
||||
awakeningId?: string | null
|
||||
awakeningLevel?: number
|
||||
axModifier1?: number | null
|
||||
axStrength1?: number | null
|
||||
axModifier2?: number | null
|
||||
axStrength2?: number | null
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
const updates: WeaponUpdatePayload = {}
|
||||
|
||||
// Element change (only for element-changeable weapons)
|
||||
if (canChangeElement && element !== weapon.element) {
|
||||
updates.element = element
|
||||
}
|
||||
|
||||
// TODO: Add weapon keys, AX skills, awakening updates
|
||||
// Weapon keys - send individual key IDs
|
||||
if (hasWeaponKeys) {
|
||||
const originalKey1 = weapon.weaponKeys?.[0]?.id
|
||||
const originalKey2 = weapon.weaponKeys?.[1]?.id
|
||||
const originalKey3 = weapon.weaponKeys?.[2]?.id
|
||||
|
||||
onSave?.(updates)
|
||||
if (weaponKey1 !== originalKey1) {
|
||||
updates.weaponKey1Id = weaponKey1 ?? null
|
||||
}
|
||||
if (weaponKey2 !== originalKey2) {
|
||||
updates.weaponKey2Id = weaponKey2 ?? null
|
||||
}
|
||||
if (weaponKey3 !== originalKey3) {
|
||||
updates.weaponKey3Id = weaponKey3 ?? null
|
||||
}
|
||||
}
|
||||
|
||||
// Awakening - send awakening ID and level
|
||||
if (hasAwakening) {
|
||||
const originalAwakeningId = weapon.awakening?.type?.id
|
||||
const originalLevel = weapon.awakening?.level ?? 1
|
||||
|
||||
if (selectedAwakening?.id !== originalAwakeningId) {
|
||||
updates.awakeningId = selectedAwakening?.id ?? null
|
||||
}
|
||||
if (awakeningLevel !== originalLevel) {
|
||||
updates.awakeningLevel = awakeningLevel
|
||||
}
|
||||
}
|
||||
|
||||
// AX skills - send modifier/strength pairs
|
||||
if (hasAxSkills) {
|
||||
const originalAx = weapon.ax ?? [
|
||||
{ modifier: -1, strength: 0 },
|
||||
{ modifier: -1, strength: 0 }
|
||||
]
|
||||
|
||||
const ax1 = axSkills[0]
|
||||
const ax2 = axSkills[1]
|
||||
const origAx1 = originalAx[0]
|
||||
const origAx2 = originalAx[1]
|
||||
|
||||
if (ax1?.modifier !== origAx1?.modifier) {
|
||||
updates.axModifier1 = ax1?.modifier ?? null
|
||||
}
|
||||
if (ax1?.strength !== origAx1?.strength) {
|
||||
updates.axStrength1 = ax1?.strength ?? null
|
||||
}
|
||||
if (ax2?.modifier !== origAx2?.modifier) {
|
||||
updates.axModifier2 = ax2?.modifier ?? null
|
||||
}
|
||||
if (ax2?.strength !== origAx2?.strength) {
|
||||
updates.axStrength2 = ax2?.strength ?? null
|
||||
}
|
||||
}
|
||||
|
||||
// Only call onSave if there are actual updates
|
||||
if (Object.keys(updates).length > 0) {
|
||||
onSave?.(updates as Partial<GridWeapon>)
|
||||
} else {
|
||||
// No changes, just close the panel
|
||||
onCancel?.()
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
|
|
@ -148,12 +226,12 @@
|
|||
</DetailsSection>
|
||||
{/if}
|
||||
|
||||
{#if hasWeaponKeys}
|
||||
{#if hasWeaponKeys && seriesSlug}
|
||||
<DetailsSection title="Weapon Keys">
|
||||
<div class="key-selects">
|
||||
{#if keySlotCount >= 1}
|
||||
<WeaponKeySelect
|
||||
series={keySeries}
|
||||
{seriesSlug}
|
||||
slot={0}
|
||||
bind:value={weaponKey1}
|
||||
{transcendenceStep}
|
||||
|
|
@ -161,7 +239,7 @@
|
|||
{/if}
|
||||
{#if keySlotCount >= 2}
|
||||
<WeaponKeySelect
|
||||
series={keySeries}
|
||||
{seriesSlug}
|
||||
slot={1}
|
||||
bind:value={weaponKey2}
|
||||
{transcendenceStep}
|
||||
|
|
@ -169,7 +247,7 @@
|
|||
{/if}
|
||||
{#if keySlotCount >= 3}
|
||||
<WeaponKeySelect
|
||||
series={keySeries}
|
||||
{seriesSlug}
|
||||
slot={2}
|
||||
bind:value={weaponKey3}
|
||||
{transcendenceStep}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
<script lang="ts">
|
||||
import { createQuery } from '@tanstack/svelte-query'
|
||||
import { entityQueries } from '$lib/api/queries/entity.queries'
|
||||
import { entityAdapter } from '$lib/api/adapters/entity.adapter'
|
||||
import type { WeaponKey } from '$lib/api/adapters/entity.adapter'
|
||||
import Select from '$lib/components/ui/Select.svelte'
|
||||
import { queryOptions } from '@tanstack/svelte-query'
|
||||
|
||||
interface Props {
|
||||
/** The weapon series (determines which keys are available) */
|
||||
series: number
|
||||
/** The slot number (1, 2, or 3) */
|
||||
/** The weapon series slug (determines which keys are available) */
|
||||
seriesSlug?: string
|
||||
/** The slot number (0, 1, or 2) */
|
||||
slot: number
|
||||
/** Currently selected weapon key ID */
|
||||
value?: string
|
||||
|
|
@ -17,42 +18,54 @@
|
|||
transcendenceStep?: number
|
||||
}
|
||||
|
||||
let { series, slot, value = $bindable(), onchange, transcendenceStep = 0 }: Props = $props()
|
||||
let { seriesSlug, slot, value = $bindable(), onchange, transcendenceStep = 0 }: Props = $props()
|
||||
|
||||
// Key type names based on series and slot (0-based indexing)
|
||||
const KEY_TYPE_NAMES: Record<number, Record<number, { en: string; ja: string }>> = {
|
||||
// Dark Opus (series 3)
|
||||
3: {
|
||||
// Key type names based on series slug and slot (0-based indexing)
|
||||
const KEY_TYPE_NAMES: Record<string, Record<number, { en: string; ja: string }>> = {
|
||||
// Dark Opus
|
||||
'dark-opus': {
|
||||
0: { en: 'Pendulum', ja: 'ペンデュラム' },
|
||||
1: { en: 'Pendulum/Chain', ja: 'ペンデュラム/チェイン' }
|
||||
},
|
||||
// Draconic (series 27)
|
||||
27: {
|
||||
// Draconic
|
||||
'draconic': {
|
||||
0: { en: 'Teluma', ja: 'テルマ' },
|
||||
1: { en: 'Teluma', ja: 'テルマ' }
|
||||
},
|
||||
// Ultima (series 13)
|
||||
13: {
|
||||
// Draconic Providence
|
||||
'draconic-providence': {
|
||||
0: { en: 'Teluma', ja: 'テルマ' },
|
||||
1: { en: 'Teluma', ja: 'テルマ' }
|
||||
},
|
||||
// Ultima
|
||||
'ultima': {
|
||||
0: { en: 'Gauph Key', ja: 'ガフスキー' },
|
||||
1: { en: 'Ultima Key', ja: 'ガフスキーΩ' },
|
||||
2: { en: 'Gate of Omnipotence', ja: 'ガフスキー' }
|
||||
},
|
||||
// Astral (series 19)
|
||||
19: {
|
||||
0: { en: 'Emblem', ja: 'エンブレム' }
|
||||
},
|
||||
// Superlative (series 40)
|
||||
40: {
|
||||
// Superlative
|
||||
'superlative': {
|
||||
0: { en: 'Teluma', ja: 'テルマ' },
|
||||
1: { en: 'Teluma', ja: 'テルマ' }
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch weapon keys for this series and slot
|
||||
const weaponKeysQuery = createQuery(() => entityQueries.weaponKeys({ series, slot }))
|
||||
// Fetch weapon keys for this series slug and slot
|
||||
const weaponKeysQuery = createQuery(() =>
|
||||
queryOptions({
|
||||
queryKey: ['weaponKeys', 'slug', seriesSlug, slot] as const,
|
||||
queryFn: async () => {
|
||||
if (!seriesSlug) return []
|
||||
return entityAdapter.getWeaponKeys({ seriesSlug, slot })
|
||||
},
|
||||
enabled: !!seriesSlug,
|
||||
staleTime: 1000 * 60 * 60,
|
||||
gcTime: 1000 * 60 * 60 * 24
|
||||
})
|
||||
)
|
||||
|
||||
// Get the key type name for this series/slot
|
||||
const keyTypeName = $derived(KEY_TYPE_NAMES[series]?.[slot]?.en ?? 'Key')
|
||||
const keyTypeName = $derived(seriesSlug ? (KEY_TYPE_NAMES[seriesSlug]?.[slot]?.en ?? 'Key') : 'Key')
|
||||
|
||||
// Group and sort weapon keys
|
||||
const groupedOptions = $derived.by(() => {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@
|
|||
import { getWeaponKeyImages } from '$lib/utils/modifiers'
|
||||
import type { WeaponKey } from '$lib/types/api/entities'
|
||||
import type { LocalizedName } from '$lib/types/api/entities'
|
||||
import type { WeaponSeriesRef } from '$lib/types/api/weaponSeries'
|
||||
|
||||
interface Props {
|
||||
weaponKeys?: WeaponKey[]
|
||||
weaponData?: {
|
||||
element?: number
|
||||
proficiency?: number | number[]
|
||||
series?: number
|
||||
series?: WeaponSeriesRef | null
|
||||
name?: LocalizedName
|
||||
}
|
||||
layout?: 'list' | 'grid'
|
||||
|
|
@ -32,7 +33,7 @@
|
|||
return key.slug || 'Weapon Key'
|
||||
}
|
||||
|
||||
function getSlotLabel(slot: number, series?: number): string {
|
||||
function getSlotLabel(slot: number, series?: WeaponSeriesRef | null): string {
|
||||
return `Skill ${slot + 1}`
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in a new issue