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:
BIN
public/assets/img/bg-login1.jpg
Normal file
BIN
public/assets/img/bg-login1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
public/assets/img/bg-login3.jpg
Normal file
BIN
public/assets/img/bg-login3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 MiB |
70
src/app/api/log-user/route.ts
Normal file
70
src/app/api/log-user/route.ts
Normal 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 });
|
||||
}
|
||||
}
|
||||
9
src/app/dashboard/page.tsx
Normal file
9
src/app/dashboard/page.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { AuthPage, LoginPageDashboard, LogUserPage } from "@/module/dashboard";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
// <LoginPageDashboard />
|
||||
// <LogUserPage />
|
||||
<AuthPage />
|
||||
)
|
||||
}
|
||||
7
src/module/dashboard/index.ts
Normal file
7
src/module/dashboard/index.ts
Normal 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 }
|
||||
4
src/module/dashboard/lib/api_log_user.ts
Normal file
4
src/module/dashboard/lib/api_log_user.ts
Normal 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);
|
||||
}
|
||||
13
src/module/dashboard/lib/type_log_user.ts
Normal file
13
src/module/dashboard/lib/type_log_user.ts
Normal 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
|
||||
}[]
|
||||
26
src/module/dashboard/ui/auth_page.tsx
Normal file
26
src/module/dashboard/ui/auth_page.tsx
Normal 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) }} />
|
||||
}
|
||||
139
src/module/dashboard/ui/log_user_page.tsx
Normal file
139
src/module/dashboard/ui/log_user_page.tsx
Normal 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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
53
src/module/dashboard/ui/login_das.tsx
Normal file
53
src/module/dashboard/ui/login_das.tsx
Normal 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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user