From a1aeffd03af30315d2373cb0714cd4f793ce5544 Mon Sep 17 00:00:00 2001
From: Fefedu973 <80718477+Fefedu973@users.noreply.github.com>
Date: Fri, 27 Sep 2024 23:34:14 +0200
Subject: [PATCH 01/31] Added long press to fetch calendar mobile, fixed
progress bar calendar fetch styling issue chrome, updated calendar tooltip,
fixed landing page horizontal scrolling bug mobile
---
src/components/LandingPage/LandingPage.jsx | 9 ++++++--
src/components/LandingPage/LandingPage2.css | 6 ++----
src/components/app/Homeworks/Calendar.css | 23 ++++++++++++++++++---
src/components/app/Homeworks/Calendar.jsx | 14 +++++++++++++
src/components/app/Homeworks/Homeworks.jsx | 2 +-
5 files changed, 44 insertions(+), 10 deletions(-)
diff --git a/src/components/LandingPage/LandingPage.jsx b/src/components/LandingPage/LandingPage.jsx
index 4431a7e..8f811cc 100644
--- a/src/components/LandingPage/LandingPage.jsx
+++ b/src/components/LandingPage/LandingPage.jsx
@@ -104,7 +104,7 @@ export default function LandingPage({ token, accountsList }) {
parallaxItems.forEach(item => {
let speed = item.getAttribute("data-speed");
- let yPos = -(scrollPosition * speed);
+ let yPos = -(scrollPosition * speed) - 100;
item.style.transform = `translateY(${yPos}px)`;
});
}
@@ -152,6 +152,11 @@ export default function LandingPage({ token, accountsList }) {
Cliquez sur une date pour accéder aux devoirs associés.
SHIFT + CLIC pour charger tous les devoirs à partir de la date sélectionnée jusqu'à aujourd'hui.
SHIFT + CLIC ou apppui prolongé pour charger tous les devoirs à partir de la date sélectionnée jusqu'à aujourd'hui.
GRIS : aujourd'hui
BLEU : devoirs
From e9829fa9c28253efefff06459869d76bbdcb77c1 Mon Sep 17 00:00:00 2001 From: Fefe_du_973 <80718477+Fefedu973@users.noreply.github.com> Date: Fri, 4 Oct 2024 22:12:33 +0200 Subject: [PATCH 02/31] Delete src/components/LandingPage/LandingPage.jsx --- src/components/LandingPage/LandingPage.jsx | 274 --------------------- 1 file changed, 274 deletions(-) delete mode 100644 src/components/LandingPage/LandingPage.jsx diff --git a/src/components/LandingPage/LandingPage.jsx b/src/components/LandingPage/LandingPage.jsx deleted file mode 100644 index 8f811cc..0000000 --- a/src/components/LandingPage/LandingPage.jsx +++ /dev/null @@ -1,274 +0,0 @@ -import { useRef, useEffect, useContext, useState } from "react"; -import { Link, useLocation, useNavigate } from "react-router-dom"; - -import OutlineEffectDiv from "../generic/CustomDivs/OutlineEffectDiv"; -import { AppContext } from "../../App" - -// graphics -import EdpuLogo from "../graphics/EdpuLogo"; -import InfoTypoIcon from "../graphics/InfoTypoIcon"; -import UpArrow from "../graphics/UpArrow"; -import EDPLogo from "../graphics/EDPLogo"; -import EDPLogoFullWidth from "../graphics/EDPLogoFullWidth"; -import DiscordFullLogo from "../graphics/DiscordFullLogo"; -import GitHubFullLogo from "../graphics/GitHubFullLogo"; -import SunIcon from "../graphics/SunIcon"; -import MoonIcon from "../graphics/MoonIcon"; -import HoverFollowDiv from "../generic/CustomDivs/HoverFollowDiv"; - -import "./LandingPage.css"; -import "./LandingPage2.css"; - -export default function LandingPage({ token, accountsList }) { - const { isMobileLayout, isTabletLayout, actualDisplayTheme, useUserSettings } = useContext(AppContext); - - const [isLoggedIn, setIsLoggedIn] = useState(token && accountsList.length > 0); // this one is different from the one in App.jsx - - const [isTop, setIsTop] = useState(true); - const [isScrollNAvigation, setIsScrollNavigation] = useState(false); - const homeSectionRef = useRef(null) - const communitySectionRef = useRef(null) - const openSourceSectionRef = useRef(null) - - const location = useLocation() - const navigate = useNavigate() - - const theme = useUserSettings("displayTheme") - const displayMode = useUserSettings("displayMode").get(); - - const changeTheme = () => { - theme.set(actualDisplayTheme === "light" ? "dark" : "light"); - }; - - useEffect(() => { - setIsLoggedIn(token && accountsList.length > 0); - }, [token, accountsList]) - - useEffect(() => { - const observer = new IntersectionObserver((intersections) => { - for (const intersection of intersections) { - if (intersection.isIntersecting) { - const elementChildren = intersection.target.children - const elements = [elementChildren[0], elementChildren[1].children[0], elementChildren[1].children[1]].flat(); - for (let i = 0; i <= elements.length; ++i) { - setTimeout(() => { - if (elements[i]) { - // elements[i].style.opacity = 1 - elements[i].classList.toggle("visible", true); - } - }, i * 200) - } - } - } - }, { - rootMargin: "0px 0px -250px 0px", - threshold: 0.1, - }) - - if (communitySectionRef.current && openSourceSectionRef.current) { - observer.observe(communitySectionRef.current) - observer.observe(openSourceSectionRef.current) - return () => { - if (communitySectionRef.current) observer.unobserve(communitySectionRef.current) - if (openSourceSectionRef.current) observer.unobserve(openSourceSectionRef.current) - } - } - }, []); - - useEffect(() => { - const handleScroll = () => { - setIsTop(window.scrollY === 0); - }; - window.addEventListener("scroll", handleScroll); - - return () => { - window.removeEventListener("scroll", handleScroll); - }; - }, []); - - useEffect(() => { - if (!location.hash) { - navigate("#home", { replace: true }); - } - const section = document.getElementById(location.hash.slice(1)) - if (section) { - section.scrollIntoView({ block: (location.hash === "#home" ? "start" : "center") }) - } - }, [location.hash]); - - - useEffect(() => { - const handleScroll = () => { - const parallaxItems = document.querySelectorAll(".parallax-item"); - let scrollPosition = window.scrollY; - - parallaxItems.forEach(item => { - let speed = item.getAttribute("data-speed"); - let yPos = -(scrollPosition * speed) - 100; - item.style.transform = `translateY(${yPos}px)`; - }); - } - - document.addEventListener("scroll", handleScroll); - - return () => { - document.removeEventListener("scroll", handleScroll); - } - - }, []) - - return (EDP offre une expérience unique avec une interface moderne et intuitive, enrichie de fonctionnalités exclusives, le tout de façon gratuite, libre et open-source.
- {isLoggedIn ? "Ouvrir l'app" : "Se connecter"} -Découvrez vos talents cachés grâce à un aperçu rapide de vos points forts. Parce que vous méritez de savoir à quel point vous êtes incroyable, nous mettons en lumière les matières dans lesquelles vous excellez.
-Fini les calculs laborieux à la main. EDP fait tout le boulot pour vous. Parce que votre temps est précieux et doit être consacré à des choses plus importantes, comme procrastiner efficacement.
-Choisissez votre camp : clair comme le jour ou sombre comme votre âme. Passez du mode Clair au mode Sombre en un clic et offrez à vos yeux le repos qu'ils méritent. Parce que même votre interface se doit d'avoir du style.
-Un coup d'œil et vous saurez tout. Avec l'aperçu rapide des dernières notes, regarder vos résultats en vif pendant l'intercours sera plus rapide que la formule 1 de Max Verstappen.
-Atteignez le nirvana académique avec le Score de streak. Surpassez vous, cumulez les bonnes notes et débloquez des badges ! N'hésitez pas à flex quand vous avez une meilleure streak que vos amis.
-Restez aux aguets avec l'aperçu des prochains contrôles. Anticipez les futurs contrôles et organisez vos révisions comme un pro. Enfin, en théorie… on ne peut pas vous garantir que vous ne procrastinerez pas quand même.
-Votre sécurité, notre priorité, parce qu’il n’y a que vous et votre conscience qui devez connaître vos petits secrets académiques. EDP ne collecte AUCUNE information personnelle ou personnellement identifiable sur les utilisateurs du service. En tant que service non-affilié à Aplim, nous utilisons l'API d'EcoleDirecte pour que vous ayez accès à vos informations.
-Rejoignez notre serveur Discord !
Vous pourrez y rencontrer les développeurs et discuter avec les membres les plus investis d'Ecole Directe Plus !
EDP est un projet open source distribué sous licence MIT, n'importe qui peut participer !
Nous partageons en toute transparence le code source d'EDP sur notre dépôt GitHub. Ainsi, n'importe qui peut contribuer au projet, rapporter des bugs, ou auditer le code à la recherche de failles. C'est une garantie de sécurité, de fiabilité et de résilience.
Il vous suffit d'identifiants EcoleDirecte
- {isLoggedIn ? "Ouvrir l'app" : "Se connecter"} -EDP offre une expérience unique avec une interface moderne et intuitive, enrichie de fonctionnalités exclusives, le tout de façon gratuite, libre et open-source.
+ {isLoggedIn ? "Ouvrir l'app" : "Se connecter"} +Découvrez vos talents cachés grâce à un aperçu rapide de vos points forts. Parce que vous méritez de savoir à quel point vous êtes incroyable, nous mettons en lumière les matières dans lesquelles vous excellez.
+Fini les calculs laborieux à la main. EDP fait tout le boulot pour vous. Parce que votre temps est précieux et doit être consacré à des choses plus importantes, comme procrastiner efficacement.
+Choisissez votre camp : clair comme le jour ou sombre comme votre âme. Passez du mode Clair au mode Sombre en un clic et offrez à vos yeux le repos qu'ils méritent. Parce que même votre interface se doit d'avoir du style.
+Un coup d'œil et vous saurez tout. Avec l'aperçu rapide des dernières notes, regarder vos résultats en vif pendant l'intercours sera plus rapide que la formule 1 de Max Verstappen.
+Atteignez le nirvana académique avec le Score de streak. Surpassez vous, cumulez les bonnes notes et débloquez des badges ! N'hésitez pas à flex quand vous avez une meilleure streak que vos amis.
+Restez aux aguets avec l'aperçu des prochains contrôles. Anticipez les futurs contrôles et organisez vos révisions comme un pro. Enfin, en théorie… on ne peut pas vous garantir que vous ne procrastinerez pas quand même.
+Votre sécurité, notre priorité, parce qu’il n’y a que vous et votre conscience qui devez connaître vos petits secrets académiques. EDP ne collecte AUCUNE information personnelle ou personnellement identifiable sur les utilisateurs du service. En tant que service non-affilié à Aplim, nous utilisons l'API d'EcoleDirecte pour que vous ayez accès à vos informations.
+Rejoignez notre serveur Discord !
Vous pourrez y rencontrer les développeurs et discuter avec les membres les plus investis d'Ecole Directe Plus !
EDP est un projet open source distribué sous licence MIT, n'importe qui peut participer !
Nous partageons en toute transparence le code source d'EDP sur notre dépôt GitHub. Ainsi, n'importe qui peut contribuer au projet, rapporter des bugs, ou auditer le code à la recherche de failles. C'est une garantie de sécurité, de fiabilité et de résilience.
Il vous suffit d'identifiants EcoleDirecte
+ {isLoggedIn ? "Ouvrir l'app" : "Se connecter"} +coefficient : {selectedElement.coef}
{message.subject}
{(new Date(message.date)).toLocaleDateString("fr-FR", { @@ -91,7 +98,7 @@ export default function Inbox({ selectedMessage, setSelectedMessage, selectedFol
Ce dossier est vide. Peut-être qu'il attend juste un miracle... ou un clic
:Vous n'avez reçu aucun message. Tendez l'oreille et profitez de cet instant de silence
) ) diff --git a/src/components/app/Messaging/MessageReader.css b/src/components/app/Messaging/MessageReader.css index 1ce627d..6e6137f 100644 --- a/src/components/app/Messaging/MessageReader.css +++ b/src/components/app/Messaging/MessageReader.css @@ -151,3 +151,76 @@ transform: translate(-50%, -50%); text-align: center; } + +.email-footer { + display: flex; +} + +.attachments-container { + display: flex; + overflow-x: auto; + white-space: nowrap; + flex-grow: 1; +} + +.attachments-container li { + list-style-type: none; + min-width: fit-content; + margin-right: 10px; +} + +.actions-container { + width: 240px; + /* Fixed width for the action buttons */ + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding-right: 10px; + padding-left: 10px; + gap: 5px; + /* Stack buttons vertically */ +} + +.action-button { + width: 40px; + height: 40px; + background: rgb(var(--background-color-1)); + padding: 5px; + border: none; + border-radius: 10px; + cursor: pointer; + transition: .2s; +} + +.action-button:is(:hover, :focus-visible) { + background: rgba(var(--background-color-3), 1); + transition: .2s; +} +.action-button path { + stroke: rgb(var(--text-color-alt)); +} + +.scroll-footer-div { + width: -moz-available; + /* Add for other brothers */ +} + +.no-attatchemnts-messages p { + color: rgb(var(--text-color-alt)); + padding-left: 15px; +} + +.no-attatchemnts-messages { + display: flex; + justify-content: center; + align-items: center; +} + +.cannot-click { + pointer-events: none; +} + +.not-allowed { + cursor: not-allowed !important; +} \ No newline at end of file diff --git a/src/components/app/Messaging/MessageReader.jsx b/src/components/app/Messaging/MessageReader.jsx index e5e2481..7f942c2 100644 --- a/src/components/app/Messaging/MessageReader.jsx +++ b/src/components/app/Messaging/MessageReader.jsx @@ -1,4 +1,5 @@ import { useState, useEffect, useContext } from "react"; +import { useNavigate, useLocation, Navigate, Link } from "react-router-dom"; import ContentLoader from "react-content-loader"; import { AppContext } from "../../../App"; @@ -8,15 +9,32 @@ import FileComponent from "../../generic/FileComponent"; import { capitalizeFirstLetter } from "../../../utils/utils"; import ScrollShadedDiv from "../../generic/CustomDivs/ScrollShadedDiv"; import DownloadIcon from "../../graphics/DownloadIcon"; +import PrintIcon from "../../graphics/PrintIcon"; +import FolderIcon from "../../graphics/FolderIcon"; +import ArchiveIcon from "../../graphics/ArchiveIcon"; +import InboxIcon from "../../graphics/InboxIcon"; +import MarkAsUnread from "../../graphics/MarkAsUnread"; +import SendIcon from "../../graphics/SendIcon"; +import DraftIcon from "../../graphics/DraftIcon"; +import { Tooltip, TooltipContent, TooltipTrigger } from "../../generic/PopUps/Tooltip"; -export default function MessageReader({ selectedMessage }) { +export default function MessageReader({ selectedMessage, fetchMessageMarkAsUnread, setSelectedMessage, archiveMessage, unarchiveMessage, moveMessage }) { + // States + const location = useLocation(); const { useUserData, actualDisplayTheme, useUserSettings } = useContext(AppContext); const settings = useUserSettings(); const messages = useUserData("sortedMessages").get(); + const messagesUnread = useUserData("sortedMessages"); const message = messages ? messages.find((item) => item.id === selectedMessage) : null; const [spoiler, setSpoiler] = useState(settings.get("isStreamerModeEnabled")); + const [folders, setFolders] = useState(useUserData("messageFolders").get()); + + useEffect(() => { + // Update the local state with the latest data + setFolders(useUserData("messageFolders").get()); + }, [useUserData("messageFolders").get()]); // behavior useEffect(() => { @@ -25,7 +43,28 @@ export default function MessageReader({ selectedMessage }) { } }, [selectedMessage]) + const handleMarkAsUnread = (event, msg) => { + event.preventDefault(); + event.stopPropagation(); + const controller = new AbortController(); + fetchMessageMarkAsUnread([msg.id], controller); + + if (msg.id === selectedMessage) { + setSelectedMessage(null); + } + + // mark as unread locally and kick the content so as to trigger a refetch the next reading (as the "mark as read" feature is trigger when fetching the message) + const oldMsg = messagesUnread.get() + const msgIdx = oldMsg.findIndex((item) => item.id === msg.id); + oldMsg[msgIdx].read = false; + oldMsg[msgIdx].content = null; + messagesUnread.set(oldMsg); + // update the messages glo + } + // JSX + const parsedHashFolder = parseInt(location.hash.slice(1, location.hash.lastIndexOf('-'))); + return (Aucun fichier joint
Sélectionnez un message dans votre boîte de réception pour le visualiser ici
} diff --git a/src/components/app/Messaging/Messaging.css b/src/components/app/Messaging/Messaging.css index 79d3ce3..975ad18 100644 --- a/src/components/app/Messaging/Messaging.css +++ b/src/components/app/Messaging/Messaging.css @@ -51,7 +51,7 @@ h3:has(~ .folders-container) { } .folders-container .folder-button { - padding: 15px; + padding: 10px; background-color: rgba(var(--background-color-0), .4); width: 100%; text-align: left; @@ -61,6 +61,9 @@ h3:has(~ .folders-container) { cursor: pointer; font-size: var(--font-size-16); transition: .1s; + display: flex; + align-items: center; + gap: 10px; } .folders-container .folder-button:is(:hover, :focus-visible) { @@ -73,3 +76,158 @@ h3:has(~ .folders-container) { max-height: 500px; } } + +.folder-icon-tooltip { + height: 40px; + width: 40px; +} + +.edit-folder-tooltip { + position: absolute; + top: 50%; + right: 5px; + transform: translateY(-50%); + height: 40px; + width: 40px; + border-radius: 10px; + cursor: pointer; + transition: .1s; +} + +.edit-folder-tooltip div { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; +} + +.edit-folder-tooltip:has([data-state="open"]) { + background-color: rgb(var(--text-color-main), .15); +} + +.edit-folder-tooltip .edit-folder-icon { + height: 33px; + transition: .1s; +} + +.edit-folder-tooltip .edit-folder-icon path { + stroke: rgba(var(--text-color-alt), .7); + transition: .1s; +} + +.edit-folder-tooltip:has([data-state="open"]) .edit-folder-icon path { + stroke: rgb(var(--text-color-main)); +} + +.edit-folder-button { + padding: 10px; + background-color: rgba(var(--background-color-0), .4); + width: 100%; + text-align: left; + border: none; + border-radius: 6px; + outline: none; + cursor: pointer; + font-size: var(--font-size-16); + transition: .1s; + display: flex; + align-items: center; + gap: 10px; +} + +.edit-folder-button:is(:hover, :focus-visible) { + background-color: rgba(var(--background-color-0), .6); +} + +.edit-folder-container { + list-style-type: none; + /* padding: 15px; */ + display: flex; + flex-flow: column nowrap; + gap: 10px; +} + +h3:has(~ .edit-folder-container) { + margin-bottom: 10px; +} + +@media only screen and (max-width: 869px) { + .window.inbox-window { + /* min-height: 160px; */ + max-height: 500px; + } +} + +.edit-folder-icon-tooltip { + height: 40px; + width: 40px; +} + +.delete:is(:hover) { + background-color: #ff0000; + transition: .3s; +} + +.delete:is(:hover) path { + stroke: #ffffff; + transition: .3s; +} + +#MessagesTitle:is(:hover){ + background-color: rgba(var(--text-color-main),.15); + transition: .3s; + cursor: text; +} + +#MessagesTitle { + padding: 10px; + border-radius: 10px; + transition: .3s; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: fit-content; +} + +.MessagesTitle-container { + transition: .3s; + width: calc(100% - 100px); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: flex; + align-items: center; + justify-content: center; +} + +.prevent-highlight { + cursor: grab !important; + background-color: transparent !important; +} + +.create-folder { + background-color: rgba(var(--background-color-0), .9) !important; +} + +.edit-folder-name-input { + transform: scale(.85); + width: 100%; +} + +.edit-folder-name-input .text-input { + text-align: center; + padding: 10px !important; +} + +.edit-folder-name-container { + width: calc(100% - 80px); +} + +.selected-folder { + background-color: rgba(var(--background-color-3), 0.6) !important; +} + +.no-questionmark { + cursor: default; +} \ No newline at end of file diff --git a/src/components/app/Messaging/Messaging.jsx b/src/components/app/Messaging/Messaging.jsx index 717f042..c16116c 100644 --- a/src/components/app/Messaging/Messaging.jsx +++ b/src/components/app/Messaging/Messaging.jsx @@ -1,4 +1,3 @@ - import { useState, useRef, useEffect, useContext } from "react"; import { useNavigate, useLocation, Navigate, Link } from "react-router-dom"; @@ -17,22 +16,42 @@ import Inbox from "./Inbox"; import MessageReader from "./MessageReader"; import { Tooltip, TooltipContent, TooltipTrigger } from "../../generic/PopUps/Tooltip"; import FolderIcon from "../../graphics/FolderIcon"; +import InboxIcon from "../../graphics/InboxIcon"; +import SendIcon from "../../graphics/SendIcon"; +import ArchiveIcon from "../../graphics/ArchiveIcon"; +import EditIcon from "../../graphics/EditIcon"; +import DeleteIcon from "../../graphics/DeleteIcon"; +import RenameIcon from "../../graphics/RenameIcon"; +import NewFolderIcon from "../../graphics/NewFolderIcon"; +import DraftIcon from "../../graphics/DraftIcon"; import { capitalizeFirstLetter } from "../../../utils/utils"; +import TextInput from "../../generic/UserInputs/TextInput"; +import { el } from "date-fns/locale"; +import { set } from "date-fns"; -export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fetchMessageContent, fetchMessageMarkAsUnread }) { +export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fetchMessageContent, fetchMessageMarkAsUnread, renameFolder, deleteFolder, createFolder, archiveMessage, unarchiveMessage, moveMessage }) { // States const navigate = useNavigate(); const location = useLocation(); - + const { useUserData } = useContext(AppContext); - // const [selectedMessage, setSelectedMessage] = useState(isNaN(parseInt(location.hash.slice(1))) ? null : parseInt(location.hash.slice(1))); const [selectedMessage, setSelectedMessage] = useState(null); const [selectedFolder, setSelectedFolder] = useState(0); const oldSelectedMessage = useRef(selectedMessage); const messages = useUserData("sortedMessages"); - const messageFolders = useUserData("messageFolders"); + const [folders, setFolders] = useState(useUserData("messageFolders").get()); + useEffect(() => { + // Update the local state with the latest data + setFolders(useUserData("messageFolders").get()); + }, [useUserData("messageFolders").get()]); + + + + + const [isEditingFolder, setIsEditingFolder] = useState(false); + const [newFolderName, setNewFolderName] = useState(''); // behavior useEffect(() => { @@ -42,7 +61,7 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe useEffect(() => { const controller = new AbortController(); if (isLoggedIn) { - if (messageFolders.get() === undefined || !messageFolders.get().find((folder) => folder.id === selectedFolder)?.fetchInitiated) { + if (folders === undefined || !folders.find((folder) => folder.id === selectedFolder)?.fetchInitiated) { fetchMessages(selectedFolder, controller); } } @@ -50,7 +69,7 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe return () => { controller.abort(); } - }, [isLoggedIn, activeAccount, selectedFolder, messages.get(), messageFolders.get()]); + }, [isLoggedIn, activeAccount, selectedFolder, messages.get(), folders]); useEffect(() => { if (messages.get() === undefined) { @@ -62,9 +81,10 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe const controller = new AbortController(); if (selectedMessage !== null) { fetchMessageContent(selectedMessage, controller); - const parsedHash = parseInt(location.hash.slice(1)); - if (parsedHash !== selectedMessage) { - const newHash = "#" + selectedMessage; + const parsedHashMessage = parseInt(location.hash.slice(location.hash.lastIndexOf('-') + 1)); + const parsedHashFolder = parseInt(location.hash.slice(1, location.hash.lastIndexOf('-'))); + if (parsedHashMessage !== selectedMessage || parsedHashFolder !== selectedFolder) { + const newHash = "#" + selectedFolder + '-' + selectedMessage; navigate(newHash); } } else { @@ -85,15 +105,27 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe if (["#patch-notes", "#policy", "#feedback"].includes(location.hash)) { return; } - const parsedHash = parseInt(location.hash.slice(1)); - if (!isNaN(parsedHash) && parsedHash !== selectedMessage) { + const parsedHashMessage = parseInt(location.hash.slice(location.hash.lastIndexOf('-') + 1)); + const parsedHashFolder = parseInt(location.hash.slice(1, location.hash.lastIndexOf('-'))); + console.log("useEffect ~ parsedHashMessage", parsedHashMessage) + + if (!isNaN(parsedHashMessage) && parsedHashMessage !== selectedMessage) { if (messages.get()) { - const doesMessageExist = messages.get()?.findIndex((item) => item.id === parsedHash) !== -1; + const doesMessageExist = messages.get()?.findIndex((item) => item.id === parsedHashMessage) !== -1; console.log("useEffect ~ doesMessageExist:", doesMessageExist) if (doesMessageExist) { - setSelectedMessage(parsedHash); + setSelectedFolder(parsedHashFolder); + setSelectedMessage(parsedHashMessage); } else { - navigate("#"); + setSelectedFolder(parsedHashFolder); + // now we need to fetch the message for the selected folder + const controller = new AbortController(); + fetchMessages(parsedHashFolder, controller); + + // now we need to select the message after fetching the messages + setTimeout(() => { + setSelectedMessage(parsedHashMessage); + }, 0); } } } @@ -103,29 +135,205 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe oldSelectedMessage.current = selectedMessage; }, [selectedMessage]); + useEffect(() => { + if (!isEditingFolder) { + const currentFolder = folders?.find((item) => item.id === selectedFolder); + if (currentFolder) { + console.log("currentFolder", currentFolder); + setNewFolderName(currentFolder.name); + } + } + }, [selectedFolder, folders, isEditingFolder]); + + + + const handleRenameSave = async () => { + if (newFolderName.trim() !== '') { + if (selectedFolder === -3) { + const controller = new AbortController(); + let newFolder = await createFolder(newFolderName, controller); + setTimeout(() => setSelectedFolder(newFolder), 0); + // refresh the folder list and title + + } else { + renameFolder(selectedFolder, newFolderName); // Call the rename function with folder ID and new name + } + setIsEditingFolder(false); // Exit editing mode + } + }; + + const handleRenameCancel = () => { + setIsEditingFolder(false); + setNewFolderName(folders?.find((item) => item.id === selectedFolder)?.name || ''); + if (selectedFolder === -3) { + setSelectedFolder(0); + } + }; + + // cancel editiing on click outside of the input + useEffect(() => { + const handleClickOutside = (event) => { + if (isEditingFolder && !event.target.closest('.edit-folder-name-container')) { + handleRenameCancel(); + } + }; + + if (isEditingFolder) { + document.addEventListener('mousedown', handleClickOutside); + } else { + document.removeEventListener('mousedown', handleClickOutside); + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isEditingFolder]); + + + // cancel editing on escape key + useEffect(() => { + const handleKeyDown = (event) => { + if (event.key === 'Escape') { + handleRenameCancel(); + } + }; + + if (isEditingFolder) { + document.addEventListener('keydown', handleKeyDown); + } else { + document.removeEventListener('keydown', handleKeyDown); + } + + return () => { + document.removeEventListener('keydown', handleKeyDown); + }; + }, [isEditingFolder]); + + // validate editing on enter key + useEffect(() => { + const handleKeyDown = (event) => { + if (event.key === 'Enter') { + handleRenameSave(); + } + }; + + if (isEditingFolder) { + document.addEventListener('keydown', handleKeyDown); + } else { + document.removeEventListener('keydown', handleKeyDown); + } + + return () => { + document.removeEventListener('keydown', handleKeyDown); + }; + }, [isEditingFolder, newFolderName]); + + // changing folder should exit editing mode + useEffect(() => { + setIsEditingFolder(false); + }, [selectedFolder]); + // JSX return (Aucun fichier joint
{message.subject}
{(new Date(message.date)).toLocaleDateString("fr-FR", { month: "long", diff --git a/src/components/app/Messaging/MessageReader.jsx b/src/components/app/Messaging/MessageReader.jsx index 225dcd1..f03cce0 100644 --- a/src/components/app/Messaging/MessageReader.jsx +++ b/src/components/app/Messaging/MessageReader.jsx @@ -132,8 +132,6 @@ export default function MessageReader({ selectedMessage, fetchMessageMarkAsUnrea const printWindow = window.open("", "_blank"); printWindow.document.write("
{message.subject}
{(new Date(message.date)).toLocaleDateString("fr-FR", { month: "long", diff --git a/src/components/app/Messaging/MessageReader.jsx b/src/components/app/Messaging/MessageReader.jsx index f03cce0..cc17b13 100644 --- a/src/components/app/Messaging/MessageReader.jsx +++ b/src/components/app/Messaging/MessageReader.jsx @@ -70,7 +70,7 @@ export default function MessageReader({ selectedMessage, fetchMessageMarkAsUnrea {selectedMessage !== null && messages && messages.length > 0 ?
{message && (settings.get("isStreamerModeEnabled") ? message?.from?.name?.split(" ")[0] + " " + "-".repeat(message?.from?.name?.length) : message?.from?.name)}
+{message && (message?.from?.civilite + " " + (settings.get("isStreamerModeEnabled") ? "-".repeat(message?.from?.nom?.length) : message?.from?.nom))}
{message && message?.date && (new Date(message.date).toLocaleDateString("fr-FR", {
month: "long",
diff --git a/src/components/app/Messaging/Messaging.jsx b/src/components/app/Messaging/Messaging.jsx
index 427ebdc..d955f17 100644
--- a/src/components/app/Messaging/Messaging.jsx
+++ b/src/components/app/Messaging/Messaging.jsx
@@ -46,13 +46,13 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe
const module = accountsListState[activeAccount].modules?.find(module => module.code === "MESSAGERIE");
- let canSendMessages = (module?.params?.destAdmin ?? "1") === "1" ||
+ let canSendMessages = false && (module?.params?.destAdmin ?? "1") === "1" ||
(module?.params?.destEleve ?? "1") === "1" ||
(module?.params?.destFamille ?? "1") === "1" ||
(module?.params?.destProf ?? "1") === "1" ||
(module?.params?.destEspTravail ?? "1") === "1";
if (accountsListState[activeAccount].accountType !== "E") {
- canSendMessages = true;
+ // canSendMessages = true;
}
const [isEditingFolder, setIsEditingFolder] = useState(false);
diff --git a/src/components/generic/FileComponent.css b/src/components/generic/FileComponent.css
index c5963bb..19215db 100644
--- a/src/components/generic/FileComponent.css
+++ b/src/components/generic/FileComponent.css
@@ -45,6 +45,7 @@
}
.file-component .file-name {
+ flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
From 8d7957712ff2f7d9b2ff51c45cf4df6e6e9294f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Truite=20S=C3=A9ch=C3=A9e?= Dossiers
diff --git a/src/components/generic/PopUps/Tooltip.jsx b/src/components/generic/PopUps/Tooltip.jsx
index ec271e8..2ff2235 100644
--- a/src/components/generic/PopUps/Tooltip.jsx
+++ b/src/components/generic/PopUps/Tooltip.jsx
@@ -195,7 +195,6 @@ export const TooltipTrigger = forwardRef(function TooltipTrigger({ children, ...
export const TooltipContent = forwardRef(function TooltipContent({ children, style, className = "", ...props }, propRef) {
const context = useTooltipContext();
- const { isTabletLayout } = useContext(AppContext);
const ref = useMergeRefs([context.refs.setFloating, children.ref, propRef]);
// Affiche / N'affiche pas la tooltip
@@ -203,7 +202,7 @@ export const TooltipContent = forwardRef(function TooltipContent({ children, sty
// Gestion du clic à l'intérieur pour fermer la tooltip
const handleClickInside = () => {
- if (context.options.closeOnClickInside && isTabletLayout) {
+ if (context.options.closeOnClickInside) {
context.setIsOpen(false);
}
};
From 46dd4af2a810adea317f1959a3960b6021368f30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Truite=20S=C3=A9ch=C3=A9e?=