feat(backoffice): slicing backoffice dimentorin - content & roadmap
This commit is contained in:
+85
@@ -0,0 +1,85 @@
|
|||||||
|
import { ArrowRightOutlined } from "@ant-design/icons";
|
||||||
|
import { Button, Input, Select, Textarea } from "@imphnen-frontend-service/ui/atoms";
|
||||||
|
import { Accordion, Modal, ModalProps } from "@imphnen-frontend-service/ui/molecules";
|
||||||
|
import { cn, For } from "@imphnen-frontend-service/utils";
|
||||||
|
import { FC } from "react";
|
||||||
|
|
||||||
|
const labelClass = cn('text-neutral-800 text-[10px] font-medium mb-1.5 inline-block md:text-xs md:mb-2 xl:text-p3')
|
||||||
|
|
||||||
|
export const ModalCreateRoadmap: FC<Omit<ModalProps, 'children'>> = ({ isOpen, onClose }) => {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={onClose}
|
||||||
|
className="xl:max-w-[64rem] bg-white px-10 py-9"
|
||||||
|
closeButtonClassName="hidden"
|
||||||
|
>
|
||||||
|
<div className="overflow-y-auto max-h-[80vh]">
|
||||||
|
<h1 className="bg-primary-50 px-6 py-3 text-neutral-800 text-p2 font-semibold mb-8">
|
||||||
|
Create Roadmaps
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-5 gap-6 mb-12">
|
||||||
|
<div className="col-span-3">
|
||||||
|
<label className={labelClass}>Prompt</label>
|
||||||
|
<Textarea
|
||||||
|
className="min-w-full w-full h-[calc(100%-2rem)]"
|
||||||
|
placeholder="Create a learning roadmap for (subject) at the (level) level. Include topics, estimated duration, and logical progression."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2 space-y-8">
|
||||||
|
<div>
|
||||||
|
<label className={labelClass}>Roadmap Name</label>
|
||||||
|
<Input type="text" className="min-w-full w-full" placeholder="Nama Roadmap" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className={labelClass}>Roadmap Name</label>
|
||||||
|
<Select className="w-full">
|
||||||
|
<option value="pemula">Pemula</option>
|
||||||
|
<option value="menengah">Menengah</option>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className={labelClass}>Model</label>
|
||||||
|
<Select className="w-full">
|
||||||
|
<option value="gpt-3.5-turbo">GPT 3.5 Turbo</option>
|
||||||
|
<option value="gpt-4">GPT 4</option>
|
||||||
|
<option value="gpt-4-32k">GPT 4 32k</option>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-span-full">
|
||||||
|
<Button>
|
||||||
|
Generate Roadmap
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 className="text-neutral-600 text-p2 font-semibold mb-8">
|
||||||
|
Roadmap Preview
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-2.5">
|
||||||
|
<For data={Array.from({ length: 3 })}>
|
||||||
|
{(_, index) => (
|
||||||
|
<Accordion
|
||||||
|
key={index}
|
||||||
|
title={`Day ${index + 1}`}
|
||||||
|
description="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In convallis tincidunt nisl, id consequat mi malesuada vel. Nulla facilisi. Nam in turpis ligula."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-end mt-12">
|
||||||
|
<Button type="button" className="flex items-center gap-5">
|
||||||
|
Submit Roadmap
|
||||||
|
<ArrowRightOutlined />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
import { DeleteOutlined, EditOutlined, PlusOutlined, SearchOutlined } from "@ant-design/icons";
|
||||||
|
import { Button, Input, Select } from "@imphnen-frontend-service/ui/atoms";
|
||||||
|
import { BackofficeWrapper, DataTable } from "@imphnen-frontend-service/ui/organisms";
|
||||||
|
import { cn } from "@imphnen-frontend-service/utils";
|
||||||
|
import { ColumnDef, getCoreRowModel, getPaginationRowModel, PaginationState, RowSelectionState, useReactTable } from "@tanstack/react-table";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ModalCreateRoadmap } from "./_components/modal/create-roadmap";
|
||||||
|
|
||||||
|
type LearningStatus = 'active' | 'inactive'
|
||||||
|
|
||||||
|
type RoadmapType = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
learningLevel: string
|
||||||
|
status: LearningStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockData: RoadmapType[] = Array.from({ length: 90 }, (_, i) => ({
|
||||||
|
id: i + 1,
|
||||||
|
name: i === 0 ? 'Ahmad Wijuana' : 'Anna Wiguana',
|
||||||
|
learningLevel: ['Pemula', 'Menengah'][Math.floor(Math.random() * 2)],
|
||||||
|
status: i % 2 === 0 ? 'active' : 'inactive',
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default function Components(): React.ReactElement {
|
||||||
|
const [openCreateModal, setOpenCreateModal] = useState(false)
|
||||||
|
|
||||||
|
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
|
||||||
|
const [pagination, setPagination] = useState<PaginationState>({
|
||||||
|
pageIndex: 0,
|
||||||
|
pageSize: 9,
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns: ColumnDef<RoadmapType>[] = [
|
||||||
|
{
|
||||||
|
id: 'select',
|
||||||
|
meta: { cellClassName: cn("w-20") },
|
||||||
|
header: ({ table }) => (
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="rounded"
|
||||||
|
checked={table.getIsAllRowsSelected()}
|
||||||
|
onChange={table.getToggleAllRowsSelectedHandler()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="rounded"
|
||||||
|
checked={row.getIsSelected()}
|
||||||
|
onChange={row.getToggleSelectedHandler()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'id',
|
||||||
|
header: 'No',
|
||||||
|
accessorKey: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
header: 'Nama Roadmap',
|
||||||
|
accessorKey: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'learningLevel',
|
||||||
|
header: 'Tingkat Belajar',
|
||||||
|
accessorKey: 'learningLevel',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'status',
|
||||||
|
header: 'Status',
|
||||||
|
accessorKey: 'status',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const status = row.original.status;
|
||||||
|
const statusColors: Record<LearningStatus, string> = {
|
||||||
|
inactive: 'bg-danger-200 text-danger-700',
|
||||||
|
active: 'bg-success-200 text-success-500',
|
||||||
|
};
|
||||||
|
const statusText: Record<LearningStatus, string> = {
|
||||||
|
inactive: 'Inactive',
|
||||||
|
active: 'Active',
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`py-2 px-4 rounded-md text-center ${statusColors[status]}`}
|
||||||
|
>
|
||||||
|
{statusText[status]}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Action',
|
||||||
|
meta: { cellClassName: cn("w-72") },
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<div className="flex gap-[8px]">
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
size="sm"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<EditOutlined /> Action
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="danger"
|
||||||
|
size="sm"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<DeleteOutlined /> Delete
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const table = useReactTable({
|
||||||
|
data: mockData,
|
||||||
|
columns,
|
||||||
|
state: {
|
||||||
|
pagination,
|
||||||
|
rowSelection,
|
||||||
|
},
|
||||||
|
enableRowSelection: true,
|
||||||
|
onRowSelectionChange: setRowSelection,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
onPaginationChange: setPagination,
|
||||||
|
pageCount: Math.ceil(mockData.length / pagination.pageSize),
|
||||||
|
manualPagination: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BackofficeWrapper title="Dimentorin.dev">
|
||||||
|
<h1 className="text-p1 font-semibold text-neutral-700 mb-8">Content & Roadmap</h1>
|
||||||
|
|
||||||
|
<section className="flex flex-col gap-6 p-8 bg-white rounded-md">
|
||||||
|
<div className="flex items-center justify-between mb-9">
|
||||||
|
<h2 className="text-p2 font-semibold text-neutral-600">AI Roadmaps</h2>
|
||||||
|
<Button type="button" variant="primary" className="flex items-center gap-2" onClick={() => setOpenCreateModal(true)}>
|
||||||
|
<PlusOutlined /> Buat Roadmap
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-between items-center gap-5 mb-2">
|
||||||
|
<div className="relative w-full">
|
||||||
|
<Input
|
||||||
|
placeholder="Cari berdasarkan nama roadmap"
|
||||||
|
className="pl-12 w-full max-h-full"
|
||||||
|
/>
|
||||||
|
<div className="absolute left-3 top-1/2 transform -translate-y-1/2 text-[16px]">
|
||||||
|
<SearchOutlined />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Select>
|
||||||
|
<option selected disabled>Tingkat Belajar</option>
|
||||||
|
<option value="pemula">Pemula</option>
|
||||||
|
<option value="menengah">Menengah</option>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DataTable data={mockData} columns={columns} table={table} />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<ModalCreateRoadmap isOpen={openCreateModal} onClose={() => setOpenCreateModal(false)} />
|
||||||
|
</BackofficeWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
AppstoreOutlined,
|
AppstoreOutlined,
|
||||||
AuditOutlined,
|
AuditOutlined,
|
||||||
|
BookOutlined,
|
||||||
InboxOutlined,
|
InboxOutlined,
|
||||||
LogoutOutlined,
|
LogoutOutlined,
|
||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
@@ -26,6 +27,7 @@ const MENUS = [
|
|||||||
{ label: 'Data Pengiriman Hadiah', href: '/prizes', icon: <InboxOutlined className="text-[20px]" /> },
|
{ label: 'Data Pengiriman Hadiah', href: '/prizes', icon: <InboxOutlined className="text-[20px]" /> },
|
||||||
{ label: 'User - Dimentorin', href: '/users-dimentorin', icon: <UserSwitchOutlined className="text-[20px]" /> },
|
{ label: 'User - Dimentorin', href: '/users-dimentorin', icon: <UserSwitchOutlined className="text-[20px]" /> },
|
||||||
{ label: 'Session - Dimentorin', href: '/session-dimentorin', icon: <ScheduleOutlined className="text-[20px]" /> },
|
{ label: 'Session - Dimentorin', href: '/session-dimentorin', icon: <ScheduleOutlined className="text-[20px]" /> },
|
||||||
|
{ label: 'Content & Roadmap', href: '/roadmap-dimentorin', icon: <BookOutlined className="text-[20px]" /> },
|
||||||
{ label: 'Settings - Dimentorin', href: '/settings-dimentorin', icon: <SettingOutlined className="text-[20px]" /> },
|
{ label: 'Settings - Dimentorin', href: '/settings-dimentorin', icon: <SettingOutlined className="text-[20px]" /> },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user