Skip to content

Commit

Permalink
feat: add theme, and verifikasi page
Browse files Browse the repository at this point in the history
Signed-off-by: hanifdwyputras <hanifdwyputrasembiring@gmail.com>
  • Loading branch information
hansputera committed Jun 4, 2023
1 parent eda089f commit 5b3488c
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 30 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"eslint": "8.41.0",
"eslint-config-next": "13.4.4",
"formik": "^2.4.1",
"fuse.js": "^6.6.2",
"js-cookie": "^3.0.5",
"next": "13.4.4",
"postcss": "8.4.23",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

99 changes: 88 additions & 11 deletions src/app/me/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import React from 'react'
import { useSessionStore } from '@/contexts/sessionContext'
// import Image from 'next/image'
import Link from 'next/link'
import useSWR from 'swr'
import { fetcher } from '@/lib/fetcher';

type StatsJson = {
archives: {
all: number;
complete: number;
speciifed: Record<string, number>;
specified: Record<string, number>;
daily: {
todayCount: number;
lastWeek: number;
Expand All @@ -18,17 +20,13 @@ type StatsJson = {

export default function MePage() {
const session = useSessionStore();
const [data, setData] = React.useState();
const { data, isLoading } = useSWR<StatsJson>(session.token ? '/api/stats' : null, url => fetcher(url, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${session.token}`,
}
}));

React.useEffect(() => {
if (session.token)
fetch('/api/stats', {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${session.token}`,
}
}).then(r => r.json()).then(setData);
}, [session?.token]);
return (
<main>
<div className="hero min-h-screen bg-base-200">
Expand All @@ -44,6 +42,85 @@ export default function MePage() {
<Link className="btn btn-secondary" href={'/terverifikasi'}>terverifikasi</Link>
</div>
</div>
{!isLoading && data?.archives && !('errors' in data) && (
<div className="grid lg:grid-cols-1 grid-cols-2 gap-4">
<div className="stats stats-vertical lg:stats-horizontal">
<div className="stat">
<h1 className="stat-title">
Total Pendaftar
</h1>
<p className="stat-value">
{data?.archives.all.toString() || '0'}
</p>
</div>

<div className="stat">
<h1 className="stat-title">
Berkas Lengkap ({Math.floor(
((data?.archives.complete || 0) / (data?.archives.all || 0)) * 100
)}%)
</h1>
<p className="stat-value">
{data?.archives.complete.toString() || '0'}
</p>
</div>

<div className="stat">
<h1 className="stat-title">
Berkas Belum Lengkap ({Math.floor(
((data ? (data?.archives.all - data?.archives.complete) : 0) / (data?.archives.all || 0)) * 100
)}%)
</h1>
<p className="stat-value">
{data ? (data.archives.all - data.archives.complete).toString() : '0'}
</p>
</div>
</div>
<div className="stats stats-vertical lg:stats-horizontal">
<div className="stat">
<h1 className="stat-title">
Pendaftar Hari Ini
</h1>
<p className="stat-value">
{data?.archives.daily.todayCount.toString() || '0'}
</p>
</div>

<div className="stat">
<h1 className="stat-title">
Pendaftar Minggu Ini
</h1>
<p className="stat-value">
{data?.archives.daily.lastWeek.toString() || '0'}
</p>
</div>
</div>
<div className="stats stats-vertical lg:stats-horizontal">
{Object.entries(data?.archives.specified || {}).map(x => (
<div className={`stat${x[0] !== 'zonasi' ? ' hidden lg:block' : ''}`} key={x[0]}>
<h1 className="stat-title">
{x[0][0].toUpperCase() + x[0].slice(1)} ({Math.floor((x[1] / data?.archives.all!) * 100)}%)
</h1>
<p className="stat-value">
{x[1].toString() || '0'}
</p>
</div>
))}
</div>
{Object.entries(data?.archives.specified || {}).slice(1).map(x => (
<div key={x[0]} className="stats stats-vertical lg:stats-horizontal lg:hidden">
<div className="stat">
<h1 className="stat-title">
{x[0][0].toUpperCase() + x[0].slice(1)} ({Math.floor((x[1] / data?.archives.all!) * 100)}%)
</h1>
<p className="stat-value">
{x[1].toString() || '0'}
</p>
</div>
</div>
))}
</div>
)}
</div>
</div>
</main>
Expand Down
136 changes: 136 additions & 0 deletions src/app/verifikasi/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
'use client';

import React from 'react'
import { useSessionStore } from '@/contexts/sessionContext';
import { fetcher } from '@/lib/fetcher';
import useSWR from 'swr'
import Fuse from 'fuse.js'

export default function VerifikasiPage() {
const session = useSessionStore();
const [currentPage, setCurrentPage] = React.useState(1);
const [selectedData, setSelectedData] = React.useState<any[]>([]);
const { data, isLoading } = useSWR(session.token ? `/api/archives?perPage=10&page=${currentPage}` : null, url => fetcher(url, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${session.token}`
},
}).then(r => r.data), {
onSuccess(data) {
setSelectedData(data.archives);
},
});
const resolveDoc = (t: string) => {
switch(t) {
case 'prestasi':
return 'certificate_path';
case 'afirmasi':
return 'kip_path';
case 'mutasi':
return 'mutation_path';
default:
return 'kk_path';
}
}

React.useEffect(() => {
setSelectedData(data?.archives || []);
}, [data]);


const cariForm = (query: string) => {
if (!query.length) {
setSelectedData(data?.archives || []);
return;
}
const fuse = new Fuse(data?.archives || [], {
keys: ['nisn', 'name', 'nik', 'birthday', 'school'],
});

const results = fuse.search(query);
setSelectedData(results.map(x => x.item));
}
return (
<div>
<div className="lg:px-40">
{!isLoading && (
<div className="join join-vertical lg:join-horizontal">
<div>
<div>
<input className="input join-item" placeholder="Cari NISN/Nama" onChange={(ev) => cariForm(ev.target.value)}/>
</div>
</div>
<div className="join-item">
<div className="join">
<button className="join-item btn">«</button>
<button className="join-item btn btn-neutral">{currentPage}</button>
<button className="join-item btn">{data?.nextPage}</button>
<button className="join-item btn btn-disabled">...</button>
<button className="join-item btn">{data?.totalPage}</button>
<button className="join-item btn">»</button>
</div>
</div>
</div>
)}
<div className="overflow-x-auto">
{isLoading && <h1 className="text-2xl font-sans text-center">Loading <span className="loading loading-dots loading-lg"></span></h1>}
{!isLoading && data && (
<>
<table className="table">
{/* head */}
<thead>
<tr className="lg:text-lg">
<th>Berkas/Kelamin</th>
<th>Nama</th>
<th>NISN</th>
<th>NIK</th>
<th>Nama Ayah</th>
<th>Nama Ibu</th>
<th>Asal Sekolah</th>
<th>TTL</th>
<th>Jalur</th>
<th>Agama</th>
<th>SKHU</th>
<th>Foto Pas</th>
<th>KK/Sertifikat/SK Mutasi/KIP</th>
</tr>
</thead>
<tbody>
{selectedData.map((archive: any) => (
<tr key={archive.id}>
<td>{archive.id.split('-')[0]}/{archive.gender}</td>
<td>{archive.name}</td>
<td>{archive.nisn}</td>
<td>{archive.nik}</td>
<td>{archive.father_name}</td>
<td>{archive.mother_name}</td>
<td>{archive.school}</td>
<td>{archive.birthday}</td>
<td>{archive.type.toUpperCase()}</td>
<td>{archive.religion.toUpperCase()}</td>
<td>
{archive.skhu_path ? <a className="text-blue-600" href={`https://ppdb.api.sman3palu.sch.id/${archive.skhu_path?.replace('public', 'storage')}`} target="_blank">
Visit
</a> : <p className="text-gray-400">-</p>}
</td>
<td>
{archive.photo_path ? <a className="text-blue-600" href={`https://ppdb.api.sman3palu.sch.id/${archive.photo_path?.replace('public', 'storage')}`} target="_blank">
Visit
</a> : <p className="text-gray-400">-</p>}
</td>
<td>
{archive[resolveDoc(archive.type)] ? <a className="text-blue-600" href={`https://ppdb.api.sman3palu.sch.id/${archive[resolveDoc(archive.type)]?.replace('public', 'storage')}`} target="_blank">
Visit
</a> : <p className="text-gray-400">-</p>}
</td>
</tr>
))}
</tbody>
</table>
</>
)}
</div>
</div>
</div>
)
}
6 changes: 4 additions & 2 deletions src/components/container.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useThemeSwitcher } from '@/contexts/themeContext';
import React from 'react';

