feat(wallet): bypass WalletConnect for TP/imToken on mobile to fix China users
Some checks failed
Deploy Staging (terry-wallet-login) / deploy (push) Failing after 40s
Some checks failed
Deploy Staging (terry-wallet-login) / deploy (push) Failing after 40s
The WalletConnect relay (wss://relay.walletconnect.org) is unreliable/blocked in mainland China. Every wallet flow (desktop QR, mobile deeplink, mobile QR) depends on it, so Chinese users see the login button hang forever and the QR code never appears. When RainbowKit's render fails, the whole site goes white because nothing catches the error. Changes: - Add WalletStackErrorBoundary around <RainbowWalletProvider> + modal so RainbowKit init failures no longer blank the entire app. - Hoist <WalletProvider> above the boundary; it only depends on the injected provider, so useWallet keeps working for header / favorites / etc. even when the WC stack is dead. - On mobile, the TP/imToken 'Open Wallet App' button now navigates directly to tpdapp://open / imtokenv2://navigate/DappView with an ?autoLogin=<kind> query, pulling the site into the wallet's in-app browser without ever touching the WC relay. MetaMask still uses the WC path (no equivalent deeplink). - Add AutoInjectedLogin: when the page loads with ?autoLogin=<kind>, wait up to 8s for window.ethereum, then connectInjectedWallet + completeLogin. Strips the param via history.replaceState to avoid re-firing on reload. - Guard against the in-app-browser disconnect/reconnect case: if getInjectedWallet(kind) is already truthy, skip the deeplink and let useWalletConnectLogin's deeplink mode take the injected fast path (avoids TP trying to open TP recursively).
This commit is contained in:
212
src/App.tsx
212
src/App.tsx
@@ -4,9 +4,11 @@ import { MotionProvider } from "./motion";
|
||||
import { ToastProvider } from "./components/Toast";
|
||||
import { SaveToAlbumGuideProvider } from "./components/SaveToAlbumGuide";
|
||||
import { FavoritesProvider } from "./favorites/FavoritesProvider";
|
||||
import { AutoInjectedLogin } from "./wallet/AutoInjectedLogin";
|
||||
import { RainbowWalletProvider } from "./wallet/RainbowWalletProvider";
|
||||
import { WalletLoginModal } from "./wallet/WalletLoginModal";
|
||||
import { WalletProvider } from "./wallet/WalletProvider";
|
||||
import { WalletStackErrorBoundary } from "./wallet/WalletStackErrorBoundary";
|
||||
import { PublicLayout } from "./layouts/PublicLayout";
|
||||
import { LocalizedHomePage } from "./pages/LocalizedHome";
|
||||
import { Browse } from "./pages/Browse";
|
||||
@@ -32,115 +34,113 @@ export default function App() {
|
||||
<I18nProvider>
|
||||
<MotionProvider>
|
||||
<ToastProvider>
|
||||
<RainbowWalletProvider>
|
||||
<WalletProvider>
|
||||
<FavoritesProvider>
|
||||
<SaveToAlbumGuideProvider>
|
||||
<AdminRouterModeProvider value="absolute">
|
||||
<ImageLightboxProvider>
|
||||
<VideoPlayerProvider>
|
||||
<PageTitleProvider>
|
||||
<WalletLoginModal />
|
||||
<BrowserRouter>
|
||||
<ScrollToTop />
|
||||
<Routes>
|
||||
<Route element={<PublicLayout />}>
|
||||
{/* English (root, no prefix) */}
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<LocalizedHomePage targetLang="en" />
|
||||
}
|
||||
/>
|
||||
<Route path="/browse" element={<Browse />} />
|
||||
<Route
|
||||
path="/categories"
|
||||
element={<CategoriesPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/official-recommendations"
|
||||
element={<OfficialRecommendationsPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/category/:slug"
|
||||
element={<CategoryPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/search"
|
||||
element={<SearchPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/resource/:id"
|
||||
element={<PostRedirect />}
|
||||
/>
|
||||
<Route
|
||||
path="/favorites"
|
||||
element={<Favorites />}
|
||||
/>
|
||||
|
||||
{/* Each non-English language gets its own nested tree. */}
|
||||
{localizedHomeRoutes.map((route) => (
|
||||
<Route key={route.path} path={route.path}>
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<LocalizedHomePage
|
||||
targetLang={route.lang}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route path="browse" element={<Browse />} />
|
||||
<Route
|
||||
path="categories"
|
||||
element={<CategoriesPage />}
|
||||
/>
|
||||
<Route
|
||||
path="official-recommendations"
|
||||
element={<OfficialRecommendationsPage />}
|
||||
/>
|
||||
<Route
|
||||
path="category/:slug"
|
||||
element={<CategoryPage />}
|
||||
/>
|
||||
<Route
|
||||
path="search"
|
||||
element={<SearchPage />}
|
||||
/>
|
||||
<Route
|
||||
path="resource/:id"
|
||||
element={<PostRedirect />}
|
||||
/>
|
||||
<Route
|
||||
path="favorites"
|
||||
element={<Favorites />}
|
||||
/>
|
||||
</Route>
|
||||
))}
|
||||
</Route>
|
||||
|
||||
{adminEnabled ? (
|
||||
AdminRouteTree()
|
||||
) : (
|
||||
<Route
|
||||
path={`${adminUiPrefix}/*`}
|
||||
element={<Navigate to="/" replace />}
|
||||
/>
|
||||
)}
|
||||
|
||||
<WalletProvider>
|
||||
<AutoInjectedLogin />
|
||||
<WalletStackErrorBoundary>
|
||||
<RainbowWalletProvider>
|
||||
<WalletLoginModal />
|
||||
</RainbowWalletProvider>
|
||||
</WalletStackErrorBoundary>
|
||||
<FavoritesProvider>
|
||||
<SaveToAlbumGuideProvider>
|
||||
<AdminRouterModeProvider value="absolute">
|
||||
<ImageLightboxProvider>
|
||||
<VideoPlayerProvider>
|
||||
<PageTitleProvider>
|
||||
<BrowserRouter>
|
||||
<ScrollToTop />
|
||||
<Routes>
|
||||
<Route element={<PublicLayout />}>
|
||||
{/* English (root, no prefix) */}
|
||||
<Route
|
||||
path="*"
|
||||
path="/"
|
||||
element={<LocalizedHomePage targetLang="en" />}
|
||||
/>
|
||||
<Route path="/browse" element={<Browse />} />
|
||||
<Route
|
||||
path="/categories"
|
||||
element={<CategoriesPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/official-recommendations"
|
||||
element={<OfficialRecommendationsPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/category/:slug"
|
||||
element={<CategoryPage />}
|
||||
/>
|
||||
<Route path="/search" element={<SearchPage />} />
|
||||
<Route
|
||||
path="/resource/:id"
|
||||
element={<PostRedirect />}
|
||||
/>
|
||||
<Route
|
||||
path="/favorites"
|
||||
element={<Favorites />}
|
||||
/>
|
||||
|
||||
{/* Each non-English language gets its own nested tree. */}
|
||||
{localizedHomeRoutes.map((route) => (
|
||||
<Route key={route.path} path={route.path}>
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<LocalizedHomePage
|
||||
targetLang={route.lang}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route path="browse" element={<Browse />} />
|
||||
<Route
|
||||
path="categories"
|
||||
element={<CategoriesPage />}
|
||||
/>
|
||||
<Route
|
||||
path="official-recommendations"
|
||||
element={<OfficialRecommendationsPage />}
|
||||
/>
|
||||
<Route
|
||||
path="category/:slug"
|
||||
element={<CategoryPage />}
|
||||
/>
|
||||
<Route
|
||||
path="search"
|
||||
element={<SearchPage />}
|
||||
/>
|
||||
<Route
|
||||
path="resource/:id"
|
||||
element={<PostRedirect />}
|
||||
/>
|
||||
<Route
|
||||
path="favorites"
|
||||
element={<Favorites />}
|
||||
/>
|
||||
</Route>
|
||||
))}
|
||||
</Route>
|
||||
|
||||
{adminEnabled ? (
|
||||
AdminRouteTree()
|
||||
) : (
|
||||
<Route
|
||||
path={`${adminUiPrefix}/*`}
|
||||
element={<Navigate to="/" replace />}
|
||||
/>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</PageTitleProvider>
|
||||
</VideoPlayerProvider>
|
||||
</ImageLightboxProvider>
|
||||
</AdminRouterModeProvider>
|
||||
</SaveToAlbumGuideProvider>
|
||||
</FavoritesProvider>
|
||||
</WalletProvider>
|
||||
</RainbowWalletProvider>
|
||||
)}
|
||||
|
||||
<Route
|
||||
path="*"
|
||||
element={<Navigate to="/" replace />}
|
||||
/>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</PageTitleProvider>
|
||||
</VideoPlayerProvider>
|
||||
</ImageLightboxProvider>
|
||||
</AdminRouterModeProvider>
|
||||
</SaveToAlbumGuideProvider>
|
||||
</FavoritesProvider>
|
||||
</WalletProvider>
|
||||
</ToastProvider>
|
||||
</MotionProvider>
|
||||
</I18nProvider>
|
||||
|
||||
Reference in New Issue
Block a user