feat(sidebar): show free chat allowance
This commit is contained in:
@@ -13,6 +13,10 @@ import { BackButton } from "@/app/_components";
|
|||||||
import { MobileShell } from "@/app/_components/core";
|
import { MobileShell } from "@/app/_components/core";
|
||||||
import { ROUTES } from "@/router/routes";
|
import { ROUTES } from "@/router/routes";
|
||||||
|
|
||||||
|
import {
|
||||||
|
FREE_PRIVATE_MESSAGE_LABEL,
|
||||||
|
FREE_STANDARD_CHAT_LABEL,
|
||||||
|
} from "./coins-rules.constants";
|
||||||
import styles from "./coins-rules-screen.module.css";
|
import styles from "./coins-rules-screen.module.css";
|
||||||
|
|
||||||
interface CoinRuleItem {
|
interface CoinRuleItem {
|
||||||
@@ -26,13 +30,13 @@ const COIN_RULES: readonly CoinRuleItem[] = [
|
|||||||
{
|
{
|
||||||
title: "Standard Chat",
|
title: "Standard Chat",
|
||||||
cost: "2 coins / message",
|
cost: "2 coins / message",
|
||||||
free: "50 free messages weekly",
|
free: FREE_STANDARD_CHAT_LABEL,
|
||||||
icon: MessageCircle,
|
icon: MessageCircle,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Private Chat",
|
title: "Private Chat",
|
||||||
cost: "10 coins / message",
|
cost: "10 coins / message",
|
||||||
free: "1 free message daily",
|
free: FREE_PRIVATE_MESSAGE_LABEL,
|
||||||
icon: Sparkles,
|
icon: Sparkles,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -92,8 +96,8 @@ export function CoinsRulesScreen() {
|
|||||||
<div>
|
<div>
|
||||||
<h2 className={styles.freeTitle}>Free Allowance</h2>
|
<h2 className={styles.freeTitle}>Free Allowance</h2>
|
||||||
<p className={styles.freeText}>
|
<p className={styles.freeText}>
|
||||||
Standard chat includes 50 free messages weekly. Private chat
|
Standard chat includes {FREE_STANDARD_CHAT_LABEL}. Private chat
|
||||||
includes 1 free message daily.
|
includes {FREE_PRIVATE_MESSAGE_LABEL}.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const FREE_STANDARD_CHAT_DAILY_COUNT = 30;
|
||||||
|
export const FREE_PRIVATE_MESSAGE_DAILY_COUNT = 2;
|
||||||
|
|
||||||
|
export const FREE_STANDARD_CHAT_LABEL = `${FREE_STANDARD_CHAT_DAILY_COUNT} free messages daily`;
|
||||||
|
export const FREE_PRIVATE_MESSAGE_LABEL = `${FREE_PRIVATE_MESSAGE_DAILY_COUNT} free private messages daily`;
|
||||||
@@ -106,6 +106,53 @@
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.freeAllowance {
|
||||||
|
display: flex;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--spacing-md, 12px);
|
||||||
|
margin-top: clamp(2px, 0.741vw, 4px);
|
||||||
|
padding: clamp(10px, 2.222vw, 12px) clamp(12px, 2.963vw, 16px);
|
||||||
|
border: 1px solid rgba(246, 87, 160, 0.12);
|
||||||
|
border-radius: var(--responsive-card-radius-sm, 18px);
|
||||||
|
background: rgba(255, 255, 255, 0.72);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.78);
|
||||||
|
}
|
||||||
|
|
||||||
|
.freeAllowanceTitle {
|
||||||
|
margin: 0;
|
||||||
|
color: #6d5d64;
|
||||||
|
font-size: var(--responsive-caption, 13px);
|
||||||
|
font-weight: 820;
|
||||||
|
line-height: 1.2;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.freeAllowanceItems {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: clamp(8px, 1.852vw, 10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.freeAllowanceItem {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 3px;
|
||||||
|
color: #51464b;
|
||||||
|
font-size: var(--responsive-caption, 13px);
|
||||||
|
font-weight: 720;
|
||||||
|
line-height: 1.2;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.freeAllowanceItem strong {
|
||||||
|
color: #f657a0;
|
||||||
|
font-size: var(--responsive-body, 16px);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
.activateButton,
|
.activateButton,
|
||||||
.topUpButton {
|
.topUpButton {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -186,4 +233,13 @@
|
|||||||
.rulesButton {
|
.rulesButton {
|
||||||
font-size: var(--responsive-body, 14px);
|
font-size: var(--responsive-body, 14px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.freeAllowance {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.freeAllowanceItems {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
import { FaCoins } from "react-icons/fa6";
|
import { FaCoins } from "react-icons/fa6";
|
||||||
|
|
||||||
|
import {
|
||||||
|
FREE_PRIVATE_MESSAGE_DAILY_COUNT,
|
||||||
|
FREE_STANDARD_CHAT_DAILY_COUNT,
|
||||||
|
} from "@/app/coins-rules/coins-rules.constants";
|
||||||
|
|
||||||
import styles from "./sidebar-wallet-card.module.css";
|
import styles from "./sidebar-wallet-card.module.css";
|
||||||
|
|
||||||
export interface SidebarWalletCardProps {
|
export interface SidebarWalletCardProps {
|
||||||
@@ -58,6 +63,20 @@ export function SidebarWalletCard({
|
|||||||
Top Up
|
Top Up
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.freeAllowance} aria-label="Free allowance">
|
||||||
|
<p className={styles.freeAllowanceTitle}>Free Allowance</p>
|
||||||
|
<div className={styles.freeAllowanceItems}>
|
||||||
|
<span className={styles.freeAllowanceItem}>
|
||||||
|
<strong>{FREE_STANDARD_CHAT_DAILY_COUNT}</strong>
|
||||||
|
<span> chats / day</span>
|
||||||
|
</span>
|
||||||
|
<span className={styles.freeAllowanceItem}>
|
||||||
|
<strong>{FREE_PRIVATE_MESSAGE_DAILY_COUNT}</strong>
|
||||||
|
<span> private / day</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { useEffect } from "react";
|
|||||||
|
|
||||||
import { MobileShell } from "@/app/_components/core";
|
import { MobileShell } from "@/app/_components/core";
|
||||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||||
import { useAuthState } from "@/stores/auth/auth-context";
|
|
||||||
import { pwaUtil } from "@/utils";
|
import { pwaUtil } from "@/utils";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -15,8 +14,6 @@ import {
|
|||||||
} from "./components";
|
} from "./components";
|
||||||
import styles from "./components/splash-screen.module.css";
|
import styles from "./components/splash-screen.module.css";
|
||||||
|
|
||||||
const AUTO_OPEN_CHAT_DELAY_MS = 1800;
|
|
||||||
|
|
||||||
// 尽量早地缓存 beforeinstallprompt,避免用户停留 splash 时浏览器事件已触发并丢失。
|
// 尽量早地缓存 beforeinstallprompt,避免用户停留 splash 时浏览器事件已触发并丢失。
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
pwaUtil.prepareInstallPrompt();
|
pwaUtil.prepareInstallPrompt();
|
||||||
@@ -24,7 +21,6 @@ if (typeof window !== "undefined") {
|
|||||||
|
|
||||||
export function SplashScreen() {
|
export function SplashScreen() {
|
||||||
const navigator = useAppNavigator();
|
const navigator = useAppNavigator();
|
||||||
const state = useAuthState();
|
|
||||||
|
|
||||||
const handleStartChat = () => {
|
const handleStartChat = () => {
|
||||||
navigator.openChat({ replace: true });
|
navigator.openChat({ replace: true });
|
||||||
@@ -34,14 +30,6 @@ export function SplashScreen() {
|
|||||||
pwaUtil.prepareInstallPrompt();
|
pwaUtil.prepareInstallPrompt();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = window.setTimeout(() => {
|
|
||||||
navigator.openChat({ replace: true });
|
|
||||||
}, AUTO_OPEN_CHAT_DELAY_MS);
|
|
||||||
|
|
||||||
return () => window.clearTimeout(timer);
|
|
||||||
}, [navigator]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MobileShell background="var(--color-sidebar-background)">
|
<MobileShell background="var(--color-sidebar-background)">
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
|
|||||||
Reference in New Issue
Block a user