update summary,

This commit is contained in:
louiscklaw
2025-04-24 02:06:05 +08:00
parent da08798b10
commit d81b3e9a9e
5 changed files with 169 additions and 15 deletions

View File

@@ -1,11 +1,10 @@
'use client';
/*
# PROMPT
RULES:
this is a subset of a typescript project
clone `LessonTypeCount`, `LessonCategoriesCount` to `UserCount` and do modifiy to get the count of users, thanks.
show loading when fetching record from db
show error when fetch record failed
*/
import * as React from 'react';
import getAllUserMetasCount from '@/db/UserMetas/GetAllCount';
@@ -15,6 +14,7 @@ import { useTranslation } from 'react-i18next';
import { Summary } from '@/components/dashboard/overview/summary';
import { LoadingSummary } from '../LoadingSummary';
import { ErrorSummary } from '../ErrorSummary';
function ActiveUserCount(): React.JSX.Element {
const { t } = useTranslation();
@@ -50,7 +50,15 @@ function ActiveUserCount(): React.JSX.Element {
);
}
if (showError) return <div>{errorDetail}</div>;
if (showError)
return (
<ErrorSummary
diff={10}
icon={UsersIcon}
title={t('用戶數量')}
trend="up"
/>
);
return (
<Summary

View File

@@ -0,0 +1,99 @@
'use client';
/*
# NOTES:
Show error to user when loading error,
use together with:
- src/components/dashboard/overview/summary/ActiveUserCount/index.tsx
*/
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Divider from '@mui/material/Divider';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import type { Icon } from '@phosphor-icons/react/dist/lib/types';
import { TrendDown as TrendDownIcon } from '@phosphor-icons/react/dist/ssr/TrendDown';
import { TrendUp as TrendUpIcon } from '@phosphor-icons/react/dist/ssr/TrendUp';
import { useTranslation } from 'react-i18next';
export interface SummaryProps {
diff: number;
icon: Icon;
title: string;
trend: 'up' | 'down';
}
export function ErrorSummary({ diff, icon: Icon, title, trend }: SummaryProps): React.JSX.Element {
const { t } = useTranslation();
return (
<Card>
<CardContent>
<Stack
direction="row"
spacing={3}
sx={{ alignItems: 'center' }}
>
<Avatar
sx={{
'--Avatar-size': '48px',
bgcolor: 'var(--mui-palette-background-paper)',
boxShadow: 'var(--mui-shadows-8)',
color: 'var(--mui-palette-text-primary)',
}}
>
<Icon fontSize="var(--icon-fontSize-lg)" />
</Avatar>
<div>
<Typography
color="text.secondary"
variant="body1"
>
{title}
</Typography>
<Typography variant="h3">Error</Typography>
</div>
</Stack>
</CardContent>
<Divider />
<Box sx={{ p: '16px' }}>
<Stack
direction="row"
spacing={1}
sx={{ alignItems: 'center' }}
>
<Box
sx={{
alignItems: 'center',
color: trend === 'up' ? 'var(--mui-palette-success-main)' : 'var(--mui-palette-error-main)',
display: 'flex',
justifyContent: 'center',
}}
>
{trend === 'up' ? (
<TrendUpIcon fontSize="var(--icon-fontSize-md)" />
) : (
<TrendDownIcon fontSize="var(--icon-fontSize-md)" />
)}
</Box>
<Typography
color="text.secondary"
variant="body2"
>
<Typography
color={trend === 'up' ? 'success.main' : 'error.main'}
component="span"
variant="subtitle2"
>
{new Intl.NumberFormat('en-US', { style: 'percent', maximumFractionDigits: 2 }).format(diff / 100)}
</Typography>{' '}
{trend === 'up' ? t('increase') : t('decrease')} {t('vs last month')}
</Typography>
</Stack>
</Box>
</Card>
);
}

View File

@@ -15,6 +15,7 @@ import { useTranslation } from 'react-i18next';
import { Summary } from '@/components/dashboard/overview/summary';
import { LoadingSummary } from '../LoadingSummary';
import { ErrorSummary } from '../ErrorSummary';
function LessonCategoriesCount(): React.JSX.Element {
const { t } = useTranslation();
@@ -40,10 +41,26 @@ function LessonCategoriesCount(): React.JSX.Element {
}, []);
if (showLoading) {
return <LoadingSummary diff={10} icon={ListChecksIcon} title={t('用戶數量')} trend="up" />;
return (
<LoadingSummary
diff={10}
icon={ListChecksIcon}
title={t('用戶數量')}
trend="up"
/>
);
}
if (showError) return <div>{errorDetail}</div>;
if (showError) {
return (
<ErrorSummary
icon={ListChecksIcon}
title={t('Error')}
diff={0}
trend="down"
/>
);
}
return (
<Summary

View File

@@ -1,5 +1,11 @@
'use client';
/*
RULES:
show loading when fetching record from db
show error when fetch record failed
*/
import * as React from 'react';
import GetAllCount from '@/db/LessonTypes/GetAllCount.tsx';
import { ListChecks as ListChecksIcon } from '@phosphor-icons/react/dist/ssr/ListChecks';
@@ -7,6 +13,7 @@ import { useTranslation } from 'react-i18next';
import { Summary } from '@/components/dashboard/overview/summary';
import { LoadingSummary } from '@/components/dashboard/overview/summary/LoadingSummary';
import { ErrorSummary } from '@/components/dashboard/overview/summary/ErrorSummary';
function LessonTypeCount(): React.JSX.Element {
const { t } = useTranslation();
@@ -42,11 +49,10 @@ function LessonTypeCount(): React.JSX.Element {
if (error) {
return (
<Summary
amount={0}
<ErrorSummary
diff={0}
icon={ListChecksIcon}
title={t('Error')}
title={t('課程類型')}
trend="down"
/>
);

View File

@@ -1,5 +1,11 @@
'use client';
/*
NOTES:
show loading when loading summary
use with:
- src/components/dashboard/overview/summary/ActiveUserCount/index.tsx
*/
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
@@ -26,7 +32,11 @@ export function Summary({ amount, diff, icon: Icon, title, trend }: SummaryProps
return (
<Card>
<CardContent>
<Stack direction="row" spacing={3} sx={{ alignItems: 'center' }}>
<Stack
direction="row"
spacing={3}
sx={{ alignItems: 'center' }}
>
<Avatar
sx={{
'--Avatar-size': '48px',
@@ -38,7 +48,10 @@ export function Summary({ amount, diff, icon: Icon, title, trend }: SummaryProps
<Icon fontSize="var(--icon-fontSize-lg)" />
</Avatar>
<div>
<Typography color="text.secondary" variant="body1">
<Typography
color="text.secondary"
variant="body1"
>
{title}
</Typography>
<Typography variant="h3">{new Intl.NumberFormat('en-US').format(amount)}</Typography>
@@ -47,7 +60,11 @@ export function Summary({ amount, diff, icon: Icon, title, trend }: SummaryProps
</CardContent>
<Divider />
<Box sx={{ p: '16px' }}>
<Stack direction="row" spacing={1} sx={{ alignItems: 'center' }}>
<Stack
direction="row"
spacing={1}
sx={{ alignItems: 'center' }}
>
<Box
sx={{
alignItems: 'center',
@@ -62,8 +79,15 @@ export function Summary({ amount, diff, icon: Icon, title, trend }: SummaryProps
<TrendDownIcon fontSize="var(--icon-fontSize-md)" />
)}
</Box>
<Typography color="text.secondary" variant="body2">
<Typography color={trend === 'up' ? 'success.main' : 'error.main'} component="span" variant="subtitle2">
<Typography
color="text.secondary"
variant="body2"
>
<Typography
color={trend === 'up' ? 'success.main' : 'error.main'}
component="span"
variant="subtitle2"
>
{new Intl.NumberFormat('en-US', { style: 'percent', maximumFractionDigits: 2 }).format(diff / 100)}
</Typography>{' '}
{trend === 'up' ? t('increase') : t('decrease')} {t('vs last month')}