diff --git a/002_source/cms/src/app/dashboard/SampleEvents.tsx b/002_source/cms/src/app/dashboard/SampleEvents.tsx new file mode 100644 index 0000000..97ef774 --- /dev/null +++ b/002_source/cms/src/app/dashboard/SampleEvents.tsx @@ -0,0 +1,36 @@ +'use client'; + +import { dayjs } from '@/lib/dayjs'; + +export interface Event { + id: string; + title: string; + description: string; + createdAt: Date; +} +export const events: Event[] = [ + { + id: 'EV-004', + title: 'Meeting with partners', + description: '17:00 to 18:00', + createdAt: dayjs().add(1, 'day').toDate(), + }, + { + id: 'EV-003', + title: 'Interview with Jonas', + description: '15:30 to 16:45', + createdAt: dayjs().add(4, 'day').toDate(), + }, + { + id: 'EV-002', + title: "Doctor's appointment", + description: '12:30 to 15:30', + createdAt: dayjs().add(4, 'day').toDate(), + }, + { + id: 'EV-001', + title: 'Weekly meeting', + description: '09:00 to 09:30', + createdAt: dayjs().add(7, 'day').toDate(), + }, +]; diff --git a/002_source/cms/src/app/dashboard/SampleMessages.tsx b/002_source/cms/src/app/dashboard/SampleMessages.tsx new file mode 100644 index 0000000..212f2d3 --- /dev/null +++ b/002_source/cms/src/app/dashboard/SampleMessages.tsx @@ -0,0 +1,42 @@ +'use client'; + +import { dayjs } from '@/lib/dayjs'; + +interface Message { + id: string; + content: string; + author: { name: string; avatar?: string; status?: 'online' | 'offline' | 'away' | 'busy' }; + createdAt: Date; +} +export const messages: Message[] = [ + { + id: 'MSG-001', + content: 'Hello, we spoke earlier on the phone', + author: { name: 'Alcides Antonio', avatar: '/assets/avatar-10.png', status: 'online' }, + createdAt: dayjs().subtract(2, 'minute').toDate(), + }, + { + id: 'MSG-002', + content: 'Is the job still available?', + author: { name: 'Marcus Finn', avatar: '/assets/avatar-9.png', status: 'offline' }, + createdAt: dayjs().subtract(56, 'minute').toDate(), + }, + { + id: 'MSG-003', + content: "What is a screening task? I'd like to", + author: { name: 'Carson Darrin', avatar: '/assets/avatar-3.png', status: 'online' }, + createdAt: dayjs().subtract(3, 'hour').subtract(23, 'minute').toDate(), + }, + { + id: 'MSG-004', + content: 'Still waiting for feedback', + author: { name: 'Fran Perez', avatar: '/assets/avatar-5.png', status: 'online' }, + createdAt: dayjs().subtract(8, 'hour').subtract(6, 'minute').toDate(), + }, + { + id: 'MSG-005', + content: 'Need more information about campaigns', + author: { name: 'Jie Yan', avatar: '/assets/avatar-8.png', status: 'offline' }, + createdAt: dayjs().subtract(10, 'hour').subtract(18, 'minute').toDate(), + }, +]; diff --git a/002_source/cms/src/app/dashboard/SamplesubScriptions.tsx b/002_source/cms/src/app/dashboard/SamplesubScriptions.tsx new file mode 100644 index 0000000..794c15a --- /dev/null +++ b/002_source/cms/src/app/dashboard/SamplesubScriptions.tsx @@ -0,0 +1,51 @@ +'use client'; +interface Subscription { + id: string; + title: string; + icon: string; + costs: string; + billingCycle: string; + status: 'paid' | 'canceled' | 'expiring'; +} +export const SamplesubScriptions: Subscription[] = [ + { + id: 'supabase', + title: 'Supabase', + icon: '/assets/company-avatar-5.png', + costs: '$599', + billingCycle: 'year', + status: 'paid', + }, + { + id: 'vercel', + title: 'Vercel', + icon: '/assets/company-avatar-4.png', + costs: '$20', + billingCycle: 'month', + status: 'expiring', + }, + { + id: 'auth0', + title: 'Auth0', + icon: '/assets/company-avatar-3.png', + costs: '$20-80', + billingCycle: 'month', + status: 'canceled', + }, + { + id: 'google_cloud', + title: 'Google Cloud', + icon: '/assets/company-avatar-2.png', + costs: '$100-200', + billingCycle: 'month', + status: 'paid', + }, + { + id: 'stripe', + title: 'Stripe', + icon: '/assets/company-avatar-1.png', + costs: '$70', + billingCycle: 'month', + status: 'paid', + }, +]; diff --git a/002_source/cms/src/app/dashboard/page.tsx b/002_source/cms/src/app/dashboard/page.tsx index fd3bad9..f29ff35 100644 --- a/002_source/cms/src/app/dashboard/page.tsx +++ b/002_source/cms/src/app/dashboard/page.tsx @@ -1,7 +1,9 @@ 'use client'; import * as React from 'react'; -// import type { Metadata } from 'next'; +import GetAllLessonCategoriesCount from '@/db/LessonCategories/GetAllCount'; +import GetAllLessonTypesCount from '@/db/LessonTypes/GetAllCount'; +import GetAllUsersCount from '@/db/Users/GetAllCount'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Stack from '@mui/material/Stack'; @@ -11,14 +13,12 @@ import { ArrowRight as ArrowRightIcon } from '@phosphor-icons/react/dist/ssr/Arr import { Briefcase as BriefcaseIcon } from '@phosphor-icons/react/dist/ssr/Briefcase'; import { FileCode as FileCodeIcon } from '@phosphor-icons/react/dist/ssr/FileCode'; import { Info as InfoIcon } from '@phosphor-icons/react/dist/ssr/Info'; +// import type { Metadata } from 'next'; import { ListChecks as ListChecksIcon } from '@phosphor-icons/react/dist/ssr/ListChecks'; import { Plus as PlusIcon } from '@phosphor-icons/react/dist/ssr/Plus'; -import { Users as UsersIcon } from '@phosphor-icons/react/dist/ssr/Users'; -import { Warning as WarningIcon } from '@phosphor-icons/react/dist/ssr/Warning'; import { useTranslation } from 'react-i18next'; // import { config } from '@/config'; -import { dayjs } from '@/lib/dayjs'; import { AppChat } from '@/components/dashboard/overview/app-chat'; import { AppLimits } from '@/components/dashboard/overview/app-limits'; import { AppUsage } from '@/components/dashboard/overview/app-usage'; @@ -27,13 +27,27 @@ import { HelperWidget } from '@/components/dashboard/overview/helper-widget'; import { Subscriptions } from '@/components/dashboard/overview/subscriptions'; import { Summary } from '@/components/dashboard/overview/summary'; -// TODO: remove me -// export const metadata = { title: `Overview | Dashboard | ${config.site.name}` } satisfies Metadata; +import ActiveUserCount from '../../components/dashboard/overview/summary/ActiveUserCount'; +import { events as SampleEvents } from './SampleEvents'; +import { messages as SampleMessages } from './SampleMessages'; +import { SamplesubScriptions } from './SamplesubScriptions'; export default function Page(): React.JSX.Element { const { t } = useTranslation(); - // return <>helloworld; + const [lessonTypesCount, setLessonTypesCount] = React.useState(0); + const [lessonCategoriesCount, setLessonCategoriesCount] = React.useState(0); + const [usersCount, setUsersCount] = React.useState(0); + + async function fetchAllCount(): Promise { + setLessonTypesCount(await GetAllLessonTypesCount()); + setLessonCategoriesCount(await GetAllLessonCategoriesCount()); + setUsersCount(await GetAllUsersCount()); + } + + React.useEffect(() => { + void fetchAllCount(); + }, []); return ( - + - + - + - + - + - + diff --git a/002_source/cms/src/components/dashboard/overview/summary/ActiveUserCount/index.tsx b/002_source/cms/src/components/dashboard/overview/summary/ActiveUserCount/index.tsx new file mode 100644 index 0000000..e544bd7 --- /dev/null +++ b/002_source/cms/src/components/dashboard/overview/summary/ActiveUserCount/index.tsx @@ -0,0 +1,44 @@ +'use client'; + +import * as React from 'react'; +import getAllUserMetasCount from '@/db/UserMetas/GetAllCount'; +// import GetAllUsersCount from '@/db/Users/GetAllCount.tsx'; +import { Typography } from '@mui/material'; +import { Users as UsersIcon } from '@phosphor-icons/react/dist/ssr/Users'; +import { useTranslation } from 'react-i18next'; + +import { Summary } from '@/components/dashboard/overview/summary'; + +function ActiveUserCount(): React.JSX.Element { + const { t } = useTranslation(); + const [amount, setAmount] = React.useState(0); + const [isLoading, setIsLoading] = React.useState(true); + + React.useEffect(() => { + getAllUserMetasCount() + .then((count) => { + setAmount(count); + setIsLoading(false); + }) + .catch((err) => { + setAmount(-99); + }); + }, []); + + if (isLoading) { + return Loading...; + } + + return ( + + ); +} + +export default ActiveUserCount; diff --git a/002_source/cms/src/components/dashboard/overview/summary/LessonCategoriesCount/index.tsx b/002_source/cms/src/components/dashboard/overview/summary/LessonCategoriesCount/index.tsx new file mode 100644 index 0000000..f9bb170 --- /dev/null +++ b/002_source/cms/src/components/dashboard/overview/summary/LessonCategoriesCount/index.tsx @@ -0,0 +1,52 @@ +'use client'; + +/* +# PROMPT + +this is a subset of a typescript project + +clone `LessonTypeCount`, `LessonCategoriesCount` to `UserCount` and do modifiy to get the count of users, thanks. +*/ +import * as React from 'react'; +import GetAllCount from '@/db/LessonCategories/GetAllCount.tsx'; +import { Typography } from '@mui/material'; +import { ListChecks as ListChecksIcon } from '@phosphor-icons/react/dist/ssr/ListChecks'; +import { useTranslation } from 'react-i18next'; + +import { Summary } from '@/components/dashboard/overview/summary'; + +function LessonCategoriesCount(): React.JSX.Element { + const { t } = useTranslation(); + const [amount, setAmount] = React.useState(0); + const [isLoading, setIsLoading] = React.useState(true); + + React.useEffect(() => { + GetAllCount() + .then((count) => { + setAmount(count); + }) + .catch((err) => { + // console.error(err); + }) + .finally(() => { + setIsLoading(false); + }); + }, []); + + if (isLoading) { + return Loading; + } + + return ( + + ); +} + +export default React.memo(LessonCategoriesCount); diff --git a/002_source/cms/src/components/dashboard/overview/summary/LessonTypeCount/index.tsx b/002_source/cms/src/components/dashboard/overview/summary/LessonTypeCount/index.tsx new file mode 100644 index 0000000..af05527 --- /dev/null +++ b/002_source/cms/src/components/dashboard/overview/summary/LessonTypeCount/index.tsx @@ -0,0 +1,52 @@ +'use client'; + +/* +# PROMPT + +this is a subset of a typescript project + +clone `LessonTypeCount` to `LessonCategoriesCount` and do modifiy to get the count of lesson category, thanks. +*/ +import * as React from 'react'; +import GetAllCount from '@/db/LessonTypes/GetAllCount.tsx'; +import { Typography } from '@mui/material'; +import { ListChecks as ListChecksIcon } from '@phosphor-icons/react/dist/ssr/ListChecks'; +import { useTranslation } from 'react-i18next'; + +import { Summary } from '@/components/dashboard/overview/summary'; + +function LessonTypeCount(): React.JSX.Element { + const { t } = useTranslation(); + const [amount, setAmount] = React.useState(0); + const [isLoading, setIsLoading] = React.useState(true); + + React.useEffect(() => { + GetAllCount() + .then((count) => { + setAmount(count); + }) + .catch((err) => { + // console.error(err); + }) + .finally(() => { + setIsLoading(false); + }); + }, []); + + if (isLoading) { + return Loading...; + } + + return ( + + ); +} + +export default React.memo(LessonTypeCount); diff --git a/002_source/cms/src/components/dashboard/overview/summary.tsx b/002_source/cms/src/components/dashboard/overview/summary/index.tsx similarity index 100% rename from 002_source/cms/src/components/dashboard/overview/summary.tsx rename to 002_source/cms/src/components/dashboard/overview/summary/index.tsx diff --git a/002_source/cms/src/constants.ts b/002_source/cms/src/constants.ts index 0c7fc45..52c8e53 100644 --- a/002_source/cms/src/constants.ts +++ b/002_source/cms/src/constants.ts @@ -3,5 +3,16 @@ const COL_LESSON_CATEGORIES = 'LessonsCategories'; const NO_VALUE = 'NO_VALUE'; const NO_NUM = -Infinity; const NS_LESSON_CATEGORY = 'lesson_category'; +const COL_USERS = 'users'; +const COL_USER_METAS = 'UserMetas'; -export { COL_LESSON_TYPES, NO_VALUE, NO_NUM, COL_LESSON_CATEGORIES, NS_LESSON_CATEGORY }; +export { + COL_LESSON_TYPES, + NO_VALUE, + NO_NUM, + COL_LESSON_CATEGORIES, + NS_LESSON_CATEGORY, + COL_USERS, + COL_USER_METAS, + // +}; diff --git a/002_source/cms/src/db/DB_AI_GUIDELINE.MD b/002_source/cms/src/db/DB_AI_GUIDELINE.MD new file mode 100644 index 0000000..d18d21e --- /dev/null +++ b/002_source/cms/src/db/DB_AI_GUIDELINE.MD @@ -0,0 +1,37 @@ +# AI GUIDELINE + +## Background information and References + +please read `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/001_documentation/Requirements/REQ0006/schema.dbml` + +please look into the md files in `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/_AI_GUIDELINE` + +please read, remember and link up the ideas, i will tell you the task afterwards + +--- + +working directory: `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/db` + +pleaes clone the `tsx` files from `LessonTypes` and `LessonCategories` to `UserMetas` and update the content + +when you draft coding, review file and append with `.tsx.draft` + +--- + +- this is part of react typescript project, with pocketbase +- `schema.dbml`, describe the collections(tables) +- folder `LessonCategories`, the correct references +- folder `LessonTypes`, the correct references +- you can find the `schema.dbml` and schema information from `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/001_documentation/Requirements/REQ0006` +- do not read root directory, assume it is a fresh copy of nextjs project is ok + +## instruction + +- break the questions into smaller parts +- review file append with `.draft`, see if the content aligned with the correct references +- read and understand `dbml` file +- lookup the every folder + +## tasks + +Thanks diff --git a/002_source/cms/src/db/LessonCategories/GetAllCount.tsx b/002_source/cms/src/db/LessonCategories/GetAllCount.tsx new file mode 100644 index 0000000..11d838a --- /dev/null +++ b/002_source/cms/src/db/LessonCategories/GetAllCount.tsx @@ -0,0 +1,11 @@ +// REQ0006 +import { COL_LESSON_CATEGORIES } from '@/constants'; + +import { pb } from '@/lib/pb'; + +export default async function GetAllCount(): Promise { + const { totalItems: count } = await pb + .collection(COL_LESSON_CATEGORIES) + .getList(1, 9999, { filter: 'visible = "visible"' }); + return count; +} diff --git a/002_source/cms/src/db/LessonTypes/Create.tsx b/002_source/cms/src/db/LessonTypes/Create.tsx index 7583bf5..e0afadd 100644 --- a/002_source/cms/src/db/LessonTypes/Create.tsx +++ b/002_source/cms/src/db/LessonTypes/Create.tsx @@ -4,7 +4,6 @@ import type { RecordModel } from 'pocketbase'; import { pb } from '@/lib/pb'; import type { CreateForm } from '@/components/dashboard/lesson_type/types'; -// import type { CreateForm } from '@/components/dashboard/lesson_type/interfaces.ts.del'; export default function createLessonType(data: CreateForm): Promise { return pb.collection(COL_LESSON_TYPES).create(data); diff --git a/002_source/cms/src/db/LessonTypes/GetAllCount.tsx b/002_source/cms/src/db/LessonTypes/GetAllCount.tsx new file mode 100644 index 0000000..00127b1 --- /dev/null +++ b/002_source/cms/src/db/LessonTypes/GetAllCount.tsx @@ -0,0 +1,14 @@ +// REQ0006 +import { COL_LESSON_TYPES } from '@/constants'; + +import { pb } from '@/lib/pb'; + +export default async function GetAllCount(): Promise { + try { + const result = await pb.collection(COL_LESSON_TYPES).getList(1, 9999, { filter: 'visible = "visible"' }); + const { totalItems: count } = result; + return count; + } catch (error) { + return 0; + } +} diff --git a/002_source/cms/src/db/UserMetas/GetAllCount.tsx b/002_source/cms/src/db/UserMetas/GetAllCount.tsx new file mode 100644 index 0000000..4d36d81 --- /dev/null +++ b/002_source/cms/src/db/UserMetas/GetAllCount.tsx @@ -0,0 +1,13 @@ +import { COL_USER_METAS } from '@/constants'; + +import { pb } from '@/lib/pb'; + +export default async function getAllUserMetasCount(): Promise { + try { + const result = await pb.collection(COL_USER_METAS).getList(1, 9998); + return result.totalItems; + } catch (error) { + console.error(error); + return -99; + } +} diff --git a/002_source/cms/src/db/Users/GetAllCount.tsx b/002_source/cms/src/db/Users/GetAllCount.tsx new file mode 100644 index 0000000..b82dc88 --- /dev/null +++ b/002_source/cms/src/db/Users/GetAllCount.tsx @@ -0,0 +1,15 @@ +// REQ0006 +import { COL_USERS } from '@/constants'; + +import { pb } from '@/lib/pb'; + +export default async function GetAllCount(): Promise { + try { + const result = await pb.collection(`users`).getList(1, 9999, { filter: 'email != ""' }); + const { totalItems: count } = result; + return count; + } catch (error) { + console.error(error); + return -99; + } +} diff --git a/002_source/cms/src/db/_PROMPT.MD b/002_source/cms/src/db/_PROMPT.MD deleted file mode 100644 index ff652e7..0000000 --- a/002_source/cms/src/db/_PROMPT.MD +++ /dev/null @@ -1,19 +0,0 @@ -# PROMPT - -with reference to `src/db/LessonTypes/DBLessonTypes.tsx`, clone and modify to fit `DBLessonCategories.tsx` thanks. - ---- - -# PROMPT - -from `LessonTypes`, clone and modify to fit `LessonCategories` (e.g. CRUD) thanks. - ---- - -# PROMPT - -with reference to -- `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/001_documentation/Requirements/REQ0006/schema.dbml` -- `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/db/LessonTypes` - -draft `UserMeta` thanks