migrate /teams/new to query-based architecture
This commit is contained in:
parent
d0f7b3b89a
commit
f66b31fea8
1 changed files with 108 additions and 149 deletions
|
|
@ -13,13 +13,22 @@
|
|||
import { partyAdapter, gridAdapter } from '$lib/api/adapters'
|
||||
import { getLocalId } from '$lib/utils/localId'
|
||||
import { storeEditKey } from '$lib/utils/editKeys'
|
||||
import type { Party } from '$lib/types/api/party'
|
||||
|
||||
// TanStack Query
|
||||
import { createQuery, useQueryClient } from '@tanstack/svelte-query'
|
||||
import { partyQueries } from '$lib/api/queries/party.queries'
|
||||
import { partyKeys } from '$lib/api/queries/party.queries'
|
||||
|
||||
// TanStack Query mutations
|
||||
import { useCreateParty } from '$lib/api/mutations/party.mutations'
|
||||
import {
|
||||
useCreateGridWeapon,
|
||||
useCreateGridCharacter,
|
||||
useCreateGridSummon
|
||||
useCreateGridSummon,
|
||||
useDeleteGridWeapon,
|
||||
useDeleteGridCharacter,
|
||||
useDeleteGridSummon
|
||||
} from '$lib/api/mutations/grid.mutations'
|
||||
import { Dialog } from 'bits-ui'
|
||||
import { replaceState } from '$app/navigation'
|
||||
|
|
@ -73,19 +82,42 @@
|
|||
return characters.length >= 5
|
||||
}
|
||||
|
||||
// Grid state
|
||||
let weapons = $state<any[]>([])
|
||||
let summons = $state<any[]>([])
|
||||
let characters = $state<any[]>([])
|
||||
let selectedSlot = $state<number | null>(null)
|
||||
let isFirstItemForSlot = false // Track if this is the first item after clicking empty cell
|
||||
|
||||
// Party state
|
||||
let partyId = $state<string | null>(null)
|
||||
let shortcode = $state<string | null>(null)
|
||||
let editKey = $state<string | null>(null)
|
||||
let isCreatingParty = $state(false)
|
||||
|
||||
// Placeholder party for 'new' route
|
||||
const placeholderParty: Party = {
|
||||
id: 'new',
|
||||
shortcode: 'new',
|
||||
name: 'New Team',
|
||||
description: '',
|
||||
weapons: [],
|
||||
summons: [],
|
||||
characters: [],
|
||||
element: 0,
|
||||
visibility: 1
|
||||
}
|
||||
|
||||
// Create query with placeholder data
|
||||
const queryClient = useQueryClient()
|
||||
const partyQuery = createQuery(() => ({
|
||||
...partyQueries.byShortcode(shortcode || 'new'),
|
||||
initialData: placeholderParty,
|
||||
enabled: false // Disable automatic fetching for 'new' party
|
||||
}))
|
||||
|
||||
// Derive state from query
|
||||
const party = $derived(partyQuery.data ?? placeholderParty)
|
||||
const weapons = $derived(party.weapons ?? [])
|
||||
const summons = $derived(party.summons ?? [])
|
||||
const characters = $derived(party.characters ?? [])
|
||||
|
||||
let selectedSlot = $state<number | null>(null)
|
||||
let isFirstItemForSlot = false // Track if this is the first item after clicking empty cell
|
||||
|
||||
// Error dialog state
|
||||
let errorDialogOpen = $state(false)
|
||||
let errorMessage = $state('')
|
||||
|
|
@ -96,6 +128,22 @@
|
|||
const createWeaponMutation = useCreateGridWeapon()
|
||||
const createCharacterMutation = useCreateGridCharacter()
|
||||
const createSummonMutation = useCreateGridSummon()
|
||||
const deleteWeapon = useDeleteGridWeapon()
|
||||
const deleteCharacter = useDeleteGridCharacter()
|
||||
const deleteSummon = useDeleteGridSummon()
|
||||
|
||||
// Helper to add item to cache
|
||||
function addItemToCache(itemType: 'weapons' | 'summons' | 'characters', item: any) {
|
||||
const cacheKey = partyKeys.detail(shortcode || 'new')
|
||||
|
||||
queryClient.setQueryData(cacheKey, (old: Party | undefined) => {
|
||||
if (!old) return placeholderParty
|
||||
return {
|
||||
...old,
|
||||
[itemType]: [...(old[itemType] ?? []), item]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Calculate if grids are full
|
||||
let isWeaponGridFull = $derived(weapons.length >= 10) // 1 mainhand + 9 grid slots
|
||||
|
|
@ -156,6 +204,12 @@
|
|||
throw new Error('Party creation did not return ID or shortcode')
|
||||
}
|
||||
|
||||
// Update the query cache with the created party
|
||||
queryClient.setQueryData(
|
||||
partyKeys.detail(createdParty.shortcode),
|
||||
createdParty
|
||||
)
|
||||
|
||||
// Step 2: Add the first item to the party
|
||||
let position = selectedSlot !== null ? selectedSlot : -1 // Use selectedSlot if available
|
||||
let itemAdded = false
|
||||
|
|
@ -174,8 +228,8 @@
|
|||
console.log('Weapon added:', addResult)
|
||||
itemAdded = true
|
||||
|
||||
// Update local state with the added weapon
|
||||
weapons = [...weapons, addResult]
|
||||
// Update cache with the added weapon
|
||||
addItemToCache('weapons', addResult)
|
||||
} else if (activeTab === GridType.Summon) {
|
||||
// Use selectedSlot if available, otherwise default to main summon
|
||||
if (selectedSlot === null) position = -1
|
||||
|
|
@ -189,8 +243,8 @@
|
|||
console.log('Summon added:', addResult)
|
||||
itemAdded = true
|
||||
|
||||
// Update local state with the added summon
|
||||
summons = [...summons, addResult]
|
||||
// Update cache with the added summon
|
||||
addItemToCache('summons', addResult)
|
||||
} else if (activeTab === GridType.Character) {
|
||||
// Use selectedSlot if available, otherwise default to first slot
|
||||
if (selectedSlot === null) position = 0
|
||||
|
|
@ -202,8 +256,8 @@
|
|||
console.log('Character added:', addResult)
|
||||
itemAdded = true
|
||||
|
||||
// Update local state with the added character
|
||||
characters = [...characters, addResult]
|
||||
// Update cache with the added character
|
||||
addItemToCache('characters', addResult)
|
||||
}
|
||||
selectedSlot = null // Reset after using
|
||||
|
||||
|
|
@ -290,8 +344,8 @@
|
|||
mainhand: position === -1
|
||||
})
|
||||
|
||||
// Add to local state
|
||||
weapons = [...weapons, response]
|
||||
// Add to cache
|
||||
addItemToCache('weapons', response)
|
||||
} else if (activeTab === GridType.Summon) {
|
||||
// Use selectedSlot for first item if available
|
||||
if (i === 0 && selectedSlot !== null && !summons.find(s => s.position === selectedSlot)) {
|
||||
|
|
@ -314,8 +368,8 @@
|
|||
friend: position === 6
|
||||
})
|
||||
|
||||
// Add to local state
|
||||
summons = [...summons, response]
|
||||
// Add to cache
|
||||
addItemToCache('summons', response)
|
||||
} else if (activeTab === GridType.Character) {
|
||||
// Use selectedSlot for first item if available
|
||||
if (i === 0 && selectedSlot !== null && !characters.find(c => c.position === selectedSlot)) {
|
||||
|
|
@ -336,8 +390,8 @@
|
|||
position
|
||||
})
|
||||
|
||||
// Add to local state
|
||||
characters = [...characters, response]
|
||||
// Add to cache
|
||||
addItemToCache('characters', response)
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
|
|
@ -348,143 +402,48 @@
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Original local-only adding logic (before party creation)
|
||||
if (activeTab === GridType.Weapon) {
|
||||
// Add weapons to empty slots
|
||||
const emptySlots = Array.from({ length: 10 }, (_, i) => i - 1) // -1 for mainhand, 0-8 for grid
|
||||
.filter(i => !weapons.find(w => w.position === i))
|
||||
|
||||
items.forEach((item, index) => {
|
||||
let position: number
|
||||
// Use selectedSlot for first item if available
|
||||
if (index === 0 && selectedSlot !== null && !weapons.find(w => w.position === selectedSlot)) {
|
||||
position = selectedSlot
|
||||
selectedSlot = null // Reset after using
|
||||
} else {
|
||||
// Find next empty slot
|
||||
const availableSlots = emptySlots.filter(s => !weapons.find(w => w.position === s))
|
||||
if (availableSlots.length === 0) return
|
||||
position = availableSlots[0]!
|
||||
}
|
||||
|
||||
const newWeapon = {
|
||||
id: `temp-${Date.now()}-${index}`,
|
||||
position,
|
||||
object: {
|
||||
granblueId: item.granblueId,
|
||||
name: item.name,
|
||||
element: item.element
|
||||
},
|
||||
mainhand: position === -1
|
||||
}
|
||||
console.log('Adding weapon:', newWeapon)
|
||||
weapons = [...weapons, newWeapon]
|
||||
})
|
||||
console.log('Updated weapons array:', weapons)
|
||||
} else if (activeTab === GridType.Summon) {
|
||||
// Add summons to empty slots
|
||||
const emptySlots = [-1, 0, 1, 2, 3, 6] // main, 4 grid slots, friend
|
||||
.filter(i => !summons.find(s => s.position === i))
|
||||
|
||||
items.forEach((item, index) => {
|
||||
let position: number
|
||||
// Use selectedSlot for first item if available
|
||||
if (index === 0 && selectedSlot !== null && !summons.find(s => s.position === selectedSlot)) {
|
||||
position = selectedSlot
|
||||
selectedSlot = null // Reset after using
|
||||
} else {
|
||||
// Find next empty slot
|
||||
const availableSlots = emptySlots.filter(s => !summons.find(sum => sum.position === s))
|
||||
if (availableSlots.length === 0) return
|
||||
position = availableSlots[0]!
|
||||
}
|
||||
|
||||
summons = [...summons, {
|
||||
id: `temp-${Date.now()}-${index}`,
|
||||
position,
|
||||
object: {
|
||||
granblueId: item.granblueId,
|
||||
name: item.name,
|
||||
element: item.element
|
||||
},
|
||||
main: position === -1,
|
||||
friend: position === 6
|
||||
}]
|
||||
})
|
||||
} else if (activeTab === GridType.Character) {
|
||||
// Add characters to empty slots
|
||||
const emptySlots = Array.from({ length: 5 }, (_, i) => i)
|
||||
.filter(i => !characters.find(c => c.position === i))
|
||||
|
||||
items.forEach((item, index) => {
|
||||
let position: number
|
||||
// Use selectedSlot for first item if available
|
||||
if (index === 0 && selectedSlot !== null && !characters.find(c => c.position === selectedSlot)) {
|
||||
position = selectedSlot
|
||||
selectedSlot = null // Reset after using
|
||||
} else {
|
||||
// Find next empty slot
|
||||
const availableSlots = emptySlots.filter(s => !characters.find(c => c.position === s))
|
||||
if (availableSlots.length === 0) return
|
||||
position = availableSlots[0]!
|
||||
}
|
||||
|
||||
characters = [...characters, {
|
||||
id: `temp-${Date.now()}-${index}`,
|
||||
position,
|
||||
object: {
|
||||
granblueId: item.granblueId,
|
||||
name: item.name,
|
||||
element: item.element
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Remove functions
|
||||
function removeWeapon(itemId: string) {
|
||||
console.log('Removing weapon:', itemId)
|
||||
weapons = weapons.filter(w => w.id !== itemId)
|
||||
return Promise.resolve({ id: 'new', shortcode: 'new', weapons, summons, characters })
|
||||
}
|
||||
|
||||
function removeSummon(itemId: string) {
|
||||
console.log('Removing summon:', itemId)
|
||||
summons = summons.filter(s => s.id !== itemId)
|
||||
return Promise.resolve({ id: 'new', shortcode: 'new', weapons, summons, characters })
|
||||
}
|
||||
|
||||
function removeCharacter(itemId: string) {
|
||||
console.log('Removing character:', itemId)
|
||||
characters = characters.filter(c => c.id !== itemId)
|
||||
return Promise.resolve({ id: 'new', shortcode: 'new', weapons, summons, characters })
|
||||
}
|
||||
|
||||
// Provide a minimal party context so Unit components can render safely.
|
||||
// Provide party context using query data
|
||||
setContext('party', {
|
||||
getParty: () => ({ id: 'new', shortcode: 'new', weapons, summons, characters }),
|
||||
updateParty: (updatedParty: any) => {
|
||||
// Update the local state when party is updated
|
||||
if (updatedParty.weapons) weapons = updatedParty.weapons
|
||||
if (updatedParty.summons) summons = updatedParty.summons
|
||||
if (updatedParty.characters) characters = updatedParty.characters
|
||||
getParty: () => party,
|
||||
updateParty: (p: Party) => {
|
||||
// Update cache instead of local state
|
||||
queryClient.setQueryData(partyKeys.detail(shortcode || 'new'), p)
|
||||
},
|
||||
canEdit: () => true,
|
||||
getEditKey: () => editKey,
|
||||
services: {
|
||||
gridService: {
|
||||
removeWeapon: (partyId: string, itemId: string) => removeWeapon(itemId),
|
||||
removeSummon: (partyId: string, itemId: string) => removeSummon(itemId),
|
||||
removeCharacter: (partyId: string, itemId: string) => removeCharacter(itemId),
|
||||
addWeapon: () => Promise.resolve({ party: { id: 'new', shortcode: 'new', weapons, summons, characters } }),
|
||||
addSummon: () => Promise.resolve({ party: { id: 'new', shortcode: 'new', weapons, summons, characters } }),
|
||||
addCharacter: () => Promise.resolve({ party: { id: 'new', shortcode: 'new', weapons, summons, characters } }),
|
||||
replaceWeapon: () => Promise.resolve({ party: { id: 'new', shortcode: 'new', weapons, summons, characters } }),
|
||||
replaceSummon: () => Promise.resolve({ party: { id: 'new', shortcode: 'new', weapons, summons, characters } }),
|
||||
replaceCharacter: () => Promise.resolve({ party: { id: 'new', shortcode: 'new', weapons, summons, characters } })
|
||||
},
|
||||
partyService: { getEditKey: () => null }
|
||||
removeWeapon: async (partyId: string, itemId: string) => {
|
||||
if (!partyId || partyId === 'new') return party
|
||||
await deleteWeapon.mutateAsync({
|
||||
id: itemId,
|
||||
partyId,
|
||||
partyShortcode: shortcode || 'new'
|
||||
})
|
||||
return party
|
||||
},
|
||||
removeSummon: async (partyId: string, itemId: string) => {
|
||||
if (!partyId || partyId === 'new') return party
|
||||
await deleteSummon.mutateAsync({
|
||||
id: itemId,
|
||||
partyId,
|
||||
partyShortcode: shortcode || 'new'
|
||||
})
|
||||
return party
|
||||
},
|
||||
removeCharacter: async (partyId: string, itemId: string) => {
|
||||
if (!partyId || partyId === 'new') return party
|
||||
await deleteCharacter.mutateAsync({
|
||||
id: itemId,
|
||||
partyId,
|
||||
partyShortcode: shortcode || 'new'
|
||||
})
|
||||
return party
|
||||
}
|
||||
}
|
||||
},
|
||||
openPicker: (opts: { type: 'weapon' | 'summon' | 'character'; position: number; item?: any }) => {
|
||||
selectedSlot = opts.position
|
||||
|
|
|
|||
Loading…
Reference in a new issue