/* eslint-disable react-hooks/exhaustive-deps */ "use client" import { downloadJson } from "@/helper"; import { converterToFreeSRJson } from "@/helper/converterToFreeSRJson"; import { useChangeTheme } from "@/hooks/useChangeTheme"; import { listCurrentLanguage, listCurrentLanguageApi } from "@/constant/constant"; import useLocaleStore from "@/stores/localeStore"; import useUserDataStore from "@/stores/userDataStore"; import { useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import EnkaImport from "../importBar/enka"; import useModelStore from "@/stores/modelStore"; import FreeSRImport from "../importBar/freesr"; import { toast } from "react-toastify"; import { micsSchema } from "@/zod"; import useGlobalStore from "@/stores/globalStore"; import MonsterBar from "../monsterBar"; import Image from "next/image"; import ConnectBar from "../connectBar"; import ExtraSettingBar from "../extraSettingBar"; import ChangelogBar from "../changelog"; import { ModalConfig } from "@/types"; import { ScrollText } from "lucide-react"; import { useShallow } from "zustand/react/shallow"; const themes = [ { label: "Winter" }, { label: "Night" }, { label: "Cupcake" }, { label: "Coffee" }, ]; function setCookieLocale(localeVal: string) { if (typeof document !== "undefined") { document.cookie = `MYNEXTAPP_LOCALE=${localeVal}; path=/; max-age=31536000;`; } } export default function Header() { const { changeTheme } = useChangeTheme() const { locale, setLocale } = useLocaleStore( useShallow((state) => ({ locale: state.locale, setLocale: state.setLocale, })) ) const { avatars, battle_type, setAvatars, setBattleType, moc_config, pf_config, as_config, ce_config, peak_config, setMocConfig, setPfConfig, setAsConfig, setCeConfig, setPeakConfig, } = useUserDataStore( useShallow((state) => ({ avatars: state.avatars, battle_type: state.battle_type, setAvatars: state.setAvatars, setBattleType: state.setBattleType, moc_config: state.moc_config, pf_config: state.pf_config, as_config: state.as_config, ce_config: state.ce_config, peak_config: state.peak_config, setMocConfig: state.setMocConfig, setPfConfig: state.setPfConfig, setAsConfig: state.setAsConfig, setCeConfig: state.setCeConfig, setPeakConfig: state.setPeakConfig, })) ) const router = useRouter() const transI18n = useTranslations("DataPage") const { setIsOpenImport, isOpenImport, setIsOpenMonster, isOpenMonster, setIsOpenConnect, isOpenConnect, setIsOpenExtra, isOpenExtra, setIsChangelog, isChangelog } = useModelStore( useShallow((state) => ({ setIsOpenImport: state.setIsOpenImport, isOpenImport: state.isOpenImport, setIsOpenMonster: state.setIsOpenMonster, isOpenMonster: state.isOpenMonster, setIsOpenConnect: state.setIsOpenConnect, isOpenConnect: state.isOpenConnect, setIsOpenExtra: state.setIsOpenExtra, isOpenExtra: state.isOpenExtra, setIsChangelog: state.setIsChangelog, isChangelog: state.isChangelog, })) ) const [importModal, setImportModal] = useState("enka"); const { isConnectPS, extraData } = useGlobalStore( useShallow((state) => ({ isConnectPS: state.isConnectPS, extraData: state.extraData, })) ) useEffect(() => { const cookieLocale = document.cookie.split("; ") .find((row) => row.startsWith("MYNEXTAPP_LOCALE")) ?.split("=")[1]; if (cookieLocale) { if (!listCurrentLanguageApi.hasOwnProperty(cookieLocale)) { setLocale("en") document.cookie = "MYNEXTAPP_LOCALE=en;" router.refresh() } else { setLocale(cookieLocale) } } else { let browserLocale = navigator.language.slice(0, 2); if (!listCurrentLanguageApi.hasOwnProperty(browserLocale)) { browserLocale = "en" } setLocale(browserLocale); document.cookie = `MYNEXTAPP_LOCALE=${browserLocale};` router.refresh() } }, [router, setLocale]) const changeLocale = (newLocale: string) => { setLocale(newLocale) setCookieLocale(newLocale) router.refresh() } const handleShow = (modalId: string) => { const modal = document.getElementById(modalId) as HTMLDialogElement | null; if (modal) { modal.showModal(); } }; // Close modal handler const handleCloseModal = (modalId: string) => { const modal = document.getElementById(modalId) as HTMLDialogElement | null; if (modal) { modal.close() } }; const modalConfigs: ModalConfig[] = [ { 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: }, { id: "changelog_modal", title: "Changelog", isOpen: isChangelog, onClose: () => { setIsChangelog(false) handleCloseModal("changelog_modal") }, content: } ] // Handle ESC key to close modal useEffect(() => { for (const item of modalConfigs) { if (!item?.isOpen) { handleCloseModal(item?.id || "") } else { handleShow(item?.id || "") } } const handleEscKey = (event: KeyboardEvent) => { if (event.key === 'Escape') { for (const item of modalConfigs) { handleCloseModal(item?.id || "") } } }; window.addEventListener('keydown', handleEscKey); return () => window.removeEventListener('keydown', handleEscKey); }, [isOpenImport, isOpenMonster, isOpenConnect, isOpenExtra, isChangelog]); const handleImportDatabase = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) { toast.error(transI18n("pleaseSelectAFile")) return } if (!file.name.endsWith(".json") || file.type !== "application/json") { toast.error(transI18n("fileMustBeAValidJsonFile")) return } if (file) { const reader = new FileReader(); reader.onload = (e) => { try { const data = JSON.parse(e.target?.result as string); const parsed = micsSchema.parse(data) setAvatars(parsed.avatars) setBattleType(parsed.battle_type) setMocConfig(parsed.moc_config) setPfConfig(parsed.pf_config) setAsConfig(parsed.as_config) setCeConfig(parsed.ce_config) setPeakConfig(parsed.peak_config) toast.success(transI18n("importDatabaseSuccess")) } catch { toast.error(transI18n("fileMustBeAValidJsonFile")) } }; reader.readAsText(file); } }; return ( {/* Mobile menu dropdown */} {transI18n("loadData")} { setImportModal("freesr") setIsOpenImport(true) }}>{transI18n("freeSr")} <> document.getElementById('database-data-upload')?.click()} > {transI18n("database")} > { setImportModal("enka") setIsOpenImport(true) }}>{transI18n("enka")} {transI18n("exportData")} downloadJson("freesr-data", converterToFreeSRJson( avatars, battle_type, moc_config, pf_config, as_config, ce_config, peak_config ) )}>{transI18n("freeSr")} downloadJson("database-data", { avatars: avatars, battle_type: battle_type, moc_config: moc_config, pf_config: pf_config, as_config: as_config, ce_config: ce_config, peak_config: peak_config })}>{transI18n("database")} { setIsOpenConnect(true) }} > {transI18n("connectSetting")} { setIsOpenMonster(true) }} className="px-3 py-2 hover:bg-base-200/70 rounded-lg transition-all duration-200 font-medium" > {transI18n("monsterSetting")} {extraData && ( { setIsOpenExtra(true) }} className="px-3 py-2 hover:bg-base-200/70 rounded-lg transition-all duration-200 font-medium" > {transI18n("extraSetting")} )} {/* Brand Logo */} Firefly SrTools Firefly Shelter {/* Desktop navigation */} {transI18n("loadData")} { setImportModal("freesr") setIsOpenImport(true) }}>{transI18n("freeSr")} <> document.getElementById('database-data-upload')?.click()} > {transI18n("database")} > { setImportModal("enka") setIsOpenImport(true) }}>{transI18n("enka")} {transI18n("exportData")} downloadJson("freesr-data", converterToFreeSRJson( avatars, battle_type, moc_config, pf_config, as_config, ce_config, peak_config ) )}>{transI18n("freeSr")} downloadJson("database-data", { avatars: avatars, battle_type: battle_type, moc_config: moc_config, pf_config: pf_config, as_config: as_config, ce_config: ce_config, peak_config: peak_config })}>{transI18n("database")} { setIsOpenConnect(true) }} > {transI18n("connectSetting")} { setIsOpenMonster(true) }} className="px-3 py-1.5 hover:bg-base-200/70 rounded-lg transition-all duration-200" > {transI18n("monsterSetting")} {extraData && ( { setIsOpenExtra(true) }} className="px-3 py-1.5 hover:bg-base-200/70 rounded-lg transition-all duration-200" > {transI18n("extraSetting")} )} {/* Right side items */} {/* PS Connection Status Badge */} {isConnectPS && ( )} {isConnectPS ? transI18n("connected") : transI18n("unconnected")} {/* View Logs Button */} { setIsChangelog(true) }} > {/* Language selector */} {listCurrentLanguage[locale as keyof typeof listCurrentLanguage]?.flag || "EN"} {Object.entries(listCurrentLanguage).map(([key, value]) => ( { changeLocale(key); const elem = document.activeElement; if (elem instanceof HTMLElement) { elem.blur(); } }} > {value.flag} {value.label} ))} {/* Theme selector */} {themes.map((theme) => ( { if (changeTheme) changeTheme(theme.label.toLowerCase()); }} > {theme.label} ))} {/* Modals */} {modalConfigs?.map(({ id, title, onClose, content }) => ( {/* Modal Header */} {title} ✕ {/* Modal Body */} {content} close ))} ) }
Firefly Shelter