From fc1a48a7e79ed6ec3bb626021e80f1800f4265a8 Mon Sep 17 00:00:00 2001 From: louiscklaw Date: Wed, 16 Apr 2025 01:35:09 +0800 Subject: [PATCH] update build ok, --- .../dashboard/lesson_types/[typeId]/page.tsx | 285 +++++++++++++++++- .../dashboard/lesson_type/notifications.tsx | 101 +++++++ .../dashboard/lesson_type/payments.tsx | 138 +++++++++ .../lesson_type/shipping-address.tsx | 46 +++ 4 files changed, 569 insertions(+), 1 deletion(-) create mode 100644 002_source/cms/src/components/dashboard/lesson_type/notifications.tsx create mode 100644 002_source/cms/src/components/dashboard/lesson_type/payments.tsx create mode 100644 002_source/cms/src/components/dashboard/lesson_type/shipping-address.tsx diff --git a/002_source/cms/src/app/dashboard/lesson_types/[typeId]/page.tsx b/002_source/cms/src/app/dashboard/lesson_types/[typeId]/page.tsx index 09d8593..20ea797 100644 --- a/002_source/cms/src/app/dashboard/lesson_types/[typeId]/page.tsx +++ b/002_source/cms/src/app/dashboard/lesson_types/[typeId]/page.tsx @@ -30,8 +30,291 @@ import { useTranslation } from 'react-i18next'; import { paths } from '@/paths'; import { dayjs } from '@/lib/dayjs'; +import { PropertyItem } from '@/components/core/property-item'; +import { PropertyList } from '@/components/core/property-list'; +// import { getLessonTypeById } from '@/components/dashboard/lesson_type/http-actions'; +import { LessonTypeDefaultValue, type LessonType } from '@/components/dashboard/lesson_type/ILessonType'; +import { Notifications } from '@/components/dashboard/lesson_type/notifications'; +import { Payments } from '@/components/dashboard/lesson_type/payments'; +import type { Address } from '@/components/dashboard/lesson_type/shipping-address'; +import { ShippingAddress } from '@/components/dashboard/lesson_type/shipping-address'; export default function Page(): React.JSX.Element { const { t } = useTranslation(); - return <>helloworld; + const { typeId } = useParams<{ typeId: string }>(); + const [isLoading, setIsLoading] = React.useState(true); + const [showLessonType, setShowLessonType] = React.useState(LessonTypeDefaultValue); + const router = useRouter(); + + return ( + + + +
+ + + {t('Lesson Types')} + +
+ + + + MV + +
+ + {showLessonType.name} + } + label={showLessonType.visible} + size="small" + variant="outlined" + /> + + + {showLessonType.id} + +
+
+
+ +
+
+
+ + + + + { + handleEditClick(); + }} + > + + + } + avatar={ + + + + } + title="Basic details" + /> + } + orientation="vertical" + sx={{ '--PropertyItem-padding': '12px 24px' }} + > + {( + [ + { key: 'Customer ID', value: }, + { key: 'Name', value: showLessonType.name }, + { key: 'Type', value: showLessonType.type }, + { key: 'Pos', value: showLessonType.pos }, + { key: 'Visible', value: }, + { + key: 'Quota', + value: ( + + + + 50% + + + ), + }, + ] satisfies { key: string; value: React.ReactNode }[] + ).map( + (item): React.JSX.Element => ( + + ) + )} + + + + + + + } + title="Security" + /> + + +
+ +
+ + A deleted lesson type cannot be restored. All data will be permanently removed. + +
+
+
+
+
+ + + + + }> + Edit + + } + avatar={ + + + + } + title="Billing details" + /> + + + } sx={{ '--PropertyItem-padding': '16px' }}> + {( + [ + { key: 'Credit card', value: '**** 4142' }, + { key: 'Country', value: 'United States' }, + { key: 'State', value: 'Michigan' }, + { key: 'City', value: 'Southfield' }, + { key: 'Address', value: '1721 Bartlett Avenue, 48034' }, + { key: 'Tax ID', value: 'EU87956621' }, + ] satisfies { key: string; value: React.ReactNode }[] + ).map( + (item): React.JSX.Element => ( + + ) + )} + + + + + + }> + Add + + } + avatar={ + + + + } + title="Shipping addresses" + /> + + + {( + [ + { + id: 'ADR-001', + country: 'United States', + state: 'Michigan', + city: 'Lansing', + zipCode: '48933', + street: '480 Haven Lane', + primary: true, + }, + { + id: 'ADR-002', + country: 'United States', + state: 'Missouri', + city: 'Springfield', + zipCode: '65804', + street: '4807 Lighthouse Drive', + }, + ] satisfies Address[] + ).map((address) => ( + + + + ))} + + + + + + +
+
+
+ ); } diff --git a/002_source/cms/src/components/dashboard/lesson_type/notifications.tsx b/002_source/cms/src/components/dashboard/lesson_type/notifications.tsx new file mode 100644 index 0000000..a6c16bd --- /dev/null +++ b/002_source/cms/src/components/dashboard/lesson_type/notifications.tsx @@ -0,0 +1,101 @@ +'use client'; + +import * as React from 'react'; +import Avatar from '@mui/material/Avatar'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import Card from '@mui/material/Card'; +import CardContent from '@mui/material/CardContent'; +import CardHeader from '@mui/material/CardHeader'; +import Chip from '@mui/material/Chip'; +import Select from '@mui/material/Select'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import { EnvelopeSimple as EnvelopeSimpleIcon } from '@phosphor-icons/react/dist/ssr/EnvelopeSimple'; + +import { dayjs } from '@/lib/dayjs'; +import { DataTable } from '@/components/core/data-table'; +import type { ColumnDef } from '@/components/core/data-table'; +import { Option } from '@/components/core/option'; + +export interface Notification { + id: string; + type: string; + status: 'delivered' | 'pending' | 'failed'; + createdAt: Date; +} + +const columns = [ + { + formatter: (row): React.JSX.Element => ( + + {row.type} + + ), + name: 'Type', + width: '300px', + }, + { + formatter: (row): React.JSX.Element => { + const mapping = { + delivered: { label: 'Delivered', color: 'success' }, + pending: { label: 'Pending', color: 'warning' }, + failed: { label: 'Failed', color: 'error' }, + } as const; + const { label, color } = mapping[row.status] ?? { label: 'Unknown', color: 'secondary' }; + + return ; + }, + name: 'Status', + width: '200px', + }, + { + formatter: (row): React.JSX.Element => ( + + {dayjs(row.createdAt).format('MMM D, YYYY hh:mm A')} + + ), + name: 'Date', + align: 'right', + }, +] satisfies ColumnDef[]; + +export interface NotificationsProps { + notifications: Notification[]; +} + +export function Notifications({ notifications }: NotificationsProps): React.JSX.Element { + return ( + + + + + } + title="Notifications" + /> + + + + +
+ +
+
+ + + columns={columns} rows={notifications} /> + + +
+
+
+ ); +} diff --git a/002_source/cms/src/components/dashboard/lesson_type/payments.tsx b/002_source/cms/src/components/dashboard/lesson_type/payments.tsx new file mode 100644 index 0000000..0420d32 --- /dev/null +++ b/002_source/cms/src/components/dashboard/lesson_type/payments.tsx @@ -0,0 +1,138 @@ +'use client'; + +import * as React from 'react'; +import Avatar from '@mui/material/Avatar'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import Card from '@mui/material/Card'; +import CardContent from '@mui/material/CardContent'; +import CardHeader from '@mui/material/CardHeader'; +import Chip from '@mui/material/Chip'; +import Divider from '@mui/material/Divider'; +import Link from '@mui/material/Link'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import { Plus as PlusIcon } from '@phosphor-icons/react/dist/ssr/Plus'; +import { ShoppingCartSimple as ShoppingCartSimpleIcon } from '@phosphor-icons/react/dist/ssr/ShoppingCartSimple'; + +import { dayjs } from '@/lib/dayjs'; +import type { ColumnDef } from '@/components/core/data-table'; +import { DataTable } from '@/components/core/data-table'; + +export interface Payment { + currency: string; + amount: number; + invoiceId: string; + status: 'pending' | 'completed' | 'canceled' | 'refunded'; + createdAt: Date; +} + +const columns = [ + { + formatter: (row): React.JSX.Element => ( + + {new Intl.NumberFormat('en-US', { style: 'currency', currency: row.currency }).format(row.amount)} + + ), + name: 'Amount', + width: '200px', + }, + { + formatter: (row): React.JSX.Element => { + const mapping = { + pending: { label: 'Pending', color: 'warning' }, + completed: { label: 'Completed', color: 'success' }, + canceled: { label: 'Canceled', color: 'error' }, + refunded: { label: 'Refunded', color: 'error' }, + } as const; + const { label, color } = mapping[row.status] ?? { label: 'Unknown', color: 'secondary' }; + + return ; + }, + name: 'Status', + width: '200px', + }, + { + formatter: (row): React.JSX.Element => { + return {row.invoiceId}; + }, + name: 'Invoice ID', + width: '150px', + }, + { + formatter: (row): React.JSX.Element => ( + + {dayjs(row.createdAt).format('MMM D, YYYY hh:mm A')} + + ), + name: 'Date', + align: 'right', + }, +] satisfies ColumnDef[]; + +export interface PaymentsProps { + ordersValue: number; + payments: Payment[]; + refundsValue: number; + totalOrders: number; +} + +export function Payments({ ordersValue, payments = [], refundsValue, totalOrders }: PaymentsProps): React.JSX.Element { + return ( + + }> + Create Payment + + } + avatar={ + + + + } + title="Payments" + /> + + + + } + spacing={3} + sx={{ justifyContent: 'space-between', p: 2 }} + > +
+ + Total orders + + {new Intl.NumberFormat('en-US').format(totalOrders)} +
+
+ + Orders value + + + {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(ordersValue)} + +
+
+ + Refunds + + + {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(refundsValue)} + +
+
+
+ + + columns={columns} rows={payments} /> + + +
+
+
+ ); +} diff --git a/002_source/cms/src/components/dashboard/lesson_type/shipping-address.tsx b/002_source/cms/src/components/dashboard/lesson_type/shipping-address.tsx new file mode 100644 index 0000000..8793e5c --- /dev/null +++ b/002_source/cms/src/components/dashboard/lesson_type/shipping-address.tsx @@ -0,0 +1,46 @@ +import * as React from 'react'; +import Button from '@mui/material/Button'; +import Card from '@mui/material/Card'; +import CardContent from '@mui/material/CardContent'; +import Chip from '@mui/material/Chip'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import { PencilSimple as PencilSimpleIcon } from '@phosphor-icons/react/dist/ssr/PencilSimple'; + +export interface Address { + id: string; + country: string; + state: string; + city: string; + zipCode: string; + street: string; + primary?: boolean; +} + +export interface ShippingAddressProps { + address: Address; +} + +export function ShippingAddress({ address }: ShippingAddressProps): React.ReactElement { + return ( + + + + + {address.street}, +
+ {address.city}, {address.state}, {address.country}, +
+ {address.zipCode} +
+ + {address.primary ? : } + + +
+
+
+ ); +}