refactor(sidebar): split state derivation
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Download, LogOut } from "lucide-react";
|
||||
import { signOut } from "next-auth/react";
|
||||
|
||||
@@ -10,61 +9,23 @@ import { ROUTES } from "@/router/routes";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
||||
import { useUserDispatch, useUserState } from "@/stores/user/user-context";
|
||||
import { pwaUtil } from "@/utils";
|
||||
|
||||
import {
|
||||
SidebarWalletCard,
|
||||
UserHeader,
|
||||
type SidebarUserState,
|
||||
} from "./components";
|
||||
import { SidebarWalletCard, UserHeader } from "./components";
|
||||
import { getSidebarViewModel } from "./sidebar-view-model";
|
||||
import { usePwaInstallEntry } from "./use-pwa-install-entry";
|
||||
import { useSidebarUserBootstrap } from "./use-sidebar-user-bootstrap";
|
||||
|
||||
import styles from "./components/sidebar-screen.module.css";
|
||||
|
||||
const FALLBACK_USERNAME = "User name";
|
||||
|
||||
export function SidebarScreen() {
|
||||
const navigator = useAppNavigator();
|
||||
const user = useUserState();
|
||||
const userDispatch = useUserDispatch();
|
||||
const auth = useAuthState();
|
||||
const authDispatch = useAuthDispatch();
|
||||
const [canShowInstallApp, setCanShowInstallApp] = useState(false);
|
||||
const pwaInstallEntry = usePwaInstallEntry();
|
||||
|
||||
useEffect(() => {
|
||||
if (!auth.hasInitialized || auth.isLoading) return;
|
||||
if (auth.loginStatus === "notLoggedIn") return;
|
||||
|
||||
userDispatch({ type: "UserFetch" });
|
||||
}, [
|
||||
auth.hasInitialized,
|
||||
auth.isLoading,
|
||||
auth.loginStatus,
|
||||
userDispatch,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const updateInstallEntryVisibility = () => {
|
||||
setCanShowInstallApp(pwaUtil.canShowInstallEntry());
|
||||
};
|
||||
|
||||
pwaUtil.prepareInstallPrompt();
|
||||
updateInstallEntryVisibility();
|
||||
const unsubscribe = pwaUtil.subscribe(updateInstallEntryVisibility);
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleInstallAppClick = async () => {
|
||||
pwaUtil.prepareInstallPrompt();
|
||||
const result = await pwaUtil.install();
|
||||
setCanShowInstallApp(
|
||||
result !== "accepted" &&
|
||||
!pwaUtil.isInstalled() &&
|
||||
pwaUtil.canShowInstallEntry(),
|
||||
);
|
||||
};
|
||||
useSidebarUserBootstrap({ auth, userDispatch });
|
||||
|
||||
const handleLogoutClick = () => {
|
||||
userDispatch({ type: "UserClearLocal" });
|
||||
@@ -73,19 +34,11 @@ export function SidebarScreen() {
|
||||
navigator.replace(ROUTES.splash, { scroll: false });
|
||||
};
|
||||
|
||||
// 状态派生:未登录 / 已登录未 VIP / 已登录 VIP
|
||||
const sidebarState: SidebarUserState =
|
||||
auth.loginStatus === "notLoggedIn"
|
||||
? "guest"
|
||||
: user.currentUser?.isVip === true
|
||||
? "vip"
|
||||
: "member";
|
||||
const view = getSidebarViewModel({
|
||||
loginStatus: auth.loginStatus,
|
||||
user,
|
||||
});
|
||||
|
||||
const isInitializingUser =
|
||||
sidebarState !== "guest" && user.currentUser == null;
|
||||
|
||||
const name = user.currentUser?.username ?? FALLBACK_USERNAME;
|
||||
const avatarUrl = user.avatarUrl;
|
||||
return (
|
||||
<MobileShell background="#fcf3f4">
|
||||
<div className={styles.shell}>
|
||||
@@ -98,42 +51,40 @@ export function SidebarScreen() {
|
||||
|
||||
<section className={`${styles.userSlot} ${styles.revealOne}`}>
|
||||
<UserHeader
|
||||
state={sidebarState}
|
||||
name={name}
|
||||
avatarUrl={avatarUrl}
|
||||
isLoading={isInitializingUser}
|
||||
state={view.state}
|
||||
name={view.name}
|
||||
avatarUrl={view.avatarUrl}
|
||||
isLoading={view.isInitializingUser}
|
||||
onLoginClick={() => navigator.openAuth(ROUTES.sidebar)}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className={`${styles.cardSlot} ${styles.revealTwo}`}>
|
||||
<SidebarWalletCard
|
||||
creditBalance={user.creditBalance}
|
||||
dailyFreeChatLimit={user.currentUser?.dailyFreeChatLimit}
|
||||
dailyFreeChatRemaining={user.currentUser?.dailyFreeChatRemaining}
|
||||
dailyFreePrivateLimit={user.currentUser?.dailyFreePrivateLimit}
|
||||
dailyFreePrivateRemaining={
|
||||
user.currentUser?.dailyFreePrivateRemaining
|
||||
}
|
||||
creditBalance={view.wallet.creditBalance}
|
||||
dailyFreeChatLimit={view.wallet.dailyFreeChatLimit}
|
||||
dailyFreeChatRemaining={view.wallet.dailyFreeChatRemaining}
|
||||
dailyFreePrivateLimit={view.wallet.dailyFreePrivateLimit}
|
||||
dailyFreePrivateRemaining={view.wallet.dailyFreePrivateRemaining}
|
||||
onActivateVip={
|
||||
sidebarState === "vip"
|
||||
? undefined
|
||||
: () => navigator.openSubscription({ type: "vip" })
|
||||
view.canActivateVip
|
||||
? () => navigator.openSubscription({ type: "vip" })
|
||||
: undefined
|
||||
}
|
||||
onTopUp={() => navigator.openSubscription({ type: "topup" })}
|
||||
onRulesClick={() => navigator.push(ROUTES.coinsRules)}
|
||||
/>
|
||||
</section>
|
||||
|
||||
{sidebarState !== "guest" ? (
|
||||
{view.canShowSettings ? (
|
||||
<section className={`${styles.settingsSlot} ${styles.revealThree}`}>
|
||||
<p className={styles.settingsLabel}>Other</p>
|
||||
<div className={styles.settingsActions}>
|
||||
{canShowInstallApp ? (
|
||||
{pwaInstallEntry.canInstall ? (
|
||||
<button
|
||||
type="button"
|
||||
className={`${styles.logoutCard} ${styles.installCard}`}
|
||||
onClick={() => void handleInstallAppClick()}
|
||||
onClick={() => void pwaInstallEntry.installApp()}
|
||||
>
|
||||
<span
|
||||
className={`${styles.logoutIcon} ${styles.installIcon}`}
|
||||
|
||||
Reference in New Issue
Block a user