Skip to content

Commit

Permalink
Added search and admin dashboard, implemented SWR for data fetching
Browse files Browse the repository at this point in the history
  • Loading branch information
Adityapnn811 committed Jul 29, 2022
1 parent a33a805 commit 27005f3
Show file tree
Hide file tree
Showing 15 changed files with 453 additions and 94 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ Check out our [Next.js deployment documentation](https://nextjs.org/docs/deploym
Ganti background global di layout.jsx

## How to run
`npm run dev`
`npm run dev`

## run redis
docker run -p 6379:6379 --name my-redis -d redis
7 changes: 4 additions & 3 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
- buat dashboard admin dan user biasa
- responsive
- Setup CI
- Kurang jwt
- error message saat login
- Kurang page verifyUser
- Kurang jwt (udah)
- error message saat login (udah)
- Kurang page verifyUser (udah)
- Tampilin dropdown mata uang yang tersedia apa aja, trus nanti konversi dari mata uang asing ke IDR dari frontend aja

Homenya admin itu search user
homenya user itu profil dan saldo
Expand Down
48 changes: 48 additions & 0 deletions components/AdminDashboard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import SearchBar from "./SearchBar"
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import { getCookie, hasCookie } from 'cookies-next';
import UserCard from "./UserCard";
import Bluebird from "bluebird";
import redis from 'redis'
import useSWR from "swr";
import next from "next";

// DONT FORGET TO RETURN in fetcher
const fetcher = async () => {
return fetch('https://dondra-backend.herokuapp.com/getAllUsers', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${getCookie('token')}`,
'Access-Control-Allow-Origin': 'https://dondra.vercel.app/'
},
}).then(res =>
res.json()
)
}
const url = 'https://dondra-backend.herokuapp.com/getAllUsers'

export default function AdminDashboard(){
const router = useRouter()
const [search, setSearch] = useState('')
useEffect(() => {
if (!hasCookie('token')) {
router.push("/login")
}
})
// Get users data from API using SWR
const {data: unverifiedUsers, _error} = useSWR(url, fetcher)

return(
<div className="my-4 justify-center md:mx-10 md:w-2/3 md:self-center rounded-lg flex flex-col">
<SearchBar onChangeHandler={setSearch}/>
{unverifiedUsers ? unverifiedUsers.map(user => {
if (user.nama.includes(search) || user.username.includes(search) || user.id.toString().includes(search)) {
return <UserCard nama={user.nama} id={user.id} photo={user.fotoKTP} username={user.username} saldo={user.saldo} isVerified={user.isVerified} key={user.id}/>
}
}) : <></>}
</div>
)
}
18 changes: 9 additions & 9 deletions components/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ function isAdmin(){

function Navbar(){
const nama = getCookie('nama');
const roleAdmin = isAdmin()
if (roleAdmin) {

if (isAdmin()) {
return (
<div className="flex flex-col">
<nav className="bg-primary border-gray-200 dark:bg-gray-900">
Expand All @@ -41,14 +41,14 @@ function Navbar(){
<nav className="bg-secondary w-full md:mx-10 md:w-2/3 md:self-center rounded-md">
<div className="py-3 mx-auto">
<div className="flex items-center justify-center">
<ul className="flex flex-row mt-0 mr-6 space-x-2 md:space-x-8 text-sm md:text-lg font-medium">
<li className="text-gray-900 font-semibold p-2 hover:bg-gray-200 hover:rounded-md">
<Link href="/" className="text-gray-900 font-semibold p-2 hover:bg-gray-200 hover:rounded-md" aria-current="page">Home</Link>
<ul className="flex flex-row mt-0 space-x-2 md:space-x-8 text-sm md:text-lg font-medium">
<li className="text-gray-900 font-semibold p-1 hover:bg-gray-200 hover:rounded-md">
<Link href="/"aria-current="page">Home</Link>
</li>
<li className="text-gray-900 font-semibold p-2 hover:bg-gray-200 hover:rounded-md">
<Link href="verifyUser" className="text-gray-900 font-semibold p-2 hover:bg-gray-200 hover:rounded-md">Verify User</Link>
<li className="text-gray-900 font-semibold p-1 hover:bg-gray-200 hover:rounded-md">
<Link href="/verifyUser">Verify User</Link>
</li>
<li className="text-gray-900 font-semibold p-2 hover:bg-gray-200 hover:rounded-md">
<li className="text-gray-900 font-semibold p-1 hover:bg-gray-200 hover:rounded-md">
<Link href="#" >Verify Transaction</Link>
</li>
</ul>
Expand Down Expand Up @@ -80,7 +80,7 @@ function Navbar(){
<nav className="bg-secondary w-full md:mx-10 md:w-2/3 md:self-center rounded-md">
<div className="py-3 mx-auto">
<div className="flex items-center justify-center">
<ul className="flex flex-row mt-0 mr-6 space-x-2 md:space-x-8 text-sm md:text-lg font-medium">
<ul className="flex flex-row mt-0 space-x-2 md:space-x-8 text-sm md:text-lg font-medium">
<li className="text-gray-900 font-semibold p-2 hover:bg-gray-200 hover:rounded-md">
<Link href="/" className="text-gray-900 font-semibold p-2 hover:bg-gray-200 hover:rounded-md" aria-current="page">Home</Link>
</li>
Expand Down
37 changes: 37 additions & 0 deletions components/SearchBar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useRef } from "react";

function SearchBar({onChangeHandler}) {

const clickPoint = useRef();
const handleFocus = () => {
clickPoint.current.style.display = "none";
};

const handleBlur = () => {
clickPoint.current.style.display = "block";
};

const changeHandler = (e) => {
onChangeHandler(e.target.value);
}

return (
<div className="items-center px-2 md:px-0 flex h-fit w-full justify-center" >
<div className="relative w-full flex">
<div className="absolute top-3 left-3 items-center" ref={clickPoint}>
<svg className="w-5 h-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20" xmlns="http:https://www.w3.org/2000/svg"><path fillRule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clipRule="evenodd"></path></svg>
</div>
<input
type="text"
className="block p-2 pl-10 w-70 text-gray-900 bg-gray-50 w-full rounded-lg border border-gray-300 focus:pl-3"
placeholder="Search name, id, username"
onFocus={handleFocus}
onBlur={handleBlur}
onChange={changeHandler}
/>
</div>
</div>
);
}

export default SearchBar
18 changes: 18 additions & 0 deletions components/UserCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default function UserCard({photo, nama, id, username, saldo, isVerified}) {
return (
<div className="bg-secondary my-4 mx-3 py-2 md:w-full md:mx-10 md:self-center rounded-lg flex flex-col md:flex-row">
<div className="align-center">
{photo ? <img alt="fotoKTP" src={photo} width="250px" height="30px" className="mr-2 rounded-lg m-3"/> : <>fotoKTP</>}
</div>
<div className={`ml-4 flex flex-1 flex-row content-between w-auto`}>
<div className="flex flex-col content-between m-3 grow">
<h1 className="text-2xl font-semibold mb-2">{nama}</h1>
<p className={`text-md md:text-xl text-black flex`}><div className="w-1/4">ID</div><div>: {id}</div></p>
<p className={`text-md md:text-xl text-black flex`}><div className="w-1/4">Username</div><div>: {username}</div></p>
<p className={`text-md md:text-xl text-black flex`}><div className="w-1/4">Saldo</div><div>: {saldo}</div></p>
<p className={`text-md md:text-xl text-black flex`}><div className="w-1/4">Status</div><div>: {isVerified ? "Sudah Terverifikasi" : "Belum Terverifikasi"}</div></p>
</div>
</div>
</div>
)
}
46 changes: 34 additions & 12 deletions components/VerifyingUserCard.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,42 @@
import Image from "next/image"
import { getCookie } from "cookies-next"
import Router from "next/router"

export default function VerifyingUserCard({photo, nama, id, username}){
const handleVerify = async () => {
await fetch(`https://dondra-backend.herokuapp.com/verifyUser/${id}`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${getCookie('token')}`,
'Access-Control-Allow-Origin': 'https://dondra.vercel.app/'
},
}).then(res => {
res.json().then(data => {
if (data.success) {
Router.push("/verifyUser")
} else {
alert('User failed to verify')
}
})
})
}


