chore: update dependencies and improve type safety in Enka components
Gitea Auto Deploy / Deploy-Container (push) Successful in 1m2s
Gitea Auto Deploy / Deploy-Container (push) Successful in 1m2s
- Updated @tanstack/react-query to version 5.102.8 - Updated next-intl to version 4.14.2 - Updated zod to version 4.5.4 - Updated baseline-browser-mapping to version 2.11.21 - Updated daisyui to version 5.7.28 - Enhanced type definitions in enka.ts by making several properties optional - Improved data handling in enka.tsx to prevent runtime errors when accessing potentially undefined properties - Added error logging for data validation failures and fetch errors
This commit is contained in:
@@ -39,7 +39,7 @@ const toCharacterInfoCard = (character: AvatarEnkaDetailInput): CharacterInfoCar
|
||||
rank: character.equipment?.rank ?? 0,
|
||||
item_id: character.equipment?.tid ?? 0,
|
||||
},
|
||||
relics: character.relicList.map((relic) => ({
|
||||
relics: (character.relicList ?? []).map((relic) => ({
|
||||
level: relic.level,
|
||||
relic_id: relic.tid,
|
||||
relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10),
|
||||
@@ -84,7 +84,7 @@ export default function EnkaImport() {
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
const validCharacters = enkaData?.detailInfo.avatarDetailList.filter((character) => mapAvatar?.[character.avatarId]) ?? [];
|
||||
const validCharacters = enkaData?.detailInfo?.avatarDetailList?.filter((character) => mapAvatar?.[character.avatarId]) ?? [];
|
||||
|
||||
const handlerFetchData = async () => {
|
||||
const cleanUid = uidInput.trim();
|
||||
@@ -105,6 +105,7 @@ export default function EnkaImport() {
|
||||
const parsed = enkaResponseSchema.safeParse(data);
|
||||
|
||||
if (!parsed.success) {
|
||||
console.error("Enka data validation failed:", parsed.error);
|
||||
setEnkaData(null);
|
||||
setSelectedCharacters([]);
|
||||
setErrorMsg(transI18n("failedToFetchEnkaData"));
|
||||
@@ -112,12 +113,13 @@ export default function EnkaImport() {
|
||||
}
|
||||
|
||||
setEnkaData(parsed.data as EnkaResponse);
|
||||
const validChars = parsed.data.detailInfo.avatarDetailList
|
||||
const validChars = (parsed.data.detailInfo?.avatarDetailList ?? [])
|
||||
.filter((character) => mapAvatar?.[character.avatarId])
|
||||
.map(toCharacterInfoCard);
|
||||
setSelectedCharacters(validChars);
|
||||
setErrorMsg("");
|
||||
} catch {
|
||||
} catch (error) {
|
||||
console.error("Enka fetch failed:", error);
|
||||
setEnkaData(null);
|
||||
setSelectedCharacters([]);
|
||||
setErrorMsg(transI18n("failedToFetchEnkaData"));
|
||||
@@ -167,7 +169,7 @@ export default function EnkaImport() {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterData = parsed.data.detailInfo.avatarDetailList.filter((character) =>
|
||||
const filterData = (parsed.data.detailInfo?.avatarDetailList ?? []).filter((character) =>
|
||||
mapAvatar?.[character.avatarId] && selectedCharacters.some((selected) => selected.avatar_id === character.avatarId)
|
||||
);
|
||||
|
||||
@@ -175,7 +177,7 @@ export default function EnkaImport() {
|
||||
const currentAvatar = listAvatars[character.avatarId.toString()];
|
||||
if (currentAvatar && Object.keys(currentAvatar).length !== 0) {
|
||||
const newProfileList = [...(currentAvatar.profileList || [])];
|
||||
const newProfile = converterOneEnkaDataToAvatarStore(character, newProfileList.length);
|
||||
const newProfile = converterOneEnkaDataToAvatarStore(character as unknown as AvatarEnkaDetailInput, newProfileList.length);
|
||||
if (newProfile) {
|
||||
newProfileList.push(newProfile);
|
||||
}
|
||||
@@ -185,7 +187,7 @@ export default function EnkaImport() {
|
||||
promotion: character.promotion ?? 0,
|
||||
data: {
|
||||
rank: character.rank ?? 0,
|
||||
skills: character.skillTreeList.reduce((acc, skill) => {
|
||||
skills: (character.skillTreeList ?? []).reduce((acc, skill) => {
|
||||
acc[skill.pointId] = skill.level;
|
||||
return acc;
|
||||
}, {} as Record<string, number>),
|
||||
|
||||
+38
-37
@@ -1,20 +1,20 @@
|
||||
interface PrivacySettingInfo {
|
||||
displayCollection: boolean
|
||||
displayRecord: boolean
|
||||
displayRecordTeam: boolean
|
||||
displayOnlineStatus: boolean
|
||||
displayDiary: boolean
|
||||
displayCollection?: boolean
|
||||
displayRecord?: boolean
|
||||
displayRecordTeam?: boolean
|
||||
displayOnlineStatus?: boolean
|
||||
displayDiary?: boolean
|
||||
}
|
||||
|
||||
interface RecordInfo {
|
||||
achievementCount: number
|
||||
bookCount: number
|
||||
avatarCount: number
|
||||
equipmentCount: number
|
||||
musicCount: number
|
||||
relicCount: number
|
||||
challengeInfo: unknown;
|
||||
maxRogueChallengeScore: number
|
||||
achievementCount?: number
|
||||
bookCount?: number
|
||||
avatarCount?: number
|
||||
equipmentCount?: number
|
||||
musicCount?: number
|
||||
relicCount?: number
|
||||
challengeInfo?: unknown
|
||||
maxRogueChallengeScore?: number
|
||||
}
|
||||
|
||||
|
||||
@@ -30,18 +30,18 @@ interface FlatProp {
|
||||
}
|
||||
|
||||
interface RelicFlat {
|
||||
props: FlatProp[]
|
||||
setName: string | number
|
||||
setID: number
|
||||
props?: FlatProp[]
|
||||
setName?: string | number
|
||||
setID?: number
|
||||
}
|
||||
|
||||
interface Relic {
|
||||
mainAffixId: number
|
||||
subAffixList: SubAffix[]
|
||||
subAffixList?: SubAffix[]
|
||||
tid: number
|
||||
type: number
|
||||
level: number
|
||||
_flat: RelicFlat
|
||||
_flat?: RelicFlat
|
||||
}
|
||||
|
||||
interface SkillTree {
|
||||
@@ -50,43 +50,44 @@ interface SkillTree {
|
||||
}
|
||||
|
||||
interface EquipmentFlat {
|
||||
props: FlatProp[]
|
||||
name: string | number
|
||||
props?: FlatProp[]
|
||||
name?: string | number
|
||||
}
|
||||
|
||||
interface Equipment {
|
||||
rank: number
|
||||
rank?: number
|
||||
tid: number
|
||||
promotion: number
|
||||
promotion?: number
|
||||
level: number
|
||||
_flat: EquipmentFlat
|
||||
_flat?: EquipmentFlat
|
||||
}
|
||||
|
||||
export interface AvatarEnkaDetail {
|
||||
relicList: Relic[]
|
||||
relicList?: Relic[]
|
||||
level: number
|
||||
promotion: number
|
||||
promotion?: number
|
||||
rank?: number
|
||||
skillTreeList: SkillTree[]
|
||||
equipment: Equipment
|
||||
skillTreeList?: SkillTree[]
|
||||
equipment?: Equipment
|
||||
avatarId: number
|
||||
_assist?: boolean
|
||||
pos?: number
|
||||
}
|
||||
|
||||
interface DetailInfo {
|
||||
worldLevel: number
|
||||
privacySettingInfo: PrivacySettingInfo
|
||||
headIcon: number
|
||||
signature: string
|
||||
avatarDetailList: AvatarEnkaDetail[]
|
||||
platform: string
|
||||
recordInfo: RecordInfo
|
||||
worldLevel?: number
|
||||
privacySettingInfo?: PrivacySettingInfo
|
||||
headIcon?: number
|
||||
signature?: string
|
||||
avatarDetailList?: AvatarEnkaDetail[]
|
||||
platform?: string
|
||||
recordInfo?: RecordInfo
|
||||
uid: number
|
||||
level: number
|
||||
nickname: string
|
||||
isDisplayAvatar: boolean
|
||||
friendCount: number
|
||||
personalCardId: number
|
||||
isDisplayAvatar?: boolean
|
||||
friendCount?: number
|
||||
personalCardId?: number
|
||||
}
|
||||
|
||||
export interface EnkaResponse {
|
||||
|
||||
+39
-38
@@ -2,22 +2,22 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const privacySettingInfoSchema = z.object({
|
||||
displayCollection: z.boolean(),
|
||||
displayRecord: z.boolean(),
|
||||
displayRecordTeam: z.boolean(),
|
||||
displayOnlineStatus: z.boolean(),
|
||||
displayDiary: z.boolean()
|
||||
displayCollection: z.boolean().optional(),
|
||||
displayRecord: z.boolean().optional(),
|
||||
displayRecordTeam: z.boolean().optional(),
|
||||
displayOnlineStatus: z.boolean().optional(),
|
||||
displayDiary: z.boolean().optional()
|
||||
});
|
||||
|
||||
const recordInfoSchema = z.object({
|
||||
achievementCount: z.number(),
|
||||
bookCount: z.number(),
|
||||
avatarCount: z.number(),
|
||||
equipmentCount: z.number(),
|
||||
musicCount: z.number(),
|
||||
relicCount: z.number(),
|
||||
challengeInfo: z.unknown(),
|
||||
maxRogueChallengeScore: z.number()
|
||||
achievementCount: z.number().optional(),
|
||||
bookCount: z.number().optional(),
|
||||
avatarCount: z.number().optional(),
|
||||
equipmentCount: z.number().optional(),
|
||||
musicCount: z.number().optional(),
|
||||
relicCount: z.number().optional(),
|
||||
challengeInfo: z.unknown().optional(),
|
||||
maxRogueChallengeScore: z.number().optional()
|
||||
});
|
||||
|
||||
const subAffixSchema = z.object({
|
||||
@@ -32,18 +32,18 @@ const flatPropSchema = z.object({
|
||||
});
|
||||
|
||||
const relicFlatSchema = z.object({
|
||||
props: z.array(flatPropSchema),
|
||||
setName: z.union([z.string(), z.number()]),
|
||||
setID: z.number()
|
||||
props: z.array(flatPropSchema).optional(),
|
||||
setName: z.union([z.string(), z.number()]).optional(),
|
||||
setID: z.number().optional()
|
||||
});
|
||||
|
||||
const relicSchema = z.object({
|
||||
mainAffixId: z.number(),
|
||||
subAffixList: z.array(subAffixSchema),
|
||||
subAffixList: z.array(subAffixSchema).optional(),
|
||||
tid: z.number(),
|
||||
type: z.number(),
|
||||
level: z.number(),
|
||||
_flat: relicFlatSchema
|
||||
_flat: relicFlatSchema.optional()
|
||||
});
|
||||
|
||||
const skillTreeSchema = z.object({
|
||||
@@ -52,43 +52,44 @@ const skillTreeSchema = z.object({
|
||||
});
|
||||
|
||||
const equipmentFlatSchema = z.object({
|
||||
props: z.array(flatPropSchema),
|
||||
name: z.union([z.string(), z.number()])
|
||||
props: z.array(flatPropSchema).optional(),
|
||||
name: z.union([z.string(), z.number()]).optional()
|
||||
});
|
||||
|
||||
const equipmentSchema = z.object({
|
||||
rank: z.number(),
|
||||
rank: z.number().optional(),
|
||||
tid: z.number(),
|
||||
promotion: z.number(),
|
||||
promotion: z.number().optional(),
|
||||
level: z.number(),
|
||||
_flat: equipmentFlatSchema
|
||||
_flat: equipmentFlatSchema.optional()
|
||||
});
|
||||
|
||||
export const avatarEnkaDetailSchema = z.object({
|
||||
relicList: z.array(relicSchema),
|
||||
relicList: z.array(relicSchema).optional(),
|
||||
level: z.number(),
|
||||
promotion: z.number(),
|
||||
promotion: z.number().optional(),
|
||||
rank: z.number().optional(),
|
||||
skillTreeList: z.array(skillTreeSchema),
|
||||
equipment: equipmentSchema,
|
||||
skillTreeList: z.array(skillTreeSchema).optional(),
|
||||
equipment: equipmentSchema.optional(),
|
||||
avatarId: z.number(),
|
||||
_assist: z.boolean().optional()
|
||||
_assist: z.boolean().optional(),
|
||||
pos: z.number().optional()
|
||||
});
|
||||
|
||||
const detailInfoSchema = z.object({
|
||||
worldLevel: z.number(),
|
||||
privacySettingInfo: privacySettingInfoSchema,
|
||||
headIcon: z.number(),
|
||||
signature: z.string(),
|
||||
avatarDetailList: z.array(avatarEnkaDetailSchema),
|
||||
platform: z.string(),
|
||||
recordInfo: recordInfoSchema,
|
||||
worldLevel: z.number().optional(),
|
||||
privacySettingInfo: privacySettingInfoSchema.optional(),
|
||||
headIcon: z.number().optional(),
|
||||
signature: z.string().optional(),
|
||||
avatarDetailList: z.array(avatarEnkaDetailSchema).optional(),
|
||||
platform: z.string().optional(),
|
||||
recordInfo: recordInfoSchema.optional(),
|
||||
uid: z.number(),
|
||||
level: z.number(),
|
||||
nickname: z.string(),
|
||||
isDisplayAvatar: z.boolean(),
|
||||
friendCount: z.number(),
|
||||
personalCardId: z.number()
|
||||
isDisplayAvatar: z.boolean().optional(),
|
||||
friendCount: z.number().optional(),
|
||||
personalCardId: z.number().optional()
|
||||
});
|
||||
|
||||
export const enkaResponseSchema = z.object({
|
||||
|
||||
Reference in New Issue
Block a user