From 0891c0aba1c90a20329e10de7346e8ae9c999212 Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 26 Oct 2026 12:31:26 -0700 Subject: [PATCH 1/8] Fix some weirdness with profession recipe previous ranks not showing as collected --- apps/frontend/shared/stores/data/static/types.ts | 10 ++++++++++ apps/frontend/types/character/character.svelte.ts | 9 +++++++++ apps/frontend/types/character/profession.svelte.ts | 1 + 3 files changed, 20 insertions(+) diff --git a/apps/frontend/shared/stores/data/static/types.ts b/apps/frontend/shared/stores/data/static/types.ts index c11f4e80f..babdb48f0 100644 --- a/apps/frontend/shared/stores/data/static/types.ts +++ b/apps/frontend/shared/stores/data/static/types.ts @@ -158,6 +158,7 @@ export class DataStatic { public professionAbilityByAbilityId = new Map(); public professionAbilityByItemId = new Map(); public professionAbilityBySpellId = new Map(); + public professionAbilityPreviousRank = new Map(); public professionBySkillLineId = new Map(); public professionBySlug = new Map(); public requiredProfessionByItemId = new Map(); @@ -238,6 +239,7 @@ export class DataStatic { ) ); + let previousAbility: [number, number] = [ability.id, ability.spellId]; for (const [extraAbilityId, extraSpellId] of ability.extraRanks || []) { const extraItemId = spellToItem[extraSpellId]; if (extraItemId) { @@ -251,6 +253,9 @@ export class DataStatic { extraSpellId ) ); + + this.professionAbilityPreviousRank.set(extraAbilityId, previousAbility); + previousAbility = [extraAbilityId, extraSpellId]; } } } @@ -262,6 +267,11 @@ export class DataStatic { for (const itemId of abililtyInfo.itemIds || []) { this.professionAbilityByItemId.set(itemId, abililtyInfo); } + + for (const [extraAbilityId, extraSpellId] of abililtyInfo.ability?.extraRanks || []) { + this.professionAbilityByAbilityId.set(extraAbilityId, abililtyInfo); + this.professionAbilityBySpellId.set(extraSpellId, abililtyInfo); + } } for (const childCategory of category?.children || []) { diff --git a/apps/frontend/types/character/character.svelte.ts b/apps/frontend/types/character/character.svelte.ts index 813a5b49d..0152a0d01 100644 --- a/apps/frontend/types/character/character.svelte.ts +++ b/apps/frontend/types/character/character.svelte.ts @@ -673,6 +673,15 @@ export class Character implements ContainsItems, HasNameAndRealm { for (const profession of Object.values(this.professions)) { for (const abilityId of profession.knownRecipes) { allKnown.add(abilityId); + + let previousAbility: [number, number]; + while ( + (previousAbility = wowthingData.static.professionAbilityPreviousRank.get( + previousAbility?.[0] || abilityId + )) + ) { + allKnown.add(previousAbility[0]); + } } } return allKnown; diff --git a/apps/frontend/types/character/profession.svelte.ts b/apps/frontend/types/character/profession.svelte.ts index 4bfe518a8..dadce23be 100644 --- a/apps/frontend/types/character/profession.svelte.ts +++ b/apps/frontend/types/character/profession.svelte.ts @@ -72,6 +72,7 @@ export class CharacterProfession { syncSet(subProfession.knownRecipes, subKnownRecipes); } + syncSet(this.knownRecipes, allKnownRecipes); } From af37dcf704891be3768264b625b1af5743d3136b Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 26 Oct 2026 12:32:41 -0700 Subject: [PATCH 2/8] Remove an unused type --- apps/frontend/types/character-race.ts | 14 -------------- apps/frontend/types/index.ts | 1 - 2 files changed, 15 deletions(-) delete mode 100644 apps/frontend/types/character-race.ts diff --git a/apps/frontend/types/character-race.ts b/apps/frontend/types/character-race.ts deleted file mode 100644 index ba66d0c6b..000000000 --- a/apps/frontend/types/character-race.ts +++ /dev/null @@ -1,14 +0,0 @@ -export class CharacterRace { - id: number; - name: string; - // female, male - icons: string[]; - - constructor(id: number, name: string) { - this.id = id; - this.name = name; - - const safeName = name.toLowerCase().replace(/ /g, '_').replace(/'/g, ''); - this.icons = [`race_${safeName}_female`, `race_${safeName}_male`]; - } -} diff --git a/apps/frontend/types/index.ts b/apps/frontend/types/index.ts index 4e281e036..1ead901c3 100644 --- a/apps/frontend/types/index.ts +++ b/apps/frontend/types/index.ts @@ -1,7 +1,6 @@ export * from './account'; export * from './achievement-data'; export * from './background-image'; -export * from './character-race'; export * from './covenant'; export * from './difficulty-data'; export * from './dungeon'; From 1092d2442105df946c7097f70b34bb0c37c730a9 Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 26 Oct 2026 12:32:52 -0700 Subject: [PATCH 3/8] Use GarrisonType enum --- apps/frontend/utils/get-progress.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/frontend/utils/get-progress.ts b/apps/frontend/utils/get-progress.ts index 1b73cb728..16832c222 100644 --- a/apps/frontend/utils/get-progress.ts +++ b/apps/frontend/utils/get-progress.ts @@ -3,6 +3,7 @@ import find from 'lodash/find'; import { covenantFeatureOrder, covenantMap } from '@/data/covenant'; import { factionIdMap } from '@/data/faction'; import { garrisonBuildingIcon, garrisonTrees, garrisonUnlockQuests } from '@/data/garrison'; +import { GarrisonType } from '@/enums/garrison-type'; import { ProgressDataType } from '@/enums/progress-data-type'; import { QuestStatus } from '@/enums/quest-status'; import { wowthingData } from '@/shared/stores/data'; @@ -56,7 +57,7 @@ export default function getProgress( let skipRequiredQuests = false; if (category.name === 'Garrisons' && group.name === 'Pet Quest') { - const garrison = character.garrisons?.[2]; + const garrison = character.garrisons?.[GarrisonType.WarlordsOfDraenor]; if (garrison?.level === 3) { skipRequiredQuests = true; } @@ -479,7 +480,8 @@ export default function getProgress( } case ProgressDataType.WodGarrison: { - const garrison = character.garrisons?.[2]; + const garrison = character.garrisons?.[GarrisonType.WarlordsOfDraenor]; + if (character.name === 'Momokan') console.log(garrison); // Garrison level if (data.value === undefined) { @@ -490,6 +492,7 @@ export default function getProgress( if ( checkCharacterQuestIds(character.id, garrisonUnlockQuests) ) { + have = 1; total = 3; } else { have = -1; From ab98f07badd962b8f5a4c73617b368e5e0b13bba Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 26 Oct 2026 12:33:00 -0700 Subject: [PATCH 4/8] Calculate gender once for RaceIcon --- apps/frontend/shared/components/images/RaceIcon.svelte | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/frontend/shared/components/images/RaceIcon.svelte b/apps/frontend/shared/components/images/RaceIcon.svelte index a5697c796..17af86d53 100644 --- a/apps/frontend/shared/components/images/RaceIcon.svelte +++ b/apps/frontend/shared/components/images/RaceIcon.svelte @@ -27,9 +27,10 @@ let race = $derived( characterRace || wowthingData.static.characterRaceById.get(character?.raceId || raceId) ); + let derivedGender = $derived(character?.gender || gender || 0); let tooltip = $derived( - `${Gender[character?.gender || gender]} ${getGenderedName(race?.name ?? 'Unknown', character?.gender ?? 0)}` + `${Gender[derivedGender]} ${getGenderedName(race?.name ?? 'Unknown', derivedGender)}` ); - + From c5c50743d9cb119e425941758ede8fd2e244e776 Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 26 Oct 2026 12:34:19 -0700 Subject: [PATCH 5/8] Add minisearch JS dependency --- apps/frontend/package-lock.json | 7 +++++++ apps/frontend/package.json | 1 + 2 files changed, 8 insertions(+) diff --git a/apps/frontend/package-lock.json b/apps/frontend/package-lock.json index c35a9ad01..28b2214d8 100644 --- a/apps/frontend/package-lock.json +++ b/apps/frontend/package-lock.json @@ -15,6 +15,7 @@ "chart.js": "^4.5.1", "chartjs-adapter-luxon": "^1.3.1", "luxon": "^3.7.2", + "minisearch": "^7.2.0", "tippy.js": "^6.3.7" }, "devDependencies": { @@ -2926,6 +2927,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "license": "MIT" + }, "node_modules/mlly": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 8388ab5df..5c5945d75 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -20,6 +20,7 @@ "chart.js": "^4.5.1", "chartjs-adapter-luxon": "^1.3.1", "luxon": "^3.7.2", + "minisearch": "^7.2.0", "tippy.js": "^6.3.7" }, "devDependencies": { From ce72561a138abc13c179b537c9bc380e1d821c75 Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 26 Oct 2026 12:44:39 -0700 Subject: [PATCH 6/8] Only include guilds with characters in them in user data --- apps/web/Controllers/ApiController.cs | 43 ++++++++++++++++----------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/apps/web/Controllers/ApiController.cs b/apps/web/Controllers/ApiController.cs index 96332411d..53fc96f9c 100644 --- a/apps/web/Controllers/ApiController.cs +++ b/apps/web/Controllers/ApiController.cs @@ -208,6 +208,7 @@ await _context.Users timer.AddPoint("Accounts"); + // Warbank PlayerWarbankItem[] warbankItems = []; if (!apiResult.Public) { @@ -218,23 +219,7 @@ await _context.Users timer.AddPoint("Warbank"); - var guilds = await _context.PlayerGuild - .Where(pg => pg.UserId == apiResult.User.Id) - .ToArrayAsync(); - - Dictionary guildItemsMap = new(); - if (!apiResult.Public) - { - int[] guildIds = guilds.Select(g => g.Id).ToArray(); - var guildItems = await _context.PlayerGuildItem - .Where(pgi => guildIds.Contains(pgi.GuildId)) - .ToArrayAsync(); - guildItemsMap = guildItems - .ToGroupedDictionary(pgi => pgi.GuildId); - } - - timer.AddPoint("Guilds"); - + // Characters var characterQuery = _context.PlayerCharacter .Where(c => c.Account.UserId == apiResult.User.Id) .Where(c => c.ClassId > 0 && c.RaceId > 0 && c.Level > 0); @@ -284,8 +269,32 @@ await _context.Users .Select(character => character.Id) .ToArray(); + var guildIds = characters + .Where(character => character.GuildId != null) + .Select(character => character.GuildId) + .Distinct() + .ToArray(); + timer.AddPoint("Characters"); + // Guilds + var guilds = await _context.PlayerGuild + .Where(pg => pg.UserId == apiResult.User.Id && + guildIds.Contains(pg.Id)) + .ToArrayAsync(); + + Dictionary guildItemsMap = new(); + if (!apiResult.Public) + { + var guildItems = await _context.PlayerGuildItem + .Where(pgi => guildIds.Contains(pgi.GuildId)) + .ToArrayAsync(); + guildItemsMap = guildItems + .ToGroupedDictionary(pgi => pgi.GuildId); + } + + timer.AddPoint("Guilds"); + var itemQuery = _context.PlayerCharacterItem .AsNoTracking() .Where(pci => characterIds.Contains(pci.CharacterId)); From 7f414cca14c4b8e31461de6cab229fd74e004d88 Mon Sep 17 00:00:00 2001 From: Freddie Date: Tue, 27 Oct 2026 11:10:19 -0700 Subject: [PATCH 7/8] Rework CraftedQualityIcon and use new images --- apps/frontend/scss/global.scss | 1 + apps/frontend/scss/images.scss | 13 +++++++ .../images/CraftedQualityIcon.svelte | 35 ++++++++++--------- .../images/sources/WowthingImage.svelte | 27 +++++++------- apps/frontend/types/props.ts | 7 ++++ 5 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 apps/frontend/scss/images.scss diff --git a/apps/frontend/scss/global.scss b/apps/frontend/scss/global.scss index b82c3d580..77da7a51b 100644 --- a/apps/frontend/scss/global.scss +++ b/apps/frontend/scss/global.scss @@ -10,6 +10,7 @@ @import "error"; @import "forms"; @import "hacks"; +@import "images"; @import "landing-page"; @import "options"; @import "reputation"; diff --git a/apps/frontend/scss/images.scss b/apps/frontend/scss/images.scss new file mode 100644 index 000000000..720fda4a6 --- /dev/null +++ b/apps/frontend/scss/images.scss @@ -0,0 +1,13 @@ +.crafting-quality-2, +.crafting-quality-13 { + scale: 1.3; +} +.crafting-quality-4 { + scale: 0.8; +} +.crafting-quality-5 { + scale: 0.7; +} +.crafting-quality-14 { + scale: 1.1; +} diff --git a/apps/frontend/shared/components/images/CraftedQualityIcon.svelte b/apps/frontend/shared/components/images/CraftedQualityIcon.svelte index 9a338bff8..b3fdfaf1f 100644 --- a/apps/frontend/shared/components/images/CraftedQualityIcon.svelte +++ b/apps/frontend/shared/components/images/CraftedQualityIcon.svelte @@ -1,29 +1,32 @@ {#if quality > 0} - Crafted Quality {quality} {/if} diff --git a/apps/frontend/shared/components/images/sources/WowthingImage.svelte b/apps/frontend/shared/components/images/sources/WowthingImage.svelte index e47cf07e3..c3b2684e3 100644 --- a/apps/frontend/shared/components/images/sources/WowthingImage.svelte +++ b/apps/frontend/shared/components/images/sources/WowthingImage.svelte @@ -1,26 +1,23 @@ {name} number; setSortState: (prefix?: string) => void; }; + +export type ImageProps = { + size: number; + border?: number; + cls?: string; + tooltip?: string; +}; From 622d09a6ad8cb965a5a5e2949aaf0fdd199f9755 Mon Sep 17 00:00:00 2001 From: Freddie Date: Tue, 27 Oct 2026 11:21:23 -0700 Subject: [PATCH 8/8] Fix CraftedQualityIcon props typing --- .../shared/components/images/CraftedQualityIcon.svelte | 7 ++++--- apps/frontend/types/utility.ts | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 apps/frontend/types/utility.ts diff --git a/apps/frontend/shared/components/images/CraftedQualityIcon.svelte b/apps/frontend/shared/components/images/CraftedQualityIcon.svelte index b3fdfaf1f..c761024a8 100644 --- a/apps/frontend/shared/components/images/CraftedQualityIcon.svelte +++ b/apps/frontend/shared/components/images/CraftedQualityIcon.svelte @@ -1,10 +1,11 @@