From c157f7e9225f9cb31ead283ee5f85daa1b0fe5a0 Mon Sep 17 00:00:00 2001 From: Divlo Date: Sat, 11 Apr 2020 21:07:13 +0200 Subject: [PATCH] =?UTF-8?q?frontend:=20FunctionsList=20et=20d=C3=A9but=20d?= =?UTF-8?q?e=20/admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/FunctionCard/FunctionCard.js | 19 +++- .../FunctionsList/FunctionsList.css} | 0 .../components/FunctionsList/FunctionsList.js | 100 ++++++++++++++++++ website/components/Header/Header.js | 5 +- website/pages/admin/[slug].js | 31 ++++++ website/pages/admin/addFunction.js | 18 ++++ website/pages/admin/index.js | 39 +++++++ website/pages/functions/index.js | 97 +---------------- website/pages/profile/[name].js | 2 +- 9 files changed, 213 insertions(+), 98 deletions(-) rename website/{public/css/pages/functions.css => components/FunctionsList/FunctionsList.css} (100%) create mode 100644 website/components/FunctionsList/FunctionsList.js create mode 100644 website/pages/admin/[slug].js create mode 100644 website/pages/admin/addFunction.js create mode 100644 website/pages/admin/index.js diff --git a/website/components/FunctionCard/FunctionCard.js b/website/components/FunctionCard/FunctionCard.js index 1719872..b3575e5 100644 --- a/website/components/FunctionCard/FunctionCard.js +++ b/website/components/FunctionCard/FunctionCard.js @@ -1,5 +1,6 @@ import Link from 'next/link'; import { useState, forwardRef } from 'react'; +import date from 'date-and-time'; import Loader from '../Loader'; import './FunctionCard.css'; import { API_URL } from '../../utils/config'; @@ -16,8 +17,18 @@ const FunctionCard = forwardRef((props, ref) => { return ( {/* FunctionCard a une hauteur pendant chargement */}
@@ -31,8 +42,8 @@ const FunctionCard = forwardRef((props, ref) => {

{props.description}

-

{props.category.name}

-

{props.publicationDate}

+

{props.categorie.name}

+

{date.format(new Date(props.createdAt), 'DD/MM/YYYY', true)}

diff --git a/website/public/css/pages/functions.css b/website/components/FunctionsList/FunctionsList.css similarity index 100% rename from website/public/css/pages/functions.css rename to website/components/FunctionsList/FunctionsList.css diff --git a/website/components/FunctionsList/FunctionsList.js b/website/components/FunctionsList/FunctionsList.js new file mode 100644 index 0000000..faaa532 --- /dev/null +++ b/website/components/FunctionsList/FunctionsList.js @@ -0,0 +1,100 @@ +import { useState, useEffect, useRef, useCallback } from 'react'; +import { useRouter } from 'next/router'; +import FunctionCard from '../FunctionCard/FunctionCard'; +import Loader from '../Loader'; +import api from '../../utils/api'; +import useAPI from '../../hooks/useAPI'; +import './FunctionsList.css'; + +const FunctionsList = (props) => { + + const { categoryId } = useRouter().query; + + // State de recherche et de catégories + const [, categories] = useAPI('/categories'); + const [inputSearch, setInputSearch] = useState({ search: "", selectedCategory: categoryId || "0" }); + + // State pour afficher les fonctions + const [functionsData, setFunctionsData] = useState({ hasMore: true, rows: [] }); + const [isLoadingFunctions, setLoadingFunctions] = useState(true); + const [pageFunctions, setPageFunctions] = useState(1); + + // Récupère la catégorie avec la query categoryId + useEffect(() => { + if (categoryId) { + handleChange({ target: { name: "selectedCategory", value: categoryId } }); + } + }, [categoryId]); + + // Récupère les fonctions si la page change + useEffect(() => { + getFunctionsData().then((data) => setFunctionsData({ + hasMore: data.hasMore, + rows: [...functionsData.rows, ...data.rows] + })); + }, [pageFunctions]); + + // Récupère les fonctions si la catégorie/recherche change + useEffect(() => { + getFunctionsData().then((data) => setFunctionsData(data)); + }, [inputSearch.selectedCategory, inputSearch.search]); + + // Permet la pagination au scroll + const observer = useRef(); + const lastFunctionCardRef = useCallback((node) => { + if (isLoadingFunctions) return; + if (observer.current) observer.current.disconnect(); + observer.current = new IntersectionObserver((entries) => { + if (entries[0].isIntersecting && functionsData.hasMore) { + setPageFunctions(pageFunctions + 1); + } + }, { threshold: 1 }); + if (node) observer.current.observe(node); + }, [isLoadingFunctions, functionsData.hasMore]); + + const getFunctionsData = () => { + setLoadingFunctions(true); + return new Promise(async (next) => { + const result = await api.get(`/functions?page=${pageFunctions}&limit=10&categoryId=${inputSearch.selectedCategory}&search=${inputSearch.search}`); + setLoadingFunctions(false); + next(result.data); + }); + } + + const handleChange = (event) => { + const inputSearchNew = { ...inputSearch }; + inputSearchNew[event.target.name] = event.target.value; + setInputSearch(inputSearchNew); + } + + return ( +
+
+ {props.children} +
+ +
+ + +
+ +
+ {functionsData.rows.map((currentFunction, index) => { + // Si c'est le dernier élément + if (functionsData.rows.length === index + 1) { + return ; + } + return ; + })} +
+ {isLoadingFunctions && } +
+ ); +} + +export default FunctionsList; \ No newline at end of file diff --git a/website/components/Header/Header.js b/website/components/Header/Header.js index da33eae..d58acb9 100644 --- a/website/components/Header/Header.js +++ b/website/components/Header/Header.js @@ -37,7 +37,6 @@ export default function Header() { diff --git a/website/pages/admin/[slug].js b/website/pages/admin/[slug].js new file mode 100644 index 0000000..001b826 --- /dev/null +++ b/website/pages/admin/[slug].js @@ -0,0 +1,31 @@ +import { Fragment } from 'react'; +import Cookies from "universal-cookie"; +import HeadTag from '../../components/HeadTag'; +import redirect from '../../utils/redirect'; + +const AdminFunctionComponent = (props) => { + + if (!props.user.isAdmin && typeof window != 'undefined') { + return redirect({}, '/404'); + } + + return ( + + +

{props.slug}

+
+ ); +} + +export async function getServerSideProps({ req, params }) { + const cookies = new Cookies(req.headers.cookie); + const { slug } = params; + return { + props: { + user: { ...cookies.get('user') }, + slug + } + }; +} + +export default AdminFunctionComponent; \ No newline at end of file diff --git a/website/pages/admin/addFunction.js b/website/pages/admin/addFunction.js new file mode 100644 index 0000000..e70e1a5 --- /dev/null +++ b/website/pages/admin/addFunction.js @@ -0,0 +1,18 @@ +import Cookies from "universal-cookie"; + +const addFunction = (props) => { + return ( +

Crée une nouvelle fonction

+ ); +} + +export async function getServerSideProps({ req }) { + const cookies = new Cookies(req.headers.cookie); + return { + props: { + user: { ...cookies.get('user') } + } + }; +} + +export default addFunction; \ No newline at end of file diff --git a/website/pages/admin/index.js b/website/pages/admin/index.js new file mode 100644 index 0000000..89ec17a --- /dev/null +++ b/website/pages/admin/index.js @@ -0,0 +1,39 @@ +import { Fragment } from 'react'; +import Link from 'next/link'; +import Cookies from "universal-cookie"; +import HeadTag from '../../components/HeadTag'; +import FunctionsList from '../../components/FunctionsList/FunctionsList'; +import redirect from '../../utils/redirect'; + +const Admin = (props) => { + + if (!props.user.isAdmin && typeof window != 'undefined') { + return redirect({}, '/404'); + } + + return ( + + + + +
+

Administration

+ + + +
+
+
+ ); +} + +export async function getServerSideProps({ req }) { + const cookies = new Cookies(req.headers.cookie); + return { + props: { + user: { ...cookies.get('user') } + } + }; +} + +export default Admin; \ No newline at end of file diff --git a/website/pages/functions/index.js b/website/pages/functions/index.js index 5f6cb04..b32130f 100644 --- a/website/pages/functions/index.js +++ b/website/pages/functions/index.js @@ -1,73 +1,9 @@ -import { Fragment, useState, useEffect, useRef, useCallback } from 'react'; -import { useRouter } from 'next/router'; +import { Fragment } from 'react'; import HeadTag from '../../components/HeadTag'; -import FunctionCard from '../../components/FunctionCard/FunctionCard'; -import Loader from '../../components/Loader'; -import api from '../../utils/api'; -import useAPI from '../../hooks/useAPI'; -import '../../public/css/pages/functions.css'; +import FunctionsList from '../../components/FunctionsList/FunctionsList'; const Functions = () => { - const { categoryId } = useRouter().query; - - // State de recherche et de catégories - const [, categories] = useAPI('/categories'); - const [inputSearch, setInputSearch] = useState({ search: "", selectedCategory: categoryId || "0" }); - - // State pour afficher les fonctions - const [functionsData, setFunctionsData] = useState({ hasMore: true, rows: [] }); - const [isLoadingFunctions, setLoadingFunctions] = useState(true); - const [pageFunctions, setPageFunctions] = useState(1); - - // Récupère la catégorie avec la query categoryId - useEffect(() => { - if (categoryId) { - handleChange({ target: { name: "selectedCategory", value: categoryId } }); - } - }, [categoryId]); - - // Récupère les fonctions si la page change - useEffect(() => { - getFunctionsData().then((data) => setFunctionsData({ - hasMore: data.hasMore, - rows: [...functionsData.rows, ...data.rows] - })); - }, [pageFunctions]); - - // Récupère les fonctions si la catégorie/recherche change - useEffect(() => { - getFunctionsData().then((data) => setFunctionsData(data)); - }, [inputSearch.selectedCategory, inputSearch.search]); - - // Permet la pagination au scroll - const observer = useRef(); - const lastFunctionCardRef = useCallback((node) => { - if (isLoadingFunctions) return; - if (observer.current) observer.current.disconnect(); - observer.current = new IntersectionObserver((entries) => { - if (entries[0].isIntersecting && functionsData.hasMore) { - setPageFunctions(pageFunctions + 1); - } - }, { threshold: 1 }); - if (node) observer.current.observe(node); - }, [isLoadingFunctions, functionsData.hasMore]); - - const getFunctionsData = () => { - setLoadingFunctions(true); - return new Promise(async (next) => { - const result = await api.get(`/functions?page=${pageFunctions}&limit=10&categoryId=${inputSearch.selectedCategory}&search=${inputSearch.search}`); - setLoadingFunctions(false); - next(result.data); - }); - } - - const handleChange = (event) => { - const inputSearchNew = { ...inputSearch }; - inputSearchNew[event.target.name] = event.target.value; - setInputSearch(inputSearchNew); - } - return ( { description="Liste des fonctions." image="/images/FunctionProject_icon_small.png" /> - -
-
-

Fonctions

-
-
- - -
- -
- {functionsData.rows.map((f, index) => { - // Si c'est le dernier élément - if (functionsData.rows.length === index + 1) { - return ; - } - return ; - })} -
- {isLoadingFunctions && } -
+ +

Fonctions

+
); } diff --git a/website/pages/profile/[name].js b/website/pages/profile/[name].js index 0b118fc..1c08cf0 100644 --- a/website/pages/profile/[name].js +++ b/website/pages/profile/[name].js @@ -169,7 +169,7 @@ const Profile = (props) => {
{props.favoritesArray.map((favorite) => { return ( - + ); })}