add quest_id support and lobby/background images for raids

- add quest_id to types and forms
- add lobby and background images to detail page
- update adapter for new image sizes
This commit is contained in:
Justin Edmund 2026-01-06 03:52:40 -08:00
parent 96db589dea
commit b2559f5f39
6 changed files with 64 additions and 10 deletions

View file

@ -109,12 +109,12 @@ export class RaidAdapter extends BaseAdapter {
* Downloads a single image for a raid (synchronous)
* Requires editor role (>= 7)
* @param slug - Raid slug
* @param size - Image size variant ('icon' or 'thumbnail')
* @param size - Image size variant ('icon', 'thumbnail', 'lobby', or 'background')
* @param force - Force re-download even if image exists
*/
async downloadRaidImage(
slug: string,
size: 'icon' | 'thumbnail',
size: 'icon' | 'thumbnail' | 'lobby' | 'background',
force?: boolean,
options?: RequestOptions
): Promise<{ success: boolean; error?: string }> {
@ -131,7 +131,7 @@ export class RaidAdapter extends BaseAdapter {
*/
async downloadRaidImages(
slug: string,
downloadOptions?: { force?: boolean; size?: 'all' | 'icon' | 'thumbnail' },
downloadOptions?: { force?: boolean; size?: 'all' | 'icon' | 'thumbnail' | 'lobby' | 'background' },
requestOptions?: RequestOptions
): Promise<{ status: string; raidId: string; message: string }> {
return this.request(`/raids/${slug}/download_images`, {

View file

@ -222,6 +222,7 @@ export interface Raid {
element: number
enemy_id?: number
summon_id?: number
quest_id?: number
group?: RaidGroup
}

View file

@ -18,6 +18,7 @@ export interface RaidFull {
element: number
enemy_id?: number
summon_id?: number
quest_id?: number
group?: RaidGroupFlat
}
@ -49,6 +50,7 @@ export interface CreateRaidInput {
group_id: string
enemy_id?: number
summon_id?: number
quest_id?: number
}
export interface UpdateRaidInput {
@ -60,6 +62,7 @@ export interface UpdateRaidInput {
group_id?: string
enemy_id?: number
summon_id?: number
quest_id?: number
}
// Input types for creating/updating raid groups

View file

@ -18,6 +18,8 @@
// CDN base URLs for raid images
const ICON_BASE_URL = 'https://prd-game-a-granbluefantasy.akamaized.net/assets_en/img/sp/assets/enemy/m'
const THUMBNAIL_BASE_URL = 'https://prd-game-a1-granbluefantasy.akamaized.net/assets_en/img/sp/assets/summon/qm'
const LOBBY_BASE_URL = 'https://prd-game-a1-granbluefantasy.akamaized.net/assets_en/img/sp/quest/assets/lobby'
const BACKGROUND_BASE_URL = 'https://prd-game-a-granbluefantasy.akamaized.net/assets_en/img/sp/quest/assets/treasureraid'
function displayName(input: any): string {
if (!input) return '—'
@ -85,6 +87,16 @@
return `${THUMBNAIL_BASE_URL}/${summonId}_high.png`
}
// Get lobby image URL (quest_id with "1" appended)
function getLobbyUrl(questId: number): string {
return `${LOBBY_BASE_URL}/${questId}1.png`
}
// Get background image URL
function getBackgroundUrl(questId: number): string {
return `${BACKGROUND_BASE_URL}/${questId}/raid_image_new.png`
}
// Get header image - prefer thumbnail, fallback to icon
const headerImage = $derived.by(() => {
if (raid?.summon_id) return getThumbnailUrl(raid.summon_id)
@ -97,6 +109,10 @@
const sizes: string[] = []
if (raid?.enemy_id) sizes.push('icon')
if (raid?.summon_id) sizes.push('thumbnail')
if (raid?.quest_id) {
sizes.push('lobby')
sizes.push('background')
}
return sizes
})
@ -124,17 +140,33 @@
})
}
// Lobby and background images from quest
if (raid.quest_id) {
images.push({
url: getLobbyUrl(raid.quest_id),
label: 'Lobby',
variant: 'lobby'
})
images.push({
url: getBackgroundUrl(raid.quest_id),
label: 'Background',
variant: 'background'
})
}
return images
})
// Image download handlers
type RaidImageSize = 'icon' | 'thumbnail' | 'lobby' | 'background'
async function handleDownloadImage(
size: string,
_transformation: string | undefined,
force: boolean
) {
if (!raidSlug) return
await raidAdapter.downloadRaidImage(raidSlug, size as 'icon' | 'thumbnail', force)
await raidAdapter.downloadRaidImage(raidSlug, size as RaidImageSize, force)
}
async function handleDownloadAllImages(force: boolean) {
@ -144,7 +176,7 @@
async function handleDownloadSize(size: string) {
if (!raidSlug) return
await raidAdapter.downloadRaidImage(raidSlug, size as 'icon' | 'thumbnail', false)
await raidAdapter.downloadRaidImage(raidSlug, size as RaidImageSize, false)
}
</script>
@ -188,6 +220,7 @@
<DetailItem label="Level" value={raid.level?.toString() ?? '-'} />
<DetailItem label="Enemy ID" value={raid.enemy_id?.toString() ?? '-'} />
<DetailItem label="Summon ID" value={raid.summon_id?.toString() ?? '-'} />
<DetailItem label="Quest ID" value={raid.quest_id?.toString() ?? '-'} />
<DetailItem label="Element">
{#if raid.element !== undefined && raid.element !== null}
<ElementBadge element={raid.element} />

View file

@ -59,7 +59,8 @@
element: 0,
group_id: '',
enemy_id: undefined as number | undefined,
summon_id: undefined as number | undefined
summon_id: undefined as number | undefined,
quest_id: undefined as number | undefined
})
// Sync edit data when raid changes
@ -73,7 +74,8 @@
element: raid.element ?? 0,
group_id: raid.group?.id || '',
enemy_id: raid.enemy_id,
summon_id: raid.summon_id
summon_id: raid.summon_id,
quest_id: raid.quest_id
}
}
})
@ -118,7 +120,8 @@
element: editData.element,
group_id: editData.group_id,
enemy_id: editData.enemy_id,
summon_id: editData.summon_id
summon_id: editData.summon_id,
quest_id: editData.quest_id
})
// Invalidate queries
@ -201,6 +204,12 @@
editable={true}
type="number"
/>
<DetailItem
label="Quest ID"
bind:value={editData.quest_id}
editable={true}
type="number"
/>
<DetailItem
label="Element"
bind:value={editData.element}

View file

@ -46,7 +46,8 @@
element: 0,
group_id: '',
enemy_id: undefined as number | undefined,
summon_id: undefined as number | undefined
summon_id: undefined as number | undefined,
quest_id: undefined as number | undefined
})
// Element options
@ -89,7 +90,8 @@
element: editData.element,
group_id: editData.group_id,
enemy_id: editData.enemy_id,
summon_id: editData.summon_id
summon_id: editData.summon_id,
quest_id: editData.quest_id
})
// Invalidate queries
@ -167,6 +169,12 @@
editable={true}
type="number"
/>
<DetailItem
label="Quest ID"
bind:value={editData.quest_id}
editable={true}
type="number"
/>
<DetailItem
label="Element"
bind:value={editData.element}