update to use,

This commit is contained in:
2025-05-16 12:07:58 +08:00
parent 7264d643d0
commit af5040ac6c
19 changed files with 281 additions and 119 deletions

View File

@@ -34,6 +34,7 @@ import { useTranslation } from 'react-i18next';
import { paths } from '@/paths';
import { dayjs } from '@/lib/dayjs';
import { logger } from '@/lib/default-logger';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import { pb } from '@/lib/pb';
import { PropertyItem } from '@/components/core/property-item';
import { PropertyList } from '@/components/core/property-list';
@@ -119,39 +120,72 @@ export default function Page(): React.JSX.Element {
{t('dashboard.lessonCategorys.list.title')}
</Link>
</div>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={3} sx={{ alignItems: 'flex-start' }}>
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flex: '1 1 auto' }}>
<Stack
direction={{ xs: 'column', sm: 'row' }}
spacing={3}
sx={{ alignItems: 'flex-start' }}
>
<Stack
direction="row"
spacing={2}
sx={{ alignItems: 'center', flex: '1 1 auto' }}
>
<Avatar
src={`http://127.0.0.1:8090/api/files/${showLessonCategory.collectionId}/${showLessonCategory.id}/${showLessonCategory.cat_image}`}
src={getImageUrlFromFile(
showLessonCategory.collectionId,
showLessonCategory.id,
showLessonCategory.cat_image
)}
sx={{ '--Avatar-size': '64px' }}
variant="rounded"
>
empty
</Avatar>
<div>
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>
<Stack
direction="row"
spacing={2}
sx={{ alignItems: 'center', flexWrap: 'wrap' }}
>
<Typography variant="h4">{showLessonCategory.name}</Typography>
<Chip
icon={<CheckCircleIcon color="var(--mui-palette-success-main)" weight="fill" />}
icon={
<CheckCircleIcon
color="var(--mui-palette-success-main)"
weight="fill"
/>
}
label={showLessonCategory.visible}
size="small"
variant="outlined"
/>
</Stack>
<Typography color="text.secondary" variant="body1">
<Typography
color="text.secondary"
variant="body1"
>
{showLessonCategory.id}
</Typography>
</div>
</Stack>
<div>
<Button endIcon={<CaretDownIcon />} variant="contained">
<Button
endIcon={<CaretDownIcon />}
variant="contained"
>
Action
</Button>
</div>
</Stack>
</Stack>
<Grid container spacing={4}>
<Grid lg={4} xs={12}>
<Grid
container
spacing={4}
>
<Grid
lg={4}
xs={12}
>
<Stack spacing={4}>
<Card>
<CardHeader
@@ -178,7 +212,16 @@ export default function Page(): React.JSX.Element {
>
{(
[
{ key: 'Customer ID', value: <Chip label={showLessonCategory.id} size="small" variant="soft" /> },
{
key: 'Customer ID',
value: (
<Chip
label={showLessonCategory.id}
size="small"
variant="soft"
/>
),
},
{ key: 'Name', value: showLessonCategory.name },
{ key: 'Pos', value: showLessonCategory.pos },
{
@@ -195,9 +238,20 @@ export default function Page(): React.JSX.Element {
{
key: 'Quota',
value: (
<Stack direction="row" spacing={2} sx={{ alignItems: 'center' }}>
<LinearProgress sx={{ flex: '1 1 auto' }} value={50} variant="determinate" />
<Typography color="text.secondary" variant="body2">
<Stack
direction="row"
spacing={2}
sx={{ alignItems: 'center' }}
>
<LinearProgress
sx={{ flex: '1 1 auto' }}
value={50}
variant="determinate"
/>
<Typography
color="text.secondary"
variant="body2"
>
50%
</Typography>
</Stack>
@@ -206,7 +260,11 @@ export default function Page(): React.JSX.Element {
] satisfies { key: string; value: React.ReactNode }[]
).map(
(item): React.JSX.Element => (
<PropertyItem key={item.key} name={item.key} value={item.value} />
<PropertyItem
key={item.key}
name={item.key}
value={item.value}
/>
)
)}
</PropertyList>
@@ -223,11 +281,17 @@ export default function Page(): React.JSX.Element {
<CardContent>
<Stack spacing={1}>
<div>
<Button color="error" variant="contained">
<Button
color="error"
variant="contained"
>
Delete account
</Button>
</div>
<Typography color="text.secondary" variant="body2">
<Typography
color="text.secondary"
variant="body2"
>
A deleted lesson category cannot be restored. All data will be permanently removed.
</Typography>
</Stack>
@@ -235,7 +299,10 @@ export default function Page(): React.JSX.Element {
</Card>
</Stack>
</Grid>
<Grid lg={8} xs={12}>
<Grid
lg={8}
xs={12}
>
<Stack spacing={4}>
<Payments
ordersValue={2069.48}
@@ -282,7 +349,10 @@ export default function Page(): React.JSX.Element {
<Card>
<CardHeader
action={
<Button color="secondary" startIcon={<PencilSimpleIcon />}>
<Button
color="secondary"
startIcon={<PencilSimpleIcon />}
>
Edit
</Button>
}
@@ -294,8 +364,14 @@ export default function Page(): React.JSX.Element {
title={t('billing-details', { ns: 'lesson_category' })}
/>
<CardContent>
<Card sx={{ borderRadius: 1 }} variant="outlined">
<PropertyList divider={<Divider />} sx={{ '--PropertyItem-padding': '16px' }}>
<Card
sx={{ borderRadius: 1 }}
variant="outlined"
>
<PropertyList
divider={<Divider />}
sx={{ '--PropertyItem-padding': '16px' }}
>
{(
[
{ key: 'Credit card', value: '**** 4142' },
@@ -307,7 +383,11 @@ export default function Page(): React.JSX.Element {
] satisfies { key: string; value: React.ReactNode }[]
).map(
(item): React.JSX.Element => (
<PropertyItem key={item.key} name={item.key} value={item.value} />
<PropertyItem
key={item.key}
name={item.key}
value={item.value}
/>
)
)}
</PropertyList>
@@ -317,7 +397,10 @@ export default function Page(): React.JSX.Element {
<Card>
<CardHeader
action={
<Button color="secondary" startIcon={<PlusIcon />}>
<Button
color="secondary"
startIcon={<PlusIcon />}
>
Add
</Button>
}
@@ -329,7 +412,10 @@ export default function Page(): React.JSX.Element {
title={t('shipping-addresses', { ns: 'lesson_category' })}
/>
<CardContent>
<Grid container spacing={3}>
<Grid
container
spacing={3}
>
{(
[
{
@@ -351,7 +437,11 @@ export default function Page(): React.JSX.Element {
},
] satisfies Address[]
).map((address) => (
<Grid key={address.id} md={6} xs={12}>
<Grid
key={address.id}
md={6}
xs={12}
>
<ShippingAddress address={address} />
</Grid>
))}

View File

@@ -10,12 +10,9 @@ import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/Caret
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import type { CrCategory } from '@/components/dashboard/cr/categories/type';
function getImageUrlFrRecord(record: CrCategory): string {
return `http://127.0.0.1:8090/api/files/${record.collectionId}/${record.id}/${record.cat_image}`;
}
export default function SampleTitleCard({ lpModel }: { lpModel: CrCategory }): React.JSX.Element {
const { t } = useTranslation();
@@ -28,7 +25,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: CrCategory }): R
>
<Avatar
variant="rounded"
src={getImageUrlFrRecord(lpModel)}
src={getImageUrlFromFile(lpModel.collectionId, lpModel.id, lpModel.cat_image)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -10,12 +10,9 @@ import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/Caret
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import { LpCategory } from '@/components/dashboard/lp/categories/type';
function getImageUrlFrRecord(record: LpCategory): string {
return `http://127.0.0.1:8090/api/files/${record.collectionId}/${record.id}/${record.cat_image}`;
}
export default function SampleTitleCard({ lpModel }: { lpModel: LpCategory }): React.JSX.Element {
const { t } = useTranslation();
@@ -28,7 +25,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: LpCategory }): R
>
<Avatar
variant="rounded"
src={getImageUrlFrRecord(lpModel)}
src={getImageUrlFromFile(lpModel.collectionId, lpModel.id, lpModel.cat_image)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -9,14 +9,14 @@ import Typography from '@mui/material/Typography';
import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/CaretDown';
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import type { Customer } from '@/components/dashboard/customer/type.d';
// import type { CrCategory } from '@/components/dashboard/cr/categories/type';
function getImageUrlFrRecord(record: Customer): string {
// TODO: fix this
// `http://127.0.0.1:8090/api/files/${'record.collectionId'}/${'record.id'}/${'record.cat_image'}`;
return 'getImageUrlFrRecord(helloworld)';
// TODO: implement getImageUrlFrRecord
return 'not implemented';
}
export default function SampleTitleCard({ lpModel }: { lpModel: Customer }): React.JSX.Element {

View File

@@ -28,12 +28,13 @@ import { PencilSimple as PencilSimpleIcon } from '@phosphor-icons/react/dist/ssr
import { Plus as PlusIcon } from '@phosphor-icons/react/dist/ssr/Plus';
import { ShieldWarning as ShieldWarningIcon } from '@phosphor-icons/react/dist/ssr/ShieldWarning';
import { User as UserIcon } from '@phosphor-icons/react/dist/ssr/User';
import { RecordModel } from 'pocketbase';
import type { RecordModel } from 'pocketbase';
import { useTranslation } from 'react-i18next';
import { paths } from '@/paths';
import { dayjs } from '@/lib/dayjs';
import { logger } from '@/lib/default-logger';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import { pb } from '@/lib/pb';
import { PropertyItem } from '@/components/core/property-item';
import { PropertyList } from '@/components/core/property-list';
@@ -45,7 +46,7 @@ import { Notifications } from '@/components/dashboard/lesson_category/notificati
import { Payments } from '@/components/dashboard/lesson_category/payments';
import type { Address } from '@/components/dashboard/lesson_category/shipping-address';
import { ShippingAddress } from '@/components/dashboard/lesson_category/shipping-address';
import { LessonCategory } from '@/components/dashboard/lesson_category/type';
import type { LessonCategory } from '@/components/dashboard/lesson_category/type';
// import type { LessonCategory } from '@/components/dashboard/lp_categories/type';
import FormLoading from '@/components/loading';
@@ -119,39 +120,72 @@ export default function Page(): React.JSX.Element {
{t('dashboard.lessonCategorys.list.title')}
</Link>
</div>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={3} sx={{ alignItems: 'flex-start' }}>
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flex: '1 1 auto' }}>
<Stack
direction={{ xs: 'column', sm: 'row' }}
spacing={3}
sx={{ alignItems: 'flex-start' }}
>
<Stack
direction="row"
spacing={2}
sx={{ alignItems: 'center', flex: '1 1 auto' }}
>
<Avatar
src={`http://127.0.0.1:8090/api/files/${showLessonCategory.collectionId}/${showLessonCategory.id}/${showLessonCategory.cat_image}`}
src={getImageUrlFromFile(
showLessonCategory.collectionId,
showLessonCategory.id,
showLessonCategory.cat_image
)}
sx={{ '--Avatar-size': '64px' }}
variant="rounded"
>
empty
</Avatar>
<div>
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>
<Stack
direction="row"
spacing={2}
sx={{ alignItems: 'center', flexWrap: 'wrap' }}
>
<Typography variant="h4">{showLessonCategory.name}</Typography>
<Chip
icon={<CheckCircleIcon color="var(--mui-palette-success-main)" weight="fill" />}
icon={
<CheckCircleIcon
color="var(--mui-palette-success-main)"
weight="fill"
/>
}
label={showLessonCategory.visible}
size="small"
variant="outlined"
/>
</Stack>
<Typography color="text.secondary" variant="body1">
<Typography
color="text.secondary"
variant="body1"
>
{showLessonCategory.id}
</Typography>
</div>
</Stack>
<div>
<Button endIcon={<CaretDownIcon />} variant="contained">
<Button
endIcon={<CaretDownIcon />}
variant="contained"
>
Action
</Button>
</div>
</Stack>
</Stack>
<Grid container spacing={4}>
<Grid lg={4} xs={12}>
<Grid
container
spacing={4}
>
<Grid
lg={4}
xs={12}
>
<Stack spacing={4}>
<Card>
<CardHeader
@@ -178,7 +212,16 @@ export default function Page(): React.JSX.Element {
>
{(
[
{ key: 'Customer ID', value: <Chip label={showLessonCategory.id} size="small" variant="soft" /> },
{
key: 'Customer ID',
value: (
<Chip
label={showLessonCategory.id}
size="small"
variant="soft"
/>
),
},
{ key: 'Name', value: showLessonCategory.name },
{ key: 'Pos', value: showLessonCategory.pos },
{
@@ -195,9 +238,20 @@ export default function Page(): React.JSX.Element {
{
key: 'Quota',
value: (
<Stack direction="row" spacing={2} sx={{ alignItems: 'center' }}>
<LinearProgress sx={{ flex: '1 1 auto' }} value={50} variant="determinate" />
<Typography color="text.secondary" variant="body2">
<Stack
direction="row"
spacing={2}
sx={{ alignItems: 'center' }}
>
<LinearProgress
sx={{ flex: '1 1 auto' }}
value={50}
variant="determinate"
/>
<Typography
color="text.secondary"
variant="body2"
>
50%
</Typography>
</Stack>
@@ -206,7 +260,11 @@ export default function Page(): React.JSX.Element {
] satisfies { key: string; value: React.ReactNode }[]
).map(
(item): React.JSX.Element => (
<PropertyItem key={item.key} name={item.key} value={item.value} />
<PropertyItem
key={item.key}
name={item.key}
value={item.value}
/>
)
)}
</PropertyList>
@@ -223,11 +281,17 @@ export default function Page(): React.JSX.Element {
<CardContent>
<Stack spacing={1}>
<div>
<Button color="error" variant="contained">
<Button
color="error"
variant="contained"
>
Delete account
</Button>
</div>
<Typography color="text.secondary" variant="body2">
<Typography
color="text.secondary"
variant="body2"
>
A deleted lesson category cannot be restored. All data will be permanently removed.
</Typography>
</Stack>
@@ -235,7 +299,10 @@ export default function Page(): React.JSX.Element {
</Card>
</Stack>
</Grid>
<Grid lg={8} xs={12}>
<Grid
lg={8}
xs={12}
>
<Stack spacing={4}>
<Payments
ordersValue={2069.48}
@@ -282,7 +349,10 @@ export default function Page(): React.JSX.Element {
<Card>
<CardHeader
action={
<Button color="secondary" startIcon={<PencilSimpleIcon />}>
<Button
color="secondary"
startIcon={<PencilSimpleIcon />}
>
Edit
</Button>
}
@@ -294,8 +364,14 @@ export default function Page(): React.JSX.Element {
title={t('billing-details', { ns: 'lesson_category' })}
/>
<CardContent>
<Card sx={{ borderRadius: 1 }} variant="outlined">
<PropertyList divider={<Divider />} sx={{ '--PropertyItem-padding': '16px' }}>
<Card
sx={{ borderRadius: 1 }}
variant="outlined"
>
<PropertyList
divider={<Divider />}
sx={{ '--PropertyItem-padding': '16px' }}
>
{(
[
{ key: 'Credit card', value: '**** 4142' },
@@ -307,7 +383,11 @@ export default function Page(): React.JSX.Element {
] satisfies { key: string; value: React.ReactNode }[]
).map(
(item): React.JSX.Element => (
<PropertyItem key={item.key} name={item.key} value={item.value} />
<PropertyItem
key={item.key}
name={item.key}
value={item.value}
/>
)
)}
</PropertyList>
@@ -317,7 +397,10 @@ export default function Page(): React.JSX.Element {
<Card>
<CardHeader
action={
<Button color="secondary" startIcon={<PlusIcon />}>
<Button
color="secondary"
startIcon={<PlusIcon />}
>
Add
</Button>
}
@@ -329,7 +412,10 @@ export default function Page(): React.JSX.Element {
title={t('shipping-addresses', { ns: 'lesson_category' })}
/>
<CardContent>
<Grid container spacing={3}>
<Grid
container
spacing={3}
>
{(
[
{
@@ -351,7 +437,11 @@ export default function Page(): React.JSX.Element {
},
] satisfies Address[]
).map((address) => (
<Grid key={address.id} md={6} xs={12}>
<Grid
key={address.id}
md={6}
xs={12}
>
<ShippingAddress address={address} />
</Grid>
))}

View File

@@ -10,11 +10,8 @@ import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/Caret
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import { LpCategory } from '@/components/dashboard/lp/categories/type';
function getImageUrlFrRecord(record: LpCategory): string {
return `http://127.0.0.1:8090/api/files/${record.collectionId}/${record.id}/${record.cat_image}`;
}
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import type { LpCategory } from '@/components/dashboard/lp/categories/type';
export default function SampleTitleCard({ lpModel }: { lpModel: LpCategory }): React.JSX.Element {
const { t } = useTranslation();
@@ -28,7 +25,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: LpCategory }): R
>
<Avatar
variant="rounded"
src={getImageUrlFrRecord(lpModel)}
src={getImageUrlFromFile(lpModel.collectionId, lpModel.id, lpModel.cat_image)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -10,12 +10,9 @@ import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/Caret
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import { LpCategory } from '@/components/dashboard/lp/categories/type';
function getImageUrlFrRecord(record: LpCategory): string {
return `http://127.0.0.1:8090/api/files/${record.collectionId}/${record.id}/${record.cat_image}`;
}
export default function SampleTitleCard({ lpModel }: { lpModel: LpCategory }): React.JSX.Element {
const { t } = useTranslation();
@@ -28,7 +25,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: LpCategory }): R
>
<Avatar
variant="rounded"
src={getImageUrlFrRecord(lpModel)}
src={getImageUrlFromFile(lpModel.collectionId, lpModel.id, lpModel.cat_image)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -10,12 +10,9 @@ import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/Caret
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import type { MfCategory } from '@/components/dashboard/mf/categories/type';
function getImageUrlFrRecord(record: MfCategory): string {
return `http://127.0.0.1:8090/api/files/${record.collectionId}/${record.id}/${record.cat_image}`;
}
export default function SampleTitleCard({ lpModel }: { lpModel: MfCategory }): React.JSX.Element {
const { t } = useTranslation();
@@ -28,7 +25,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: MfCategory }): R
>
<Avatar
variant="rounded"
src={getImageUrlFrRecord(lpModel)}
src={getImageUrlFromFile(lpModel.collectionId, lpModel.id, lpModel.cat_image)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -10,12 +10,9 @@ import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/Caret
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import type { MfCategory } from '@/components/dashboard/mf/categories/type';
function getImageUrlFrRecord(record: MfCategory): string {
return `http://127.0.0.1:8090/api/files/${record.collectionId}/${record.id}/${record.cat_image}`;
}
export default function SampleTitleCard({ lpModel }: { lpModel: MfCategory }): React.JSX.Element {
const { t } = useTranslation();
@@ -28,7 +25,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: MfCategory }): R
>
<Avatar
variant="rounded"
src={getImageUrlFrRecord(lpModel)}
src={getImageUrlFromFile(lpModel.collectionId, lpModel.id, lpModel.cat_image)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -9,14 +9,10 @@ import Typography from '@mui/material/Typography';
import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/CaretDown';
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import type { Student } from '@/components/dashboard/student/type.d';
// import type { CrCategory } from '@/components/dashboard/cr/categories/type';
function getImageUrlForStudent(student: Student): string {
return `http://127.0.0.1:8090/api/files/${student.collectionId}/${student.id}/${student.avatar}`;
}
export default function SampleTitleCard({ studentRecord }: { studentRecord: Student }): React.JSX.Element {
const { t } = useTranslation();
@@ -29,7 +25,7 @@ export default function SampleTitleCard({ studentRecord }: { studentRecord: Stud
>
<Avatar
variant="rounded"
src={getImageUrlForStudent(studentRecord)}
src={getImageUrlFromFile(studentRecord.collectionId, studentRecord.id, studentRecord.avatar)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -9,13 +9,9 @@ import Typography from '@mui/material/Typography';
import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/CaretDown';
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import { Teacher } from '@/components/dashboard/teacher/type.d';
// import type { CrCategory } from '@/components/dashboard/cr/categories/type';
function getImageUrlFrRecord(teacher: Teacher): string {
return `http://127.0.0.1:8090/api/files/${teacher.collectionId}/${teacher.id}/${teacher.avatar}`;
}
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import type { Teacher } from '@/components/dashboard/teacher/type.d';
export default function SampleTitleCard({ teacherRecord }: { teacherRecord: Teacher }): React.JSX.Element {
const { t } = useTranslation();
@@ -29,7 +25,7 @@ export default function SampleTitleCard({ teacherRecord }: { teacherRecord: Teac
>
<Avatar
variant="rounded"
src={getImageUrlFrRecord(teacherRecord)}
src={getImageUrlFromFile(teacherRecord.collectionId, teacherRecord.id, teacherRecord.avatar)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -9,13 +9,9 @@ import Typography from '@mui/material/Typography';
import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/CaretDown';
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
import { useTranslation } from 'react-i18next';
import { Teacher } from '@/components/dashboard/teacher/type.d';
// import type { CrCategory } from '@/components/dashboard/cr/categories/type';
function getImageUrlFrRecord(teacher: Teacher): string {
return `http://127.0.0.1:8090/api/files/${teacher.collectionId}/${teacher.id}/${teacher.avatar}`;
}
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import type { Teacher } from '@/components/dashboard/teacher/type.d';
export default function SampleTitleCard({ teacherRecord }: { teacherRecord: Teacher }): React.JSX.Element {
const { t } = useTranslation();
@@ -29,7 +25,7 @@ export default function SampleTitleCard({ teacherRecord }: { teacherRecord: Teac
>
<Avatar
variant="rounded"
src={getImageUrlFrRecord(teacherRecord)}
src={getImageUrlFromFile(teacherRecord.collectionId, teacherRecord.id, teacherRecord.avatar)}
sx={{ '--Avatar-size': '64px' }}
>
{t('empty')}

View File

@@ -34,6 +34,7 @@ import { useTranslation } from 'react-i18next';
import { paths } from '@/paths';
import { dayjs } from '@/lib/dayjs';
import { logger } from '@/lib/default-logger';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import { pb } from '@/lib/pb';
import { PropertyItem } from '@/components/core/property-item';
import { PropertyList } from '@/components/core/property-list';
@@ -128,7 +129,11 @@ export default function Page(): React.JSX.Element {
sx={{ alignItems: 'center', flex: '1 1 auto' }}
>
<Avatar
src={`http://127.0.0.1:8090/api/files/${showLessonCategory.collectionId}/${showLessonCategory.id}/${showLessonCategory.cat_image}`}
src={getImageUrlFromFile(
showLessonCategory.collectionId,
showLessonCategory.id,
showLessonCategory.image
)}
sx={{ '--Avatar-size': '64px' }}
variant="rounded"
>

View File

@@ -26,6 +26,7 @@ import { useTranslation } from 'react-i18next';
import { paths } from '@/paths';
import { dayjs } from '@/lib/dayjs';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import { DataTable } from '@/components/core/data-table';
import type { ColumnDef } from '@/components/core/data-table';
@@ -43,7 +44,7 @@ function columns(handleDeleteClick: (userMetaId: string) => void): ColumnDef<Use
sx={{ alignItems: 'center' }}
>
<Avatar
src={`http://127.0.0.1:8090/api/files/${row.collectionId}/${row.id}/${row.avatar}`}
src={getImageUrlFromFile(row.collectionId, row.id, row.avatar)}
variant="rounded"
/>
<div>

View File

@@ -1,10 +1,9 @@
// RULES:
// should match the collection `Vocabularies` from `schema.dbml`
export interface Vocabulary {
id: string;
created?: string;
updated?: string;
image?: string;
image: string;
sound?: string;
word?: string;
word_c?: string;
@@ -23,6 +22,9 @@ export interface Vocabulary {
//
};
};
//
id: string;
collectionId: string;
}
// RULES: for use with vocabulary-create-form.tsx

View File

@@ -16,12 +16,13 @@ import { useTranslation } from 'react-i18next';
import { paths } from '@/paths';
import { dayjs } from '@/lib/dayjs';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import { DataTable } from '@/components/core/data-table';
import type { ColumnDef } from '@/components/core/data-table';
import ConfirmDeleteModal from './confirm-delete-modal';
import { useVocabulariesSelection } from './vocabularies-selection-context';
import type { Vocabulary } from './type';
import { useVocabulariesSelection } from './vocabularies-selection-context';
function columns(handleDeleteClick: (testId: string) => void): ColumnDef<Vocabulary>[] {
return [
@@ -45,7 +46,7 @@ function columns(handleDeleteClick: (testId: string) => void): ColumnDef<Vocabul
sx={{ alignItems: 'center' }}
>
<Avatar
src={`http://127.0.0.1:8090/api/files/${row.collectionId}/${row.id}/${row.cat_image}`}
src={getImageUrlFromFile(row.collectionId, row.id, row.image)}
variant="rounded"
>
<ImagesIcon size={32} />

View File

@@ -4,6 +4,7 @@ import * as React from 'react';
import RouterLink from 'next/link';
import { useParams, useRouter } from 'next/navigation';
import { COL_VOCABULARIES } from '@/constants';
import { listLessonCategories } from '@/db/LessonCategories/listLessonCategories';
import { zodResolver } from '@hookform/resolvers/zod';
import { LoadingButton } from '@mui/lab';
import { Avatar, Divider } from '@mui/material';
@@ -12,7 +13,6 @@ import Button from '@mui/material/Button';
import Card from '@mui/material/Card';
import CardActions from '@mui/material/CardActions';
import CardContent from '@mui/material/CardContent';
import FormControl from '@mui/material/FormControl';
import FormHelperText from '@mui/material/FormHelperText';
import InputLabel from '@mui/material/InputLabel';
@@ -27,8 +27,10 @@ import { useTranslation } from 'react-i18next';
import { z as zod } from 'zod';
import { paths } from '@/paths';
import isDevelopment from '@/lib/check-is-development';
import { logger } from '@/lib/default-logger';
import { base64ToFile, fileToBase64 } from '@/lib/file-to-base64';
import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts';
import { pb } from '@/lib/pb';
import { Option } from '@/components/core/option';
import { toast } from '@/components/core/toaster';
@@ -36,8 +38,6 @@ import FormLoading from '@/components/loading';
import ErrorDisplay from '../error';
import type { EditFormProps } from './type';
import { listLessonCategories } from '@/db/LessonCategories/listLessonCategories';
import isDevelopment from '@/lib/check-is-development';
const schema = zod.object({
image: zod.union([zod.array(zod.any()), zod.string()]).optional(),
@@ -144,9 +144,7 @@ export function VocabularyEditForm(): React.JSX.Element {
reset({ ...defaultValues, ...result });
if (result.image !== '') {
const fetchResult = await fetch(
`http://127.0.0.1:8090/api/files/${result.collectionId}/${result.id}/${result.image}`
);
const fetchResult = await fetch(getImageUrlFromFile(result.collectionId, result.id, result.image));
const blob = await fetchResult.blob();
const url = await fileToBase64(blob);

View File

@@ -3,6 +3,8 @@
// get file url from pocketbase record
//
export default function getImageUrlFromFile(collectionId: string, id: string, imgFile: string): string {
return `http://127.0.0.1:8090/api/files/${collectionId}/${id}/${imgFile}`;
import { POCKETBASE_URL } from './pb';
export default function getImageUrlFromFile(collectionId: string, id: string, imgFile: string | undefined): string {
return `${POCKETBASE_URL}/api/files/${collectionId}/${id}/${imgFile}`;
}

View File

@@ -1,3 +1,6 @@
import PocketBase from 'pocketbase';
if (!process.env.NEXT_PUBLIC_POCKETBASE_URL) throw new Error('the pocketbase url cannot empty');
export const POCKETBASE_URL: string = process.env.NEXT_PUBLIC_POCKETBASE_URL;
export const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);