diff --git a/.gitignore b/.gitignore index 7099b18..0563835 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,4 @@ yarn-error.log* # typescript *.tsbuildinfo -next-env.d.ts - -/src/app/builder/monster-hunter-world \ No newline at end of file +next-env.d.ts \ No newline at end of file diff --git a/src/app/builder/monster-hunter-world/adapter/MHWEquipmentAdapter.tsx b/src/app/builder/monster-hunter-world/adapter/MHWEquipmentAdapter.tsx new file mode 100644 index 0000000..5d86f38 --- /dev/null +++ b/src/app/builder/monster-hunter-world/adapter/MHWEquipmentAdapter.tsx @@ -0,0 +1,44 @@ +import {EquipmentAdapter} from "@/components/builder/adapter/EquipmentAdapter"; +import {Equipment} from "@/core/entity/game/Equipment"; +import React from "react"; +import {GearType} from "@/core/entity/game/GearType"; +import {SearchEquipmentComponent} from "@/components/builder/SearchEquipmentComponent"; +import {Localization} from "@/core/entity/localization/Localization"; +import ArmorIcon from "@/icons/ArmorIcon.svg" +import {Icon} from "@/components/image/icon"; + +const EQUIPMENT_ICONS: Record = { + [GearType.Armor]: ArmorIcon +} + +export class MHWEquipmentAdapter implements EquipmentAdapter { + + adapt( + equipment: Equipment, + localization: Localization, + onClick: (equipment: Equipment) => void + ): React.ReactNode { + switch(equipment.type) { + case GearType.Weapon: + return <> + + case GearType.Helm: + case GearType.Armor: + case GearType.Glove: + case GearType.Belt: + case GearType.Legs: + return onClick(equipment)} /> + + case GearType.Charms: + return <> + + case GearType.SpecializedTool: + return <> + + } + } + +} \ No newline at end of file diff --git a/src/app/builder/monster-hunter-world/components/MHWBuilderComponent.tsx b/src/app/builder/monster-hunter-world/components/MHWBuilderComponent.tsx new file mode 100644 index 0000000..902e114 --- /dev/null +++ b/src/app/builder/monster-hunter-world/components/MHWBuilderComponent.tsx @@ -0,0 +1,70 @@ +'use client' +import {BuildMakerComponent} from "@/components/builder/view/BuildMakerComponent"; +import React, {useEffect, useMemo, useState} from "react"; +import {Equipment} from "@/core/entity/game/Equipment"; +import {Localization} from "@/core/entity/localization/Localization"; +import EquipmentCategoryModel from "@/components/builder/model/EquipmentCategoryModel"; +import ArmorIcon from "@/icons/ArmorIcon.svg" +import {GearType} from "@/core/entity/game/GearType"; +import {Ailment} from "@/core/entity/game/Ailment"; +import {EquipmentAdapter} from "@/components/builder/adapter/EquipmentAdapter"; +import {GetStaticProps} from "next"; +import {container} from "tsyringe"; +import {MHW_EQUIPMENT_ADAPTER} from "@/app/builder/monster-hunter-world/di/Config"; + +export default function MHWBuilderComponent() { + const equipmentAdapter = container.resolve(MHW_EQUIPMENT_ADAPTER) + + const [armors, setArmors] = useState([]) + const [localization, setLocalization] = useState({}) + + useEffect(() => { + setArmors([ + { + type: GearType.Armor, + id: "armor.mock", + rarity: 12, + skills: [ + { id: "skill.mock.1" }, + { id: "skill.mock.2" }, + { id: "skill.mock.3" }, + ], + resistances: [ + { ailment: Ailment.Fire, value: 3 }, + { ailment: Ailment.Ice, value: -4 }, + { ailment: Ailment.Thunder, value: 5 } + ], + jewels: [3, 2] + } + ]) + + setLocalization({ + "category.armor": "Armor", + "search.armor.placeholder": "Search for armors", + "armor.mock": "Mock Armor", + "skill.mock.1": "Mock Lv. 1", + "skill.mock.2": "Mock Lv. 2", + "skill.mock.3": "Mock Lv. 3", + }) + }, []); + + const categories = useMemo(() => { + return [ + { + name: localization["category.armor"], + searchPlaceholder: localization["search.armor.placeholder"], + icon: ArmorIcon, + maxJewels: 3, + equipments: armors + } + ] + }, [armors, localization]) + + return ( + <> + + + ) +} \ No newline at end of file diff --git a/src/app/builder/monster-hunter-world/components/MHWBuilderContainer.tsx b/src/app/builder/monster-hunter-world/components/MHWBuilderContainer.tsx new file mode 100644 index 0000000..c824a27 --- /dev/null +++ b/src/app/builder/monster-hunter-world/components/MHWBuilderContainer.tsx @@ -0,0 +1,16 @@ +'use client' +import MHWBuilderComponent from "@/app/builder/monster-hunter-world/components/MHWBuilderComponent"; +import {EquipmentAdapter} from "@/components/builder/adapter/EquipmentAdapter"; +import {GetStaticProps} from "next"; +import {container} from "tsyringe"; +import {MHW_EQUIPMENT_ADAPTER, MHWBuilderModule} from "@/app/builder/monster-hunter-world/di/Config"; +import {ModuleContext} from "@/app/di/component/ModuleContext"; + +export default function MHWBuilderContainer() { + return ( + <> + + + + ) +} \ No newline at end of file diff --git a/src/app/builder/monster-hunter-world/di/Config.ts b/src/app/builder/monster-hunter-world/di/Config.ts new file mode 100644 index 0000000..c3afd9d --- /dev/null +++ b/src/app/builder/monster-hunter-world/di/Config.ts @@ -0,0 +1,16 @@ +import {container} from "tsyringe"; +import {MHWEquipmentAdapter} from "@/app/builder/monster-hunter-world/adapter/MHWEquipmentAdapter"; +import {Module} from "@/app/di/Module"; + +export const MHW_DATA_REPOSITORY: string = "mhw.repository.data" +export const MHW_LOCALIZATION_REPOSITORY: string = "mhw.repository.localization" +export const MHW_API_BASE_URL: string = "mhw.api.url" +export const MHW_EQUIPMENT_ADAPTER: string = "mhw.adapter.equipment" + +export const MHWBuilderModule: Module = { + register() { + container.register(MHW_EQUIPMENT_ADAPTER, { + useClass: MHWEquipmentAdapter + }) + } +} \ No newline at end of file diff --git a/src/app/builder/monster-hunter-world/page.tsx b/src/app/builder/monster-hunter-world/page.tsx new file mode 100644 index 0000000..8f37c66 --- /dev/null +++ b/src/app/builder/monster-hunter-world/page.tsx @@ -0,0 +1,14 @@ +import { Metadata } from 'next' +import MHWBuilderContainer from "@/app/builder/monster-hunter-world/components/MHWBuilderContainer"; +export const metadata: Metadata = { + title: "HunterPie Hub | Monster Hunter World Builder", + description: "Build creator for Monster Hunter World" +} + +export default function Page() { + return ( + <> + + + ) +} \ No newline at end of file diff --git a/src/app/builder/monster-hunter-world/repository/game-data/MHWGameDataRepository.ts b/src/app/builder/monster-hunter-world/repository/game-data/MHWGameDataRepository.ts new file mode 100644 index 0000000..9081118 --- /dev/null +++ b/src/app/builder/monster-hunter-world/repository/game-data/MHWGameDataRepository.ts @@ -0,0 +1,96 @@ +import {IGameDataRepository} from "@/core/repository/game-data/IGameDataRepository"; +import {Equipment} from "@/core/entity/game/Equipment"; +import {IHttpService} from "@/core/http/IHttpService"; +import {Ailment} from "@/core/entity/game/Ailment"; +import {Resistance} from "@/core/entity/game/Resistance"; +import {Skill} from "@/core/entity/game/Skill"; +import {GearType} from "@/core/entity/game/GearType"; +import {Inject, Service} from "typedi"; +import {MHW_API_BASE_URL, MHW_DATA_REPOSITORY} from "@/app/builder/monster-hunter-world/di/Config"; + +const DEFAULT_TIMEOUT = 10_000 + +@Service(MHW_DATA_REPOSITORY) +export default class MHWGameDataRepository implements IGameDataRepository { + @Inject() private readonly _httpService!: IHttpService + @Inject(MHW_API_BASE_URL) private readonly _baseUrl!: string + + async findAllArmors(): Promise { + const response = await this._httpService.get({ + url: this._baseUrl + "/chests.json", + timeout: DEFAULT_TIMEOUT + }) + + if (!response.isSuccessful) + return [] + + const mhwArmors: MHWBaseGear[] = JSON.parse(response.data!) + return mhwArmors.map(armor => { + return { + type: GearType.Armor, + id: armor.id.toString(), + rarity: armor.rarity, + skills: this._convertSkills(armor.skills), + resistances: this._convertResistances(armor.elementalResistances), + defense: armor.defense, + jewels: armor.slots + } + }) + } + + async findAllBelts(): Promise { + const response = await this._httpService.get({ + url: this._baseUrl + "/belts.json", + timeout: DEFAULT_TIMEOUT + }) + if (!response.isSuccessful) + return [] + + const mhwBelts: MHWBaseGear[] = JSON.parse(response.data!) + return mhwBelts.map(belt => { + return { + type: GearType.Belt, + id: belt.id.toString(), + rarity: belt.rarity, + skills: this._convertSkills(belt.skills), + resistances: this._convertResistances(belt.elementalResistances), + defense: belt.defense, + jewels: belt.slots + } + }) + } + + async findAllCharms(): Promise { + throw new Error("not implemented") + } + + async findAllGloves(): Promise { + throw new Error("not implemented") + } + + async findAllHelms(): Promise { + throw new Error("not implemented") + } + + async findAllLegs(): Promise { + throw new Error("not implemented") + } + + private _convertSkills(skills: MHWSkill[]): Skill[] { + return skills.map(({skillId, level}) => { + return { + id: `${skillId}-${level}` + } + }) + } + + private _convertResistances(resistances: MHWElementalResistances): Resistance[] { + return [ + { ailment: Ailment.Fire, value: resistances.fire }, + { ailment: Ailment.Water, value: resistances.water }, + { ailment: Ailment.Thunder, value: resistances.thunder }, + { ailment: Ailment.Ice, value: resistances.ice }, + { ailment: Ailment.Dragon, value: resistances.dragon }, + ] + } +} diff --git a/src/app/builder/monster-hunter-world/repository/game-data/model/MHWBaseGear.ts b/src/app/builder/monster-hunter-world/repository/game-data/model/MHWBaseGear.ts new file mode 100644 index 0000000..8d7e182 --- /dev/null +++ b/src/app/builder/monster-hunter-world/repository/game-data/model/MHWBaseGear.ts @@ -0,0 +1,21 @@ +interface MHWSkill { + skillId: number + level: number +} + +interface MHWElementalResistances { + fire: number + water: number + thunder: number + ice: number + dragon: number +} + +interface MHWBaseGear { + id: number + rarity: number + skills: MHWSkill[] + defense: number + elementalResistances: MHWElementalResistances + slots: number[] +} \ No newline at end of file