From ab664eb8ea31d04856e28eff60f436eb1cdf7f37 Mon Sep 17 00:00:00 2001 From: AzenKain Date: Thu, 2 Oct 2025 23:27:42 +0700 Subject: [PATCH] UPDATE: Extra Setting for FF GO --- messages/cn.json | 7 +- messages/en.json | 7 +- messages/ja.json | 7 +- messages/ko.json | 7 +- messages/vi.json | 7 +- messages/zh.json | 7 +- src/components/actionBar/index.tsx | 189 ++++++------- src/components/connectBar/index.tsx | 167 +++++++++++ src/components/extraSettingBar/index.tsx | 120 ++++++++ src/components/header/index.tsx | 340 ++++++++--------------- src/components/monsterBar/ce.tsx | 121 +++++--- src/components/relicsInfo/index.tsx | 105 +++---- src/helper/connect.ts | 15 +- src/lib/api/api.ts | 15 +- src/stores/globalStore.ts | 5 + src/stores/modelStore.ts | 4 + src/types/extraData.ts | 13 + src/types/index.ts | 1 + src/types/srtools.ts | 3 + src/zod/extraData.zod.ts | 15 + src/zod/index.ts | 1 + src/zod/srtools.zod.ts | 2 + 22 files changed, 728 insertions(+), 430 deletions(-) create mode 100644 src/components/connectBar/index.tsx create mode 100644 src/components/extraSettingBar/index.tsx create mode 100644 src/types/extraData.ts create mode 100644 src/zod/extraData.zod.ts diff --git a/messages/cn.json b/messages/cn.json index 715c49f..9f9e831 100644 --- a/messages/cn.json +++ b/messages/cn.json @@ -248,6 +248,11 @@ "downRoll": "减少副属性", "actions": "操作", "avatars": "头像", - "quickView": "快速预览" + "quickView": "快速预览", + "extraSetting": "额外设置", + "disableCensorship": "禁用审查", + "hideUI": "隐藏界面", + "theoryCraftMode": "理论研究模式", + "cycleCount": "循环次数" } } \ No newline at end of file diff --git a/messages/en.json b/messages/en.json index 69357f1..16435a0 100644 --- a/messages/en.json +++ b/messages/en.json @@ -249,6 +249,11 @@ "downRoll": "Down Roll", "actions": "Actions", "avatars": "Avatars", - "quickView": "Quick View" + "quickView": "Quick View", + "extraSetting": "Extra Settings", + "disableCensorship": "Disable Censorship", + "hideUI": "Hide UI", + "theoryCraftMode": "Theorycraft Mode", + "cycleCount": "Cycle Count" } } \ No newline at end of file diff --git a/messages/ja.json b/messages/ja.json index d403ac9..087b2b4 100644 --- a/messages/ja.json +++ b/messages/ja.json @@ -248,6 +248,11 @@ "downRoll": "サブステータスを減らす", "actions": "アクション", "avatars": "アバター", - "quickView": "クイックビュー" + "quickView": "クイックビュー", + "extraSetting": "追加設定", + "disableCensorship": "検閲を無効化", + "hideUI": "UIを非表示", + "theoryCraftMode": "シアリークラフトモード", + "cycleCount": "サイクル数" } } \ No newline at end of file diff --git a/messages/ko.json b/messages/ko.json index a010439..fce899a 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -248,6 +248,11 @@ "downRoll": "부옵션 감소", "actions": "동작", "avatars": "아바타", - "quickView": "빠른 조회" + "quickView": "빠른 조회", + "extraSetting": "추가 설정", + "disableCensorship": "검열 비활성화", + "hideUI": "UI 숨기기", + "theoryCraftMode": "이론 제작 모드", + "cycleCount": "사이클 수" } } \ No newline at end of file diff --git a/messages/vi.json b/messages/vi.json index cf1c9b6..6e9422a 100644 --- a/messages/vi.json +++ b/messages/vi.json @@ -248,6 +248,11 @@ "downRoll": "Giảm dòng", "actions": "Hành động", "avatars": "Nhân vật", - "quickView": "Xem nhanh" + "quickView": "Xem nhanh", + "extraSetting": "Cài đặt bổ sung", + "disableCensorship": "Tắt kiểm duyệt", + "hideUI": "Ẩn giao diện", + "theoryCraftMode": "Chế độ Theorycraft", + "cycleCount": "Số vòng" } } \ No newline at end of file diff --git a/messages/zh.json b/messages/zh.json index 8c336a1..8b6adf6 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -248,6 +248,11 @@ "downRoll": "减少副属性", "actions": "操作", "avatars": "头像", - "quickView": "快速预览" + "quickView": "快速预览", + "extraSetting": "额外设置", + "disableCensorship": "禁用审查", + "hideUI": "隐藏界面", + "theoryCraftMode": "理论研究模式", + "cycleCount": "循环次数" } } \ No newline at end of file diff --git a/src/components/actionBar/index.tsx b/src/components/actionBar/index.tsx index 75f7c79..818483f 100644 --- a/src/components/actionBar/index.tsx +++ b/src/components/actionBar/index.tsx @@ -26,19 +26,19 @@ export default function ActionBar() { const { setListCopyAvatar } = useCopyProfileStore() const transI18n = useTranslations("DataPage") const { locale } = useLocaleStore() - const { - isOpenCreateProfile, - setIsOpenCreateProfile, - isOpenCopy, + const { + isOpenCreateProfile, + setIsOpenCreateProfile, + isOpenCopy, setIsOpenCopy, isOpenAvatars, - setIsOpenAvatars + setIsOpenAvatars } = useModelStore() const { avatars, setAvatar } = useUserDataStore() const [profileName, setProfileName] = useState(""); const [formState, setFormState] = useState("EDIT"); const [profileEdit, setProfileEdit] = useState(-1); - const { isConnectPS, setIsConnectPS } = useGlobalStore() + const { isConnectPS } = useGlobalStore() const profileCurrent = useMemo(() => { if (!avatarSelected) return null; @@ -104,7 +104,7 @@ export default function ActionBar() { } console.log(isOpenAvatars) if (!isOpenAvatars) { - + handleCloseModal("avatars_modal"); return; } @@ -157,20 +157,71 @@ export default function ActionBar() { toast.success(transI18n("syncSuccess")) } else { toast.error(`${transI18n("syncFailed")}: ${res.message}`) - setIsConnectPS(false) } } else { const res = await connectToPS() if (res.success) { toast.success(transI18n("connectedSuccess")) - setIsConnectPS(true) } else { toast.error(`${transI18n("connectedFailed")}: ${res.message}`) - setIsConnectPS(false) } } } + + const modalConfigs = [ + { + id: "update_profile_modal", + title: formState === "CREATE" ? transI18n("createNewProfile") : transI18n("editProfile"), + onClose: () => { + setIsOpenCreateProfile(false) + handleCloseModal("update_profile_modal") + }, + content: ( +
+
+ + setProfileName(e.target.value)} + /> +
+
+ +
+
+ ) + }, + { + id: "copy_profile_modal", + title: transI18n("copyProfiles").toUpperCase(), + onClose: () => { + setIsOpenCopy(false) + handleCloseModal("copy_profile_modal") + }, + content: + }, + { + id: "avatars_modal", + title: transI18n("avatars").toUpperCase(), + onClose: () => { + setIsOpenAvatars(false) + handleCloseModal("avatars_modal") + }, + content: { setIsOpenAvatars(false); handleCloseModal("avatars_modal") }} /> + } + ] + + return (
@@ -302,12 +353,12 @@ export default function ActionBar() {
-
@@ -376,96 +427,28 @@ export default function ActionBar() {
- -
-
- { - setIsOpenCreateProfile(false) - handleCloseModal("update_profile_modal") - }} - > - ✕ - -
- -
-

- {formState === "CREATE" ? transI18n("createNewProfile") : transI18n("editProfile")} -

-
- -
-
- - setProfileName(e.target.value)} - /> + {modalConfigs.map(({ id, title, onClose, content }) => ( + +
+
+ + ✕ +
- -
- +
+

+ {title} +

+ {content}
-
-
- - -
-
- { - setIsOpenCopy(false) - handleCloseModal("copy_profile_modal") - }} - > - ✕ - -
-
-

- {transI18n("copyProfiles").toUpperCase()} -

-
- -
-
- - - -
-
- { - setIsOpenAvatars(false) - handleCloseModal("avatars_modal") - }} - > - ✕ - -
-
-

- {transI18n("avatars").toUpperCase()} -

-
- {setIsOpenAvatars(false); handleCloseModal("avatars_modal")}} /> -
-
+
+ ))}
diff --git a/src/components/connectBar/index.tsx b/src/components/connectBar/index.tsx new file mode 100644 index 0000000..a29e438 --- /dev/null +++ b/src/components/connectBar/index.tsx @@ -0,0 +1,167 @@ +"use client" + +import { connectToPS, syncDataToPS } from "@/helper" +import useConnectStore from "@/stores/connectStore" +import useGlobalStore from "@/stores/globalStore" +import { useTranslations } from "next-intl" +import { useState } from "react" + +export default function ConnectBar() { + const transI18n = useTranslations("DataPage") + const [message, setMessage] = useState({ text: '', type: '' }); + const { + connectionType, + privateType, + serverUrl, + username, + password, + setConnectionType, + setPrivateType, + setServerUrl, + setUsername, + setPassword + } = useConnectStore() + const { isConnectPS } = useGlobalStore() + + return ( +
+ {/* Select connection type */} +
+ + +
+ + {/* Show host/port if Other */} + {connectionType === "Other" && ( +
+
+ + setServerUrl(e.target.value)} + /> +
+
+ + +
+ +
+ + setUsername(e.target.value)} + /> +
+
+ + setPassword(e.target.value)} + /> +
+
+ )} + + {message.text && ( +
+ {message.text} +
+ )} + +
+ {/* Status */} +
+ {transI18n("status")}: + + {isConnectPS ? transI18n("connected") : transI18n("unconnected")} + +
+ + {/* Buttons */} +
+ + + {isConnectPS && ( + + )} +
+
+ +
+ ) +} \ No newline at end of file diff --git a/src/components/extraSettingBar/index.tsx b/src/components/extraSettingBar/index.tsx new file mode 100644 index 0000000..9c85a79 --- /dev/null +++ b/src/components/extraSettingBar/index.tsx @@ -0,0 +1,120 @@ +'use client' +import { motion } from "framer-motion" +import { EyeOff, Eye, Hammer, RefreshCw, ShieldBan } from "lucide-react" +import useGlobalStore from '@/stores/globalStore'; +import { useTranslations } from "next-intl"; + + +export default function ExtraSettingBar() { + const { extraData, setExtraData } = useGlobalStore() + const transI18n = useTranslations("DataPage") + + return ( +
+
+ {/* Theorycraft Mode */} + {extraData?.theory_craft?.mode !== undefined && ( + + + + )} + + {/* Cycle Count */} + {extraData?.theory_craft?.mode && ( + + + + )} + + {/* Hidden UI */} + {extraData?.setting?.hide_ui !== undefined && ( + + + + )} + + {/* Censorship */} + {extraData?.setting?.censorship !== undefined && ( + + + + )} +
+
+ ); +} diff --git a/src/components/header/index.tsx b/src/components/header/index.tsx index 57252fc..71a6d2b 100644 --- a/src/components/header/index.tsx +++ b/src/components/header/index.tsx @@ -1,5 +1,5 @@ "use client" -import { connectToPS, downloadJson, syncDataToPS } from "@/helper"; +import { downloadJson } from "@/helper"; import { converterToFreeSRJson } from "@/helper/converterToFreeSRJson"; import { useChangeTheme } from "@/hooks/useChangeTheme"; import { listCurrentLanguage } from "@/constant/constant"; @@ -15,10 +15,11 @@ import useModelStore from "@/stores/modelStore"; import FreeSRImport from "../importBar/freesr"; import { toast } from "react-toastify"; import { micsSchema } from "@/zod"; -import useConnectStore from "@/stores/connectStore"; import useGlobalStore from "@/stores/globalStore"; import MonsterBar from "../monsterBar"; import Image from "next/image"; +import ConnectBar from "../connectBar"; +import ExtraSettingBar from "../extraSettingBar"; const themes = [ { label: "Winter" }, @@ -55,24 +56,14 @@ export default function Header() { setIsOpenMonster, isOpenMonster, setIsOpenConnect, - isOpenConnect + isOpenConnect, + setIsOpenExtra, + isOpenExtra } = useModelStore() - const [message, setMessage] = useState({ text: '', type: '' }); const [importModal, setImportModal] = useState("enka"); - const { - connectionType, - privateType, - serverUrl, - username, - password, - setConnectionType, - setPrivateType, - setServerUrl, - setUsername, - setPassword - } = useConnectStore() - const { isConnectPS, setIsConnectPS } = useGlobalStore() + + const { isConnectPS, extraData } = useGlobalStore() useEffect(() => { @@ -134,17 +125,22 @@ export default function Header() { handleCloseModal("connect_modal"); return; } + if (!isOpenExtra) { + handleCloseModal("extra_modal"); + return; + } const handleEscKey = (event: KeyboardEvent) => { if (event.key === 'Escape') { handleCloseModal("connect_modal"); handleCloseModal("import_modal"); handleCloseModal("monster_modal"); + handleCloseModal("extra_modal"); } }; window.addEventListener('keydown', handleEscKey); return () => window.removeEventListener('keydown', handleEscKey); - }, [isOpenImport, isOpenMonster, isOpenConnect]); + }, [isOpenImport, isOpenMonster, isOpenConnect, isOpenExtra]); const handleImportDatabase = (event: React.ChangeEvent) => { @@ -183,6 +179,56 @@ export default function Header() { }; + + const modalConfigs = [ + { + id: "connect_modal", + title: transI18n("psConnection"), + isOpen: isOpenConnect, + onClose: () => { + setIsOpenConnect(false) + handleCloseModal("connect_modal") + }, + content: + }, + { + id: "import_modal", + title: transI18n("importSetting"), + isOpen: isOpenImport, + onClose: () => { + setIsOpenImport(false) + handleCloseModal("import_modal") + }, + content: ( + <> + {importModal === "enka" && } + {importModal === "freesr" && } + + ) + }, + { + id: "monster_modal", + title: transI18n("monsterSetting"), + isOpen: isOpenMonster, + onClose: () => { + setIsOpenMonster(false) + handleCloseModal("monster_modal") + }, + content: + }, + { + id: "extra_modal", + title: transI18n("extraSetting"), + isOpen: isOpenExtra, + onClose: () => { + setIsOpenExtra(false) + handleCloseModal("extra_modal") + }, + content: + } + ] + + return (
@@ -279,6 +325,20 @@ export default function Header() { {transI18n("monsterSetting")} + + {extraData && ( +
  • + +
  • + )}
    @@ -386,6 +446,19 @@ export default function Header() { {transI18n("monsterSetting")} + {extraData && ( +
  • + +
  • + )}
    @@ -495,225 +568,30 @@ export default function Header() {
    - -
    -
    - { - setIsOpenConnect(false) - handleCloseModal("connect_modal") - }} - > - ✕ - -
    - -
    -

    - {"PS Connection"} -

    -
    - -
    - {/* Select connection type */} -
    - - + ✕ +
    - {/* Show host/port if Other */} - {connectionType === "Other" && ( -
    -
    - - setServerUrl(e.target.value)} - /> -
    -
    - - -
    - -
    - - setUsername(e.target.value)} - /> -
    -
    - - setPassword(e.target.value)} - /> -
    -
    - )} - - {message.text && ( -
    - {message.text} -
    - )} - -
    - {/* Status */} -
    - {transI18n("status")}: - - {isConnectPS ? transI18n("connected") : transI18n("unconnected")} - -
    - - {/* Buttons */} -
    - - - {isConnectPS && ( - - )} -
    +
    +

    + {title} +

    + {content}
    -
    -
    - - - -
    -
    - { - handleCloseModal("import_modal") - setIsOpenImport(false) - }} - > - ✕ - -
    - -
    -

    - {transI18n("importSetting")} -

    -
    - - {importModal === "enka" && } - {importModal === "freesr" && } -
    -
    - - -
    -
    - { - handleCloseModal("monster_modal") - setIsOpenMonster(false) - }} - > - ✕ - -
    - -
    -

    - {transI18n("monsterSetting")} -

    -
    - -
    -
    - + + ))} ) } \ No newline at end of file diff --git a/src/components/monsterBar/ce.tsx b/src/components/monsterBar/ce.tsx index 28243bd..a449ee1 100644 --- a/src/components/monsterBar/ce.tsx +++ b/src/components/monsterBar/ce.tsx @@ -20,6 +20,7 @@ import { MonsterBasic } from "@/types"; import cloneDeep from 'lodash/cloneDeep' import { useTranslations } from "next-intl"; import { listCurrentLanguageApi } from "@/constant/constant"; +import useGlobalStore from "@/stores/globalStore"; export default function CeBar() { @@ -33,6 +34,7 @@ export default function CeBar() { const [showSearchStage, setShowSearchStage] = useState(false) const [stageSearchTerm, setStageSearchTerm] = useState("") const [stagePage, setStagePage] = useState(1) + const { extraData, setExtraData } = useGlobalStore() const pageSize = 30 @@ -41,29 +43,29 @@ export default function CeBar() { const listMonsterDetail = useMemo(() => { const result: MonsterBasic[] = [] - - for (const monster of Object.values(mapMonsterInfo)) { - for (const monsterChild of monster.Child) { - result.push({ - id: monsterChild.Id.toString(), - rank: monster.Rank, - camp: null, - icon: monster.ImagePath, - weak: monsterChild.StanceWeakList, - desc: monster.Desc, - child: [], - lang: new Map([ - [listCurrentLanguageApi[locale], monster.Name], - ]), - }) - } - } - - return result - }, [mapMonsterInfo, locale]) - - const filteredMonsters = useMemo(() => { + for (const monster of Object.values(mapMonsterInfo)) { + for (const monsterChild of monster.Child) { + result.push({ + id: monsterChild.Id.toString(), + rank: monster.Rank, + camp: null, + icon: monster.ImagePath, + weak: monsterChild.StanceWeakList, + desc: monster.Desc, + child: [], + lang: new Map([ + [listCurrentLanguageApi[locale], monster.Name], + ]), + }) + } + } + + return result + }, [mapMonsterInfo, locale]) + + + const filteredMonsters = useMemo(() => { const newlistMonster = new Set() for (const monster of listMonsterDetail) { if (getLocaleName(locale, monster).toLowerCase().includes(searchTerm.toLowerCase())) { @@ -110,13 +112,39 @@ export default function CeBar() { setStagePage(1) }, [stageSearchTerm]) + + useEffect(() => { + if (!ce_config) return + if (!extraData || !extraData.theory_craft?.mode) return + + const newExtraData = cloneDeep(extraData) + if (!newExtraData.theory_craft.hp) { + newExtraData.theory_craft.hp = {} + } + + for (let i = 0; i < ce_config.monsters.length; i++) { + const waveKey = (i + 1).toString() + if (!newExtraData.theory_craft.hp[waveKey]) { + newExtraData.theory_craft.hp[waveKey] = [] + } + for (let j = 0; j < ce_config.monsters[i].length; j++) { + if (newExtraData.theory_craft.hp[waveKey][j] === undefined) { + newExtraData.theory_craft.hp[waveKey][j] = 0 + } + } + } + setExtraData(newExtraData) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ce_config]) + + return (
    { - - setShowSearchWaveId(null) - setShowSearchStage(false) - }}> - + + setShowSearchWaveId(null) + setShowSearchStage(false) + }}> +
    @@ -289,7 +317,7 @@ export default function CeBar() { className="btn btn-xs btn-success absolute -top-2 right-12 opacity-50 group-hover:opacity-100 transition-opacity" onClick={() => { const newCeConfig = cloneDeep(ce_config) - + newCeConfig.monsters[waveIndex].push({ monster_id: Number(member.monster_id), level: member.level, @@ -337,13 +365,13 @@ export default function CeBar() {
    - {getLocaleName(locale, listMonsterDetail.find((monster) => monster.id === member.monster_id.toString())) } {`(${member.monster_id})`} + {getLocaleName(locale, listMonsterDetail.find((monster) => monster.id === member.monster_id.toString()))} {`(${member.monster_id})`}
    -
    - Lv. +
    + LV. { @@ -357,6 +385,31 @@ export default function CeBar() { }} />
    + {(extraData?.theory_craft?.mode === true && ( +
    + HP + { + const val = Number(e.target.value) + if (isNaN(val) || val < 0) return + + const newData = cloneDeep(extraData) + + if (!newData?.theory_craft?.hp?.[(waveIndex + 1).toString()]) { + newData.theory_craft.hp[(waveIndex + 1).toString()] = [] + } + + newData.theory_craft.hp[(waveIndex + 1).toString()][memberIndex] = val + + setExtraData(newData) + }} + /> +
    + ))}
    @@ -374,7 +427,7 @@ export default function CeBar() { setShowSearchWaveId(null) return } - + setShowSearchWaveId(waveIndex) }} > @@ -430,7 +483,7 @@ export default function CeBar() {
    {listMonsterDetail.find((monster2) => monster2.id === monster.id)?.icon?.split("/")?.pop()?.replace(".png", "") && ( monster2.id ===monster.id)?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} + src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonsterDetail.find((monster2) => monster2.id === monster.id)?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} alt="Enemy Icon" width={376} height={512} diff --git a/src/components/relicsInfo/index.tsx b/src/components/relicsInfo/index.tsx index 23cee4e..a3a21c4 100644 --- a/src/components/relicsInfo/index.tsx +++ b/src/components/relicsInfo/index.tsx @@ -28,14 +28,14 @@ export default function RelicsInfo() { listSelectedSubStats, } = useRelicMakerStore() const { mapSubAffix } = useAffixStore() - const { - isOpenRelic, + const { + isOpenRelic, setIsOpenRelic, isOpenQuickView, - setIsOpenQuickView + setIsOpenQuickView } = useModelStore() const transI18n = useTranslations("DataPage") - + const { mapRelicInfo } = useRelicStore() const handleShow = (modalId: string) => { @@ -75,7 +75,7 @@ export default function RelicsInfo() { window.addEventListener('keydown', handleEscKey); return () => window.removeEventListener('keydown', handleEscKey); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpenRelic]); const getRelic = useCallback((slot: string) => { @@ -150,6 +150,27 @@ export default function RelicsInfo() { return listEffects; }, [avatars, avatarSelected]); + const modalConfigs = [ + { + id: "action_detail_modal", + title: null, // không có title + onClose: () => { + setIsOpenRelic(false) + handleCloseModal("action_detail_modal") + }, + content: + }, + { + id: "quick_view_modal", + title: transI18n("quickView").toUpperCase(), + onClose: () => { + setIsOpenQuickView(false) + handleCloseModal("quick_view_modal") + }, + content: + } + ] + return (
    @@ -226,7 +247,7 @@ export default function RelicsInfo() { }} className="btn btn-info" > - {transI18n("changeRelic")} + {transI18n("changeRelic")}
    @@ -316,49 +337,33 @@ export default function RelicsInfo() {
    - -
    -
    - { - setIsOpenRelic(false) - handleCloseModal("action_detail_modal") - }} - > - ✕ - -
    - -
    - -
    - - -
    -
    - { - setIsOpenQuickView(false) - handleCloseModal("quick_view_modal") - }} - > - ✕ - -
    -
    -

    - {transI18n("quickView").toUpperCase()} -

    + {modalConfigs.map(({ id, title, onClose, content }) => ( + +
    +
    + + ✕ +
    - -
    -
    + + {title && ( +
    +

    + {title} +

    +
    + )} + + {content} +
    +
    + ))} + ); } diff --git a/src/helper/connect.ts b/src/helper/connect.ts index 3660680..7827bb1 100644 --- a/src/helper/connect.ts +++ b/src/helper/connect.ts @@ -4,6 +4,7 @@ import useConnectStore from "@/stores/connectStore" import useUserDataStore from "@/stores/userDataStore" import { converterToFreeSRJson } from "./converterToFreeSRJson" import { pSResponseSchema } from "@/zod" +import useGlobalStore from "@/stores/globalStore" export const connectToPS = async (): Promise<{ success: boolean, message: string }> => { const { @@ -13,6 +14,7 @@ export const connectToPS = async (): Promise<{ success: boolean, message: string username, password } = useConnectStore.getState() + const {setExtraData, setIsConnectPS} = useGlobalStore.getState() let urlQuery = serverUrl if (!urlQuery.startsWith("http://") && !urlQuery.startsWith("https://")) { @@ -36,10 +38,14 @@ export const connectToPS = async (): Promise<{ success: boolean, message: string } const response = await SendDataToServer(username, password, urlQuery, null) if (typeof response === "string") { + setIsConnectPS(false) return { success: false, message: response } } else if (response.status != 200) { + setIsConnectPS(false) return { success: false, message: response.message } } else { + setIsConnectPS(true) + setExtraData(response?.extra_data) return { success: true, message: "" } } } @@ -53,6 +59,9 @@ export const syncDataToPS = async (): Promise<{ success: boolean, message: strin password } = useConnectStore.getState() + const {extraData, setIsConnectPS, setExtraData} = useGlobalStore.getState() + + const {avatars, battle_type, moc_config, pf_config, as_config, ce_config, peak_config} = useUserDataStore.getState() const data = converterToFreeSRJson(avatars, battle_type, moc_config, pf_config, as_config, ce_config, peak_config) @@ -76,12 +85,16 @@ export const syncDataToPS = async (): Promise<{ success: boolean, message: strin return { success: true, message: "" } } } - const response = await SendDataToServer(username, password, urlQuery, data) + const response = await SendDataToServer(username, password, urlQuery, data, extraData) if (typeof response === "string") { + setIsConnectPS(false) return { success: false, message: response } } else if (response.status != 200) { + setIsConnectPS(false) return { success: false, message: response.message } } else { + setIsConnectPS(true) + setExtraData(response?.extra_data) return { success: true, message: "" } } } \ No newline at end of file diff --git a/src/lib/api/api.ts b/src/lib/api/api.ts index d448b06..c42dc2a 100644 --- a/src/lib/api/api.ts +++ b/src/lib/api/api.ts @@ -3,6 +3,7 @@ import { AffixDetail, ASDetail, CharacterDetail, ConfigMaze, FreeSRJson, LightConeDetail, MocDetail, MonsterDetail, PeakDetail, PFDetail, PSResponse, RelicDetail } from "@/types"; import axios from 'axios'; import { pSResponseSchema } from "@/zod"; +import { ExtraData } from "@/types"; export async function getConfigMazeApi(): Promise { try { @@ -236,11 +237,15 @@ export async function fetchMonsterByIdNative(ids: string, locale: string): Promi } } - - -export async function SendDataToServer(username: string, password: string, serverUrl: string, data: FreeSRJson | null): Promise { +export async function SendDataToServer( + username: string, + password: string, + serverUrl: string, + data: FreeSRJson | null, + extraData?: ExtraData +): Promise { try { - const response = await axios.post(`${serverUrl}`, { username, password, data }) + const response = await axios.post(`${serverUrl}`, { username, password, data, extra_data: extraData }) const parsed = pSResponseSchema.safeParse(response.data) if (!parsed.success) { return "Invalid response schema"; @@ -251,7 +256,7 @@ export async function SendDataToServer(username: string, password: string, serve } } -export async function SendDataThroughProxy({data}: {data: any}) { +export async function SendDataThroughProxy({ data }: { data: any }) { try { const response = await axios.post(`/api/proxy`, { ...data }) return response.data; diff --git a/src/stores/globalStore.ts b/src/stores/globalStore.ts index df5dfd4..85c977e 100644 --- a/src/stores/globalStore.ts +++ b/src/stores/globalStore.ts @@ -1,12 +1,17 @@ import { create } from 'zustand' +import { ExtraData } from '@/types' interface GlobalState { isConnectPS: boolean; + extraData?: ExtraData; + setExtraData: (newExtraData: ExtraData | undefined) => void; setIsConnectPS: (newIsConnectPS: boolean) => void; } const useGlobalStore = create((set) => ({ isConnectPS: false, + extraData: undefined, + setExtraData: (newExtraData: ExtraData | undefined) => set({ extraData: newExtraData }), setIsConnectPS: (newIsConnectPS: boolean) => set({ isConnectPS: newIsConnectPS }), })); diff --git a/src/stores/modelStore.ts b/src/stores/modelStore.ts index 997be45..e9728f8 100644 --- a/src/stores/modelStore.ts +++ b/src/stores/modelStore.ts @@ -12,6 +12,8 @@ interface ModelState { isOpenConnect: boolean; isOpenAvatars: boolean; isOpenQuickView: boolean; + isOpenExtra: boolean; + setIsOpenExtra: (newIsOpenExtra: boolean) => void; setIsOpenQuickView: (newIsOpenQuickView: boolean) => void; setIsOpenAvatars: (newIsOpenAvatars: boolean) => void; setIsOpenConnect: (newIsOpenConnect: boolean) => void; @@ -35,6 +37,8 @@ const useModelStore = create((set) => ({ isOpenConnect: false, isOpenAvatars: false, isOpenQuickView: false, + isOpenExtra: false, + setIsOpenExtra: (newIsOpenExtra: boolean) => set({ isOpenExtra: newIsOpenExtra }), setIsOpenQuickView: (newIsOpenQuickView: boolean) => set({ isOpenQuickView: newIsOpenQuickView }), setIsOpenAvatars: (newIsOpenAvatars: boolean) => set({ isOpenAvatars: newIsOpenAvatars }), setIsOpenConnect: (newIsOpenConnect: boolean) => set({ isOpenConnect: newIsOpenConnect }), diff --git a/src/types/extraData.ts b/src/types/extraData.ts new file mode 100644 index 0000000..82b20b0 --- /dev/null +++ b/src/types/extraData.ts @@ -0,0 +1,13 @@ +export interface ExtraData { + theory_craft: { + hp: Record + cycle_count: number + mode: boolean + } + setting: { + censorship: boolean + cm: boolean + first_person: boolean + hide_ui: boolean + }; +} diff --git a/src/types/index.ts b/src/types/index.ts index ec15323..450cc04 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -19,3 +19,4 @@ export * from "./mocDetail" export * from "./monsterValue" export * from "./peakDetail" export * from "./monsterDetail" +export * from "./extraData" diff --git a/src/types/srtools.ts b/src/types/srtools.ts index 84f1faa..1350d27 100644 --- a/src/types/srtools.ts +++ b/src/types/srtools.ts @@ -1,3 +1,5 @@ +import { ExtraData } from "./extraData"; + export interface SubAffix { sub_affix_id: number; count: number; @@ -81,5 +83,6 @@ export interface FreeSRJson { export interface PSResponse { status: number; message: string; + extra_data?: ExtraData } diff --git a/src/zod/extraData.zod.ts b/src/zod/extraData.zod.ts new file mode 100644 index 0000000..59385cf --- /dev/null +++ b/src/zod/extraData.zod.ts @@ -0,0 +1,15 @@ +import { z } from "zod"; + +export const extraDataSchema = z.object({ + theory_craft: z.object({ + hp: z.record(z.string(), z.array(z.number())), + cycle_count: z.number(), + mode: z.boolean(), + }), + setting: z.object({ + censorship: z.boolean(), + cm: z.boolean(), + first_person: z.boolean(), + hide_ui: z.boolean(), + }), +}); \ No newline at end of file diff --git a/src/zod/index.ts b/src/zod/index.ts index fcb8479..0c2898f 100644 --- a/src/zod/index.ts +++ b/src/zod/index.ts @@ -11,3 +11,4 @@ export * from "./mics.zod"; export * from "./relicBasic.zod"; export * from "./relicDetail.zod"; export * from "./srtools.zod"; +export * from "./extraData.zod"; diff --git a/src/zod/srtools.zod.ts b/src/zod/srtools.zod.ts index 848f5e3..67367d8 100644 --- a/src/zod/srtools.zod.ts +++ b/src/zod/srtools.zod.ts @@ -1,5 +1,6 @@ // Generated by ts-to-zod import { z } from "zod"; +import { extraDataSchema } from "./extraData.zod"; export const subAffixSchema = z.object({ sub_affix_id: z.number(), @@ -87,4 +88,5 @@ export const freeSRJsonSchema = z.object({ export const pSResponseSchema = z.object({ status: z.number(), message: z.string(), + extra_data: extraDataSchema.optional(), });