Skip to content

Commit

Permalink
Merge pull request #3 from hduoc2003/feature/create-header-and-footer
Browse files Browse the repository at this point in the history
#2 done
  • Loading branch information
hduoc2003 authored Oct 17, 2023
2 parents 11a0330 + f75f1f4 commit a7d3acf
Show file tree
Hide file tree
Showing 27 changed files with 1,502 additions and 8 deletions.
Empty file removed app/(user)/blank.tsx
Empty file.
22 changes: 19 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
'use client';
import Header from '@/components/layouts/Header'
import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import Footer from '@/components/layouts/Footer'
import { ReduxProvider } from '@/redux/provider';
import NavBar from '@/components/layouts/NavBar';
import { THEME } from '@/styles/theme';
import { MAIN_FONT } from '@/styles/fonts';

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
title: 'UETable',
Expand All @@ -16,7 +21,18 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<body className={MAIN_FONT.className}>
<ReduxProvider>
<div className='flex'>
<NavBar />
<div className='w-full'>
<Header />
{children}
<Footer />
</div>
</div>
</ReduxProvider>
</body>
</html>
)
}
9 changes: 9 additions & 0 deletions app/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client';

export default function Loading() {
return (
<div>
<h1>Loading</h1>
</div>
);
}
10 changes: 9 additions & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import Image from 'next/image'
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })

export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<main className={`flex min-h-screen flex-col items-center justify-between p-24`}>
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
Get started by editing&nbsp;
Expand Down Expand Up @@ -111,3 +113,9 @@ export default function Home() {
</main>
)
}

// export default function Home() {
// return (
// <main></main>
// )
// }
7 changes: 7 additions & 0 deletions app/signin/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export default function SignIn() {
return (
<div>SignIn</div>
)
}
7 changes: 7 additions & 0 deletions app/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export default function SignUp() {
return (
<div>SignUp</div>
)
}
Empty file removed components/blank.tsx
Empty file.
19 changes: 19 additions & 0 deletions components/common/SearchBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Input } from 'antd'
import React from 'react'
import { BiSearchAlt } from "react-icons/bi";

export default function SearchBar({
onSearch
}: {
onSearch: (value: string) => void
}): React.JSX.Element {
return (
<Input.Search
placeholder='Tìm kiếm môn học'
allowClear
onSearch={onSearch}
size='large'
style={{ width: 400 }}
/>
)
}
23 changes: 23 additions & 0 deletions components/layouts/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Image from 'next/image'
import React from 'react'
import UETLogo from '../../public/images/uet-logo.svg';
import { THEME } from '@/styles/theme';

export default function Footer() {
return (
<div>
<div className='h-0.5 mb-5' style={{ backgroundColor: THEME.PRIMARY_COLOR }}></div>
<div className="flex-row">
<div className="flex items-center ml-4 mb-4">
<Image src={UETLogo} alt='uet-logo' />
<div className="flex-col ml-2">
<div className='font-semibold' style={{ color: THEME.PRIMARY_COLOR }}>
Trường Đại học Công nghệ, Đại học Quốc gia Hà Nội
</div>
<div className='text-gray-400 text-xs'>Nhà E3, 144 Xuân Thuỷ, Cầu Giấy, Hà Nội</div>
</div>
</div>
</div>
</div>
)
}
152 changes: 152 additions & 0 deletions components/layouts/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
"use client";

