Skip to content

Commit 15d5e11

Browse files
committed
refactor(discord-bot): replace static item ID map with Teamcraft tw-items.json lookup
- add `findItemId` method to `teamcraftApp` using cached `_nameToId` map - update `itemCommand` to use `teamcraftApp.findItemId` instead of static `itemId` map - update `materiaCommand` to use `teamcraftApp.findItemId` with async `Promise.all` collection - update `toUniversalisLink` to accept optional `itemId` param; remove `itemId` import - pass resolved item IDs directly to `toUniversalisLink` at all call sites - guard `data.listings` with `?? []` since field is now typed as optional
1 parent 4e211de commit 15d5e11

4 files changed

Lines changed: 37 additions & 27 deletions

File tree

@apps/discord-bot/src/(features)/commands/itemCommand.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
type ChatInputCommandInteraction,
44
SlashCommandBuilder,
55
} from 'discord.js'
6-
import { itemId } from '~/(constants)/itemId'
76
import { calcWeightedAvgPrice } from '~/(features)/commands/calcWeightedAvgPrice'
87
import { toUniversalisLink } from '~/(features)/markdown/toUniversalisLink'
98
import { teamcraftApp } from '~/(services)/teamcraft/teamcraftApp'
@@ -64,13 +63,14 @@ export const itemCommand = {
6463
.trim()
6564
.replaceAll('', '')
6665

67-
const targetItemId = itemId.get(itemName) || null
68-
6966
const result = await interaction.reply(`🔍1️⃣ 搜尋物品與配方...`)
7067

7168
/** 目標物品的生產配方 */
7269
const targetRecipe = await teamcraftApp.searchRecipes(itemName)
7370

71+
/** 目標物品的 Universalis item ID(由 Teamcraft tw-items.json 查詢) */
72+
const targetItemId = await teamcraftApp.findItemId(itemName)
73+
7474
if (!targetItemId && !targetRecipe) {
7575
await result.edit(`🔍❌ 找不到相關物品與配方: \`${itemName}\``)
7676
return
@@ -95,11 +95,11 @@ export const itemCommand = {
9595
targetItemPricing.nqSaleVelocity = data.nqSaleVelocity
9696
targetItemPricing.hqSaleVelocity = data.hqSaleVelocity
9797
targetItemPricing.nqSalePrice = calcWeightedAvgPrice(
98-
data.listings,
98+
data.listings ?? [],
9999
false,
100100
)
101101
targetItemPricing.hqSalePrice = calcWeightedAvgPrice(
102-
data.listings,
102+
data.listings ?? [],
103103
true,
104104
)
105105
}
@@ -152,6 +152,7 @@ export const itemCommand = {
152152

153153
const materialLink = toUniversalisLink(
154154
materialName ?? '__無資訊__',
155+
matId,
155156
)
156157

157158
if (hqPrice > 0) {
@@ -168,7 +169,7 @@ export const itemCommand = {
168169

169170
await result.edit(
170171
dedent`
171-
## 📦 **${toUniversalisLink(targetRecipe.resultItemName)}**
172+
## 📦 **${toUniversalisLink(targetRecipe.resultItemName, targetRecipe.resultItemId)}**
172173
> ${targetRecipe.jobName}配方(\`rlv ${targetRecipe.rlvl}\`)
173174
174175
### 📊 平均單件售價
@@ -194,7 +195,7 @@ export const itemCommand = {
194195

195196
await result.edit(
196197
dedent`
197-
## 📦 **${toUniversalisLink(itemName)}**
198+
## 📦 **${toUniversalisLink(itemName, targetItemId)}**
198199
> 無配方 - ${googleSearchLink}
199200
200201
### 📊 平均單件售價

@apps/discord-bot/src/(features)/commands/materiaCommand.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
} from 'discord.js'
66
import { chunk, keyBy } from 'lodash-es'
77
import type { z } from 'zod'
8-
import { itemId } from '~/(constants)/itemId'
98
import { toUniversalisLink } from '~/(features)/markdown/toUniversalisLink'
9+
import { teamcraftApp } from '~/(services)/teamcraft/teamcraftApp'
1010
import { universalisApp } from '~/(services)/universalis/universalisApp'
1111
import { universalisTypes } from '~/(services)/universalis/universalisTypes'
1212

@@ -86,19 +86,23 @@ export const materiaCommand = {
8686
const result = await interaction.reply('🔍 查詢所有魔晶石物價ing...')
8787

8888
// 收集所有魔晶石物品(保持排序)
89-
const materiaItems = MATERIA_CONFIG.flatMap((materia) =>
90-
TYPE_NAMES.map((typeName, typeIndex) => {
91-
const fullName = `${materia.name}${typeName}`
92-
const materiaId = itemId.get(fullName)
93-
return {
94-
...materia,
95-
typeName,
96-
typeNumber: typeIndex + 1,
97-
fullName,
98-
id: materiaId,
99-
}
100-
}),
101-
).filter((item) => item.id !== undefined)
89+
const materiaItemsRaw = MATERIA_CONFIG.flatMap((materia) =>
90+
TYPE_NAMES.map((typeName, typeIndex) => ({
91+
...materia,
92+
typeName,
93+
typeNumber: typeIndex + 1,
94+
fullName: `${materia.name}${typeName}`,
95+
})),
96+
)
97+
98+
const materiaItems = (
99+
await Promise.all(
100+
materiaItemsRaw.map(async (item) => ({
101+
...item,
102+
id: await teamcraftApp.findItemId(item.fullName),
103+
})),
104+
)
105+
).filter((item): item is typeof item & { id: number } => item.id !== null)
102106

103107
const allMateriaIds = materiaItems.map((item) => item.id!)
104108

@@ -147,7 +151,7 @@ export const materiaCommand = {
147151
const velocityEmoji = getVelocityEmoji(velocity)
148152

149153
output.push(
150-
`${item.emoji} ${toUniversalisLink(item.fullName)} (${item.typeNumber}${item.attr})` +
154+
`${item.emoji} ${toUniversalisLink(item.fullName, item.id)} (${item.typeNumber}${item.attr})` +
151155
` | ` +
152156
`${velocityEmoji} 銷量市場規模 ${Math.round(velocity).toLocaleString('en-US')}件` +
153157
` x ` +
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
import { itemId } from '~/(constants)/itemId'
21
import { toLink } from '~/(features)/markdown/toLink'
32
import { envVar } from '~/envVar'
43

5-
export function toUniversalisLink(itemName: string) {
6-
const _itemId = itemId.get(itemName) || null
7-
8-
return `${toLink(itemName, `<${envVar.FF14_UNIVERSALIS_SITE_URL}/market/${_itemId}>`)}`
4+
export function toUniversalisLink(itemName: string, itemId?: number | null) {
5+
return `${toLink(itemName, `<${envVar.FF14_UNIVERSALIS_SITE_URL}/market/${itemId ?? null}>`)}`
96
}

@apps/discord-bot/src/(services)/teamcraft/teamcraftApp.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ export const teamcraftApp = {
8484
return _idToName!.get(itemId) ?? null
8585
},
8686

87+
/**
88+
* Returns the FFXIV item ID for a given TW item name, or `null` if not found.
89+
*/
90+
async findItemId(name: string): Promise<number | null> {
91+
await loadTwItems()
92+
return _nameToId!.get(name) ?? null
93+
},
94+
8795
/**
8896
* Returns the TW job name for a given job ID, or `null` if not found.
8997
*

0 commit comments

Comments
 (0)