Merge pull request #192 from bipproduction/amalia/04-september-24

upd: member
This commit is contained in:
Amalia
2024-09-04 17:18:01 +08:00
committed by GitHub
6 changed files with 183 additions and 67 deletions

View File

@@ -3,6 +3,8 @@ import { funGetUserByCookies } from "@/module/auth";
import { createLogUser } from "@/module/user"; import { createLogUser } from "@/module/user";
import _ from "lodash"; import _ from "lodash";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import path from "path";
import fs from "fs";
// GET ALL MEMBER / USER // GET ALL MEMBER / USER
export async function GET(request: Request) { export async function GET(request: Request) {
@@ -86,7 +88,9 @@ export async function POST(request: Request) {
if (user.id == undefined) { if (user.id == undefined) {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
} }
const data = await request.json(); const body = await request.formData()
const data = JSON.parse(body.get("data") as string)
const file = body.get("file") as File
const village = String(user.idVillage) const village = String(user.idVillage)
let groupFix = data.idGroup let groupFix = data.idGroup
@@ -95,15 +99,26 @@ export async function POST(request: Request) {
groupFix = user.idGroup groupFix = user.idGroup
} }
const cek = await prisma.user.count({ const cekNIK = await prisma.user.count({
where: {
nik: data.nik
},
});
const cekEmail = await prisma.user.count({
where: {
email: data.email
},
});
const cekPhone = await prisma.user.count({
where: { where: {
nik: data.nik,
email: data.email,
phone: data.phone phone: data.phone
}, },
}); });
if (cek == 0) {
if (cekNIK == 0 && cekEmail == 0 && cekPhone == 0) {
const users = await prisma.user.create({ const users = await prisma.user.create({
data: { data: {
nik: data.nik, nik: data.nik,
@@ -121,6 +136,28 @@ export async function POST(request: Request) {
}, },
}); });
if (String(file) != "undefined" && String(file) != "null") {
const root = path.join(process.cwd(), "./public/image/user/");
const fExt = file.name.split(".").pop()
const fileName = users.id + '.' + fExt;
const filePath = path.join(root, fileName);
// Konversi ArrayBuffer ke Buffer
const buffer = Buffer.from(await file.arrayBuffer());
// Tulis file ke sistem
fs.writeFileSync(filePath, buffer);
await prisma.user.update({
where: {
id: users.id
},
data: {
img: fileName
}
})
}
// create log user // create log user
const log = await createLogUser({ act: 'CREATE', desc: 'User membuat data user baru', table: 'user', data: users.id }) const log = await createLogUser({ act: 'CREATE', desc: 'User membuat data user baru', table: 'user', data: users.id })
@@ -129,8 +166,6 @@ export async function POST(request: Request) {
return Response.json({ success: false, message: "User sudah ada" }, { status: 400 }); return Response.json({ success: false, message: "User sudah ada" }, { status: 400 });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
return Response.json({ success: false, message: "Internal Server Error" }, { status: 500 }); return Response.json({ success: false, message: "Internal Server Error" }, { status: 500 });

View File

@@ -0,0 +1,66 @@
export const valueRoleUser =
[
{
login: "supadmin",
data: [
{
id: "cosupadmin",
name: "Wakil Super Admin"
},
{
id: "admin",
name: "Admin"
},
{
id: "coadmin",
name: "Wakil Admin"
},
{
id: "user",
name: "User"
},
]
},
{
login: "cosupadmin",
data: [
{
id: "admin",
name: "Admin"
},
{
id: "coadmin",
name: "Wakil Admin"
},
{
id: "user",
name: "User"
},
],
},
{
login: "admin",
data: [
{
id: "coadmin",
name: "Wakil Admin"
},
{
id: "user",
name: "User"
},
],
},
{
login: "coadmin",
data: [
{
id: "user",
name: "User"
},
],
}
]

View File

@@ -5,7 +5,7 @@ export const funGetAllmember = async (path?: string) => {
return await response.json().catch(() => null); return await response.json().catch(() => null);
} }
export const funGetRoleUser= async (path?: string) => { export const funGetRoleUser = async (path?: string) => {
const response = await fetch(`/api/role-user${(path) ? path : ''}`, { next: { tags: ['member'] } }); const response = await fetch(`/api/role-user${(path) ? path : ''}`, { next: { tags: ['member'] } });
return await response.json().catch(() => null); return await response.json().catch(() => null);
} }
@@ -15,25 +15,10 @@ export const funGetOneMember = async (path: string) => {
return await response.json().catch(() => null); return await response.json().catch(() => null);
} }
export const funCreateMember = async (data: IFormMember) => { export const funCreateMember = async (data: FormData) => {
if (data.name.length < 3)
return { success: false, message: 'Name minimal 3 karakter' }
if (data.email.length < 3)
return { success: false, message: 'Email minimal 3 karakter' }
if (data.phone.length < 10)
return { success: false, message: 'Phone minimal 10 karakter' }
if (data.nik.length < 16)
return { success: false, message: 'NIK harus 16 karakter' }
const response = await fetch("/api/user", { const response = await fetch("/api/user", {
method: "POST", method: "POST",
headers: { body: data,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
}); });
return await response.json().catch(() => null); return await response.json().catch(() => null);
} }

View File

@@ -2,18 +2,20 @@
import { globalRole, WARNA } from "@/module/_global"; import { globalRole, WARNA } from "@/module/_global";
import LayoutModal from "@/module/_global/layout/layout_modal"; import LayoutModal from "@/module/_global/layout/layout_modal";
import { funGetAllGroup, IDataGroup } from "@/module/group"; import { funGetAllGroup, IDataGroup } from "@/module/group";
import { Box, Button, rem, Select, Stack, Text, TextInput } from "@mantine/core"; import { Avatar, Box, Button, Indicator, rem, Select, Stack, Text, TextInput } from "@mantine/core";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useEffect, useState } from "react"; import { useRef, useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { HiUser } from "react-icons/hi2";
import { IDataPositionMember, IDataROleMember } from "../lib/type_member"; import { IDataPositionMember, IDataROleMember } from "../lib/type_member";
import { funGetAllPosition } from "@/module/position/lib/api_position"; import { funGetAllPosition } from "@/module/position/lib/api_position";
import { funCreateMember, funGetRoleUser } from "../lib/api_member"; import { funCreateMember } from "../lib/api_member";
import _ from "lodash"; import _ from "lodash";
import { useHookstate } from "@hookstate/core"; import { useHookstate } from "@hookstate/core";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import { funGetUserByCookies } from "@/module/auth"; import { funGetUserByCookies } from "@/module/auth";
import { valueRoleUser } from "../../lib/val_user";
import { FaCamera } from "react-icons/fa6";
import { Dropzone } from "@mantine/dropzone";
export default function CreateMember() { export default function CreateMember() {
const router = useRouter(); const router = useRouter();
@@ -22,7 +24,9 @@ export default function CreateMember() {
const [listPosition, setListPosition] = useState<IDataPositionMember[]>([]); const [listPosition, setListPosition] = useState<IDataPositionMember[]>([]);
const [listUserRole, setListUserRole] = useState<IDataROleMember[]>([]); const [listUserRole, setListUserRole] = useState<IDataROleMember[]>([]);
const roleLogin = useHookstate(globalRole) const roleLogin = useHookstate(globalRole)
const [groupLogin, setGroupLogin] = useState(""); const [img, setIMG] = useState<any | null>()
const [imgForm, setImgForm] = useState<any>()
const openRef = useRef<() => void>(null)
const [touched, setTouched] = useState({ const [touched, setTouched] = useState({
nik: false, nik: false,
name: false, name: false,
@@ -62,8 +66,10 @@ export default function CreateMember() {
async function getLogin() { async function getLogin() {
try { try {
const res = await funGetUserByCookies(); const res = await funGetUserByCookies();
setGroupLogin(String(res.idGroup)); if (roleLogin.get() != "supadmin") {
getAllPosition(res.idGroup); getAllPosition(res.idGroup)
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
@@ -84,8 +90,7 @@ export default function CreateMember() {
async function getAllUserRole() { async function getAllUserRole() {
try { try {
const res = await funGetRoleUser(); setListUserRole(valueRoleUser.filter((v) => v.login == roleLogin.get())[0]?.data);
setListUserRole(res.data);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
@@ -108,16 +113,21 @@ export default function CreateMember() {
return; return;
} }
if (val) { if (val) {
const res = await funCreateMember({ const fd = new FormData()
nik: listData.nik, fd.append("file", imgForm)
name: listData.name, fd.append("data", JSON.stringify(
phone: listData.phone, {
email: listData.email, nik: listData.nik,
gender: listData.gender, name: listData.name,
idGroup: listData.idGroup, phone: listData.phone,
idPosition: listData.idPosition, email: listData.email,
idUserRole: listData.idUserRole, gender: listData.gender,
}); idGroup: listData.idGroup,
idPosition: listData.idPosition,
idUserRole: listData.idUserRole,
}
))
const res = await funCreateMember(fd);
if (res.success) { if (res.success) {
toast.success(res.message); toast.success(res.message);
setModal(false); setModal(false);
@@ -137,26 +147,37 @@ export default function CreateMember() {
useShallowEffect(() => { useShallowEffect(() => {
getAllGroup(); getAllGroup();
getAllUserRole(); getAllUserRole();
getLogin()
if (roleLogin.get() != "supadmin") {
getLogin()
}
}, []); }, []);
return ( return (
<Box> <Box>
<Stack align="center" justify="center" gap="xs" pt={30} px={20} pb={100}> <Stack align="center" justify="center" gap="xs" pt={30} px={20} pb={100}>
<Box <Dropzone
bg={WARNA.biruTua} openRef={openRef}
py={30} onDrop={async (files) => {
px={50} if (!files || _.isEmpty(files))
style={{ return toast.error('Tidak ada gambar yang dipilih')
borderRadius: 10, setImgForm(files[0])
const buffer = URL.createObjectURL(new Blob([new Uint8Array(await files[0].arrayBuffer())]))
setIMG(buffer)
}}
activateOnClick={false}
maxSize={1 * 1024 ** 2}
accept={['image/png', 'image/jpeg', 'image/heic']}
onReject={(files) => {
return toast.error('File yang diizinkan: .png, .jpg, dan .heic dengan ukuran maksimal 1 MB')
}} }}
> >
<HiUser size={100} color={WARNA.bgWhite} /> </Dropzone>
</Box> <Indicator offset={20} withBorder inline color={WARNA.borderBiruMuda} position="bottom-end" label={<FaCamera size={20} />} size={40} onClick={() => openRef.current?.()}>
<Avatar
size="150"
radius={"100"}
src={img}
/>
</Indicator>
{ {
roleLogin.get() == "supadmin" && roleLogin.get() == "supadmin" &&
<Select <Select

View File

@@ -1,5 +1,5 @@
'use client' 'use client'
import { LayoutNavbarHome, LayoutIconBack, WARNA, LayoutDrawer, SkeletonDetailProfile } from "@/module/_global"; import { LayoutNavbarHome, LayoutIconBack, WARNA, LayoutDrawer, SkeletonDetailProfile, globalRole } from "@/module/_global";
import { Box, Group, ActionIcon, Stack, Text, Center, Avatar, Skeleton } from "@mantine/core"; import { Box, Group, ActionIcon, Stack, Text, Center, Avatar, Skeleton } from "@mantine/core";
import { HiMenu } from "react-icons/hi"; import { HiMenu } from "react-icons/hi";
import { HiUser } from "react-icons/hi2"; import { HiUser } from "react-icons/hi2";
@@ -14,6 +14,7 @@ import Link from "next/link";
import { funGetOneMember } from "../lib/api_member"; import { funGetOneMember } from "../lib/api_member";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { IListMember, IMember } from "../lib/type_member"; import { IListMember, IMember } from "../lib/type_member";
import { useHookstate } from "@hookstate/core";
export default function NavbarDetailMember({ id }: IMember) { export default function NavbarDetailMember({ id }: IMember) {
@@ -22,6 +23,7 @@ export default function NavbarDetailMember({ id }: IMember) {
const [selectId, setSelectId] = useState<string>(''); const [selectId, setSelectId] = useState<string>('');
const [active, setActive] = useState<boolean>(false) const [active, setActive] = useState<boolean>(false)
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const roleLogin = useHookstate(globalRole)
useShallowEffect(() => { useShallowEffect(() => {
featchGetOne() featchGetOne()
@@ -56,9 +58,12 @@ export default function NavbarDetailMember({ id }: IMember) {
<LayoutNavbarHome> <LayoutNavbarHome>
<Group justify="space-between"> <Group justify="space-between">
<LayoutIconBack /> <LayoutIconBack />
<ActionIcon onClick={() => setOpen(true)} variant="light" bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Info"> {
<HiMenu size={20} color='white' /> (roleLogin.get() != "user") &&
</ActionIcon> <ActionIcon onClick={() => setOpen(true)} variant="light" bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Info">
<HiMenu size={20} color='white' />
</ActionIcon>
}
</Group> </Group>
<Stack <Stack
align="center" align="center"
@@ -68,12 +73,12 @@ export default function NavbarDetailMember({ id }: IMember) {
<Center> <Center>
<Avatar src={`/api/file/img?jenis=image&cat=user&file=${dataOne?.img}`} alt="it's me" size="xl" /> <Avatar src={`/api/file/img?jenis=image&cat=user&file=${dataOne?.img}`} alt="it's me" size="xl" />
</Center> </Center>
{loading ? {loading ?
<> <>
<Skeleton height={25} mt={10} width={"40%"} /> <Skeleton height={25} mt={10} width={"40%"} />
<Skeleton height={15} mt={12} width={"30%"} /> <Skeleton height={15} mt={12} width={"30%"} />
</> </>
: :
<> <>
<Text c={'white'} fw={'bold'} fz={25}>{dataOne?.name}</Text> <Text c={'white'} fw={'bold'} fz={25}>{dataOne?.name}</Text>
<Text c={'white'} fw={'lighter'} fz={15}>{dataOne?.group} - {dataOne?.position}</Text> <Text c={'white'} fw={'lighter'} fz={15}>{dataOne?.group} - {dataOne?.position}</Text>
@@ -82,7 +87,7 @@ export default function NavbarDetailMember({ id }: IMember) {
</Stack> </Stack>
</LayoutNavbarHome> </LayoutNavbarHome>
{loading {loading
? ?
<SkeletonDetailProfile /> <SkeletonDetailProfile />
: :
<Box p={20}> <Box p={20}>

View File

@@ -1,19 +1,23 @@
'use client' 'use client'
import { LayoutDrawer, LayoutNavbarNew, WARNA } from "@/module/_global"; import { globalRole, LayoutDrawer, LayoutNavbarNew, WARNA } from "@/module/_global";
import { ActionIcon } from "@mantine/core"; import { ActionIcon } from "@mantine/core";
import { HiMenu } from "react-icons/hi"; import { HiMenu } from "react-icons/hi";
import DrawerListMember from "./drawer_list_member"; import DrawerListMember from "./drawer_list_member";
import { useState } from "react"; import { useState } from "react";
import { useHookstate } from "@hookstate/core";
export default function NavbarListMember() { export default function NavbarListMember() {
const [isOpenDrawer, setOpenDrawer] = useState(false) const [isOpenDrawer, setOpenDrawer] = useState(false)
const roleLogin = useHookstate(globalRole)
return ( return (
<> <>
<LayoutNavbarNew back="/home" title="Anggota" <LayoutNavbarNew back="/home" title="Anggota"
menu={ menu={(roleLogin.get() != "user") ?
<ActionIcon onClick={() => setOpenDrawer(true)} variant="light" bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Settings"> <ActionIcon onClick={() => setOpenDrawer(true)} variant="light" bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Settings">
<HiMenu size={20} color='white' /> <HiMenu size={20} color='white' />
</ActionIcon> </ActionIcon>
: <></>
} }
/> />
<LayoutDrawer opened={isOpenDrawer} title={'Menu'} onClose={() => setOpenDrawer(false)}> <LayoutDrawer opened={isOpenDrawer} title={'Menu'} onClose={() => setOpenDrawer(false)}>