import { THEME } from "@/styles/theme";
import React, { ReactNode, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { authActions } from "@/redux/auth/authSlice";
import { authSelector } from "@/redux/auth/authSelector";
import { Avatar, Badge, Select } from "antd";
import { IoNotificationsOutline, IoNotifications } from "react-icons/io5";
import SearchBar from "../common/SearchBar";
import Link from "next/link";
import { MAIN_FONT } from "@/styles/fonts";

const languages = ['Tiếng Việt', 'English'];


interface TabProps {
selected: boolean;
children: ReactNode;
}

const Tab: React.FC<TabProps> = ({ selected, children }: TabProps) => {
const [hover, setHover] = useState<Boolean>(false);

return (
<button
style={{
justifyItems: "center",
height: "100%",
// backgroundColor: 'red',
position: "relative",
}}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
{hover ? (
<div
style={{
height: "2px",
width: "100%",
backgroundColor: THEME.PRIMARY_COLOR,
position: "absolute",
top: "0px",
}}
></div>
) : null}
<div style={selected ? { color: THEME.PRIMARY_COLOR } : {}}>
{children}
</div>
</button>
);
};

export default function Header() {
const dispatch = useDispatch();
const authState = useSelector(authSelector);
const [avtURL, setAvtURL] = useState<string>('https://yt3.googleusercontent.com/-CFTJHU7fEWb7BYEb6Jh9gm1EpetvVGQqtof0Rbh-VQRIznYYKJxCaqv_9HeBcmJmIsp2vOO9JU=s900-c-k-c0x00ffffff-no-rj')
const [avtStrokeColor, setAvtStrokeColor] = useState<string>(THEME.PRIMARY_COLOR);
const [notiCount, setNotiCount] = useState(10)

const handleSignIn = (): void => {
dispatch(authActions.updateAuthState({
signedIn: true,
username: "21020059",
name: "Bùi Huy Dược"
}))
};

const handleSignOut = (): void => {
dispatch(authActions.updateAuthState({
signedIn: false
}))
};

const handleOnSearch = (value: string): void => {
console.log(value)
}

return (
<div className="flex items-center h-[70px] sticky top-0 z-[1000] border-b-[0px] border-gray-200" style={{ backgroundColor: THEME.SECONDARY_COLOR }}>
{/* <NavBar/> */}
<div className="ml-10 flex-1">
<SearchBar onSearch={handleOnSearch} />
</div>
<Select
defaultValue={languages[0]}
// onChange={handleProvinceChange}
options={languages.map((language: string, i: number) => ({
label: language,
value: language,
}))}
className={`w-[110px] mr-[30px] ${MAIN_FONT.className}`}
/>
{
authState.signedIn ?
<div className="flex mr-5">
<button onClick={() => setNotiCount(0)}>
<Badge count={notiCount} overflowCount={9} title="Thông báo" className={`mr-7 ${MAIN_FONT.className}`}>
<div className="w-[40px] h-[40px] rounded-full flex items-center justify-center bg-gray-200 hover:bg-gray-300">
<IoNotificationsOutline size={25} />
</div>
</Badge>
</button>
<button
onClick={handleSignOut}
onMouseEnter={() => setAvtStrokeColor(THEME.DARK_PRIMARY_COLOR)}
onMouseLeave={() => setAvtStrokeColor(THEME.PRIMARY_COLOR)}
>
<div className="relative flex">
<Avatar className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" src={avtURL} size={40}></Avatar>
<svg width="50" height="50" viewBox="0 0 32 32"><circle r="15" cx="16" cy="16" fill="none" stroke-width="2" style={{ stroke: avtStrokeColor }}></circle></svg>
</div>
</button>
<div className="ml-3">
<div className="font-semibold ">Xin chào,</div>
<div className="text-xs font-semibold">{`${authState.username} ${authState.name}`}</div>
</div>
</div>
:
<div className="flex gap-4 mr-10">
<Link href='/signup'>
<button
style={{
// backgroundColor: "gray",
borderRadius: "10px",
padding: "7px 17px",
color: THEME.PRIMARY_COLOR,
}}
className="bg-gray-200 hover:bg-gray-300"
>
Đăng ký
</button>
</Link>
<Link href='/signin'>
<button
className="bg-primary hover:bg-dark-primary"
style={{
// backgroundColor: THEME.PRIMARY_COLOR,
borderRadius: "10px",
padding: "7px 17px",
color: THEME.SECONDARY_COLOR,
}}
onClick={handleSignIn}
>
Đăng nhập
</button>
</Link>
</div>
}
</div>
);
}
87 changes: 87 additions & 0 deletions components/layouts/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use client';

import { THEME } from '@/styles/theme'
import Link from 'next/link'
import React, { useState } from 'react'
import { AiOutlineMenu, AiOutlineSchedule, AiFillSchedule } from 'react-icons/ai'
import { MdOutlineTopic, MdTopic } from 'react-icons/md'
import { BsFiletypeDoc, BsPerson, BsPersonRolodex } from 'react-icons/bs'
import { TfiStatsUp } from 'react-icons/tfi'
import { ImStatsDots } from 'react-icons/im'
import MySubjects from '../../public/images/my-subjects.svg'
import Image from 'next/image'

const NavsContent: string[] = [
"Thời khoá biểu",
"Môn học của tôi",
"Học phần",
"Thống kê",
];

const iconSize = 22;

// const NavsIcons = [
// <AiOutlineSchedule key={0} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>,
// // <Image src={MySubjects} alt='My subjects' key={1} width={iconSize} height={iconSize}></Image>,
// // <MdOutlineTopic key={1} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>,
// <BsPersonRolodex key={1} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>,
// <MdOutlineTopic key={2} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>,
// <TfiStatsUp key={3} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>
// ]

const NavsIcons = [
<AiFillSchedule key={0} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>,
// <Image src={MySubjects} alt='My subjects' key={1} width={iconSize} height={iconSize}></Image>,
// <MdOutlineTopic key={1} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>,
<BsPersonRolodex key={1} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>,
<MdTopic key={2} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>,
<ImStatsDots key={3} size={iconSize} color={THEME.ROYAL_GRAY_COLOR}/>
]

const NavsRoutes = [
'/schedule',
'/mysubject',
'/allsubject',
'/stats'
]

export default function NavBar() {
const [expand, setExpand] = useState(true);

const handleCollapse = () => {
setExpand(!expand);
};

return (
<div
className="h-screen sticky left-0 top-0 border-r-[1px] border-gray-200 px-5 bg-secondary"
>
<div className='flex gap-5 h-[70px] items-center'>
<button onClick={handleCollapse}><AiOutlineMenu size={iconSize} /></button>
{/* <Image src={UETLogo} alt="UET Logo" height={50} width={50} /> */}
{
expand &&
<Link href='/'>
<div className="text-3xl font-extrabold tracking-wide" style={{ color: THEME.PRIMARY_COLOR }}>UETable</div>
</Link>
}
</div>
<div className='mt-[30px]'>
{
NavsContent.map((navContent: string, i: number) => {
return (
<div className='hover:bg-light-primary py-[10px] -mx-5 pl-5' key={i}>
<Link href={NavsRoutes[i]} >
<div className="flex gap-3 items-center">
{NavsIcons[i]}
{expand && <div className='text-royal-gray'>{navContent}</div>}
</div>
</Link>
</div>
)
})
}
</div>
</div>
)
}
Loading

0 comments on commit a7d3acf

Please sign in to comment.