Skip to content

Commit

Permalink
Updated dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
lenn0n13 committed Jul 18, 2024
1 parent 0737694 commit ff66e04
Show file tree
Hide file tree
Showing 17 changed files with 444 additions and 105 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
.env
142 changes: 95 additions & 47 deletions app/(pages)/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,102 @@
import React from 'react'
import Card from '../../components/Card/Card'
import { HomeModernIcon, CreditCardIcon, UserGroupIcon, UsersIcon, BuildingOffice2Icon } from '@heroicons/react/24/solid'
import Logout from './logout'
'use client'
import React, { useEffect, useState } from 'react'
import Image from 'next/image'
import MainWrapper from '@/app/components/PageWrapper/MainWrapper'
import { useAxios } from "@hooks/all"
import { formatRawNumber } from '@/app/utils/validator'
import ReceiveMoneyIcon from "@/public/receive-money.svg"
import CollectMoneyIcon from "@/public/collect-money.svg"
import AvailableUnitIcon from "@/public/available-unit.svg"
import TotalClientIcon from "@/public/total-client.svg"
import TotalAgentIcon from "@/public/total-agent.svg"
import TopAgentIcon from "@/public/top-agent.svg"
import TopAgentCollectible from "@/public/agent-collectible.svg"

type dataProps = {
overall_lot: {
collectibles: number,
receivables: number
},
available_units: number,
client_count: number,
agent_count: number,
top_agent: any
}
const Dashboard = () => {
const { get } = useAxios()
const [data, setData] = useState<dataProps>()

return (
<div className="">
<div className="h-[100vh]">
<div className=" flex items-center justify-center h-[100%]">
<div className="grid grid-cols-12 gap-4 mx-4">
<div className="col-span-3 w-[300px] py-5">
<Card>
<div className="font-bold text-xl">Admin Panel</div>
<div className="border-b border-slate-400 mb-5 mt-3 opacity-30"></div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-green-600 dark:text-green-500" role="button">
<HomeModernIcon className="h-6 w-6" />
<div className="font-bold">Dashboard</div>
</div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-slate-700 dark:text-slate-200" role="button">
<CreditCardIcon className="h-6 w-6" />
<div className="">Payments</div>
</div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-slate-700 dark:text-slate-200" role="button">
<UserGroupIcon className="h-6 w-6" />
<div className="">Client</div>
</div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-slate-700 dark:text-slate-200" role="button">
<UsersIcon className="h-6 w-6" />
<div className="">Agent</div>
</div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-slate-700 dark:text-slate-200" role="button">
<BuildingOffice2Icon className="h-6 w-6" />
<div className="">Branch</div>
</div>
<div className="border-b border-slate-400 mb-5 mt-3 opacity-30"></div>
<Logout/>
</Card>
</div>
<div className="col-span-9 max-h-[80vh] overflow-hidden py-5">
<div className="">
<Card>
<div className="font-bold">Contents</div>
</Card>
</div>
</div>
</div>
</div>
const handleGetStatistics = async () => {
const response = await get({
url: "/statistics",
requiresAuth: true,
authPrefix: 'Bearer'
})
if (response.result) {
setData(response)
}
}

const formatNumber = (num: number, dec: number = 2, lead: string = '₱') => {
return formatRawNumber(num, dec, lead)
}

const Item = ({ children, title, className, icon }: { children: React.ReactNode, title: string, className?: string, icon: HTMLImageElement }) => {
return <div className={`flex gap-3 items-center justi ${className}`}>
<Image src={icon} className='hidden sm:block h-[30px] w-[30px] md:h-[50px] md:w-[50px] ' alt="icon" />
<div className={`flex flex-col`}>
<div className="font-bold text-[16px] lg:text-[17px]">{title}</div>
<div className="text-[14px] md:text-[20px] ">{children}</div>
</div>
</div>
)
}

useEffect(() => {
handleGetStatistics()
}, [])


if (!data) {
return (<>Loading....</>)
} else {
return (
<MainWrapper>
<div className='flex items-center gap-2' >
<div className="font-bold text-xl dark:text-white mt-3 pb-3">My Dashboard</div>
</div>
<div className="border-b border-slate-400 mb-5 mt-3 opacity-30"></div>
<div className='grid grid-cols-2 md:grid-cols-3'>
<Item title="Total Collectibles" className='mb-12' icon={CollectMoneyIcon}>
<span className='text-green-700 dark:text-green-500 font-bold'>{formatNumber(data.overall_lot.collectibles)}</span>
</Item>
<Item title="Total Receivables" className='mb-12' icon={ReceiveMoneyIcon}>
<span className='text-orange-600 dark:text-orange-500 font-bold'>{formatNumber(data.overall_lot.receivables)}</span>
</Item>
<Item title="Units" className='mb-12' icon={AvailableUnitIcon}>
<span className={`font-bold ${data.available_units === 0 ? 'text-red-700 dark:text-red-500' : ''}`}>
{formatNumber(data.available_units, 0, '')}</span>
</Item>
<Item title="Total Client" className='mb-12' icon={TotalClientIcon}>
<span className='dark:text-white'>{formatNumber(data.client_count, 0, '')}</span>
</Item>
<Item title="Total Agent" className='mb-12' icon={TotalAgentIcon}>
<span className='dark:text-white'>{formatNumber(data.agent_count, 0, '')}</span>
</Item>

</div>
<div className='grid grid-cols-2 md:grid-cols-3'>
<Item title="Top Agent" icon={TopAgentIcon}>
<span className='dark:text-white'>{data.top_agent[0].agent_name}</span>
</Item>
<Item title="Collectibles" icon={TopAgentCollectible}>
<span className='dark:text-white'> {formatNumber(data.top_agent[0].collectibles)}</span>
</Item>
</div>
</MainWrapper>
)
}


}

