diff --git a/src/components/form/Dropdown.tsx b/src/components/form/Dropdown.tsx index f0427428..d4127fa9 100644 --- a/src/components/form/Dropdown.tsx +++ b/src/components/form/Dropdown.tsx @@ -13,9 +13,12 @@ interface DropdownProps { selectedItem: OptionItem; setSelectedItem: (value: OptionItem) => void; options: Array; + direction?: "up" | "down"; } export function Dropdown(props: DropdownProps) { + const { direction = "down" } = props; + return (
@@ -31,7 +34,7 @@ export function Dropdown(props: DropdownProps) { @@ -41,7 +44,9 @@ export function Dropdown(props: DropdownProps) { leaveFrom="opacity-100" leaveTo="opacity-0" > - + {props.options.map((opt) => ( diff --git a/src/pages/onboarding/Onboarding.tsx b/src/pages/onboarding/Onboarding.tsx index 8a15f639..f05b3c05 100644 --- a/src/pages/onboarding/Onboarding.tsx +++ b/src/pages/onboarding/Onboarding.tsx @@ -3,6 +3,7 @@ import { Trans, useTranslation } from "react-i18next"; import { Button } from "@/components/buttons/Button"; import { Toggle } from "@/components/buttons/Toggle"; +import { Dropdown } from "@/components/form/Dropdown"; import { Icon, Icons } from "@/components/Icon"; import { SettingsCard } from "@/components/layout/SettingsCard"; import { Stepper } from "@/components/layout/Stepper"; @@ -36,6 +37,7 @@ import { import { PageTitle } from "@/pages/parts/util/PageTitle"; import { conf } from "@/setup/config"; import { useAuthStore } from "@/stores/auth"; +import { Region, useRegionStore } from "@/utils/detectRegion"; import { getProxyUrls } from "@/utils/proxyUrls"; import { Status, testFebboxToken } from "../parts/settings/SetupPart"; @@ -53,6 +55,7 @@ export function FEDAPISetup() { const [isExpanded, setIsExpanded] = useState(false); const febboxToken = useAuthStore((s) => s.febboxToken); const setFebboxToken = useAuthStore((s) => s.setFebboxToken); + const { region, setRegion } = useRegionStore(); const [status, setStatus] = useState("unset"); const statusMap: Record = { @@ -61,6 +64,14 @@ export function FEDAPISetup() { unset: "noresult", }; + const regionOptions = [ + { id: "us-east", name: "US East" }, + { id: "us-west", name: "US West" }, + { id: "south-america", name: "South America" }, + { id: "asia", name: "Asia" }, + { id: "europe", name: "Europe" }, + ]; + useEffect(() => { const checkTokenStatus = async () => { const result = await getFebboxTokenStatus(febboxToken); @@ -165,6 +176,21 @@ export function FEDAPISetup() { passwordToggleable className="flex-grow" /> +
+ r.id === region)?.name || + "US East", + }} + setSelectedItem={(item) => + setRegion(item.id as Region, true) + } + direction="up" + /> +
{status === "error" && (

diff --git a/src/pages/parts/settings/ConnectionsPart.tsx b/src/pages/parts/settings/ConnectionsPart.tsx index ddfaa2a5..602737dd 100644 --- a/src/pages/parts/settings/ConnectionsPart.tsx +++ b/src/pages/parts/settings/ConnectionsPart.tsx @@ -9,6 +9,7 @@ import { Trans, useTranslation } from "react-i18next"; import { Button } from "@/components/buttons/Button"; import { Toggle } from "@/components/buttons/Toggle"; +import { Dropdown } from "@/components/form/Dropdown"; import { Icon, Icons } from "@/components/Icon"; import { SettingsCard } from "@/components/layout/SettingsCard"; import { @@ -26,6 +27,7 @@ import { } from "@/pages/parts/settings/SetupPart"; import { conf } from "@/setup/config"; import { useAuthStore } from "@/stores/auth"; +import { Region, useRegionStore } from "@/utils/detectRegion"; interface ProxyEditProps { proxyUrls: string[] | null; @@ -229,6 +231,7 @@ async function getFebboxTokenStatus(febboxToken: string | null) { function FebboxTokenEdit({ febboxToken, setFebboxToken }: FebboxTokenProps) { const { t } = useTranslation(); const [showVideo, setShowVideo] = useState(false); + const { region, setRegion } = useRegionStore(); const [status, setStatus] = useState("unset"); const statusMap: Record = { @@ -237,6 +240,14 @@ function FebboxTokenEdit({ febboxToken, setFebboxToken }: FebboxTokenProps) { unset: "noresult", }; + const regionOptions = [ + { id: "us-east", name: "US East" }, + { id: "us-west", name: "US West" }, + { id: "south-america", name: "South America" }, + { id: "asia", name: "Asia" }, + { id: "europe", name: "Europe" }, + ]; + useEffect(() => { const checkTokenStatus = async () => { const result = await getFebboxTokenStatus(febboxToken); @@ -337,6 +348,19 @@ function FebboxTokenEdit({ febboxToken, setFebboxToken }: FebboxTokenProps) { passwordToggleable className="flex-grow" /> +

+ r.id === region)?.name || + "US East", + }} + setSelectedItem={(item) => setRegion(item.id as Region, true)} + direction="up" + /> +
{status === "error" && (

diff --git a/src/utils/detectRegion.tsx b/src/utils/detectRegion.tsx index 4b77dbf7..6423c91f 100644 --- a/src/utils/detectRegion.tsx +++ b/src/utils/detectRegion.tsx @@ -12,18 +12,22 @@ export type Region = interface RegionStore { region: Region | null; lastChecked: number | null; - setRegion: (region: Region) => void; + userPicked: boolean; + setRegion: (region: Region, userPicked?: boolean) => void; } // const TEN_DAYS_MS = 10 * 24 * 60 * 60 * 1000; -const THIRTY_MINUTES_MS = 30 * 60 * 1000; +const ONE_DAY_MS = 24 * 60 * 60 * 1000; +// const THIRTY_MINUTES_MS = 30 * 60 * 1000; export const useRegionStore = create()( persist( (set) => ({ region: null, lastChecked: null, - setRegion: (region) => set({ region, lastChecked: Date.now() }), + userPicked: false, + setRegion: (region, userPicked = false) => + set({ region, lastChecked: Date.now(), userPicked }), }), { name: "__MW::region", @@ -48,10 +52,16 @@ function determineRegion(data: { export async function detectRegion(): Promise { const store = useRegionStore.getState(); + // If user picked a region, always return that + if (store.userPicked && store.region) { + return store.region; + } + + // If we have a recent detection, return that if ( store.region && store.lastChecked && - Date.now() - store.lastChecked < THIRTY_MINUTES_MS + Date.now() - store.lastChecked < ONE_DAY_MS ) { return store.region; } @@ -61,7 +71,9 @@ export async function detectRegion(): Promise { const data = await response.json(); const detectedRegion = determineRegion(data); - store.setRegion(detectedRegion); // Persist the detected region + if (!store.userPicked) { + store.setRegion(detectedRegion); // Only update if not user picked + } return detectedRegion; } catch (error) { console.warn("Failed to detect region:", error);