Merge pull request #294 from bipproduction/join

Join
This commit is contained in:
Amalia
2024-10-09 10:13:25 +08:00
committed by GitHub
49 changed files with 2318 additions and 826 deletions

View File

@@ -59,6 +59,7 @@ model Village {
Project Project[] Project Project[]
Division Division[] Division Division[]
ColorTheme ColorTheme[] ColorTheme ColorTheme[]
BannerImage BannerImage[]
} }
model Group { model Group {
@@ -481,6 +482,18 @@ model ColorTheme {
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
} }
model BannerImage {
id String @id @default(cuid())
Village Village? @relation(fields: [idVillage], references: [id])
idVillage String?
title String
extension String
image String
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Subscription { model Subscription {
id String @id @default(cuid()) id String @id @default(cuid())
data Json data Json

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 34 KiB

BIN
public/icon2-192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -1,3 +1,7 @@
export default function Page({ params }: { params: { id: string } }) { import { EditBanner } from "@/module/banner";
return <div>Edit Banner</div>;
export default function Page() {
return (
<EditBanner />
);
} }

View File

@@ -0,0 +1,10 @@
import { ViewfileBanner } from '@/module/banner';
import React from 'react';
function Page() {
return (
<ViewfileBanner/>
);
}
export default Page;

View File

@@ -2,10 +2,10 @@ import { NotificationManager } from "@/module/_global/components/notification_ma
const publicKey = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY!; const publicKey = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY!;
console.log( // console.log(
process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY, // process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY // process.env.VAPID_PRIVATE_KEY
); // );
export default function Page() { export default function Page() {
return ( return (

View File

View File

@@ -0,0 +1,113 @@
import { DIR, funDeleteFile, funUploadFile, prisma } from "@/module/_global";
import { funGetUserByCookies } from "@/module/auth";
import { createLogUser } from "@/module/user";
import { NextResponse } from "next/server";
// GET ONE BANNER
export async function GET(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params;
const user = await funGetUserByCookies()
if (user.id == undefined) {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
}
const data = await prisma.bannerImage.findUnique({
where: {
id: String(id)
}
})
return NextResponse.json({ success: true, message: "Berhasil mendapatkan banner", data }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan banner, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}
// DELETE BANNER
export async function DELETE(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params;
const user = await funGetUserByCookies()
if (user.id == undefined) {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
}
const upd = await prisma.bannerImage.update({
where: {
id: String(id)
},
data: {
isActive: false
}
})
// create log user
const log = await createLogUser({ act: 'DELETE', desc: 'User menghapus banner', table: 'bannerImage', data: id })
return NextResponse.json({ success: true, message: "Berhasil menghapus banner" }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal menghapus banner, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}
// UPDATE BANNER
export async function PUT(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params;
const user = await funGetUserByCookies()
if (user.id == undefined) {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
}
const body = await request.formData()
const file = body.get("file") as File
const data = body.get("data")
const { title } = JSON.parse(data as string)
const upd = await prisma.bannerImage.update({
where: {
id: String(id)
},
data: {
title
},
select: {
image: true
}
})
if (String(file) != "undefined" && String(file) != "null") {
const fExt = file.name.split(".").pop()
const fileName = id + '.' + fExt;
const newFile = new File([file], fileName, { type: file.type });
await funDeleteFile({ fileId: String(upd.image) })
const upload = await funUploadFile({ file: newFile, dirId: DIR.banner })
await prisma.bannerImage.update({
where: {
id: id
},
data: {
image: upload.data.id
}
})
}
// create log user
const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate data banner', table: 'bannerImage', data: user.id })
return NextResponse.json({ success: true, message: "Berhasil mengupdate banner" }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mengupdate banner, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -0,0 +1,74 @@
import { DIR, funUploadFile, funViewDir, prisma } from "@/module/_global";
import { funGetUserByCookies } from "@/module/auth";
import { createLogUser } from "@/module/user";
import { NextResponse } from "next/server";
// GET ALL BANNER
export async function GET() {
try {
const user = await funGetUserByCookies()
if (user.id == undefined) {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
}
const data = await prisma.bannerImage.findMany({
where: {
isActive: true,
idVillage: user.idVillage
},
orderBy: {
createdAt: 'desc'
}
});
return NextResponse.json({ success: true, message: "Berhasil mendapatkan banner", data }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan data banner, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}
// CREATE BANNER
export async function POST(request: Request) {
try {
const user = await funGetUserByCookies()
if (user.id == undefined) {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
}
const body = await request.formData()
const file = body.get("file") as File;
const data = body.get("data");
const { title } = JSON.parse(data as string)
const fExt = file.name.split(".").pop()
const fName = file.name.replace("." + fExt, "")
const newFile = new File([file], file.name, { type: file.type });
const ini = funViewDir({ dirId: DIR.user })
const upload = await funUploadFile({ file: newFile, dirId: DIR.banner })
if (upload.success) {
const create = await prisma.bannerImage.create({
data: {
title: title,
idVillage: user.idVillage,
extension: String(fExt),
image: upload.data.id
}
})
// create log user
const log = await createLogUser({ act: 'CREATE', desc: 'User menambah data banner baru', table: 'bannerImage', data: user.id })
return Response.json({ success: true, message: 'Sukses menambah data banner' }, { status: 200 });
} else {
return Response.json({ success: false, message: 'Gagal menambah data banner' }, { status: 200 });
}
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal menambahkan banner, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -1,6 +1,6 @@
import { prisma } from "@/module/_global"; import { prisma } from "@/module/_global";
import { funGetUserByCookies } from "@/module/auth"; import { funGetUserByCookies } from "@/module/auth";
import _, { ceil } from "lodash"; import _, { ceil, some } from "lodash";
import moment from "moment"; import moment from "moment";
import "moment/locale/id"; import "moment/locale/id";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
@@ -35,11 +35,21 @@ export async function GET(request: Request) {
isActive: true, isActive: true,
} }
} }
} else { } else if (roleUser == "admin" || roleUser == "cosupadmin") {
kondisi = { kondisi = {
isActive: true, isActive: true,
idGroup: idGroup idGroup: idGroup
} }
} else {
kondisi = {
isActive: true,
idGroup: idGroup,
ProjectMember: {
some: {
idUser: user.id
}
}
}
} }
const data = await prisma.project.findMany({ const data = await prisma.project.findMany({
@@ -133,17 +143,31 @@ export async function GET(request: Request) {
kondisi = { kondisi = {
isActive: true, isActive: true,
Division: { Division: {
isActive: true,
idVillage: idVillage, idVillage: idVillage,
Group: { Group: {
isActive: true, isActive: true,
} }
} }
} }
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
kondisi = {
isActive: true,
Division: {
isActive: true,
idGroup: idGroup
}
}
} else { } else {
kondisi = { kondisi = {
isActive: true, isActive: true,
Division: { Division: {
idGroup: idGroup isActive: true,
DivisionMember: {
some: {
idUser: user.id
}
}
} }
} }
} }
@@ -185,18 +209,33 @@ export async function GET(request: Request) {
isActive: true, isActive: true,
category: 'FILE', category: 'FILE',
Division: { Division: {
isActive: true,
idVillage: idVillage, idVillage: idVillage,
Group: { Group: {
isActive: true, isActive: true,
} }
} }
} }
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
kondisi = {
isActive: true,
category: 'FILE',
Division: {
isActive: true,
idGroup: idGroup
}
}
} else { } else {
kondisi = { kondisi = {
isActive: true, isActive: true,
category: 'FILE', category: 'FILE',
Division: { Division: {
idGroup: idGroup isActive: true,
DivisionMember: {
some: {
idUser: user.id
}
}
} }
} }
} }
@@ -284,7 +323,7 @@ export async function GET(request: Request) {
dateEnd: true, dateEnd: true,
createdAt: true, createdAt: true,
status: true, status: true,
idDivision:true, idDivision: true,
DivisionCalendar: { DivisionCalendar: {
select: { select: {
title: true, title: true,
@@ -327,18 +366,33 @@ export async function GET(request: Request) {
isActive: true, isActive: true,
status: 1, status: 1,
Division: { Division: {
isActive: true,
idVillage: idVillage, idVillage: idVillage,
Group: { Group: {
isActive: true, isActive: true,
} }
} }
} }
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
kondisi = {
isActive: true,
status: 1,
Division: {
idGroup: idGroup,
isActive: true
}
}
} else { } else {
kondisi = { kondisi = {
isActive: true, isActive: true,
status: 1, status: 1,
Division: { Division: {
idGroup: idGroup isActive: true,
DivisionMember: {
some: {
idUser: user.id
}
}
} }
} }
} }

View File

@@ -36,9 +36,9 @@ export async function POST() {
const subscriptionData = sub.data as any; const subscriptionData = sub.data as any;
await webpush.sendNotification(subscriptionData, notificationPayload); await webpush.sendNotification(subscriptionData, notificationPayload);
console.log( // console.log(
`Notification sent successfully to ${subscriptionData.endpoint}` // `Notification sent successfully to ${subscriptionData.endpoint}`
); // );
successCount++; successCount++;
} catch (error: any) { } catch (error: any) {
console.error( console.error(

View File

@@ -167,7 +167,7 @@ export async function POST(request: Request) {
const cekPhone = await prisma.user.count({ const cekPhone = await prisma.user.count({
where: { where: {
phone: data.phone phone: "62" + data.phone
}, },
}); });
@@ -177,7 +177,7 @@ export async function POST(request: Request) {
data: { data: {
nik: data.nik, nik: data.nik,
name: data.name, name: data.name,
phone: data.phone, phone: "62" + data.phone,
email: data.email, email: data.email,
gender: data.gender, gender: data.gender,
idGroup: groupFix, idGroup: groupFix,

View File

@@ -5,15 +5,16 @@ import { RefObject } from "react";
export const pwd_key_config = "fchgvjknlmdfnbvghhujlaknsdvjbhknlkmsdbdyu567t8y9u30r4587638y9uipkoeghjvuyi89ipkoefmnrjbhtiu4or9ipkoemnjfbhjiuoijdklnjhbviufojkejnshbiuojijknehgruyu" export const pwd_key_config = "fchgvjknlmdfnbvghhujlaknsdvjbhknlkmsdbdyu567t8y9u30r4587638y9uipkoeghjvuyi89ipkoefmnrjbhtiu4or9ipkoemnjfbhjiuoijdklnjhbviufojkejnshbiuojijknehgruyu"
export const globalRole = hookstate<string>('') export const globalRole = hookstate<string>('')
export const DIR = { export const DIR = {
parentDir: "cm0x8a1as0001bp5te7354yrp",
task: "cm0xhcqf0000dacbbixjb09yn", task: "cm0xhcqf0000dacbbixjb09yn",
project: "cm0xhc9sv000bacbb7rfikw1k", project: "cm0xhc9sv000bacbb7rfikw1k",
document: "cm0xhbkf50009acbbtw03qo4l", document: "cm0xhbkf50009acbbtw03qo4l",
village: "cm0xhb91o0007acbbkx8rk8hj", village: "cm0xhb91o0007acbbkx8rk8hj",
user: "cm0x8dbwn0005bp5tgmfcthzw", user: "cm0x8dbwn0005bp5tgmfcthzw",
banner: "cm1sxex19004938bjvyaq8vta"
} }
export const keyWibu= 'padahariminggukuturutayahkekotanaikdelmanistimewakududukdimuka' export const keyWibu = 'padahariminggukuturutayahkekotanaikdelmanistimewakududukdimuka'
export const TEMA = hookstate<IGlobalTema>({ export const TEMA = hookstate<IGlobalTema>({
utama: "#19345E", utama: "#19345E",

View File

@@ -0,0 +1,22 @@
export async function funViewDir({ dirId }: { dirId: string }) {
try {
const res = await fetch("https://wibu-storage.wibudev.com/api/dir/" + dirId + "/tree", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.WS_APIKEY}`
}
});
if (res.ok) {
const hasil = await res.json()
return { success: true, data: hasil.data }
} else {
const errorText = await res.text();
return { success: false, data: {} }
}
} catch (error) {
console.error("Upload error:", error);
return { success: false, data: {} }
}
}

View File

@@ -25,6 +25,7 @@ import NotificationCustome from "./components/notification_custome";
import { ScrollProvider } from "./components/scroll_provider"; import { ScrollProvider } from "./components/scroll_provider";
import SkeletonUser from "./components/skeleton_user"; import SkeletonUser from "./components/skeleton_user";
import SkeletonList from "./components/skeleton_list"; import SkeletonList from "./components/skeleton_list";
import { funViewDir } from "./fun/view_dir";
export { WARNA }; export { WARNA };
export { LayoutLogin }; export { LayoutLogin };
@@ -59,3 +60,4 @@ export { currentScroll }
export { SkeletonUser } export { SkeletonUser }
export { SkeletonList } export { SkeletonList }
export { keyWibu } export { keyWibu }
export { funViewDir }

View File

@@ -19,14 +19,13 @@ export default function CreateAnnouncement() {
const memberGroup = useHookstate(globalMemberAnnouncement) const memberGroup = useHookstate(globalMemberAnnouncement)
const memberValue = memberGroup.get() as GroupData[] const memberValue = memberGroup.get() as GroupData[]
const [selectedFiles, setSelectedFiles] = useState<any>([]) const [selectedFiles, setSelectedFiles] = useState<any>([])
const [loadingKonfirmasi, setLoadingKonfirmasi] = useState(false)
const router = useRouter() const router = useRouter()
const tema = useHookstate(TEMA) const tema = useHookstate(TEMA)
const [data, setData] = useWibuRealtime({ const [data, setData] = useWibuRealtime({
WIBU_REALTIME_TOKEN: keyWibu, WIBU_REALTIME_TOKEN: keyWibu,
project: "sdm" project: "sdm"
}) })
const [isChooseMember, setIsChooseMember] = useState(false) const [isChooseMember, setIsChooseMember] = useState(false)
const [isData, setisData] = useState({ const [isData, setisData] = useState({
title: "", title: "",
@@ -37,8 +36,10 @@ export default function CreateAnnouncement() {
desc: false desc: false
}); });
async function onSubmit() { async function onSubmit() {
try { try {
setLoadingKonfirmasi(true)
const response = await funCreateAnnouncement({ const response = await funCreateAnnouncement({
title: isData.title, title: isData.title,
desc: isData.desc, desc: isData.desc,
@@ -56,9 +57,11 @@ export default function CreateAnnouncement() {
} catch (error) { } catch (error) {
console.error(error) console.error(error)
toast.error("Gagal menambahkan pengumuman, coba lagi nanti"); toast.error("Gagal menambahkan pengumuman, coba lagi nanti");
} finally {
setLoadingKonfirmasi(false)
setOpen(false)
} }
setOpen(false)
} }
async function loadData() { async function loadData() {
@@ -69,18 +72,31 @@ export default function CreateAnnouncement() {
loadData() loadData()
}, []) }, [])
function onToChooseMember() {
setIsChooseMember(true)
}
if (isChooseMember) return <CreateUsersAnnouncement onClose={() => { setIsChooseMember(false) }} />
function onCheck() { function onCheck() {
if (Object.values(touched).some((v) => v == true)) const cek = checkAll()
if (!cek)
return false return false
if (memberValue.length == 0)
return toast.error("Error! silahkan pilih divisi")
setOpen(true) setOpen(true)
} }
function checkAll() {
let nilai = true
if (isData.title === "") {
setTouched(touched => ({ ...touched, title: true }))
nilai = false
}
if (isData.desc === "") {
setTouched(touched => ({ ...touched, desc: true }))
nilai = false
}
return nilai
}
function onValidation(kategori: string, val: string) { function onValidation(kategori: string, val: string) {
if (kategori == 'title') { if (kategori == 'title') {
@@ -100,6 +116,8 @@ export default function CreateAnnouncement() {
} }
} }
if (isChooseMember) return <CreateUsersAnnouncement onClose={() => { setIsChooseMember(false) }} />
return ( return (
<Box> <Box>
<LayoutNavbarNew back="/announcement/" title="Tambah Pengumuman" menu={<></>} /> <LayoutNavbarNew back="/announcement/" title="Tambah Pengumuman" menu={<></>} />
@@ -151,7 +169,7 @@ export default function CreateAnnouncement() {
padding: 10, padding: 10,
borderRadius: 10 borderRadius: 10
}} }}
onClick={() => { onToChooseMember() }} onClick={() => { setIsChooseMember(true) }}
> >
<Text size="sm"> <Text size="sm">
Tambah divisi penerima pengumuman Tambah divisi penerima pengumuman
@@ -162,7 +180,7 @@ export default function CreateAnnouncement() {
<Box pt={20} mb={100}> <Box pt={20} mb={100}>
<Text c={tema.get().utama} mb={10}>Divisi Terpilih</Text> <Text c={tema.get().utama} mb={10}>Divisi Terpilih</Text>
{(memberGroup.length === 0) ? ( {(memberGroup.length === 0) ? (
<Text c="dimmed" ta={"center"} fs={"italic"}>Belum ada anggota</Text> <Text c="dimmed" ta={"center"} fs={"italic"}>Belum ada divisi yang dipilih</Text>
) : memberGroup.get().map((v: any, i: any) => { ) : memberGroup.get().map((v: any, i: any) => {
return ( return (
<Box key={i} mt={10}> <Box key={i} mt={10}>
@@ -195,13 +213,14 @@ export default function CreateAnnouncement() {
Simpan Simpan
</Button> </Button>
</Box> </Box>
<LayoutModal opened={isOpen} onClose={() => setOpen(false)} <LayoutModal loading={loadingKonfirmasi} opened={isOpen} onClose={() => setOpen(false)}
description="Apakah Anda yakin ingin menambahkan data?" description="Apakah Anda yakin ingin menambahkan data?"
onYes={(val) => { onYes={(val) => {
if (val) { if (val) {
onSubmit() onSubmit()
} else {
setOpen(false)
} }
setOpen(false)
}} /> }} />
</Box> </Box>

View File

@@ -1,15 +1,16 @@
"use client"; "use client";
import { LayoutNavbarNew, TEMA, WARNA } from '@/module/_global'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import { funGetGroupDivision } from '@/module/group/lib/api_group'; import { funGetGroupDivision } from '@/module/group/lib/api_group';
import { Box, Button, Divider, Flex, Group, rem, Skeleton, Stack, Text } from '@mantine/core';
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
import React, { useState } from 'react';
import { FaCheck } from 'react-icons/fa';
import { GroupData } from '../lib/type_announcement';
import { useHookstate } from '@hookstate/core'; import { useHookstate } from '@hookstate/core';
import { globalMemberAnnouncement } from '../lib/val_announcement'; import { ActionIcon, Box, Button, Divider, Group, rem, Skeleton, Stack, Text } from '@mantine/core';
import { FaMinus } from 'react-icons/fa6'; import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
import { useState } from 'react';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { FaCheck } from 'react-icons/fa';
import { FaMinus } from 'react-icons/fa6';
import { HiChevronLeft } from 'react-icons/hi2';
import { GroupData } from '../lib/type_announcement';
import { globalMemberAnnouncement } from '../lib/val_announcement';
@@ -112,7 +113,13 @@ export default function CreateUsersAnnouncement({ onClose }: { onClose: (val: an
return ( return (
<div> <div>
<LayoutNavbarNew back="" title="Tambah Divisi Penerima Pengumuman" menu={<></>} /> <LayoutNavbarNew state={
<Box>
<ActionIcon variant="light" onClick={() => { onClose(true) }} bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
<HiChevronLeft size={20} color='white' />
</ActionIcon>
</Box>
} title="Tambah Divisi Penerima Pengumuman" menu={<></>} />
<Box p={20} pb={100}> <Box p={20} pb={100}>
<Group justify='flex-end' mb={20}> <Group justify='flex-end' mb={20}>
<Text <Text

View File

@@ -1,21 +1,21 @@
'use client' 'use client'
import { LayoutNavbarNew, TEMA, WARNA } from "@/module/_global"; import { LayoutNavbarNew, TEMA } from "@/module/_global";
import LayoutModal from "@/module/_global/layout/layout_modal"; import LayoutModal from "@/module/_global/layout/layout_modal";
import { useHookstate } from "@hookstate/core";
import { Box, Button, Flex, Group, List, rem, Skeleton, Stack, Text, Textarea, TextInput } from "@mantine/core"; import { Box, Button, Flex, Group, List, rem, Skeleton, Stack, Text, Textarea, TextInput } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { HiOutlineChevronRight } from "react-icons/hi2";
import { funEditAnnouncement, funGetAnnouncementById } from "../lib/api_announcement";
import { useParams, useRouter } from "next/navigation";
import { useHookstate } from "@hookstate/core";
import { globalMemberEditAnnouncement } from "../lib/val_announcement";
import { GroupData, GroupDataEditAnnouncement } from "../lib/type_announcement";
import EditChooseMember from "./edit_choose_member";
import { IoIosArrowForward } from "react-icons/io"; import { IoIosArrowForward } from "react-icons/io";
import { funEditAnnouncement, funGetAnnouncementById } from "../lib/api_announcement";
import { GroupData } from "../lib/type_announcement";
import { globalMemberEditAnnouncement } from "../lib/val_announcement";
import EditChooseMember from "./edit_choose_member";
export default function EditAnnouncement() { export default function EditAnnouncement() {
const [isOpen, setOpen] = useState(false) const [isOpen, setOpen] = useState(false)
const [loadingKonfirmasi, setLoadingKonfirmasi] = useState(false)
const [isChooseDivisi, setChooseDivisi] = useState(false) const [isChooseDivisi, setChooseDivisi] = useState(false)
const param = useParams<{ id: string }>() const param = useParams<{ id: string }>()
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
@@ -75,6 +75,7 @@ export default function EditAnnouncement() {
toast.error("Gagal mendapatkan pengumuman, coba lagi nanti") toast.error("Gagal mendapatkan pengumuman, coba lagi nanti")
} finally { } finally {
setLoading(false) setLoading(false)
setOpen(false)
} }
} }
@@ -94,30 +95,24 @@ export default function EditAnnouncement() {
if (response.success) { if (response.success) {
toast.success(response.message) toast.success(response.message)
setLoadingSubmit(false)
router.push(`/announcement/${param.id}`) router.push(`/announcement/${param.id}`)
} else { } else {
toast.error(response.message) toast.error(response.message)
} }
setLoadingSubmit(false)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
toast.error("Gagal mengedit pengumuman, coba lagi nanti"); toast.error("Gagal mengedit pengumuman, coba lagi nanti");
} finally { } finally {
setLoadingSubmit(false) setLoadingSubmit(false)
setOpen(false)
} }
setOpen(false)
} }
if (isChooseDivisi) return <EditChooseMember onClose={() => { setChooseDivisi(false) }} />
function onCheck() { function onCheck() {
if (Object.values(touched).some((v) => v == true)) if (Object.values(touched).some((v) => v == true))
return false return false
if (memberGroup.get().length == 0)
return toast.error("Error! silahkan pilih divisi")
setOpen(true) setOpen(true)
} }
@@ -140,6 +135,8 @@ export default function EditAnnouncement() {
} }
} }
if (isChooseDivisi) return <EditChooseMember onClose={() => { setChooseDivisi(false) }} />
return ( return (
<> <>
<LayoutNavbarNew back="" title="Edit Pengumuman" menu={<></>} /> <LayoutNavbarNew back="" title="Edit Pengumuman" menu={<></>} />
@@ -160,7 +157,7 @@ export default function EditAnnouncement() {
: :
<> <>
<TextInput <TextInput
size="md" type="text" radius={30} placeholder="Judul Pengumuman" withAsterisk label="Judul" w={"100%"} size="md" type="text" radius={10} placeholder="Judul Pengumuman" withAsterisk label="Judul" w={"100%"}
styles={{ styles={{
input: { input: {
color: tema.get().utama, color: tema.get().utama,
@@ -231,28 +228,34 @@ export default function EditAnnouncement() {
)) ))
: :
memberGroup.get().map((v: any, i: any) => { <>
return ( <Text c={tema.get().utama} mb={10}>Divisi Terpilih</Text>
<Box key={i} mt={10}> {
<Text fw={"bold"}>{v.name}</Text> memberGroup.get().length == 0 ? <Text c="dimmed" ta={"center"} fs={"italic"}>Belum ada divisi yang dipilih</Text> :
<Box pl={20} pr={10}> memberGroup.get().map((v: any, i: any) => {
<Flex direction={"column"} gap={"md"}> return (
<List> <Box key={i} mt={10}>
{ <Text fw={"bold"}>{v.name}</Text>
v.Division.map((division: any) => { <Box pl={20} pr={10}>
return <List.Item key={division.id}> <Flex direction={"column"} gap={"md"}>
<Text lineClamp={1}>{division.name}</Text> <List>
</List.Item> {
}) v.Division.map((division: any) => {
} return <List.Item key={division.id}>
</List> <Text lineClamp={1}>{division.name}</Text>
</Flex> </List.Item>
</Box> })
</Box> }
); </List>
</Flex>
</Box>
</Box>
);
})
}
</>
}
)
} }
</Box> </Box>
@@ -282,8 +285,9 @@ export default function EditAnnouncement() {
onYes={(val) => { onYes={(val) => {
if (val) { if (val) {
onSubmit() onSubmit()
} else {
setOpen(false)
} }
setOpen(false)
}} /> }} />
</> </>
) )

View File

@@ -1,17 +1,16 @@
"use client"; "use client";
import { LayoutNavbarNew, TEMA, WARNA } from '@/module/_global'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import { funGetGroupDivision } from '@/module/group/lib/api_group'; import { funGetGroupDivision } from '@/module/group/lib/api_group';
import { Box, Button, Divider, Flex, Group, rem, Skeleton, Stack, Text } from '@mantine/core';
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
import React, { useState } from 'react';
import { FaCheck } from 'react-icons/fa';
import { GroupData, GroupDataEditAnnouncement } from '../lib/type_announcement';
import { useHookstate } from '@hookstate/core'; import { useHookstate } from '@hookstate/core';
import { globalMemberEditAnnouncement } from '../lib/val_announcement'; import { ActionIcon, Box, Button, Divider, Group, rem, Skeleton, Stack, Text } from '@mantine/core';
import { FaMinus } from 'react-icons/fa6'; import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
import { useState } from 'react';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { FaCheck } from 'react-icons/fa';
import { FaMinus } from 'react-icons/fa6';
import { HiChevronLeft } from 'react-icons/hi2';
import { GroupData } from '../lib/type_announcement';
import { globalMemberEditAnnouncement } from '../lib/val_announcement';
interface CheckedState { interface CheckedState {
[key: string]: string[]; [key: string]: string[];
@@ -111,7 +110,13 @@ export default function EditChooseMember({ onClose }: { onClose: (val: any) => v
return ( return (
<div> <div>
<LayoutNavbarNew back="" title="Tambah Divisi Penerima Pengumuman" menu={<></>} /> <LayoutNavbarNew state={
<Box>
<ActionIcon variant="light" onClick={() => { onClose(true) }} bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
<HiChevronLeft size={20} color='white' />
</ActionIcon>
</Box>
} title="Tambah Divisi Penerima Pengumuman" menu={<></>} />
<Box p={20} pb={100}> <Box p={20} pb={100}>
<Group justify='flex-end' mb={20}> <Group justify='flex-end' mb={20}>
<Text <Text

View File

@@ -49,23 +49,30 @@ function ViewLogin() {
if (cekLogin.success) { if (cekLogin.success) {
const code = Math.floor(Math.random() * 1000) + 1000 const code = Math.floor(Math.random() * 1000) + 1000
setLoading(true) setLoading(true)
try {
const res = await fetch(`https://wa.wibudev.com/code?nom=${cekLogin.phone}&text=*DARMASABA*%0A%0A const res = await fetch(`https://wa.wibudev.com/code?nom=${cekLogin.phone}&text=*DARMASABA*%0A%0A
JANGAN BERIKAN KODE RAHASIA ini kepada siapa pun TERMASUK PIHAK DARMASABA. Masukkan otentikasi: *${encodeURIComponent(code)}*`).then( JANGAN BERIKAN KODE RAHASIA ini kepada siapa pun TERMASUK PIHAK DARMASABA. Masukkan otentikasi: *${encodeURIComponent(code)}*`).then(
async (res) => { async (res) => {
if (res.status == 200) { if (res.status == 200) {
setValPhone(cekLogin.phone) setValPhone(cekLogin.phone)
setOTP(code) setOTP(code)
setUser(cekLogin.id) setUser(cekLogin.id)
setVerif(true) setVerif(true)
setLoading(false) setLoading(false)
toast.success('Kode verifikasi telah dikirim') toast.success('Kode verifikasi telah dikirim')
} else { } else {
toast.error('Internal Server Error') console.error(res.status)
setLoading(false) toast.error('Internal Server Error')
setLoading(false)
}
} }
} )
) } catch (error) {
console.error(error)
toast.error('Internal Server Error')
}finally{
setLoading(false)
}
} else { } else {
return toast.error(cekLogin.message) return toast.error(cekLogin.message)
} }

View File

@@ -14,26 +14,30 @@ export default function ViewVerification({ phone, otp, user }: IVerification) {
const [isLoading, setLoading] = useState(false) const [isLoading, setLoading] = useState(false)
async function onResend() { async function onResend() {
const code = Math.floor(Math.random() * 1000) + 1000 try {
const code = Math.floor(Math.random() * 1000) + 1000
const res = await fetch(`https://wa.wibudev.com/code?nom=${phone}&text=*DARMASABA*%0A%0A const res = await fetch(`https://wa.wibudev.com/code?nom=${phone}&text=*DARMASABA*%0A%0A
JANGAN BERIKAN KODE RAHASIA ini kepada siapa pun TERMASUK PIHAK DARMASABA. Masukkan otentikasi: *${encodeURIComponent(code)}*`) JANGAN BERIKAN KODE RAHASIA ini kepada siapa pun TERMASUK PIHAK DARMASABA. Masukkan otentikasi: *${encodeURIComponent(code)}*`)
.then( .then(
async (res) => { async (res) => {
if (res.status == 200) { if (res.status == 200) {
toast.success('Kode verifikasi telah dikirim') toast.success('Kode verifikasi telah dikirim')
setOTP(code) setOTP(code)
} else { } else {
toast.error('Internal Server Error') toast.error('Internal Server Error')
}
} }
} );
); } catch (error) {
console.error(error)
toast.error('Internal Server Error')
}
} }
async function getVerification() { async function getVerification() {
setLoading(true) setLoading(true)
if (isOTP == inputOTP) { if (isOTP == inputOTP) {
const setCookies = await funSetCookies({ user: user }) const setCookies: any = await funSetCookies({ user: user })
if (setCookies.success) { if (setCookies.success) {
toast.success(setCookies.message) toast.success(setCookies.message)

View File

@@ -1,4 +1,6 @@
import NavbarBanner from "./ui/navbar_banner"; import NavbarBanner from "./ui/navbar_banner";
import ListBanner from "./ui/list_banner"; import ListBanner from "./ui/list_banner";
import CreateBanner from "./ui/create_banner"; import CreateBanner from "./ui/create_banner";
export {NavbarBanner, ListBanner, CreateBanner} import EditBanner from "./ui/edit_banner";
import ViewfileBanner from "./ui/viewfile_banner";
export { NavbarBanner, ListBanner, CreateBanner, EditBanner, ViewfileBanner }

View File

@@ -0,0 +1,35 @@
export const funGetAllBanner = async (path?: string) => {
const response = await fetch(`/api/banner${(path) ? path : ''}`, { next: { tags: ['banner'] } });
return await response.json().catch(() => null);
}
export const funDeleteBanner = async (path: string) => {
const response = await fetch(`/api/banner/${path}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
});
return await response.json().catch(() => null);
};
export const funCreateBanner = async (data: FormData) => {
const response = await fetch(`/api/banner`, {
method: "POST",
body: data,
});
return await response.json().catch(() => null);
}
export const funGetOneBanner = async (path: string) => {
const response = await fetch(`/api/banner/${path}`)
return await response.json().catch(() => null);
}
export const funEditBanner = async (path: string, data: FormData) => {
const response = await fetch(`/api/banner/${path}`, {
method: "PUT",
body: data,
});
return await response.json().catch(() => null);
}

View File

@@ -0,0 +1,19 @@
export interface IDataBanner {
id: string
title: string
extension: string
image: string
}[]
export interface IEditDataBanner {
id: string
title: string
extension: string
image: string
}
export interface ICreateDataBanner {
id: string
title: string
extension: string
image: string
}

View File

@@ -1,71 +1,206 @@
'use client' 'use client'
import { LayoutNavbarNew, WARNA } from '@/module/_global'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import { Box, Button, FileInput, Group, Paper, rem, Text, TextInput } from '@mantine/core'; import LayoutModal from '@/module/_global/layout/layout_modal';
import { IconUpload, IconPhoto, IconX } from '@tabler/icons-react'; import { useHookstate } from '@hookstate/core';
import { Dropzone, DropzoneProps, IMAGE_MIME_TYPE } from '@mantine/dropzone'; import { Box, Button, Group, Image, Paper, rem, Text, TextInput } from '@mantine/core';
import React from 'react'; import { Dropzone } from '@mantine/dropzone';
import { IconPhoto, IconUpload, IconX } from '@tabler/icons-react';
import _ from 'lodash';
import { useRouter } from 'next/navigation';
import { useRef, useState } from 'react';
import toast from 'react-hot-toast';
import { funCreateBanner } from '../lib/api_banner';
import { title } from 'process';
function CreateBanner() {
const router = useRouter();
const [isModal, setModal] = useState(false);
const tema = useHookstate(TEMA)
const [loadingKonfirmasi, setLoadingKonfirmasi] = useState(false)
const [listData, setListData] = useState({
title: "",
image: ""
});
const [imgForm, setImgForm] = useState<any>()
const openRef = useRef<() => void>(null)
const [img, setIMG] = useState<any | null>()
const [touched, setTouched] = useState({
title: false,
image: false
})
function onValidation(kategori: string, val: any) {
if (kategori == 'title') {
setListData({ ...listData, title: val })
if (val === "") {
setTouched({ ...touched, title: true })
} else {
setTouched({ ...touched, title: false })
}
} else if (kategori == 'image') {
if (imgForm) {
setTouched({ ...touched, image: false })
} else {
setTouched({ ...touched, image: true })
}
}
}
async function onSubmit(val: boolean) {
if (!imgForm || !listData.title) {
toast.error("Mohon lengkapi semua data");
}
try {
setLoadingKonfirmasi(true)
const fd = new FormData()
fd.append("file", imgForm)
fd.append("data", JSON.stringify(
{
title: listData.title,
image: listData.image
}
))
const res = await funCreateBanner(fd);
if (res.success) {
toast.success(res.message);
router.push('/banner')
} else {
toast.error(res.message);
}
setModal(false);
} catch (error) {
toast.error("Error");
} finally {
setLoadingKonfirmasi(false)
setModal(false);
}
}
// async function loadData() {
// const
// }
function CreateBanner(props: Partial<DropzoneProps>) {
return ( return (
<Box> <Box>
<LayoutNavbarNew back='/banner' title='Tambah Banner' menu={<></>} /> <LayoutNavbarNew back='/banner' title='Tambah Banner' menu />
<Box p={20}> <Box p={20}>
<Box> <Box>
<Paper withBorder radius={20}> <Paper withBorder radius={20}>
<Dropzone <Dropzone
onDrop={(files) => console.log('accepted files', files)} openRef={openRef}
onReject={(files) => console.log('rejected files', files)} onDrop={async (files) => {
maxSize={5 * 1024 ** 2} if (!files || _.isEmpty(files))
accept={IMAGE_MIME_TYPE} return toast.error('Tidak ada gambar yang dipilih')
{...props} const file = files[0]
setImgForm(file)
const buffer = URL.createObjectURL(new Blob([new Uint8Array(await files[0].arrayBuffer())]))
setIMG(buffer)
onValidation('image', files[0])
}}
activateOnClick={false}
maxSize={1 * 1024 ** 2}
accept={['image/png', 'imagfe/jpeg', 'image/heic']}
onReject={(files) => {
return toast.error('File yang diizinkan: .png, .jpg, dan .heic dengan ukuran maksimal 1 MB')
}}
onClick={() => openRef.current?.()}
> >
<Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
<Dropzone.Accept>
<IconUpload
style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-blue-6)' }}
stroke={1.5}
/>
</Dropzone.Accept>
<Dropzone.Reject>
<IconX
style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-red-6)' }}
stroke={1.5}
/>
</Dropzone.Reject>
<Dropzone.Idle>
<IconPhoto
style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-dimmed)' }}
stroke={1.5}
/>
</Dropzone.Idle>
<Box> {
<Text size="xl" inline> img ?
Upload File <Image radius="md" src={img} alt='' />
</Text> :
<Text size="sm" c="dimmed" inline mt={7}> <Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
File Tidak Boleh Melebihi 500mb <Dropzone.Accept>
</Text> <IconUpload
</Box> style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-blue-6)' }}
</Group> stroke={1.5}
/>
</Dropzone.Accept>
<Dropzone.Reject>
<IconX
style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-red-6)' }}
stroke={1.5}
/>
</Dropzone.Reject>
<Dropzone.Idle>
<IconPhoto
style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-dimmed)' }}
stroke={1.5}
/>
</Dropzone.Idle>
<div>
<Text size="xl" inline>
Klik Untuk Upload Image
</Text>
<Text size="sm" c="dimmed" inline mt={7}>
Ukuran Foto Tidak Boleh Lebih Dari 1MB
</Text>
</div>
</Group>
}
</Dropzone> </Dropzone>
</Paper> </Paper>
<Box> <Box>
<TextInput <TextInput
mt={10} mt={10}
label={ <Text>Judul Banner</Text>} label={<Text >Judul Banner</Text>}
value={listData.title}
placeholder='Judul Banner' placeholder='Judul Banner'
onChange={(e) => {
setListData({ ...listData, title: e.target.value })
onValidation('title', e.target.value)
}}
styles={{ styles={{
input: { input: {
border: `1px solid ${"#D6D8F6"}`, border: `1px solid ${touched.title ? 'red' : "#D6D8F6"}`,
borderRadius: 10, borderRadius: 10,
}, },
}} }}
/> />
</Box> </Box>
<Button size='lg' bg={WARNA.biruTua} radius={30} fullWidth mt={20}>Simpan</Button> <Box pos={"fixed"} bottom={0} p={rem(20)} w={"100%"} style={{
maxWidth: rem(510),
zIndex: 999,
backgroundColor: `${tema.get().bgUtama}`
}}>
<Button
size='lg'
color='white'
bg={tema.get().utama} radius={30} fullWidth
onClick={() => {
if (touched.title || touched.image) {
toast.error("Mohon Isi Semua Data")
} else {
setModal(true)
}
}}
>Simpan</Button>
</Box>
</Box> </Box>
</Box> </Box>
<LayoutModal
loading={loadingKonfirmasi}
opened={isModal}
onClose={() => setModal(false)}
description="Apakah anda yakin ingin menambahkan banner ini?"
onYes={(val) => {
if (val) {
onSubmit(val);
} else {
setModal(false);
}
}}
/>
</Box> </Box>
); );
} }

View File

@@ -0,0 +1,188 @@
'use client'
import { LayoutNavbarNew, TEMA, WARNA } from '@/module/_global';
import LayoutModal from '@/module/_global/layout/layout_modal';
import { useHookstate } from '@hookstate/core';
import { Box, Button, Image, Paper, rem, TextInput } from '@mantine/core';
import { Dropzone } from '@mantine/dropzone';
import { useShallowEffect } from '@mantine/hooks';
import _ from 'lodash';
import { useParams, useRouter } from 'next/navigation';
import { useRef, useState } from 'react';
import toast from 'react-hot-toast';
import { funEditBanner, funGetOneBanner } from '../lib/api_banner';
import { IEditDataBanner } from '../lib/type_banner';
export default function EditBanner() {
const router = useRouter()
const param = useParams<{ id: string }>()
const tema = useHookstate(TEMA)
const [isModal, setModal] = useState(false)
const [data, setData] = useState<IEditDataBanner>({
id: "",
title: "",
extension: "",
image: "",
});
const openRef = useRef<() => void>(null)
const [img, setIMG] = useState<any | null>()
const [imgForm, setImgForm] = useState<any>()
const [loading, setLoading] = useState(false)
const [touched, setTouched] = useState({
title: false,
image: false
})
function onValidation(kategori: string, val: any) {
if (kategori == 'title') {
setData({ ...data, title: val })
if (val === "") {
setTouched({ ...touched, title: true })
} else {
setTouched({ ...touched, title: false })
}
} else if (kategori == 'image') {
if (imgForm) {
setTouched({ ...touched, image: false })
} else {
setTouched({ ...touched, image: true })
}
}
}
async function getOneData() {
try {
const res = await funGetOneBanner(param.id)
console.log(res)
setData(res.data)
setIMG(`https://wibu-storage.wibudev.com/api/files/${res.data.image}`)
} catch (error) {
console.error(error)
}
}
async function onSubmit(val: boolean) {
try {
setLoading(true)
const fd = new FormData()
fd.append("file", imgForm)
fd.append("data", JSON.stringify(
{
id: data.id,
title: data.title,
image: data.image,
extension: data.extension
}
))
const res = await funEditBanner(param.id, fd)
if (res.success) {
toast.success(res.message)
router.push('/banner')
} else {
toast.error(res.message)
}
} catch (error) {
toast.error("Error");
} finally {
setLoading(false)
setModal(false)
}
}
useShallowEffect(() => {
getOneData()
}, [])
return (
<Box>
<LayoutNavbarNew back='/banner' title='Edit Banner' menu={<></>} />
<Box p={20}>
<Box>
<Paper withBorder radius={20}>
<Dropzone
openRef={openRef}
onDrop={async (files) => {
if (!files || _.isEmpty(files))
return toast.error("Tidak Ada Gambar Yang Dipilih")
setImgForm(files[0])
const buffer = URL.createObjectURL(new Blob([new Uint8Array(await files[0].arrayBuffer())]))
setIMG(buffer)
onValidation('image', files[0])
}}
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')
}}
onClick={() => openRef.current?.()}
>
<Image radius={"md"} src={img} alt="" />
</Dropzone>
</Paper>
<Box>
<TextInput
mt={10}
label="Judul Banner"
placeholder='Banner'
value={data.title}
onChange={(e) => {
setData({ ...data, title: e.target.value })
onValidation('title', e.target.value)
}}
styles={{
input: {
border: `1px solid ${touched.title ? 'red' : "#D6D8F6"}`,
borderRadius: 10,
},
}}
required
size='md'
/>
</Box>
<Box pos={"fixed"} bottom={0} p={rem(20)} w={"100%"} style={{
maxWidth: rem(510),
zIndex: 999,
backgroundColor: `${tema.get().bgUtama}`
}}>
<Button
size='lg'
color='white'
bg={tema.get().utama}
radius={30}
fullWidth
onClick={() => {
if (touched.title || touched.image) {
toast.error('Mohon Isi Semua Data')
} else {
setModal(true)
}
}}
>
Simpan
</Button>
<LayoutModal
loading={loading}
opened={isModal}
onClose={() => setModal(false)}
description="Apakah Anda yakin ingin mengedit banner ini?"
onYes={(val) => {
if (val) {
onSubmit(val)
} else {
setModal(false)
}
}}
/>
</Box>
</Box>
</Box>
</Box>
);
}

View File

@@ -1,77 +1,237 @@
'use client' 'use client'
import { LayoutDrawer, SkeletonSingle, TEMA, WARNA } from '@/module/_global'; import { currentScroll, LayoutDrawer, LayoutModalViewFile, TEMA, WARNA } from '@/module/_global';
import LayoutModal from '@/module/_global/layout/layout_modal';
import { useHookstate } from '@hookstate/core'; import { useHookstate } from '@hookstate/core';
import { Anchor, Box, Flex, Group, Image, SimpleGrid, Stack, Text, TextInput } from '@mantine/core'; import { ActionIcon, Anchor, Box, Flex, Group, Image, Paper, SimpleGrid, Stack, Text, TextInput } from '@mantine/core';
import _ from 'lodash'; import { useParams, useRouter } from 'next/navigation';
import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react';
import React, { useState } from 'react';
import { FaFile, FaPencil, FaTrash } from 'react-icons/fa6'; import { FaFile, FaPencil, FaTrash } from 'react-icons/fa6';
import { IDataBanner } from '../lib/type_banner';
import toast from 'react-hot-toast';
import { useShallowEffect } from '@mantine/hooks';
import { funDeleteBanner, funGetAllBanner, funGetOneBanner } from '../lib/api_banner';
import { HiMagnifyingGlass } from 'react-icons/hi2'; import { HiMagnifyingGlass } from 'react-icons/hi2';
import { IoAddCircle } from 'react-icons/io5';
function ListBanner() { function ListBanner() {
const [isList, setIsList] = useState(false)
const tema = useHookstate(TEMA) const tema = useHookstate(TEMA)
const [searchQuery, setSearchQuery] = useState('')
const [loading, setLoading] = useState(true);
const [isData, setData] = useState([]);
const [valChoose, setValChoose] = useState("");
const router = useRouter(); const router = useRouter();
const param = useParams<{ id: string }>()
const [isOpenModalView, setOpenModalView] = useState(false)
const [isOpenModal, setOpenModal] = useState(false)
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const [idDataStorage, setIdDataStorage] = useState('')
const [isExtension, setExtension] = useState('')
const [loading, setLoading] = useState(true)
const [isData, setData] = useState<IDataBanner[]>([])
const [idData, setIdData] = useState('')
const [isPage, setPage] = useState(1)
const [searchQuerry, setSearchQuerry] = useState('')
// const { value: containerRef } = useHookstate(currentScroll);
const handleList = () => {
setIsList(!isList)
}
const fetchData = async (loading: boolean) => {
try {
if (loading)
setLoading(true)
const response = await funGetAllBanner('?search=' + searchQuerry)
if (response.success) {
setData(response.data.map((banner: { image: any; }) => ({ ...banner, image: banner.image })));
} else {
toast.error(response.message)
}
setLoading(false)
} catch (error) {
console.error(error)
toast.error("Gagal mendapatkan banner, coba lagi nanti");
} finally {
setLoading(false)
}
}
function searchBanner(search: string) {
setSearchQuerry(search)
setPage(1)
}
useShallowEffect(() => {
fetchData(true)
}, [searchQuerry])
useShallowEffect(() => {
fetchData(false)
}, [isPage])
async function onDelete(id: string) {
try {
const res = await funDeleteBanner(id);
if (res.success) {
toast.success(res.message)
setData(isData.filter((banner) => banner.id !== id));
setIdData("")
setIdDataStorage("")
setOpenDrawer(false)
} else {
toast.error(res.message);
}
} catch (error) {
console.error(error);
toast.error("Gagal menghapus banner, coba lagi nanti");
}
}
return ( return (
<Box pt={20}> <Box pt={2}>
<Box> <Box p={20}>
<TextInput
styles={{
input: {
color: tema.get().utama,
borderRadius: '#A3A3A3',
borderColor: '#A3A3A3',
},
}}
size='md'
radius={30}
leftSection={<HiMagnifyingGlass size={20} />}
placeholder='pencarian'
value={searchQuerry}
onChange={(val) => { searchBanner(val.target.value) }}
/>
</Box>
<Box p={20}>
<Anchor underline='never'> <Anchor underline='never'>
<Stack align='center' justify='center'> <Stack align='center' justify='center'>
{[...Array(5)].map((_, index) => ( {isData.map((v, index) => (
<div key={index} onClick={() => { setOpenDrawer(true) }}> <Paper radius={'md'} withBorder key={index} onClick={() => {
<Text c={"dark"} ta={"center"}>Banner {index + 1}</Text> setIdData(v.id);
<Image radius={"lg"} src={`/assets/img/banner/Banner-${index + 1}.png`} alt='' w={380} h={194.5} /> setIdDataStorage(v.image);
</div> setExtension(v.extension);
setOpenDrawer(true)
}
}
style={{
width: '100%',
maxWidth: 550,
height: 85,
backgroundColor: 'transparent',
border: `1px solid ${tema.get().bgTotalKegiatan}`
}}>
<Group mt={"15"}>
<ActionIcon variant='transparent' w={"100"}>
<Image
radius={"xs"}
src={`https://wibu-storage.wibudev.com/api/files/${v.image}`}
alt=''
w={76}
h={38.9}
/>
</ActionIcon>
<Flex direction={"column"}>
<Text c={"dark"} fz={"h4"}>{v.title}</Text>
</Flex>
</Group>
</Paper>
))} ))}
</Stack> </Stack>
</Anchor> </Anchor>
</Box> </Box>
<LayoutDrawer
opened={openDrawer} <LayoutDrawer opened={openDrawer} title={'Menu'} onClose={() => setOpenDrawer(false)}>
onClose={() => setOpenDrawer(false)} <Box>
title={<Text lineClamp={1}>{"Menu"}</Text>} <Stack pt={10}>
> <SimpleGrid
<SimpleGrid cols={{ base: 2, sm: 3, lg: 3 }}
cols={{ base: 3, sm: 3, lg: 3 }} style={{
> alignContent: "flex-start",
<Box> alignItems: "flex-start"
<Anchor underline='never'> }}
<Flex direction={"column"}> >
<FaPencil size={30} color={WARNA.biruTua} /> <Flex onClick={() => router.push(`/banner/edit/${idData}`)} direction="column" align="center" justify="center" pb={20}>
<Text c={"dark"} mt={10}>Edit</Text> <Box>
</Flex> <FaPencil size={30} color={WARNA.biruTua} />
</Anchor> </Box>
</Box> <Box>
<Box> <Text c={tema.get().utama} fz={{ base: 'sm', md: 'md' }}>Edit</Text>
<Anchor underline='never'> </Box>
<Flex direction={"column"}> </Flex>
<FaFile size={30} color={WARNA.biruTua} />
<Text c={"dark"} mt={10}>View File</Text>
</Flex> <Flex onClick={() => { setOpenModalView(true) }} direction={"column"} align={"center"} justify={"center"}>
</Anchor> <Box>
</Box> <FaFile size={30} color={tema.get().utama} />
<Box > </Box>
<Anchor underline='never'> <Box>
<Flex direction={"column"}> <Text c={tema.get().utama} fz={{ base: 'sm', md: 'md'}}>Lihat File</Text>
<FaTrash size={30} color={WARNA.biruTua} /> </Box>
<Text ta="center" c={"dark"} mt={10}>Hapus</Text> </Flex>
</Flex>
</Anchor> <Flex onClick={() => { setOpenModal(true) }} direction={"column"} align={"center"} justify={"center"}>
</Box> <Box>
</SimpleGrid> <FaTrash size={30} color={tema.get().utama} />
</Box>
<Box>
<Text c={tema.get().utama} fz={{ base: 'sm', md: 'md'}}>Hapus</Text>
</Box>
</Flex>
</SimpleGrid>
</Stack>
</Box>
</LayoutDrawer> </LayoutDrawer>
<LayoutModal
opened={isOpenModal}
onClose={() => setOpenModal(false)}
description='Apakah Anda yakin ingin menghapus banner?'
onYes={(val) => {
if (val) {
onDelete(idData)
}
setOpenModal(false)
}} />
<LayoutModalViewFile opened={isOpenModalView} onClose={() => setOpenModalView(false)} file={idDataStorage} extension={isExtension} fitur="image" />
</Box> </Box>
); );
} }
export default ListBanner; export default ListBanner;
// useEffect(() => {
// const handleScroll = async () => {
// if (containerRef && containerRef.current) {
// const scrollTop = containerRef.current.scrollTop;
// const containerHeight = containerRef.current.clientHeight;
// const scrollHeight = containerRef.current.scrollHeight;
// if (scrollTop + containerHeight + 1 >= scrollHeight) {
// setPage(isPage + 1)
// }
// }
// };
// const container = containerRef?.current;
// container?.addEventListener("scroll", handleScroll);
// return () => {
// container?.removeEventListener("scroll", handleScroll);
// };
// }, [containerRef, isPage]);

View File

@@ -0,0 +1,13 @@
import { LayoutNavbarNew } from '@/module/_global';
import { Box } from '@mantine/core';
import React from 'react';
function ViewfileBanner() {
return (
<Box>
<LayoutNavbarNew back='/banner' title='View File Banner' menu={<></>}/>
</Box>
);
}
export default ViewfileBanner;

View File

@@ -1,11 +1,428 @@
import { Box } from '@mantine/core'; 'use client'
import React from 'react'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import NavbarCreateDivisionCalender from './navbar_create_division_calender'; import LayoutModal from '@/module/_global/layout/layout_modal';
import { useHookstate } from '@hookstate/core';
import { Avatar, Box, Button, Divider, Grid, Group, rem, Select, SimpleGrid, Stack, Text, Textarea, TextInput } from '@mantine/core';
import { DateInput, TimeInput } from '@mantine/dates';
import { useMediaQuery } from '@mantine/hooks';
import moment from 'moment';
import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react';
import toast from 'react-hot-toast';
import { IoIosArrowDropright } from 'react-icons/io';
import { funCreateCalender } from '../lib/api_calender';
import { IFormMemberCalender } from '../lib/type_calender';
import { globalCalender } from '../lib/val_calender';
import CreateUserCalender from './create_user_calender';
export default function CreateCalenderDivisionCaleder() { export default function CreateCalenderDivisionCaleder() {
const [value, setValue] = useState<Date | null>(null);
const router = useRouter()
const [isModal, setModal] = useState(false)
const [loadingModal, setLoadingModal] = useState(false)
const member = useHookstate(globalCalender)
const memberValue = member.get() as IFormMemberCalender[]
const [openMember, setOpenMember] = useState(false)
const param = useParams<{ id: string, detail: string }>()
const tema = useHookstate(TEMA)
const isMobile = useMediaQuery('(max-width: 369px)');
const isMobile2 = useMediaQuery("(max-width: 438px)");
const [touched, setTouched] = useState({
title: false,
dateStart: false,
timeStart: false,
timeEnd: false,
repeatEventTyper: false,
desc: false,
repeatValue: false
})
const [isData, setData] = useState({
idDivision: "",
title: "",
dateStart: "",
timeStart: "",
timeEnd: "",
linkMeet: "",
repeatEventTyper: "",
desc: "",
repeatValue: "1"
})
async function onSubmit(val: boolean) {
try {
setLoadingModal(true)
const response = await funCreateCalender({
idDivision: param.id,
title: isData.title,
dateStart: isData.dateStart,
timeStart: isData.timeStart,
timeEnd: isData.timeEnd,
linkMeet: isData.linkMeet,
repeatEventTyper: isData.repeatEventTyper,
desc: isData.desc,
repeatValue: isData.repeatValue,
member: memberValue
})
if (response.success) {
setModal(false)
router.push(`/division/${param.id}/calender`)
toast.success(response.message)
member.set([])
} else {
toast.error(response.message)
setModal(false)
}
} catch (error) {
console.error(error)
toast.error("Gagal menambahkan pengumuman, coba lagi nanti");
} finally {
setModal(false)
setLoadingModal(false)
}
}
function onCheck() {
const cek = checkAll()
if (!cek)
return false
if (memberValue.length == 0)
return toast.error("Error! silahkan pilih anggota")
setModal(true)
}
function checkAll() {
let nilai = true
if (isData.title === "") {
setTouched(touched => ({ ...touched, title: true }))
nilai = false
}
if (isData.dateStart === "") {
setTouched(touched => ({ ...touched, dateStart: true }))
nilai = false
}
if (isData.timeStart == "") {
setTouched(touched => ({ ...touched, timeStart: true }))
nilai = false
}
if (isData.timeEnd == "" || isData.timeStart > isData.timeEnd) {
setTouched(touched => ({ ...touched, timeEnd: true }))
nilai = false
}
if (isData.repeatEventTyper == "" || String(isData.repeatEventTyper) == "null") {
setTouched(touched => ({ ...touched, repeatEventTyper: true }))
nilai = false
}
if (isData.repeatValue === "" || Number(isData.repeatValue) <= 0) {
setTouched(touched => ({ ...touched, repeatValue: true }))
nilai = false
}
return nilai
}
function onValidation(kategori: string, val: any) {
if (kategori == 'title') {
setData({ ...isData, title: val })
if (val === "") {
setTouched({ ...touched, title: true })
} else {
setTouched({ ...touched, title: false })
}
} else if (kategori == 'dateStart') {
setValue(val)
setData({ ...isData, dateStart: moment(val).format("YYYY-MM-DD") })
if (val === "") {
setTouched({ ...touched, dateStart: true })
} else {
setTouched({ ...touched, dateStart: false })
}
} else if (kategori == 'timeStart') {
setData({ ...isData, timeStart: val })
if (val == "") {
setTouched({ ...touched, timeStart: true })
} else {
setTouched({ ...touched, timeStart: false })
}
} else if (kategori == 'timeEnd') {
setData({ ...isData, timeEnd: val })
if (val == "" || isData.timeStart > val) {
setTouched({ ...touched, timeEnd: true })
} else {
setTouched({ ...touched, timeEnd: false })
}
} else if (kategori == 'repeatEventTyper') {
setData(isData => ({ ...isData, repeatEventTyper: val }))
if (val == "once") {
setData(isData => ({ ...isData, repeatValue: "1" }))
}
if (val == "" || String(val) == "null") {
setTouched({ ...touched, repeatEventTyper: true })
} else {
setTouched({ ...touched, repeatEventTyper: false })
}
} else if (kategori == 'repeatValue') {
setData(isData => ({ ...isData, repeatValue: val, }))
if (val === "" || Number(val) <= 0) {
setTouched(touched => ({ ...touched, repeatValue: true }))
} else {
setTouched({ ...touched, repeatValue: false })
}
}
}
if (openMember) return <CreateUserCalender onClose={() => setOpenMember(false)} />
return ( return (
<Box> <Box>
<NavbarCreateDivisionCalender /> <LayoutNavbarNew back={`/division/${param.id}/calender/`} title="Tambah Acara" menu />
<Box p={20}>
<Stack pb={100}>
<TextInput
required
styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
size="md"
placeholder="Nama Acara"
label="Nama Acara"
value={isData.title}
onChange={(event) => { onValidation('title', event.target.value) }}
error={
touched.title && (
isData.title == "" ? "Nama Acara Tidak Boleh Kosong" : null
)
}
/>
<DateInput
required
styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
size="md"
value={value}
onChange={(val) => { onValidation('dateStart', val) }}
placeholder="Input Tanggal"
label="Tanggal"
error={
touched.dateStart && (
isData.dateStart == "" ? "Tanggal Tidak Boleh Kosong" : null
)
}
/>
<SimpleGrid
cols={{ base: 2, sm: 2, lg: 2 }}
>
<TimeInput
required
styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
size="md"
label="Waktu Awal"
value={isData.timeStart}
onChange={(event) => onValidation('timeStart', event.target.value)}
error={
touched.timeStart && (
isData.timeStart == "" ? "Waktu Awal Tidak Boleh Kosong" : null
)
}
/>
<TimeInput
required
styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
size="md"
label="Waktu Akhir"
value={isData.timeEnd}
onChange={(event) => onValidation('timeEnd', event.target.value)}
error={
touched.timeEnd && (
isData.timeEnd == "" ? "Waktu Akhir Tidak Boleh Kosong" : null
) ||
(isData.timeStart > isData.timeEnd ? "Waktu Akhir Tidak Tepat" : null)
}
/>
</SimpleGrid>
<TextInput
styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
size="md"
placeholder="Link Meet"
label="Link Meet"
value={isData.linkMeet}
onChange={(event) => setData({ ...isData, linkMeet: event.target.value })}
/>
<Select
required
styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
size="md"
placeholder="Ulangi Acara"
label="Ulangi Acara"
data={[
{ value: 'once', label: 'Acara 1 Kali' },
{ value: 'daily', label: 'Setiap Hari' },
{ value: 'weekly', label: 'Mingguan' },
{ value: 'monthly', label: 'Bulanan' },
{ value: 'yearly', label: 'Tahunan' },
]}
value={isData.repeatEventTyper}
onChange={(val: any) => { onValidation('repeatEventTyper', val) }}
error={
touched.repeatEventTyper && (
isData.repeatEventTyper == "" || String(isData.repeatEventTyper) == "null" ? "Ulangi Acara Tidak Boleh Kosong" : null
)
}
/>
<TextInput styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
type='number'
required
label="Jumlah pengulangan"
size="md"
placeholder='Jumlah pengulangan'
value={isData.repeatValue}
min={1}
disabled={(isData.repeatEventTyper == "once") ? true : false}
onChange={(event) => { onValidation('repeatValue', event.currentTarget.value) }}
error={
touched.repeatValue && (
isData.repeatValue == "" ? "Jumlah pengulangan tidak boleh kosong" :
Number(isData.repeatValue) <= 0 ? "Jumlah pengulangan tidak boleh di bawah 1" : ""
)
}
/>
<Textarea styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
value={isData.desc}
size="md" placeholder='Deskripsi' label="Deskripsi"
onChange={(event) => setData({ ...isData, desc: event.target.value })}
/>
<Box mt={5} onClick={() => setOpenMember(true)}>
<Group
justify="space-between"
p={10}
style={{
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
}}
>
<Text>Tambah Anggota</Text>
<IoIosArrowDropright size={25} />
</Group>
</Box>
{
member.length > 0 &&
<Box pt={30} mb={60}>
<Group justify="space-between">
<Text c={tema.get().utama}>Anggota Terpilih</Text>
<Text c={tema.get().utama}>Total {member.length} Anggota</Text>
</Group>
<Box pt={10}>
<Box mb={20}>
<Box
style={{
border: `1px solid ${"#C7D6E8"}`,
borderRadius: 10,
}}
px={20}
py={10}
>
{member.length == 0 ?
<Box style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '10vh' }}>
<Text c="dimmed" ta={"center"} fs={"italic"}>Tidak ada Anggota</Text>
</Box>
:
member.get().map((v: any, i: any) => {
return (
<Box key={i}>
<Grid align='center' mt={10}
>
<Grid.Col span={1}>
<Avatar src={`https://wibu-storage.wibudev.com/api/files/${v.img}`} alt="it's me" size={'lg'} />
</Grid.Col>
<Grid.Col span={8}>
<Text c={tema.get().utama} fw={"bold"} lineClamp={1} pl={isMobile2 ? 40 : 30} fz={isMobile ? 14 : 16} >
{v.name}
</Text>
</Grid.Col>
<Grid.Col span={3}>
<Text c={tema.get().utama} fw={"bold"} ta={'end'} fz={isMobile ? 13 : 16}>
Anggota
</Text>
</Grid.Col>
</Grid>
<Box mt={10}>
<Divider size={"xs"} />
</Box>
</Box>
);
})}
</Box>
</Box>
</Box>
</Box>
}
</Stack>
</Box>
<Box pos={'fixed'} bottom={0} p={rem(20)} w={"100%"} style={{
maxWidth: rem(550),
zIndex: 999,
backgroundColor: `${tema.get().bgUtama}`,
}}>
<Button
c={"white"}
bg={tema.get().utama}
size="lg"
radius={30}
fullWidth
onClick={() => { onCheck() }}
>
Simpan
</Button>
</Box>
<LayoutModal loading={loadingModal} opened={isModal} onClose={() => setModal(false)}
description="Apakah Anda yakin ingin menambahkan data?"
onYes={(val) => {
if (val) {
onSubmit(val)
} else {
setModal(false)
}
}} />
</Box> </Box>
); );
} }

View File

@@ -1,21 +1,22 @@
"use client" "use client"
import { LayoutNavbarNew, TEMA } from '@/module/_global'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import { Box, Button, Group, rem, Select, SimpleGrid, Skeleton, Stack, Text, Textarea, TextInput } from '@mantine/core';
import { DateInput, TimeInput } from '@mantine/dates';
import React, { useState } from 'react';
import { useParams, useRouter } from 'next/navigation';
import LayoutModal from '@/module/_global/layout/layout_modal'; import LayoutModal from '@/module/_global/layout/layout_modal';
import toast from 'react-hot-toast'; import { useHookstate } from '@hookstate/core';
import { funEditCalenderById, funGetOneCalender, funGetOneCalenderByIdCalendar, } from '../lib/api_calender'; import { Box, Button, Group, rem, Select, SimpleGrid, Skeleton, Stack, Textarea, TextInput } from '@mantine/core';
import { DateInput, TimeInput } from '@mantine/dates';
import { useShallowEffect } from '@mantine/hooks'; import { useShallowEffect } from '@mantine/hooks';
import { IDetailByIdCalender } from '../lib/type_calender';
import moment from 'moment'; import moment from 'moment';
import "moment/locale/id"; import "moment/locale/id";
import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react';
import toast from 'react-hot-toast';
import { funEditCalenderById, funGetOneCalenderByIdCalendar } from '../lib/api_calender';
import { IDetailByIdCalender } from '../lib/type_calender';
import UpdateListUsers from './update_list_users'; import UpdateListUsers from './update_list_users';
import { useHookstate } from '@hookstate/core';
export default function UpdateDivisionCalender() { export default function UpdateDivisionCalender() {
const [isModal, setModal] = useState(false) const [isModal, setModal] = useState(false)
const [loadingModal, setLoadingModal] = useState(false)
const param = useParams<{ id: string, detail: string }>() const param = useParams<{ id: string, detail: string }>()
const [isDataCalender, setDataCalender] = useState<IDetailByIdCalender>() const [isDataCalender, setDataCalender] = useState<IDetailByIdCalender>()
const [openMember, setOpenMember] = useState(false) const [openMember, setOpenMember] = useState(false)
@@ -54,35 +55,89 @@ export default function UpdateDivisionCalender() {
const [value, setValue] = useState<Date | null>(null); const [value, setValue] = useState<Date | null>(null);
const router = useRouter() const router = useRouter()
async function onSubmit(val: boolean) {
try {
if (val) {
const response = await funEditCalenderById(param.detail, {
title: isDataCalender?.title,
dateStart: isDataCalender?.dateStart,
timeStart: isDataCalender?.timeStart,
timeEnd: isDataCalender?.timeEnd,
linkMeet: isDataCalender?.linkMeet,
repeatEventTyper: isDataCalender?.repeatEventTyper,
desc: isDataCalender?.desc,
repeatValue: isDataCalender?.repeatValue
})
if (response.success) { function onCheck() {
setModal(false) if (Object.values(touched).some((v) => v == true))
router.push(`/division/${param.id}/calender`) return false
toast.success(response.message) setModal(true)
} else { }
toast.error(response.message)
} async function onSubmit() {
try {
setLoadingModal(true)
const response = await funEditCalenderById(param.detail, {
title: isDataCalender?.title,
dateStart: isDataCalender?.dateStart,
timeStart: isDataCalender?.timeStart,
timeEnd: isDataCalender?.timeEnd,
linkMeet: isDataCalender?.linkMeet,
repeatEventTyper: isDataCalender?.repeatEventTyper,
desc: isDataCalender?.desc,
repeatValue: isDataCalender?.repeatValue
})
if (response.success) {
router.push(`/division/${param.id}/calender`)
toast.success(response.message)
} else {
toast.error(response.message)
} }
setModal(false)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
toast.error("Terjadi kesalahan! Silahkan coba kembali"); toast.error("Terjadi kesalahan! Silahkan coba kembali");
setModal(false)
} finally { } finally {
setModal(false) setModal(false)
setLoadingModal(false)
}
}
function onValidation(kategori: string, val: any) {
if (kategori == 'title') {
setDataCalender({ ...isDataCalender, title: val })
if (val === "") {
setTouched({ ...touched, title: true })
} else {
setTouched({ ...touched, title: false })
}
} else if (kategori == 'dateStart') {
setValue(val)
setDataCalender({ ...isDataCalender, dateStart: moment(val).format("YYYY-MM-DD") })
if (val === "") {
setTouched({ ...touched, dateStart: true })
} else {
setTouched({ ...touched, dateStart: false })
}
} else if (kategori == 'timeStart') {
setDataCalender({ ...isDataCalender, timeStart: val })
if (val == "") {
setTouched({ ...touched, timeStart: true })
} else {
setTouched({ ...touched, timeStart: false })
}
} else if (kategori == 'timeEnd') {
setDataCalender({ ...isDataCalender, timeEnd: val })
if (val == "" || String(isDataCalender?.timeStart) > String(val)) {
setTouched({ ...touched, timeEnd: true })
} else {
setTouched({ ...touched, timeEnd: false })
}
} else if (kategori == 'repeatEventTyper') {
setDataCalender(isDataCalender => ({ ...isDataCalender, repeatEventTyper: val }))
if (val == "once") {
setDataCalender(isDataCalender => ({ ...isDataCalender, repeatValue: "1" }))
}
if (val == "" || String(val) == "null") {
setTouched({ ...touched, repeatEventTyper: true })
} else {
setTouched({ ...touched, repeatEventTyper: false })
}
} else if (kategori == 'repeatValue') {
setDataCalender(isDataCalender => ({ ...isDataCalender, repeatValue: val, }))
if (val === "" || Number(val) <= 0) {
setTouched(touched => ({ ...touched, repeatValue: true }))
} else {
setTouched({ ...touched, repeatValue: false })
}
} }
} }
@@ -117,16 +172,7 @@ export default function UpdateDivisionCalender() {
placeholder="Acara" placeholder="Acara"
label="Acara" label="Acara"
defaultValue={isDataCalender?.title} defaultValue={isDataCalender?.title}
onChange={ onChange={(event) => { onValidation('title', event.target.value) }}
(event) => {
setDataCalender({
...isDataCalender,
title: event.target.value
})
setTouched({ ...touched, title: false })
}
}
onBlur={() => setTouched({ ...touched, title: true })}
required required
error={ error={
touched.title && ( touched.title && (
@@ -145,20 +191,10 @@ export default function UpdateDivisionCalender() {
value={ value={
(isDataCalender?.dateStart == '' || isDataCalender?.dateStart == null) ? null : new Date(isDataCalender.dateStart) (isDataCalender?.dateStart == '' || isDataCalender?.dateStart == null) ? null : new Date(isDataCalender.dateStart)
} }
onChange={ onChange={(val) => { onValidation('dateStart', val) }}
(val) => {
setValue(val);
setDataCalender({
...isDataCalender,
dateStart: moment(val).format("YYYY-MM-DD")
})
setTouched({ ...touched, dateStart: false })
}
}
placeholder="Input Tanggal" placeholder="Input Tanggal"
label="Tanggal" label="Tanggal"
minDate={new Date()} minDate={new Date()}
onBlur={() => setTouched({ ...touched, dateStart: true })}
error={ error={
touched.dateStart && ( touched.dateStart && (
isDataCalender?.dateStart == "" ? "Tanggal Tidak Boleh Kosong" : null isDataCalender?.dateStart == "" ? "Tanggal Tidak Boleh Kosong" : null
@@ -178,17 +214,8 @@ export default function UpdateDivisionCalender() {
}} }}
size="md" size="md"
label="Waktu Awal" label="Waktu Awal"
// value={isDataCalender?.timeStart}
defaultValue={isDataCalender?.timeStart} defaultValue={isDataCalender?.timeStart}
onChange={ onChange={(event) => { onValidation('timeStart', event.target.value) }}
(event) => {
setDataCalender({
...isDataCalender,
timeStart: event.target.value
})
}
}
onBlur={() => setTouched({ ...touched, timeStart: true })}
error={touched.timeStart && !isDataCalender?.timeStart ? "Waktu Awal Tidak Boleh Kosong" : null} error={touched.timeStart && !isDataCalender?.timeStart ? "Waktu Awal Tidak Boleh Kosong" : null}
required required
/> />
@@ -201,17 +228,8 @@ export default function UpdateDivisionCalender() {
}} }}
size="md" size="md"
label="Waktu Akhir" label="Waktu Akhir"
// value={isDataCalender?.timeEnd}
defaultValue={isDataCalender?.timeEnd} defaultValue={isDataCalender?.timeEnd}
onChange={ onChange={(event) => { onValidation('timeEnd', event.target.value) }}
(event) => {
setDataCalender({
...isDataCalender,
timeEnd: event.target.value
})
}
}
onBlur={() => setTouched({ ...touched, timeEnd: true })}
required required
error={ error={
touched.timeEnd && ( touched.timeEnd && (
@@ -232,14 +250,7 @@ export default function UpdateDivisionCalender() {
placeholder="Link Meet" placeholder="Link Meet"
label="Link Meet" label="Link Meet"
defaultValue={isDataCalender?.linkMeet} defaultValue={isDataCalender?.linkMeet}
onChange={ onChange={(event) => { setDataCalender({ ...isDataCalender, linkMeet: event.target.value }) }}
(event) => {
setDataCalender({
...isDataCalender,
linkMeet: event.target.value
})
}
}
/> />
<Select <Select
styles={{ styles={{
@@ -260,76 +271,36 @@ export default function UpdateDivisionCalender() {
]} ]}
value={isDataCalender?.repeatEventTyper} value={isDataCalender?.repeatEventTyper}
defaultValue={isDataCalender?.repeatEventTyper} defaultValue={isDataCalender?.repeatEventTyper}
onChange={ onChange={(val: any) => { onValidation('repeatEventTyper', val) }}
(val: any) => {
setDataCalender({
...isDataCalender,
repeatEventTyper: val
})
setTouched({ ...touched, repeatEventTyper: false })
}
}
onBlur={() => setTouched({ ...touched, repeatEventTyper: true })}
error={ error={
touched.repeatEventTyper && ( touched.repeatEventTyper && (
isDataCalender?.repeatEventTyper == "" ? "Ulangi Acara Tidak Boleh Kosong" : null isDataCalender?.repeatEventTyper == "" || String(isDataCalender?.repeatEventTyper) == "null" ? "Ulangi Acara Tidak Boleh Kosong" : null
) )
} }
required required
/> />
{isDataCalender?.repeatEventTyper == "once" ? <TextInput styles={{
<TextInput styles={{ input: {
input: { border: `1px solid ${"#D6D8F6"}`,
border: `1px solid ${"#D6D8F6"}`, borderRadius: 10,
borderRadius: 10, },
}, }}
}} type='number'
type='number' required
required label="Jumlah pengulangan"
label="Jumlah pengulangan" size="md"
size="md" min={1}
disabled disabled={(isDataCalender?.repeatEventTyper == "once") ? true : false}
placeholder='Jumlah pengulangan' placeholder='Jumlah pengulangan'
defaultValue={"1"} defaultValue={isDataCalender?.repeatValue}
onChange={(event) => { onChange={(event) => { onValidation('repeatValue', event.currentTarget.value) }}
setDataCalender({ ...isDataCalender, repeatValue: String(event.currentTarget.value) }) error={
setTouched({ ...touched, repeatValue: false }) touched.repeatValue && (
}} isDataCalender?.repeatValue == "" ? "Jumlah pengulangan tidak boleh kosong" :
onBlur={() => setTouched({ ...touched, repeatValue: true })} Number(isDataCalender?.repeatValue) <= 0 ? "Jumlah pengulangan tidak boleh di bawah 1" : ""
error={ )
touched.repeatValue && ( }
isDataCalender?.repeatValue == "" ? "Jumlah pengulangan tidak boleh kosong" : null />
// || Number(isDataCalender?.repeatValue) <= 0 ? "Jumlah pengulangan tidak boleh dibawah 1" : null
)
}
/>
:
<TextInput styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
type='number'
required
label="Jumlah pengulangan"
size="md"
min={1}
placeholder='Jumlah pengulangan'
defaultValue={isDataCalender?.repeatValue}
onChange={(event) => {
setDataCalender({ ...isDataCalender, repeatValue: String(event.currentTarget.value) })
setTouched({ ...touched, repeatValue: false })
}}
onBlur={() => setTouched({ ...touched, repeatValue: true })}
error={
touched.repeatValue && (
isDataCalender?.repeatValue == "" ? "Jumlah pengulangan tidak boleh kosong" :
Number(isDataCalender?.repeatValue) <= 0 ? "Jumlah pengulangan tidak boleh di bawah 1" : ""
)
}
/>
}
<Textarea styles={{ <Textarea styles={{
input: { input: {
border: `1px solid ${"#D6D8F6"}`, border: `1px solid ${"#D6D8F6"}`,
@@ -365,15 +336,21 @@ export default function UpdateDivisionCalender() {
size="lg" size="lg"
radius={30} radius={30}
fullWidth fullWidth
onClick={() => setModal(true)} onClick={() => onCheck()}
> >
Simpan Simpan
</Button> </Button>
} }
</Box> </Box>
<LayoutModal opened={isModal} onClose={() => setModal(false)} <LayoutModal loading={loadingModal} opened={isModal} onClose={() => setModal(false)}
description="Apakah Anda yakin ingin mengubah data acara ini? Data ini akan mempengaruhi semua data yang terkait" description="Apakah Anda yakin ingin mengubah data acara ini? Data ini akan mempengaruhi semua data yang terkait"
onYes={(val) => { onSubmit(val) }} /> onYes={(val) => {
if (val) {
onSubmit()
} else {
setModal(false)
}
}} />
</Box> </Box>
); );
} }

View File

@@ -1,13 +1,12 @@
"use client" "use client"
import { LayoutNavbarNew, TEMA } from '@/module/_global'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import { useHookstate } from '@hookstate/core';
import { Badge, Box, Button, Center, ColorInput, Flex, Pill, rem, SimpleGrid, Stack, Text, TextInput } from '@mantine/core';
import React, { useState } from 'react';
import { funCreateTheme } from '../lib/api_theme';
import toast from 'react-hot-toast';
import { useRouter } from 'next/navigation';
import LayoutModal from '@/module/_global/layout/layout_modal'; import LayoutModal from '@/module/_global/layout/layout_modal';
import _ from 'lodash'; import { useHookstate } from '@hookstate/core';
import { Box, Button, Center, ColorInput, Flex, Pill, rem, SimpleGrid, Stack, TextInput } from '@mantine/core';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import toast from 'react-hot-toast';
import { funCreateTheme } from '../lib/api_theme';
export default function CreatePaletteColor() { export default function CreatePaletteColor() {
const [isValModal, setValModal] = useState(false); const [isValModal, setValModal] = useState(false);
@@ -56,11 +55,46 @@ export default function CreatePaletteColor() {
} }
function onCheck() { function onCheck() {
if (Object.values(touched).some((v) => v == true)) const cek = checkAll()
if (!cek)
return false return false
setValModal(true) setValModal(true)
} }
function checkAll() {
let nilai = true
if (isWarna.name === "") {
setTouched(touched => ({ ...touched, name: true }))
nilai = false
}
if (isWarna.utama === "" || isWarna.utama.substring(0, 1) !== '#') {
setTouched(touched => ({ ...touched, utama: true }))
nilai = false
}
if (isWarna.bgUtama === "" || isWarna.bgUtama.substring(0, 1) !== '#') {
setTouched(touched => ({ ...touched, bgUtama: true }))
nilai = false
}
if (isWarna.bgIcon === "" || isWarna.bgIcon.substring(0, 1) !== '#') {
setTouched(touched => ({ ...touched, bgIcon: true }))
nilai = false
}
if (isWarna.bgFiturHome === "" || isWarna.bgFiturHome.substring(0, 1) !== '#') {
setTouched(touched => ({ ...touched, bgFiturHome: true }))
nilai = false
}
if (isWarna.bgFiturDivision === "" || isWarna.bgFiturDivision.substring(0, 1) !== '#') {
setTouched(touched => ({ ...touched, bgFiturDivision: true }))
nilai = false
}
if (isWarna.bgTotalKegiatan === "" || isWarna.bgTotalKegiatan.substring(0, 1) !== '#') {
setTouched(touched => ({ ...touched, bgTotalKegiatan: true }))
nilai = false
}
return nilai
}
function onValidation(kategori: string, val: string) { function onValidation(kategori: string, val: string) {
if (kategori == 'name') { if (kategori == 'name') {
setWarna({ ...isWarna, name: val }) setWarna({ ...isWarna, name: val })
@@ -239,8 +273,8 @@ export default function CreatePaletteColor() {
} }
error={ error={
touched.bgTotalKegiatan && ( touched.bgTotalKegiatan && (
isWarna.bgTotalKegiatan == "" ? "Background Total Kegiatan Tidak Boleh Kosong" : isWarna.bgTotalKegiatan == "" ? "Background Total Kegiatan Tidak Boleh Kosong" :
isWarna.bgTotalKegiatan.substring(0, 1) != "#" ? "Kode Warna Tidak Valid" : null isWarna.bgTotalKegiatan.substring(0, 1) != "#" ? "Kode Warna Tidak Valid" : null
) )
} }
/> />

View File

@@ -1,14 +1,14 @@
"use client" "use client"
import { LayoutNavbarNew, TEMA } from '@/module/_global'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import LayoutModal from "@/module/_global/layout/layout_modal";
import { useHookstate } from '@hookstate/core'; import { useHookstate } from '@hookstate/core';
import { Badge, Box, Button, Center, ColorInput, Flex, Pill, rem, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core'; import { Box, Button, Center, ColorInput, Flex, Pill, rem, SimpleGrid, Skeleton, Stack, TextInput } from '@mantine/core';
import React, { useState } from 'react'; import { useShallowEffect } from '@mantine/hooks';
import { IEditTheme } from '../lib/type_theme'; import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { funEditTheme, funGetThemeById } from '../lib/api_theme'; import { funEditTheme, funGetThemeById } from '../lib/api_theme';
import { useParams, useRouter } from 'next/navigation'; import { IEditTheme } from '../lib/type_theme';
import { useShallowEffect } from '@mantine/hooks';
import LayoutModal from "@/module/_global/layout/layout_modal";
export default function EditPaletteColor() { export default function EditPaletteColor() {
const tema = useHookstate(TEMA) const tema = useHookstate(TEMA)
@@ -16,6 +16,7 @@ export default function EditPaletteColor() {
const [isModal, setModal] = useState(false) const [isModal, setModal] = useState(false)
const param = useParams<{ id: string }>() const param = useParams<{ id: string }>()
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [loadingKonfirmasi, setLoadingKonfirmasi] = useState(false);
const [touched, setTouched] = useState({ const [touched, setTouched] = useState({
name: false, name: false,
utama: false, utama: false,
@@ -62,6 +63,7 @@ export default function EditPaletteColor() {
async function onSubmit() { async function onSubmit() {
try { try {
setLoadingKonfirmasi(true)
const res = await funEditTheme(param.id, isWarna) const res = await funEditTheme(param.id, isWarna)
if (res.success) { if (res.success) {
toast.success(res.message); toast.success(res.message);
@@ -72,6 +74,9 @@ export default function EditPaletteColor() {
} catch (error) { } catch (error) {
console.error(error) console.error(error)
toast.error("Gagal mengedit tema, coba lagi nanti"); toast.error("Gagal mengedit tema, coba lagi nanti");
} finally {
setLoadingKonfirmasi(false)
setModal(false)
} }
} }
@@ -381,11 +386,13 @@ export default function EditPaletteColor() {
</Box> </Box>
<LayoutModal opened={isModal} onClose={() => setModal(false)} description="Apakah Anda yakin ingin mengubah data?" <LayoutModal loading={loadingKonfirmasi} opened={isModal} onClose={() => setModal(false)} description="Apakah Anda yakin ingin mengubah data?"
onYes={(val) => { onYes={(val) => {
if (val) if (val) {
onSubmit() onSubmit()
setModal(false) } else {
setModal(false)
}
} }
} /> } />
</Box> </Box>

View File

@@ -13,6 +13,7 @@ import { funCreateDiscussion } from "../lib/api_discussion";
export default function FormCreateDiscussion({ id }: { id: string }) { export default function FormCreateDiscussion({ id }: { id: string }) {
const [isValModal, setValModal] = useState(false) const [isValModal, setValModal] = useState(false)
const [loadingModal, setLoadingModal] = useState(false)
const router = useRouter() const router = useRouter()
const [isImg, setImg] = useState("") const [isImg, setImg] = useState("")
const param = useParams<{ id: string, detail: string }>() const param = useParams<{ id: string, detail: string }>()
@@ -50,26 +51,25 @@ export default function FormCreateDiscussion({ id }: { id: string }) {
async function createDiscussion(val: boolean) { async function createDiscussion(val: boolean) {
try { try {
if (val) { setLoadingModal(true)
const response = await funCreateDiscussion({ const response = await funCreateDiscussion({
desc: isData.desc, desc: isData.desc,
idDivision: id idDivision: id
}) })
if (response.success) { if (response.success) {
setDataRealtime(response.notif) setDataRealtime(response.notif)
toast.success(response.message) toast.success(response.message)
router.push(`/division/${param.id}/discussion/`) router.push(`/division/${param.id}/discussion/`)
setValModal(false) } else {
} else { toast.error(response.message)
toast.error(response.message)
}
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
toast.error("Gagal menambahkan diskusi, coba lagi nanti"); toast.error("Gagal menambahkan diskusi, coba lagi nanti");
} finally { } finally {
setValModal(false) setValModal(false)
setLoadingModal(false)
} }
} }
@@ -94,12 +94,12 @@ export default function FormCreateDiscussion({ id }: { id: string }) {
}} }}
value={isData.desc} value={isData.desc}
onChange={(e) => setData({ ...isData, desc: e.target.value })} onChange={(e) => setData({ ...isData, desc: e.target.value })}
onBlur={() => setTouched({ ...touched, desc: true })} // onBlur={() => setTouched({ ...touched, desc: true })}
error={ // error={
touched.desc && ( // touched.desc && (
isData.desc == "" ? "Form Tidak Boleh Kosong" : null // isData.desc == "" ? "Form Tidak Boleh Kosong" : null
) // )
} // }
/> />
</Box> </Box>
</Grid.Col> </Grid.Col>
@@ -130,9 +130,11 @@ export default function FormCreateDiscussion({ id }: { id: string }) {
</Button> </Button>
</Box> </Box>
<LayoutModal opened={isValModal} onClose={() => setValModal(false)} <LayoutModal loading={loadingModal} opened={isValModal} onClose={() => setValModal(false)}
description="Apakah Anda yakin ingin menambah data?" description="Apakah Anda yakin ingin menambah data?"
onYes={(val) => { createDiscussion(val) }} /> onYes={(val) => {
createDiscussion(val)
}} />
</Box> </Box>
) )
} }

View File

@@ -12,6 +12,7 @@ import { useHookstate } from "@hookstate/core"
export default function FormEditDiscussion() { export default function FormEditDiscussion() {
const [isValModal, setValModal] = useState(false) const [isValModal, setValModal] = useState(false)
const [loadingModal, setLoadingModal] = useState(false)
const router = useRouter() const router = useRouter()
const param = useParams<{ id: string, detail: string }>() const param = useParams<{ id: string, detail: string }>()
const [isDataOne, setDataOne] = useState("") const [isDataOne, setDataOne] = useState("")
@@ -35,43 +36,43 @@ export default function FormEditDiscussion() {
} }
} }
async function fetchEditDiscussion(val: boolean) { async function fetchEditDiscussion() {
try { try {
if (val) { setLoadingModal(true)
const response = await funEditDiscussion(param.detail, { const response = await funEditDiscussion(param.detail, {
desc: isDataOne desc: isDataOne
}) })
if (response.success) { if (response.success) {
toast.success(response.message) toast.success(response.message)
setValModal(false) setValModal(false)
router.push(`/division/${param.id}/discussion/${param.detail}`) router.push(`/division/${param.id}/discussion/${param.detail}`)
} else { } else {
toast.error(response.message) toast.error(response.message)
}
} }
setValModal(false)
} catch (error) { } catch (error) {
console.error(error); console.error(error);
setValModal(false) setValModal(false)
toast.error("Gagal menambahkan diskusi, coba lagi nanti"); toast.error("Gagal menambahkan diskusi, coba lagi nanti");
} finally { } finally {
setValModal(false) setValModal(false)
setLoadingModal(false)
} }
} }
async function getData() { async function getData() {
try { try {
setLoading(true) setLoading(true)
const res = await funGetProfileByCookies() const res = await funGetProfileByCookies()
setIMG(`https://wibu-storage.wibudev.com/api/files/${res.data.img}`) setIMG(`https://wibu-storage.wibudev.com/api/files/${res.data.img}`)
setLoading(false) setLoading(false)
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} finally { } finally {
setLoading(false) setLoading(false)
} }
} }
useShallowEffect(() => { useShallowEffect(() => {
fetchGetOneDiscussion() fetchGetOneDiscussion()
getData() getData()
@@ -84,43 +85,43 @@ export default function FormEditDiscussion() {
<Box p={20}> <Box p={20}>
<Grid gutter={0} pt={10}> <Grid gutter={0} pt={10}>
<Grid.Col span={2}> <Grid.Col span={2}>
{loading ? {loading ?
<Skeleton height={60} width={60} radius={100} /> <Skeleton height={60} width={60} radius={100} />
: :
<Avatar src={img} alt="it's me" size="lg" /> <Avatar src={img} alt="it's me" size="lg" />
} }
</Grid.Col> </Grid.Col>
<Grid.Col span={10}> <Grid.Col span={10}>
{loading ? {loading ?
Array(10) Array(10)
.fill(null) .fill(null)
.map((_, i) => ( .map((_, i) => (
<Box key={i} mb={20}> <Box key={i} mb={20}>
<Skeleton height={20} radius={10} /> <Skeleton height={20} radius={10} />
</Box> </Box>
)) ))
: :
<Box> <Box>
<Textarea <Textarea
placeholder="Tuliskan apa yang ingin anda diskusikan" placeholder="Tuliskan apa yang ingin anda diskusikan"
styles={{ styles={{
input: { input: {
border: 'none', border: 'none',
backgroundColor: 'transparent', backgroundColor: 'transparent',
height: "50vh" height: "50vh"
} }
}} }}
value={isDataOne} value={isDataOne}
onChange={(e) => setDataOne(e.target.value)} onChange={(e) => setDataOne(e.target.value)}
onBlur={() => setTouched({ ...touched, desc: true })} // onBlur={() => setTouched({ ...touched, desc: true })}
error={ // error={
touched.desc && ( // touched.desc && (
isDataOne == "" ? "Form Tidak Boleh Kosong" : null // isDataOne == "" ? "Form Tidak Boleh Kosong" : null
) // )
} // }
/> />
</Box> </Box>
} }
</Grid.Col> </Grid.Col>
</Grid> </Grid>
</Box> </Box>
@@ -153,9 +154,15 @@ export default function FormEditDiscussion() {
} }
</Box> </Box>
<LayoutModal opened={isValModal} onClose={() => setValModal(false)} <LayoutModal loading={loadingModal} opened={isValModal} onClose={() => setValModal(false)}
description="Apakah Anda yakin ingin mengubah data?" description="Apakah Anda yakin ingin mengubah data?"
onYes={(val) => { fetchEditDiscussion(val) }} /> onYes={(val) => {
if (val) {
fetchEditDiscussion()
} else {
setValModal(false)
}
}} />
</Box> </Box>
) )
} }

View File

@@ -1,29 +1,15 @@
"use client"; "use client";
import { LayoutNavbarNew, TEMA } from "@/module/_global"; import { LayoutNavbarNew, TEMA } from "@/module/_global";
import { useHookstate } from "@hookstate/core";
import {
Avatar,
Box,
Button,
Divider,
Flex,
Grid,
Group,
rem,
Select,
Stack,
Text,
Textarea,
TextInput,
} from "@mantine/core";
import { useMediaQuery, useShallowEffect } from "@mantine/hooks";
import { useRouter } from "next/navigation";
import React, { useState } from "react";
import { IoIosArrowDropright } from "react-icons/io";
import { globalMemberDivision } from "../lib/val_division";
import toast from "react-hot-toast";
import { funGetUserByCookies } from "@/module/auth"; import { funGetUserByCookies } from "@/module/auth";
import { funGetAllGroup, IDataGroup } from "@/module/group"; import { funGetAllGroup, IDataGroup } from "@/module/group";
import { useHookstate } from "@hookstate/core";
import { Avatar, Box, Button, Divider, Grid, Group, rem, Select, Stack, Text, Textarea, TextInput } from "@mantine/core";
import { useMediaQuery, useShallowEffect } from "@mantine/hooks";
import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";
import { IoIosArrowDropright } from "react-icons/io";
import { globalMemberDivision } from "../lib/val_division";
import NavbarAdminDivision from "./navbar_admin_division"; import NavbarAdminDivision from "./navbar_admin_division";
import NavbarCreateUsers from "./navbar_create_users"; import NavbarCreateUsers from "./navbar_create_users";
@@ -58,23 +44,14 @@ export default function CreateDivision() {
setRoleUser(loadUser.idUserRole) setRoleUser(loadUser.idUserRole)
} }
function onSubmit() { function onCheck() {
if (roleUser == "supadmin" && (body.idGroup == "" || body.idGroup == null)) { const cek = checkAll()
return toast.error("Error! grup harus diisi") if (!cek)
} return false
if (member.length == 0)
if (body.name == "") {
return toast.error("Error! nama divisi harus diisi")
}
if (member.length == 0) {
return toast.error("Error! belum ada anggota yang terdaftar") return toast.error("Error! belum ada anggota yang terdaftar")
}
setChooseAdmin(true) setChooseAdmin(true)
} }
function onToChooseAnggota() { function onToChooseAnggota() {
@@ -86,7 +63,7 @@ export default function CreateDivision() {
function onChooseGroup(val: any) { function onChooseGroup(val: any) {
member.set([]) member.set([])
setBody({ ...body, idGroup: val }) onValidation('idGroup', val)
} }
@@ -95,6 +72,39 @@ export default function CreateDivision() {
loadData(); loadData();
}, []); }, []);
function onValidation(kategori: string, val: any) {
if (kategori == 'name') {
setBody({ ...body, name: val })
if (val === "") {
setTouched({ ...touched, name: true })
} else {
setTouched({ ...touched, name: false })
}
} else if (kategori == 'idGroup') {
setBody({ ...body, idGroup: val, })
if (val === "" || String(val) == "null") {
setTouched(touched => ({ ...touched, idGroup: true }))
} else {
setTouched({ ...touched, idGroup: false })
}
} else if (kategori == 'desc') {
setBody({ ...body, desc: val })
}
}
function checkAll() {
let nilai = true
if (roleUser == "supadmin" && (body.idGroup === "" || String(body.idGroup) == "null")) {
setTouched(touched => ({ ...touched, idGroup: true }))
nilai = false
}
if (body.name === "") {
setTouched(touched => ({ ...touched, name: true }))
nilai = false
}
return nilai
}
if (isChooseAdmin) return <NavbarAdminDivision data={body} onSuccess={(val) => { if (isChooseAdmin) return <NavbarAdminDivision data={body} onSuccess={(val) => {
@@ -133,10 +143,9 @@ export default function CreateDivision() {
onChange={(val) => { onChange={(val) => {
onChooseGroup(val) onChooseGroup(val)
}} }}
onBlur={() => setTouched({ ...touched, idGroup: true })}
error={ error={
touched.idGroup && ( touched.idGroup && (
body.idGroup == "" ? "Grup Tidak Boleh Kosong" : null body.idGroup == "" || String(body.idGroup) == "null" ? "Grup Tidak Boleh Kosong" : null
) )
} }
value={body.idGroup} value={body.idGroup}
@@ -150,11 +159,10 @@ export default function CreateDivision() {
required required
radius={10} radius={10}
value={body.name} value={body.name}
onChange={(val) => { setBody({ ...body, name: val.target.value }) }} onChange={(val) => { onValidation('name', val.target.value) }}
onBlur={() => setTouched({ ...touched, name: true })}
error={ error={
touched.name && ( touched.name && (
body.name == "" ? "Nama Tidak Boleh Kosong" : null body.name == "" ? "Nama Divisi Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -230,16 +238,7 @@ export default function CreateDivision() {
zIndex: 999, zIndex: 999,
backgroundColor: `${tema.get().bgUtama}`, backgroundColor: `${tema.get().bgUtama}`,
}}> }}>
<Button <Button color="white" bg={tema.get().utama} size="lg" radius={30} fullWidth onClick={() => { onCheck() }} >
color="white"
bg={tema.get().utama}
size="lg"
radius={30}
fullWidth
onClick={() => {
onSubmit()
}}
>
Simpan Simpan
</Button> </Button>
</Box> </Box>

View File

@@ -1,25 +1,22 @@
"use client" "use client"
import { LayoutNavbarNew, TEMA } from '@/module/_global'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import LayoutModal from '@/module/_global/layout/layout_modal'; import LayoutModal from '@/module/_global/layout/layout_modal';
import { Box, Button, rem, Select, Skeleton, Stack, Textarea, TextInput } from '@mantine/core'; import { useHookstate } from '@hookstate/core';
import { Box, Button, rem, Skeleton, Stack, Textarea, TextInput } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks'; import { useShallowEffect } from '@mantine/hooks';
import { useParams, useRouter } from 'next/navigation'; import { useParams, useRouter } from 'next/navigation';
import React, { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { funEditDivision, funGetDivisionById } from '../lib/api_division'; import { funEditDivision, funGetDivisionById } from '../lib/api_division';
import { funGetAllGroup, IDataGroup } from '@/module/group';
import { funGetUserByCookies } from '@/module/auth';
import { useHookstate } from '@hookstate/core';
export default function EditDivision() { export default function EditDivision() {
const [openModal, setOpenModal] = useState(false) const [openModal, setOpenModal] = useState(false)
const router = useRouter() const router = useRouter()
const param = useParams<{ id: string }>() const param = useParams<{ id: string }>()
const tema = useHookstate(TEMA) const tema = useHookstate(TEMA)
const [loadingModal, setLoadingModal] = useState(false)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [body, setBody] = useState<any>({ const [body, setBody] = useState<any>({
idGroup: "",
name: "", name: "",
desc: "", desc: "",
}); });
@@ -28,6 +25,36 @@ export default function EditDivision() {
name: false, name: false,
}); });
function onValidation(kategori: string, val: any) {
if (kategori == 'name') {
setBody({ ...body, name: val })
if (val === "") {
setTouched({ ...touched, name: true })
} else {
setTouched({ ...touched, name: false })
}
} else if (kategori == "desc") {
setBody({ ...body, desc: val })
}
}
function onCheck() {
const cek = checkAll()
if (!cek)
return false
setOpenModal(true)
}
function checkAll() {
let nilai = true
if (body.name === "") {
setTouched(touched => ({ ...touched, name: true }))
nilai = false
}
return nilai
}
async function getOneData() { async function getOneData() {
try { try {
@@ -56,17 +83,19 @@ export default function EditDivision() {
async function onUpdate() { async function onUpdate() {
try { try {
setLoadingModal(true)
const res = await funEditDivision(param.id, body) const res = await funEditDivision(param.id, body)
if (res.success) { if (res.success) {
toast.success(res.message) toast.success(res.message)
} else { } else {
toast.error(res.message) toast.error(res.message)
} }
setOpenModal(false)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
setOpenModal(false)
toast.error("Gagal mengedit divisi, coba lagi nanti"); toast.error("Gagal mengedit divisi, coba lagi nanti");
} finally {
setLoadingModal(false)
setOpenModal(false)
} }
} }
@@ -88,26 +117,22 @@ export default function EditDivision() {
: :
<> <>
<TextInput <TextInput
placeholder="Judul" placeholder="Nama Divisi"
label="Judul" label="Nama Divisi"
size="md" size="md"
required required
radius={40} radius={10}
value={body.name} value={body.name}
onChange={(e) => { onChange={(e) => { onValidation('name', e.currentTarget.value) }}
setBody({ ...body, name: e.target.value })
setTouched({ ...touched, name: false })
}}
onBlur={() => setTouched({ ...touched, name: true })}
error={ error={
touched.name && ( touched.name && (
body.name == "" ? "Judul Tidak Boleh Kosong" : null body.name == "" ? "Nama Divisi Tidak Boleh Kosong" : null
) )
} }
/> />
<Textarea placeholder="Deskripsi" label="Deskripsi" size="md" radius={10} <Textarea placeholder="Deskripsi" label="Deskripsi" size="md" radius={10}
value={body.desc} value={body.desc}
onChange={(e) => { setBody({ ...body, desc: e.currentTarget.value }) }} onChange={(e) => { onValidation('desc', e.currentTarget.value) }}
styles={{ styles={{
input: { input: {
height: "40vh" height: "40vh"
@@ -132,21 +157,13 @@ export default function EditDivision() {
size="lg" size="lg"
radius={30} radius={30}
fullWidth fullWidth
onClick={() => { onClick={() => { onCheck() }}
if (
body.name !== ""
) {
setOpenModal(true)
} else {
toast.error("Judul Tidak Boleh Kosong")
}
}}
> >
Simpan Simpan
</Button> </Button>
} }
</Box> </Box>
<LayoutModal opened={openModal} onClose={() => setOpenModal(false)} description='Apakah Anda yakin ingin edit data' <LayoutModal loading={loadingModal} opened={openModal} onClose={() => setOpenModal(false)} description='Apakah Anda yakin ingin edit data'
onYes={(val) => { onYes={(val) => {
if (val) { if (val) {
onUpdate() onUpdate()

View File

@@ -135,9 +135,9 @@ export default function InformationDivision() {
</Stack> </Stack>
)) ))
: :
(deskripsi != null && deskripsi != undefined) ? (deskripsi != null && deskripsi != undefined && deskripsi != "") ?
<Text ta={"justify"}>{deskripsi}</Text> <Text ta={"justify"}>{deskripsi}</Text>
: <></> : <Text ta={"center"} c={"dimmed"} fs={"italic"}>Tidak ada deskripsi</Text>
} }
</Box> </Box>
</Box> </Box>
@@ -195,12 +195,12 @@ export default function InformationDivision() {
}} }}
> >
<Grid.Col span={1}> <Grid.Col span={1}>
<Avatar src={`https://wibu-storage.wibudev.com/api/files/${v.img}`} alt="it's me" size={'lg'} /> <Avatar src={`https://wibu-storage.wibudev.com/api/files/${v.img}`} alt="it's me" size={'lg'} />
</Grid.Col> </Grid.Col>
<Grid.Col span={8}> <Grid.Col span={8}>
<Text c={tema.get().utama} fw={"bold"} truncate="end" pl={isMobile2 ? 40 : 30} fz={isMobile ? 14 : 16}> <Text c={tema.get().utama} fw={"bold"} truncate="end" pl={isMobile2 ? 40 : 30} fz={isMobile ? 14 : 16}>
{v.name} {v.name}
</Text> </Text>
</Grid.Col> </Grid.Col>
<Grid.Col span={3}> <Grid.Col span={3}>
<Text c={tema.get().utama} fw={"bold"} ta={'end'} fz={isMobile ? 13 : 16}> <Text c={tema.get().utama} fw={"bold"} ta={'end'} fz={isMobile ? 13 : 16}>

View File

@@ -45,8 +45,10 @@ export default function DrawerGroup({ onSuccess, }: { onSuccess: (val: boolean)
} }
function onCheck() { function onCheck() {
if (Object.values(touched).some((v) => v == true)) const cek = checkAll()
if (!cek) {
return false return false
}
createData() createData()
} }
@@ -58,7 +60,15 @@ export default function DrawerGroup({ onSuccess, }: { onSuccess: (val: boolean)
} else { } else {
setTouched({ ...touched, name: false }) setTouched({ ...touched, name: false })
} }
} }
}
function checkAll() {
if (namaGroup == "" || namaGroup.length < 3) {
setTouched({ ...touched, name: true })
return false
}
return true
} }
return ( return (
@@ -102,7 +112,7 @@ export default function DrawerGroup({ onSuccess, }: { onSuccess: (val: boolean)
}} }}
error={ error={
touched.name && touched.name &&
(namaGroup == "" ? "Error! harus memasukkan grup" : (namaGroup == "" ? "Grup Tidak Boleh Kosong" :
namaGroup.length < 3 ? "Masukkan Minimal 3 karakter" : "" namaGroup.length < 3 ? "Masukkan Minimal 3 karakter" : ""
) )
} }

View File

@@ -162,7 +162,7 @@ export default function EditDrawerGroup({ onUpdated, id, isActive, }: { onUpdate
}} }}
error={ error={
touched.name && touched.name &&
(name == "" ? "Error! harus memasukkan grup" : (name == "" ? "Grup Tidak Boleh Kosong" :
name.length < 3 ? "Masukkan Minimal 3 karakter" : "" name.length < 3 ? "Masukkan Minimal 3 karakter" : ""
) )
} }

View File

@@ -18,6 +18,7 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: {
const [isModal, setModal] = useState(false) const [isModal, setModal] = useState(false)
const refresh = useHookstate(globalRefreshPosition) const refresh = useHookstate(globalRefreshPosition)
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [loadingEdit, setLoadingEdit] = useState(false)
const tema = useHookstate(TEMA) const tema = useHookstate(TEMA)
const [data, setData] = useState<any>({ const [data, setData] = useState<any>({
id: id, id: id,
@@ -27,7 +28,6 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: {
const [listGroup, setListGorup] = useState<IDataPosition[]>([]) const [listGroup, setListGorup] = useState<IDataPosition[]>([])
const [touched, setTouched] = useState({ const [touched, setTouched] = useState({
name: false, name: false,
idGroup: false
}); });
function onCLose() { function onCLose() {
@@ -70,6 +70,7 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: {
async function onSubmit() { async function onSubmit() {
try { try {
setLoadingEdit(true)
const res = await funEditPosition(id, { const res = await funEditPosition(id, {
name: data.name, name: data.name,
idGroup: data.idGroup idGroup: data.idGroup
@@ -88,6 +89,8 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: {
} catch (error) { } catch (error) {
toast.error('Error'); toast.error('Error');
toast.error("Edit jabatan gagal, coba lagi nanti"); toast.error("Edit jabatan gagal, coba lagi nanti");
} finally {
setLoadingEdit(false)
} }
} }
@@ -98,20 +101,20 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: {
function onCheck() { function onCheck() {
if (Object.values(touched).some((v) => v == true)) if (Object.values(touched).some((v) => v == true))
return false return false
onSubmit() onSubmit()
} }
function onValidation(kategori: string, val: string) { function onValidation(kategori: string, val: string) {
if (kategori == 'name') { if (kategori == 'name') {
setData({...data, name: val}) setData({ ...data, name: val })
if (val == "" || val.length < 3) { if (val == "" || val.length < 3) {
setTouched({ ...touched, name: true }) setTouched({ ...touched, name: true })
} else { } else {
setTouched({ ...touched, name: false }) setTouched({ ...touched, name: false })
} }
} }
} }
async function nonActive(val: boolean) { async function nonActive(val: boolean) {
try { try {
@@ -189,13 +192,12 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: {
size="md" size="md"
value={String(data.name)} value={String(data.name)}
onChange={(e) => { onValidation('name', e.target.value) }} onChange={(e) => { onValidation('name', e.target.value) }}
onBlur={() => setTouched({ ...touched, name: true })}
error={ error={
touched.name && touched.name &&
(data.name == "" ? "Error! harus memasukkan Nama Jabatan" : (data.name == "" ? "Error! harus memasukkan Nama Jabatan" :
data.name.length < 3 ? "Masukkan Minimal 3 karakter" : "" data.name.length < 3 ? "Masukkan Minimal 3 karakter" : ""
) )
} }
radius={10} radius={10}
placeholder="Nama Jabatan" placeholder="Nama Jabatan"
/> />
@@ -208,7 +210,8 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: {
size="lg" size="lg"
radius={30} radius={30}
fullWidth fullWidth
onClick={onSubmit} onClick={() => { onCheck() }}
loading={loadingEdit}
> >
EDIT EDIT
</Button> </Button>

View File

@@ -15,6 +15,7 @@ import { globalRefreshPosition } from "../lib/val_posisition";
export default function DrawerListPosition({ onCreated }: { onCreated: (val: boolean) => void }) { export default function DrawerListPosition({ onCreated }: { onCreated: (val: boolean) => void }) {
const roleLogin = useHookstate(globalRole) const roleLogin = useHookstate(globalRole)
const [openDrawerGroup, setOpenDrawerGroup] = useState(false) const [openDrawerGroup, setOpenDrawerGroup] = useState(false)
const [loadingSave, setLoadingSave] = useState(false)
const router = useRouter() const router = useRouter()
const [listGroup, setListGorup] = useState<IDataGroup[]>([]) const [listGroup, setListGorup] = useState<IDataGroup[]>([])
const refresh = useHookstate(globalRefreshPosition) const refresh = useHookstate(globalRefreshPosition)
@@ -52,6 +53,7 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo
async function onSubmit() { async function onSubmit() {
try { try {
setLoadingSave(true)
const res = await funCreatePosition({ const res = await funCreatePosition({
name: listData.name, name: listData.name,
idGroup: listData.idGroup idGroup: listData.idGroup
@@ -70,23 +72,41 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo
} catch (error) { } catch (error) {
toast.error('Error') toast.error('Error')
} finally {
setLoadingSave(false)
} }
} }
function onCheck() { function onCheck() {
if (Object.values(touched).some((v) => v == true)) const check = checkAll()
return false if (!check)
return false
onSubmit() onSubmit()
} }
function checkAll() {
let nilai = true
if (listData.name == "" || listData.name.length < 3) {
setTouched(touched => ({ ...touched, name: true }))
nilai = false
}
if (roleLogin.get() == "supadmin" && listData.idGroup == "") {
setTouched(touched => ({ ...touched, idGroup: true }))
nilai = false
}
return nilai
}
function onValidation(kategori: string, val: string) { function onValidation(kategori: string, val: string) {
if (kategori == 'name') { if (kategori == 'name') {
setListData({...listData, name: val}) setListData({ ...listData, name: val })
if (val == "" || val.length < 3) { if (val == "" || val.length < 3) {
setTouched({ ...touched, name: true }) setTouched({ ...touched, name: true })
} else { } else {
setTouched({ ...touched, name: false }) setTouched({ ...touched, name: false })
} }
} else if (kategori == 'idGroup') { } else if (kategori == 'idGroup') {
setListData({ ...listData, idGroup: val }) setListData({ ...listData, idGroup: val })
if (val == "") { if (val == "") {
@@ -95,7 +115,7 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo
setTouched({ ...touched, idGroup: false }) setTouched({ ...touched, idGroup: false })
} }
} }
} }
return ( return (
<Box> <Box>
@@ -130,7 +150,7 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo
sm: "67vh", sm: "67vh",
lg: "67vh", lg: "67vh",
xl: "70vh" xl: "70vh"
}}> }}>
{ {
roleLogin.get() == "supadmin" && roleLogin.get() == "supadmin" &&
@@ -149,8 +169,7 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo
radius={10} radius={10}
mb={5} mb={5}
withAsterisk withAsterisk
onChange={(e: any) => onChange={(e: any) => { onValidation('idGroup', e) }
{ onValidation('idGroup', e) }
} }
styles={{ styles={{
input: { input: {
@@ -185,7 +204,7 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo
(listData.name == "" ? "Error! harus memasukkan Nama Jabatan" : (listData.name == "" ? "Error! harus memasukkan Nama Jabatan" :
listData.name.length < 3 ? "Masukkan Minimal 3 karakter" : "" listData.name.length < 3 ? "Masukkan Minimal 3 karakter" : ""
) )
} }
required required
/> />
<Box pos={"absolute"} bottom={10} left={0} right={0}> <Box pos={"absolute"} bottom={10} left={0} right={0}>
@@ -196,6 +215,7 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo
radius={30} radius={30}
fullWidth fullWidth
onClick={() => { onCheck() }} onClick={() => { onCheck() }}
loading={loadingSave}
> >
SIMPAN SIMPAN
</Button> </Button>

View File

@@ -24,7 +24,6 @@ import ResultsFile from "./results_file";
export default function CreateProject() { export default function CreateProject() {
const router = useRouter(); const router = useRouter();
const [openDrawer, setOpenDrawer] = useState(false)
const [openDrawerFile, setOpenDrawerFile] = useState(false) const [openDrawerFile, setOpenDrawerFile] = useState(false)
const [openDrawerTask, setOpenDrawerTask] = useState(false) const [openDrawerTask, setOpenDrawerTask] = useState(false)
const [isModal, setModal] = useState(false) const [isModal, setModal] = useState(false)
@@ -42,6 +41,7 @@ export default function CreateProject() {
const roleLogin = useHookstate(globalRole) const roleLogin = useHookstate(globalRole)
const isMobile = useMediaQuery('(max-width: 369px)'); const isMobile = useMediaQuery('(max-width: 369px)');
const tema = useHookstate(TEMA) const tema = useHookstate(TEMA)
const [loadingModal, setLoadingModal] = useState(false)
const [body, setBody] = useState<any>({ const [body, setBody] = useState<any>({
idGroup: "", idGroup: "",
@@ -50,13 +50,12 @@ export default function CreateProject() {
const [touched, setTouched] = useState({ const [touched, setTouched] = useState({
title: false, title: false,
idGroup: false, idGroup: false,
desc: false
}); });
const [data, setDataRealtime] = useWibuRealtime({ const [data, setDataRealtime] = useWibuRealtime({
WIBU_REALTIME_TOKEN: keyWibu, WIBU_REALTIME_TOKEN: keyWibu,
project: "sdm" project: "sdm"
}) })
function deleteFile(index: number) { function deleteFile(index: number) {
setListFile([...listFile.filter((val, i) => i !== index)]) setListFile([...listFile.filter((val, i) => i !== index)])
@@ -92,7 +91,7 @@ export default function CreateProject() {
function onChooseGroup(val: any) { function onChooseGroup(val: any) {
member.set([]) member.set([])
setBody({ ...body, idGroup: val }) onValidation('idGroup', val)
} }
useShallowEffect(() => { useShallowEffect(() => {
@@ -102,6 +101,7 @@ export default function CreateProject() {
async function onSubmit() { async function onSubmit() {
try { try {
setLoadingModal(true)
const fd = new FormData(); const fd = new FormData();
for (let i = 0; i < fileForm.length; i++) { for (let i = 0; i < fileForm.length; i++) {
fd.append(`file${i}`, fileForm[i]); fd.append(`file${i}`, fileForm[i]);
@@ -130,6 +130,54 @@ export default function CreateProject() {
} catch (error) { } catch (error) {
console.error(error) console.error(error)
toast.error("Gagal menambahkan kegiatan, coba lagi nanti"); toast.error("Gagal menambahkan kegiatan, coba lagi nanti");
} finally {
setLoadingModal(false)
setModal(false)
}
}
function onCheck() {
const cek = checkAll()
if (!cek)
return false
if (dataTask.length == 0)
return toast.error("Error! silahkan tambahkan tugas")
if (memberValue.length == 0)
return toast.error("Error! silahkan pilih anggota")
setModal(true)
}
function checkAll() {
let nilai = true
if (body.idGroup === "" || String(body.idGroup) == "null") {
setTouched(touched => ({ ...touched, idGroup: true }))
nilai = false
}
if (body.title === "") {
setTouched(touched => ({ ...touched, title: true }))
nilai = false
}
return nilai
}
function onValidation(kategori: string, val: string) {
if (kategori == 'idGroup') {
setBody({ ...body, idGroup: val })
if (val === "" || String(val) == "null") {
setTouched({ ...touched, idGroup: true })
} else {
setTouched({ ...touched, idGroup: false })
}
} else if (kategori == 'title') {
setBody({ ...body, title: val })
if (val === "") {
setTouched({ ...touched, title: true })
} else {
setTouched({ ...touched, title: false })
}
} }
} }
@@ -164,14 +212,12 @@ export default function CreateProject() {
}))} }))}
onChange={(val) => { onChange={(val) => {
onChooseGroup(val) onChooseGroup(val)
setTouched({ ...touched, idGroup: false })
}} }}
value={(body.idGroup == "") ? null : body.idGroup} value={(body.idGroup == "") ? null : body.idGroup}
onBlur={() => setTouched({ ...touched, idGroup: true })}
error={ error={
touched.idGroup && ( touched.idGroup && (
body.idGroup == "" ? "Grup Tidak Boleh Kosong" : null body.idGroup == "" || String(body.idGroup) == "null" ? "Grup Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -190,11 +236,7 @@ export default function CreateProject() {
placeholder="Nama Kegiatan" placeholder="Nama Kegiatan"
size="md" size="md"
value={body.title} value={body.title}
onChange={(e) => { onChange={(e) => { onValidation('title', e.target.value) }}
setBody({ ...body, title: e.target.value })
setTouched({ ...touched, title: false })
}}
onBlur={() => setTouched({ ...touched, title: true })}
error={ error={
touched.title && ( touched.title && (
body.title == "" ? "Kegiatan Tidak Boleh Kosong" : null body.title == "" ? "Kegiatan Tidak Boleh Kosong" : null
@@ -356,16 +398,7 @@ export default function CreateProject() {
size="lg" size="lg"
radius={30} radius={30}
fullWidth fullWidth
onClick={() => { onClick={() => { onCheck() }}>
if (
body.title !== "" &&
body.idGroup !== ""
) {
setModal(true)
} else {
toast.error("Mohon lengkapi data terlebih dahulu");
}
}}>
Simpan Simpan
</Button> </Button>
</Box> </Box>
@@ -494,13 +527,15 @@ export default function CreateProject() {
</LayoutDrawer> </LayoutDrawer>
<LayoutModal opened={isModal} onClose={() => setModal(false)} <LayoutModal loading={loadingModal} opened={isModal} onClose={() => setModal(false)}
description="Apakah Anda yakin ingin menambahkan data?" description="Apakah Anda yakin ingin menambahkan data?"
onYes={(val) => { onYes={(val) => {
if (val) { if (val) {
onSubmit() onSubmit()
} else {
setModal(false)
} }
setModal(false)
}} /> }} />
</Box > </Box >
); );

View File

@@ -1,13 +1,13 @@
"use client" "use client"
import { useParams, useRouter } from 'next/navigation'; import { LayoutNavbarNew, TEMA } from '@/module/_global';
import React, { useState } from 'react';
import toast from 'react-hot-toast';
import { funEditProject, funGetOneProjectById } from '../lib/api_project';
import { useShallowEffect } from '@mantine/hooks';
import { Box, Button, Input, rem, Skeleton, Stack, TextInput } from '@mantine/core';
import { LayoutNavbarNew, TEMA} from '@/module/_global';
import LayoutModal from '@/module/_global/layout/layout_modal'; import LayoutModal from '@/module/_global/layout/layout_modal';
import { useHookstate } from '@hookstate/core'; import { useHookstate } from '@hookstate/core';
import { Box, Button, rem, Skeleton, Stack, TextInput } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react';
import toast from 'react-hot-toast';
import { funEditProject, funGetOneProjectById } from '../lib/api_project';
export default function EditTaskProject() { export default function EditTaskProject() {
const router = useRouter() const router = useRouter()
@@ -20,13 +20,6 @@ export default function EditTaskProject() {
name: false, name: false,
}); });
function onVerification() {
if (name == "")
return toast.error("Error! harus memasukkan judul Kegiatan")
setOpenModal(true)
}
async function onSubmit() { async function onSubmit() {
try { try {
const res = await funEditProject(param.id, { name }) const res = await funEditProject(param.id, { name })
@@ -42,6 +35,27 @@ export default function EditTaskProject() {
} }
} }
function onCheck() {
if (name == "") {
setTouched({ ...touched, name: true })
return false
}
setOpenModal(true)
}
function onValidation(kategori: string, val: string) {
if (kategori == 'title') {
setName(val)
if (val === "") {
setTouched({ ...touched, name: true })
} else {
setTouched({ ...touched, name: false })
}
}
}
async function getOneData() { async function getOneData() {
try { try {
setLoading(true) setLoading(true)
@@ -69,32 +83,28 @@ export default function EditTaskProject() {
<LayoutNavbarNew back="" title={"Edit Judul Kegiatan"} menu /> <LayoutNavbarNew back="" title={"Edit Judul Kegiatan"} menu />
<Box p={20}> <Box p={20}>
<Stack pt={15}> <Stack pt={15}>
{loading ? {loading ?
<Skeleton height={40} mt={20} radius={10} /> <Skeleton height={40} mt={20} radius={10} />
: :
<TextInput <TextInput
styles={{ styles={{
input: { input: {
border: `1px solid ${"#D6D8F6"}`, border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10, borderRadius: 10,
}, },
}} }}
placeholder="Input Kegiatan" placeholder="Nama Kegiatan"
label="Judul Kegiatan" label="Kegiatan"
required required
size="md" size="md"
value={name} value={name}
onChange={(e) => { onChange={(e) => { onValidation('title', e.target.value) }}
setName(e.target.value) error={
setTouched({ ...touched, name: false }) touched.name && (
}} name == "" ? "Kegiatan Tidak Boleh Kosong" : null
error={ )
touched.name && ( }
name == "" ? "Judul Kegiatan Tidak Boleh Kosong" : null />
)
}
onBlur={() => setTouched({ ...touched, name: true })}
/>
} }
</Stack> </Stack>
</Box> </Box>
@@ -104,19 +114,19 @@ export default function EditTaskProject() {
backgroundColor: `${tema.get().bgUtama}`, backgroundColor: `${tema.get().bgUtama}`,
}}> }}>
{loading ? {loading ?
<Skeleton height={50} radius={30} /> <Skeleton height={50} radius={30} />
: :
<Button <Button
c={"white"} c={"white"}
bg={tema.get().utama} bg={tema.get().utama}
size="lg" size="lg"
radius={30} radius={30}
fullWidth fullWidth
onClick={() => { onVerification() }} onClick={() => { onCheck() }}
> >
Simpan Simpan
</Button> </Button>
} }
</Box> </Box>

View File

@@ -1,30 +1,29 @@
"use client"; "use client";
import { keyWibu, LayoutDrawer, LayoutNavbarNew, TEMA } from "@/module/_global"; import { keyWibu, LayoutDrawer, LayoutNavbarNew, TEMA } from "@/module/_global";
import { Avatar, Box, Button, Center, Divider, Flex, Grid, Group, Input, rem, SimpleGrid, Stack, Text, TextInput } from "@mantine/core"; import LayoutModal from "@/module/_global/layout/layout_modal";
import { useHookstate } from "@hookstate/core";
import { Avatar, Box, Button, Divider, Flex, Grid, Group, rem, SimpleGrid, Stack, Text, TextInput } from "@mantine/core";
import { Dropzone } from '@mantine/dropzone';
import { useMediaQuery } from "@mantine/hooks";
import _ from "lodash";
import { useParams, useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import React, { useRef, useState } from "react"; import { useRef, useState } from "react";
import toast from "react-hot-toast";
import { FaTrash } from "react-icons/fa6";
import { IoIosArrowDropright } from "react-icons/io"; import { IoIosArrowDropright } from "react-icons/io";
import { BsFiletypeCsv } from "react-icons/bs"; import { useWibuRealtime } from "wibu-realtime";
import { funCreateTask } from "../lib/api_task";
import { IFormDateTask, IFormMemberTask, IListFileTask } from "../lib/type_task";
import { globalMemberTask } from "../lib/val_task";
import ViewDateEndTask from "./create_date_end_task";
import CreateUsersProject from "./create_users_project"; import CreateUsersProject from "./create_users_project";
import ResultsDateAndTask from "./results_date-and_task"; import ResultsDateAndTask from "./results_date-and_task";
import ResultsFile from "./results_file"; import ResultsFile from "./results_file";
import { useHookstate } from "@hookstate/core";
import { globalMemberTask } from "../lib/val_task";
import ViewDateEndTask from "./create_date_end_task";
import { IFormDateTask, IFormMemberTask, IListFileTask } from "../lib/type_task";
import { Dropzone } from '@mantine/dropzone';
import toast from "react-hot-toast";
import _ from "lodash";
import { FaTrash } from "react-icons/fa6";
import LayoutModal from "@/module/_global/layout/layout_modal";
import { funCreateTask } from "../lib/api_task";
import { useMediaQuery } from "@mantine/hooks";
import { useWibuRealtime } from "wibu-realtime";
export default function CreateTask() { export default function CreateTask() {
const router = useRouter() const router = useRouter()
const param = useParams<{ id: string }>() const param = useParams<{ id: string }>()
const [openDrawer, setOpenDrawer] = useState(false) const [loadingModal, setLoadingModal] = useState(false)
const [openDrawerFile, setOpenDrawerFile] = useState(false) const [openDrawerFile, setOpenDrawerFile] = useState(false)
const [openDrawerTask, setOpenDrawerTask] = useState(false) const [openDrawerTask, setOpenDrawerTask] = useState(false)
const [openMember, setOpenMember] = useState(false) const [openMember, setOpenMember] = useState(false)
@@ -44,8 +43,6 @@ export default function CreateTask() {
const tema = useHookstate(TEMA) const tema = useHookstate(TEMA)
const [touched, setTouched] = useState({ const [touched, setTouched] = useState({
title: false, title: false,
task: false,
member: false
}); });
const [data, setData] = useWibuRealtime({ const [data, setData] = useWibuRealtime({
WIBU_REALTIME_TOKEN: keyWibu, WIBU_REALTIME_TOKEN: keyWibu,
@@ -66,6 +63,7 @@ export default function CreateTask() {
async function onSubmit() { async function onSubmit() {
try { try {
setLoadingModal(true)
const fd = new FormData(); const fd = new FormData();
for (let i = 0; i < fileForm.length; i++) { for (let i = 0; i < fileForm.length; i++) {
fd.append(`file${i}`, fileForm[i]); fd.append(`file${i}`, fileForm[i]);
@@ -95,10 +93,51 @@ export default function CreateTask() {
} catch (error) { } catch (error) {
console.error(error) console.error(error)
toast.error("Gagal menambahkan tugas divisi, coba lagi nanti"); toast.error("Gagal menambahkan tugas divisi, coba lagi nanti");
} finally {
setLoadingModal(false)
setOpenModal(false)
} }
} }
function onCheck() {
const cek = checkAll()
if (!cek)
return false
if (dataTask.length == 0)
return toast.error("Error! silahkan tambahkan tugas")
if (memberValue.length == 0)
return toast.error("Error! silahkan pilih anggota")
setOpenModal(true)
}
function checkAll() {
let nilai = true
if (title === "") {
setTouched(touched => ({ ...touched, title: true }))
nilai = false
}
return nilai
}
function onValidation(kategori: string, val: string) {
if (kategori == 'title') {
setTitle(val)
if (val === "") {
setTouched({ ...touched, title: true })
} else {
setTouched({ ...touched, title: false })
}
}
}
if (openTugas) return <ViewDateEndTask onClose={(val) => { setOpenTugas(false) }} onSet={(val) => { if (openTugas) return <ViewDateEndTask onClose={(val) => { setOpenTugas(false) }} onSet={(val) => {
setDataTask([...dataTask, val]) setDataTask([...dataTask, val])
setOpenTugas(false) setOpenTugas(false)
@@ -123,11 +162,7 @@ export default function CreateTask() {
size="md" size="md"
label="Judul Tugas" label="Judul Tugas"
value={title} value={title}
onChange={(e) => { onChange={(e) => { onValidation('title', e.target.value) }}
setTitle(e.target.value)
setTouched({ ...touched, title: false })
}}
onBlur={() => setTouched({ ...touched, title: true })}
required required
error={ error={
touched.title && ( touched.title && (
@@ -287,15 +322,7 @@ export default function CreateTask() {
bg={tema.get().utama} bg={tema.get().utama}
size="lg" radius={30} size="lg" radius={30}
fullWidth fullWidth
onClick={() => { onClick={() => { onCheck() }}>
if (
title !== ""
) {
setOpenModal(true)
} else {
toast.error("Semua form harus diisi")
}
}}>
Simpan Simpan
</Button> </Button>
</Box> </Box>
@@ -412,13 +439,14 @@ export default function CreateTask() {
<LayoutModal opened={openModal} onClose={() => setOpenModal(false)} <LayoutModal loading={loadingModal} opened={openModal} onClose={() => setOpenModal(false)}
description="Apakah Anda yakin ingin menambahkan data?" description="Apakah Anda yakin ingin menambahkan data?"
onYes={(val) => { onYes={(val) => {
if (val) { if (val) {
onSubmit() onSubmit()
} else {
setOpenModal(false)
} }
setOpenModal(false)
}} /> }} />
</Box > </Box >
); );

View File

@@ -1,28 +1,15 @@
"use client"; "use client";
import { LayoutNavbarNew, TEMA } from "@/module/_global"; import { LayoutNavbarNew, TEMA } from "@/module/_global";
import {
Avatar,
Box,
Button,
Flex,
Group,
Input,
rem,
SimpleGrid,
Skeleton,
Stack,
Text,
TextInput,
} from "@mantine/core";
import React, { useState } from "react";
import { DatePicker } from "@mantine/dates";
import { useParams, useRouter } from "next/navigation";
import toast from "react-hot-toast";
import moment from "moment";
import { funEditDetailTask, funGetDetailTask } from "../lib/api_task";
import { useShallowEffect } from "@mantine/hooks";
import LayoutModal from "@/module/_global/layout/layout_modal"; import LayoutModal from "@/module/_global/layout/layout_modal";
import { useHookstate } from "@hookstate/core"; import { useHookstate } from "@hookstate/core";
import { Box, Button, Group, rem, SimpleGrid, Skeleton, Stack, Text, TextInput } from "@mantine/core";
import { DatePicker } from "@mantine/dates";
import { useShallowEffect } from "@mantine/hooks";
import moment from "moment";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";
import { funEditDetailTask, funGetDetailTask } from "../lib/api_task";
export default function EditDetailTask() { export default function EditDetailTask() {
@@ -185,10 +172,10 @@ export default function EditDetailTask() {
touched.title && touched.title &&
(title == "" ? "Error! harus memasukkan Judul Tahapan" : "" (title == "" ? "Error! harus memasukkan Judul Tahapan" : ""
) )
} }
onChange={(e) => { onChange={(e) => {
onValidation('title', e.target.value) onValidation('title', e.target.value)
}} }}
/> />
} }
</Stack> </Stack>

View File

@@ -1,22 +1,13 @@
"use client"; "use client";
import { LayoutNavbarNew, TEMA } from "@/module/_global"; import { LayoutNavbarNew, TEMA } from "@/module/_global";
import {
Box,
Button,
Input,
rem,
Skeleton,
Stack,
Textarea,
TextInput,
} from "@mantine/core";
import React, { useState } from "react";
import { useParams, useRouter } from "next/navigation";
import toast from "react-hot-toast";
import LayoutModal from "@/module/_global/layout/layout_modal"; import LayoutModal from "@/module/_global/layout/layout_modal";
import { funEditTask, funGetTaskDivisionById } from "../lib/api_task";
import { useShallowEffect } from "@mantine/hooks";
import { useHookstate } from "@hookstate/core"; import { useHookstate } from "@hookstate/core";
import { Box, Button, rem, Skeleton, Stack, TextInput } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";
import { funEditTask, funGetTaskDivisionById } from "../lib/api_task";
export default function EditTask() { export default function EditTask() {
@@ -31,12 +22,22 @@ export default function EditTask() {
}); });
function onVerification() { function onVerification() {
if (title == "") if (Object.values(touched).some((v) => v == true))
return toast.error("Error! harus memasukkan judul tugas") return false
setOpenModal(true) setOpenModal(true)
} }
function onValidation(kategori: string, val: string) {
if (kategori == 'title') {
setTitle(val)
if (val === "") {
setTouched({ ...touched, title: true })
} else {
setTouched({ ...touched, title: false })
}
}
}
async function onSubmit() { async function onSubmit() {
try { try {
const res = await funEditTask(param.detail, { title }) const res = await funEditTask(param.detail, { title })
@@ -96,16 +97,12 @@ export default function EditTask() {
label="Judul Tugas" label="Judul Tugas"
size="md" size="md"
value={title} value={title}
onChange={(e) => { onChange={(e) => { onValidation('title', e.target.value)}}
setTitle(e.target.value)
setTouched({ ...touched, title: false })
}}
error={ error={
touched.title && ( touched.title && (
title == "" ? "Error! harus memasukkan judul tugas" : null title == "" ? "Error! harus memasukkan judul tugas" : null
) )
} }
onBlur={() => setTouched({ ...touched, title: true })}
/> />
} }
</Stack> </Stack>

View File

@@ -1,25 +1,26 @@
"use client"; "use client";
import { globalRole, TEMA, WARNA } from "@/module/_global"; import { globalRole, TEMA } from "@/module/_global";
import LayoutModal from "@/module/_global/layout/layout_modal"; import LayoutModal from "@/module/_global/layout/layout_modal";
import { funGetUserByCookies } from "@/module/auth";
import { funGetAllGroup, IDataGroup } from "@/module/group"; import { funGetAllGroup, IDataGroup } from "@/module/group";
import { funGetAllPosition } from "@/module/position/lib/api_position";
import { useHookstate } from "@hookstate/core";
import { Avatar, Box, Button, Indicator, rem, Select, Stack, Text, TextInput } from "@mantine/core"; import { Avatar, Box, Button, Indicator, rem, Select, Stack, Text, TextInput } from "@mantine/core";
import { Dropzone } from "@mantine/dropzone";
import { useShallowEffect } from "@mantine/hooks";
import _ from "lodash";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { IDataPositionMember, IDataROleMember } from "../lib/type_member";
import { funGetAllPosition } from "@/module/position/lib/api_position";
import { funCreateMember } from "../lib/api_member";
import _ from "lodash";
import { useHookstate } from "@hookstate/core";
import { useShallowEffect } from "@mantine/hooks";
import { funGetUserByCookies } from "@/module/auth";
import { valueRoleUser } from "../../lib/val_user";
import { FaCamera } from "react-icons/fa6"; import { FaCamera } from "react-icons/fa6";
import { Dropzone } from "@mantine/dropzone"; import { valueRoleUser } from "../../lib/val_user";
import { funCreateMember } from "../lib/api_member";
import { IDataPositionMember, IDataROleMember } from "../lib/type_member";
export default function CreateMember() { export default function CreateMember() {
const router = useRouter(); const router = useRouter();
const [isModal, setModal] = useState(false); const [isModal, setModal] = useState(false);
const [loadingKonfirmasi, setLoadingKonfirmasi] = useState(false);
const [listGroup, setListGorup] = useState<IDataGroup[]>([]); const [listGroup, setListGorup] = useState<IDataGroup[]>([]);
const [listPosition, setListPosition] = useState<IDataPositionMember[]>([]); const [listPosition, setListPosition] = useState<IDataPositionMember[]>([]);
const [listUserRole, setListUserRole] = useState<IDataROleMember[]>([]); const [listUserRole, setListUserRole] = useState<IDataROleMember[]>([]);
@@ -100,37 +101,33 @@ export default function CreateMember() {
async function onSubmit(val: boolean) { async function onSubmit(val: boolean) {
try { try {
if (_.isEmpty(listData)) { setLoadingKonfirmasi(true)
return; const fd = new FormData()
} fd.append("file", imgForm)
if (val) { fd.append("data", JSON.stringify(
const fd = new FormData() {
fd.append("file", imgForm) nik: listData.nik,
fd.append("data", JSON.stringify( name: listData.name,
{ phone: listData.phone,
nik: listData.nik, email: listData.email,
name: listData.name, gender: listData.gender,
phone: listData.phone, idGroup: listData.idGroup,
email: listData.email, idPosition: listData.idPosition,
gender: listData.gender, idUserRole: listData.idUserRole,
idGroup: listData.idGroup,
idPosition: listData.idPosition,
idUserRole: listData.idUserRole,
}
))
const res = await funCreateMember(fd);
if (res.success) {
toast.success(res.message);
setModal(false);
router.push("/member?active=true");
} else {
toast.error(res.message);
} }
))
const res = await funCreateMember(fd);
if (res.success) {
toast.success(res.message);
router.push("/member?active=true");
} else {
toast.error(res.message);
} }
setModal(false); setModal(false);
} catch (error) { } catch (error) {
toast.error("Error"); toast.error("Error");
} finally { } finally {
setLoadingKonfirmasi(false)
setModal(false); setModal(false);
} }
} }
@@ -142,12 +139,61 @@ export default function CreateMember() {
}, []); }, []);
function onCheck() { function onCheck() {
if (Object.values(touched).some((v) => v == true)) const cek = checkAll()
if (!cek)
return false return false
setModal(true) setModal(true)
} }
function onValidation(kategori: string, val: string) { function checkAll() {
let nilai = true
if (listData.nik === "" || listData.nik.length !== 16) {
setTouched(touched => ({ ...touched, nik: true }))
nilai = false
}
if (listData.name === "") {
setTouched(touched => ({ ...touched, name: true }))
nilai = false
}
if (listData.phone == "" || !(listData.phone.length >= 10 && listData.phone.length <= 15)) {
setTouched(touched => ({ ...touched, phone: true }))
nilai = false
}
if (listData.email == "" || !/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(listData.email)) {
setTouched(touched => ({ ...touched, email: true }))
nilai = false
}
if (listData.gender == "" || String(listData.gender) == "null") {
setTouched(touched => ({ ...touched, gender: true }))
nilai = false
}
if (roleLogin.get() == "supadmin" && (listData.idGroup == "" || String(listData.idGroup) == "null")) {
setTouched(touched => ({ ...touched, idGroup: true }))
nilai = false
}
if (listData.idPosition === "" || String(listData.idPosition) == "null") {
setTouched(touched => ({ ...touched, idPosition: true }))
nilai = false
}
if (listData.idUserRole === "" || String(listData.idUserRole) == "null") {
setTouched(touched => ({ ...touched, idUserRole: true }))
nilai = false
}
return nilai
}
function onValidation(kategori: string, val: any) {
if (kategori == 'nik') { if (kategori == 'nik') {
setListData({ ...listData, nik: val }) setListData({ ...listData, nik: val })
if (val === "" || val.length !== 16) { if (val === "" || val.length !== 16) {
@@ -178,28 +224,28 @@ export default function CreateMember() {
} }
} else if (kategori == 'gender') { } else if (kategori == 'gender') {
setListData({ ...listData, gender: val }) setListData({ ...listData, gender: val })
if (val == "" || val == "null") { if (val == "" || String(val) == "null") {
setTouched({ ...touched, gender: true }) setTouched({ ...touched, gender: true })
} else { } else {
setTouched({ ...touched, gender: false }) setTouched({ ...touched, gender: false })
} }
} else if (kategori == 'idGroup') { } else if (kategori == 'idGroup') {
setListData({ ...listData, idGroup: val, idPosition: "", }) setListData(listData => ({ ...listData, idGroup: val, }))
if (val === "") { if (val === "" || String(val) == "null") {
setTouched({ ...touched, idGroup: true }) setTouched(touched => ({ ...touched, idGroup: true }))
} else { } else {
setTouched({ ...touched, idGroup: false }) setTouched({ ...touched, idGroup: false })
} }
} else if (kategori == 'idPosition') { } else if (kategori == 'idPosition') {
setListData({ ...listData, idPosition: val }) setListData(listData => ({ ...listData, idPosition: val }))
if (val === "") { if (val === "" || String(val) == "null") {
setTouched({ ...touched, idPosition: true }) setTouched(touched => ({ ...touched, idPosition: true }))
} else { } else {
setTouched({ ...touched, idPosition: false }) setTouched({ ...touched, idPosition: false })
} }
} else if (kategori == 'idUserRole') { } else if (kategori == 'idUserRole') {
setListData({ ...listData, idUserRole: val }) setListData({ ...listData, idUserRole: val })
if (val === "") { if (val === "" || String(val) == "null") {
setTouched({ ...touched, idUserRole: true }) setTouched({ ...touched, idUserRole: true })
} else { } else {
setTouched({ ...touched, idUserRole: false }) setTouched({ ...touched, idUserRole: false })
@@ -210,6 +256,7 @@ export default function CreateMember() {
async function changeGrup(val: any) { async function changeGrup(val: any) {
setListPosition([]); setListPosition([]);
onValidation('idGroup', val) onValidation('idGroup', val)
onValidation('idPosition', '')
getAllPosition(val); getAllPosition(val);
} }
@@ -269,7 +316,7 @@ export default function CreateMember() {
onChange={(val: any) => { changeGrup(val) }} onChange={(val: any) => { changeGrup(val) }}
error={ error={
touched.idGroup && ( touched.idGroup && (
listData.idGroup == "" ? "Grup Tidak Boleh Kosong" : null listData.idGroup == "" || String(listData.idGroup) == "null" ? "Grup Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -301,7 +348,7 @@ export default function CreateMember() {
value={listData.idPosition == "" ? null : listData.idPosition} value={listData.idPosition == "" ? null : listData.idPosition}
error={ error={
touched.idPosition && ( touched.idPosition && (
listData.idPosition == "" ? "Jabatan Tidak Boleh Kosong" : null listData.idPosition == "" || String(listData.idPosition) == "null" ? "Jabatan Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -331,7 +378,7 @@ export default function CreateMember() {
onChange={(val: any) => { onValidation('idUserRole', val) }} onChange={(val: any) => { onValidation('idUserRole', val) }}
error={ error={
touched.idUserRole && ( touched.idUserRole && (
listData.idUserRole == "" ? "Role Tidak Boleh Kosong" : null listData.idUserRole == "" || String(listData.idUserRole) == "null" ? "Role Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -423,7 +470,7 @@ export default function CreateMember() {
error={ error={
touched.phone && ( touched.phone && (
listData.phone == "" ? "Nomor Telepon Tidak Boleh Kosong" : listData.phone == "" ? "Nomor Telepon Tidak Boleh Kosong" :
listData.phone.length < 10 ? "Nomor Telepon harus 10 digit" : null listData.phone.length < 10 ? "Nomor Telepon Tidak Valid" : null
) )
} }
/> />
@@ -449,7 +496,7 @@ export default function CreateMember() {
onChange={(val: any) => { onValidation('gender', val) }} onChange={(val: any) => { onValidation('gender', val) }}
error={ error={
touched.gender && ( touched.gender && (
listData.gender == "" ? "Jenis Kelamin Tidak Boleh Kosong" : null listData.gender == "" || String(listData.gender == "null") ? "Jenis Kelamin Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -471,11 +518,16 @@ export default function CreateMember() {
</Button> </Button>
</Box> </Box>
<LayoutModal <LayoutModal
loading={loadingKonfirmasi}
opened={isModal} opened={isModal}
onClose={() => setModal(false)} onClose={() => setModal(false)}
description="Apakah Anda yakin ingin menambahkan data?" description="Apakah Anda yakin ingin menambahkan data?"
onYes={(val) => { onYes={(val) => {
onSubmit(val); if (val) {
onSubmit(val);
} else {
setModal(false);
}
}} }}
/> />
</Box> </Box>

View File

@@ -1,25 +1,25 @@
'use client' 'use client'
import { globalRole, TEMA, WARNA } from "@/module/_global"; import { globalRole, TEMA } 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 { funGetAllPosition } from "@/module/position/lib/api_position"; import { funGetAllPosition } from "@/module/position/lib/api_position";
import { useHookstate } from "@hookstate/core";
import { Avatar, Box, Button, Indicator, rem, Select, Skeleton, Stack, Text, TextInput } from "@mantine/core"; import { Avatar, Box, Button, Indicator, rem, Select, Skeleton, Stack, Text, TextInput } from "@mantine/core";
import { Dropzone } from "@mantine/dropzone";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import _ from "lodash";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useRef, 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, IEditDataMember, IFormMember } from "../lib/type_member";
import { funEditMember, funGetOneMember, funGetRoleUser } from "../lib/api_member";
import _ from "lodash";
import { Dropzone } from "@mantine/dropzone";
import { FaCamera } from "react-icons/fa6"; import { FaCamera } from "react-icons/fa6";
import { useHookstate } from "@hookstate/core";
import { valueRoleUser } from "../../lib/val_user"; import { valueRoleUser } from "../../lib/val_user";
import { funEditMember, funGetOneMember } from "../lib/api_member";
import { IDataPositionMember, IDataROleMember, IEditDataMember } from "../lib/type_member";
export default function EditMember({ id }: { id: string }) { export default function EditMember({ id }: { id: string }) {
const [isModal, setModal] = useState(false) const [isModal, setModal] = useState(false)
const [loadingKonfirmasi, setLoadingKonfirmasi] = useState(false)
const router = useRouter() const router = useRouter()
const [listGroup, setListGorup] = useState<IDataGroup[]>([]) const [listGroup, setListGorup] = useState<IDataGroup[]>([])
const [listPosition, setListPosition] = useState<IDataPositionMember[]>([]) const [listPosition, setListPosition] = useState<IDataPositionMember[]>([])
@@ -111,26 +111,24 @@ export default function EditMember({ id }: { id: string }) {
async function onSubmit(val: boolean) { async function onSubmit(val: boolean) {
try { try {
if (_.isEmpty(data)) { setLoadingKonfirmasi(true)
return const fd = new FormData()
fd.append("file", imgForm)
fd.append("data", JSON.stringify(data))
const res = await funEditMember(id, fd)
if (res.success) {
toast.success(res.message)
router.push(`/member?active=true`)
} else {
toast.error(res.message)
} }
if (val) {
const fd = new FormData()
fd.append("file", imgForm)
fd.append("data", JSON.stringify(data))
const res = await funEditMember(id, fd)
if (res.success) {
toast.success(res.message)
router.push(`/member?active=true`)
} else {
toast.error(res.message)
}
}
} catch (error) { } catch (error) {
toast.error('Error'); toast.error('Error');
} finally {
setLoadingKonfirmasi(false)
setModal(false)
} }
} }
@@ -171,21 +169,21 @@ export default function EditMember({ id }: { id: string }) {
} }
} else if (kategori == 'gender') { } else if (kategori == 'gender') {
setData({ ...data, gender: val }) setData({ ...data, gender: val })
if (val == "" || val == "null") { if (val == "" || String(val) == "null") {
setTouched({ ...touched, gender: true }) setTouched({ ...touched, gender: true })
} else { } else {
setTouched({ ...touched, gender: false }) setTouched({ ...touched, gender: false })
} }
} else if (kategori == 'idPosition') { } else if (kategori == 'idPosition') {
setData({ ...data, idPosition: val }) setData({ ...data, idPosition: val })
if (val === "") { if (val === "" || String(val) == "null") {
setTouched({ ...touched, idPosition: true }) setTouched({ ...touched, idPosition: true })
} else { } else {
setTouched({ ...touched, idPosition: false }) setTouched({ ...touched, idPosition: false })
} }
} else if (kategori == 'idUserRole') { } else if (kategori == 'idUserRole') {
setData({ ...data, idUserRole: val }) setData({ ...data, idUserRole: val })
if (val === "") { if (val === "" || String(val) == "null") {
setTouched({ ...touched, idUserRole: true }) setTouched({ ...touched, idUserRole: true })
} else { } else {
setTouched({ ...touched, idUserRole: false }) setTouched({ ...touched, idUserRole: false })
@@ -267,7 +265,7 @@ export default function EditMember({ id }: { id: string }) {
value={(data?.idPosition == "") ? null : data.idPosition} value={(data?.idPosition == "") ? null : data.idPosition}
error={ error={
touched.idPosition && ( touched.idPosition && (
data.idPosition == "" ? "Jabatan Tidak Boleh Kosong" : null data.idPosition == "" || String(data.idPosition) == "null" ? "Jabatan Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -292,7 +290,7 @@ export default function EditMember({ id }: { id: string }) {
value={data?.idUserRole} value={data?.idUserRole}
error={ error={
touched.idUserRole && ( touched.idUserRole && (
data.idUserRole == "" ? "Role Tidak Boleh Kosong" : null data.idUserRole == "" || String(data.idUserRole) == "null" ? "Role Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -325,7 +323,6 @@ export default function EditMember({ id }: { id: string }) {
}} }}
onChange={(e) => { onValidation('name', e.target.value) }} onChange={(e) => { onValidation('name', e.target.value) }}
value={data.name} value={data.name}
onBlur={() => setTouched({ ...touched, name: true })}
error={ error={
touched.name && ( touched.name && (
data.name == "" ? "Nama Tidak Boleh Kosong" : null data.name == "" ? "Nama Tidak Boleh Kosong" : null
@@ -366,7 +363,7 @@ export default function EditMember({ id }: { id: string }) {
error={ error={
touched.phone && ( touched.phone && (
data.phone == "" ? "Nomor Telepon Tidak Boleh Kosong" : data.phone == "" ? "Nomor Telepon Tidak Boleh Kosong" :
data.phone.length < 10 ? "Nomor Telepon harus 10 digit" : null data.phone.length < 10 ? "Nomor Telepon Tidak Valid" : null
) )
} }
/> />
@@ -395,7 +392,7 @@ export default function EditMember({ id }: { id: string }) {
value={data.gender} value={data.gender}
error={ error={
touched.gender && ( touched.gender && (
data.gender == "" ? "Gender Tidak Boleh Kosong" : null data.gender == "" || String(data.gender) == "null" ? "Gender Tidak Boleh Kosong" : null
) )
} }
/> />
@@ -422,12 +419,14 @@ export default function EditMember({ id }: { id: string }) {
</Button> </Button>
} }
</Box> </Box>
<LayoutModal opened={isModal} onClose={() => setModal(false)} <LayoutModal loading={loadingKonfirmasi} opened={isModal} onClose={() => setModal(false)}
description="Apakah Anda yakin ingin mengubah data?" description="Apakah Anda yakin ingin mengubah data?"
onYes={(val) => { onYes={(val) => {
if (val) if (val) {
onSubmit(val) onSubmit(val)
setModal(false) } else {
setModal(false)
}
} }
} /> } />
</Box> </Box>