frontend: Affichage dynamique des fonctions
TODO: Rendre fonctionnel la rechercher et le tri par catégorie
This commit is contained in:
parent
c9f817930c
commit
5edf5e7069
@ -27,6 +27,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.FunctionCard__image {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
.FunctionCard__title {
|
.FunctionCard__title {
|
||||||
font-size: 1.4em;
|
font-size: 1.4em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
11
frontend/config/api.js
Normal file
11
frontend/config/api.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { API_URL } from './config';
|
||||||
|
|
||||||
|
const api = axios.create({
|
||||||
|
baseURL: API_URL,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default api;
|
1
frontend/config/config.js
Normal file
1
frontend/config/config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const API_URL = "http://localhost:8080";
|
31
frontend/package-lock.json
generated
31
frontend/package-lock.json
generated
@ -1796,6 +1796,37 @@
|
|||||||
"postcss-value-parser": "^4.0.2"
|
"postcss-value-parser": "^4.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"axios": {
|
||||||
|
"version": "0.19.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
||||||
|
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "1.5.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"follow-redirects": {
|
||||||
|
"version": "1.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||||
|
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "=3.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"babel-code-frame": {
|
"babel-code-frame": {
|
||||||
"version": "6.26.0",
|
"version": "6.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@zeit/next-css": "^1.0.1",
|
"@zeit/next-css": "^1.0.1",
|
||||||
|
"axios": "^0.19.2",
|
||||||
"next": "9.3.1",
|
"next": "9.3.1",
|
||||||
"next-fonts": "^1.0.3",
|
"next-fonts": "^1.0.3",
|
||||||
"react": "16.13.0",
|
"react": "16.13.0",
|
||||||
|
@ -1,48 +1,86 @@
|
|||||||
import { Fragment } from 'react';
|
import { Fragment, useState, useEffect } from 'react';
|
||||||
import HeadTag from '../components/HeadTag';
|
import HeadTag from '../components/HeadTag';
|
||||||
import FunctionCard from '../components/FunctionCard/FunctionCard';
|
import FunctionCard from '../components/FunctionCard/FunctionCard';
|
||||||
import '../public/css/pages/functions.css';
|
import '../public/css/pages/functions.css';
|
||||||
|
import { API_URL } from '../config/config';
|
||||||
|
import api from '../config/api';
|
||||||
|
|
||||||
const Functions = () => (
|
const Functions = () => {
|
||||||
<Fragment>
|
|
||||||
<HeadTag
|
|
||||||
title="Fonctions"
|
|
||||||
description="Liste des fonctions."
|
|
||||||
image="/images/FunctionProject_icon_small.png"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="container text-center">
|
const [categories, setCategories] = useState([]);
|
||||||
|
|
||||||
<div className="row justify-content-center">
|
const [functions, setFunctions] = useState([]);
|
||||||
<h1 className="Functions__title">Fonctions</h1>
|
const [isLoadingFunctions, setLoadingFunctions] = useState(true);
|
||||||
|
const [pageFunctions, setPageFunctions] = useState(1);
|
||||||
|
const [hasMoreFunctions, sethasMoreFunctions] = useState(false);
|
||||||
|
|
||||||
|
// Récupère les catégories
|
||||||
|
useEffect(() => {
|
||||||
|
api.get('/categories')
|
||||||
|
.then((result) => {
|
||||||
|
setCategories(result.data);
|
||||||
|
})
|
||||||
|
.catch((error) => console.error(error));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Récupère les fonctions
|
||||||
|
useEffect(() => {
|
||||||
|
api.get(`/functions?page=${pageFunctions}&limit=10`)
|
||||||
|
.then((result) => {
|
||||||
|
setLoadingFunctions(false);
|
||||||
|
sethasMoreFunctions(result.data.hasMore);
|
||||||
|
setFunctions([...functions, ...result.data.rows]);
|
||||||
|
})
|
||||||
|
.catch((error) => console.error(error));
|
||||||
|
}, [pageFunctions]);
|
||||||
|
|
||||||
|
const loadMore = () => {
|
||||||
|
setLoadingFunctions(true);
|
||||||
|
setPageFunctions(pageFunctions + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<HeadTag
|
||||||
|
title="Fonctions"
|
||||||
|
description="Liste des fonctions."
|
||||||
|
image="/images/FunctionProject_icon_small.png"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="container text-center">
|
||||||
|
<div className="row justify-content-center">
|
||||||
|
<h1 className="Functions__title">Fonctions</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="Functions__search-container row justify-content-center">
|
||||||
|
<select className="Functions__select form-control">
|
||||||
|
<option value="0">Toutes catégories</option>
|
||||||
|
{categories.map((category) => (
|
||||||
|
<option key={category.id} value={category.id} className="Functions__select-option" style={{ backgroundColor: category.color }}>{category.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<input type="search" className="form-control Functions__search-input" name="search" id="search" placeholder="🔎 Rechercher..."></input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row justify-content-center">
|
||||||
|
|
||||||
|
{functions.map((f) => (
|
||||||
|
<FunctionCard key={f.id} slug={f.slug} image={API_URL + f.image} title={f.title} description={f.description} category={f.categorie} publicationDate={new Date(f.createdAt).toLocaleDateString('fr-FR')} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
{
|
||||||
|
!isLoadingFunctions && hasMoreFunctions
|
||||||
|
?
|
||||||
|
<button className="btn btn-dark" onClick={loadMore}>Charger plus de fonctions ?</button>
|
||||||
|
: !hasMoreFunctions ?
|
||||||
|
null
|
||||||
|
:
|
||||||
|
<p>Chargement...</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Fragment>
|
||||||
<div className="Functions__search-container row justify-content-center">
|
);
|
||||||
<select className="Functions__select form-control">
|
}
|
||||||
{/* TODO: API Call to fetch categories */}
|
|
||||||
<option>Toutes catégories</option>
|
|
||||||
<option className="Functions__select-option" style={{ backgroundColor: "#406880" }}>✨ Utilitaires</option>
|
|
||||||
</select>
|
|
||||||
<input type="search" className="form-control Functions__search-input" name="search" id="search" placeholder="🔎 Rechercher..."></input>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="row justify-content-center">
|
|
||||||
{/* TODO: API Call to fetch data */}
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
<FunctionCard slug="weatherRequest" image="/images/functions/weatherRequest.png" title="Météo" description="Affiche la météo et l'heure locale." category={{ name: "✨ Utilitaires", color: "#406880" }} publicationDate="18/03/2020" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default Functions;
|
export default Functions;
|
@ -73,3 +73,22 @@ a, .important {
|
|||||||
border: 1px solid #ced4da;
|
border: 1px solid #ced4da;
|
||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
}
|
}
|
||||||
|
.btn {
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: .375rem .75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
border-radius: .25rem;
|
||||||
|
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||||
|
}
|
||||||
|
.btn-dark:hover {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #23272b;
|
||||||
|
border-color: #1d2124;
|
||||||
|
}
|
||||||
|
.btn-dark {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #343a40;
|
||||||
|
border-color: #343a40;
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
Reference in New Issue
Block a user