export default Dashboard
109 changes: 56 additions & 53 deletions app/(pages)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import Image from "next/image"
import { useState } from "react";
import { useRouter } from 'next/navigation'
import { useAxios, useCookie, useDispatch } from "@hooks/all";
import { useAxios, useCookie, useDispatch, useEncryption } from "@hooks/all";
import { openModal, closeModal } from "@/app/store/reducers/modal";

import Input from "@/app/components/Forms/Input";
Expand All @@ -16,6 +16,7 @@ import ErrorModal from "@/app/components/Modal/ErrorModal";
export default function Login() {
const router = useRouter()
const dispatch = useDispatch()
const { encode } = useEncryption()
const { post, isLoading } = useAxios()
const { setCookie } = useCookie()
const [password, setPassword] = useState<string | number>()
Expand All @@ -38,7 +39,7 @@ export default function Login() {
// Set token to browser's cookies
setCookie({
name: 'user_token',
value: response.access,
value: encode(response.access),
days: 7
})
// Redirect to dashboard
Expand All @@ -51,69 +52,71 @@ export default function Login() {
}

return (
<div className="flex items-center justify-center h-[100vh]">

<>
<ErrorModal
message="Incorrect password, please try again."
>
<Button
buttonStyle="solid"
type="button"
className="!bg-gray-300 !border-none !text-black"
onClick={() => { dispatch(closeModal()) }}>Close</Button>
className="!bg-gray-200 !border-none !text-black hover:!bg-gray-300"
onClick={() => { dispatch(closeModal()) }}>
Close
</Button>
</ErrorModal>
<div className="flex items-center justify-center h-[100vh]">
<Card>
<div className="flex flex-col m-auto w-100 items-center xl:w-[300px] rounded-xl ">
<div className="">
<Image className="object-cover w-[100px] h-[100px] opacity-90" src={NRLogo} alt="" />
</div>
<div className="title font-bold text-2xl dark:text-white">NR Login </div>
<div className="text-sm">Welcome</div>
<Form onSubmit={handleLogin} className=" w-full">
<Input
autoFocus
value={password}
onChange={(password: string | number) => { setPassword(password) }}
type="password"
wrapperClassName="mt-5"
placeholder="Enter Admin Password"
/>

<Card>
<div className="flex flex-col m-auto w-100 items-center xl:w-[300px] rounded-xl ">
<div className="">
<Image className="object-cover w-[100px] h-[100px] opacity-90" src={NRLogo} alt="" />
</div>
<div className="title font-bold text-2xl dark:text-white">NR Login </div>
<div className="text-sm">Welcome</div>
<Form onSubmit={handleLogin} className=" w-full">
<Input
autoFocus
value={password}
onChange={(password: string | number) => { setPassword(password) }}
type="password"
wrapperClassName="mt-5"
placeholder="Enter Admin Password"
/>
<div className="mt-2">
<Button buttonStyle="solid" type="submit" isLoading={isLoading}>
<div className="flex items-center justify-center gap-2">
LOGIN
<svg className="flex-shrink-0 size-4"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round">
<path d="M5 12h14"></path>
<path d="m12 5 7 7-7 7"></path>
</svg>
</div>
</Button>
</div>
</Form>

<div className="mt-2">
<Button buttonStyle="solid" type="submit" isLoading={isLoading}>
<div className="flex items-center justify-center gap-2">
LOGIN
<svg className="flex-shrink-0 size-4"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round">
<path d="M5 12h14"></path>
<path d="m12 5 7 7-7 7"></path>
</svg>
</div>
</Button>
</div>
</Form>
<Link>
<div className="mt-5 font-bold text-[14px]" >
Forgot Password?
</div>
</Link>

<Link>
<div className="mt-5 font-bold text-[14px]" >
Forgot Password?
<div className="mt-4 text-[14px] text-center">
Copyright © {getCurrentYear()} <span className="">NR Realty Development</span>
</div>
</Link>

<div className="mt-4 text-[14px] text-center">
Copyright © {getCurrentYear()} <span className="">NR Realty Development</span>
</div>
</div>

</Card>
</div>
</Card>
</div>
</>
);
}
2 changes: 1 addition & 1 deletion app/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const Modal = ({

return createPortal(<div className="relative">
<div id="hs-vertically-centered-modal" className={`hs-overlay size-full fixed top-0 start-0 ${show() ? 'z-[80]' : 'z-0 duration-500 ease-out transition-all'} overflow-x-hidden overflow-y-auto pointer-events-none`}>
<div className={`${show() ? ' mt-7 opacity-100 duration-500' : ' opacity-0 mt-0 duration-500'} p-5 ease-out transition-all ${modalSize[size]} min-h-[calc(100%-3.5rem)] flex items-center`}>
<div className={`${show() ? 'mt-7 opacity-100' : 'mt-0 opacity-0'} duration-500 p-5 ease-out transition-all ${modalSize[size]} min-h-[calc(100%-3.5rem)] flex items-center`}>
<div className=" bg-opacity-90 w-full flex flex-col bg-white border shadow-sm rounded-xl pointer-events-auto dark:bg-neutral-800 dark:border-neutral-700 dark:shadow-neutral-700/70">
<div className={`justify-between items-center py-3 px-4 border-b dark:border-neutral-700 ${hideHeader ? 'hidden' : 'flex'}`}>
<h3 className="font-bold text-gray-800 dark:text-white">
Expand Down
File renamed without changes.
62 changes: 62 additions & 0 deletions app/components/PageWrapper/MainWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

import Card from '@/app/components/Card/Card'
import Logout from '@/app/components/PageWrapper/Logout'
import Image from "next/image"
import { HomeModernIcon, CreditCardIcon, UserGroupIcon, UsersIcon, BuildingOffice2Icon } from '@heroicons/react/24/solid'

import NRLogo from "@/public/nr.png"

type MainWrapperProps = {
children: React.ReactNode
}
const MainWrapper = ({ children }: MainWrapperProps) => {

return (
<>
<div className=" flex lg:items-center pt-12 lg:pt-0 justify-center h-[100%] lg:h-[100vh]">
<div className="flex flex-row flex-wrap justify-center w-full gap-4 mx-4">
<div className="basis-full lg:basis-1/5 py-5">
<Card>
<div className='flex items-center gap-2' >
<Image className="object-cover w-[50px] h-[50px] opacity-90" src={NRLogo} alt="" />
<div className="font-bold text-xl dark:text-white"> NR Realty</div>
</div>
<div className="border-b border-slate-400 mb-5 mt-3 opacity-30"></div>
<div className="flex flex-row lg:flex-col justify-between">
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-green-600 dark:text-green-500" role="button">
<HomeModernIcon className="h-6 w-6" />
<div className="font-bold hidden md:block">Dashboard</div>
</div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-slate-700 dark:text-slate-200" role="button">
<CreditCardIcon className="h-6 w-6" />
<div className="font-bold hidden md:block">Payments</div>
</div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-slate-700 dark:text-slate-200" role="button">
<UserGroupIcon className="h-6 w-6" />
<div className="font-bold hidden md:block">Client</div>
</div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-slate-700 dark:text-slate-200" role="button">
<UsersIcon className="h-6 w-6" />
<div className="font-bold hidden md:block">Agent</div>
</div>
<div className="flex flex-row gap-2 mb-4 hover:text-slate-400 text-slate-700 dark:text-slate-200" role="button">
<BuildingOffice2Icon className="h-6 w-6" />
<div className="font-bold hidden md:block">Branch</div>
</div>
</div>
<div className="border-b border-slate-400 mb-5 mt-3 opacity-30"></div>
<Logout />
</Card>
</div>
<div className="basis-full lg:basis-3/4 xl:basis-2/4 overflow-hidden py-5">
<Card>
{children}
</Card>
</div>
</div>
</div>
</>
)
}

export default MainWrapper
4 changes: 2 additions & 2 deletions app/components/PageWrapper/PageWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import Auth from "@/app/components/Auth/Auth";
const page = ({ children }: { children: React.ReactNode }) => {
return (
<div className='relative h-[100vh] overflow-y-scroll'>
<div className="bg-land dark:bg-dark-land bg-cover bg-fixed text-slate-800">
<div className="bg-land dark:bg-dark-land bg-cover bg-fixed text-slate-800 min-h-[100%]">
<Auth>
{children}
</Auth>
<div className="absolute bottom-0 w-full">
<div className="mt-[10px] lg:mt-[-26px] w-full">
<div className="flex items-center text-center text-[12px] justify-center text-white font-bold pb-2">
Powered By NextJS, TypeScript, Tailwind and Redux.
</div>
Expand Down
1 change: 1 addition & 0 deletions app/hooks/useAxios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const useAxios = () => {
}

const checkIfUnauthorized = (statusCode: number) => {
return
if (statusCode === 401 && window.location.pathname !== '/login' && window.location.pathname !== '/') {
removeAllToken()
const hostName = String(window.location.hostname).replace("dev", "").replace("staging", "")
Expand Down
Loading

0 comments on commit ff66e04

Please sign in to comment.