feat: add grid API endpoints and drag-drop support

This commit is contained in:
Justin Edmund 2025-09-17 10:46:49 -07:00
parent 666109ef7d
commit e4c59e14f6
3 changed files with 129 additions and 53 deletions

View file

@ -282,3 +282,97 @@ export async function removeCharacter(
throw new Error(`Failed to remove character: ${res.statusText}`) throw new Error(`Failed to remove character: ${res.statusText}`)
} }
} }
// Uncap update methods - these use special endpoints
export async function updateCharacterUncap(
gridCharacterId: string,
uncapLevel?: number,
transcendenceStep?: number,
headers?: Record<string, string>
): Promise<any> {
const body = {
character: {
id: gridCharacterId,
...(uncapLevel !== undefined && { uncap_level: uncapLevel }),
...(transcendenceStep !== undefined && { transcendence_step: transcendenceStep })
}
}
const res = await fetch('/api/uncap/characters', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...headers
},
body: JSON.stringify(body)
})
if (!res.ok) {
throw new Error(`Failed to update character uncap: ${res.statusText}`)
}
return res.json()
}
export async function updateWeaponUncap(
gridWeaponId: string,
uncapLevel?: number,
transcendenceStep?: number,
headers?: Record<string, string>
): Promise<any> {
const body = {
weapon: {
id: gridWeaponId,
...(uncapLevel !== undefined && { uncap_level: uncapLevel }),
...(transcendenceStep !== undefined && { transcendence_step: transcendenceStep })
}
}
const res = await fetch('/api/uncap/weapons', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...headers
},
body: JSON.stringify(body)
})
if (!res.ok) {
throw new Error(`Failed to update weapon uncap: ${res.statusText}`)
}
return res.json()
}
export async function updateSummonUncap(
gridSummonId: string,
uncapLevel?: number,
transcendenceStep?: number,
headers?: Record<string, string>
): Promise<any> {
const body = {
summon: {
id: gridSummonId,
...(uncapLevel !== undefined && { uncap_level: uncapLevel }),
...(transcendenceStep !== undefined && { transcendence_step: transcendenceStep })
}
}
const res = await fetch('/api/uncap/summons', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...headers
},
body: JSON.stringify(body)
})
if (!res.ok) {
throw new Error(`Failed to update summon uncap: ${res.statusText}`)
}
return res.json()
}

View file

@ -99,7 +99,10 @@ export function createDragDropContext(handlers: DragDropHandlers = {}) {
if (e.pointerType === 'touch') { if (e.pointerType === 'touch') {
initiateTouchDrag(e, item, source, type) initiateTouchDrag(e, item, source, type)
} else { } else {
startDrag(item, { ...source, type }) // For mouse, don't start drag immediately - wait for actual drag movement
// This prevents the dragging class from being applied on simple clicks
state.touchState.touchStartPos = { x: e.clientX, y: e.clientY }
state.touchState.currentTouch = { item, source, type }
} }
} }
@ -123,10 +126,20 @@ export function createDragDropContext(handlers: DragDropHandlers = {}) {
Math.pow(e.clientY - state.touchState.touchStartPos.y, 2) Math.pow(e.clientY - state.touchState.touchStartPos.y, 2)
) )
if (distance > state.touchState.touchThreshold && state.touchState.longPressTimer) { // For touch events, cancel long press if moved too much
if (e.pointerType === 'touch' && distance > state.touchState.touchThreshold && state.touchState.longPressTimer) {
clearTimeout(state.touchState.longPressTimer) clearTimeout(state.touchState.longPressTimer)
state.touchState.longPressTimer = null state.touchState.longPressTimer = null
} }
// For mouse events, start dragging after threshold movement
if (e.pointerType === 'mouse' && !state.isDragging && state.touchState.currentTouch) {
if (distance > state.touchState.touchThreshold) {
const { item, source, type } = state.touchState.currentTouch
startDrag(item, { ...source, type })
state.touchState.currentTouch = null
}
}
} }
function handlePointerUp() { function handlePointerUp() {
@ -135,6 +148,7 @@ export function createDragDropContext(handlers: DragDropHandlers = {}) {
state.touchState.longPressTimer = null state.touchState.longPressTimer = null
} }
state.touchState.touchStartPos = null state.touchState.touchStartPos = null
state.touchState.currentTouch = null
} }
function startDrag(item: GridItem, source: DragSource) { function startDrag(item: GridItem, source: DragSource) {

View file

@ -1,5 +1,6 @@
import type { Party, GridWeapon, GridSummon, GridCharacter } from '$lib/types/api/party' import type { Party, GridWeapon, GridSummon, GridCharacter } from '$lib/types/api/party'
import * as partiesApi from '$lib/api/resources/parties' import * as partiesApi from '$lib/api/resources/parties'
import * as gridApi from '$lib/api/resources/grid'
import type { FetchLike } from '$lib/api/core' import type { FetchLike } from '$lib/api/core'
export interface GridOperation { export interface GridOperation {
@ -171,27 +172,15 @@ export class GridService {
} }
async updateWeaponUncap( async updateWeaponUncap(
partyId: string,
gridWeaponId: string, gridWeaponId: string,
uncapLevel: number, uncapLevel?: number,
transcendenceLevel: number, transcendenceStep?: number,
editKey?: string editKey?: string
): Promise<Party> { ): Promise<any> {
const payload = { return gridApi.updateWeaponUncap(
id: gridWeaponId, gridWeaponId,
uncapLevel, uncapLevel,
transcendenceLevel transcendenceStep,
}
// Set uncap to 6 when transcending
if (transcendenceLevel > 0 && uncapLevel < 6) {
payload.uncapLevel = 6
}
return partiesApi.updateWeaponGrid(
this.fetch,
partyId,
payload,
this.buildHeaders(editKey) this.buildHeaders(editKey)
) )
} }
@ -281,27 +270,15 @@ export class GridService {
} }
async updateSummonUncap( async updateSummonUncap(
partyId: string,
gridSummonId: string, gridSummonId: string,
uncapLevel: number, uncapLevel?: number,
transcendenceLevel: number, transcendenceStep?: number,
editKey?: string editKey?: string
): Promise<Party> { ): Promise<any> {
const payload = { return gridApi.updateSummonUncap(
id: gridSummonId, gridSummonId,
uncapLevel, uncapLevel,
transcendenceLevel transcendenceStep,
}
// Set uncap to 6 when transcending
if (transcendenceLevel > 0 && uncapLevel < 6) {
payload.uncapLevel = 6
}
return partiesApi.updateSummonGrid(
this.fetch,
partyId,
payload,
this.buildHeaders(editKey) this.buildHeaders(editKey)
) )
} }
@ -413,24 +390,15 @@ export class GridService {
} }
async updateCharacterUncap( async updateCharacterUncap(
partyId: string,
gridCharacterId: string, gridCharacterId: string,
uncapLevel: number, uncapLevel?: number,
transcendenceLevel: number, transcendenceStep?: number,
perpetuity: boolean,
editKey?: string editKey?: string
): Promise<Party> { ): Promise<any> {
const payload = { return gridApi.updateCharacterUncap(
id: gridCharacterId, gridCharacterId,
uncapLevel, uncapLevel,
transcendenceLevel, transcendenceStep,
perpetuity
}
return partiesApi.updateCharacterGrid(
this.fetch,
partyId,
payload,
this.buildHeaders(editKey) this.buildHeaders(editKey)
) )
} }