Skip to content
Snippets Groups Projects
Commit a6c4d41f authored by Esther Regina's avatar Esther Regina
Browse files

Merge branch 'esther' into 'develop'

admin kursus, dashboard owner, login

See merge request !4
parents 642c0514 64f5540f
Branches
Tags
1 merge request!4admin kursus, dashboard owner, login
......@@ -12,7 +12,7 @@ const Template = ({ children }) => {
const handleLogout = (e) => {
e.preventDefault();
window.localStorage.removeItem("token");
window.location.reload();
window.location.replace("/");
}
useEffect(() => {
const token = window.localStorage.getItem("token")
......
import Image from "next/image"
import { useRouter } from "next/router"
import { useEffect, useState } from "react"
const Template = ({ children }) => {
const router = useRouter()
const [userObject, setUser] = useState(null)
const handleLogin = (e) => {
e.preventDefault();
router.push("/auth/login")
return;
}
const handleLogout = (e) => {
e.preventDefault();
window.localStorage.removeItem("token");
window.location.replace("/");
}
useEffect(() => {
const token = window.localStorage.getItem("token")
if (!token) return;
const tokenParsed = token.split(" ")[1]
fetch(`https://rpl-backend-production.up.railway.app/v1/auth/verify/${tokenParsed}`).then(async (response) => {
if (response.status !== 200) return null;
const responsejson = await response.json();
setUser(responsejson.data)
}).catch(error=>{
console.error(error)
return
})
}, [])
return <>
<header className="flex flex-row align-middle justify-between bg-[#AEDEFC] px-10">
<div className="flex flex-row align-middle justify-center space-x-3">
<Image src="/logo.png" alt="Main Logo" width={100} height={100} />
<span className="h-min my-auto font-bold text-xl">SISTEM MANAJEMEN KURSUS MENGEMUDI RPL</span>
</div>
<div className="flex flex-row align-middle justify-center space-x-6">
{userObject === null && <span className="h-min my-auto font-semibold">Login as Admin Kursus/Owner?</span>}
{userObject !== null && <span className="h-min my-auto font-semibold">Logged in as {userObject.tipe_user}</span>}
{userObject === null && <button className="bg-[#F875AA] h-1/2 w-28 rounded-2xl font-bold text-white text-xl my-auto p-2 " onClick={handleLogin}>Log In</button>}
{userObject !== null && <button className="bg-[#F875AA] h-1/2 w-28 rounded-2xl font-bold text-white text-xl my-auto p-2 " onClick={handleLogout}>Log Out</button>}
</div>
</header >
{children}
</>
}
export default Template
\ No newline at end of file
import Template from "@/components/template"
import { useState } from "react"
import { toast } from "react-toastify"
import { useRouter } from "next/router"
const Create = () => {
const router = useRouter()
const [username, setusername] = useState("")
const [password, setpassword] = useState("")
const handleUpdate = async () => {
const token = window.localStorage.getItem("token")
if (token === undefined || token === null) {
window.location.replace("/auth/login")
return
}
const body = JSON.stringify({
username,
password
})
const updateQuery = await fetch("https://rpl-backend-production.up.railway.app/v1/adminkursus/create", {
method: "POST",
headers: {
Authorization: token,
"Content-Type": "application/json"
},
body
}).then(response => response).catch(() => null)
if (updateQuery === null) {
toast.error("Something went wrong..")
return
}
if (updateQuery.status !== 200) {
toast.error("Failed to create...")
return
}
toast.success("Successfully created!")
router.push("/adminkursus")
return;
}
return <>
<Template>
<main className="min-h-screen px-14 py-5 bg-[#FFF6F6]">
<div className="w-full mb-2">
<span className="text-[#F875AA] font-bold text-2xl hover:cursor-pointer" onClick={(e) => {
e.preventDefault()
router.back()
}}>Back</span>
</div>
<h1 className="text-[#F875AA] font-extrabold text-5xl mb-20 text-center">Create Admin Kursus</h1>
<form className="w-2/3 mx-auto space-y-10 flex flex-col align-middle justify-evenly" onSubmit={(e) => {
e.preventDefault()
handleUpdate()
return;
}}>
<div className="flex flex-row align-middle justify-between">
<span className="h-min my-auto font-bold text-lg">Username</span>
<input value={username} onChange={(e) => {
setusername(e.target.value)
}} type="text" required className="drop-shadow-xl w-2/3 p-2 rounded-xl" />
</div>
<div className="flex flex-row align-middle justify-between">
<span className="h-min my-auto font-bold text-lg">Password</span>
<input value={password} onChange={(e) => {
setpassword(e.target.value)
}} type="password" required className="drop-shadow-xl w-2/3 p-2 rounded-xl" />
</div>
<input type="submit" className="bg-[#F875AA] px-8 py-3 text-xl font-bold text-white rounded-xl mx-auto" value={"Simpan"} />
</form>
</main>
</Template >
</>
}
export default Create
\ No newline at end of file
import Template from "@/components/template"
import { useEffect, useState } from "react"
import { toast } from "react-toastify"
import { useRouter } from "next/router"
const Edit = () => {
const router = useRouter()
const [user_id, setuserid] = useState("")
const [username, setusername] = useState("")
const [password_hash, setpassword_hash] = useState("")
const [password, setpassword] = useState("")
const handleUpdate = async () => {
const token = window.localStorage.getItem("token")
if (token === undefined || token === null) {
window.location.replace("/auth/login")
return
}
const body = JSON.stringify({
username,
password
})
const updateQuery = await fetch("https://rpl-backend-production.up.railway.app/v1/adminkursus/update/" + router.query.id, {
method: "PATCH",
headers: {
Authorization: token,
"Content-Type": "application/json"
},
body
}).then(response => response).catch(() => null)
if (updateQuery === null) {
toast.error("Something went wrong..")
return
}
if (updateQuery.status !== 200) {
toast.error("Failed to update...")
return
}
toast.success("Successfully updated!")
router.push("/adminkursus")
return;
}
useEffect(() => {
const token = window.localStorage.getItem("token")
if (token === undefined || token === null) {
window.location.replace("/auth/login")
return
}
fetch("https://rpl-backend-production.up.railway.app/v1/adminkursus/list/" + router.query.id, {
method: "GET",
headers: {
"Authorization": token
}
}).then(async response => {
if (response.status !== 200) {
toast.error("Failed to retrieve items")
return
}
const responsejson = await response.json()
setuserid(responsejson.data.user_id)
setusername(responsejson.data.username)
setpassword_hash(responsejson.data.password_hash)
})
//eslint-disable-next-line
}, [])
return <>
<Template>
<main className="min-h-screen px-14 py-5 bg-[#FFF6F6]">
<div className="w-full mb-2">
<span className="text-[#F875AA] font-bold text-2xl hover:cursor-pointer" onClick={(e) => {
e.preventDefault()
router.back()
}}>Back</span>
</div>
<h1 className="text-[#F875AA] font-extrabold text-5xl mb-20 text-center">Update Admin Kursus</h1>
<form className="w-2/3 mx-auto space-y-10 flex flex-col align-middle justify-evenly" onSubmit={(e) => {
e.preventDefault()
handleUpdate()
return;
}}>
<div className="flex flex-row align-middle justify-between">
<span className="h-min my-auto font-bold text-lg">user_id</span>
<input disabled value={user_id} type="tel" required className="drop-shadow-xl w-2/3 p-2 rounded-xl" />
</div>
<div className="flex flex-row align-middle justify-between">
<span className="h-min my-auto font-bold text-lg">Username</span>
<input value={username} onChange={(e) => {
setusername(e.target.value)
}} type="text" required className="drop-shadow-xl w-2/3 p-2 rounded-xl" />
</div>
<div className="flex flex-row align-middle justify-between">
<span className="h-min my-auto font-bold text-lg">Password</span>
<input value={password} onChange={(e) => {
setpassword(e.target.value)
}} type="password" required className="drop-shadow-xl w-2/3 p-2 rounded-xl" />
</div>
<input type="submit" className="bg-[#F875AA] px-8 py-3 text-xl font-bold text-white rounded-xl mx-auto" value={"Simpan"} />
</form>
</main>
</Template >
</>
}
export default Edit
\ No newline at end of file
import Template from "@/components/template"
import { useEffect, useState } from "react"
import { toast } from "react-toastify"
import { useRouter } from "next/router"
const Index = () => {
const [rows, setRows] = useState([])
const router = useRouter()
const [deleteToggle, setDeleteToggle] = useState(null)
const [currentPage, setCurrentPage] = useState(1);
const [isLastPage, setLastPage] = useState(false)
const getNextPage = async (page) => {
const token = window.localStorage.getItem("token")
if (token === undefined || token === null) {
window.location.replace("/auth/login")
return;
}
const getItems = await fetch("https://rpl-backend-production.up.railway.app/v1/adminkursus/list?page=" + (page), {
method: "GET",
headers: {
Authorization: token
}
}).then(response => response).catch(() => null)
if (getItems === null) {
toast.error("Something went wrong..")
return;
}
if (getItems.status !== 200) {
toast.error("Unable to get more items!")
return
}
const responsejson = await getItems.json();
setLastPage(responsejson.data.length < 10)
setRows(responsejson.data);
return
}
const handleDelete = async () => {
const token = window.localStorage.getItem("token")
if (token === undefined || token === null) {
window.location.replace("/auth/login")
return
}
const deleteRequest = await fetch("https://rpl-backend-production.up.railway.app/v1/adminkursus/delete/" + deleteToggle, {
method: "DELETE",
headers: {
Authorization: token
}
}).then(response => response).catch(() => null)
setDeleteToggle(null)
if (deleteRequest === null) {
toast.error("Something went wrong...");
return;
}
if (deleteRequest.status !== 200) {
toast.error("Failed to delete..");
return;
}
toast.success("Successfully deleted!");
router.reload();
return;
}
useEffect(() => {
const token = window.localStorage.getItem("token")
if (token === undefined || token === null) {
window.location.replace("/auth/login")
return
}
fetch("https://rpl-backend-production.up.railway.app/v1/adminkursus/list", {
method: "GET",
headers: {
"Authorization": token
}
}).then(async response => {
if (response.status !== 200) {
toast.error("Failed to retrieve items")
return
}
const responsejson = await response.json()
setRows(responsejson.data)
})
}, [])
return <>
<Template>
<main className="min-h-screen px-14 py-5 bg-[#FFF6F6]">
<div className="w-full mb-2">
<span className="text-[#F875AA] font-bold text-2xl hover:cursor-pointer" onClick={(e) => {
e.preventDefault()
router.back()
}}>Back</span>
</div>
<div className="flex flex-row align-middle justify-between">
<h1 className="text-[#F875AA] font-extrabold text-5xl mb-8">Data Akun Admin</h1>
<button onClick={(e) => {
e.preventDefault();
router.push("/adminkursus/create")
}} className="bg-[#F875AA] p-4 text-lg font-bold text-white rounded-3xl">Create</button>
</div>
<table className="w-full text-center border-spacing-3 border-separate">
<thead>
<tr>
<th className="bg-[#F875AA] p-2 border border-[#F875AA]">User ID</th>
<th className="bg-[#F875AA] p-2 border border-[#F875AA]">Username</th>
<th className="bg-[#F875AA] p-2 border border-[#F875AA]">Password</th>
<th className=""></th>
</tr>
</thead>
<tbody>
{rows.filter(row => row.user_id !== 10000).map((row, index) => {
return <tr key={row.user_id}>
<td className="p-6 border border-[#F875AA] bg-white">{row.user_id}</td>
<td className="p-6 border border-[#F875AA] bg-white">{row.username}</td>
<td className="p-6 border border-[#F875AA] bg-white">{row.password_hash}</td>
<td className="px-2 flex flex-col align-middle justify-evenly space-y-2 ">
<button className="bg-[#AEDEFC] p-1 rounded-lg" onClick={(e) => {
e.preventDefault();
router.push("/adminkursus/edit/" + row.user_id)
return;
}}>Update</button>
<button data-modal-target="popup-modal" data-modal-toggle="popup-modal" className="bg-[#FFDFDF] p-1 rounded-lg" onClick={(e) => {
e.preventDefault()
setDeleteToggle(row.user_id)
}}>Delete</button>
</td>
</tr>
})}
</tbody>
</table>
<div className="flex flex-row align-middle justify-around">
<button className="bg-red-400 p-5 rounded-2xl text-white font-bold" disabled={currentPage === 1} onClick={() => {
getNextPage(currentPage - 1)
setCurrentPage(page => page - 1)
}}>Prev</button>
<span className="h-min my-auto font-bold">Page {currentPage}</span>
<button className="bg-blue-400 p-5 rounded-2xl text-white font-bold" disabled={isLastPage} onClick={() => {
getNextPage(currentPage + 1)
setCurrentPage(page => page + 1)
}}>Next</button>
</div>
</main>
{deleteToggle !== null && <div className="left-0 top-0 fixed w-screen h-screen bg-white bg-opacity-80 p-20 flex flex-col align-middle justify-center">
<div className="w-1/2 mx-auto space-y-5">
<h1 className="text-center p-10 bg-[#FFDFDF] border-2 border-[#F875AA] rounded-xl font-bold text-xl">Apakah anda yakin akan menghapus data admin kursus?</h1>
<div className="space-x-5 flex flex-row align-middle justify">
<button className="p-3 rounded-xl w-full bg-[#FFDFDF] border-2 border-[#F875AA]" onClick={(e) => {
e.preventDefault();
handleDelete()
}}>Delete</button>
<button className="p-3 rounded-xl w-full bg-[#FFDFDF] border-2 border-[#F875AA]" onClick={(e) => {
e.preventDefault()
setDeleteToggle(null)
}}>Cancel</button>
</div>
</div>
</div>}
</Template >
</>
}
export default Index
\ No newline at end of file
import Template from "@/components/template"
import { useState } from "react"
import { toast } from "react-toastify"
import { useRouter } from "next/router"
import Image from "next/image"
const Login = () => {
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
return <Template>
<main className="min-h-screen flex flex-col align-middle justify-center">
<h1 className="font-bold text-center text-3xl mb-5">Temporary login screen...</h1>
<h3 className="font-semibold text-center text-xl mb-5">geblek hirup daek jadi runtahhh</h3>
<form onSubmit={(e) => {
const router = useRouter()
const handleGoBack = () => {
router.back()
}
return (
<main className="min-h-screen px-14 py-7 bg-[#FFF6F6] flex flex-col">
<div className="fex flex-row w-full">
<button className="text-xl text-[#F875AA] font-extrabold" onClick={handleGoBack}>Back</button>
</div>
<div className="flex flex-col w-1/2 align-middle justify-around mx-auto my-auto">
<h1 className="text-center font-extrabold text-5xl text-[#F875AA]">Log In</h1>
<div className="w-full"><Image src={"/logo.png"} width={400} height={400} alt="Main Logo" className="mx-auto"/></div>
<form className="flex flex-col align-middle justify-evenly space-y-8" onSubmit={(e) => {
e.preventDefault()
const requestBody = JSON.stringify({
username, password
username,password
})
fetch("https://rpl-backend-production.up.railway.app/v1/auth/login", {
method: "POST",
body: requestBody,
headers: {
"Content-Type": "application/json"
}
}).then(async (response) => {
if (response.status !== 200) {
toast.error("Failed to login..")
return
}
const responsejson = await response.json();
const type = responsejson.data.type
const token = responsejson.data.token
localStorage.setItem("token", `${type} ${token}`)
window.location.replace("/")
return
}).catch(() => {
toast.error("Something went wrong..")
})
method: "POST",
body: requestBody,
headers: {
"Content-Type": "application/json"
}
}).then(async (response) => {
if (response.status !== 200){
toast.error("Failed to login..")
return
}
const responsejson = await response.json();
const type = responsejson.data.type
const token = responsejson.data.token
window.localStorage.setItem("token", `${type} ${token}`)
}} className="flex flex-col align-middle justify-center w-1/2 bg-slate-300 p-28 mx-auto space-y-2">
<input type="text" placeholder="Username" required className="p-2 rounded-xl" value={username} onChange={(e) => {
setUsername(e.target.value)
}} />
<input type="password" placeholder="Password" required className="p-2 rounded-xl" value={password} onChange={(e) => {
setPassword(e.target.value)
}} />
<input type="submit" className="bg-blue-500 w-1/3 p-3 mx-auto rounded-xl font-bold text-white" value={"Login"} />
fetch("https://rpl-backend-production.up.railway.app/v1/auth/verify/" + token,)
.then(async(response) =>{
const responsejson = await response.json();
if (responsejson.data.tipe_user === "OWNER"){
router.push("/dashboard/owner")
return
}
if (responsejson.data.tipe_user === "ADMIN"){
router.push("/dashboard/admin")
return
}
})
}).catch(() => {
toast.error("Something went wrong..")
})
}}>
<div className="flex flex-row align-middle justify-between ">
<span className="h-min my-auto font-extrabold text-[#F875AA] text-xl">Username</span>
<input className="w-2/3 drop-shadow-lg p-3 rounded-xl shadow shadow-red-100" type="text" placeholder="Username" required value={username} onChange={(e) => {
setUsername(e.target.value)
}}/>
</div>
<div className="flex flex-row align-middle justify-between ">
<span className="h-min my-auto font-extrabold text-[#F875AA] text-xl">Password</span>
<input className="w-2/3 drop-shadow-lg p-3 rounded-xl shadow shadow-red-100" type="password" placeholder="Password" required value={password} onChange={(e) => {
setPassword(e.target.value)
}}/>
</div>
<input type="submit" value={"Log In"} className="w-min px-20 py-3 mx-auto bg-pink-400 rounded-xl text-white font-bold text-2xl hover:cursor-pointer"/>
</form>
</div>
</main>
</Template>
)
}
export default Login
\ No newline at end of file
import Template from "@/components/templatenofooter"
import { toast } from "react-toastify"
import { useEffect, useState} from "react"
import { useRouter } from "next/router"
const DashboardOwner = () => {
const router = useRouter();
const [username, setUsername] = useState(null)
useEffect(() => {
const token = window.localStorage.getItem("token")
if (!token){
window.location.replace("/auth/login")
}
const tokenParsed = token.split(" ")[1]
fetch(`https://rpl-backend-production.up.railway.app/v1/auth/verify/${tokenParsed}`).then(async (response) => {
if (response.status !== 200){
toast.error("Failed to retrieve items")
return;
}
const responsejson = await response.json();
if (responsejson.data.tipe_user !== "ADMIN"){
window.location.replace("/auth/login")
return
}
setUsername(responsejson.data.username)
})
}, [])
return (
<Template>
<main className="min-h-screen px-14 py-10 bg-[#FFF6F6]">
<div className="text-[#F875AA] font-extrabold text-5xl mb-20 text-center">Selamat datang kembali, {username}!</div>
<div className = "flex flex-row align-middle justify-between">
{/* <div className="bg-white p-6 rounded-lg shadow-md" /> */}
</div>
<div className="w-[226px] h-[95px] left-[638px] top-[381px] absolute text-center text-pink-400 text-[32px] font-extrabold font-'Poppins'">Data<br/>Pelanggan</div>
<div className="w-[126px] h-[53px] left-[694px] top-[715px] absolute">
<div className="w-[126px] h-[53px] left-0 top-0 absolute bg-sky-200 rounded-[15px]" />
<span className="w-[84.28px] h-[28.33px] left-[21px] top-[15px] absolute text-center text-black text-base font-bold font-'Poppins'" onClick={(e) => {
e.preventDefault()
router.push("/")
}}>Ubah</span>
</div>
<img className="w-[171px] h-[171px] left-[670px] top-[497px] absolute" src="/client.png" />
</main>
</Template>
)
}
export default DashboardOwner
\ No newline at end of file
import Template from "@/components/templatenofooter"
import { toast } from "react-toastify"
import { useEffect } from "react"
import { useRouter } from "next/router"
import Image from "next/image"
const DashboardOwner = () => {
const router = useRouter();
useEffect(() => {
const token = window.localStorage.getItem("token")
if (!token) {
window.location.replace("/auth/login")
}
const tokenParsed = token.split(" ")[1]
fetch(`https://rpl-backend-production.up.railway.app/v1/auth/verify/${tokenParsed}`).then(async (response) => {
if (response.status !== 200) {
console.log(response)
toast.error("Failed to retrieve items")
return;
}
const responsejson = await response.json();
if (responsejson.data.tipe_user !== "OWNER") {
window.location.replace("/auth/login")
return
}
}).catch(error => {
console.error(error)
return
})
}, [])
return (
<Template>
<main className="min-h-screen px-28 py-28 bg-[#FFF6F6] flex flex-col align-middle space-y-20">
<h2 className="text-center text-5xl font-extrabold text-[#F875AA] ">Selamat datang kembali, Helmi!</h2>
<div className="flex flex-row align-middle justify-evenly">
<div className="bg-white rounded-xl px-5 py-10 space-y-5 flex flex-col align-middle justify-evenly shadow-xl w-1/4">
<span className="text-center font-extrabold text-xl text-[#F875AA]">Data Kelas Yang Tersedia</span>
<Image className="mx-auto" src="/todolist.png" width={99} height={100} alt="Data Kelas" />
<button className="bg-sky-200 rounded-xl font-bold text-center w-min mx-auto px-10 py-3" onClick={
()=>router.push("/kelasmengemudi")}>Ubah</button>
</div>
<div className="bg-white rounded-xl px-5 py-10 space-y-5 flex flex-col align-middle justify-evenly shadow-xl w-1/4">
<span className="text-center font-extrabold text-xl text-[#F875AA]">Akun Pengguna Admin</span>
<Image className="mx-auto" src="/setting.png" width={117} height={117} alt="Akun Pengguna Admin" />
<button className="bg-sky-200 rounded-xl font-bold text-center w-min mx-auto px-10 py-3" onClick={
()=>router.push("/adminkursus")}>Ubah</button>
</div>
<div className="bg-white rounded-xl px-5 py-10 space-y-5 flex flex-col align-middle justify-evenly shadow-xl w-1/4">
<span className="text-center font-extrabold text-xl text-[#F875AA]">Info Perusahaan dan FAQ</span>
<Image className="mx-auto" src="/briefcase.png" width={108} height={108} alt="Data Kelas" />
<button className="bg-sky-200 rounded-xl font-bold text-center w-min mx-auto px-10 py-3"onClick={
()=>router.push("/infoperusahaan")}>Ubah</button>
</div>
</div>
<div className="flex flex-row align-middle justify-center space-x-32">
<div className="bg-white rounded-xl px-5 py-10 space-y-5 flex flex-col align-middle justify-evenly shadow-xl w-1/4">
<span className="text-center font-extrabold text-xl text-[#F875AA]">Data Kendaraan</span>
<Image className="mx-auto" src="/sedan.png" width={138} height={138} alt="Data Kendaraan" />
<button className="bg-sky-200 rounded-xl font-bold text-center w-min mx-auto px-10 py-3" onClick={
()=>router.push("/kendaraan")}>Ubah</button>
</div>
<div className="bg-white rounded-xl px-5 py-10 space-y-5 flex flex-col align-middle justify-evenly shadow-xl w-1/4">
<span className="text-center font-extrabold text-xl text-[#F875AA]">Data Instruktur</span>
<Image className="mx-auto" src="/instructor.png" width={112} height={112} alt="Data Instruktur" />
<button className="bg-sky-200 rounded-xl font-bold text-center w-min mx-auto px-10 py-3"onClick={
()=>router.push("/instruktur")}>Ubah</button>
</div>
</div>
</main>
</Template>
)
}
export default DashboardOwner
\ No newline at end of file
public/back.png

514 B

public/briefcase.png

8.43 KiB

public/client.png

12.7 KiB

public/instructor.png

9.5 KiB

public/sedan.png

5.76 KiB

public/setting.png

7.08 KiB

public/todolist.png

4.37 KiB

0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment