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

@ -281,4 +281,98 @@ export async function removeCharacter(
if (!res.ok) {
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') {
initiateTouchDrag(e, item, source, type)
} 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)
)
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)
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() {
@ -135,6 +148,7 @@ export function createDragDropContext(handlers: DragDropHandlers = {}) {
state.touchState.longPressTimer = null
}
state.touchState.touchStartPos = null
state.touchState.currentTouch = null
}
function startDrag(item: GridItem, source: DragSource) {

View file

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