feat: integrate site display type into pricing components
Add siteDisplayType prop across various pricing components to conditionally render pricing information based on the selected display type. This update enhances the user experience by ensuring that pricing details are accurately represented according to the chosen display mode, particularly for token-based views.
This commit is contained in:
35
web/src/hooks/common/useHeaderBar.js
vendored
35
web/src/hooks/common/useHeaderBar.js
vendored
@@ -150,7 +150,9 @@ export const useHeaderBar = ({ onMobileMenuToggle, drawerOpen }) => {
|
||||
const handleLanguageChange = useCallback(
|
||||
async (lang) => {
|
||||
// Change language immediately for responsive UX
|
||||
const previousLang = normalizeLanguage(i18n.language);
|
||||
i18n.changeLanguage(lang);
|
||||
localStorage.setItem('i18nextLng', lang);
|
||||
|
||||
// If user is logged in, save preference to backend
|
||||
if (userState?.user?.id) {
|
||||
@@ -159,25 +161,34 @@ export const useHeaderBar = ({ onMobileMenuToggle, drawerOpen }) => {
|
||||
language: lang,
|
||||
});
|
||||
if (res.data.success) {
|
||||
// Update user context with new setting
|
||||
// Keep user preference and local cache in sync so route changes
|
||||
// don't reapply an older remembered language.
|
||||
let settings = {};
|
||||
if (userState?.user?.setting) {
|
||||
try {
|
||||
const settings = JSON.parse(userState.user.setting);
|
||||
settings.language = lang;
|
||||
userDispatch({
|
||||
type: 'login',
|
||||
payload: {
|
||||
...userState.user,
|
||||
setting: JSON.stringify(settings),
|
||||
},
|
||||
});
|
||||
settings = JSON.parse(userState.user.setting) || {};
|
||||
} catch (e) {
|
||||
// Ignore parse errors
|
||||
settings = {};
|
||||
}
|
||||
}
|
||||
|
||||
settings.language = lang;
|
||||
const nextUser = {
|
||||
...userState.user,
|
||||
setting: JSON.stringify(settings),
|
||||
};
|
||||
|
||||
userDispatch({
|
||||
type: 'login',
|
||||
payload: nextUser,
|
||||
});
|
||||
localStorage.setItem('user', JSON.stringify(nextUser));
|
||||
}
|
||||
} catch (error) {
|
||||
// Silently ignore errors - language was already changed locally
|
||||
if (previousLang) {
|
||||
i18n.changeLanguage(previousLang);
|
||||
localStorage.setItem('i18nextLng', previousLang);
|
||||
}
|
||||
console.error('Failed to save language preference:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export const useModelPricingData = () => {
|
||||
[statusState],
|
||||
);
|
||||
|
||||
// 默认货币与站点展示类型同步(USD/CNY),TOKENS 时仍允许切换视图内货币
|
||||
// 默认货币与站点展示类型同步;TOKENS 由视图层走倍率展示
|
||||
const siteDisplayType = useMemo(
|
||||
() => statusState?.status?.quota_display_type || 'USD',
|
||||
[statusState],
|
||||
@@ -88,6 +88,13 @@ export const useModelPricingData = () => {
|
||||
}
|
||||
}, [siteDisplayType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (siteDisplayType === 'TOKENS') {
|
||||
setShowWithRecharge(false);
|
||||
setCurrency('USD');
|
||||
}
|
||||
}, [siteDisplayType]);
|
||||
|
||||
const filteredModels = useMemo(() => {
|
||||
let result = models;
|
||||
|
||||
@@ -356,6 +363,7 @@ export const useModelPricingData = () => {
|
||||
setCurrentPage,
|
||||
currency,
|
||||
setCurrency,
|
||||
siteDisplayType,
|
||||
showWithRecharge,
|
||||
setShowWithRecharge,
|
||||
tokenUnit,
|
||||
|
||||
@@ -152,7 +152,12 @@ export const useLogsData = () => {
|
||||
|
||||
const getInitialBillingDisplayMode = () => {
|
||||
const savedMode = localStorage.getItem(BILLING_DISPLAY_MODE_STORAGE_KEY);
|
||||
return savedMode === 'price' || savedMode === 'ratio' ? savedMode : 'price';
|
||||
if (savedMode === 'price' || savedMode === 'ratio') {
|
||||
return savedMode;
|
||||
}
|
||||
return localStorage.getItem('quota_display_type') === 'TOKENS'
|
||||
? 'ratio'
|
||||
: 'price';
|
||||
};
|
||||
|
||||
// Column visibility state
|
||||
|
||||
Reference in New Issue
Block a user