export const Container = ({ children, isCenter = true }:{ children: React.ReactNode, isCenter?: boolean; }) => {
export const Container = ({ children }:{ children: React.ReactNode }) => {
const themer = useThemeSwitcher();
return (
<div className={`md:mx-auto bg-[#091426] shadow-md rounded-md md:w-1/2 md:h-1/2 p-5 flex flex-col items-center`}>
<div className={`mt-10 md:mx-auto ${themer.theme === 'dracula' ? 'bg-[#091426]' : 'bg-[#F6F6F6]'} shadow-md rounded-md md:w-1/2 md:h-1/2 p-5 flex flex-col items-center`}>
{children}
</div>
)
Expand Down
14 changes: 8 additions & 6 deletions src/components/forms/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Cookies from 'js-cookie'
import { FormField } from './field';
import { useRouter } from 'next/navigation'
import { useSessionStore } from '@/contexts/sessionContext'
import { useThemeSwitcher } from '@/contexts/themeContext'

type DataProps = {
isError: boolean;
Expand All @@ -23,6 +24,7 @@ const righteous = Righteous({
});
export const LoginForm = () => {
const session = useSessionStore();
const themer = useThemeSwitcher();
const [data, setData] = React.useState<DataProps>({
isError: false,
});
Expand Down Expand Up @@ -75,7 +77,7 @@ export const LoginForm = () => {
if (res.errors || res.error) {
setData({
isError: true,
message: res.error || res.message,
message: res.error || res.message || res.errors,
});
actions.setSubmitting(false);
} else {
Expand Down Expand Up @@ -120,16 +122,16 @@ export const LoginForm = () => {
{data.message ? (
<div className="text-center mt-2">
<div className={`alert alert-${data.isError ? 'error' : 'success'} shadow-lg`}>
<div>
<svg xmlns="http://www.w3.org/2000/svg" className="stroke-current flex-shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
<span>{data.isError ? 'Error' : 'Sukses'}! {data.message}</span>
</div>
<div className="flex flex-row justify-center items-center">
<svg xmlns="http://www.w3.org/2000/svg" className="stroke-current flex-shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
{data.isError ? 'Error' : 'Sukses'}! {data.message.trim()}
</div>
</div>
</div>
) : null}
<div className="text-center">
<div className="text-center">
<button disabled={props.isSubmitting} className={`btn border-none mt-2 bg-[#1b30a5]${props.isSubmitting ? ' loading' : ''}`}>login</button>
<button disabled={props.isSubmitting} className={`btn border-none mt-2 bg-[#1b30a5]${themer.theme === 'lofi' ? 'text-white' : ''}${props.isSubmitting ? ' loading' : ''}`}>login</button>
</div>
</div>
</Form>
Expand Down
Loading

0 comments on commit 5b3488c

Please sign in to comment.