update left menu path,
This commit is contained in:
@@ -46,7 +46,7 @@
|
||||
"deleteButton": "刪除"
|
||||
},
|
||||
"list": {
|
||||
"title": "課程類型列表",
|
||||
"title": "課程類型列表1",
|
||||
"message": "請選擇課程類型",
|
||||
"empty": {
|
||||
"title": "目前沒有課程類型",
|
||||
|
@@ -37,8 +37,11 @@
|
||||
"dashboard.lessonTypes.edit.error": "課程類型更新失敗",
|
||||
"dashboard.lessonTypes.delete.success": "課程類型刪除成功",
|
||||
"dashboard.lessonTypes.delete.error": "課程類型刪除失敗",
|
||||
"dashboard.lessonTypes.list": "課程類型列表",
|
||||
"dashboard.lessonTypes.list.title": "課程類型列表",
|
||||
"dashboard.lessonTypes.list": "課程類型",
|
||||
"dashboard.lessonCategories.list": "詞語種類",
|
||||
"dashboard.vocabulary.list": "詞語種類",
|
||||
"dashboard.connective.list": "詞語種類",
|
||||
"dashboard.lessonTypes.list.title": "課程類型列表3",
|
||||
"dashboard.lessonTypes.list.message": "請選擇課程類型",
|
||||
"dashboard.lessonTypes.list.empty": "目前沒有課程類型",
|
||||
"dashboard.lessonTypes.list.empty.title": "目前沒有課程類型",
|
||||
|
@@ -1,104 +0,0 @@
|
||||
# Connective Revision Guidelines
|
||||
|
||||
## Files and component highlight
|
||||
|
||||
1. `_GUIDELINES.md` - this document
|
||||
1. categories
|
||||
|
||||
- list (page.tsx), also containing a button to delete record
|
||||
- read/view ([cat_id]/page.tsx)
|
||||
- create (create/page.tsx)
|
||||
- edit/update (edit/[cat_id]/page.tsx)
|
||||
- optional data for testing(lp-categories-sample-data.tsx)
|
||||
|
||||
1. questions
|
||||
|
||||
- list (page.tsx), also containing a button to delete record
|
||||
- read/view ([cat_id]/page.tsx)
|
||||
- create (create/page.tsx)
|
||||
- edit/update (edit/[cat_id]/page.tsx)
|
||||
- optional data for testing(lp-categories-sample-data.tsx)
|
||||
|
||||
## Prompt Documents
|
||||
|
||||
Each edit page contains `_PROMPT.md` file that provides guidance for editing.
|
||||
|
||||
## Sample Data
|
||||
|
||||
- `categories/lp-categories-sample-data.tsx`: Categories sample data
|
||||
- `questions/cr-categories-sample-data.tsx`: Questions sample data
|
||||
|
||||
## Assumptions & Requirements
|
||||
|
||||
1. Using PocketBase to handle ConnectiveRevision records
|
||||
2. Each ConnectiveRevision record has:
|
||||
- `id` (autogenerated)
|
||||
- `collectionId` (autogenerated)
|
||||
- `collectionName` (autogenerated)
|
||||
- `created` (autogenerated)
|
||||
- `updated` (autogenerated)
|
||||
- `title` (string)
|
||||
- `description` (string)
|
||||
- `category` (string)
|
||||
- `status` (string)
|
||||
- `priority` (number)
|
||||
- `dueDate` (string)
|
||||
- `assignee` (string)
|
||||
- `reporter` (string)
|
||||
- `comments` (array)
|
||||
- `attachments` (array)
|
||||
- `tags` (array)
|
||||
- `related` (array)
|
||||
- `history` (array)
|
||||
|
||||
## Assumption and Requirements
|
||||
|
||||
- the `@` sign refer to `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src`
|
||||
- assume `pb` is located in `@/lib/pb`
|
||||
- type information defined in `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/db/Customers/type.d.tsx`
|
||||
|
||||
## Component Development Guidelines
|
||||
|
||||
### Requirements
|
||||
|
||||
1. **Single Responsibility Principle**:
|
||||
|
||||
2. **File Organization**:
|
||||
|
||||
- One file per component
|
||||
- File name should match component name (PascalCase)
|
||||
- Place components in logical directories based on their purpose
|
||||
|
||||
3. **Type Safety**:
|
||||
|
||||
- Always use TypeScript types/interfaces
|
||||
- Import types from `@/db/Customers/type.d.tsx`
|
||||
|
||||
4. **PocketBase Integration**:
|
||||
- Use `pb` instance from `@/lib/pb`
|
||||
|
||||
### Component Example
|
||||
|
||||
```typescript
|
||||
'use client';
|
||||
|
||||
import { pb } from '@/lib/pb';
|
||||
import { COL_ExampleModel } from '@/constants';
|
||||
import type { ExampleType } from '@/db/ExampleModel/type';
|
||||
|
||||
// common reference to error display, Provide user-friendly error messages
|
||||
import ErrorDisplay from '@/components/dashboard/error';
|
||||
|
||||
// declare `Props` explicitively
|
||||
interface Props {
|
||||
initialData?: ExampleType;
|
||||
}
|
||||
|
||||
export default function ExampleForm({ initialData }: Props) {
|
||||
let { t } = useTranslate();
|
||||
|
||||
// Render form UI
|
||||
return <>helloworld</>
|
||||
}
|
||||
|
||||
```
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -135,7 +135,11 @@ export default function Layout({ children, params }: LayoutProps): React.JSX.Ele
|
||||
const filteredThreads = filterThreads(threads, labelId);
|
||||
|
||||
return (
|
||||
<MailProvider currentLabelId={labelId} labels={labels} threads={filteredThreads}>
|
||||
<MailProvider
|
||||
currentLabelId={labelId}
|
||||
labels={labels}
|
||||
threads={filteredThreads}
|
||||
>
|
||||
<MailView>{children}</MailView>
|
||||
</MailProvider>
|
||||
);
|
||||
|
@@ -0,0 +1,17 @@
|
||||
import * as React from 'react';
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
import { config } from '@/config';
|
||||
import { ThreadView } from '@/components/dashboard/mail/thread-view';
|
||||
|
||||
export const metadata = { title: `Thread | Mail | Dashboard | ${config.site.name}` } satisfies Metadata;
|
||||
|
||||
interface PageProps {
|
||||
params: { threadId: string };
|
||||
}
|
||||
|
||||
export default function Page({ params }: PageProps): React.JSX.Element {
|
||||
const { threadId } = params;
|
||||
|
||||
return <ThreadView threadId={threadId} />;
|
||||
}
|
@@ -0,0 +1,146 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { dayjs } from '@/lib/dayjs';
|
||||
import { MailProvider } from '@/components/dashboard/mail/mail-context';
|
||||
import { MailView } from '@/components/dashboard/mail/mail-view';
|
||||
import type { Label, Thread } from '@/components/dashboard/mail/types';
|
||||
|
||||
function filterThreads(threads: Thread[], labelId: string): Thread[] {
|
||||
return threads.filter((thread) => {
|
||||
if (['inbox', 'sent', 'drafts', 'spam', 'trash'].includes(labelId)) {
|
||||
return thread.folder === labelId;
|
||||
}
|
||||
|
||||
if (labelId === 'important') {
|
||||
return thread.isImportant;
|
||||
}
|
||||
|
||||
if (labelId === 'starred') {
|
||||
return thread.isStarred;
|
||||
}
|
||||
|
||||
if (thread.labels.includes(labelId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
const labels = [
|
||||
{ id: 'inbox', type: 'system', name: 'Inbox', unreadCount: 1, totalCount: 0 },
|
||||
{ id: 'sent', type: 'system', name: 'Sent', unreadCount: 0, totalCount: 0 },
|
||||
{ id: 'drafts', type: 'system', name: 'Drafts', unreadCount: 0, totalCount: 0 },
|
||||
{ id: 'spam', type: 'system', name: 'Spam', unreadCount: 0, totalCount: 0 },
|
||||
{ id: 'trash', type: 'system', name: 'Trash', unreadCount: 0, totalCount: 1 },
|
||||
{ id: 'important', type: 'system', name: 'Important', unreadCount: 0, totalCount: 1 },
|
||||
{ id: 'starred', type: 'system', name: 'Starred', unreadCount: 1, totalCount: 1 },
|
||||
{ id: 'work', type: 'custom', name: 'Work', color: '#43A048', unreadCount: 0, totalCount: 1 },
|
||||
{ id: 'business', type: 'custom', name: 'Business', color: '#1E88E5', unreadCount: 1, totalCount: 2 },
|
||||
{ id: 'personal', type: 'custom', name: 'Personal', color: '#FB8A00', unreadCount: 0, totalCount: 1 },
|
||||
] satisfies Label[];
|
||||
|
||||
const threads = [
|
||||
{
|
||||
id: 'TRD-004',
|
||||
from: { avatar: '/assets/avatar-9.png', email: 'marcus.finn@domain.com', name: 'Marcus Finn' },
|
||||
to: [{ avatar: '/assets/avatar.png', email: 'sofia@devias.io', name: 'Sofia Rivers' }],
|
||||
subject: 'Website redesign. Interested in collaboration',
|
||||
message: `Hey there,
|
||||
|
||||
I hope this email finds you well. I'm glad you liked my projects, and I would be happy to provide you with a quote for a similar project.
|
||||
|
||||
Please let me know your requirements and any specific details you have in mind, so I can give you an accurate quote.
|
||||
|
||||
Looking forward to hearing from you soon.
|
||||
|
||||
Best regards,
|
||||
|
||||
Marcus Finn`,
|
||||
attachments: [
|
||||
{
|
||||
id: 'ATT-001',
|
||||
name: 'working-sketch.png',
|
||||
size: '128.5 KB',
|
||||
type: 'image',
|
||||
url: '/assets/image-abstract-1.png',
|
||||
},
|
||||
{ id: 'ATT-002', name: 'summer-customers.pdf', size: '782.3 KB', type: 'file', url: '#' },
|
||||
{
|
||||
id: 'ATT-003',
|
||||
name: 'desktop-coffee.png',
|
||||
size: '568.2 KB',
|
||||
type: 'image',
|
||||
url: '/assets/image-minimal-1.png',
|
||||
},
|
||||
],
|
||||
folder: 'inbox',
|
||||
labels: ['work', 'business'],
|
||||
isImportant: true,
|
||||
isStarred: false,
|
||||
isUnread: true,
|
||||
createdAt: dayjs().subtract(3, 'hour').toDate(),
|
||||
},
|
||||
{
|
||||
id: 'TRD-003',
|
||||
to: [{ name: 'Sofia Rivers', avatar: '/assets/avatar.png', email: 'sofia@devias.io' }],
|
||||
from: { name: 'Miron Vitold', avatar: '/assets/avatar-1.png', email: 'miron.vitold@domain.com' },
|
||||
subject: 'Amazing work',
|
||||
message: `Hey, nice projects! I really liked the one in react. What's your quote on kinda similar project?`,
|
||||
folder: 'spam',
|
||||
labels: [],
|
||||
isImportant: false,
|
||||
isStarred: true,
|
||||
isUnread: false,
|
||||
createdAt: dayjs().subtract(1, 'day').toDate(),
|
||||
},
|
||||
{
|
||||
id: 'TRD-002',
|
||||
from: { name: 'Penjani Inyene', avatar: '/assets/avatar-4.png', email: 'penjani.inyene@domain.com' },
|
||||
to: [{ name: 'Sofia Rivers', avatar: '/assets/avatar.png', email: 'sofia@devias.io' }],
|
||||
subject: 'Flight reminder',
|
||||
message: `Dear Sofia,
|
||||
|
||||
Your flight is coming up soon. Please don't forget to check in for your scheduled flight.`,
|
||||
folder: 'inbox',
|
||||
labels: ['business'],
|
||||
isImportant: false,
|
||||
isStarred: false,
|
||||
isUnread: false,
|
||||
createdAt: dayjs().subtract(2, 'day').toDate(),
|
||||
},
|
||||
{
|
||||
id: 'TRD-001',
|
||||
from: { name: 'Carson Darrin', avatar: '/assets/avatar-3.png', email: 'carson.darrin@domain.com' },
|
||||
to: [{ name: 'Sofia Rivers', avatar: '/assets/avatar.png', email: 'sofia@devias.io' }],
|
||||
subject: 'Possible candidates for the position',
|
||||
message: `My market leading client has another fantastic opportunity for an experienced Software Developer to join them on a heavily remote basis`,
|
||||
folder: 'trash',
|
||||
labels: ['personal'],
|
||||
isImportant: false,
|
||||
isStarred: false,
|
||||
isUnread: true,
|
||||
createdAt: dayjs().subtract(2, 'day').toDate(),
|
||||
},
|
||||
] satisfies Thread[];
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
params: { labelId: string };
|
||||
}
|
||||
|
||||
export default function Layout({ children, params }: LayoutProps): React.JSX.Element {
|
||||
const { labelId } = params;
|
||||
|
||||
const filteredThreads = filterThreads(threads, labelId);
|
||||
|
||||
return (
|
||||
<MailProvider
|
||||
currentLabelId={labelId}
|
||||
labels={labels}
|
||||
threads={filteredThreads}
|
||||
>
|
||||
<MailView>{children}</MailView>
|
||||
</MailProvider>
|
||||
);
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
import { config } from '@/config';
|
||||
import { ThreadsView } from '@/components/dashboard/mail/threads-view';
|
||||
|
||||
export const metadata = { title: `Mail | Dashboard | ${config.site.name}` } satisfies Metadata;
|
||||
|
||||
export default function Page(): React.JSX.Element {
|
||||
return <ThreadsView />;
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
import { config } from '@/config';
|
||||
import { ThreadsView } from '@/components/dashboard/mail/threads-view';
|
||||
|
||||
export const metadata = { title: `Mail | Dashboard | ${config.site.name}` } satisfies Metadata;
|
||||
|
||||
export default function Page(): React.JSX.Element {
|
||||
return <ThreadsView />;
|
||||
}
|
@@ -35,32 +35,25 @@ export const layoutConfig = {
|
||||
key: 'lesson-types',
|
||||
title: 'dashboard.lessonTypes.list',
|
||||
href: paths.dashboard.lesson_types.list,
|
||||
//
|
||||
},
|
||||
{
|
||||
key: 'lesson-types:create',
|
||||
title: 'dashboard.lessonTypes.create',
|
||||
href: paths.dashboard.lesson_types.create,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'lesson-categories',
|
||||
title: 'categories',
|
||||
icon: 'users',
|
||||
items: [
|
||||
{
|
||||
key: 'lesson-categories',
|
||||
title: 'dashboard.lessonTypes.list',
|
||||
title: 'dashboard.lessonCategories.list',
|
||||
href: paths.dashboard.lesson_categories.list,
|
||||
},
|
||||
{
|
||||
key: 'lesson-categories:create',
|
||||
title: 'dashboard.lessonTypes.create',
|
||||
href: paths.dashboard.lesson_categories.create,
|
||||
key: 'vocabulary',
|
||||
title: 'dashboard.vocabulary.list',
|
||||
href: paths.dashboard.vocabulary.list,
|
||||
},
|
||||
{
|
||||
key: 'connectives',
|
||||
title: 'dashboard.connective.list',
|
||||
href: paths.dashboard.connectives.list,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'quiz_lp',
|
||||
title: 'listening-practice',
|
||||
@@ -124,9 +117,10 @@ export const layoutConfig = {
|
||||
title: 'teachers',
|
||||
icon: 'users',
|
||||
items: [
|
||||
{ key: 'teachers', title: 'List teachers', href: paths.dashboard.teachers.list },
|
||||
{ key: 'teachers:create', title: 'Create teacher', href: paths.dashboard.teachers.create },
|
||||
{ key: 'teachers:details', title: 'Teacher details', href: paths.dashboard.teachers.details('1') },
|
||||
{ key: 'teachers', title: 'List', href: paths.dashboard.teachers.list },
|
||||
{ key: 'teacher-mail', title: 'Mail', href: paths.dashboard.teachers.mail.list('1') },
|
||||
// { key: 'teachers:create', title: 'Create teacher', href: paths.dashboard.teachers.create },
|
||||
// { key: 'teachers:details', title: 'Teacher details', href: paths.dashboard.teachers.details('1') },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@@ -77,61 +77,79 @@ export const paths = {
|
||||
},
|
||||
crypto: '/dashboard/crypto',
|
||||
lesson_types: {
|
||||
list: '/dashboard/lesson_types',
|
||||
list: '/dashboard/lesson_types/list',
|
||||
create: '/dashboard/lesson_types/create',
|
||||
details: (id: string) => `/dashboard/lesson_types/${id}`,
|
||||
details: (id: string) => `/dashboard/lesson_types/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/lesson_types/edit/${id}`,
|
||||
},
|
||||
lesson_categories: {
|
||||
list: '/dashboard/lesson_categories',
|
||||
list: '/dashboard/lesson_categories/list',
|
||||
create: '/dashboard/lesson_categories/create',
|
||||
details: (id: string) => `/dashboard/lesson_categories/${id}`,
|
||||
details: (id: string) => `/dashboard/lesson_categories/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/lesson_categories/edit/${id}`,
|
||||
},
|
||||
vocabulary: {
|
||||
list: '/dashboard/vocabulary/list',
|
||||
create: '/dashboard/vocabulary/create',
|
||||
details: (id: string) => `/dashboard/vocabulary/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/vocabulary/edit/${id}`,
|
||||
},
|
||||
connectives: {
|
||||
list: '/dashboard/connectives/list',
|
||||
create: '/dashboard/connectives/create',
|
||||
details: (id: string) => `/dashboard/connectives/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/connectives/edit/${id}`,
|
||||
},
|
||||
lp_categories: {
|
||||
list: '/dashboard/lp/categories',
|
||||
list: '/dashboard/lp/categories/list',
|
||||
create: '/dashboard/lp/categories/create',
|
||||
details: (id: string) => `/dashboard/lp/categories/${id}`,
|
||||
details: (id: string) => `/dashboard/lp/categories/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/lp/categories/edit/${id}`,
|
||||
},
|
||||
lp_questions: {
|
||||
list: '/dashboard/lp/questions',
|
||||
list: '/dashboard/lp/questions/list',
|
||||
create: '/dashboard/lp/questions/create',
|
||||
details: (id: string) => `/dashboard/lp/questions/${id}`,
|
||||
details: (id: string) => `/dashboard/lp/questions/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/lp/questions/edit/${id}`,
|
||||
},
|
||||
mf_categories: {
|
||||
list: '/dashboard/mf/categories',
|
||||
list: '/dashboard/mf/categories/list',
|
||||
create: '/dashboard/mf/categories/create',
|
||||
details: (id: string) => `/dashboard/mf/categories/${id}`,
|
||||
details: (id: string) => `/dashboard/mf/categories/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/mf/categories/edit/${id}`,
|
||||
},
|
||||
mf_questions: {
|
||||
list: '/dashboard/mf/questions',
|
||||
list: '/dashboard/mf/questions/list',
|
||||
create: '/dashboard/mf/questions/create',
|
||||
details: (id: string) => `/dashboard/mf/questions/${id}`,
|
||||
details: (id: string) => `/dashboard/mf/questions/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/mf/questions/edit/${id}`,
|
||||
},
|
||||
cr_categories: {
|
||||
list: '/dashboard/cr/categories',
|
||||
list: '/dashboard/cr/categories/list',
|
||||
create: '/dashboard/cr/categories/create',
|
||||
details: (id: string) => `/dashboard/cr/categories/${id}`,
|
||||
details: (id: string) => `/dashboard/cr/categories/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/cr/categories/edit/${id}`,
|
||||
},
|
||||
cr_questions: {
|
||||
list: '/dashboard/cr/questions',
|
||||
list: '/dashboard/cr/questions/list',
|
||||
create: '/dashboard/cr/questions/create',
|
||||
details: (id: string) => `/dashboard/cr/questions/${id}`,
|
||||
details: (id: string) => `/dashboard/cr/questions/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/cr/questions/edit/${id}`,
|
||||
},
|
||||
teachers: {
|
||||
list: '/dashboard/teachers',
|
||||
list: '/dashboard/teachers/list',
|
||||
create: '/dashboard/teachers/create',
|
||||
details: (id: string) => `/dashboard/teachers/${id}`,
|
||||
details: (id: string) => `/dashboard/teachers/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/teachers/edit/${id}`,
|
||||
mail: {
|
||||
list: (id: string) => `/dashboard/teachers/mail/${id}/list`,
|
||||
// create: '/dashboard/teachers/create',
|
||||
// details: (id: string) => `/dashboard/teachers/${id}`,
|
||||
// edit: (id: string) => `/dashboard/teachers/edit/${id}`,
|
||||
},
|
||||
},
|
||||
students: {
|
||||
list: '/dashboard/students',
|
||||
list: '/dashboard/students/list',
|
||||
create: '/dashboard/students/create',
|
||||
view: (id: string) => `/dashboard/students/view/${id}`,
|
||||
edit: (id: string) => `/dashboard/students/edit/${id}`,
|
||||
|
Reference in New Issue
Block a user