Commit 2ec6f4fd authored by ThinhNC's avatar ThinhNC

fix(router): support standalone web basename and fallback api url on vercel

parent 98465e1f
Pipeline #53708 passed with stage
in 35 seconds
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.84.0", "react-hook-form": "^7.84.0",
"react-router-dom": "^6.30.4",
"zmp-sdk": "latest", "zmp-sdk": "latest",
"zmp-ui": "latest", "zmp-ui": "latest",
"zod": "^4.4.3", "zod": "^4.4.3",
......
...@@ -29,6 +29,9 @@ importers: ...@@ -29,6 +29,9 @@ importers:
react-hook-form: react-hook-form:
specifier: ^7.84.0 specifier: ^7.84.0
version: 7.84.0(react@18.3.1) version: 7.84.0(react@18.3.1)
react-router-dom:
specifier: ^6.30.4
version: 6.30.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
zmp-sdk: zmp-sdk:
specifier: latest specifier: latest
version: 2.52.2(@babel/core@7.29.7) version: 2.52.2(@babel/core@7.29.7)
......
...@@ -4,9 +4,9 @@ import { ...@@ -4,9 +4,9 @@ import {
App, App,
Route, Route,
SnackbarProvider, SnackbarProvider,
ZMPRouter,
useNavigate, useNavigate,
} from "zmp-ui"; } from "zmp-ui";
import { ZMPRouter } from "@/components/router/ZMPRouter";
import { QueryClientProvider } from "@tanstack/react-query"; import { QueryClientProvider } from "@tanstack/react-query";
import { queryClient } from "@/lib/query-client"; import { queryClient } from "@/lib/query-client";
import { useAuthStore, GUEST_STORAGE_KEY } from "@/stores/auth-store"; import { useAuthStore, GUEST_STORAGE_KEY } from "@/stores/auth-store";
......
import React, { useCallback, useMemo, useRef, useState } from "react";
import { BrowserRouter, MemoryRouter } from "react-router-dom";
export interface AnimationRouterContextType {
animate: boolean;
direction: string;
setAnimate: (config: { animate?: boolean; direction?: string }) => void;
pageScrollPosition: Record<string, number>;
updatePosition: (key: string, position: number) => void;
}
export const AnimationRouterContext = React.createContext<AnimationRouterContextType | undefined>(undefined);
export interface ZMPRouterProps {
children?: React.ReactNode;
memoryRouter?: boolean;
}
const PAGE_TRANSITION_FORWARD = "forward";
const PAGE_TRANSITION_BACKWARD = "backward";
export const ZMPRouter: React.FC<ZMPRouterProps> = (props) => {
const [animate, setAnimate] = useState(true);
const [direction, setDirection] = useState(PAGE_TRANSITION_FORWARD);
const pageScrollPosition = useRef<Record<string, number>>({});
const { children, memoryRouter } = props;
// Determine basepath safely:
// Inside Zalo webview, the path begins with `/zapps/<APP_ID>`.
// On Vercel / standalone web, use "" so all standard routes (/, /login, etc.) match.
const win = typeof window !== "undefined" ? (window as unknown as Record<string, unknown>) : null;
let basepath = (win?.BASE_PATH as string) || "";
const pathname = typeof window !== "undefined" ? window.location.pathname : "";
const appId = (win?.APP_ID as string) || "";
if (pathname.startsWith("/zapps/") && appId) {
basepath = `/zapps/${appId}`;
} else if (!basepath) {
basepath = "";
}
const handleSetAnimate = useCallback(
({ animate: ani = true, direction: dir = PAGE_TRANSITION_FORWARD }: { animate?: boolean; direction?: string }) => {
setAnimate(Boolean(ani));
const correctDirection = [PAGE_TRANSITION_FORWARD, PAGE_TRANSITION_BACKWARD].includes(dir)
? dir
: PAGE_TRANSITION_FORWARD;
setDirection(correctDirection);
},
[]
);
const updateScrollPosition = (key: string, position: number) => {
pageScrollPosition.current[key] = position;
};
const contextValue = useMemo(
() => ({
setAnimate: handleSetAnimate,
animate,
direction,
pageScrollPosition: pageScrollPosition.current,
updatePosition: updateScrollPosition,
}),
[animate, direction, handleSetAnimate]
);
const RouterComponent = memoryRouter ? MemoryRouter : BrowserRouter;
const routerProps = memoryRouter ? { initialEntries: [basepath || "/"] } : {};
return (
<AnimationRouterContext.Provider value={contextValue}>
<RouterComponent basename={basepath} {...routerProps}>
{children}
</RouterComponent>
</AnimationRouterContext.Provider>
);
};
export default ZMPRouter;
...@@ -2,7 +2,8 @@ import axios from "axios"; ...@@ -2,7 +2,8 @@ import axios from "axios";
import { useAuthStore } from "@/stores/auth-store"; import { useAuthStore } from "@/stores/auth-store";
import { safeStorage } from "@/lib/storage"; import { safeStorage } from "@/lib/storage";
export const API_BASE_URL = import.meta.env.VITE_API_URL || "http://localhost:7777/api/v1"; export const API_BASE_URL =
import.meta.env.VITE_API_URL || "https://finwise-miniapp-be-wc86.onrender.com/api/v1";
const apiBaseUrl = API_BASE_URL; const apiBaseUrl = API_BASE_URL;
// Create an Axios instance // Create an Axios instance
......
...@@ -12,9 +12,13 @@ export default () => { ...@@ -12,9 +12,13 @@ export default () => {
assetsInlineLimit: 0, assetsInlineLimit: 0,
}, },
resolve: { resolve: {
alias: { alias: [
"@": path.resolve(__dirname, "./src"), { find: "@", replacement: path.resolve(__dirname, "./src") },
{
find: /.*\/components\/router\/ZMPRouter(\.js)?$/,
replacement: path.resolve(__dirname, "./src/components/router/ZMPRouter.tsx"),
}, },
],
}, },
}); });
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment