upd: dashboard developer

Deskripsi:
- gambar bg login
- ui login dashboard developer
- api log user
- ui log user page
- integrasi dg api

No Issues
This commit is contained in:
amel
2025-02-21 10:34:45 +08:00
parent b6a8069d19
commit 6aee5f8055
10 changed files with 321 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

View File

@@ -0,0 +1,70 @@
import { prisma } from "@/module/_global";
import _ from "lodash";
import moment from "moment";
import "moment/locale/id";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const idVillage = searchParams.get("village");
const dStart = searchParams.get('dateStart');
const dEnd = searchParams.get('dateEnd');
const awalDate = moment(dStart).format('YYYY-MM-DD') + ' 00:00:01'
const akhirDate = moment(dEnd).format('YYYY-MM-DD') + ' 23:59:59'
const data = await prisma.userLog.findMany({
where: {
User: {
idVillage: String(idVillage)
},
createdAt: {
gte: new Date(awalDate),
lte: new Date(akhirDate),
}
},
select: {
User: {
select: {
name: true,
img: true,
UserRole: {
select: {
name: true
}
},
Group: {
select: {
name: true
}
}
}
},
id: true,
createdAt: true,
idUser: true,
action: true,
desc: true,
idContent: true,
tbContent: true,
}
})
const fixData = data.map((v: any) => ({
..._.omit(v, ["createdAt", "User"]),
createdAt: moment(v.createdAt).format("lll").replace("pukul", ""),
userName: v.User.name,
userImg: v.User.img,
userRole: v.User.UserRole.name,
userGroup: v.User.Group.name
}))
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: fixData }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -0,0 +1,9 @@
import { AuthPage, LoginPageDashboard, LogUserPage } from "@/module/dashboard";
export default function Page() {
return (
// <LoginPageDashboard />
// <LogUserPage />
<AuthPage />
)
}

View File

@@ -0,0 +1,7 @@
import AuthPage from "./ui/auth_page";
import LogUserPage from "./ui/log_user_page";
import LoginPageDashboard from "./ui/login_das";
export { LoginPageDashboard }
export { LogUserPage }
export { AuthPage }

View File

@@ -0,0 +1,4 @@
export const funGetLogUserDashboard = async (path?: string) => {
const response = await fetch(`/api/log-user${(path) ? path : ''}`);
return await response.json().catch(() => null);
}

View File

@@ -0,0 +1,13 @@
export interface IDataLogUserDashboard {
id: string
idUser: string
idContent: string
tbContent: string
action: string
desc: string
userName: string
userImg: string | null
userRole: string
userGroup: string
createdAt: string
}[]

View File

@@ -0,0 +1,26 @@
'use client'
import { useState } from "react";
import LogUserPage from "./log_user_page";
import LoginPageDashboard from "./login_das";
import toast from "react-hot-toast";
export default function AuthPage() {
const [valid, setValid] = useState(false)
function cekPassword(pass: string) {
if (pass == "wibuSekali") {
toast.success("Selamat datang di dashboard developer!")
setTimeout(() => {
setValid(true)
}, 2000);
} else {
setValid(false)
toast.error("Password salah")
}
}
if (valid) return <LogUserPage />
return <LoginPageDashboard onSubmit={(val) => { cekPassword(val) }} />
}

View File

