feat(sidebar): show user info with three-state UI (guest/member/vip)

Sidebar screen now primarily displays user-related information
and derives three render states from loginStatus + currentUser.isVip:

- guest (notLoggedIn): welcome panel + Sign in / Sign up entries
- member (logged in, no VIP): user info card + Get VIP CTA + Log out
- vip (logged in, VIP): user info card with VIP badge + Manage VIP CTA
  + Log out

Adds UserView.isVip (default false), patches user-machine.toView()
to populate it, and introduces three presentational components
(GuestPanel, UserInfoCard, VipCta) co-located under src/app/sidebar.

Preserves existing UserInit + logout-redirect behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-15 17:52:52 +08:00
parent 1449acd6c9
commit fd5dfe2715
9 changed files with 466 additions and 21 deletions
+2 -2
View File
@@ -22,7 +22,7 @@ import { GuestChatQuota as GuestChatQuotaDto } from "@/data/dto/chat/guest_chat_
import { z } from "zod";
import { type Result as ResultT, Result } from "@/utils/result";
import { formatDate } from "@/utils/date";
import { todayString } from "@/utils/date";
import { SpAsyncUtil } from "@/utils/storage";
import { StorageKeys } from "../storage_keys";
import type { IChatStorage } from "./ichat_storage";
@@ -51,7 +51,7 @@ export class ChatStorage implements IChatStorage {
if (existing.success && existing.data != null) {
return existing;
}
const today = formatDate(new Date());
const today = todayString(new Date());
const initResult = await this.setGuestDailyChatQuota(
GuestChatQuotaDto.threshold,
today,