From 3fe18b77a959e433d380270bfbe972f57c50f929 Mon Sep 17 00:00:00 2001 From: bipproduction Date: Mon, 8 Jul 2024 10:32:45 +0800 Subject: [PATCH] tambahan untuk divisi --- next.config.mjs | 6 +- package.json | 7 +- src/app/(dev-test)/test-division/layout.tsx | 5 +- src/app/(dev-test)/test-division/page.tsx | 24 +++- .../test-devision/count-devision/route.ts | 5 + .../test-devision/list-anggota/route.ts | 6 + .../test-devision/list-devision/route.ts | 0 .../test-devision/list-division/route.ts | 6 + .../test-devision/list-group/route.ts | 6 + src/app/api/division/get/route.ts | 4 + src/app/api/division/post/route.tsx | 4 + .../division/dummy => dummy_data}/index.ts | 0 .../dummy => dummy_data}/list_devision.json | 0 src/lib/apiFetch.ts | 51 ++++++++ src/lib/pagePath.ts | 111 ++++++++++++++++++ src/lib/stateApi.ts | 107 +++++++++++++++++ src/module/division/api/api_division.ts | 16 +++ .../division/component/BottomDrawer.tsx | 68 +++++++++++ .../division/component/ContainerDivision.tsx | 26 ++++ .../division/component/HeadDivision.tsx | 36 ++++++ .../division/component/ListDivision.tsx | 11 ++ .../division/component/ListWithSearch.tsx | 40 +++++++ .../division/component/MorePeopleIcon.tsx | 16 +++ .../division/component/SearchDivision.tsx | 8 ++ src/module/division/component/ToogleList.tsx | 17 +++ src/module/division/component/ViewGrid.tsx | 36 ++++++ src/module/division/component/ViewList.tsx | 23 ++++ src/module/division/lib/BottomMenu.tsx | 33 ++++++ src/module/division/lib/ButtonConfirm.tsx | 25 ++++ src/module/division/lib/ButtonNavi.tsx | 6 + src/module/division/lib/MultiSelectList.tsx | 53 +++++++++ src/module/division/lib/SingleSelect.tsx | 46 ++++++++ src/module/division/lib/WebVitals.tsx | 12 ++ src/module/division/lib/devision_state.ts | 14 +++ .../lib/division/get_count_devision.ts | 5 + .../division/lib/division/get_list_anggota.ts | 45 +++++++ .../lib/division/get_list_devision.ts | 5 + .../division/lib/division/get_list_group.ts | 18 +++ src/module/division/lib/toast.tsx | 20 ++++ src/module/division/ui/DevisionPage.tsx | 7 -- src/module/division/ui/DivisionCreate.tsx | 81 +++++++++++++ src/module/division/ui/DivisionFilter.tsx | 22 ++++ ...{DevisionLayout.tsx => DivisionLayout.tsx} | 4 +- src/module/division/ui/DivisionPage.tsx | 21 ++++ src/module/division/ui/DivisionReport.tsx | 5 + src/module/division/ui/DivisionView.tsx | 10 ++ yarn.lock | 43 ++++++- 47 files changed, 1094 insertions(+), 20 deletions(-) create mode 100644 src/app/api/(dev-test)/test-devision/count-devision/route.ts create mode 100644 src/app/api/(dev-test)/test-devision/list-anggota/route.ts delete mode 100644 src/app/api/(dev-test)/test-devision/list-devision/route.ts create mode 100644 src/app/api/(dev-test)/test-devision/list-division/route.ts create mode 100644 src/app/api/(dev-test)/test-devision/list-group/route.ts create mode 100644 src/app/api/division/get/route.ts create mode 100644 src/app/api/division/post/route.tsx rename src/{module/division/dummy => dummy_data}/index.ts (100%) rename src/{module/division/dummy => dummy_data}/list_devision.json (100%) create mode 100644 src/lib/apiFetch.ts create mode 100644 src/lib/pagePath.ts create mode 100644 src/lib/stateApi.ts create mode 100644 src/module/division/api/api_division.ts create mode 100644 src/module/division/component/BottomDrawer.tsx create mode 100644 src/module/division/component/ContainerDivision.tsx create mode 100644 src/module/division/component/HeadDivision.tsx create mode 100644 src/module/division/component/ListDivision.tsx create mode 100644 src/module/division/component/ListWithSearch.tsx create mode 100644 src/module/division/component/MorePeopleIcon.tsx create mode 100644 src/module/division/component/SearchDivision.tsx create mode 100644 src/module/division/component/ToogleList.tsx create mode 100644 src/module/division/component/ViewGrid.tsx create mode 100644 src/module/division/component/ViewList.tsx create mode 100644 src/module/division/lib/BottomMenu.tsx create mode 100644 src/module/division/lib/ButtonConfirm.tsx create mode 100644 src/module/division/lib/ButtonNavi.tsx create mode 100644 src/module/division/lib/MultiSelectList.tsx create mode 100644 src/module/division/lib/SingleSelect.tsx create mode 100644 src/module/division/lib/WebVitals.tsx create mode 100644 src/module/division/lib/devision_state.ts create mode 100644 src/module/division/lib/division/get_count_devision.ts create mode 100644 src/module/division/lib/division/get_list_anggota.ts create mode 100644 src/module/division/lib/division/get_list_devision.ts create mode 100644 src/module/division/lib/division/get_list_group.ts create mode 100644 src/module/division/lib/toast.tsx delete mode 100644 src/module/division/ui/DevisionPage.tsx create mode 100644 src/module/division/ui/DivisionCreate.tsx create mode 100644 src/module/division/ui/DivisionFilter.tsx rename src/module/division/ui/{DevisionLayout.tsx => DivisionLayout.tsx} (62%) create mode 100644 src/module/division/ui/DivisionPage.tsx create mode 100644 src/module/division/ui/DivisionReport.tsx create mode 100644 src/module/division/ui/DivisionView.tsx diff --git a/next.config.mjs b/next.config.mjs index 4678774..059cc82 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,8 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + devIndicators: { + buildActivityPosition: 'bottom-right', + }, +}; export default nextConfig; diff --git a/package.json b/package.json index d3ae8ba..2f92bd9 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "seed": "tsx prisma/seed.ts" }, "dependencies": { + "@hookstate/core": "^4.0.1", + "@hookstate/localstored": "^4.0.2", "@mantine/carousel": "^7.11.1", "@mantine/charts": "^7.11.0", "@mantine/code-highlight": "^7.11.0", @@ -30,13 +32,16 @@ "@tiptap/extension-link": "^2.4.0", "@tiptap/react": "^2.4.0", "@tiptap/starter-kit": "^2.4.0", + "@types/lodash": "^4.17.6", "dayjs": "^1.11.11", "embla-carousel-autoplay": "^7.1.0", "embla-carousel-react": "^7.1.0", + "lodash": "^4.17.21", "next": "14.2.4", "react": "^18", "react-dom": "^18", "react-icons": "^5.2.1", + "react-simple-toasts": "^5.10.0", "recharts": "2" }, "devDependencies": { @@ -58,4 +63,4 @@ "keywords": [], "author": "", "license": "ISC" -} \ No newline at end of file +} diff --git a/src/app/(dev-test)/test-division/layout.tsx b/src/app/(dev-test)/test-division/layout.tsx index 7584196..ad0bd7f 100644 --- a/src/app/(dev-test)/test-division/layout.tsx +++ b/src/app/(dev-test)/test-division/layout.tsx @@ -1,7 +1,8 @@ -import { DevisionLayout } from "@/module/division/ui/DevisionLayout"; +import { DevisionLayout } from "@/module/division/ui/DivisionLayout"; + export default function Layout({ children }: { children: React.ReactNode }) { return {children} - ; + } \ No newline at end of file diff --git a/src/app/(dev-test)/test-division/page.tsx b/src/app/(dev-test)/test-division/page.tsx index 1f54dfa..107ea6b 100644 --- a/src/app/(dev-test)/test-division/page.tsx +++ b/src/app/(dev-test)/test-division/page.tsx @@ -1,6 +1,22 @@ -import { DevisionPage } from "@/module/division/ui/DevisionPage"; -import { Stack } from "@mantine/core"; -export default function Page() { - return +import { DivisionPage } from "@/module/division/ui/DivisionPage"; +import { SimpleGrid, Skeleton, Stack } from "@mantine/core"; +import { Suspense } from "react"; + +export default function Page({ params, searchParams }: { params: any, searchParams: any }) { + + return + + + + + + + + + + + }> + + } \ No newline at end of file diff --git a/src/app/api/(dev-test)/test-devision/count-devision/route.ts b/src/app/api/(dev-test)/test-devision/count-devision/route.ts new file mode 100644 index 0000000..3ca3fb4 --- /dev/null +++ b/src/app/api/(dev-test)/test-devision/count-devision/route.ts @@ -0,0 +1,5 @@ +import { getCountDivision } from "@/module/division/lib/division/get_count_devision" +export async function GET() { + const countDivision = getCountDivision() + return Response.json({ count: countDivision }) +} \ No newline at end of file diff --git a/src/app/api/(dev-test)/test-devision/list-anggota/route.ts b/src/app/api/(dev-test)/test-devision/list-anggota/route.ts new file mode 100644 index 0000000..e66464d --- /dev/null +++ b/src/app/api/(dev-test)/test-devision/list-anggota/route.ts @@ -0,0 +1,6 @@ +import { getListAnggota } from "@/module/division/lib/division/get_list_anggota"; + +export async function GET() { + const listAnggota = await getListAnggota() + return Response.json(listAnggota) +} \ No newline at end of file diff --git a/src/app/api/(dev-test)/test-devision/list-devision/route.ts b/src/app/api/(dev-test)/test-devision/list-devision/route.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/api/(dev-test)/test-devision/list-division/route.ts b/src/app/api/(dev-test)/test-devision/list-division/route.ts new file mode 100644 index 0000000..b33e0ce --- /dev/null +++ b/src/app/api/(dev-test)/test-devision/list-division/route.ts @@ -0,0 +1,6 @@ +import { getListDevision } from "@/module/division/lib/division/get_list_devision" + +export async function GET() { + const list_devision = await getListDevision() + return Response.json(list_devision) +} \ No newline at end of file diff --git a/src/app/api/(dev-test)/test-devision/list-group/route.ts b/src/app/api/(dev-test)/test-devision/list-group/route.ts new file mode 100644 index 0000000..17015e4 --- /dev/null +++ b/src/app/api/(dev-test)/test-devision/list-group/route.ts @@ -0,0 +1,6 @@ +import { getListGroup } from "@/module/division/lib/division/get_list_group" + +export async function GET() { + const listGroup = await getListGroup() + return Response.json(listGroup) +} \ No newline at end of file diff --git a/src/app/api/division/get/route.ts b/src/app/api/division/get/route.ts new file mode 100644 index 0000000..5f2c972 --- /dev/null +++ b/src/app/api/division/get/route.ts @@ -0,0 +1,4 @@ +import { apiDivision } from "@/module/division/api/api_division"; +export async function GET(req: Request) { + return apiDivision(req, "GET") +} \ No newline at end of file diff --git a/src/app/api/division/post/route.tsx b/src/app/api/division/post/route.tsx new file mode 100644 index 0000000..dd75154 --- /dev/null +++ b/src/app/api/division/post/route.tsx @@ -0,0 +1,4 @@ +import { apiDivision } from "@/module/division/api/api_division"; +export async function POST(req: Request) { + return apiDivision(req, "POST") +} \ No newline at end of file diff --git a/src/module/division/dummy/index.ts b/src/dummy_data/index.ts similarity index 100% rename from src/module/division/dummy/index.ts rename to src/dummy_data/index.ts diff --git a/src/module/division/dummy/list_devision.json b/src/dummy_data/list_devision.json similarity index 100% rename from src/module/division/dummy/list_devision.json rename to src/dummy_data/list_devision.json diff --git a/src/lib/apiFetch.ts b/src/lib/apiFetch.ts new file mode 100644 index 0000000..5e0855c --- /dev/null +++ b/src/lib/apiFetch.ts @@ -0,0 +1,51 @@ +interface Params { + searchParams?: Record; + token?: string; + body?: Record; +} + +async function funPramas(url: string, method: string, params?: Params) { + const property: Record = {}; + if (params) { + if (params.searchParams) { + property.searchParams = + "?" + new URLSearchParams(params.searchParams).toString(); + } + + if (params.body) { + property.body = JSON.stringify(params.body); + } + + if (params.token) { + property.headers.Authorization = `Bearer ${params.token}`; + } + } + property.method = method; + try { + const res = await fetch(`${url}${property?.searchParams || ""}`, property); + return await res.json().catch(() => null); + } catch { + return null; + } +} + +export const apiPathTestDevisionListGroupGET = () => + `/api/test-devision/list-group/`; +export const apiFetchTestDevisionListGroupGET = async (params?: Params) => + funPramas(apiPathTestDevisionListGroupGET(), "GET", params); + +export const apiPathTestDevisionListDivisionGET = () => + `/api/test-devision/list-division/`; +export const apiFetchTestDevisionListDivisionGET = async (params?: Params) => + funPramas(apiPathTestDevisionListDivisionGET(), "GET", params); + +export const apiPathTestDevisionListAnggotaRouterTsGET = () => + `/api/test-devision/list-anggota/router.ts`; +export const apiFetchTestDevisionListAnggotaRouterTsGET = async ( + params?: Params, +) => funPramas(apiPathTestDevisionListAnggotaRouterTsGET(), "GET", params); + +export const apiPathTestDevisionCountDevisionGET = () => + `/api/test-devision/count-devision/`; +export const apiFetchTestDevisionCountDevisionGET = async (params?: Params) => + funPramas(apiPathTestDevisionCountDevisionGET(), "GET", params); diff --git a/src/lib/pagePath.ts b/src/lib/pagePath.ts new file mode 100644 index 0000000..029e675 --- /dev/null +++ b/src/lib/pagePath.ts @@ -0,0 +1,111 @@ +/** + * + * [/Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/page.tsx](file:///Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/page.tsx) + */ +export const pagePathPageTsx = (params?: { + searchParams?: Record; +}) => { + let searchParams = ""; + if (params && params.searchParams) { + searchParams = "?" + new URLSearchParams(params.searchParams).toString(); + } + return `page.tsx${searchParams}`; +}; + +/** + * + * [/Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(dev-test)/test-division/page.tsx](file:///Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(dev-test)/test-division/page.tsx) + */ +export const pagePathTestDivision = (params?: { + searchParams?: Record; +}) => { + let searchParams = ""; + if (params && params.searchParams) { + searchParams = "?" + new URLSearchParams(params.searchParams).toString(); + } + return `/test-division${searchParams}`; +}; + +/** + * + * [/Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(auth)/welcome/page.tsx](file:///Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(auth)/welcome/page.tsx) + */ +export const pagePathWelcome = (params?: { + searchParams?: Record; +}) => { + let searchParams = ""; + if (params && params.searchParams) { + searchParams = "?" + new URLSearchParams(params.searchParams).toString(); + } + return `/welcome${searchParams}`; +}; + +/** + * + * [/Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(auth)/verification/page.tsx](file:///Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(auth)/verification/page.tsx) + */ +export const pagePathVerification = (params?: { + searchParams?: Record; +}) => { + let searchParams = ""; + if (params && params.searchParams) { + searchParams = "?" + new URLSearchParams(params.searchParams).toString(); + } + return `/verification${searchParams}`; +}; + +/** + * + * [/Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(application)/search/page.tsx](file:///Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(application)/search/page.tsx) + */ +export const pagePathSearch = (params?: { + searchParams?: Record; +}) => { + let searchParams = ""; + if (params && params.searchParams) { + searchParams = "?" + new URLSearchParams(params.searchParams).toString(); + } + return `/search${searchParams}`; +}; + +/** + * + * [/Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(application)/profile/page.tsx](file:///Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(application)/profile/page.tsx) + */ +export const pagePathProfile = (params?: { + searchParams?: Record; +}) => { + let searchParams = ""; + if (params && params.searchParams) { + searchParams = "?" + new URLSearchParams(params.searchParams).toString(); + } + return `/profile${searchParams}`; +}; + +/** + * + * [/Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(application)/home/page.tsx](file:///Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(application)/home/page.tsx) + */ +export const pagePathHome = (params?: { + searchParams?: Record; +}) => { + let searchParams = ""; + if (params && params.searchParams) { + searchParams = "?" + new URLSearchParams(params.searchParams).toString(); + } + return `/home${searchParams}`; +}; + +/** + * + * [/Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(application)/detail-feature/page.tsx](file:///Users/bip/Documents/projects/bip/sistem-desa-mandiri/src/app/(application)/detail-feature/page.tsx) + */ +export const pagePathDetailFeature = (params?: { + searchParams?: Record; +}) => { + let searchParams = ""; + if (params && params.searchParams) { + searchParams = "?" + new URLSearchParams(params.searchParams).toString(); + } + return `/detail-feature${searchParams}`; +}; diff --git a/src/lib/stateApi.ts b/src/lib/stateApi.ts new file mode 100644 index 0000000..2cf8404 --- /dev/null +++ b/src/lib/stateApi.ts @@ -0,0 +1,107 @@ + +'use client'; +import { State, hookstate, useHookstate } from '@hookstate/core'; + +const useState = (s: State) => { + const state = useHookstate(s); + const get = state.value; + const set = (v: typeof state.value) => state.set(v); + return [get, set] as const; +}; + +interface ParamsLoad { + searchParams?: Record + token?: string + body?: Record +} + +const funLoad = async (url: string, params?: ParamsLoad, set?: any, method?: string) => { + const property: Record = {} + if(params) { + if(params.searchParams) { + property.searchParams = "?"+new URLSearchParams(params.searchParams).toString(); + } + + if(params.body) { + property.body = JSON.stringify(params.body); + } + + if(params.token) { + property.headers.Authorization = `Bearer ${params.token}`; + } + } + property.method = method; + const res = await fetch(url, property ); + const json = await res.json().then((json) => json).catch(() => null); + if(json && set) set(json); + return { + res, + json + }; + +} + +const testDevisionListGroup = hookstate(undefined); +export const ProviderTestDevisionListGroup = ({data}: {data: any}) => { + if(data && testDevisionListGroup.value === undefined) { + testDevisionListGroup.set(data) + } + return null +} +export const useTestDevisionListGroup = () => { + + const [get, set] = useState(useHookstate(testDevisionListGroup)) + const load = (params?: ParamsLoad) => funLoad(`/api/test-devision/list-group/`,params, set, "GET") + const value: T = get + return [value, set, load] as const +}; + + +const testDevisionListDivision = hookstate(undefined); +export const ProviderTestDevisionListDivision = ({data}: {data: any}) => { + if(data && testDevisionListDivision.value === undefined) { + testDevisionListDivision.set(data) + } + return null +} +export const useTestDevisionListDivision = () => { + + const [get, set] = useState(useHookstate(testDevisionListDivision)) + const load = (params?: ParamsLoad) => funLoad(`/api/test-devision/list-division/`,params, set, "GET") + const value: T = get + return [value, set, load] as const +}; + + +const testDevisionListAnggota = hookstate(undefined); +export const ProviderTestDevisionListAnggota = ({data}: {data: any}) => { + if(data && testDevisionListAnggota.value === undefined) { + testDevisionListAnggota.set(data) + } + return null +} +export const useTestDevisionListAnggota = () => { + + const [get, set] = useState(useHookstate(testDevisionListAnggota)) + const load = (params?: ParamsLoad) => funLoad(`/api/test-devision/list-anggota/`,params, set, "GET") + const value: T = get + return [value, set, load] as const +}; + + +const testDevisionCountDevision = hookstate(undefined); +export const ProviderTestDevisionCountDevision = ({data}: {data: any}) => { + if(data && testDevisionCountDevision.value === undefined) { + testDevisionCountDevision.set(data) + } + return null +} +export const useTestDevisionCountDevision = () => { + + const [get, set] = useState(useHookstate(testDevisionCountDevision)) + const load = (params?: ParamsLoad) => funLoad(`/api/test-devision/count-devision/`,params, set, "GET") + const value: T = get + return [value, set, load] as const +}; + + diff --git a/src/module/division/api/api_division.ts b/src/module/division/api/api_division.ts new file mode 100644 index 0000000..ebb71eb --- /dev/null +++ b/src/module/division/api/api_division.ts @@ -0,0 +1,16 @@ +type Method = "GET" | "POST" + +const listApi = [ + { + "page": "" + } +] + +export async function apiDivision(req: Request, method: Method) { + const { searchParams } = new URL(req.url) + const page = searchParams.get("page") + + if (!page) return Response.json({ message: "page not found" }, { status: 404 }) + + return Response.json({ message: "ok" }) +} \ No newline at end of file diff --git a/src/module/division/component/BottomDrawer.tsx b/src/module/division/component/BottomDrawer.tsx new file mode 100644 index 0000000..3f05a89 --- /dev/null +++ b/src/module/division/component/BottomDrawer.tsx @@ -0,0 +1,68 @@ +'use client' +import { ActionIcon, Drawer, Flex, Stack, Text } from "@mantine/core"; +import { MdAddCircle, MdClose, MdFileCopy, MdSort } from "react-icons/md"; +import { pagePathTestDivision } from "@/lib/pagePath"; + +export function BottomDrawer({ openDrawer, setOpenDrawer }: { openDrawer: boolean, setOpenDrawer: any }) { + + function onAddDivisi() { + window.location.href = pagePathTestDivision({ searchParams: { page: "division-create" } }) + } + + function onDivisionFilter() { + window.location.href = pagePathTestDivision({ searchParams: { page: "division-filter" } }) + } + + function onDivisionReport() { + window.location.href = pagePathTestDivision({ searchParams: { page: "division-report" } }) + } + return setOpenDrawer(false)} + position="bottom" + withCloseButton={false} + styles={{ + content: { + margin: "0 auto", + maxWidth: 550, + height: 200, + borderTopRightRadius: 20, + borderTopLeftRadius: 20 + } + }} + + > + + + + Menu + + setOpenDrawer(false)} variant="subtle"> + + + + + + + + + + Tambah Divisi + + + + + + Filter + + + + + + Report + + + + +} \ No newline at end of file diff --git a/src/module/division/component/ContainerDivision.tsx b/src/module/division/component/ContainerDivision.tsx new file mode 100644 index 0000000..f8e39a5 --- /dev/null +++ b/src/module/division/component/ContainerDivision.tsx @@ -0,0 +1,26 @@ +'use client' + +import { Box } from "@mantine/core" +import _ from "lodash" +import { DivisionCreate } from "../ui/DivisionCreate" +import { DivisionFilter } from "../ui/DivisionFilter" +import { DivisionReport } from "../ui/DivisionReport" +import { HeadDivision } from "./HeadDivision" +import { ListWithSearch } from "./ListWithSearch" +import { DivisionView } from "../ui/DivisionView" + + +const listPage = ["division", "division-create", "division-filter", "division-report"] +export function ContainerDevision({ params, searchParams, list_devision, countDevision }: { params: any, searchParams: any, list_devision: any[], countDevision: any }) { + const page = searchParams.page || "division" + const division = list_devision.map((v) => ({ ...v, name: _.kebabCase(v.name) })).find((v) => v.name === page) || null + return + + {/* {JSON.stringify(division)} */} + {page === "division" && } + {page === "division-create" && } + {page === "division-filter" && } + {page === "division-report" && } + {division && division.name === page && } + +} \ No newline at end of file diff --git a/src/module/division/component/HeadDivision.tsx b/src/module/division/component/HeadDivision.tsx new file mode 100644 index 0000000..7b3e43a --- /dev/null +++ b/src/module/division/component/HeadDivision.tsx @@ -0,0 +1,36 @@ +'use client' +import { WARNA } from "@/module/_global"; +import { ActionIcon, Box, Flex, Title } from "@mantine/core"; +import { useSearchParams } from "next/navigation"; +import { useState } from "react"; +import { MdArrowBackIos, MdMenu } from "react-icons/md"; +import { useTitle } from "../lib/devision_state"; +import { BottomDrawer } from "./BottomDrawer"; +import { pagePathTestDivision } from "@/lib/pagePath"; +import _ from "lodash"; + +export function HeadDivision({ title }: { title: string }) { + const [openDrawer, setOpenDrawer] = useState(false) + + function onBack() { + window.location.href = pagePathTestDivision() + } + + return + + + + + {_.startCase(title)} + setOpenDrawer(true)} bg={WARNA.bgIcon} > + + + + + +} \ No newline at end of file diff --git a/src/module/division/component/ListDivision.tsx b/src/module/division/component/ListDivision.tsx new file mode 100644 index 0000000..8141d4f --- /dev/null +++ b/src/module/division/component/ListDivision.tsx @@ -0,0 +1,11 @@ +import { Stack } from "@mantine/core"; +import { ViewGrid } from "./ViewGrid"; +import { ViewList } from "./ViewList"; + +export function ListDivision({ listData, isGrid }: { listData: any[], isGrid?: boolean }) { + return + {listData.map((v, k) => isGrid ? : )} + + + +} \ No newline at end of file diff --git a/src/module/division/component/ListWithSearch.tsx b/src/module/division/component/ListWithSearch.tsx new file mode 100644 index 0000000..a08d676 --- /dev/null +++ b/src/module/division/component/ListWithSearch.tsx @@ -0,0 +1,40 @@ +'use client' + +import { Box, Card, Center, Flex, Stack, Text, Title } from "@mantine/core" +import { ListDivision } from "./ListDivision" +import { SearchDivision } from "./SearchDivision" +import { ToogleList } from "./ToogleList" +import { useState } from "react" +import { useShallowEffect } from "@mantine/hooks" +import { WARNA } from "@/module/_global" +import { apiFetchTestDevisionListDivisionGET } from "@/lib/apiFetch" + + +export function ListWithSearch({ listData, count }: { listData: any[], count: number }) { + const [isGrid, setIsGrid] = useState(true) + const [search, setSearch] = useState("") + const [listDivision, setListDivision] = useState(listData) + + useShallowEffect(() => { + apiFetchTestDevisionListDivisionGET().then(setListDivision) + }, []) + + + return + + + + + + + + Total Divisi +
+ {count} +
+
+
+
+ v.name.toLowerCase().includes(search.toLowerCase()))} isGrid={isGrid} /> +
+} \ No newline at end of file diff --git a/src/module/division/component/MorePeopleIcon.tsx b/src/module/division/component/MorePeopleIcon.tsx new file mode 100644 index 0000000..f776f16 --- /dev/null +++ b/src/module/division/component/MorePeopleIcon.tsx @@ -0,0 +1,16 @@ +'use client' + +import { WARNA } from "@/module/_global" +import { Avatar } from "@mantine/core" +import { MdAccountCircle, MdPeople } from "react-icons/md" + +export function MorePeopleIcon() { + return + + + + + +5 + + +} \ No newline at end of file diff --git a/src/module/division/component/SearchDivision.tsx b/src/module/division/component/SearchDivision.tsx new file mode 100644 index 0000000..22c7391 --- /dev/null +++ b/src/module/division/component/SearchDivision.tsx @@ -0,0 +1,8 @@ +'use client' + +import { TextInput } from "@mantine/core" +import { MdSearch } from "react-icons/md" + +export function SearchDivision({ text, setText }: { text: string, setText: any }) { + return setText(e.target.value)} value={text} radius={30} leftSection={} placeholder="Cari Divisi" /> +} \ No newline at end of file diff --git a/src/module/division/component/ToogleList.tsx b/src/module/division/component/ToogleList.tsx new file mode 100644 index 0000000..652b23a --- /dev/null +++ b/src/module/division/component/ToogleList.tsx @@ -0,0 +1,17 @@ +'use client' + +import { ActionIcon, Box } from "@mantine/core" +import { useState } from "react" +import { MdGrid3X3, MdGridView, MdList, MdViewList } from "react-icons/md" + +export function ToogleList({ isGrid, setIsGrid }: { isGrid: boolean, setIsGrid: any }) { + function onToogleList() { + setIsGrid(!isGrid) + } + + return + + {isGrid ? : } + + +} \ No newline at end of file diff --git a/src/module/division/component/ViewGrid.tsx b/src/module/division/component/ViewGrid.tsx new file mode 100644 index 0000000..bcee477 --- /dev/null +++ b/src/module/division/component/ViewGrid.tsx @@ -0,0 +1,36 @@ +import { WARNA } from "@/module/_global"; +import { Stack, Box, Title, Group, Text, UnstyledButton } from "@mantine/core"; +import { MorePeopleIcon } from "./MorePeopleIcon"; +import { pagePathTestDivision } from "@/lib/pagePath"; +import _ from "lodash"; + +export function ViewGrid({ v }: { v: any }) { + return ( + { + window.location.href = pagePathTestDivision({ searchParams: { page: _.kebabCase(v.name) } }) + }}> + + + {v.name} + + + + {v.desc} + + + + + + + + ); +} \ No newline at end of file diff --git a/src/module/division/component/ViewList.tsx b/src/module/division/component/ViewList.tsx new file mode 100644 index 0000000..b0f0e71 --- /dev/null +++ b/src/module/division/component/ViewList.tsx @@ -0,0 +1,23 @@ +import { pagePathTestDivision } from "@/lib/pagePath"; +import { Avatar, Flex, Stack, Text, Title, UnstyledButton } from "@mantine/core"; +import _ from "lodash"; +import { MdPeople } from "react-icons/md"; + +export function ViewList({ v }: { v: any }) { + return ( + { + window.location.href = pagePathTestDivision({ searchParams: { page: _.kebabCase(v.name) } }) + }}> + + + + + + {v.name} + + + + ) +} \ No newline at end of file diff --git a/src/module/division/lib/BottomMenu.tsx b/src/module/division/lib/BottomMenu.tsx new file mode 100644 index 0000000..699085f --- /dev/null +++ b/src/module/division/lib/BottomMenu.tsx @@ -0,0 +1,33 @@ +import { ActionIcon, Drawer, Flex, Stack, Text } from "@mantine/core"; +import { MdClose } from "react-icons/md"; + +export function BottomMenu({size, title, openDrawer, setOpenDrawer, children }: { size?: number | string, title?: string, openDrawer: boolean, setOpenDrawer: any, children: React.ReactNode }) { + return setOpenDrawer(false)} + position="bottom" + withCloseButton={false} + size={size || "md"} + styles={{ + content: { + margin: "0 auto", + maxWidth: 550, + borderTopRightRadius: 20, + borderTopLeftRadius: 20 + } + }} + > + + + + {title || 'Menu'} + + setOpenDrawer(false)} variant="subtle"> + + + + {children} + + +} \ No newline at end of file diff --git a/src/module/division/lib/ButtonConfirm.tsx b/src/module/division/lib/ButtonConfirm.tsx new file mode 100644 index 0000000..30dab1f --- /dev/null +++ b/src/module/division/lib/ButtonConfirm.tsx @@ -0,0 +1,25 @@ +import { WARNA } from "@/module/_global"; +import { Button, Flex, Stack, Text, UnstyledButton } from "@mantine/core"; +import { BottomMenu } from "./BottomMenu"; +import { useState } from "react"; + +export function ButtonConfirm({ label, desc, onConfirm }: { label: string, desc: string, onConfirm: () => void }) { + const [open, setOpen] = useState(false) + + const onClickConfirm = () => { + setOpen(false) + onConfirm() + } + return + + + + {desc} + + setOpen(false)}>Cancel + + + + + +} \ No newline at end of file diff --git a/src/module/division/lib/ButtonNavi.tsx b/src/module/division/lib/ButtonNavi.tsx new file mode 100644 index 0000000..1857121 --- /dev/null +++ b/src/module/division/lib/ButtonNavi.tsx @@ -0,0 +1,6 @@ +import { WARNA } from "@/module/_global"; +import { Button } from "@mantine/core"; + +export function ButtonNavi({ children, onClick }: { children: React.ReactNode, onClick?: () => void }) { + return +} \ No newline at end of file diff --git a/src/module/division/lib/MultiSelectList.tsx b/src/module/division/lib/MultiSelectList.tsx new file mode 100644 index 0000000..d06ddd1 --- /dev/null +++ b/src/module/division/lib/MultiSelectList.tsx @@ -0,0 +1,53 @@ +'use client' +import { ActionIcon, Anchor, Button, Card, Divider, Flex, Group, NavLink, Paper, ScrollArea, Select, Stack, Text, UnstyledButton } from "@mantine/core"; +import { useState } from "react"; +import { MdArrowForwardIos, MdCheckBox, MdCheckBoxOutlineBlank } from "react-icons/md"; +import { BottomMenu } from "./BottomMenu"; +import { ButtonNavi } from "./ButtonNavi"; +import _ from "lodash"; +import { WARNA } from "@/module/_global"; + +export function MultiSelectList( + { label, placeholder, data = [], listSelected = [], setListSelected }: + { label?: string, placeholder?: string, data?: any[], listSelected: any[], setListSelected: any } +) { + const [open, setOpen] = useState(false) + // const [listSelected, setListSelected] = useState(defaultValue) + + function selected(value: { label: string, value: any }) { + if (listSelected.includes(value.value)) { + setListSelected(listSelected.filter((v) => v !== value.value)) + } else { + setListSelected([...listSelected, value.value]) + } + } + + const onClickSimpan = () => { + setOpen(false) + } + return + setOpen(true)}> + + + {_.isEmpty(listSelected) ? "Pilih Anggota" : "Tambah Anggota"} + + + + + + + + {data.map((v, k) => + selected(v)} + leftSection={listSelected.includes(v.value) ? : } + label={v.label} /> + )} + + + Simpan + + + + +} \ No newline at end of file diff --git a/src/module/division/lib/SingleSelect.tsx b/src/module/division/lib/SingleSelect.tsx new file mode 100644 index 0000000..9646b01 --- /dev/null +++ b/src/module/division/lib/SingleSelect.tsx @@ -0,0 +1,46 @@ +'use client' +import { Flex, Group, NavLink, Paper, ScrollArea, Select, Stack, Text, UnstyledButton } from "@mantine/core"; +import { useState } from "react"; +import { BottomMenu } from "./BottomMenu"; +import { MdArrowForwardIos, MdCheckBox, MdCheckBoxOutlineBlank } from "react-icons/md"; +import _ from "lodash"; + +export function SingleSelect({ desc, icon, placeholder, selected, setSelected, data }: { desc?: string, icon?: any, placeholder: string, selected: any, setSelected: any, data: any[] }) { + const [open, setOpen] = useState(false) + const completed = desc && !_.isEmpty(data) && !_.isEmpty(selected) + + const onSelected = (value: any) => { + setSelected(value) + setOpen(false) + } + return + setOpen(true)} disabled={_.isEmpty(data)}> + + + + + {icon && icon} + {!_.isEmpty(data) ? data?.filter((v) => v.value === selected)[0]?.label || placeholder : placeholder} + + + + {completed && {desc}} + + + + + + + {data?.map((v, k) => onSelected(v.value)} + leftSection={selected === v.value ? + : + } + key={k} + label={v.label} />)} + + + + +} \ No newline at end of file diff --git a/src/module/division/lib/WebVitals.tsx b/src/module/division/lib/WebVitals.tsx new file mode 100644 index 0000000..a85e3e1 --- /dev/null +++ b/src/module/division/lib/WebVitals.tsx @@ -0,0 +1,12 @@ +'use client' + +import { useReportWebVitals } from 'next/web-vitals'; + +export function WebVitals({ searchParams }: { searchParams: any }) { + const log = searchParams.log; + useReportWebVitals((metric) => { + log && console.log(JSON.stringify(metric, null, 4)); + }); + + return null; +} diff --git a/src/module/division/lib/devision_state.ts b/src/module/division/lib/devision_state.ts new file mode 100644 index 0000000..b69eb0a --- /dev/null +++ b/src/module/division/lib/devision_state.ts @@ -0,0 +1,14 @@ +import { State, hookstate, useHookstate } from "@hookstate/core"; + +const useState = (s: State) => { + const state = useHookstate(s); + const get = state.value; + const set = (v: typeof state.value) => state.set(v); + return [get, set] as const; +}; + +const title = hookstate("Divisi") +export const useTitle = () => useState(title); + +const filter = hookstate("") +export const useDivisionfilter = () => useState(filter) \ No newline at end of file diff --git a/src/module/division/lib/division/get_count_devision.ts b/src/module/division/lib/division/get_count_devision.ts new file mode 100644 index 0000000..0344a21 --- /dev/null +++ b/src/module/division/lib/division/get_count_devision.ts @@ -0,0 +1,5 @@ +import { list_devision } from "@/dummy_data"; + +export async function getCountDivision() { + return list_devision.length +} \ No newline at end of file diff --git a/src/module/division/lib/division/get_list_anggota.ts b/src/module/division/lib/division/get_list_anggota.ts new file mode 100644 index 0000000..51e495f --- /dev/null +++ b/src/module/division/lib/division/get_list_anggota.ts @@ -0,0 +1,45 @@ +const listAnggota = [ + { + id: "1", + name: "Anggota 1", + }, + { + id: "2", + name: "Anggota 2", + }, + { + id: "3", + name: "Anggota 3", + }, + { + id: "4", + name: "Anggota 4", + }, + { + id: "5", + name: "Anggota 5", + }, + { + id: "6", + name: "Anggota 6", + }, + { + id: "7", + name: "Anggota 7", + }, + { + id: "8", + name: "Anggota 8", + }, + { + id: "9", + name: "Anggota 9", + }, + { + id: "10", + name: "Anggota 10", + }, +] +export async function getListAnggota() { + return listAnggota +} diff --git a/src/module/division/lib/division/get_list_devision.ts b/src/module/division/lib/division/get_list_devision.ts new file mode 100644 index 0000000..f712541 --- /dev/null +++ b/src/module/division/lib/division/get_list_devision.ts @@ -0,0 +1,5 @@ +import { list_devision } from "@/dummy_data"; + +export async function getListDevision() { + return list_devision +} \ No newline at end of file diff --git a/src/module/division/lib/division/get_list_group.ts b/src/module/division/lib/division/get_list_group.ts new file mode 100644 index 0000000..5503d66 --- /dev/null +++ b/src/module/division/lib/division/get_list_group.ts @@ -0,0 +1,18 @@ +const listGroup = [ + { + id: "1", + name: "Group 1", + + }, + { + id: "2", + name: "Group 2", + }, + { + id: "3", + name: "Group 3", + } +] +export async function getListGroup() { + return listGroup +} \ No newline at end of file diff --git a/src/module/division/lib/toast.tsx b/src/module/division/lib/toast.tsx new file mode 100644 index 0000000..ac7f601 --- /dev/null +++ b/src/module/division/lib/toast.tsx @@ -0,0 +1,20 @@ +import { WARNA } from '@/module/_global' +import t from 'react-simple-toasts' + +type Event = "error" | "success" | "info" | "warning" +export const toast = (message: string, event?: Event) => { + t(message, { + position: "center", + render: (message) =>
+
{message?.toString()}
+
, + }) +} \ No newline at end of file diff --git a/src/module/division/ui/DevisionPage.tsx b/src/module/division/ui/DevisionPage.tsx deleted file mode 100644 index 7f42906..0000000 --- a/src/module/division/ui/DevisionPage.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { Stack } from "@mantine/core"; - -export function DevisionPage() { - return - - ; -} \ No newline at end of file diff --git a/src/module/division/ui/DivisionCreate.tsx b/src/module/division/ui/DivisionCreate.tsx new file mode 100644 index 0000000..32c2dac --- /dev/null +++ b/src/module/division/ui/DivisionCreate.tsx @@ -0,0 +1,81 @@ +'use client' + +import { ActionIcon, Avatar, Button, Card, Flex, ScrollArea, Select, Stack, Text, TextInput, Textarea } from "@mantine/core" +import { MultiSelectList } from "../lib/MultiSelectList" +import { WARNA } from "@/module/_global" +import { useTestDevisionListAnggota, useTestDevisionListGroup } from "@/lib/stateApi" +import { useState } from "react" +import _ from "lodash" +import { MdAccountCircle, MdClose, MdGroup, MdGroupAdd, MdGroupWork, MdShield } from "react-icons/md" +import { ButtonNavi } from "../lib/ButtonNavi" +import { pagePathTestDivision } from "@/lib/pagePath" +import { SingleSelect } from "../lib/SingleSelect" +import { ButtonConfirm } from "../lib/ButtonConfirm" +import { toast } from "../lib/toast" + + +export function DivisionCreate() { + const [val, setVal, load] = useTestDevisionListGroup() + const [listAnggota, setListAnggota] = useTestDevisionListAnggota() + const [listSelectedAnggota, setListSelectedAnggota] = useState([]) + const [selectedAdmin, setSelectedAdmin] = useState("") + const [selectedGroup, setSelectedGroup] = useState("") + + return + } + selected={selectedGroup} + setSelected={setSelectedGroup} + data={val && val.map((v) => ({ label: v.name, value: v.id }))} + placeholder="Pilih Grup" /> + +