@@ -0,0 +1,139 @@
'use client'
import { Avatar, Box, Button, Center, Divider, Flex, Grid, Group, Text, Loader } from "@mantine/core";
import { DateInput } from "@mantine/dates";
import _ from "lodash";
import { useState } from "react";
import { IDataLogUserDashboard } from "../lib/type_log_user";
import toast from "react-hot-toast";
import { funGetLogUserDashboard } from "../lib/api_log_user";
import moment from "moment";
import { useShallowEffect } from "@mantine/hooks";
export default function LogUserPage() {
const [value, setValue] = useState<Date | undefined>(new Date());
const [valueEnd, setValueEnd] = useState<Date | undefined>(new Date());
const [data, setData] = useState<IDataLogUserDashboard[]>([]);
const [loading, setLoading] = useState(true)
async function onShow(awal: any, akhir: any) {
try {
setLoading(true)
const res = await funGetLogUserDashboard(`?village=desa1&dateStart=${moment(awal).format("YYYY-MM-DD")}&dateEnd=${moment(akhir).format("YYYY-MM-DD")}`)
if (res.success) {
setData(res.data)
} else {
toast.error(res.message)
}
} catch (error) {
console.error(error)
toast.error("Gagal mendapatkan data, coba lagi nanti");
} finally {
setLoading(false)
}
}
function onChangeDateStart(val: any, kat: string) {
if (kat == "start") {
val == null ? setValue(undefined) : setValue(val)
if (valueEnd != undefined && val != undefined && valueEnd < val) {
setValueEnd(val)
onShow(val, val)
} else {
onShow(val, valueEnd)
}
} else if (kat == "end") {
val == null ? setValueEnd(undefined) : setValueEnd(val)
onShow(value, val)
}
}
useShallowEffect(() => {
onShow(value, valueEnd)
}, [])
return (
<>
<Box p={15}>
<Box mb={20}>
<DateInput
value={value}
onChange={(val) => { onChangeDateStart(val, 'start') }}
label="Tanggal Awal"
placeholder="Tanggal Awal"
mb={5}
/>
<DateInput
minDate={value}
value={valueEnd}
onChange={(val) => { onChangeDateStart(val, 'end') }}
label="Tanggal Akhir"
placeholder="Tanggal Akhir"
/>
</Box>
<Flex gap="sm" justify="center" align="center" direction="column" wrap="wrap">
{
!loading ?
data.length > 0 ?
data.map((item, i) => {
return (
<Box key={i} w={"100%"} style={{ backgroundColor: 'white', padding: 10, borderRadius: 10 }}>
<Grid align="center" style={{ borderBottomWidth: 1, borderBottomColor: 'whitesmoke', borderBottomStyle: 'solid', paddingBottom: 5 }}>
<Grid.Col
span={{
base: 1,
xs: 1,
sm: 1,
md: 1,
lg: 1,
xl: 1,
}}
>
<Avatar size={50} alt="image" src={`https://wibu-storage.wibudev.com/api/files/${item.userImg}`} />
</Grid.Col>
<Grid.Col
span={{
base: 10,
xs: 10.5,
sm: 10.5,
md: 10.5,
lg: 10.5,
xl: 10.5,
}}
pl={20}
pr={0}
>
<Group justify="space-between">
<Text fw={"bold"} c={"black"} truncate="end" >
{item.userName}
</Text>
<Text fw={"lighter"} fz={12}>{item.createdAt}</Text>
</Group>
<Text fw={"lighter"} fz={12} truncate="end">
{item.userRole + ' - ' + item.userGroup}
</Text>
</Grid.Col>
</Grid>
<Box px={10} py={5}>
<Text>{item.desc}</Text>
<Text fw={"lighter"} fz={10}>{item.tbContent + ' | ' + item.idContent}</Text>
</Box>
</Box>
)
})
:
(
<Text ta={'center'}>Data Kosong</Text>
)
:
(
<Loader color="grape" type="dots" />
)
}
</Flex>
</Box>
</>
)
}

View File

@@ -0,0 +1,53 @@
'use client'
import { Box, Button, Image, PasswordInput, Stack, Text } from "@mantine/core";
import { useViewportSize } from "@mantine/hooks";
import { useState } from "react";
export default function LoginPageDashboard({ onSubmit }: { onSubmit: (val: string) => void }) {
const { height, width } = useViewportSize();
const [password, setPassword] = useState("")
return (
<>
<Stack
h={height}
bg="#c1a0fd"
align="stretch"
justify="space-between"
gap="xl"
>
<Image
w="auto"
src="/assets/img/bg-login3.jpg"
alt="background login"
/>
<Text ta={'center'} fw={'bold'} fz={45} color="white" ff={'Arial'}
style={{
textShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
lineHeight: '10px'
}}>
WELCOME!
</Text>
<Box h="35%" bg="white" style={{ borderTopLeftRadius: 50, borderTopRightRadius: 50, boxShadow: '0px 0px 15px rgba(0, 0, 0, 0.25)', paddingLeft: 50, paddingRight: 50, justifyContent: 'center', alignItems: 'center' }}>
<Stack justify="center" h={"100%"}>
<Box mb={20}>
<Text ta={'center'} ff={'Arial'} fz={20}>Sign in</Text>
<Text c={'#7e7e7e'} ff={'Arial'} fz={13}>If you do not know the password, kindly contact the developer for assistance.</Text>
</Box>
<PasswordInput
variant="filled"
size="md"
radius="xl"
placeholder="Password"
ff={'Arial'}
withAsterisk
onChange={(e) => setPassword(e.target.value)}
/>
<Button ff={'Arial'} variant="filled" radius="xl" size="md" bg={'#ad73f1'} onClick={() => onSubmit(password)}>Submit</Button>
</Stack>
</Box>
</Stack>
</>
)
}