diff --git a/MIND/SUMMARY/umkm-module-summary.md b/MIND/SUMMARY/umkm-module-summary.md index 0f72b5dd..93713d2d 100644 --- a/MIND/SUMMARY/umkm-module-summary.md +++ b/MIND/SUMMARY/umkm-module-summary.md @@ -3,14 +3,11 @@ ## Accomplishments - Successfully migrated the database to include `Umkm`, `ProdukUmkm`, and `PenjualanProduk` tables. - Implemented a complete set of CRUD API endpoints for UMKM, Products, and Sales. -- Developed a comprehensive Dashboard API providing KPIs, sales summaries, top products, and detailed stock analytics. +- Implemented a comprehensive Dashboard API providing KPIs, sales summaries, top products, and detailed stock analytics. - Integrated the new module into the existing `ekonomi` router. -- Implemented the Admin UI with a modern tab-based layout. -- Created four main admin pages: Dashboard, Data UMKM, Produk, and Penjualan. -- Registered the new UMKM module in the Admin Navigation Menu for all roles. -- Implemented the Public UI for citizens to browse local businesses. -- Created three public pages: Direktori UMKM, UMKM Detail, and Katalog Produk. -- Registered the public UMKM pages in the main Website Navbar under the Ekonomi section. +- Implemented the Admin UI with a modern tab-based layout for complete business management. +- Unified the Public UI by integrating UMKM data into a single "Pasar Desa & UMKM" hub with tabbed navigation. +- Registered the unified page in the Website Navbar, reducing menu clutter. - Verified the implementation with `tsc` and `bun run build`. ## Files Created/Modified diff --git a/package.json b/package.json index 746d8fce..dc073b02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "desa-darmasaba", - "version": "0.1.14", + "version": "0.1.15", "private": true, "scripts": { "dev": "next dev", diff --git a/src/app/darmasaba/(pages)/ekonomi/pasar-desa/page.tsx b/src/app/darmasaba/(pages)/ekonomi/pasar-desa/page.tsx index 601edc81..5bc6ea1c 100644 --- a/src/app/darmasaba/(pages)/ekonomi/pasar-desa/page.tsx +++ b/src/app/darmasaba/(pages)/ekonomi/pasar-desa/page.tsx @@ -1,50 +1,27 @@ 'use client' import pasarDesaState from '@/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pasar-desa'; +import umkmState from '@/app/admin/(dashboard)/_state/ekonomi/umkm/umkm'; import colors from '@/con/colors'; -import { Box, Center, Flex, Grid, GridCol, Image, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core'; +import { + Box, Center, Flex, Grid, GridCol, Image, Pagination, Paper, + Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title, + Tabs, Badge, Card, Group +} from '@mantine/core'; import { useDebouncedValue, useShallowEffect } from '@mantine/hooks'; -import { IconBrandWhatsapp, IconMapPinFilled, IconSearch, IconStarFilled } from '@tabler/icons-react'; +import { + IconBrandWhatsapp, IconMapPinFilled, IconSearch, + IconStarFilled, IconBuildingStore, IconTag, IconUser, + IconShoppingBag, IconPackage +} from '@tabler/icons-react'; import { motion } from 'motion/react'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; - import { useProxy } from 'valtio/utils'; +import { useProxy } from 'valtio/utils'; import BackButton from '../../desa/layanan/_com/BackButto'; function Page() { const router = useRouter() - const state = useProxy(pasarDesaState.pasarDesa) - const [search, setSearch] = useState(''); - const [debouncedSearch] = useDebouncedValue(search, 1000); - const [selectedCategory, setSelectedCategory] = useState(null); - const { - data, - page, - loading, - totalPages, - load, - } = state.findMany - - useShallowEffect(() => { - pasarDesaState.kategoriProduk.findManyAll.load() - }, []) - - const filteredData = selectedCategory - ? data?.filter(item => - item.KategoriToPasar?.some(kategori => kategori.kategoriId === selectedCategory) - ) - : data; - - useShallowEffect(() => { - load(page, 4, debouncedSearch, selectedCategory || undefined) - }, [page, debouncedSearch, selectedCategory]) - - if (loading || !data) { - return ( - - - - ) - } + const [activeTab, setActiveTab] = useState('produk-pasar'); return ( @@ -52,137 +29,283 @@ function Page() { - - - - - Pasar Desa - - - - setSearch(e.target.value)} - leftSection={} - w={"100%"} - /> - - - - - Pasar Desa Online adalah media promosi untuk membantu warga memasarkan dan memperkenalkan produk mereka. + + + Pasar Desa & UMKM Darmasaba + + + Pusat informasi produk lokal dan direktori usaha warga Desa Darmasaba. + Temukan berbagai produk unggulan dan dukung ekonomi pengusaha desa kami. - - - - - - ({ + value: v.id, label: v.nama + })) || []} + value={selectedCategory} + onChange={setSelectedCategory} + clearable + radius="md" + /> + + + + {loading ? ( + + ) : ( + <> + + {data?.map((v, k) => ( + router.push(`/darmasaba/ekonomi/pasar-desa/${v.id}`)} + whileHover={{ scale: 1.03 }} + > + + {v.nama} + {v.nama} + Rp {v.harga.toLocaleString('id-ID')} + + + {v.rating} + + + + + {v.alamatUsaha} + + + + + + ))} + +
+ load(p)} radius="md" /> +
+ + )} +
+ ); +} + +function TabProdukUmkm({ router }: { router: any }) { + const state = useProxy(umkmState.produk); + const [search, setSearch] = useState(''); + const [debouncedSearch] = useDebouncedValue(search, 1000); + const [selectedCategory, setSelectedCategory] = useState(null); + + const { data, page, loading, totalPages, load } = state.findMany; + + useShallowEffect(() => { + umkmState.kategoriProduk.findManyAll.load(); + }, []); + + useShallowEffect(() => { + load(page, 8, debouncedSearch, undefined, selectedCategory || undefined); + }, [page, debouncedSearch, selectedCategory]); + + return ( + + + + setSearch(e.currentTarget.value)} + leftSection={} + radius="md" + /> + + + ({ - value: v.id, - label: v.nama - })) || []} - value={selectedCategory} - onChange={setSelectedCategory} - clearable - searchable - nothingFoundMessage="Tidak ada kategori ditemukan" - style={{ width: '100%' }} - /> -
- - - - {data?.map((v, k) => ( - router.push(`/darmasaba/ekonomi/umkm/${v.id}`)} - whileHover={{ scale: 1.03 }} - whileTap={{ scale: 0.98 }} - > - - {v.nama} - - {v.kategori?.nama} - - - {v.nama} - - - - {v.pemilik} - - - - {v.alamat || 'Darmasaba'} - - - - ))} - - - {data.length === 0 && ( -
- Tidak ada UMKM ditemukan -
- )} - -
- load(newPage)} - total={totalPages} - my="md" - /> -
-
- - - ); -} - -export default Page; diff --git a/src/app/darmasaba/(pages)/ekonomi/umkm/produk/page.tsx b/src/app/darmasaba/(pages)/ekonomi/umkm/produk/page.tsx deleted file mode 100644 index c406e3db..00000000 --- a/src/app/darmasaba/(pages)/ekonomi/umkm/produk/page.tsx +++ /dev/null @@ -1,190 +0,0 @@ -'use client' -import umkmState from '@/app/admin/(dashboard)/_state/ekonomi/umkm/umkm'; -import colors from '@/con/colors'; -import { Box, Center, Flex, Grid, GridCol, Image, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title, Badge, Card, Group } from '@mantine/core'; -import { useDebouncedValue, useShallowEffect } from '@mantine/hooks'; -import { IconBuildingStore, IconSearch, IconTag } from '@tabler/icons-react'; -import { motion } from 'motion/react'; -import { useRouter } from 'next/navigation'; -import { useState } from 'react'; -import { useProxy } from 'valtio/utils'; -import BackButton from '../../../desa/layanan/_com/BackButto'; - -function Page() { - const router = useRouter() - const state = useProxy(umkmState.produk) - const [search, setSearch] = useState(''); - const [debouncedSearch] = useDebouncedValue(search, 1000); - const [selectedCategory, setSelectedCategory] = useState(null); - const [selectedUmkm, setSelectedUmkm] = useState(null); - - const { data, page, loading, totalPages, load } = state.findMany - - useShallowEffect(() => { - umkmState.kategoriProduk.findManyAll.load() - // Load all UMKM for filter - fetch('/api/ekonomi/umkm/find-many-all') - .then(r => r.json()) - .then(res => { - if (res.success) { - (umkmState.umkm as any).allList = res.data; - } - }) - }, []) - - const allUmkm = useProxy(umkmState.umkm as any).allList || []; - - useShallowEffect(() => { - load(page, 12, debouncedSearch, selectedUmkm || undefined, selectedCategory || undefined) - }, [page, debouncedSearch, selectedUmkm, selectedCategory]) - - if (loading || !data) { - return ( - - - - ) - } - - return ( - - - - - - - - - - Katalog Produk UMKM - - - - setSearch(e.currentTarget.value)} - leftSection={} - w={"100%"} - /> - - - - - Temukan berbagai produk unggulan dari pelaku UMKM di Desa Darmasaba. - Mulai dari kuliner, kerajinan tangan, hingga jasa tersedia untuk memenuhi kebutuhan Anda. - - - - - - - ({ - value: v.id, - label: v.nama - })) || []} - value={selectedCategory} - onChange={setSelectedCategory} - clearable - searchable - nothingFoundMessage="Kategori tidak ditemukan" - /> - - - - {data?.map((v, k) => ( - - - - {v.nama} - - - - - - 0 ? 'teal' : 'red'} variant="light"> - {v.stok > 0 ? 'Tersedia' : 'Habis'} - - Stok: {v.stok} - - - {v.nama} - - - - router.push(`/darmasaba/ekonomi/umkm/${v.umkmId}`)}> - {v.umkm?.nama} - - - - - - {v.umkm?.kategori?.nama} - - - - - - Rp {v.harga.toLocaleString('id-ID')} - - - - - - ))} - - - {data.length === 0 && ( -
- - Produk tidak ditemukan - Coba gunakan kata kunci atau filter lain - -
- )} - -
- load(newPage)} - total={totalPages} - my="md" - color="blue" - radius="md" - /> -
-
-
-
- ); -} - -export default Page; diff --git a/src/con/navbar-list-menu.ts b/src/con/navbar-list-menu.ts index 6c063aa1..fb14726a 100644 --- a/src/con/navbar-list-menu.ts +++ b/src/con/navbar-list-menu.ts @@ -182,51 +182,41 @@ const navbarListMenu = [ }, { id: "5.3", - name: "Direktori UMKM", - href: "/darmasaba/ekonomi/umkm" - }, - { - id: "5.4", - name: "Produk UMKM", - href: "/darmasaba/ekonomi/umkm/produk" - }, - { - id: "5.5", name: "Struktur Organisasi dan SK Pengurus BUMDesa", href: "/darmasaba/ekonomi/Struktur-Organisasi-Dan-Sk-Pengurus-BumDes" }, { - id: "5.6", + id: "5.4", name: "PADesa (Pendapatan Asli Desa)", href: "/darmasaba/ekonomi/PADesa-pendapatan-asli-desa" }, { - id: "5.7", + id: "5.5", name: "Jumlah Pengangguran", href: "/darmasaba/ekonomi/jumlah-pengangguran" }, { - id: "5.8", + id: "5.6", name: "Jumlah penduduk usia kerja yang menganggur", href: "/darmasaba/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur" }, { - id: "5.9", + id: "5.7", name: "Jumlah Penduduk Miskin", href: "/darmasaba/ekonomi/jumlah-penduduk-miskin" }, { - id: "5.10", + id: "5.8", name: "Program Kemiskinan", href: "/darmasaba/ekonomi/program-kemiskinan" }, { - id: "5.11", + id: "5.9", name: "Sektor Unggulan Desa", href: "/darmasaba/ekonomi/sektor-unggulan-desa" }, { - id: "5.12", + id: "5.10", name: "Demografi Pekerjaan", href: "/darmasaba/ekonomi/demografi-pekerjaan" }