add grid api endpoints and services

This commit is contained in:
Justin Edmund 2025-09-15 21:24:37 -07:00
parent 4030b19e9e
commit da4c3d09f9
9 changed files with 402 additions and 19 deletions

View file

@ -243,7 +243,11 @@ export class APIClient {
throw new Error(error.error || `Failed to update party: ${response.statusText}`) throw new Error(error.error || `Failed to update party: ${response.statusText}`)
} }
return response.json() const data = await response.json()
// The API returns { party: { ... } }, extract the party object
const party = data.party || data
// Transform the response to match our clean types
return transformResponse(party)
} }
/** /**
@ -298,12 +302,46 @@ export class APIClient {
return response.json() return response.json()
} }
/**
* Update a weapon in a party
*/
async updateWeapon(
partyId: string,
gridWeaponId: string,
updates: {
position?: number
uncapLevel?: number
transcendenceStep?: number
element?: number
}
): Promise<any> {
const editKey = this.getEditKey(partyId)
const response = await fetch(`/api/parties/${partyId}/weapons/${gridWeaponId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {})
},
body: JSON.stringify(updates)
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || `Failed to update weapon: ${response.statusText}`)
}
return response.json()
}
/** /**
* Remove a weapon from a party * Remove a weapon from a party
*/ */
async removeWeapon(partyId: string, gridWeaponId: string): Promise<void> { async removeWeapon(partyId: string, gridWeaponId: string): Promise<void> {
const editKey = this.getEditKey(partyId) const editKey = this.getEditKey(partyId)
console.log('Removing weapon:', { partyId, gridWeaponId, editKey })
const response = await fetch(`/api/parties/${partyId}/weapons`, { const response = await fetch(`/api/parties/${partyId}/weapons`, {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
@ -314,7 +352,16 @@ export class APIClient {
}) })
if (!response.ok) { if (!response.ok) {
const error = await response.json() console.error('Remove weapon failed:', response.status, response.statusText)
// Try to get the response text to see what the server is returning
const text = await response.text()
console.error('Response body:', text)
let error = { error: 'Failed to remove weapon' }
try {
error = JSON.parse(text)
} catch (e) {
// Not JSON, use the text as is
}
throw new Error(error.error || `Failed to remove weapon: ${response.statusText}`) throw new Error(error.error || `Failed to remove weapon: ${response.statusText}`)
} }
} }
@ -351,6 +398,38 @@ export class APIClient {
return response.json() return response.json()
} }
/**
* Update a summon in a party
*/
async updateSummon(
partyId: string,
gridSummonId: string,
updates: {
position?: number
quickSummon?: boolean
uncapLevel?: number
transcendenceStep?: number
}
): Promise<any> {
const editKey = this.getEditKey(partyId)
const response = await fetch(`/api/parties/${partyId}/summons/${gridSummonId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {})
},
body: JSON.stringify(updates)
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || `Failed to update summon: ${response.statusText}`)
}
return response.json()
}
/** /**
* Remove a summon from a party * Remove a summon from a party
*/ */
@ -367,7 +446,7 @@ export class APIClient {
}) })
if (!response.ok) { if (!response.ok) {
const error = await response.json() const error = await response.json().catch(() => ({ error: 'Failed to remove summon' }))
throw new Error(error.error || `Failed to remove summon: ${response.statusText}`) throw new Error(error.error || `Failed to remove summon: ${response.statusText}`)
} }
} }
@ -404,6 +483,38 @@ export class APIClient {
return response.json() return response.json()
} }
/**
* Update a character in a party
*/
async updateCharacter(
partyId: string,
gridCharacterId: string,
updates: {
position?: number
uncapLevel?: number
transcendenceStep?: number
perpetuity?: boolean
}
): Promise<any> {
const editKey = this.getEditKey(partyId)
const response = await fetch(`/api/parties/${partyId}/characters/${gridCharacterId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {})
},
body: JSON.stringify(updates)
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || `Failed to update character: ${response.statusText}`)
}
return response.json()
}
/** /**
* Remove a character from a party * Remove a character from a party
*/ */
@ -420,7 +531,7 @@ export class APIClient {
}) })
if (!response.ok) { if (!response.ok) {
const error = await response.json() const error = await response.json().catch(() => ({ error: 'Failed to remove character' }))
throw new Error(error.error || `Failed to remove character: ${response.statusText}`) throw new Error(error.error || `Failed to remove character: ${response.statusText}`)
} }
} }

View file

@ -47,6 +47,35 @@ export async function addWeapon(
return res.json() return res.json()
} }
export async function updateWeapon(
fetch: FetchLike,
partyId: string,
gridWeaponId: string,
updates: {
position?: number
uncapLevel?: number
transcendenceStep?: number
element?: number
},
headers?: Record<string, string>
): Promise<any> {
const res = await fetch(buildUrl(`/grid_weapons/${gridWeaponId}`), {
method: 'PUT',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...headers
},
body: JSON.stringify({ weapon: updates })
})
if (!res.ok) {
throw new Error(`Failed to update weapon: ${res.statusText}`)
}
return res.json()
}
export async function removeWeapon( export async function removeWeapon(
fetch: FetchLike, fetch: FetchLike,
partyId: string, partyId: string,
@ -113,6 +142,35 @@ export async function addSummon(
return res.json() return res.json()
} }
export async function updateSummon(
fetch: FetchLike,
partyId: string,
gridSummonId: string,
updates: {
position?: number
quickSummon?: boolean
uncapLevel?: number
transcendenceStep?: number
},
headers?: Record<string, string>
): Promise<any> {
const res = await fetch(buildUrl(`/grid_summons/${gridSummonId}`), {
method: 'PUT',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...headers
},
body: JSON.stringify({ summon: updates })
})
if (!res.ok) {
throw new Error(`Failed to update summon: ${res.statusText}`)
}
return res.json()
}
export async function removeSummon( export async function removeSummon(
fetch: FetchLike, fetch: FetchLike,
partyId: string, partyId: string,
@ -175,6 +233,35 @@ export async function addCharacter(
return res.json() return res.json()
} }
export async function updateCharacter(
fetch: FetchLike,
partyId: string,
gridCharacterId: string,
updates: {
position?: number
uncapLevel?: number
transcendenceStep?: number
perpetuity?: boolean
},
headers?: Record<string, string>
): Promise<any> {
const res = await fetch(buildUrl(`/grid_characters/${gridCharacterId}`), {
method: 'PUT',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...headers
},
body: JSON.stringify({ character: updates })
})
if (!res.ok) {
throw new Error(`Failed to update character: ${res.statusText}`)
}
return res.json()
}
export async function removeCharacter( export async function removeCharacter(
fetch: FetchLike, fetch: FetchLike,
partyId: string, partyId: string,

View file

@ -109,6 +109,30 @@ export class GridService {
) )
} }
async updateWeapon(
partyId: string,
gridWeaponId: string,
updates: {
position?: number
uncapLevel?: number
transcendenceStep?: number
element?: number
},
editKey?: string
): Promise<Party> {
const payload = {
id: gridWeaponId,
...updates
}
return partiesApi.updateWeaponGrid(
this.fetch,
partyId,
payload,
this.buildHeaders(editKey)
)
}
async moveWeapon( async moveWeapon(
partyId: string, partyId: string,
gridWeaponId: string, gridWeaponId: string,
@ -119,7 +143,7 @@ export class GridService {
id: gridWeaponId, id: gridWeaponId,
position: newPosition position: newPosition
} }
return partiesApi.updateWeaponGrid( return partiesApi.updateWeaponGrid(
this.fetch, this.fetch,
partyId, partyId,
@ -223,7 +247,31 @@ export class GridService {
id: gridSummonId, id: gridSummonId,
_destroy: true _destroy: true
} }
return partiesApi.updateSummonGrid(
this.fetch,
partyId,
payload,
this.buildHeaders(editKey)
)
}
async updateSummon(
partyId: string,
gridSummonId: string,
updates: {
position?: number
quickSummon?: boolean
uncapLevel?: number
transcendenceStep?: number
},
editKey?: string
): Promise<Party> {
const payload = {
id: gridSummonId,
...updates
}
return partiesApi.updateSummonGrid( return partiesApi.updateSummonGrid(
this.fetch, this.fetch,
partyId, partyId,
@ -331,7 +379,31 @@ export class GridService {
id: gridCharacterId, id: gridCharacterId,
_destroy: true _destroy: true
} }
return partiesApi.updateCharacterGrid(
this.fetch,
partyId,
payload,
this.buildHeaders(editKey)
)
}
async updateCharacter(
partyId: string,
gridCharacterId: string,
updates: {
position?: number
uncapLevel?: number
transcendenceStep?: number
perpetuity?: boolean
},
editKey?: string
): Promise<Party> {
const payload = {
id: gridCharacterId,
...updates
}
return partiesApi.updateCharacterGrid( return partiesApi.updateCharacterGrid(
this.fetch, this.fetch,
partyId, partyId,

View file

@ -50,14 +50,13 @@ export const DELETE: RequestHandler = async ({ request, params, fetch }) => {
const body = await request.json() const body = await request.json()
const editKey = request.headers.get('X-Edit-Key') const editKey = request.headers.get('X-Edit-Key')
// Forward to Rails API // Forward to Rails API - use grid_characters endpoint with the ID
const response = await fetch(buildUrl('/characters'), { const response = await fetch(buildUrl(`/grid_characters/${body.gridCharacterId}`), {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {}) ...(editKey ? { 'X-Edit-Key': editKey } : {})
}, }
body: JSON.stringify({ grid_character_id: body.gridCharacterId })
}) })
if (response.ok) { if (response.ok) {

View file

@ -0,0 +1,38 @@
import { json, type RequestHandler } from '@sveltejs/kit'
import { buildUrl } from '$lib/api/core'
/**
* PUT /api/parties/[id]/characters/[characterId] - Update character in party
* Proxies to Rails API with proper authentication
*/
export const PUT: RequestHandler = async ({ request, params, fetch }) => {
try {
const body = await request.json()
const editKey = request.headers.get('X-Edit-Key')
// Transform to Rails API format
const railsBody = {
character: body
}
// Forward to Rails API
const response = await fetch(buildUrl(`/grid_characters/${params.characterId}`), {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {})
},
body: JSON.stringify(railsBody)
})
const data = await response.json()
return json(data, { status: response.status })
} catch (error) {
console.error('Error updating character:', error)
return json(
{ error: 'Failed to update character' },
{ status: 500 }
)
}
}

View file

@ -52,14 +52,13 @@ export const DELETE: RequestHandler = async ({ request, params, fetch }) => {
const body = await request.json() const body = await request.json()
const editKey = request.headers.get('X-Edit-Key') const editKey = request.headers.get('X-Edit-Key')
// Forward to Rails API // Forward to Rails API - use grid_summons endpoint with the ID
const response = await fetch(buildUrl('/summons'), { const response = await fetch(buildUrl(`/grid_summons/${body.gridSummonId}`), {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {}) ...(editKey ? { 'X-Edit-Key': editKey } : {})
}, }
body: JSON.stringify({ grid_summon_id: body.gridSummonId })
}) })
if (response.ok) { if (response.ok) {

View file

@ -0,0 +1,38 @@
import { json, type RequestHandler } from '@sveltejs/kit'
import { buildUrl } from '$lib/api/core'
/**
* PUT /api/parties/[id]/summons/[summonId] - Update summon in party
* Proxies to Rails API with proper authentication
*/
export const PUT: RequestHandler = async ({ request, params, fetch }) => {
try {
const body = await request.json()
const editKey = request.headers.get('X-Edit-Key')
// Transform to Rails API format
const railsBody = {
summon: body
}
// Forward to Rails API
const response = await fetch(buildUrl(`/grid_summons/${params.summonId}`), {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {})
},
body: JSON.stringify(railsBody)
})
const data = await response.json()
return json(data, { status: response.status })
} catch (error) {
console.error('Error updating summon:', error)
return json(
{ error: 'Failed to update summon' },
{ status: 500 }
)
}
}

View file

@ -51,14 +51,15 @@ export const DELETE: RequestHandler = async ({ request, params, fetch }) => {
const body = await request.json() const body = await request.json()
const editKey = request.headers.get('X-Edit-Key') const editKey = request.headers.get('X-Edit-Key')
// Forward to Rails API console.log('DELETE weapon request:', { body, params })
const response = await fetch(buildUrl('/weapons'), {
// Forward to Rails API - use grid_weapons endpoint with the ID
const response = await fetch(buildUrl(`/grid_weapons/${body.gridWeaponId}`), {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {}) ...(editKey ? { 'X-Edit-Key': editKey } : {})
}, }
body: JSON.stringify({ grid_weapon_id: body.gridWeaponId })
}) })
if (response.ok) { if (response.ok) {

View file

@ -0,0 +1,38 @@
import { json, type RequestHandler } from '@sveltejs/kit'
import { buildUrl } from '$lib/api/core'
/**
* PUT /api/parties/[id]/weapons/[weaponId] - Update weapon in party
* Proxies to Rails API with proper authentication
*/
export const PUT: RequestHandler = async ({ request, params, fetch }) => {
try {
const body = await request.json()
const editKey = request.headers.get('X-Edit-Key')
// Transform to Rails API format
const railsBody = {
weapon: body
}
// Forward to Rails API
const response = await fetch(buildUrl(`/grid_weapons/${params.weaponId}`), {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
...(editKey ? { 'X-Edit-Key': editKey } : {})
},
body: JSON.stringify(railsBody)
})
const data = await response.json()
return json(data, { status: response.status })
} catch (error) {
console.error('Error updating weapon:', error)
return json(
{ error: 'Failed to update weapon' },
{ status: 500 }
)
}
}