export default function VerifyingUserCard({className, photo, bankName, cardNumber, cardName, currency, width, height, bankTextSize, textSize}){
return (
<div className={className ? `p-4 flex flex-row ${className}` : "bg-white flex w-full m-3 pr-5"}>
<div className="bg-secondary my-4 mx-3 md:mx-10 md:w-2/3 md:self-center rounded-lg flex flex-col md:flex-row">
<div className="align-center">
{photo ? <image src={photo} width={width} height={height} className="mr-2 rounded-lg"/> : <>photo</>}
{photo ? <img alt="fotoKTP" src={photo} width="250px" height="30px" className="mr-2 rounded-lg m-3"/> : <>fotoKTP</>}
</div>
<div className={`ml-4 flex flex-1 flex-col content-between w-auto`}>
<div className="flex flex-row flex-1 w-full justify-between">
<h1 className={` ${bankTextSize} font-bold`}>{bankName}</h1>
<div>
<button className="mr-2">Verify</button>
</div>
<div className={`ml-4 flex flex-1 flex-row content-between w-auto`}>
<div className="flex flex-col content-between m-3 grow">
<h1 className="text-2xl font-semibold">{nama}</h1>
<p className={`text-md md:text-xl text-black`}>{id}</p>
<p className={`text-md md:text-xl text-black`}>{username}</p>
</div>
<div className="flex flex-col content-between">
<p className={` ${textSize} text-gray-500`}>{cardNumber} - {cardName}</p>
<p className={` ${textSize} text-gray-500`}>{currency}</p>
<div className="flex ">
<button className="text-xl m-4 bg-green-500 py-2 px-4 rounded-lg hover:bg-emerald-500 text-white font-semibold border-green-500 border-2" onClick={handleVerify}>Verify</button>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 27005f3

Please sign in to comment.