diff --git a/src/Components/Accounts/Adm/admAccountsTable.js b/src/Components/Accounts/Adm/admAccountsTable.js
index 82f9e0ad..3bc62f9e 100644
--- a/src/Components/Accounts/Adm/admAccountsTable.js
+++ b/src/Components/Accounts/Adm/admAccountsTable.js
@@ -5,12 +5,15 @@ import { toast } from 'react-toastify'
import DeleteAccountPopupContent from '../../Popup/deleteAccount'
import Popup from 'reactjs-popup'
import cross from '../../../assets/Cross.png'
-import minusButton from '../../../assets/minus-button.png'
+import deleteButton from '../../../assets/deleteIcon.png'
+import suspendButton from '../../../assets/suspendIcon.png'
+import restoreButton from '../../../assets/restoreIcon.png'
export default function AdmAccountsTable () {
const [accountList, setAccountList] = useState([]) // list of accounts
const [isPopupOpen, setIsPopupOpen] = useState(false)
const [userId, setUserId] = useState('')
+ const [actionType, setActionType] = useState('delete')
async function getAccountList () {
const baseUrl = process.env.REACT_APP_BACKEND_URL + '/user/all'
@@ -28,6 +31,27 @@ export default function AdmAccountsTable () {
} else {
const data = await resp.json()
setAccountList(data)
+ getSuspendedAccountList(data)
+ }
+ }
+
+ async function getSuspendedAccountList (list) {
+ const baseUrl = process.env.REACT_APP_BACKEND_URL + '/user/getDisabled'
+ const token = sessionStorage.getItem('token')
+
+ const resp = await fetch(baseUrl, {
+ method: 'GET',
+ headers: {
+ 'x-auth-token': token,
+ 'Content-Type': 'application/json'
+ }
+ })
+ if (resp.status === 401) {
+ disconnect()
+ } else {
+ const data = await resp.json()
+ const array = [...list, ...data]
+ setAccountList(array)
}
}
@@ -39,7 +63,8 @@ export default function AdmAccountsTable () {
setIsPopupOpen(!isPopupOpen)
}
- const callDeleteAccount = (userIdValue) => {
+ const callDeleteAccount = (userIdValue, action) => {
+ setActionType(action)
setUserId(userIdValue)
setIsPopupOpen(!isPopupOpen)
}
@@ -61,6 +86,7 @@ export default function AdmAccountsTable () {
if (resp.status === 401) {
disconnect()
} else if (resp.status === 200) {
+ setIsPopupOpen(false)
toast.success(deleteType ? 'Le compte a été supprimé' : 'Le compte a été suspendu')
getAccountList()
} else {
@@ -69,13 +95,36 @@ export default function AdmAccountsTable () {
}
}
+ async function activateAccount (accountId) {
+ const baseUrl = process.env.REACT_APP_BACKEND_URL + '/adm/activateUser/' + accountId
+ const token = sessionStorage.getItem('token')
+
+ const resp = await fetch(baseUrl, {
+ method: 'POST',
+ headers: {
+ 'x-auth-token': token,
+ 'Content-Type': 'application/json'
+ }
+ })
+ if (resp.status === 401) {
+ disconnect()
+ } else if (resp.status === 200) {
+ setIsPopupOpen(false)
+ toast.success('Le compte a été restauré')
+ getAccountList()
+ } else {
+ toast.error("une alerte s'est produite")
+ getAccountList()
+ }
+ }
+
return (
{(close) => (
-
+
)}
@@ -96,7 +145,14 @@ export default function AdmAccountsTable () {
{data.firstname}
{data.lastname}
{data.email}
-
{ e.stopPropagation(); callDeleteAccount(data._id) }} src={minusButton} alt='delete' title='Supprimer ou suspendre le compte' />
+
+ {
+ data.active
+ ? { e.stopPropagation(); callDeleteAccount(data._id, 'suspend') }} src={suspendButton} alt='delete' title='Suspendre le compte' />
+ : { e.stopPropagation(); callDeleteAccount(data._id, 'restore') }} src={restoreButton} alt='delete' title='Restaurer le compte' />
+ }
+ { e.stopPropagation(); callDeleteAccount(data._id, 'delete') }} src={deleteButton} alt='delete' title='Supprimer le compte' />
+
)
}
diff --git a/src/Components/Accounts/SchoolAdm/schoolAccountsTable.js b/src/Components/Accounts/SchoolAdm/schoolAccountsTable.js
index d2290478..e6f33fe6 100644
--- a/src/Components/Accounts/SchoolAdm/schoolAccountsTable.js
+++ b/src/Components/Accounts/SchoolAdm/schoolAccountsTable.js
@@ -6,9 +6,12 @@ import { toast } from 'react-toastify'
import DeleteAccountPopupContent from '../../Popup/deleteAccount'
import Popup from 'reactjs-popup'
import cross from '../../../assets/Cross.png'
-import minusButton from '../../../assets/minus-button.png'
+import deleteButton from '../../../assets/deleteIcon.png'
+import suspendButton from '../../../assets/suspendIcon.png'
+import restoreButton from '../../../assets/restoreIcon.png'
+import Select from 'react-select'
-export default function SchoolAccountsTable () {
+export default function SchoolAccountsTable ({ status }) {
const [teacherList, setTeacherList] = useState([])
const [studentList, setStudentList] = useState([])
const [selectedUser, setSelectedUser] = useState(null)
@@ -16,13 +19,43 @@ export default function SchoolAccountsTable () {
const [isPopupOpen, setIsPopupOpen] = useState(false)
const [fileImage, setFileImage] = useState(null)
const [userId, setUserId] = useState('')
+ const [isMultiStatus, setIsMultiStatus] = useState(true)
+ const [classesList, setClassesList] = useState([])
+ const [actionType, setActionType] = useState('delete')
+ const [classError, setClassError] = useState(false)
const [updatedUser, setUpdatedUser] = useState({
firstname: '',
lastname: '',
email: '',
- picture: null
+ classes: [],
+ picture: null,
+ role: ''
})
+ async function getSuspendedAccountList (accounts) {
+ const baseUrl = process.env.REACT_APP_BACKEND_URL + '/user/getDisabled'
+ const token = sessionStorage.getItem('token')
+
+ const resp = await fetch(baseUrl, {
+ method: 'GET',
+ headers: {
+ 'x-auth-token': token,
+ 'Content-Type': 'application/json'
+ }
+ })
+ if (resp.status === 401) {
+ disconnect()
+ } else {
+ const data = await resp.json()
+ const array = [...accounts, ...data]
+
+ const teacherAccounts = array.filter(account => account.role.name === 'teacher')
+ const studentAccounts = array.filter(account => account.role.name === 'student')
+ setTeacherList(teacherAccounts)
+ setStudentList(studentAccounts)
+ }
+ }
+
async function getAccountList () {
const baseUrl = `${process.env.REACT_APP_BACKEND_URL}/user/all`
const token = sessionStorage.getItem('token')
@@ -45,7 +78,26 @@ export default function SchoolAccountsTable () {
setTeacherList(teacherAccounts)
setStudentList(studentAccounts)
+ getSuspendedAccountList(data)
}
+
+ fetch(process.env.REACT_APP_BACKEND_URL + '/shared/classes', {
+ method: 'GET',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ return response.json()
+ })
+ .then((data) => setClassesList(data))
+ .catch((error) => {
+ toast.error(error.message)
+ })
}
const showClasses = (classes) => {
@@ -71,8 +123,11 @@ export default function SchoolAccountsTable () {
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
- picture: user.picture
+ classes: user.classes,
+ picture: user.picture,
+ role: user.role._id
})
+ setIsMultiStatus(user.role.name === 'teacher')
setIsEditing(true)
}
@@ -84,40 +139,75 @@ export default function SchoolAccountsTable () {
}))
}
+ const handleClassChange = (e) => {
+ setUpdatedUser(prevState => ({
+ ...prevState,
+ classes: e
+ }))
+ }
+
const handleFileChange = (e) => {
setFileImage(e.target.files[0])
setUpdatedUser(prevState => ({
...prevState,
picture: e.target.files[0]
}))
- // const selectedFile = e.target.files[0]
- // if (selectedFile) {
- // const reader = new FileReader()
- // reader.readAsDataURL(selectedFile)
- // reader.onload = () => {
- // const base64Image = reader.result
- // setUpdatedUser(prevState => ({
- // ...prevState,
- // picture: base64Image
- // }))
- // }
- // reader.onerror = (error) => {
- // console.error('Error occurred while reading the file:', error)
- // }
- // }
+ }
+
+ function callAction (classe, action) {
+ fetch(process.env.REACT_APP_BACKEND_URL + '/adm/classes/' + classe._id + action, {
+ method: 'PATCH',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(action === '/updateStudent' ? { studentId: selectedUser._id } : { teacherId: selectedUser._id })
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ })
+ .catch((error) => {
+ setClassError(true)
+ toast.error('Un problème est survenu avec la classe.', error.message)
+ })
+ }
+
+ const handleUltimateClassChange = () => {
+ if (selectedUser.role.name === 'teacher') {
+ const removeClasses = []
+ const addClasses = []
+
+ // Assuming selectedUser and updatedUser have a `classes` property that is an array
+ const selectedUserClasses = selectedUser.classes || []
+ const updatedUserClasses = updatedUser.classes || []
+
+ addClasses.push(...updatedUserClasses.filter((cls) => !selectedUserClasses.includes(cls)))
+
+ removeClasses.push(...selectedUserClasses.filter((cls) => !updatedUserClasses.includes(cls)))
+
+ removeClasses.map((classe) => { return callAction(classe, '/removeTeacher') })
+ addClasses.map(classe => { return callAction(classe, '/addTeacher') })
+ } else {
+ const studentClass = []
+ studentClass.push(updatedUser.classes)
+
+ studentClass.map(classe => { return callAction(classe, '/updateStudent') })
+ }
+ if (!classError) { toast.success('Le profil a été mis à jour avec succès.') }
}
const handleUpdate = async (e) => {
e.preventDefault()
+
try {
const formData = new FormData()
formData.append('firstname', updatedUser.firstname)
formData.append('lastname', updatedUser.lastname)
+ formData.append('role', updatedUser.role)
formData.append('email', updatedUser.email)
- // if (updatedUser.picture) {
- // formData.append('file', updatedUser.picture)
- // }
- console.log(fileImage)
+
if (fileImage) {
formData.append('file', fileImage)
}
@@ -133,17 +223,11 @@ export default function SchoolAccountsTable () {
if (response.status === 401) {
disconnect()
} else if (response.ok) {
- // setSelectedUser(null)
- // setUpdatedUser({
- // firstname: '',
- // lastname: '',
- // email: '',
- // picture: null
- // })
- setFileImage(null)
- toast.success('Le profil a été mis à jour avec succès.')
setIsEditing(false)
+ setFileImage(null)
+ handleUltimateClassChange()
getAccountList() // Refresh the list
+ setClassError(false)
} else {
toast.error('Erreur lors de la mise à jour du profil: ' + response.statusText)
}
@@ -171,6 +255,30 @@ export default function SchoolAccountsTable () {
} else if (resp.status === 200) {
toast.success(deleteType ? 'Le compte a été supprimé' : 'Le compte a été suspendu')
getAccountList()
+ setIsPopupOpen(false)
+ } else {
+ toast.error("une alerte s'est produite")
+ getAccountList()
+ }
+ }
+
+ async function activateAccount (accountId) {
+ const baseUrl = process.env.REACT_APP_BACKEND_URL + '/adm/activateUser/' + accountId
+ const token = sessionStorage.getItem('token')
+
+ const resp = await fetch(baseUrl, {
+ method: 'POST',
+ headers: {
+ 'x-auth-token': token,
+ 'Content-Type': 'application/json'
+ }
+ })
+ if (resp.status === 401) {
+ disconnect()
+ } else if (resp.status === 200) {
+ toast.success('Le compte a été restauré')
+ getAccountList()
+ setIsPopupOpen(false)
} else {
toast.error("une alerte s'est produite")
getAccountList()
@@ -186,7 +294,8 @@ export default function SchoolAccountsTable () {
setIsEditing(!isEditing)
}
- const callDeleteAccount = (userIdValue) => {
+ const callDeleteAccount = (userIdValue, action) => {
+ setActionType(action)
setUserId(userIdValue)
setIsPopupOpen(!isPopupOpen)
}
@@ -197,7 +306,7 @@ export default function SchoolAccountsTable () {
{(close) => (
-
+
)}
@@ -207,44 +316,63 @@ export default function SchoolAccountsTable () {
Modifier Profil
-
@@ -266,8 +394,8 @@ export default function SchoolAccountsTable () {
Nom
Email
Classe(s)
-
Modifier
- {sessionStorage.getItem('role') !== 'teacher' ?
: ''}
+ {status &&
Modifier }
+ {status ?
: ''}
@@ -279,8 +407,16 @@ export default function SchoolAccountsTable () {
{data.lastname}
{data.email}
{showClasses(data.classes)}
- { e.stopPropagation(); handleEditClick(data) }} title='Modifier le profil'>Modifier
- {sessionStorage.getItem('role') !== 'teacher' && { e.stopPropagation(); callDeleteAccount(data._id) }} src={minusButton} alt='delete' title='Supprimer ou suspendre le compte' /> }
+ {status && { e.stopPropagation(); handleEditClick(data) }} title='Modifier le profil'>Modifier }
+ {status &&
+
+ {
+ data.active
+ ? { e.stopPropagation(); callDeleteAccount(data._id, 'suspend') }} src={suspendButton} alt='delete' title='Suspendre le compte' />
+ : { e.stopPropagation(); callDeleteAccount(data._id, 'restore') }} src={restoreButton} alt='delete' title='Restaurer le compte' />
+ }
+ { e.stopPropagation(); callDeleteAccount(data._id, 'delete') }} src={deleteButton} alt='delete' title='Supprimer le compte' />
+ }
)
}
@@ -302,8 +438,8 @@ export default function SchoolAccountsTable () {
Nom
Email
Classe
- Modifier
- {sessionStorage.getItem('role') !== 'teacher' ? : ''}
+ {status && Modifier }
+ {status ? : ''}
@@ -315,8 +451,16 @@ export default function SchoolAccountsTable () {
{data.lastname}
{data.email}
{showClasses(data.classes)}
- { e.stopPropagation(); handleEditClick(data) }} title='Modifier le Profil'>Modifier
- {sessionStorage.getItem('role') !== 'teacher' && { e.stopPropagation(); callDeleteAccount(data._id) }} src={minusButton} alt='delete' title='Supprimer ou suspendre le compte' /> }
+ {status && { e.stopPropagation(); handleEditClick(data) }} title='Modifier le Profil'>Modifier }
+ {status &&
+
+ {
+ data.active
+ ? { e.stopPropagation(); callDeleteAccount(data._id, 'suspend') }} src={suspendButton} alt='delete' title='Suspendre le compte' />
+ : { e.stopPropagation(); callDeleteAccount(data._id, 'restore') }} src={restoreButton} alt='delete' title='Restaurer le compte' />
+ }
+ { e.stopPropagation(); callDeleteAccount(data._id, 'delete') }} src={deleteButton} alt='delete' title='Supprimer le compte' />
+ }
)
}
diff --git a/src/Components/Aides/aides.jsx b/src/Components/Aides/aides.jsx
index 041565f1..46f9b6e6 100644
--- a/src/Components/Aides/aides.jsx
+++ b/src/Components/Aides/aides.jsx
@@ -3,13 +3,13 @@ import '../../css/Components/Aides/aides.scss'
import { disconnect } from '../../functions/disconnect'
import phoneIcon from '../../assets/phoneIcon.png'
import mailIcon from '../../assets/mailIcon.png'
+import { toast } from 'react-toastify'
export default function AidePage () {
const [categories, setCategories] = useState([])
const [contacts, setContacts] = useState([])
const [chosenContact, setChosenContact] = useState([])
const [filteredContacts, setFilteredContacts] = useState([])
- const [errMessage, setErrMessage] = useState('')
const [defaultID, setDefaultID] = useState(null)
const [selectedCat, setSelectedCat] = useState(null)
const [selectedContact, setSelectedContact] = useState(null)
@@ -39,7 +39,7 @@ export default function AidePage () {
setSelectedCat(filterID[0]._id)
}
})
- .catch(error => setErrMessage(error.message))
+ .catch(error => toast.error(error.message))
fetch(helpNumbersUrl, {
method: 'GET',
@@ -59,7 +59,7 @@ export default function AidePage () {
setChosenContact(data[0])
setSelectedContact(data[0]._id)
})
- .catch(error => setErrMessage('Erreur ' + error.status + ': ' + error.message))
+ .catch(error => toast.error('Erreur ' + error.status + ': ' + error.message))
}, [])
const filterContactsByCategory = (category) => {
@@ -90,7 +90,6 @@ export default function AidePage () {
return (
-
{errMessage || ''}
{categories.map((category) => (
filterContactsByCategory(category._id)}>
@@ -107,26 +106,26 @@ export default function AidePage () {
)}
diff --git a/src/Components/Alerts/lastAlerts.js b/src/Components/Alerts/lastAlerts.js
index 09e59fcb..08801d96 100644
--- a/src/Components/Alerts/lastAlerts.js
+++ b/src/Components/Alerts/lastAlerts.js
@@ -5,9 +5,9 @@ import { Link } from 'react-router-dom'
import rightArrowInverted from '../../assets/right-arrow-inverted.png'
import UserProfile from '../userProfile/userProfile'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
export function LastAlerts () {
- const [errMessage, setErrMessage] = useState('')
const [alerts, setAlerts] = useState([])
useEffect(() => {
@@ -75,7 +75,7 @@ export function LastAlerts () {
promisedList.then((alertList) => setAlerts(alertList))
})
.catch((error) => {
- setErrMessage('Erreur : ', error.message)
+ toast.error('Erreur : ', error.message)
})
}, [])
@@ -117,9 +117,6 @@ export function LastAlerts () {
)
: (Vous n'avez pas de nouvelle alerte.
)
}
- {
- errMessage ? {errMessage}
: ''
- }
)
diff --git a/src/Components/Alerts/showAlerts.js b/src/Components/Alerts/showAlerts.js
index 5325fd25..82f768f3 100644
--- a/src/Components/Alerts/showAlerts.js
+++ b/src/Components/Alerts/showAlerts.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react'
+import React from 'react'
import '../../css/Components/Alerts/lastAlerts.scss'
import '../../css/pages/createAlerts.scss'
import UserProfile from '../userProfile/userProfile'
diff --git a/src/Components/ChatRoom/chatRoom.jsx b/src/Components/ChatRoom/chatRoom.jsx
index 10086f7c..87059561 100644
--- a/src/Components/ChatRoom/chatRoom.jsx
+++ b/src/Components/ChatRoom/chatRoom.jsx
@@ -15,7 +15,6 @@ import UserProfile from '../../Components/userProfile/userProfile'
const Messages = () => {
const [conversations, setConversations] = useState([])
const [currentConversation, setCurrentConversation] = useState('')
- const [currentParticipants, setCurrentParticipants] = useState('')
const [notification, setNotification] = useState({ visible: false, message: '', type: '' })
const { send, chats } = useContext(WebsocketContext) // eslint-disable-line
const inputFile = useRef(null)
@@ -51,7 +50,7 @@ const Messages = () => {
noUserParticipants.map((participant) => (
convName.push(participant.firstname + ' ' + participant.lastname)
))
- setCurrentParticipants(convName.join(', '))
+ // setCurrentParticipants(convName.join(', '))
return {
_id: conversation._id,
date: conversation.date,
@@ -265,6 +264,10 @@ const Messages = () => {
setShowCreateConversationPopup(!showCreateConversationPopup)
}
+ const truncateString = (str) => {
+ return str.length > 25 ? str.slice(0, 30) + '...' : str
+ }
+
const createConversation = async (convTitle, selectedContacts) => {
try {
const userId = localStorage.getItem('id')
@@ -397,7 +400,6 @@ const Messages = () => {
conversations={conversations}
currentConversation={currentConversation}
setCurrentConversation={setCurrentConversation}
- setCurrentParticipants={setCurrentParticipants}
clearMessageAndError={clearMessageAndError}
openCreateConversationPopup={openCreateConversationPopup}
/>
@@ -411,7 +413,7 @@ const Messages = () => {
-
{currentConversation.name}
+
{truncateString(currentConversation.name)}
{currentConversation.participants.length} {currentConversation.participants.length > 1 ? 'membres' : 'membre'}
@@ -420,15 +422,15 @@ const Messages = () => {
setShowAddParticipantsPopup(true)}>
Gestion de la conversation
-
Signaler} modal contentStyle={{width: '400px'}}>
- {(close) => (
-
-
-
- )}
+ Signaler} modal contentStyle={{ width: '400px' }}>
+ {(close) => (
+
+
+
+ )}
@@ -493,7 +495,7 @@ const Messages = () => {
Aucune conversation sélectionnée.
)}
-
+
{(close) => (
Nouvelle conversation
@@ -502,7 +504,7 @@ const Messages = () => {
)}
- setShowAddParticipantsPopup(false)} modal contentStyle={{width: '400px'}}>
+ setShowAddParticipantsPopup(false)} modal contentStyle={{ width: '400px' }}>
{(close) => (
Gestion de la conversation
diff --git a/src/Components/ChatRoom/chatRoomSidebar.jsx b/src/Components/ChatRoom/chatRoomSidebar.jsx
index 352697cc..3874acab 100644
--- a/src/Components/ChatRoom/chatRoomSidebar.jsx
+++ b/src/Components/ChatRoom/chatRoomSidebar.jsx
@@ -6,7 +6,6 @@ const ChatRoomSidebar = ({
conversations,
currentConversation,
setCurrentConversation,
- setCurrentParticipants,
clearMessageAndError,
openCreateConversationPopup
}) => {
@@ -23,7 +22,10 @@ const ChatRoomSidebar = ({
conversation.participants?.map((participant) => (
conv.push(participant.firstname + ' ' + participant.lastname)
))
- setCurrentParticipants(conv.join(', '))
+ }
+
+ const truncateString = (str) => {
+ return str.length > 25 ? str.slice(0, 30) + '...' : str
}
return (
@@ -33,13 +35,12 @@ const ChatRoomSidebar = ({
+ Nouvelle conversation
- {/*
*/}
{conversations.map((conversation, index) => (
handleClick(conversation)}>
-
- {conversation.name}
+
+ {truncateString(conversation.name)}
{
(chats.value.unseenChats.includes(conversation._id)) &&
diff --git a/src/Components/ChatRoom/reportButton.jsx b/src/Components/ChatRoom/reportButton.jsx
index 28947a90..482a0906 100644
--- a/src/Components/ChatRoom/reportButton.jsx
+++ b/src/Components/ChatRoom/reportButton.jsx
@@ -2,8 +2,8 @@ import React, { useState } from 'react'
import '../../css/pages/createReports.scss'
import '../../css/Components/Popup/popup.scss'
import { disconnect } from '../../functions/disconnect'
-import Select from 'react-select';
-import { toast } from 'react-toastify';
+import Select from 'react-select'
+import { toast } from 'react-toastify'
import cross from '../../assets/Cross.png'
const ReportButton = ({ currentConversation, close }) => {
@@ -30,19 +30,20 @@ const ReportButton = ({ currentConversation, close }) => {
const colourStyles = {
control: (styles) => (
- { ...styles,
+ {
+ ...styles,
backgroundColor: 'white',
- height: '45px',
+ height: '45px'
}
),
multiValueLabel: (styles, { data }) => ({
...styles,
fontWeight: '500'
- }),
- };
+ })
+ }
const handleCloseBtn = () => {
- close();
+ close()
}
const handleConfirmClick = async () => {
@@ -85,7 +86,7 @@ const ReportButton = ({ currentConversation, close }) => {
return (
<>
-
+
Créer un Signalement
@@ -115,9 +116,9 @@ const ReportButton = ({ currentConversation, close }) => {
getOptionLabel={(option) => (option.firstname + ' ' + option.lastname)}
/>
-
+
Description
-
+
Confirmer le signalement
>
diff --git a/src/Components/Graph/studentGraphSpace.js b/src/Components/Graph/studentGraphSpace.js
index 0851189a..f89914c2 100644
--- a/src/Components/Graph/studentGraphSpace.js
+++ b/src/Components/Graph/studentGraphSpace.js
@@ -38,7 +38,9 @@ export function StudentGraphSpace () {
return aDate - bDate
})
const sortedMoodData = {}
- keys.forEach((key) => sortedMoodData[key] = moodData[key])
+ keys.forEach((key) => {
+ sortedMoodData[key] = moodData[key]
+ })
createOrUpdateChart(sortedMoodData)
} catch (error) {
console.error('Error fetching mood data:', error)
@@ -66,7 +68,7 @@ export function StudentGraphSpace () {
pointBorderColor: 'white',
pointHoverBackgroundColor: 'white',
pointHoverBorderColor: 'white',
- tension: 0.1,
+ tension: 0.1
}
]
},
diff --git a/src/Components/Graph/teacherGraphSpace.js b/src/Components/Graph/teacherGraphSpace.js
index f6b746c6..1bd57412 100644
--- a/src/Components/Graph/teacherGraphSpace.js
+++ b/src/Components/Graph/teacherGraphSpace.js
@@ -17,9 +17,9 @@ Chart.register(LineController, LineElement, PointElement, LinearScale, Title, Ca
export function TeacherGraphSpace () {
const [moodData, setMoodData] = useState([])
- const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0])
- const [activeFilter, setActiveFilter] = useState('Semaine')
- const [selectedClass, setSelectedClass] = useState(null)
+ const selectedDate = useState(new Date().toISOString().split('T')[0])
+ const activeFilter = useState('Semaine')
+ const selectedClass = useState(null)
const moodChartRef = useRef(null)
@@ -44,7 +44,7 @@ export function TeacherGraphSpace () {
}
const mData = await response.json()
const moodList = []
- Object.keys(mData).filter(o => o != 'averagePercentage').forEach((date) => {
+ Object.keys(mData).filter(o => o !== 'averagePercentage').forEach((date) => {
moodList.push({
date,
data: mData[date].moods
diff --git a/src/Components/Header/headerComp.js b/src/Components/Header/headerComp.js
index 4376c543..17b0be2c 100644
--- a/src/Components/Header/headerComp.js
+++ b/src/Components/Header/headerComp.js
@@ -70,11 +70,9 @@ export default function HeaderComp ({ title, withLogo = true, subtitle, withRetu
})
.then((data) => {
setNotifications(data)
- // setNbNotification(data.length)
})
.catch((error) => /* istanbul ignore next */ {
console.error(error)
- // setErrMessage('Erreur : ', error.message)
})
}
diff --git a/src/Components/Popup/accessingReportedConversation.jsx b/src/Components/Popup/accessingReportedConversation.jsx
new file mode 100644
index 00000000..0f89bb25
--- /dev/null
+++ b/src/Components/Popup/accessingReportedConversation.jsx
@@ -0,0 +1,81 @@
+import React, { useEffect, useState } from 'react'
+import '../../css/Components/Popup/popup.scss'
+import '../../css/pages/createAlerts.scss'
+import Message from '../../Components/ChatRoom/message'
+import UserProfile from '../../Components/userProfile/userProfile'
+import '../../css/pages/chatRoomPage.scss'
+
+const AccessingReportedConversationPopupContent = ({ signaledBy, reportedConversation }) => {
+ const [currentConversation, setCurrentConversation] = useState('')
+ const [messages, setMessages] = useState([])
+
+ useEffect(() => {
+ const convParticipants = reportedConversation.participants.map(participant => participant.user)
+ const convName = []
+ convParticipants.map((participant) => (
+ convName.push(participant.firstname + ' ' + participant.lastname)
+ ))
+ setCurrentConversation({
+ _id: reportedConversation._id,
+ date: reportedConversation.date,
+ participants: convParticipants,
+ name: reportedConversation.title !== 'placeholder title' ? reportedConversation.title : convName.join(', ')
+ })
+
+ const messageData = reportedConversation.messages.map((message) => ({
+ contentType: !message.file ? 'text' : 'file',
+ ...message
+ }))
+ setMessages(messageData)
+ }, [reportedConversation, signaledBy])
+
+ const truncateString = (str) => {
+ return str.length > 25 ? str.slice(0, 30) + '...' : str
+ }
+
+ return (
+
+
+ {currentConversation
+ ? (
+
+
+
+
{truncateString(currentConversation.name)}
+
+ {currentConversation.participants.length} {currentConversation.participants.length > 1 ? 'membres' : 'membre'}
+
+
+
+
+
+
+
+ {messages.map((message, index) => (
+
+ ))}
+
+
+
+
+ {currentConversation.participants.map((participant, indexP) => (
+
+
+
+ ))}
+
+
+
+ )
+ : (
+
Cette converssation n'est pas disponible actuellement.
+ )}
+
+
+ )
+}
+
+export default AccessingReportedConversationPopupContent
diff --git a/src/Components/Popup/alertCreation.jsx b/src/Components/Popup/alertCreation.jsx
index a6e96285..66d6c210 100644
--- a/src/Components/Popup/alertCreation.jsx
+++ b/src/Components/Popup/alertCreation.jsx
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react'
+import { toast } from 'react-toastify'
import '../../css/Components/Popup/popup.scss'
import '../../css/pages/createAlerts.scss'
import { disconnect } from '../../functions/disconnect'
@@ -13,7 +14,6 @@ const AlertCreationPopupContent = () => {
const [selectedClasses, setSelectedClasses] = useState([])
const [file, setFile] = useState(null)
const [isClass, setIsClass] = useState(true)
- const [errMessage, setErrMessage] = useState('')
useEffect(() => {
// Requête GET : récupération de la liste des types d’utilisateurs
@@ -34,7 +34,7 @@ const AlertCreationPopupContent = () => {
setRole(data.roles[0]._id)
setUserRoles(data.roles)
})
- .catch((error) => /* istanbul ignore next */ { setErrMessage('Erreur lors de la récupération des roles', error.message) })
+ .catch((error) => /* istanbul ignore next */ { toast.error('Erreur lors de la récupération des roles', error.message) })
// Requête GET : récupération des classes dont l’utilisateur est en charge
fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/classes`, {
@@ -51,7 +51,7 @@ const AlertCreationPopupContent = () => {
return response.json()
})
.then((data) => (data.message === 'Access Forbidden' ? setUserClasses([]) : setUserClasses(data)))
- .catch((error) => /* istanbul ignore next */ { setErrMessage('Erreur lors de la récupération des classes', error.message) })
+ .catch((error) => /* istanbul ignore next */ { toast.error('Erreur lors de la récupération des classes', error.message) })
}, [])
const handleAlertSubmit = async (e) => {
@@ -71,16 +71,16 @@ const AlertCreationPopupContent = () => {
}
if (title === '') {
- setErrMessage('Le titre est vide.')
+ toast.error('Le titre est vide.')
return
} else if (message === '') {
- setErrMessage('Le message est vide.')
+ toast.error('Le message est vide.')
return
} else if (isClass && selectedClasses.length === 0) {
- setErrMessage("Aucune classe n'a été sélectionnée.")
+ toast.error("Aucune classe n'a été sélectionnée.")
return
} else if (!isClass && role === '') {
- setErrMessage("Aucun rôle n'a été sélectionné.")
+ toast.error("Aucun rôle n'a été sélectionné.")
return
}
@@ -99,7 +99,7 @@ const AlertCreationPopupContent = () => {
return response.json()
})
.then((data) => {
- setErrMessage('Alerte envoyée avec succès')
+ toast.success('Alerte envoyée avec succès')
if (file) {
addFileToAlert(data._id)
} else {
@@ -107,7 +107,7 @@ const AlertCreationPopupContent = () => {
}
})
.catch((error) => /* istanbul ignore next */ {
- setErrMessage('Erreur lors de l\'envoi de l\'alerte', error)
+ toast.error('Erreur lors de l\'envoi de l\'alerte', error)
})
function addFileToAlert (id) {
@@ -125,10 +125,10 @@ const AlertCreationPopupContent = () => {
if (response.status === 401) {
disconnect()
}
- setErrMessage('Fichier envoyé avec l\'alerte avec succès')
+ toast.success('Fichier envoyé avec l\'alerte avec succès')
window.location.reload()
})
- .catch((error) => /* istanbul ignore next */ { setErrMessage('Erreur lors de l\'envoi du fichier avec l\'alerte', error) })
+ .catch((error) => /* istanbul ignore next */ { toast.error('Erreur lors de l\'envoi du fichier avec l\'alerte', error) })
}
}
@@ -211,7 +211,6 @@ const AlertCreationPopupContent = () => {
Fichier joint
setFile(e.target.files[0])} />
- {errMessage ?
{errMessage} : ''}
Créer l'Alerte
>
)
diff --git a/src/Components/Popup/alertDeletion.jsx b/src/Components/Popup/alertDeletion.jsx
new file mode 100644
index 00000000..b8bcc388
--- /dev/null
+++ b/src/Components/Popup/alertDeletion.jsx
@@ -0,0 +1,15 @@
+import React from 'react'
+import '../../css/Components/Popup/popup.scss'
+import '../../css/pages/createAlerts.scss'
+
+const AlertDeletionPopupContent = ({ onClose, chosenAlert, handleDeleteAlert }) => {
+ return (
+ <>
+
Êtes-vous certain(e) de vouloir supprimer cette alerte ?
+
Cette action sera irréversible.
+
handleDeleteAlert(chosenAlert.id, onClose)}>Supprimer l'Alerte
+ >
+ )
+}
+
+export default AlertDeletionPopupContent
diff --git a/src/Components/Popup/alertModification.jsx b/src/Components/Popup/alertModification.jsx
index f4cc7841..fa935477 100644
--- a/src/Components/Popup/alertModification.jsx
+++ b/src/Components/Popup/alertModification.jsx
@@ -1,9 +1,12 @@
import React, { useState, useEffect } from 'react'
import '../../css/Components/Popup/popup.scss'
import '../../css/pages/createAlerts.scss'
+import { toast } from 'react-toastify'
+import { disconnect } from '../../functions/disconnect'
-const AlertModificationPopupContent = ({ chosenAlert, handleEditAlert, errMessage }) => {
+const AlertModificationPopupContent = ({ onClose, chosenAlert, handleEditAlert }) => {
const [editedAlert, setEditedAlert] = useState(chosenAlert)
+ const [file, setFile] = useState(null)
useEffect(() => {
setEditedAlert(chosenAlert)
@@ -13,6 +16,33 @@ const AlertModificationPopupContent = ({ chosenAlert, handleEditAlert, errMessag
setEditedAlert({ ...editedAlert, [e.target.name]: e.target.value })
}
+ function addFileToAlert (id) {
+ const fileData = new FormData()
+ fileData.append('file', file)
+
+ fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/alert/file/${id}`, {
+ method: 'POST',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token')
+ },
+ body: fileData
+ })
+ .then(response => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ toast.success('Fichier envoyé avec l\'alerte avec succès')
+ })
+ .catch((error) => /* istanbul ignore next */ {
+ toast.error(`Erreur lors de l'envoi du fichier avec l'alerte ${error.message}`)
+ })
+ }
+
+ const editAlert = (e) => {
+ if (file !== null) { addFileToAlert(chosenAlert.id) }
+ handleEditAlert(editedAlert, onClose)
+ }
+
return (
<>
@@ -23,12 +53,11 @@ const AlertModificationPopupContent = ({ chosenAlert, handleEditAlert, errMessag
Message *
- {/*
+
Fichier joint
setFile(e.target.files[0])} />
- */}
- {errMessage ? {errMessage} : ''}
- handleEditAlert(editedAlert)}>Modifier l'Alerte
+
+
editAlert()}>Modifier l'Alerte
>
)
}
diff --git a/src/Components/Popup/categoryCreation.jsx b/src/Components/Popup/categoryCreation.jsx
index 72ce729d..c0f21a04 100644
--- a/src/Components/Popup/categoryCreation.jsx
+++ b/src/Components/Popup/categoryCreation.jsx
@@ -1,23 +1,15 @@
import React, { useState } from 'react'
import '../../css/Components/Popup/popup.scss'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
-const CategoryCreationPopupContent = () => {
+const CategoryCreationPopupContent = ({ onClose }) => {
const [name, setName] = useState('')
- const [errMessage, setErrMessage] = useState('')
- const [notification, setNotification] = useState({ visible: false, message: '', type: '' })
const handleNameChange = (event) => {
setName(event.target.value)
}
- const openNotification = (message, type) => {
- setNotification({ visible: true, message, type })
- setTimeout(() => {
- setNotification({ visible: false, message: '', type: '' })
- }, 3000) // La notification sera visible pendant 3 secondes
- }
-
const fetchCategoryRegister = async () => {
const categoryRegisterUrl = process.env.REACT_APP_BACKEND_URL + '/adm/helpNumbersCategory/register'
@@ -36,24 +28,17 @@ const CategoryCreationPopupContent = () => {
disconnect()
}
if (response.ok) {
- setErrMessage('Catégorie créée avec succès.')
- openNotification('Catégorie créée avec succès.', 'success')
- setTimeout(() => {
- window.location.reload()
- }, 2000)
+ toast.success('Catégorie créée avec succès.')
} else {
const data = await response.json()
- setErrMessage(data.message)
- openNotification(data.message, 'error')
+ toast.error(data.message)
}
})
.catch((error) => {
- setErrMessage(error.message)
- openNotification(error.message, 'error')
+ toast.error(error.message)
})
} else {
- setErrMessage('La catégorie est vide.')
- openNotification('La catégorie est vide.', 'error')
+ toast.error('La catégorie est vide.')
}
}
@@ -63,11 +48,6 @@ const CategoryCreationPopupContent = () => {
Catégorie *
- {errMessage ?
{errMessage} : ''}
- {notification.visible &&
-
- {notification.message}
-
}
Créer la Catégorie
>
)
diff --git a/src/Components/Popup/conversationCreation.jsx b/src/Components/Popup/conversationCreation.jsx
index f776101b..f027331f 100644
--- a/src/Components/Popup/conversationCreation.jsx
+++ b/src/Components/Popup/conversationCreation.jsx
@@ -42,31 +42,32 @@ const ConversationCreationPopupContent = ({ contacts, createConversation, closeC
const colourStyles = {
control: (styles) => (
- { ...styles,
+ {
+ ...styles,
backgroundColor: 'white',
- height: '45px',
+ height: '45px'
}
),
multiValueLabel: (styles, { data }) => ({
...styles,
fontWeight: '500'
- }),
- };
+ })
+ }
return (
<>
{isAddingParticipants && (
-
Membres actuels ({members.length})
-
+
Membres actuels ({members.length})
+
{members && members.map((member, index) => (
-
{member.firstname} {member.lastname}
+
{member.firstname} {member.lastname}
))}
)}
- {isAddingParticipants ?
Sélectionner un/des utilisateur(s) :
Rechercher un ou plusieurs membre(s) * }
+ {isAddingParticipants ?
Sélectionner un/des utilisateur(s) :
Rechercher un ou plusieurs membre(s) * }
{!isAddingParticipants && (
- Donner un nom à la conversation
+ Donner un nom à la conversation
)}
-
-
+
+
{isAddingParticipants ? 'Ajouter le membre' : 'Créer la conversation'}
{isAddingParticipants && (
-
setShowLeaveConversationPopup(true)}>
+ setShowLeaveConversationPopup(true)}>
Quitter la conversation
)}
diff --git a/src/Components/Popup/csvAccountCreation.jsx b/src/Components/Popup/csvAccountCreation.jsx
index 375bb019..3e5aa34a 100644
--- a/src/Components/Popup/csvAccountCreation.jsx
+++ b/src/Components/Popup/csvAccountCreation.jsx
@@ -1,14 +1,11 @@
import React, { useState } from 'react'
import '../../css/Components/Popup/popup.scss'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
const CsvAccountCreationPopupContent = () => {
const role = sessionStorage.getItem('role')
const [fileName, setFile] = useState()
- const [errMessage, setErrMessage] = useState('')
- const [successMessage, setSuccessMessage] = useState('')
- const [popupVisible, setPopupVisible] = useState(false)
- const [popupContent, setPopupContent] = useState('')
const csvCreationUrl = process.env.REACT_APP_BACKEND_URL + '/adm/csvRegisterUser'
@@ -16,16 +13,6 @@ const CsvAccountCreationPopupContent = () => {
setFile(event.target.files[0])
}
- const openPopup = (message) => {
- setPopupContent(message)
- setPopupVisible(true)
- }
-
- const closePopup = () => {
- setPopupVisible(false)
- setPopupContent('')
- }
-
const csvAccountCreation = async (event) => {
event.preventDefault()
const formData = new FormData()
@@ -44,16 +31,14 @@ const CsvAccountCreationPopupContent = () => {
}
const data = await response.json()
if (response.ok) {
- setSuccessMessage('Compte(s) créé(s) avec succès')
- openPopup('Compte(s) créé(s) avec succès')
+ toast.success('Compte(s) créé(s) avec succès')
window.location.reload()
} else {
- openPopup(`À la ligne ${data[0].rowCSV} du fichier CSV, ${data[0].errors[0]}`)
+ toast.error(`À la ligne ${data[0].rowCSV} du fichier CSV, ${data[0].errors[0]}`)
}
})
.catch((error) => {
- setErrMessage(error.message)
- openPopup(error.message)
+ toast.error(error.message)
})
}
@@ -61,17 +46,24 @@ const CsvAccountCreationPopupContent = () => {
<>
- Le fichier attendu est un fichier .csv suivant le format: {role === 'admin' ? 'firstname,lastname,email' : 'firstname,lastname,email,role,class'}
+ Le fichier attendu est un fichier .csv suivant le format: {role === 'admin'
+ ? (
+ <>
+ firstname,lastname,email,role
+ exemple,exemple,exemple@exemple,administration
+ exemple,exemple,exemple@exemple,administration
+ >
+ )
+ : (
+ <>
+ firstname,lastname,email,role,class
+ exemple,exemple,exemple@exemple,teacher,0:1:2
+ exemple,exemple,exemple@exemple,student,0
+ exemple,exemple,exemple@exemple,student,1
+ >
+ )}
+
- {errMessage ? {errMessage} : ''}
- {successMessage ? {successMessage} : ''}
- {popupVisible &&
- }
Créer le(s) Compte(s)
>
)
diff --git a/src/Components/Popup/deleteAccount.jsx b/src/Components/Popup/deleteAccount.jsx
index 467a68f9..10cc3c5c 100644
--- a/src/Components/Popup/deleteAccount.jsx
+++ b/src/Components/Popup/deleteAccount.jsx
@@ -2,17 +2,30 @@ import React from 'react'
import '../../css/Components/Popup/popup.scss'
import '../../css/pages/createAlerts.scss'
-const DeleteAccountPopupContent = ({ userIdValue, deleteUserAccount, closeDeleteAccountPopup }) => {
+const DeleteAccountPopupContent = ({ userIdValue, actionType, deleteUserAccount, activateAccount, closeDeleteAccountPopup }) => {
+ const handleAction = (action) => {
+ if (!action) {
+ deleteUserAccount(false, userIdValue)
+ } else {
+ activateAccount(userIdValue)
+ }
+ closeDeleteAccountPopup()
+ }
+
return (
<>
-
Suppression du Compte
-
Êtes-vous sûr(e) de vouloir supprimer ce compte ?
-
Une suppression temporaire dure 7 jours.
-
Cette action sera irreversible.
+
{actionType === 'delete' ? 'Suppression' : actionType === 'suspend' ? 'Suspension' : 'Restauration'} du Compte
+
Êtes-vous sûr(e) de vouloir {actionType === 'delete' ? 'supprimer' : actionType === 'suspend' ? 'suspendre' : 'restaurer'} ce compte ?
+
{actionType === 'delete' ? 'Cette action sera irreversible.' : ''}
- deleteUserAccount(true, userIdValue)}>Suppression définitive
- deleteUserAccount(false, userIdValue)}>Suppression temporaire
+ {
+ actionType === 'delete'
+ ? deleteUserAccount(true, userIdValue)}>Supprimer
+ : actionType === 'suspend'
+ ? handleAction(false)}>Suspendre
+ : handleAction(true)}>Restaurer
+ }
Annuler
>
)
diff --git a/src/Components/Popup/desanonymFeeling.jsx b/src/Components/Popup/desanonymFeeling.jsx
new file mode 100644
index 00000000..9d8f4e0a
--- /dev/null
+++ b/src/Components/Popup/desanonymFeeling.jsx
@@ -0,0 +1,23 @@
+import React, { useState } from 'react'
+import '../../css/Components/Popup/popup.scss'
+import '../../css/pages/createAlerts.scss'
+
+const DesanonymFeelingPopupContent = ({ handleAskDesanonym }) => {
+ const [message, setMessage] = useState('')
+
+ const handleMessage = (event) => {
+ setMessage(event.target.value)
+ }
+
+ return (
+
+
Demande de désanonymisation d'un ressenti
+
+
+
+ handleAskDesanonym(message)}>Faire la demande
+
+ )
+}
+
+export default DesanonymFeelingPopupContent
diff --git a/src/Components/Popup/facilityClassesCreation.jsx b/src/Components/Popup/facilityClassesCreation.jsx
new file mode 100644
index 00000000..91bbc7e7
--- /dev/null
+++ b/src/Components/Popup/facilityClassesCreation.jsx
@@ -0,0 +1,172 @@
+import React, { useState, useEffect } from 'react'
+import '../../css/Components/Popup/popup.scss'
+import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPenToSquare, faTrashCan, faSquarePlus } from '@fortawesome/free-regular-svg-icons'
+
+const FacilityClassesCreationPopupContent = () => {
+ const [name, setName] = useState('')
+ const [newClass, setNewClass] = useState('')
+ const [classList, setClassList] = useState([])
+ const [isRename, setIsRename] = useState(null)
+
+ function getClasses () {
+ fetch(process.env.REACT_APP_BACKEND_URL + '/shared/classes', {
+ method: 'GET',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ return response.json()
+ })
+ .then((data) => setClassList(data))
+ .catch((error) => {
+ toast.error(error.message)
+ })
+ }
+
+ useEffect(() => {
+ getClasses()
+ }, [])
+
+ const handleCreateClass = () => {
+ if (newClass === '') { return }
+ fetch(process.env.REACT_APP_BACKEND_URL + '/adm/classes/register', {
+ method: 'POST',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ name: newClass
+ })
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ if (response.status === 200) {
+ getClasses()
+ setNewClass('')
+ toast.success('La classe a été créée avec succès.')
+ }
+ })
+ .catch((error) => {
+ toast.error(error.message)
+ })
+ }
+
+ const handleDeleteClass = (classId) => {
+ fetch(process.env.REACT_APP_BACKEND_URL + '/adm/classes/' + classId, {
+ method: 'DELETE',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ if (response.status === 200) {
+ getClasses()
+ toast.success('La classe a été supprimée avec succès.')
+ }
+ })
+ .catch((error) => {
+ toast.error(error.message)
+ })
+ }
+
+ const handleRenameClass = (classId, className) => {
+ if (isRename && classId === isRename) {
+ fetch(process.env.REACT_APP_BACKEND_URL + '/adm/classes/' + classId, {
+ method: 'PATCH',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ name
+ })
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ if (response.status === 422) {
+ toast.warn('Une classe possède déjà ce nom.')
+ }
+ if (response.status === 200) {
+ getClasses()
+ setIsRename(null)
+ setName('')
+ toast.success('La classe a été renommée avec succès.')
+ }
+ })
+ .catch((error) => {
+ toast.error(error.message)
+ })
+ } else {
+ setName(className)
+ setIsRename(classId)
+ }
+ }
+
+ const handleChangeClassName = (e) => {
+ setName(e.target.value)
+ }
+
+ const handleChangeNewClassName = (e) => {
+ setNewClass(e.target.value)
+ }
+
+ const handleKeyPress = (e, classId, className, isNewName) => {
+ if (e.key === 'Enter') {
+ if (isNewName) {
+ handleCreateClass()
+ } else {
+ handleRenameClass(classId, className)
+ }
+ }
+ }
+
+ return (
+
+
Gérer les classes de l'Établissement
+
+
+ handleKeyPress(e, null, null, true)} onChange={handleChangeNewClassName} placeholder='Ajouter une classe ...' />
+
+
+
+
+ {
+ classList.length > 0 && classList.map((classe, index) => (
+
+ {isRename === classe._id
+ ? (
+
+ handleKeyPress(e, classe._id, classe.name, false)} onChange={handleChangeClassName} />
+
+ )
+ :
{classe.name} }
+
+ handleRenameClass(classe._id, classe.name)} />
+ handleDeleteClass(classe._id)} />
+
+
+ ))
+ }
+
+
+ )
+}
+
+export default FacilityClassesCreationPopupContent
diff --git a/src/Components/Popup/helpNumberAndCategoryEditPopupContent.jsx b/src/Components/Popup/helpNumberAndCategoryEditPopupContent.jsx
index 6ac29225..3d77aceb 100644
--- a/src/Components/Popup/helpNumberAndCategoryEditPopupContent.jsx
+++ b/src/Components/Popup/helpNumberAndCategoryEditPopupContent.jsx
@@ -9,6 +9,7 @@ const HelpNumberAndCategoryEditPopupContent = ({ type, onClose }) => {
const [selectedItem, setSelectedItem] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState('')
+ const [categoryList, setCategoryList] = useState([])
useEffect(() => {
const fetchItems = async () => {
@@ -19,8 +20,6 @@ const HelpNumberAndCategoryEditPopupContent = ({ type, onClose }) => {
const numberUrl = process.env.REACT_APP_BACKEND_URL + '/user/helpNumbers'
const url = type === 'number' ? numberUrl : categoryUrl
- console.log('Fetching data from:', url)
-
try {
const response = await fetch(url, {
headers: {
@@ -31,18 +30,41 @@ const HelpNumberAndCategoryEditPopupContent = ({ type, onClose }) => {
if (response.status === 401) {
disconnect()
- throw new Error('Unauthorized access')
+ toast.error('Unauthorized access')
}
if (!response.ok) {
- throw new Error(`Error ${response.status}: ${response.statusText}`)
+ toast.error(`Error ${response.status}: ${response.statusText}`)
}
const data = await response.json()
setItems(data)
+ if (type === 'number') {
+ try {
+ const response = await fetch(categoryUrl, {
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ }
+ })
+
+ if (response.status === 401) {
+ disconnect()
+ toast.error('Unauthorized access')
+ }
+
+ if (!response.ok) {
+ toast.error(`Error ${response.status}: ${response.statusText}`)
+ }
+
+ const data = await response.json()
+ setCategoryList(data)
+ } catch (error) {
+ toast.error('Error fetching data:', error)
+ }
+ }
} catch (error) {
- console.error('Error fetching data:', error)
- setError(error.message)
+ toast.error('Error fetching data:', error)
} finally {
setLoading(false)
}
@@ -71,10 +93,8 @@ const HelpNumberAndCategoryEditPopupContent = ({ type, onClose }) => {
if (!response.ok) {
const errorData = await response.json()
- console.log('Erreur renvoyée par le serveur:', errorData)
- throw new Error(`Error ${response.status}: ${errorData.message || 'Unknown error'}`)
+ toast.error(`Error ${response.status}: ${errorData.message || 'Unknown error'}`)
}
-
toast.success(`${type === 'number' ? 'Numéro' : 'Catégorie'} supprimé avec succès !`)
onClose()
window.location.reload() // Rafraîchir la page après suppression
@@ -89,7 +109,7 @@ const HelpNumberAndCategoryEditPopupContent = ({ type, onClose }) => {
const item = items.find((item) => item._id === selectedId)
setSelectedItem(item)
if (item && type === 'number') {
- setFormData({ name: item.name, telephone: item.telephone || '' })
+ setFormData({ name: item.name, telephone: item.telephone || '', helpNumbersCategory: item.helpNumbersCategory })
} else {
setFormData({ name: item.name })
}
@@ -175,7 +195,7 @@ const HelpNumberAndCategoryEditPopupContent = ({ type, onClose }) => {
Catégorie
- {items.map((option, index) => (
+ {categoryList.map((option, index) => (
{option.name}
diff --git a/src/Components/Popup/helpNumberCreation.jsx b/src/Components/Popup/helpNumberCreation.jsx
index 0d516acf..43a211db 100644
--- a/src/Components/Popup/helpNumberCreation.jsx
+++ b/src/Components/Popup/helpNumberCreation.jsx
@@ -1,9 +1,9 @@
import React, { useState, useEffect } from 'react'
import '../../css/Components/Popup/popup.scss'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
-const HelpNumberCreationPopupContent = () => {
- const [errMessage, setErrMessage] = useState('')
+const HelpNumberCreationPopupContent = ({ onClose }) => {
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [categoryID, setCategoryID] = useState('')
@@ -49,7 +49,7 @@ const HelpNumberCreationPopupContent = () => {
setCategories(data)
setCategoryID(data.length > 0 ? data[0]._id : '')
} else {
- setErrMessage('Erreur lors de la récupération des catégories.')
+ toast.error('Erreur lors de la récupération des catégories.')
}
}
@@ -68,16 +68,16 @@ const HelpNumberCreationPopupContent = () => {
let sendPost = true
if (name === '') {
- setErrMessage('Le nom est vide.')
+ toast.error('Le nom est vide.')
sendPost = false
} else if (!/^\d{10}$/.test(telephone) || telephone === '') {
- setErrMessage('Veuillez fournir un numéro de téléphone valide (10 chiffres).')
+ toast.error('Veuillez fournir un numéro de téléphone valide (10 chiffres).')
sendPost = false
} else if (email === '' || !validateEmail(email)) {
- setErrMessage('Veuillez fournir une adresse email valide.')
+ toast.error('Veuillez fournir une adresse email valide.')
sendPost = false
} else if (description === '') {
- setErrMessage("Veuillez fournir une description de ce numéro d'aide.")
+ toast.error("Veuillez fournir une description de ce numéro d'aide.")
sendPost = false
}
@@ -100,14 +100,14 @@ const HelpNumberCreationPopupContent = () => {
disconnect()
}
if (response.ok) {
- setErrMessage("Numéro d'aide ajouté avec succès.")
- window.location.reload()
+ toast.success("Numéro d'aide ajouté avec succès.")
+ onClose()
} else /* istanbul ignore next */ {
const data = response.json()
- setErrMessage(data.message)
+ toast.error(data.message)
}
})
- .catch((error) => /* istanbul ignore next */ { setErrMessage(error.message) })
+ .catch((error) => /* istanbul ignore next */ { toast.error(error.message) })
}
}
@@ -139,7 +139,6 @@ const HelpNumberCreationPopupContent = () => {
Description *
- {errMessage ? {errMessage} : ''}
Créer le Numéro
>
)
diff --git a/src/Components/Popup/moodFormCreation.jsx b/src/Components/Popup/moodFormCreation.jsx
index 733e2c1f..a42e2113 100644
--- a/src/Components/Popup/moodFormCreation.jsx
+++ b/src/Components/Popup/moodFormCreation.jsx
@@ -1,10 +1,5 @@
import React, { useState } from 'react'
import '../../css/Components/Popup/popup.scss'
-import veryBadMood from '../../assets/newVeryBadMood.png'
-import badMood from '../../assets/newBadMood.png'
-import averageMood from '../../assets/newAverageMood.png'
-import happyMood from '../../assets/newHappyMood.png'
-import veryHappyMood from '../../assets/newVeryHappyMood.png'
import '../../css/Components/Feelings/feelings.scss'
import { disconnect } from '../../functions/disconnect'
import emoji1 from '../../assets/emojis/1.png'
@@ -18,9 +13,9 @@ import emoji2Selected from '../../assets/emojis/2s.png'
import emoji3Selected from '../../assets/emojis/3s.png'
import emoji4Selected from '../../assets/emojis/4s.png'
import emoji5Selected from '../../assets/emojis/5s.png'
+import { toast } from 'react-toastify'
-const MoodFormCreationPopupContent = () => {
- const [errMessage, setErrMessage] = useState('')
+const MoodFormCreationPopupContent = ({ onClose }) => {
const [newMood, setNewMood] = useState('')
const [newAnonymous, setNewAnonymous] = useState(true)
const [newMessage, setNewMessage] = useState('')
@@ -58,38 +53,38 @@ const MoodFormCreationPopupContent = () => {
disconnect()
}
if (response.status === 200) {
- window.location.reload()
+ toast.success('Le ressenti a été créé avec succès.')
+ onClose()
}
})
.catch(error => /* istanbul ignore next */ {
- setErrMessage('Erreur lors de la récupération des ressentis', error)
+ toast.error('Erreur lors de la récupération des ressentis', error)
})
} else {
- setErrMessage("L'humeur est manquante.")
+ toast.error("L'humeur est manquante.")
}
}
return (
<>
- Créer un ressenti
-
- Mon humeur *
-
-
handleMood(0)} />
-
handleMood(1)} />
-
handleMood(2)} />
-
handleMood(3)} />
-
handleMood(4)} />
-
-
- Message
-
-
-
-
Anonyme
+
Créer un ressenti
+
+ Mon humeur *
+
+
handleMood(0)} />
+
handleMood(1)} />
+
handleMood(2)} />
+
handleMood(3)} />
+
handleMood(4)} />
- {errMessage ? {errMessage} : ''}
- Créer le Ressenti
+
+
Message
+
+
+
+ Anonyme
+
+
Créer le Ressenti
>
)
}
diff --git a/src/Components/Popup/reportCreation.jsx b/src/Components/Popup/reportCreation.jsx
index e5d774d2..734948ac 100644
--- a/src/Components/Popup/reportCreation.jsx
+++ b/src/Components/Popup/reportCreation.jsx
@@ -3,9 +3,9 @@ import '../../css/Components/Popup/popup.scss'
import '../../css/pages/createReports.scss'
import { disconnect } from '../../functions/disconnect'
import Select from 'react-select'
-import { toast } from 'react-toastify';
+import { toast } from 'react-toastify'
-const ReportCreationPopupContent = () => {
+const ReportCreationPopupContent = ({ onClose }) => {
const userId = localStorage.getItem('id')
const [reason, setReason] = useState('')
const [message, setMessage] = useState('')
@@ -14,16 +14,17 @@ const ReportCreationPopupContent = () => {
const colourStyles = {
control: (styles) => (
- { ...styles,
+ {
+ ...styles,
backgroundColor: 'white',
- height: '45px',
+ height: '45px'
}
),
multiValueLabel: (styles, { data }) => ({
...styles,
fontWeight: '500'
- }),
- };
+ })
+ }
useEffect(() => {
fetch(`${process.env.REACT_APP_BACKEND_URL}/user/chat/users`, {
@@ -93,7 +94,7 @@ const ReportCreationPopupContent = () => {
return (
<>
-
+
Créer un Signalement
@@ -122,9 +123,9 @@ const ReportCreationPopupContent = () => {
getOptionLabel={(option) => (option.firstname + ' ' + option.lastname)}
/>
-
+
Description
-
+
Confirmer le signalement
>
diff --git a/src/Components/Popup/singleAccountCreation.jsx b/src/Components/Popup/singleAccountCreation.jsx
index eb5dc178..d4342221 100644
--- a/src/Components/Popup/singleAccountCreation.jsx
+++ b/src/Components/Popup/singleAccountCreation.jsx
@@ -3,15 +3,15 @@ import '../../css/Components/Popup/popup.scss'
import Select from 'react-select'
import userIcon from '../../assets/userIcon.png'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
-const SingleAccountCreationPopupContent = () => {
+const SingleAccountCreationPopupContent = ({ close }) => {
const roleProfile = sessionStorage.getItem('role')
const singleCreationUrl = process.env.REACT_APP_BACKEND_URL + '/adm/register'
const [firstname, setFirstName] = useState('')
const [lastname, setLastName] = useState('')
const [email, setEmail] = useState('')
const [rolesList, setRolesList] = useState([])
- const [errMessage, setErrMessage] = useState('')
const [role, setRole] = useState('')
const [classes, setClasses] = useState([])
const [classesList, setClassesList] = useState([])
@@ -19,7 +19,6 @@ const SingleAccountCreationPopupContent = () => {
const [isMultiStatus, setIsMultiStatus] = useState(true)
const [picture, setPicture] = useState(null)
const [title, setTitle] = useState(null)
- const [notification, setNotification] = useState(null) // Ajout de l'état de la notification
const handleFirstNameChange = (event) => {
setFirstName(event.target.value)
@@ -89,25 +88,25 @@ const SingleAccountCreationPopupContent = () => {
}
if (firstname === '') {
- setErrMessage('Il manque le prénom.')
+ toast.error('Il manque le prénom.')
return
} else if (lastname === '') {
- setErrMessage('Il manque le nom de famille.')
+ toast.error('Il manque le nom de famille.')
return
} else if (email === '') {
- setErrMessage("Il manque l'adresse email.")
+ toast.error("Il manque l'adresse email.")
return
} else if (!validateEmail(email)) {
- setErrMessage("L'adresse email n'est pas valide.")
+ toast.error("L'adresse email n'est pas valide.")
return
} else if (roleProfile !== 'admin' && picture === '') {
- setErrMessage('Veuillez fournir une image de profil')
+ toast.error('Veuillez fournir une image de profil')
return
} else if (roleProfile !== 'admin' && classesArray.length === 0) {
if (role.name === 'teacher') {
- setErrMessage('Veuillez assigner une ou plusieurs classes à cet enseignant.')
+ toast.error('Veuillez assigner une ou plusieurs classes à cet enseignant.')
} else {
- setErrMessage('Veuillez assigner une classe à cet étudiant.')
+ toast.error('Veuillez assigner une classe à cet étudiant.')
}
return
}
@@ -141,7 +140,7 @@ const SingleAccountCreationPopupContent = () => {
if (response.status === 401) {
disconnect()
} else if (response.ok) {
- setNotification({ type: 'success', message: 'Compte créé avec succès' }) // Déclencher la notification de succès
+ toast.success('Compte créé avec succès')
window.location.reload()
} else {
return response.json()
@@ -149,11 +148,11 @@ const SingleAccountCreationPopupContent = () => {
})
.then((data) => {
if (data) {
- setNotification({ type: 'error', message: data.message }) // Déclencher la notification d'erreur si nécessaire
+ toast.error(data.message)
}
})
.catch((e) => {
- setNotification({ type: 'error', message: e.message }) // Déclencher la notification d'erreur en cas d'erreur
+ toast.error(e.message)
})
}
@@ -176,7 +175,7 @@ const SingleAccountCreationPopupContent = () => {
setRole(data.roles.filter((user) => user.name === 'teacher')[0]._id)
})
.catch((error) => {
- setErrMessage(error.message)
+ toast.error(error.message)
})
fetch(process.env.REACT_APP_BACKEND_URL + '/shared/classes', {
@@ -194,7 +193,7 @@ const SingleAccountCreationPopupContent = () => {
})
.then((data) => setClassesList(data))
.catch((error) => {
- setErrMessage(error.message)
+ toast.error(error.message)
})
fetch(process.env.REACT_APP_BACKEND_URL + '/shared/titles', {
@@ -214,30 +213,12 @@ const SingleAccountCreationPopupContent = () => {
setTitlesList(data)
})
.catch((error) => {
- setErrMessage(error.message)
+ toast.error(error.message)
})
}, [])
- useEffect(() => {
- // Effacer la notification après 5 secondes
- if (notification) {
- const timer = setTimeout(() => {
- setNotification(null)
- }, 5000)
-
- return () => clearTimeout(timer)
- }
- }, [notification])
-
return (
<>
- {/* Affichage de la notification */}
- {notification && (
-
- {notification.message}
-
- )}
-
{/* Le reste du contenu du composant */}
{roleProfile === 'admin'
? (
@@ -311,7 +292,6 @@ const SingleAccountCreationPopupContent = () => {
)}
- {errMessage ?
{errMessage} : ''}
Créer le Compte
>
)
diff --git a/src/Components/Profil/profilPage.jsx b/src/Components/Profil/profilPage.jsx
index 421baf69..cf53f687 100644
--- a/src/Components/Profil/profilPage.jsx
+++ b/src/Components/Profil/profilPage.jsx
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import '../../css/pages/profilPage.scss'
import userIcon from '../../assets/userIcon.png'
-import { disconnect } from '../../functions/disconnect'
import Popup from 'reactjs-popup'
import cross from '../../assets/Cross.png'
import { toast } from 'react-toastify'
@@ -131,7 +130,7 @@ const ProfilPage = ({ isModif, handleProfileModification }) => {
navigate('/profile')
} else {
navigate('/profile')
- const text = await response.text()
+ // const text = await response.text()
setNegativeResponse('')
console.log(`Erreur lors de la mise à jour du profil: ${response.statusText}`)
}
@@ -155,8 +154,8 @@ const ProfilPage = ({ isModif, handleProfileModification }) => {
}
return (
-
-
+
+
{(close) => (
Mettre à jour le profil
@@ -164,7 +163,7 @@ const ProfilPage = ({ isModif, handleProfileModification }) => {
)}
{negativeResponse &&
{negativeResponse}
}
-
+
@@ -215,7 +214,7 @@ const ProfilPage = ({ isModif, handleProfileModification }) => {
{userProfile.email}
-
disconnect()} className='item'>
+
disconnect()} className='item'>
Déconnexion
diff --git a/src/Components/Sidebar/sidebar.jsx b/src/Components/Sidebar/sidebar.jsx
index 14128391..aaed2327 100644
--- a/src/Components/Sidebar/sidebar.jsx
+++ b/src/Components/Sidebar/sidebar.jsx
@@ -5,6 +5,7 @@ import Popup from 'reactjs-popup'
import { Tooltip } from 'react-tooltip'
import moment from 'moment'
import logoSchood from '../../assets/logo_schood.png'
+import { toast } from 'react-toastify'
import { FaUsers, FaExclamationCircle } from 'react-icons/fa'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
@@ -49,7 +50,6 @@ import schoodIcon from '../../assets/sidenav/schood-icon.png'
export default function Sidebar () {
const [isCollapsed, setIsCollapsed] = useState(true)
const [dailyMood, setDailyMood] = useState(null)
- const [profile, setProfile] = useState(null)
const { chats } = useContext(WebsocketContext)
const location = useLocation()
const [isShown, setIsShown] = useState(false)
@@ -88,7 +88,7 @@ export default function Sidebar () {
setDailyMood(data.mood)
}
})
- .catch((e) => { console.error(e) })
+ .catch((e) => { toast.error(e.statusText) })
}
const getUnseenNotifications = () => {
@@ -130,7 +130,7 @@ export default function Sidebar () {
if (role === 'student') {
getDailyMood()
}
- setProfile(JSON.parse(sessionStorage.getItem('profile')))
+ // setProfile(JSON.parse(sessionStorage.getItem('profile')))
}, [])
let pages = []
@@ -162,6 +162,9 @@ export default function Sidebar () {
if (sessionStorage.getItem('role') === 'student') {
const feelingsObj = { id: 'ressentis', path: '/feelings', icon:
, iconSelected:
, label: 'Mes ressentis', title: 'Mes ressentis', selected: IsCurrentPage('/feelings', false) }
pages.splice(6, 0, feelingsObj)
+ } else {
+ const accountsObj = { id: 'accounts', path: '/accounts', icon:
, label: 'Comptes', title: 'Comptes', selected: IsCurrentPage('/accounts', false) }
+ pages.splice(6, 0, accountsObj)
}
}
@@ -183,10 +186,11 @@ export default function Sidebar () {
disconnect()
} else {
setDailyMood(mood)
+ toast.success('Votre humeur du jour a été prise en compte.')
}
})
.catch((error) => {
- console.error(error)
+ toast.error(error.statusText)
})
}
@@ -208,7 +212,7 @@ export default function Sidebar () {
setNotifications(data)
})
.catch((error) => {
- console.error(error)
+ toast.error(error)
})
}
@@ -273,6 +277,9 @@ export default function Sidebar () {
toggleSidebar()} className='item'>
+
disconnect()} className='item'>
+
+
)}
@@ -281,8 +288,9 @@ export default function Sidebar () {
-
+
{role === 'student' && (
@@ -316,6 +324,9 @@ export default function Sidebar () {
toggleSidebar()} className='item'>
Réduire
+
disconnect()} className='item'>
+
+
)}
diff --git a/src/Components/reports/reportSidebar.jsx b/src/Components/reports/reportSidebar.jsx
index 1f521e48..d1815e25 100644
--- a/src/Components/reports/reportSidebar.jsx
+++ b/src/Components/reports/reportSidebar.jsx
@@ -4,26 +4,31 @@ import { translate } from '../../functions/translate'
const ReportSidebar = ({
reports,
currentReport,
- setCurrentReport,
- handleReportSelection
+ handleCurrentReport,
+ showTreated,
+ handleShowTreated
}) => {
const handleClick = (report) => {
- setCurrentReport(report)
- if (report.conversation) {
- handleReportSelection(report._id, report.conversation)
- }
+ handleCurrentReport(report)
}
return (
+
+
handleShowTreated(false)}>En Attente
+
handleShowTreated(true)}>Traités
+
- {reports.map((report, index) => (
-
handleClick(report)}>
-
- {translate(report.type)}
+ {reports
+ .filter((report) =>
+ showTreated ? report.status === 'seen' : (!report.status || report.status === 'unseen')
+ ).map((report, index) => (
+
handleClick(report)}>
+
+ {translate(report.type)}
+
-
- ))}
+ ))}
)
diff --git a/src/Users/Admin/feelingsAdminPage.jsx b/src/Users/Admin/feelingsAdminPage.jsx
index 810ed418..0f401e2b 100644
--- a/src/Users/Admin/feelingsAdminPage.jsx
+++ b/src/Users/Admin/feelingsAdminPage.jsx
@@ -4,22 +4,29 @@ import Popup from 'reactjs-popup'
import HeaderComp from '../../Components/Header/headerComp'
import '../../css/Components/Feelings/feelings.scss'
import '../../css/Components/Popup/popup.scss'
+import DesanonymFeelingPopupContent from '../../Components/Popup/desanonymFeeling'
import cross from '../../assets/Cross.png'
+import closeBlack from '../../assets/closeBlack.png'
import veryBadMood from '../../assets/newVeryBadMood.png'
import badMood from '../../assets/newBadMood.png'
import averageMood from '../../assets/newAverageMood.png'
import happyMood from '../../assets/newHappyMood.png'
import veryHappyMood from '../../assets/newVeryHappyMood.png'
+import questionIcon from '../../assets/questionIcon.png'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
const FeelingsAdminPage = () => {
- const [errMessage, setErrMessage] = useState('')
- const [isCreateOpen, setIsCreateOpen] = useState(false)
- const [isModified, setIsModified] = useState(false)
- // const [selectedFeeling, setSelectedFeeling] = useState(null)
- const [newMood, setNewMood] = useState('')
- const [newAnonymous, setNewAnonymous] = useState(true)
- const [newMessage, setNewMessage] = useState('')
+ const [isOpen, setIsOpen] = useState(false)
+ const [isShown, setIsShown] = useState(false)
+ const [shownFeeling, setShownFeeling] = useState([])
+ const [demand, setDemand] = useState({
+ user: '',
+ mood: '0',
+ reason: '',
+ message: 'Pas de message'
+ })
+ const [demands, setDemands] = useState([])
const [feelings, setFeelings] = useState([])
const imagePaths = useMemo(() => {
return [
@@ -43,46 +50,35 @@ const FeelingsAdminPage = () => {
}
}, [])
- const handleMood = (moodNumber) => {
- setNewMood(moodNumber)
+ const handleDemandPopup = (userId, feelingId, feelingMood) => {
+ demand.user = userId
+ demand.reason = feelingId
+ demand.mood = feelings.find(item => item.mood === feelingMood)._id
+ setDemand(demand)
+ const toFind = demands.find(item => item.reason === feelingId)
+ if (toFind) { toast.warn('Vous avez déjà effectué une demande de désanonymisation pour ce ressenti.') } else { setIsOpen(!isOpen) }
}
- const handleAnonymous = () => {
- setNewAnonymous(!newAnonymous)
- }
-
- const handleMessage = (event) => {
- setNewMessage(event.target.value)
- }
-
- const handleUpdateFeelings = () => {
- const dataPayload = {
- comment: newMessage,
- mood: newMood,
- annonymous: newAnonymous
- }
-
- if (newMood !== '') {
- fetch(`${process.env.REACT_APP_BACKEND_URL}/admin/mood`, {
- method: isModified ? 'PATCH' : 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'x-auth-token': sessionStorage.getItem('token')
- },
- body: JSON.stringify(dataPayload)
+ async function getDesanonym () {
+ fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/desanonym/`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-auth-token': sessionStorage.getItem('token')
+ }
+ })
+ .then(response => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ return response.json()
+ })
+ .then(data => {
+ setDemands(data)
+ })
+ .catch(error => /* istanbul ignore next */ {
+ toast.error('Erreur lors de la récupération des ressentis', error)
})
- .then(response => {
- if (response.status === 401) {
- disconnect()
- }
- if (response.status === 200) { window.location.reload() }
- })
- .catch(error => /* istanbul ignore next */ {
- setErrMessage('Erreur lors de la récupération des ressentis', error)
- })
- } else {
- setErrMessage('L\'humeur n\'est pas indiquée.')
- }
}
useEffect(() => {
@@ -101,32 +97,54 @@ const FeelingsAdminPage = () => {
})
.then(data => {
if (Array.isArray(data)) {
+ console.log(data)
setFeelings(prevFeelings => [...prevFeelings, ...data])
} else {
- setErrMessage('Les données reçues ne sont pas valides.')
+ toast.error('Les données reçues ne sont pas valides.')
}
})
.catch(error => /* istanbul ignore next */ {
- setErrMessage('Erreur lors de la récupération des ressentis', error)
+ toast.error('Erreur lors de la récupération des ressentis', error)
})
+ getDesanonym()
}, [])
const handleClosePopup = () => {
- setIsCreateOpen(false)
+ setIsOpen(false)
}
- const handleFeelingsModification = (feeling) => {
- setIsCreateOpen(true)
- setIsModified(true)
- // setSelectedFeeling(feeling)
- setNewMood(feeling.mood)
- setNewAnonymous(feeling.annonymous)
- setNewMessage(feeling.comment)
+ const handleAskDesanonym = (message) => {
+ demand.message = (message || 'Pas de message')
+ fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/desanonym/`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-auth-token': sessionStorage.getItem('token')
+ },
+ body: JSON.stringify(demand)
+ })
+ .then(response => {
+ if (response.status === 401) {
+ disconnect()
+ } else if (response.status === 200) {
+ // set feeling.status to waiting !
+ toast.success('La demande de désanonymisation a été effectuée.')
+ getDesanonym()
+ setIsOpen(!isOpen)
+ } else {
+ toast.error('Erreur serveur.')
+ }
+ return response
+ })
+ .catch(error => /* istanbul ignore next */ {
+ console.error('Network or unexpected error:', error)
+ toast.error("Erreur lors de l'envoi de la demande")
+ })
}
- async function getUserName (username) {
- await fetch(`${process.env.REACT_APP_BACKEND_URL}/user/profile/${username}`, {
- method: 'GET',
+ const deleteDemand = (demandId) => {
+ fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/desanonym/` + demandId, {
+ method: 'Delete',
headers: {
'Content-Type': 'application/json',
'x-auth-token': sessionStorage.getItem('token')
@@ -135,16 +153,28 @@ const FeelingsAdminPage = () => {
.then(response => {
if (response.status === 401) {
disconnect()
+ } else if (response.status === 200) {
+ toast.success('La demande de désanonymisation supprimée.')
+ getDesanonym()
+ } else {
+ toast.error('Erreur serveur.')
}
- return response.json()
- })
- .then(data => {
- return `${data.firstname} ${data.lastname}`
+ return response
})
.catch(error => /* istanbul ignore next */ {
- setErrMessage('Erreur lors de la récupération des ressentis', error)
+ console.error('Network or unexpected error:', error)
+ toast.error('Erreur lors de la suppression de la demande.')
})
- return 'Erreur'
+ }
+
+ const handleCloseFeelingPopup = () => {
+ setIsShown(!isShown)
+ }
+
+ const handleShowFeeling = (feelingId) => {
+ const feeling = feelings.find(item => item._id === feelingId)
+ setShownFeeling(feeling)
+ handleCloseFeelingPopup()
}
return (
@@ -158,43 +188,62 @@ const FeelingsAdminPage = () => {
/>
-
+
{(close) => (
-
+
- {{/* here we can start a conv with the person who sent a feeling or indicate that it has been taken into account or ask for the person to identify who they are */}}
- {/*
Mon humeur *
-
-
handleMood(0)} title='Très Mauvaise Humeur'>
-
-
-
handleMood(1)} title='Mauvaise Humeur'>
-
-
-
handleMood(2)} title='Humeur Neutre'>
-
-
-
handleMood(3)} title='Bonne Humeur'>
-
+
+
+ )}
+
+
+ {(close) => (
+
+
+
+
{moment(shownFeeling.date).format('DD/MM/YYYY')}
+
+
+
+
+
+
{emotions[moods[shownFeeling.mood]]}
+
+
+
{shownFeeling.date !== '' ? 'Pris en compte le:' : 'En attente de prise en compte'}
+
{shownFeeling.date !== '' ? `${moment(shownFeeling.date).format('DD/MM/YYYY')}` : ''}
+
+
Anonyme
-
handleMood(4)} title='Très Bonne Humeur'>
-
+
-
-
Message
-
-
-
- Anonyme
-
*/}
- {errMessage ?
{errMessage} : ''}
-
{!isModified ? 'Créer le Ressenti' : 'Modifier le Ressenti'}
+
)}
+
+
Vos demandes de désanonymisation
+
+ {
+ demands.length !== 0
+ ? (
+ demands.map((dem) => (
+
handleShowFeeling(dem.reason)} className={`demand-container ${dem.status === 'refused' ? 'red-filler' : dem.status === 'accepted' ? 'green-filler' : 'orange-filler'}`} key={dem._id}>
+
{dem.status === 'refused' ? 'Refus de désanonymisation d\'un ressenti' : dem.status === 'accepted' ? 'Ressenti désanonymisé' : 'Demande de désanonymisation d\'un ressenti en attente d\'une réponse'}
+
{ e.stopPropagation(); deleteDemand(dem._id) }}>
+
+ ))
+ )
+ : (
+
Aucune demande en cours
+ )
+ }
+
+
- {Array.isArray(feelings) && feelings.map((feeling) => (
+ {feelings.length !== 0 && feelings.map((feeling) => (
{moment(feeling.date).format('DD/MM/YYYY')}
@@ -208,7 +257,7 @@ const FeelingsAdminPage = () => {
{feeling.date !== '' ? 'Pris en compte le:' : 'En attente de prise en compte'}
{feeling.date !== '' ? `${moment(feeling.date).format('DD/MM/YYYY')}` : ''}
-
{feeling.annonymous ? 'Anonyme' : `${feeling.user.firstname} ${feeling.user.lastname}`}
+
{feeling.annonymous ? (<>Anonyme
handleDemandPopup(feeling.user._id, feeling._id, feeling.mood)} src={questionIcon} alt='Demander à désanonymiser' title='Faire une demande de désanonymisation' /> >) : `${feeling.user.firstname} ${feeling.user.lastname}`}
{feeling.comment}
diff --git a/src/Users/Public/forgottenPasswordPage.jsx b/src/Users/Public/forgottenPasswordPage.jsx
index bf9528d2..9510622d 100644
--- a/src/Users/Public/forgottenPasswordPage.jsx
+++ b/src/Users/Public/forgottenPasswordPage.jsx
@@ -76,8 +76,8 @@ export default function ForgottenPasswordPage () {
{redirectMessage}
)
: (
-
0 ? 'remember-me-error' : 'remember-me-normal'} id='remember-me'>
- Se rappeler de moi
+ Se rappeler de moi
{message}
diff --git a/src/Users/SchoolAdmin/reportChecking.jsx b/src/Users/SchoolAdmin/reportChecking.jsx
index 0a743146..cab48b63 100644
--- a/src/Users/SchoolAdmin/reportChecking.jsx
+++ b/src/Users/SchoolAdmin/reportChecking.jsx
@@ -6,15 +6,34 @@ import ReportSidebar from '../../Components/reports/reportSidebar'
import UserProfile from '../../Components/userProfile/userProfile'
import { disconnect } from '../../functions/disconnect'
import { translate } from '../../functions/translate'
+import { toast } from 'react-toastify'
+import Popup from 'reactjs-popup'
+import cross from '../../assets/Cross.png'
+import chatIcon from '../../assets/chatIcon.png'
+import AccessingReportedConversationPopupContent from '../../Components/Popup/accessingReportedConversation'
const ReportChecking = () => {
const [reports, setReports] = useState([])
const [currentReport, setCurrentReport] = useState('')
- // const [reportedConversation, setReportedConversation] = useState(null)
- // const [reportedConversationMessages, setReportedConversationMessages] = useState(null)
- // const [isReportProcessed, setIsReportProcessed] = useState(false)
- // const [error, setError] = useState('')
- // const [reportRequest, setReportRequests] = useState([])
+ const [showTreated, setShowTreated] = useState(false)
+ const [reportedConversation, setReportedConversation] = useState(null)
+ const [isAccessing, setIsAccessing] = useState(false)
+ const [signaledBy, setSignaledBy] = useState([])
+
+ const handleCurrentReport = (report) => {
+ setCurrentReport(report)
+ setSignaledBy(report.signaledBy)
+ if (report.conversation) {
+ setReportedConversation(report.conversation)
+ } else {
+ setReportedConversation(null)
+ }
+ }
+
+ const handleShowTreated = (result) => {
+ setShowTreated(result)
+ }
+
const fetchReportRequests = async () => {
try {
const response = await fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/report`, {
@@ -31,106 +50,77 @@ const ReportChecking = () => {
setReports(data)
setCurrentReport(data[data.length - 1])
if (data[data.length - 1].conversation) {
- handleReportSelection(data[data.length - 1]._id, data[data.length - 1].conversation)
+ setReportedConversation(data[data.length - 1].conversation)
+ setSignaledBy(data[data.length - 1].signaledBy)
}
- console.log(data)
} catch (error) /* istanbul ignore next */ {
- console.error('Erreur lors de la récupération des demandes de signalement.')
+ toast.error('Erreur lors de la récupération des demandes de signalement.')
}
}
- // const fetchReportedConversation = async (conversationId) => {
- // try {
- // const response = await fetch(`${process.env.REACT_APP_BACKEND_URL}/user/chat/${conversationId}`, {
- // method: 'GET',
- // headers: {
- // 'x-auth-token': sessionStorage.getItem('token'),
- // 'Content-Type': 'application/json'
- // }
- // })
- // if (response.status === 401) {
- // disconnect();
- // }
- // const data = await response.json()
- // setReportedConversation(data)
- // } catch (error) /* istanbul ignore next */ {
- // setError('Erreur lors de la récupération de la conversation signalée.')
- // }
- // }
-
- // const fetchReportedConversationMessages = async (conversationId) => {
- // try {
- // const response = await fetch(`${process.env.REACT_APP_BACKEND_URL}/user/chat/${conversationId}/messages`, {
- // method: 'GET',
- // headers: {
- // 'x-auth-token': sessionStorage.getItem('token'),
- // 'Content-Type': 'application/json'
- // }
- // })
- // if (response.status === 401) {
- // disconnect()
- // }
- // const data = await response.json()
- // setReportedConversationMessages(data)
- // } catch (error) /* istanbul ignore next */ {
- // setError('Erreur lors de la récupération de la conversation signalée.')
- // }
- // }
-
- /* const checkReportProcessingStatus = async (reportId) => {
- // on a pas moyen de vérifier le status d'un report, la route ci dessous n'est pas valide
- try {
- const response = await fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/report/${reportId}`, {
- method: 'GET',
+ const handleReportProcessing = async (reportId, isProcessed) => {
+ if (isProcessed === 'processed') {
+ await fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/report/processing/${reportId}`, {
+ method: 'POST',
headers: {
'x-auth-token': sessionStorage.getItem('token'),
'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ status: 'seen', responseMessage: 'ok' })
+ }).then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ if (response.status === 200) {
+ toast.success('Le signalement est traité.')
}
})
- if (response.status === 401) {
- disconnect();
- }
- const data = await response.json()
- setIsReportProcessed(data.processed)
- } catch (error) {
- setError('Erreur lors de la vérification du statut de traitement.')
- }
- } */
-
- const handleReportProcessing = async (reportId, isProcessed) => {
- try {
- if (isProcessed) {
- await fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/report/processing/${reportId}`, {
- method: 'POST',
- headers: {
- 'x-auth-token': sessionStorage.getItem('token'),
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({ status: 'seen', responseMessage: 'ok' })
+ .catch((error) => {
+ toast.error('Un problème est survenu, le signalement ne peut être traité.', error.message)
+ })
+ } else if (isProcessed === 'waiting') {
+ await fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/report/processing/${reportId}`, {
+ method: 'POST',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ status: 'unseen', responseMessage: 'ok' })
+ }).then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ if (response.status === 200) {
+ toast.success('Le signalement a été mis en attente.')
+ }
+ })
+ .catch((error) => {
+ toast.error('Un problème est survenu, le signalement ne peut être traité.', error.message)
})
- fetchReportRequests()
- } else {
- await fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/report/${reportId}`, {
- method: 'DELETE',
- headers: {
- 'x-auth-token': sessionStorage.getItem('token'),
- 'Content-Type': 'application/json'
- }
+ } else {
+ await fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/report/${reportId}`, {
+ method: 'DELETE',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ }
+ }).then((response) => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ if (response.status === 200) {
+ toast.success('Le signalement est supprimé.')
+ }
+ })
+ .catch((error) => {
+ toast.error('Un problème est survenu, le signalement ne peut être supprimé.', error.message)
})
- fetchReportRequests()
- // setReports((prevReports) => prevReports.filter((report) => report._id !== reportId))
- }
-
- // setIsReportProcessed(isProcessed)
- } catch (error) {
- console.error('Erreur lors du traitement de la demande.')
}
+ fetchReportRequests()
}
- const handleReportSelection = async (reportId, conversationId) => {
- // await fetchReportedConversation(conversationId)
- // await fetchReportedConversationMessages(conversationId)
- // await checkReportProcessingStatus(reportId)
+ const handleAccessReportedChat = () => {
+ setIsAccessing(!isAccessing)
}
useEffect(() => {
@@ -149,38 +139,47 @@ const ReportChecking = () => {
-
+
setIsAccessing(false)} modal>
+ {(close) => (
+
+
+
+
+ )}
+
{currentReport
? (
-
{translate(currentReport.type)}
+
{translate(currentReport.type)} {
+ reportedConversation && (
+
+ )
+ }
+
{currentReport.status === 'seen'
- ? 'La requête a été traitée'
+ ? (
+ handleReportProcessing(currentReport._id, 'waiting')}>Mettre en attente
+ )
: (
- handleReportProcessing(currentReport._id, true)}>Traiter la requête
+ handleReportProcessing(currentReport._id, 'processed')}>Traiter la requête
)}
- handleReportProcessing(currentReport._id, false)}>Supprimer la requête
+ handleReportProcessing(currentReport._id, 'deleted')}>Supprimer la requête
{
- currentReport.message && (
-
{currentReport.message}
- )
- }
- {/*
// waiting for conversation routes to be fixed */}
- {/* {reportedConversationMessages.map((message, index) => (
-
- ))} */}
- {/* {error &&
{error}
} */}
- {/*
*/}
+ currentReport.message && (
+
{currentReport.message}
+ )
+ }
diff --git a/src/Users/SchoolAdmin/schoolAdmAccountsPage.js b/src/Users/SchoolAdmin/schoolAdmAccountsPage.js
index 28da869a..4b22a6b4 100644
--- a/src/Users/SchoolAdmin/schoolAdmAccountsPage.js
+++ b/src/Users/SchoolAdmin/schoolAdmAccountsPage.js
@@ -3,6 +3,7 @@ import HeaderComp from '../../Components/Header/headerComp'
import SchoolAccountsTable from '../../Components/Accounts/SchoolAdm/schoolAccountsTable'
import CsvAccountCreationPopupContent from '../../Components/Popup/csvAccountCreation'
import SingleAccountCreationPopupContent from '../../Components/Popup/singleAccountCreation'
+import FacilityClassesCreationPopupContent from '../../Components/Popup/facilityClassesCreation'
import '../../css/pages/accountsPage.scss'
import '../../css/Components/Popup/popup.scss'
import Popup from 'reactjs-popup'
@@ -11,12 +12,16 @@ import cross from '../../assets/Cross.png'
export default function SchoolAdmAccountsPage () {
const [isOpenSingle, setIsOpenSingle] = useState(false)
const [isOpenMany, setIsOpenMany] = useState(false)
+ const [isOpenClasses, setIsOpenClasses] = useState(false)
const handleSingleAccount = () => {
setIsOpenSingle(!isOpenSingle)
if (isOpenMany) {
setIsOpenMany(!isOpenMany)
}
+ if (isOpenClasses) {
+ setIsOpenClasses(!isOpenClasses)
+ }
}
const handleManyAccounts = () => {
@@ -24,6 +29,19 @@ export default function SchoolAdmAccountsPage () {
if (isOpenSingle) {
setIsOpenSingle(!isOpenSingle)
}
+ if (isOpenClasses) {
+ setIsOpenClasses(!isOpenClasses)
+ }
+ }
+
+ const handleClasses = () => {
+ setIsOpenClasses(!isOpenClasses)
+ if (isOpenMany) {
+ setIsOpenMany(!isOpenMany)
+ }
+ if (isOpenSingle) {
+ setIsOpenSingle(!isOpenSingle)
+ }
}
const buttonComponent = [
@@ -34,6 +52,10 @@ export default function SchoolAdmAccountsPage () {
{
name: 'Ajouter une Liste de Comptes',
handleFunction: handleManyAccounts
+ },
+ {
+ name: 'Gérer les classes',
+ handleFunction: handleClasses
}
]
@@ -41,9 +63,9 @@ export default function SchoolAdmAccountsPage () {
@@ -64,7 +86,15 @@ export default function SchoolAdmAccountsPage () {
)}
-
+
setIsOpenClasses(false)} modal>
+ {(close) => (
+
+
+
+
+ )}
+
+
)
diff --git a/src/Users/Shared/alertsPage.jsx b/src/Users/Shared/alertsPage.jsx
index d4b9e8c3..d4cef9b0 100644
--- a/src/Users/Shared/alertsPage.jsx
+++ b/src/Users/Shared/alertsPage.jsx
@@ -12,6 +12,8 @@ import UserProfile from '../../Components/userProfile/userProfile'
import AlertCreationPopupContent from '../../Components/Popup/alertCreation'
import AlertModificationPopupContent from '../../Components/Popup/alertModification.jsx'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
+import AlertDeletionPopupContent from '../../Components/Popup/alertDeletion'
const AlertsPage = () => {
const roleProfile = sessionStorage.getItem('role')
@@ -20,15 +22,7 @@ const AlertsPage = () => {
const [alerts, setAlerts] = useState([])
const [chosenAlert, setChosenAlert] = useState({})
const { id } = useParams()
- const [errMessage, setErrMessage] = useState('')
- const [notification, setNotification] = useState({ visible: false, message: '', type: '' })
-
- const openNotification = (message, type) => {
- setNotification({ visible: true, message, type })
- setTimeout(() => {
- setNotification({ visible: false, message: '', type: '' })
- }, 3000) // La notification sera visible pendant 3 secondes
- }
+ const [isDeleting, setIsDeleting] = useState(false)
const fetchAlerts = async () => {
try {
@@ -126,7 +120,7 @@ const AlertsPage = () => {
}
}
- const handleEditAlert = (alert) => {
+ const handleEditAlert = (alert, onClose) => {
fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/alert/${alert.id}`, {
method: 'PATCH',
headers: {
@@ -139,34 +133,33 @@ const AlertsPage = () => {
if (response.ok) {
fetchAlerts() // Rafraîchir la liste des alertes après modification
setIsModifying(false)
- openNotification('L\'alerte a été modifiée avec succès.', 'success')
+ toast.success('L\'alerte a été modifiée avec succès.')
+ onClose()
} else {
- setErrMessage('Erreur lors de la mise à jour')
+ toast.error('Erreur lors de la mise à jour')
}
})
.catch((error) => console.error('Erreur : ', error))
}
- const handleDeleteAlert = (alertId) => {
- const confirmDelete = window.confirm('Êtes-vous sûr de vouloir supprimer cette alerte ?')
- if (confirmDelete) {
- fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/alert/${alertId}`, {
- method: 'DELETE',
- headers: {
- 'x-auth-token': sessionStorage.getItem('token')
+ const handleDeleteAlert = (alertId, close) => {
+ fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/alert/${alertId}`, {
+ method: 'DELETE',
+ headers: {
+ 'x-auth-token': sessionStorage.getItem('token')
+ }
+ })
+ .then((response) => {
+ if (response.ok) {
+ fetchAlerts() // Rafraîchir la liste des alertes après suppression
+ setChosenAlert('')
+ toast.success('L\'alerte a été supprimée avec succès.')
+ close()
+ } else {
+ toast.error('Erreur lors de la suppression')
}
})
- .then((response) => {
- if (response.ok) {
- fetchAlerts() // Rafraîchir la liste des alertes après suppression
- setChosenAlert('')
- openNotification('L\'alerte a été supprimée avec succès.', 'success')
- } else {
- setErrMessage('Erreur lors de la suppression')
- }
- })
- .catch((error) => console.error('Erreur : ', error))
- }
+ .catch((error) => toast.error('Erreur : ', error))
}
useEffect(() => {
@@ -191,6 +184,10 @@ const AlertsPage = () => {
setIsModifying(!isModifying)
}
+ const handleDeleting = () => {
+ setIsDeleting(!isDeleting)
+ }
+
const buttonComponent = [
{
name: 'Créer une alerte',
@@ -205,7 +202,7 @@ const AlertsPage = () => {
},
{
name: 'Supprimer',
- handleFunction: () => handleDeleteAlert(chosenAlert.id)
+ handleFunction: handleDeleting
}
]
@@ -222,15 +219,11 @@ const AlertsPage = () => {
/>
- {notification.visible &&
-
- {notification.message}
-
}
setIsOpen(false)} modal>
{(close) => (
-
+
)}
@@ -238,7 +231,15 @@ const AlertsPage = () => {
{(close) => (
-
+
+
+ )}
+
+
setIsDeleting(false)} modal>
+ {(close) => (
+
+
+
)}
@@ -246,7 +247,7 @@ const AlertsPage = () => {
id === undefined
? Object.entries(alerts).map(([day, items]) => (
-
+
diff --git a/src/Users/Shared/helpPage.jsx b/src/Users/Shared/helpPage.jsx
index 4e27d918..e942ebe7 100644
--- a/src/Users/Shared/helpPage.jsx
+++ b/src/Users/Shared/helpPage.jsx
@@ -69,7 +69,7 @@ const HelpPage = () => {
{(close) => (
-
+
)}
@@ -77,7 +77,7 @@ const HelpPage = () => {
{(close) => (
-
+
)}
diff --git a/src/Users/Student/dashboardStudent.jsx b/src/Users/Student/dashboardStudent.jsx
index f88b59ee..9e08c94f 100644
--- a/src/Users/Student/dashboardStudent.jsx
+++ b/src/Users/Student/dashboardStudent.jsx
@@ -35,19 +35,19 @@ const StudentHomePage = () => {
withLogo
/>
-
+
{(close) => (
-
+
-
+
)}
-
+
{(close) => (
-
+
)}
diff --git a/src/Users/Student/feelingsStudentPage.jsx b/src/Users/Student/feelingsStudentPage.jsx
index c4db3a27..3c44f63c 100644
--- a/src/Users/Student/feelingsStudentPage.jsx
+++ b/src/Users/Student/feelingsStudentPage.jsx
@@ -5,12 +5,15 @@ import HeaderComp from '../../Components/Header/headerComp'
import '../../css/Components/Feelings/feelings.scss'
import '../../css/Components/Popup/popup.scss'
import cross from '../../assets/Cross.png'
+import acceptIcon from '../../assets/acceptIcon.png'
+import refuseIcon from '../../assets/refuseIcon.png'
import veryBadMood from '../../assets/newVeryBadMood.png'
import badMood from '../../assets/newBadMood.png'
import averageMood from '../../assets/newAverageMood.png'
import happyMood from '../../assets/newHappyMood.png'
import veryHappyMood from '../../assets/newVeryHappyMood.png'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
import emoji1 from '../../assets/emojis/1.png'
import emoji2 from '../../assets/emojis/2.png'
import emoji3 from '../../assets/emojis/3.png'
@@ -24,10 +27,14 @@ import emoji4Selected from '../../assets/emojis/4s.png'
import emoji5Selected from '../../assets/emojis/5s.png'
const FeelingsStudentPage = () => {
- const [errMessage, setErrMessage] = useState('')
+ const [userProfile, setUserProfile] = useState([])
const [isCreateOpen, setIsCreateOpen] = useState(false)
const [isPassed, setIsPassed] = useState(false)
const [isModified, setIsModified] = useState(false)
+ const [isShown, setIsShown] = useState(false)
+ const [shownFeeling, setShownFeeling] = useState([])
+ const [feelings, setFeelings] = useState([])
+ const [demands, setDemands] = useState([])
const [lastFeeling, setLastFeeling] = useState([])
const [newMood, setNewMood] = useState('')
const [newAnonymous, setNewAnonymous] = useState(true)
@@ -89,10 +96,10 @@ const FeelingsStudentPage = () => {
if (response.status === 200) { window.location.reload() }
})
.catch(error => /* istanbul ignore next */ {
- setErrMessage('Erreur lors de la récupération des ressentis', error)
+ toast.error('Erreur lors de la récupération des ressentis', error)
})
} else {
- setErrMessage('L\'humeur n\'est pas indiquée.')
+ toast.error('L\'humeur n\'est pas indiquée.')
}
}
@@ -194,20 +201,20 @@ const FeelingsStudentPage = () => {
})
.then(data => {
setLastFeeling(data[0])
+ setFeelings(data)
if (!isPassed) { fillFeelingsContainer(data) }
})
.catch(error => /* istanbul ignore next */ {
- setErrMessage('Erreur lors de la récupération des ressentis', error)
+ toast.error('Erreur lors de la récupération des ressentis', error)
})
+ getDesanonym()
}, [setLastFeeling, emotions, moods, imagePaths, lastFeeling.length])
const handleClosePopup = () => {
- // document.getElementById('grey-filter').style.display = 'none'
setIsCreateOpen(false)
}
const handleFeelingsModification = () => {
- // document.getElementById('grey-filter').style.display = 'flex'
setIsCreateOpen(!isCreateOpen)
setIsModified(true)
setNewMood(lastFeeling.mood)
@@ -216,7 +223,6 @@ const FeelingsStudentPage = () => {
}
const handleFeelingsCreation = () => {
- // document.getElementById('grey-filter').style.display = 'flex'
setIsCreateOpen(!isCreateOpen)
setIsModified(false)
setNewMood('')
@@ -224,6 +230,62 @@ const FeelingsStudentPage = () => {
setNewMessage('')
}
+ async function getDesanonym () {
+ fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/desanonym/`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-auth-token': sessionStorage.getItem('token')
+ }
+ })
+ .then(response => {
+ if (response.status === 401) {
+ disconnect()
+ }
+ return response.json()
+ })
+ .then(data => {
+ setDemands(data)
+ })
+ .catch(error => /* istanbul ignore next */ {
+ toast.error('Erreur lors de la récupération des ressentis', error)
+ })
+ }
+
+ const handleCloseFeelingPopup = () => {
+ setIsShown(!isShown)
+ }
+
+ const handleShowFeeling = (feelingId, user) => {
+ const feeling = feelings.find(item => item._id === feelingId)
+ setUserProfile(user)
+ setShownFeeling(feeling)
+ handleCloseFeelingPopup()
+ }
+
+ const handleDemand = (id, answer) => {
+ fetch(`${process.env.REACT_APP_BACKEND_URL}/shared/desanonym/` + id, {
+ method: 'PATCH',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-auth-token': sessionStorage.getItem('token')
+ },
+ body: JSON.stringify({
+ status: answer
+ })
+ })
+ .then(response => {
+ if (response.status === 401) {
+ disconnect()
+ } else if (response.status === 200) {
+ getDesanonym()
+ }
+ })
+ .catch(error => /* istanbul ignore next */ {
+ toast.error('Erreur lors de la récupération des ressentis', error)
+ })
+ }
+
const buttonComponent = [
{
name: 'Créer un ressenti',
@@ -247,14 +309,14 @@ const FeelingsStudentPage = () => {
/>
-
+
{(close) => (
-
-
{!isModified ? 'Créer un ressenti': 'Modifier le dernier ressenti'}
+
+
{!isModified ? 'Créer un ressenti' : 'Modifier le dernier ressenti'}
- Mon humeur *
-
+
Mon humeur *
+
handleMood(0)} />
handleMood(1)} />
handleMood(2)} />
@@ -262,17 +324,69 @@ const FeelingsStudentPage = () => {
handleMood(4)} />
-
Message
-
+
Message
+
- Anonyme
+ Anonyme
- {errMessage ?
{errMessage} : ''}
{!isModified ? 'Créer le Ressenti' : 'Modifier le Ressenti'}
)}
+
+ {(close) => (
+
+
+
+
{moment(shownFeeling.date).format('DD/MM/YYYY')}
+
+
+
+
+
+
{emotions[moods[shownFeeling.mood]]}
+
+
+
{shownFeeling.date !== '' ? 'Pris en compte le:' : 'En attente de prise en compte'}
+
{shownFeeling.date !== '' ? `${moment(shownFeeling.date).format('DD/MM/YYYY')}` : ''}
+
+
{shownFeeling.annonymous ? 'Anonyme' : userProfile.firstname + ' ' + userProfile.lastname}
+
+
+
{shownFeeling.comment}
+
+
+
+
+ )}
+
+
+
Vos demandes de désanonymisation
+
+ {
+ demands.length !== 0
+ ? (
+ demands.map((dem) => (
+
handleShowFeeling(dem.reason, dem.user)} className={`demand-container ${dem.status === 'refused' ? 'red-filler' : dem.status === 'accepted' ? 'green-filler' : 'orange-filler'}`} key={dem._id}>
+
{dem.status === 'refused' ? 'Refus de désanonymisation d\'un ressenti' : dem.status === 'accepted' ? 'Ressenti désanonymisé' : 'Demande de désanonymisation d\'un ressenti en attente d\'une réponse'}
+
+ {
+ dem.status !== 'accepted' && { e.stopPropagation(); handleDemand(dem._id, 'accepted') }}>
+ }
+ {
+ dem.status !== 'refused' && { e.stopPropagation(); handleDemand(dem._id, 'refused') }}>
+ }
+
+
+ ))
+ )
+ : (
+
Aucune demande en cours
+ )
+ }
+
+
diff --git a/src/Users/Student/statisticsStudent.jsx b/src/Users/Student/statisticsStudent.jsx
index 8f4c6fec..9510e8be 100644
--- a/src/Users/Student/statisticsStudent.jsx
+++ b/src/Users/Student/statisticsStudent.jsx
@@ -4,13 +4,11 @@ import { Chart } from 'chart.js'
import '../../css/pages/homePage.scss'
import '../../css/pages/statistiques.scss'
import { library } from '@fortawesome/fontawesome-svg-core'
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSadTear, faFrown, faMeh, faSmile, faLaughBeam } from '@fortawesome/free-solid-svg-icons'
import { disconnect } from '../../functions/disconnect'
import emoji4 from '../../assets/emojis/4s.png'
Chart.defaults.font.family = 'Inter'
-
library.add(faSadTear, faFrown, faMeh, faSmile, faLaughBeam)
const StudentStatPage = () => {
@@ -319,8 +317,7 @@ const StudentStatPage = () => {
- )
- }
+ )}
diff --git a/src/Users/Teacher/dashboardTeacher.jsx b/src/Users/Teacher/dashboardTeacher.jsx
index 9b966165..0eeba69a 100644
--- a/src/Users/Teacher/dashboardTeacher.jsx
+++ b/src/Users/Teacher/dashboardTeacher.jsx
@@ -30,7 +30,7 @@ const TeacherHomePage = () => {
{(close) => (
-
+
)}
diff --git a/src/Users/Teacher/modifyFormTeacherPage.jsx b/src/Users/Teacher/modifyFormTeacherPage.jsx
index 1af6b1c2..787ca04b 100644
--- a/src/Users/Teacher/modifyFormTeacherPage.jsx
+++ b/src/Users/Teacher/modifyFormTeacherPage.jsx
@@ -9,10 +9,10 @@ import '../../css/Components/Buttons/questionnaireButtons.css'
import 'react-datepicker/dist/react-datepicker.css'
import '../../css/Components/Popup/popup.scss'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
const ModifyFormTeacherPage = () => {
const [questionInc, setQuestionInc] = useState(1)
- const [errMessage, setErrMessage] = useState('')
const [questions, setQuestions] = useState([])
const [position, setPosition] = useState(-1)
const [isOpen, setIsOpen] = useState(false)
@@ -42,10 +42,10 @@ const ModifyFormTeacherPage = () => {
setQuestionInc(data.questions.length)
setParutionDate(moment(data.fromDate).format('YYYY-MM-DD'))
} else {
- setErrMessage(data.message)
+ toast.error(data.message)
}
})
- .catch(error => /* istanbul ignore next */ { setErrMessage(error.message) })
+ .catch(error => /* istanbul ignore next */ { toast.error(error.message) })
}, [id])
function postQuestions () {
@@ -57,14 +57,14 @@ const ModifyFormTeacherPage = () => {
if (title !== '') {
for (let i = 0; i < questions.length; i++) {
if (questions[i].title === '') {
- setErrMessage(`Question n°${i + 1} n'a pas été renseignée.`)
+ toast.error(`Question n°${i + 1} n'a pas été renseignée.`)
proceed = false
break
} else if (questions[i].type === 'multiple') {
for (let j = 0; j < questions[i].answers.length; j++) {
if (questions[i].answers[j].title === '') {
proceed = false
- setErrMessage(`La réponse n°${j + 1} de la question n°${i + 1} n'a pas été renseignée.`)
+ toast.error(`La réponse n°${j + 1} de la question n°${i + 1} n'a pas été renseignée.`)
break
}
}
@@ -72,7 +72,7 @@ const ModifyFormTeacherPage = () => {
}
} else {
proceed = false
- setErrMessage('Le questionnaire n\'a pas de titre.')
+ toast.error('Le questionnaire n\'a pas de titre.')
}
if (proceed) {
@@ -91,12 +91,13 @@ const ModifyFormTeacherPage = () => {
if (response.status === 401) {
disconnect()
} else if (response.status !== 200) {
- setErrMessage(response.status + ' error : ' + response.statusText)
+ toast.error(response.status + ' error : ' + response.statusText)
} else {
+ toast.success('Le questionnaire a été modifié avec succcès.')
window.location.href = '/questionnaire/' + id
}
})
- .catch(error => setErrMessage(error.message))
+ .catch(error => toast.error(error.message))
}
}
@@ -219,7 +220,6 @@ const ModifyFormTeacherPage = () => {
Sauvegarder les Modifications ?
Vous êtes sur le point de quitter la page et vous avez des modifications en cours qui ne sont pas sauvegardées. En quittant sans sauvegarder, vous perdrez toute vos modifications.
- {errMessage ?
{errMessage} : ''}
Annuler
@@ -230,7 +230,7 @@ const ModifyFormTeacherPage = () => {
)}
-
+
-
{
(questionInc > 0 && questions) && questions.map((question, index) =>
diff --git a/src/Users/Teacher/newFormPage.jsx b/src/Users/Teacher/newFormPage.jsx
index fa9fd1c5..23645536 100644
--- a/src/Users/Teacher/newFormPage.jsx
+++ b/src/Users/Teacher/newFormPage.jsx
@@ -7,10 +7,10 @@ import 'react-datepicker/dist/react-datepicker.css'
import '../../css/pages/formPage.scss'
import '../../css/Components/Buttons/questionnaireButtons.css'
import { disconnect } from '../../functions/disconnect'
+import { toast } from 'react-toastify'
const NewFormPage = () => {
const [questionInc, setQuestionInc] = useState(1)
- const [errMessage, setErrMessage] = useState('')
const [questions, setQuestions] = useState([{
title: '',
type: 'text',
@@ -29,14 +29,14 @@ const NewFormPage = () => {
if (title !== '') {
for (let i = 0; i < questions.length; i++) {
if (questions[i].title === '') {
- setErrMessage(`Question n°${i + 1} n'a pas été renseignée.`)
+ toast.error(`Question n°${i + 1} n'a pas été renseignée.`)
proceed = false
break
} else if (questions[i].type === 'multiple') {
for (let j = 0; j < questions[i].answers.length; j++) {
if (questions[i].answers[j].title === '') {
proceed = false
- setErrMessage(`La réponse n°${j + 1} de la question n°${i + 1} n'a pas été renseignée.`)
+ toast.error(`La réponse n°${j + 1} de la question n°${i + 1} n'a pas été renseignée.`)
break
}
}
@@ -44,7 +44,7 @@ const NewFormPage = () => {
}
} else {
proceed = false
- setErrMessage('Le questionnaire n\'a pas de titre.')
+ toast.error('Le questionnaire n\'a pas de titre.')
}
if (proceed) {
@@ -64,12 +64,13 @@ const NewFormPage = () => {
disconnect()
}
if (response.status !== 200) {
- setErrMessage(response.status + ' error : ' + response.statusText)
+ toast.error(response.status + ' error : ' + response.statusText)
} else {
+ toast.success('Le questionnaire a été créé avec succès')
window.location.href = '/questionnaires'
}
})
- .catch(error => setErrMessage(error.message))
+ .catch(error => toast.error(error.message))
}
}
@@ -186,7 +187,6 @@ const NewFormPage = () => {
Sauvegarder les modifications ?
Vous êtes sur le point de quitter la page et vous avez des modifications en cours qui ne sont pas sauvegardées. En quittant sans sauvegarder, vous perdrez toutes vos modifications.
- {errMessage ?
{errMessage} : ''}
Continuer l'édition
@@ -197,11 +197,6 @@ const NewFormPage = () => {
)}
-
diff --git a/src/Users/Teacher/statisticsTeacher.jsx b/src/Users/Teacher/statisticsTeacher.jsx
index 9342581c..00893240 100644
--- a/src/Users/Teacher/statisticsTeacher.jsx
+++ b/src/Users/Teacher/statisticsTeacher.jsx
@@ -5,7 +5,6 @@ import '../../css/pages/homePage.scss'
import '../../css/pages/statistiques.scss'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faSadTear, faFrown, faMeh, faSmile, faLaughBeam } from '@fortawesome/free-solid-svg-icons'
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { disconnect } from '../../functions/disconnect'
import emoji4 from '../../assets/emojis/4s.png'
Chart.defaults.font.family = 'Inter'
@@ -418,9 +417,9 @@ const TeacherStatPage = () => {
Année
-
+
Filtrer par classe:
-
+
Toutes les classes
{classes.map((classItem) => (
{classItem.name}
@@ -428,12 +427,12 @@ const TeacherStatPage = () => {
-
+
Evolution de l'humeur
-
+
diff --git a/src/assets/acceptIcon.png b/src/assets/acceptIcon.png
new file mode 100644
index 00000000..8728e98c
Binary files /dev/null and b/src/assets/acceptIcon.png differ
diff --git a/src/assets/chatIcon.png b/src/assets/chatIcon.png
new file mode 100644
index 00000000..d7a14da1
Binary files /dev/null and b/src/assets/chatIcon.png differ
diff --git a/src/assets/closeBlack.png b/src/assets/closeBlack.png
new file mode 100644
index 00000000..22c3bb29
Binary files /dev/null and b/src/assets/closeBlack.png differ
diff --git a/src/assets/deleteIcon.png b/src/assets/deleteIcon.png
new file mode 100644
index 00000000..26198164
Binary files /dev/null and b/src/assets/deleteIcon.png differ
diff --git a/src/assets/questionIcon.png b/src/assets/questionIcon.png
new file mode 100644
index 00000000..5f590f8c
Binary files /dev/null and b/src/assets/questionIcon.png differ
diff --git a/src/assets/refuseIcon.png b/src/assets/refuseIcon.png
new file mode 100644
index 00000000..0b0ad2c6
Binary files /dev/null and b/src/assets/refuseIcon.png differ
diff --git a/src/assets/restoreIcon.png b/src/assets/restoreIcon.png
new file mode 100644
index 00000000..c95fefc5
Binary files /dev/null and b/src/assets/restoreIcon.png differ
diff --git a/src/assets/suspendIcon.png b/src/assets/suspendIcon.png
new file mode 100644
index 00000000..f8f3af3e
Binary files /dev/null and b/src/assets/suspendIcon.png differ
diff --git a/src/css/Components/Accounts/accountsTable.css b/src/css/Components/Accounts/accountsTable.css
index a745a43e..0271ab7a 100644
--- a/src/css/Components/Accounts/accountsTable.css
+++ b/src/css/Components/Accounts/accountsTable.css
@@ -4,6 +4,12 @@
flex-direction: column;
}
+.action-td {
+ justify-content: space-evenly;
+ display: flex;
+ align-items: center;
+}
+
.newBreak {
border: none;
border-bottom: 2px solid #4f23e2;
@@ -96,7 +102,8 @@ table {
}
.suspendBtn {
- width: 25px;
+ width: 40px;
+ height: 40px;
}
.valHead1bis, .valHead1 {
@@ -119,12 +126,11 @@ table {
font-weight: bold;
z-index: 999;
}
-
+
.success {
background-color: #4CAF50; /* Vert */
}
-
+
.error {
background-color: #f44336; /* Rouge */
}
-
\ No newline at end of file
diff --git a/src/css/Components/Feelings/feelings.scss b/src/css/Components/Feelings/feelings.scss
index a5c5b680..baf7989b 100644
--- a/src/css/Components/Feelings/feelings.scss
+++ b/src/css/Components/Feelings/feelings.scss
@@ -168,3 +168,71 @@ textarea {
font-weight: bold;
font-size: large;
}
+
+.demands-container {
+ border-radius: 26px;
+ box-shadow: 5px 5px 5px 0px lightgray;
+ border: 1px solid lightgrey;
+ display: flex;
+ flex-direction: column;
+ align-items: start;
+ padding-bottom: 10px;
+ margin-bottom: 10px;
+ max-height: calc(40%);
+ overflow-y: scroll;
+}
+
+.demand-container-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+}
+
+.demand-container {
+ border-radius: 10px;
+ box-shadow: 5px 5px 5px 0px lightgray;
+ border: 1px solid lightgrey;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: start;
+ width: 95%;
+ cursor: pointer;
+}
+
+.demand-close-btn {
+ border: none;
+ background: none;
+}
+
+.close-img {
+ width: 30px;
+}
+
+.close-img:hover {
+ transition: 0.5;
+ width: 31px;
+}
+
+.demand-close-btn:hover {
+ border: none;
+ background: none;
+}
+
+.demand-content {
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+.green-filler {
+ background-color: green;
+}
+
+.orange-filler {
+ background-color: orange;
+}
+
+.red-filler {
+ background-color: red;
+}
\ No newline at end of file
diff --git a/src/css/Components/Header/headerComp.scss b/src/css/Components/Header/headerComp.scss
index 2ce49fb8..b2f38b0a 100644
--- a/src/css/Components/Header/headerComp.scss
+++ b/src/css/Components/Header/headerComp.scss
@@ -24,7 +24,7 @@
color: black;
margin-right: 10px;
}
-
+
#subtitle {
font-size: 17px;
font-weight: 600;
@@ -68,7 +68,7 @@
cursor: pointer;
font-family: Inter;
width: auto;
- height: 39px;
+ height: 70px;
font-size: 18px;
margin-left: 10px;
}
diff --git a/src/css/Components/Popup/popup.scss b/src/css/Components/Popup/popup.scss
index fed7576b..f09e38a3 100644
--- a/src/css/Components/Popup/popup.scss
+++ b/src/css/Components/Popup/popup.scss
@@ -210,12 +210,108 @@
font-weight: bold;
z-index: 999;
}
-
+
.success {
background-color: #4CAF50; /* Vert */
}
-
+
.error {
background-color: #f44336; /* Rouge */
}
-
\ No newline at end of file
+
+
+ label {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+ input, select, textarea {
+ width: 90%;
+ border: 2px solid #4f23e2;
+ border-radius: 15px;
+ height: 25px;
+ padding-left: 10px;
+ background-color: white;
+ }
+
+ textarea {
+ height: 15%;
+ }
+
+ #select-classes .css-13cymwt-control, #select-classes .react-select__menu {
+ border: 2px solid #4f23e2;
+ border-radius: 15px;
+ }
+
+ .label-content-warning {
+ text-align: center;
+ width: 450px;
+ }
+}
+
+.form-profile-modif {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ justify-content: center;
+ align-content: center;
+}
+
+.desanonym-popup-content {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ justify-content: center;
+ align-content: center;
+}
+.classes-gestion-container {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ justify-content: center;
+ align-content: center;
+}
+
+.class-input-container {
+ display: flex;
+ flex-direction: row;
+ gap: 10px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 20px 0 20px ;
+}
+
+.class-list-container {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ justify-content: flex-start;
+ align-content: center;
+ overflow-y: scroll;
+ height: 55vh;
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+.class-container {
+ display: flex;
+ flex-direction: row;
+ gap: 10px;
+ align-content: center;
+ justify-content: space-between;
+ border: 1px solid lightgrey;
+ box-shadow: 5px 5px 5px 0px lightgray;
+ border-radius: 5px;
+ padding: 10px;
+}
+
+.icon-popup {
+ cursor: pointer;
+ width: 20px;
+ height: 20px;
+}
+
+.icon-popup:hover {
+ transition: 0.2s;
+ height: 23px;
+}
\ No newline at end of file
diff --git a/src/css/pages/chatRoomPage.scss b/src/css/pages/chatRoomPage.scss
index 53cbb374..159f55f0 100644
--- a/src/css/pages/chatRoomPage.scss
+++ b/src/css/pages/chatRoomPage.scss
@@ -598,3 +598,495 @@
}
}
}
+
+
+////////////////////////////////////////////////////////////
+.conversation-popup {
+ width: 100vw !important;
+}
+
+.messaging-popup {
+ height: calc(100% - 29px);
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+
+ .chat-sidebar {
+ box-sizing: border-box;
+ border: 1px solid lightgrey;
+ box-shadow: 5px 5px 5px 0px lightgray;
+ border-radius: 5px;
+ height: 100%;
+ width: 250px;
+
+ .top {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ margin-top: 5px;
+ margin-bottom: 10px;
+
+ .new-conversation-button {
+ display: flex;
+ flex-direction: row;
+ justify-content: start;
+ align-items: center;
+ width: 230px;
+ cursor: pointer;
+
+ background-color: #4F23E2;
+ border-radius: 5px;
+
+ color: white;
+ font-size: 14px;
+ font-family: 'Inter';
+ font-weight: 500;
+ }
+
+ .new-conversation-button:hover {
+ background-color: #3b1ca9;
+ }
+
+ .divider {
+ margin-top: 4px;
+ height: 4px;
+ width: 100%;
+ background-color: #4F23E2;
+ }
+ }
+
+ .content {
+ display: flex;
+ flex-direction: column;
+ justify-content: start;
+ align-items: start;
+ height: 100%;
+ width: 100%;
+ margin-left: 0px;
+
+ .conversation-notification {
+ width: 15px;
+ height: 15px;
+ border-radius: 100%;
+ background-color: red;
+ margin-right: 5px;
+ }
+
+ .active-conversation {
+ height: 71px;
+ width: 100%;
+ background-color: #4F23E2;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+
+ .text {
+ color: white;
+ font-size: 16px;
+ font-family: Inter;
+ font-weight: 600;
+ margin-left: 10px;
+ }
+ }
+
+ .active-conversation:hover {
+ background-color: #3b1ca9;
+ color: white;
+ }
+
+ .conversation {
+ height: 71px;
+ width: 100%;
+ background-color: white;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+
+ .text {
+ margin-left: 10px;
+ color: #4F23E2;
+ font-size: 16px;
+ font-family: Inter;
+ font-weight: 600;
+ }
+ }
+
+ .conversation:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+
+ .chat {
+ width: 100%;
+ height: 100%;
+ border: 1px solid lightgrey;
+ box-shadow: 5px 5px 5px 0px lightgray;
+ border-radius: 26px;
+ margin-left: 50px;
+ box-sizing: border-box;
+
+ .chat-content {
+ width: 100%;
+ height: 100%;
+
+ .top {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ height: 80px;
+ background-color: white;
+ border-top-left-radius: 35px;
+ border-top-right-radius: 30px;
+ border-bottom: 1px solid #9699FF;
+
+ .top-info {
+ display: flex;
+ flex-direction: column;
+ margin-left: 20px;
+ gap: 10px;
+
+ .conv-name {
+ font-size: 32px;
+ font-family: Inter;
+ font-weight: 600;
+ color: black;
+ }
+
+ .participants-container {
+ display: flex;
+ flex-direction: row;
+ color: #4F23E2;
+ font-size: 18px;
+ font-family: Inter;
+ }
+ }
+
+
+ .report-btn {
+ border-radius: 5px;
+ background-color: #4F23E2;
+ border: none;
+ color: white;
+ font-size: 22px;
+ font-family: Inter;
+ font-weight: 400;
+ height: 34px;
+ margin-right: 12px;
+ cursor: pointer;
+ align-items: center;
+ display: flex;
+ }
+
+ .report-btn:hover {
+ background-color: #3b1ca9;
+ }
+ }
+
+ .bottom {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+
+ .left {
+ display: flex;
+ flex: 0.70;
+ flex-direction: column;
+ justify-content: start;
+ align-items: start;
+ max-height: 80%;
+
+ .top2 {
+ // flex: 0.89;
+ width: 100%;
+ height: 100%;
+ overflow-y: auto;
+ overflow-x: hidden;
+ max-height: 55vh;
+
+ .message-list {
+ width: calc(100% - 20px);
+ height: calc(100% - 20px);
+ margin: 10px 0px 10px 10px;
+
+ .my-messages {
+ background-color: #FFD2D5;
+ width: 40%;
+ margin-left: calc(60% - 40px);
+ border-radius: 26px;
+ height: fit-content;
+ min-height: 100px;
+ color: #4F23E2;
+
+ .message-header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px #4F23E2 solid;
+ white-space: nowrap;
+ font-size: 12px;
+ font-family: Inter;
+ font-weight: 600;
+ padding: 5px 10px 5px 10px;
+ }
+
+ .message-content {
+ font-size: 16px;
+ font-weight: 600;
+ font-family: Inter;
+ color: #4F23E2;
+ }
+
+ .message-content2 {
+ padding: 5px 10px 5px 10px;
+ overflow-wrap: anywhere;
+ width: 95%;
+ }
+
+ .with-file {
+ display: flex;
+ flex-direction: column;
+ justify-content: start;
+ align-items: start;
+ width: 100%;
+
+ .file {
+ padding: 5px 10px 5px 10px;
+ width: calc(100% - 20px);
+ border-top: 1px #4F23E2 solid;
+ margin-top: 15px;
+ }
+ }
+ }
+
+ .other-messages {
+ background-color: #4F23E2;
+ width: 40%;
+ border-radius: 26px;
+ margin-left: 40px;
+ height: fit-content;
+ min-height: 100px;
+ color: white;
+
+ .message-header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px white solid;
+ color: white !important;
+ font-size: 12px;
+ font-family: Inter;
+ font-weight: 600;
+ white-space: nowrap;
+ padding: 5px 10px 5px 10px;
+ }
+
+ .message-content {
+ font-size: 16px;
+ font-weight: 600;
+ font-family: Inter;
+ color: white;
+ }
+
+ .message-content2 {
+ padding: 5px 10px 5px 10px;
+ }
+
+ .with-file {
+ display: flex;
+ flex-direction: column;
+ justify-content: start;
+ align-items: start;
+ width: 100%;
+
+ .file {
+ padding: 5px 10px 5px 10px;
+ width: calc(100% - 20px);
+ border-top: 1px white solid;
+ margin-top: 15px;
+ }
+ }
+ }
+
+ .message-identification {
+ display: flex;
+ gap: 20px;
+
+ .img {
+ height: 35px;
+ width: 35px;
+ border-radius: 100%;
+ }
+
+ .image-right {
+ display: flex;
+ margin-top: -40px;
+ }
+
+ .image-left {
+ display: flex;
+ margin-left: 0px;
+ margin-top: -40px;
+ }
+
+ .message-time {
+ margin-bottom: 15px;
+ color: gray;
+ }
+ }
+ }
+
+ }
+
+ .bottom2 {
+ // flex: 0.11;
+ border-top: none;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: end;
+ align-items: center;
+
+ .column {
+ display: flex;
+ flex-direction: column;
+ justify-content: end;
+ align-items: center;
+ margin-bottom: 10px;
+ width: 100%;
+ height: 100%;
+
+ .file-name {
+ color: #4F23E2;
+ font-size: 16px;
+ font-family: Inter;
+ font-weight: 600;
+ margin-bottom: 8px;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+
+ .send-button {
+ color: white;
+ font-size: 16px;
+ font-family: Inter;
+ font-weight: 600;
+ background-color: #4F23E2;
+ border: none;
+ border-radius: 100px;
+ margin-left: 5px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ }
+
+ .message-input {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ width: 95%;
+ height: 50%;
+
+ .file-input {
+ margin-right: 6px;
+ cursor: pointer;
+ input {
+ width: 0;
+ height: 0;
+ }
+ }
+
+ .message-area {
+ border: none;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+
+ input {
+ width: 100%;
+ height: 25px;
+ border-radius: 5px;
+ background-color: #EAEAEA;
+ z-index: 99;
+ color: #4F23E2;
+ font-size: 16px;
+ font-family: Inter;
+ font-weight: 600;
+ border: none;
+ padding-left: 10px;
+ }
+
+ textarea:focus, input:focus {
+ outline: none;
+ }
+
+ .send-button {
+ border-radius: 5px;
+ background-color: #4F23E2;
+ height: 25px;
+ width: 100px;
+ z-index: 0;
+ color: white;
+ font-size: 16px;
+ font-family: Inter;
+ font-weight: 600;
+ border: none;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .send-button:hover {
+ background-color: #3b1ca9;
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ .right {
+ flex: 0.20;
+ width: 100%;
+ height: 100%;
+ border-left: 4px #4F23E2 solid;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+
+ .user-profile {
+ border: 3px #4F23E2 solid;
+ border-radius: 26px;
+ margin-top: 6px;
+ margin-right: 2px;
+ margin-left: 2px;
+ width: fit-content;
+ height: fit-content;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/css/pages/reportChecking.scss b/src/css/pages/reportChecking.scss
index 60339d0a..7a106645 100644
--- a/src/css/pages/reportChecking.scss
+++ b/src/css/pages/reportChecking.scss
@@ -27,13 +27,23 @@
display: flex;
flex-direction: row;
justify-content: center;
+ width: 100%;
.report-sidebar-button {
font-size: large;
- font-family: Inter;
padding: 5px;
cursor: pointer;
}
+
+ .blue-filler {
+ background-color: #4F23E2;
+ color: white
+ }
+
+ .report-sidebar-button:hover {
+ font-size: larger;
+ transition: 0.1s;
+ }
}
.top {
@@ -171,6 +181,11 @@
font-weight: 600;
color: black;
margin-left: 20px;
+
+ .report-chat-icon {
+ width: 20px;
+ cursor: pointer;
+ }
}
.report-btn {
diff --git a/src/index.jsx b/src/index.jsx
index 52db5094..66628fca 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -33,7 +33,6 @@ import Sidebar from './Components/Sidebar/sidebar'
import { WebsocketProvider } from './contexts/websocket'
import { Slide, ToastContainer } from 'react-toastify'
import './css/index.scss'
-import SchoolAccountsTable from './Components/Accounts/SchoolAdm/schoolAccountsTable'
const rootElement = document.getElementById('root')
@@ -64,30 +63,21 @@ if (rootElement) {
} />
} />
} />
+
} />
>
)}
{sessionStorage.getItem('role') === 'admin' && (
<>
} />
} />
-
} />
-
} />
-
} />
-
} />
-
} />
>
)}
{sessionStorage.getItem('role') === 'administration' && (
<>
} />
} />
-
} />
-
} />
} />
} />
-
} />
-
} />
-
} />
} />
} />
>
@@ -98,25 +88,18 @@ if (rootElement) {
} />
} />
} />
-
} />
-
} />
} />
>
)}
{sessionStorage.getItem('role') === 'teacher' && (
<>
} />
-
} />
} />
} />
} />
} />
} />
-
} />
-
} />
-
} />
-
} />
-
} />
+
} />
} />
>
)}