diff --git a/api/controllers/comments.js b/api/controllers/comments.js
index af3a14a..98f77d9 100644
--- a/api/controllers/comments.js
+++ b/api/controllers/comments.js
@@ -38,8 +38,11 @@ exports.postCommentsByFunctionId = async (req, res, next) => {
if (!resultFunction) {
return errorHandling(next, { message: "La fonction n'existe pas.", statusCode: 404 });
}
- await Comments.create({ message, userId: req.userId, functionId });
- return res.status(201).json({ result: "Le commentaire a bien été ajouté!" });
+ if (!message) {
+ return errorHandling(next, { message: "Vous ne pouvez pas poster de commentaire vide.", statusCode: 400 });
+ }
+ const comment = await Comments.create({ message, userId: req.userId, functionId });
+ return res.status(201).json(comment);
} catch (error) {
console.log(error);
return errorHandling(next, serverError);
diff --git a/website/components/CommentCard/CommentCard.css b/website/components/CommentCard/CommentCard.css
new file mode 100644
index 0000000..8fc2115
--- /dev/null
+++ b/website/components/CommentCard/CommentCard.css
@@ -0,0 +1,33 @@
+.CommentCard {
+ display: flex;
+ flex-direction: column;
+ word-wrap: break-word;
+ box-shadow: 0px 0px 6px 6px rgba(0, 0, 0, .25);
+ border: 1px solid black;
+ border-radius: .7em;
+ margin: 15px 0 15px 0;
+}
+.CommentCard__container {
+ height: 100%;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ padding: 20px;
+}
+.CommentCard__user-logo {
+ border-radius: 50%;
+ object-fit: cover;
+ width: 50px;
+ height: 50px;
+ cursor: pointer;
+}
+.CommentCard__message-info {
+ display: flex;
+ align-items: center;
+ margin-left: 10px;
+ font-size: 16px;
+}
+.CommentCard__message {
+ line-height: 1.8;
+ margin: 15px 0 0 0;
+}
\ No newline at end of file
diff --git a/website/components/CommentCard/CommentCard.js b/website/components/CommentCard/CommentCard.js
new file mode 100644
index 0000000..2947c8b
--- /dev/null
+++ b/website/components/CommentCard/CommentCard.js
@@ -0,0 +1,32 @@
+import Link from 'next/link';
+import { forwardRef } from 'react';
+import { API_URL } from '../../utils/config';
+import date from 'date-and-time';
+import './CommentCard.css';
+
+const CommentCard = forwardRef((props, ref) => {
+ return (
+
+
+
+
+
+
+
+
+ {props.user.name}
+
+ - {date.format(new Date(props.createdAt), 'DD/MM/YYYY à HH:mm', true)}
+
+
+
+
+
+ );
+});
+
+export default CommentCard;
\ No newline at end of file
diff --git a/website/components/FunctionCard/FunctionCard.js b/website/components/FunctionCard/FunctionCard.js
index 71dfdac..1719872 100644
--- a/website/components/FunctionCard/FunctionCard.js
+++ b/website/components/FunctionCard/FunctionCard.js
@@ -38,6 +38,6 @@ const FunctionCard = forwardRef((props, ref) => {
);
-})
+});
export default FunctionCard;
\ No newline at end of file
diff --git a/website/components/FunctionComments/FunctionComments.css b/website/components/FunctionComments/FunctionComments.css
new file mode 100644
index 0000000..51d4139
--- /dev/null
+++ b/website/components/FunctionComments/FunctionComments.css
@@ -0,0 +1,7 @@
+.FunctionComments__row {
+ margin-bottom: 20px;
+}
+.FunctionComments__textarea {
+ height: auto;
+ resize: vertical;
+}
\ No newline at end of file
diff --git a/website/components/FunctionComments/FunctionComments.js b/website/components/FunctionComments/FunctionComments.js
new file mode 100644
index 0000000..2ff8ad6
--- /dev/null
+++ b/website/components/FunctionComments/FunctionComments.js
@@ -0,0 +1,113 @@
+import { Fragment, useState, useEffect, useContext, useRef, useCallback } from 'react';
+import Link from 'next/link';
+import { UserContext } from '../../contexts/UserContext';
+import CommentCard from '../CommentCard/CommentCard';
+import Loader from '../Loader';
+import api from '../../utils/api';
+import './FunctionComments.css';
+
+const FunctionComments = ({ functionId }) => {
+
+ // State pour poster un commentaire
+ const { isAuth, user } = useContext(UserContext);
+ const [inputState, setInputState] = useState({});
+
+ // State pour afficher les commentaires
+ const [commentsData, setCommentsData] = useState({ hasMore: true, rows: [] });
+ const [isLoadingComments, setLoadingComments] = useState(true);
+ const [pageComments, setPageComments] = useState(1);
+
+ // Permet la pagination au scroll
+ const observer = useRef();
+ const lastCommentCardRef = useCallback((node) => {
+ if (isLoadingComments) return;
+ if (observer.current) observer.current.disconnect();
+ observer.current = new IntersectionObserver((entries) => {
+ if (entries[0].isIntersecting && commentsData.hasMore) {
+ setPageComments(pageComments + 1);
+ }
+ }, { threshold: 1 });
+ if (node) observer.current.observe(node);
+ }, [isLoadingComments, commentsData.hasMore]);
+
+ const getCommentsData = () => {
+ setLoadingComments(true);
+ return new Promise(async (next) => {
+ const result = await api.get(`/comments/${functionId}/?page=${pageComments}&limit=10`);
+ setLoadingComments(false);
+ next(result.data);
+ });
+ }
+
+ // Récupère les commentaires si la page change
+ useEffect(() => {
+ getCommentsData().then((data) => setCommentsData({
+ hasMore: data.hasMore,
+ rows: [...commentsData.rows, ...data.rows]
+ }));
+ }, [pageComments]);
+
+ const handleChange = (event) => {
+ const inputStateNew = { ...inputState };
+ inputStateNew[event.target.name] = event.target.value;
+ setInputState(inputStateNew);
+ }
+
+ const handleSubmit = async (event) => {
+ event.preventDefault();
+ const token = user.token;
+ if (isAuth && token != undefined && inputState.commentPost != undefined) {
+ try {
+ const response = await api.post(`/comments/${functionId}`, { message: inputState.commentPost }, { headers: { 'Authorization': token } });
+ const comment = { ...response.data, user: { name: user.name, logo: user.logo } };
+ setCommentsData({ hasMore: commentsData.hasMore, rows: [comment, ...commentsData.rows] });
+ setInputState({});
+ } catch { }
+ }
+ }
+
+ return (
+
+
+
+
+ {
+ (isAuth) ?
+
+ :
+
+ Vous devez être connecté pour poster un commentaire.
+
+ }
+
+
+
+
+ {isLoadingComments &&
+
+
+
+ }
+
+ {commentsData.rows.map((comment, index) => {
+ // Si c'est le dernier élément
+ if (commentsData.rows.length === index + 1) {
+ return ;
+ }
+ return ;
+ })}
+
+
+
+ );
+}
+
+export default FunctionComments;
\ No newline at end of file
diff --git a/website/components/FunctionForm.js b/website/components/FunctionForm.js
index f3f08c1..2d2d142 100644
--- a/website/components/FunctionForm.js
+++ b/website/components/FunctionForm.js
@@ -1,4 +1,4 @@
-import { useState } from 'react';
+import { Fragment, useState } from 'react';
import Loader from './Loader';
import htmlParser from 'html-react-parser';
import api from '../utils/api';
@@ -38,7 +38,7 @@ const FunctionForm = (props) => {
);
}
return (
-
+
-
+
);
}
diff --git a/website/components/FunctionTabManager.js b/website/components/FunctionTabManager.js
new file mode 100644
index 0000000..c572192
--- /dev/null
+++ b/website/components/FunctionTabManager.js
@@ -0,0 +1,30 @@
+import FunctionTabs from './FunctionTabs/FunctionTabs';
+import FunctionForm from './FunctionForm';
+import FunctionComments from './FunctionComments/FunctionComments';
+
+const FunctionTabManager = (props) => {
+ if (props.functionInfo.type === "form") {
+ return (
+
+
+
+
+ Article
+
+
+
+
+ );
+ }
+
+ return (
+
+ Article
+
+
+
+
+ );
+}
+
+export default FunctionTabManager;
\ No newline at end of file
diff --git a/website/contexts/FunctionTabsContext.js b/website/contexts/FunctionTabsContext.js
index f080886..c12b30a 100644
--- a/website/contexts/FunctionTabsContext.js
+++ b/website/contexts/FunctionTabsContext.js
@@ -4,7 +4,7 @@ export const FunctionTabsContext = createContext();
function FunctionTabsContextProvider(props) {
- const [slideIndex, setSlideIndex] = useState(0);
+ const [slideIndex, setSlideIndex] = useState(2);
return (
diff --git a/website/pages/functions/[slug].js b/website/pages/functions/[slug].js
index 15dd8a6..9771df8 100644
--- a/website/pages/functions/[slug].js
+++ b/website/pages/functions/[slug].js
@@ -2,8 +2,7 @@ import FunctionTabsContextProvider from '../../contexts/FunctionTabsContext';
import HeadTag from '../../components/HeadTag';
import FunctionComponentTop from '../../components/FunctionComponentTop';
import FunctionTabsTop from '../../components/FunctionTabs/FunctionTabsTop';
-import FunctionTabs from '../../components/FunctionTabs/FunctionTabs';
-import FunctionForm from '../../components/FunctionForm';
+import FunctionTabManager from '../../components/FunctionTabManager';
import redirect from '../../utils/redirect';
import api from '../../utils/api';
import { API_URL } from '../../utils/config';
@@ -18,22 +17,10 @@ const FunctionComponent = (props) => {
return (
-
-
-
-
- {(props.type !== "article") ?
-
- :
- Slide 1
- }
- Slide 2
- Slide 3
-
-
+
);
diff --git a/website/pages/functions/index.js b/website/pages/functions/index.js
index e2bc4a0..36ca75e 100644
--- a/website/pages/functions/index.js
+++ b/website/pages/functions/index.js
@@ -3,9 +3,9 @@ import { useRouter } from 'next/router';
import HeadTag from '../../components/HeadTag';
import FunctionCard from '../../components/FunctionCard/FunctionCard';
import Loader from '../../components/Loader';
-import '../../public/css/pages/functions.css';
import api from '../../utils/api';
import useAPI from '../../hooks/useAPI';
+import '../../public/css/pages/functions.css';
const Functions = () => {
diff --git a/website/pages/profile/[name].js b/website/pages/profile/[name].js
index d2ffaac..0b118fc 100644
--- a/website/pages/profile/[name].js
+++ b/website/pages/profile/[name].js
@@ -52,7 +52,7 @@ const Profile = (props) => {
formData.append('isPublicEmail', inputState.isPublicEmail);
formData.append('logo', inputState.logo);
- api.put('/users/', formData, { headers: { 'Authorization': user.token } })
+ api.put('/users/', formData, { headers: { 'Authorization': token } })
.then(() => {
setIsLoading(false);
logoutUser();
diff --git a/website/public/css/general.css b/website/public/css/general.css
index ac5e396..6895f94 100644
--- a/website/public/css/general.css
+++ b/website/public/css/general.css
@@ -41,6 +41,9 @@ a:hover {
justify-content: center;
align-items: center;
}
+div[aria-hidden="true"] > * {
+ display: none;
+}
/* LOADING */
.isLoading {