From 567d23765105e7e03d314fe032c101d51625cf39 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Thu, 6 Aug 2026 01:03:50 +0700 Subject: [PATCH] feat(dimentorin): backoffice admin panel (dashboard, user mgmt, session mgmt, content/roadmap, feedback, settings) --- .../mentoring/backoffice/content/page.tsx | 234 +++++++++++ .../mentoring/backoffice/feedback/page.tsx | 118 ++++++ .../(public)/mentoring/backoffice/layout.tsx | 147 +++++++ .../(public)/mentoring/backoffice/page.tsx | 206 ++++++++++ .../mentoring/backoffice/sessions/page.tsx | 217 +++++++++++ .../mentoring/backoffice/settings/page.tsx | 189 +++++++++ .../mentoring/backoffice/users/page.tsx | 364 ++++++++++++++++++ libs/service/src/api/dimentorin/index.ts | 69 ++++ libs/service/src/api/users/index.ts | 101 ++++- libs/service/src/hooks/dimentorin/index.ts | 79 +++- libs/service/src/hooks/users/index.ts | 109 +++++- libs/service/src/types/dimentorin/index.ts | 69 ++++ libs/service/src/types/users/index.ts | 88 ++++- 13 files changed, 1979 insertions(+), 11 deletions(-) create mode 100644 apps/dimentorin/src/app/(public)/mentoring/backoffice/content/page.tsx create mode 100644 apps/dimentorin/src/app/(public)/mentoring/backoffice/feedback/page.tsx create mode 100644 apps/dimentorin/src/app/(public)/mentoring/backoffice/layout.tsx create mode 100644 apps/dimentorin/src/app/(public)/mentoring/backoffice/page.tsx create mode 100644 apps/dimentorin/src/app/(public)/mentoring/backoffice/sessions/page.tsx create mode 100644 apps/dimentorin/src/app/(public)/mentoring/backoffice/settings/page.tsx create mode 100644 apps/dimentorin/src/app/(public)/mentoring/backoffice/users/page.tsx diff --git a/apps/dimentorin/src/app/(public)/mentoring/backoffice/content/page.tsx b/apps/dimentorin/src/app/(public)/mentoring/backoffice/content/page.tsx new file mode 100644 index 0000000..887a993 --- /dev/null +++ b/apps/dimentorin/src/app/(public)/mentoring/backoffice/content/page.tsx @@ -0,0 +1,234 @@ +import { FC, ReactElement, useState } from 'react'; +import { Button } from '@imphnen-frontend-service/ui/atoms'; +import { For, Show, cn } from '@imphnen-frontend-service/utils'; +import { + PlusOutlined, + EditOutlined, + DeleteOutlined, + BookOutlined, + FileTextOutlined, + FlagOutlined, +} from '@ant-design/icons'; +import { toast } from 'sonner'; +import { + useGetRoadmapList, + usePostCreateRoadmap, + usePatchUpdateRoadmap, + useDeleteRoadmap, + useGetMaterialsList, +} from '@imphnen-frontend-service/service'; +import { TRoadmapRequest } from '@imphnen-frontend-service/service'; + +const STATUS_STYLE: Record = { + upcoming: 'bg-warning-100 text-warning-800', + in_progress: 'bg-primary-100 text-primary-700', + shipped: 'bg-success-100 text-success-700', +}; + +const STATUS_OPTIONS = ['upcoming', 'in_progress', 'shipped']; + +const emptyForm: TRoadmapRequest = { title: '', description: '', status: 'upcoming' }; + +const Components: FC = (): ReactElement => { + const { data: roadmap, isLoading: roadmapLoading, refetch } = useGetRoadmapList(); + const { data: materials } = useGetMaterialsList(); + const createRoadmap = usePostCreateRoadmap(); + const updateRoadmap = usePatchUpdateRoadmap(); + const deleteRoadmap = useDeleteRoadmap(); + + const [modalOpen, setModalOpen] = useState(false); + const [editingId, setEditingId] = useState(null); + const [form, setForm] = useState(emptyForm); + const [saving, setSaving] = useState(false); + + const items = roadmap ?? []; + const materialList = Array.isArray(materials) ? materials : materials?.data ?? []; + + const openCreate = () => { + setEditingId(null); + setForm(emptyForm); + setModalOpen(true); + }; + + const openEdit = (r: (typeof items)[number]) => { + setEditingId(r.id); + setForm({ title: r.title, description: r.description, status: r.status }); + setModalOpen(true); + }; + + const handleSave = async () => { + if (!form.title || !form.description) { + toast.error('Judul dan deskripsi wajib diisi'); + return; + } + setSaving(true); + try { + if (editingId) { + await updateRoadmap.mutateAsync({ id: editingId, payload: form }); + toast.success('Roadmap diperbarui'); + } else { + await createRoadmap.mutateAsync(form); + toast.success('Roadmap ditambahkan'); + } + setModalOpen(false); + await refetch(); + } catch { + toast.error('Gagal menyimpan roadmap'); + } finally { + setSaving(false); + } + }; + + const handleDelete = async (r: (typeof items)[number]) => { + if (!window.confirm(`Hapus roadmap "${r.title}"?`)) return; + try { + await deleteRoadmap.mutateAsync(r.id); + toast.success('Roadmap dihapus'); + await refetch(); + } catch { + toast.error('Gagal menghapus roadmap'); + } + }; + + const inputCls = + 'w-full rounded-lg border border-neutral-200 p-2 text-sm outline-none focus:border-primary-500 focus:ring-1 focus:ring-primary-500'; + + return ( +
+
+
+

Content & Roadmap

+

Kelola materi mentoring dan jalur belajar.

+
+ +
+ + {/* Materials */} +
+
+ +

Materi Mentoring

+ {materialList.length} materi +
+
+ + + + + + + + + + + + + + + + + {(m) => ( + + + + + + + )} + + +
JudulKategoriStatusDibuat
+ Belum ada materi. +
{m.title}{m.category} + + {m.isPublished ? 'Published' : 'Draft'} + + + {new Date(m.createdAt).toLocaleDateString('id-ID', { day: 'numeric', month: 'short', year: 'numeric' })} +
+
+
+ + {/* Roadmap */} +
+
+ +

Roadmap / Jalur Belajar

+
+ +
Memuat...
+
+
+ +
Belum ada item roadmap.
+
+ + {(r) => ( +
+
+
+

{r.title}

+ + {r.status.replace('_', ' ')} + +
+

{r.description}

+

{r.votes} votes

+
+
+ + +
+
+ )} +
+
+
+ + +
+
+
+

+ {editingId ? 'Edit Roadmap' : 'Tambah Roadmap'} +

+ +
+
+
+ + setForm({ ...form, title: e.target.value })} /> +
+
+ +