Skip to content
Snippets Groups Projects
Commit 87e6dad5 authored by Princelle Maxime's avatar Princelle Maxime :gay_pride_flag:
Browse files

:sparkles: adding pages and routes

parent ef075f90
Branches
2 merge requests!4Add CI deployment,!1Persistance
...@@ -3,53 +3,33 @@ import React from 'react'; ...@@ -3,53 +3,33 @@ import React from 'react';
import { import {
BrowserRouter as Router, BrowserRouter as Router,
Routes, Routes,
Route, Route
Navigate,
useLocation
} from "react-router-dom"; } from "react-router-dom";
import Dashboard from './pages/dashboard'; import Sell from './pages/sell';
import Login from './pages/login'; import Login from './pages/login';
import Main from './components/layout/main';
import { useAuth } from "./auth/useAuth";
import { AuthProvider } from './auth/AuthProvider'; import { AuthProvider } from './auth/AuthProvider';
export default function App() { export default function App() {
// DEV: auto logged in
return ( return (
<Router> <Router>
<div> <div>
<AuthProvider> <AuthProvider>
<Routes> <Routes>
<Route path="/" element={<h1>Welcome!</h1>} /> <Route index element={<h1>Welcome!</h1>} />
<Route path="/login" element={<Login/>} /> <Route path="login" element={<Login/>} />
<Route <Route path="dashboard" element={<Main />}>
path="/dashboard" <Route index element={<Sell />} />
element={ <Route path="sell" element={<h1>Sell...</h1>} />
<RequireAuth> <Route path="stock" element={<h1>Stock...</h1>} />
<Dashboard /> <Route path="settings" element={<h1>Settings...</h1>} />
</RequireAuth> </Route>
} <Route path="*" element={<h1>No match !</h1>} />
/>
</Routes> </Routes>
</AuthProvider> </AuthProvider>
</div> </div>
</Router> </Router>
); );
} }
function RequireAuth({ children }: { children: JSX.Element }) {
let auth = useAuth();
let location = useLocation();
if (!auth.user) {
// Redirect them to the /login page, but save the current location they were
// trying to go to when they were redirected. This allows us to send them
// along to that page after they login, which is a nicer user experience
// than dropping them off on the home page.
return <Navigate to="/login" state={{ from: location }} />;
}
return children;
}
\ No newline at end of file
import {
Navigate,
useLocation
} from "react-router-dom";
import { useAuth } from "./useAuth";
function RequireAuth({ children }: { children: JSX.Element }) {
let auth = useAuth();
let location = useLocation();
if (!auth.user) {
// Redirect them to the /login page, but save the current location they were
// trying to go to when they were redirected. This allows us to send them
// along to that page after they login, which is a nicer user experience
// than dropping them off on the home page.
return <Navigate to="/login" state={{ from: location }} />;
}
return children;
}
export { RequireAuth };
\ No newline at end of file
...@@ -8,11 +8,13 @@ import { ...@@ -8,11 +8,13 @@ import {
XIcon XIcon
} from '@heroicons/react/outline'; } from '@heroicons/react/outline';
import { Link } from 'react-router-dom';
const navigation = [ const navigation = [
{ name: 'Accueil', href: '/', icon: HomeIcon }, { name: 'Accueil', href: '/dashboard', icon: HomeIcon },
{ name: 'Vendre', href: '/sell', icon: CurrencyEuroIcon }, { name: 'Vendre', href: '/dashboard/sell', icon: CurrencyEuroIcon },
{ name: 'Gestion des stocks', href: '/stock', icon: ShoppingCartIcon }, { name: 'Gestion des stocks', href: '/dashboard/stock', icon: ShoppingCartIcon },
{ name: 'Réglages', href: '/settings', icon: CogIcon }, { name: 'Réglages', href: '/dashboard/settings', icon: CogIcon },
]; ];
function classNames(...classes: unknown[]) { function classNames(...classes: unknown[]) {
...@@ -75,9 +77,9 @@ const Navbar = ({ sidebarOpen, setSidebarOpen, path }) => { ...@@ -75,9 +77,9 @@ const Navbar = ({ sidebarOpen, setSidebarOpen, path }) => {
<div className="mt-5 flex-1 h-0 overflow-y-auto"> <div className="mt-5 flex-1 h-0 overflow-y-auto">
<nav className="px-2 space-y-1"> <nav className="px-2 space-y-1">
{navigation.map((item) => ( {navigation.map((item) => (
<a <Link
key={item.name} key={item.name}
href={item.href} to={item.href}
className={classNames( className={classNames(
item.href === path ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white', item.href === path ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
'group flex items-center px-2 py-2 text-base font-medium rounded-md' 'group flex items-center px-2 py-2 text-base font-medium rounded-md'
...@@ -91,7 +93,7 @@ const Navbar = ({ sidebarOpen, setSidebarOpen, path }) => { ...@@ -91,7 +93,7 @@ const Navbar = ({ sidebarOpen, setSidebarOpen, path }) => {
aria-hidden="true" aria-hidden="true"
/> />
{item.name} {item.name}
</a> </Link>
))} ))}
</nav> </nav>
</div> </div>
......
...@@ -4,30 +4,27 @@ import { ...@@ -4,30 +4,27 @@ import {
UserIcon, UserIcon,
MenuAlt2Icon, MenuAlt2Icon,
} from '@heroicons/react/outline'; } from '@heroicons/react/outline';
import {
SearchIcon
} from '@heroicons/react/solid';
import Navbar from '../core/navbar'; import Navbar from '../core/navbar';
import { useAuth } from '../../auth/useAuth'; import { useAuth } from '../../auth/useAuth';
import { useNavigate } from 'react-router-dom'; import { RequireAuth } from '../../auth/RequireAuth';
import { Outlet, useNavigate } from 'react-router-dom';
interface LayoutProps { interface LayoutProps {
path: string,
handleSearch: any,
title?: string, title?: string,
subTitle?: string, subTitle?: string,
children: any children?: any
}; };
function classNames(...classes: unknown[]) { function classNames(...classes: unknown[]) {
return classes.filter(Boolean).join(' '); return classes.filter(Boolean).join(' ');
} }
const Main = ({ path, handleSearch, title, subTitle, children }: LayoutProps) => { const Main = ({ title, subTitle, children }: LayoutProps) => {
let auth = useAuth(); let auth = useAuth();
let navigate = useNavigate(); let navigate = useNavigate();
let path = window.location.pathname;
const userNavigation = [ const userNavigation = [
{ name: 'Se déconnecter', action: () => {return auth.signout(() => navigate("/"))} }, { name: 'Se déconnecter', action: () => {return auth.signout(() => navigate("/"))} },
...@@ -35,11 +32,8 @@ const Main = ({ path, handleSearch, title, subTitle, children }: LayoutProps) => ...@@ -35,11 +32,8 @@ const Main = ({ path, handleSearch, title, subTitle, children }: LayoutProps) =>
const [sidebarOpen, setSidebarOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false);
let handleSearchChange = (e) => {
handleSearch(e.target.value);
}
return ( return (
<RequireAuth>
<div className="h-screen flex overflow-hidden bg-gray-100"> <div className="h-screen flex overflow-hidden bg-gray-100">
<Navbar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} path={path} /> <Navbar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} path={path} />
...@@ -54,26 +48,7 @@ const Main = ({ path, handleSearch, title, subTitle, children }: LayoutProps) => ...@@ -54,26 +48,7 @@ const Main = ({ path, handleSearch, title, subTitle, children }: LayoutProps) =>
<MenuAlt2Icon className="h-6 w-6" aria-hidden="true" /> <MenuAlt2Icon className="h-6 w-6" aria-hidden="true" />
</button> </button>
<div className="flex-1 px-4 flex justify-between"> <div className="flex-1 px-4 flex justify-between">
<div className="flex-1 flex"> <div className="flex-1 flex w-full md:ml-0 items-center"><span className="text-xl font-semibold">Dashboard</span></div>
<form className="w-full flex md:ml-0" action="#" method="GET">
<label htmlFor="search-field" className="sr-only">
Rechercher
</label>
<div className="relative w-full text-gray-400 focus-within:text-gray-600">
<div className="absolute inset-y-0 left-0 flex items-center pointer-events-none">
<SearchIcon className="h-5 w-5" aria-hidden="true" />
</div>
<input
id="search-field"
className="block w-full h-full pl-8 pr-3 py-2 border-transparent text-gray-900 placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-0 focus:border-transparent sm:text-sm"
placeholder="Rechercher"
type="search"
name="search"
onChange={(e) => {handleSearchChange(e)}}
/>
</div>
</form>
</div>
<div className="ml-4 flex items-center md:ml-6"> <div className="ml-4 flex items-center md:ml-6">
{/* Profile dropdown */} {/* Profile dropdown */}
<Menu as="div" className="ml-3 relative"> <Menu as="div" className="ml-3 relative">
...@@ -125,11 +100,12 @@ const Main = ({ path, handleSearch, title, subTitle, children }: LayoutProps) => ...@@ -125,11 +100,12 @@ const Main = ({ path, handleSearch, title, subTitle, children }: LayoutProps) =>
<h1 className="text-xl font-normal text-gray-600">{subTitle}</h1> <h1 className="text-xl font-normal text-gray-600">{subTitle}</h1>
</div> </div>
)} )}
{children} <Outlet />
</div> </div>
</main> </main>
</div> </div>
</div> </div>
</RequireAuth>
); );
}; };
......
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { CollectionIcon, EmojiSadIcon } from '@heroicons/react/outline';
import Main from "../components/layout/main";
import SellListItem from "../components/sellListItem"; import SellListItem from "../components/sellListItem";
const products = [ const products = [
...@@ -66,9 +66,7 @@ const products = [ ...@@ -66,9 +66,7 @@ const products = [
}, },
]; ];
const Dashboard = () => { const Sell = () => {
const path = window.location.pathname;
let [search, setSearch] = useState(""); let [search, setSearch] = useState("");
let [productsList, setProductsList] = useState(products); let [productsList, setProductsList] = useState(products);
...@@ -79,24 +77,40 @@ const Dashboard = () => { ...@@ -79,24 +77,40 @@ const Dashboard = () => {
})) }))
}, [search]); }, [search]);
let handleSearch = (search: string) => {
setSearch(search);
}
return ( return (
<Main path={path} handleSearch={handleSearch} title="Accueil"> <div className="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
<div className="max-w-7xl mx-auto px-4 sm:px-6 md:px-8"> <div className="pb-5">
{[...Array.from((new Set(productsList.map(item => item.category))))].map((category) => (<div> <label htmlFor="search" className="block text-sm font-medium text-gray-700">Recherche</label>
<h1 className="text-lg font-medium py-2 pt-4">{category}</h1> <div className="mt-1 relative flex items-center">
<ul className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-5"> <input type="text" name="search" id="search" value={search} onChange={(e) => {setSearch(e.target.value)}} className="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full pr-12 sm:text-sm border-gray-300 rounded-md" />
{productsList.filter((p) => p.category === category).map((product) => ( </div>
<SellListItem product={product} key={product.name} /> </div>
))} {productsList.length > 0 && [...Array.from((new Set(productsList.map(item => item.category))))].map((category) => (<div>
</ul> <h1 className="text-lg font-medium py-2 pt-4">{category}</h1>
</div>))} <ul className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-5">
{productsList.filter((p) => p.category === category).map((product) => (
<SellListItem product={product} key={product.name} />
))}
</ul>
</div>))}
{productsList.length === 0 &&
<div className="text-center w-full mt-10">
<EmojiSadIcon className="mx-auto h-12 w-12 text-gray-400"/>
<h3 className="mt-2 text-sm font-medium text-gray-900">Aucun produit trouvé !</h3>
<p className="mt-1 text-sm text-gray-500">Essayez de réduire vos critères de recherche.</p>
<div className="mt-6">
<button
type="button"
onClick={() => setSearch("")}
className="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
<CollectionIcon className="-ml-1 mr-2 h-5 w-5" aria-hidden="true" />
Afficher tout
</button>
</div> </div>
</Main> </div>}
</div>
); );
}; };
export default Dashboard; export default Sell;
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