feat: redesign wallet login and favorites, fix desktop/mobile bugs
- Remove forced BNB chain switch on injected login (signature is chain-agnostic) - Refine isMobileDevice so touch Macs stay on desktop flow - Wire RainbowKit/WalletConnect as a real MetaMask/imToken QR fallback, gated on a valid VITE_WALLETCONNECT_PROJECT_ID - Rebuild login modal: single desktop primary action, collapsible other methods, mobile open-app fallback feedback, brand icons - Add My Favorites entry points (header, mobile menu, wallet dropdown) - Favorites page: error retry, mobile filter drawer - Auto sign-out and re-login prompt on favorites 401 - Full native translations for all wallet strings across 7 locales Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,12 @@ import {
|
||||
import { useToast } from "../components/Toast";
|
||||
import { useI18n } from "../i18n";
|
||||
import { useWallet } from "../wallet/WalletProvider";
|
||||
import { addFavorite, getFavoriteIds, removeFavorite } from "./api";
|
||||
import {
|
||||
addFavorite,
|
||||
getFavoriteIds,
|
||||
isFavoritesAuthError,
|
||||
removeFavorite,
|
||||
} from "./api";
|
||||
|
||||
type FavoriteStatus = "unknown" | "favorited" | "notFavorited";
|
||||
|
||||
@@ -30,7 +35,13 @@ export function FavoritesProvider({ children }: { children: ReactNode }) {
|
||||
const { t } = useI18n();
|
||||
const { showToast } = useToast();
|
||||
const wallet = useWallet();
|
||||
const { address, openLoginModal, status, token } = wallet;
|
||||
const { address, logout, openLoginModal, status, token } = wallet;
|
||||
|
||||
const handleAuthError = useCallback(() => {
|
||||
logout();
|
||||
openLoginModal();
|
||||
showToast(t("favoriteSessionExpired"));
|
||||
}, [logout, openLoginModal, showToast, t]);
|
||||
const [favoriteIds, setFavoriteIds] = useState<Set<string>>(() => new Set());
|
||||
const [knownIds, setKnownIds] = useState<Set<string>>(() => new Set());
|
||||
const [pendingIds, setPendingIds] = useState<Set<string>>(() => new Set());
|
||||
@@ -113,6 +124,8 @@ export function FavoritesProvider({ children }: { children: ReactNode }) {
|
||||
ids.forEach((id) => next.add(id));
|
||||
return next;
|
||||
});
|
||||
} catch (error) {
|
||||
if (isFavoritesAuthError(error)) handleAuthError();
|
||||
} finally {
|
||||
requestIds.forEach((id) => inFlightIdsRef.current.delete(id));
|
||||
if (queuedIdsRef.current.size > 0 && batchTimerRef.current === null) {
|
||||
@@ -122,7 +135,7 @@ export function FavoritesProvider({ children }: { children: ReactNode }) {
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
}, [handleAuthError]);
|
||||
|
||||
const ensureFavoriteIds = useCallback(
|
||||
async (resourceIds: string[]) => {
|
||||
@@ -158,7 +171,8 @@ export function FavoritesProvider({ children }: { children: ReactNode }) {
|
||||
);
|
||||
} catch (error) {
|
||||
markFavorite(resourceId, currentlyFavorite);
|
||||
showToast(t("favoriteFailed"), "error");
|
||||
if (isFavoritesAuthError(error)) handleAuthError();
|
||||
else showToast(t("favoriteFailed"), "error");
|
||||
throw error;
|
||||
} finally {
|
||||
setPendingIds((prev) => {
|
||||
@@ -168,7 +182,7 @@ export function FavoritesProvider({ children }: { children: ReactNode }) {
|
||||
});
|
||||
}
|
||||
},
|
||||
[favoriteIds, markFavorite, showToast, t, token],
|
||||
[favoriteIds, handleAuthError, markFavorite, showToast, t, token],
|
||||
);
|
||||
|
||||
const toggleFavorite = useCallback(
|
||||
|
||||
Reference in New Issue
Block a user