fix request cancellation issue in batch add weapons/summons
The addWeapons/addSummons methods were using Promise.all with Array.fill() which created arrays where all elements referenced the same object. This caused the request deduplication logic in BaseAdapter to cancel previous requests since they all had the same body/requestId. Fix: - Use Array.from() with spread to create unique object instances - Execute requests sequentially to avoid deduplication conflicts - Improve error handling in AddToCollectionModal to filter CancelledErrors
This commit is contained in:
parent
d9dd8f58ee
commit
c37c4f0101
2 changed files with 58 additions and 33 deletions
|
|
@ -203,13 +203,19 @@ export class CollectionAdapter extends BaseAdapter {
|
|||
inputs: Array<CollectionWeaponInput & { quantity?: number }>
|
||||
): Promise<CollectionWeapon[]> {
|
||||
// Expand inputs based on quantity
|
||||
// Note: We create individual objects to ensure unique request IDs for deduplication
|
||||
const expanded = inputs.flatMap((input) => {
|
||||
const count = input.quantity ?? 1
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { quantity, ...rest } = input
|
||||
return Array(count).fill(rest) as CollectionWeaponInput[]
|
||||
return Array.from({ length: count }, () => ({ ...rest })) as CollectionWeaponInput[]
|
||||
})
|
||||
return Promise.all(expanded.map((input) => this.addWeapon(input)))
|
||||
// Execute sequentially to avoid request deduplication issues
|
||||
const results: CollectionWeapon[] = []
|
||||
for (const input of expanded) {
|
||||
results.push(await this.addWeapon(input))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -282,13 +288,19 @@ export class CollectionAdapter extends BaseAdapter {
|
|||
inputs: Array<CollectionSummonInput & { quantity?: number }>
|
||||
): Promise<CollectionSummon[]> {
|
||||
// Expand inputs based on quantity
|
||||
// Note: We create individual objects to ensure unique request IDs for deduplication
|
||||
const expanded = inputs.flatMap((input) => {
|
||||
const count = input.quantity ?? 1
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { quantity, ...rest } = input
|
||||
return Array(count).fill(rest) as CollectionSummonInput[]
|
||||
return Array.from({ length: count }, () => ({ ...rest })) as CollectionSummonInput[]
|
||||
})
|
||||
return Promise.all(expanded.map((input) => this.addSummon(input)))
|
||||
// Execute sequentially to avoid request deduplication issues
|
||||
const results: CollectionSummon[] = []
|
||||
for (const input of expanded) {
|
||||
results.push(await this.addSummon(input))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -219,42 +219,55 @@
|
|||
}
|
||||
|
||||
async function handleAdd() {
|
||||
// Capture selected data before any state changes
|
||||
const currentEntityType = entityType
|
||||
const characterInputs =
|
||||
currentEntityType === 'character'
|
||||
? Array.from(selectedIds).map((characterId) => ({
|
||||
characterId,
|
||||
uncapLevel: 4,
|
||||
transcendenceStep: 0
|
||||
}))
|
||||
: []
|
||||
const weaponInputs =
|
||||
currentEntityType === 'weapon'
|
||||
? Array.from(selectedQuantities.entries()).map(([weaponId, quantity]) => ({
|
||||
weaponId,
|
||||
quantity,
|
||||
uncapLevel: 3,
|
||||
transcendenceStep: 0
|
||||
}))
|
||||
: []
|
||||
const summonInputs =
|
||||
currentEntityType === 'summon'
|
||||
? Array.from(selectedQuantities.entries()).map(([summonId, quantity]) => ({
|
||||
summonId,
|
||||
quantity,
|
||||
uncapLevel: 3,
|
||||
transcendenceStep: 0
|
||||
}))
|
||||
: []
|
||||
|
||||
try {
|
||||
if (entityType === 'character') {
|
||||
if (selectedIds.size === 0) return
|
||||
|
||||
const inputs = Array.from(selectedIds).map((characterId) => ({
|
||||
characterId,
|
||||
uncapLevel: 4,
|
||||
transcendenceStep: 0
|
||||
}))
|
||||
await addCharacterMutation.mutateAsync(inputs)
|
||||
} else if (entityType === 'weapon') {
|
||||
if (selectedQuantities.size === 0) return
|
||||
|
||||
const inputs = Array.from(selectedQuantities.entries()).map(([weaponId, quantity]) => ({
|
||||
weaponId,
|
||||
quantity,
|
||||
uncapLevel: 3,
|
||||
transcendenceStep: 0
|
||||
}))
|
||||
await addWeaponMutation.mutateAsync(inputs)
|
||||
if (currentEntityType === 'character') {
|
||||
if (characterInputs.length === 0) return
|
||||
await addCharacterMutation.mutateAsync(characterInputs)
|
||||
} else if (currentEntityType === 'weapon') {
|
||||
if (weaponInputs.length === 0) return
|
||||
await addWeaponMutation.mutateAsync(weaponInputs)
|
||||
} else {
|
||||
if (selectedQuantities.size === 0) return
|
||||
|
||||
const inputs = Array.from(selectedQuantities.entries()).map(([summonId, quantity]) => ({
|
||||
summonId,
|
||||
quantity,
|
||||
uncapLevel: 3,
|
||||
transcendenceStep: 0
|
||||
}))
|
||||
await addSummonMutation.mutateAsync(inputs)
|
||||
if (summonInputs.length === 0) return
|
||||
await addSummonMutation.mutateAsync(summonInputs)
|
||||
}
|
||||
|
||||
// Close modal after successful mutation
|
||||
open = false
|
||||
onOpenChange?.(false)
|
||||
} catch (error) {
|
||||
console.error(`Failed to add ${entityNames[entityType].plural}:`, error)
|
||||
// Only log non-cancellation errors
|
||||
if (error && typeof error === 'object' && 'name' in error && error.name !== 'CancelledError') {
|
||||
console.error(`Failed to add ${entityNames[currentEntityType].plural}:`, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue