Skip to content

Commit

Permalink
feat(Messaging): add content loaders,
Browse files Browse the repository at this point in the history
fix(Messaging): multiple bug fixes
  • Loading branch information
Truiteseche committed Sep 20, 2024
1 parent 421d0fc commit bec283f
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 42 deletions.
18 changes: 9 additions & 9 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,15 @@
--alpha-shadow-color-scroll-shaded-div: 0.3;

--color-very-good: 21, 87, 37;
--color-very-good-background: 0, 255, 0, 0.2;
--color-good: 66, 77, 30;
--color-good-background: 201, 255, 0, 0.2;
--color-average: 89, 89, 25;
--color-average-background: 255, 217, 0, 0.2;
--color-bad: 104, 80, 35;
--color-bad-background: 255, 165, 0, 0.2;
--color-very-bad: 117, 45, 45;
--color-very-bad-background: 153, 1, 1, 0.2;
--color-very-good-background: 0, 255, 0, 0.2;
--color-good: 66, 77, 30;
--color-good-background: 201, 255, 0, 0.2;
--color-average: 89, 89, 25;
--color-average-background: 255, 217, 0, 0.2;
--color-bad: 104, 80, 35;
--color-bad-background: 255, 165, 0, 0.2;
--color-very-bad: 117, 45, 45;
--color-very-bad-background: 153, 1, 1, 0.2;
}

:root.balanced *,
Expand Down
9 changes: 2 additions & 7 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -874,9 +874,6 @@ export default function App() {
newGrade.subjectName = grade.libelleMatiere;
newGrade.isSignificant = !grade.nonSignificatif;
newGrade.examSubjectSRC = grade.uncSujet;
if (grade.id == 6291688) {
console.log(grade)
}
newGrade.examSubjectSRC = grade.uncSujet === "" ? undefined : new File(grade.uncSujet, "NODEVOIR", grade.uncSujet, `sujet-${grade.devoir}-${grade.subjectCode}`, { idDevoir: grade.id });
newGrade.examCorrectionSRC = grade.uncCorrige === "" ? undefined : new File(grade.uncCorrige, "NODEVOIR", grade.uncCorrige, `correction-${grade.devoir}-${grade.subjectCode}`, { idDevoir: grade.id });
newGrade.isReal = true;
Expand Down Expand Up @@ -1141,7 +1138,7 @@ export default function App() {


function sortMessages(messages) {
const sortedMessages = messages.messages.received.map((message) => { console.log("files:", message.files); return {
const sortedMessages = messages.messages.received.map((message) => { return {
date: message.date,
files: structuredClone(message.files)?.map((file) => new File(file.id, file.type, file.libelle)),
from: message.from,
Expand Down Expand Up @@ -1316,7 +1313,6 @@ export default function App() {
})
})
.then((response) => {
console.log(".then ~ response:", response)
// GESTION DATA
let statusCode = response.code;
if (statusCode === 200) {
Expand Down Expand Up @@ -1696,7 +1692,6 @@ export default function App() {
)
.then((response) => response.json())
.then((response) => {
console.log(".then ~ response:", response)
let code;
if (accountsListState[activeAccount].firstName === "Guest") {
code = 49969;
Expand All @@ -1723,7 +1718,7 @@ export default function App() {

async function fetchMessageContent(id, controller) {
const oldSortedMessages = useUserData("sortedMessages").get();
if (oldSortedMessages) {
if (oldSortedMessages && oldSortedMessages?.length > 0) {
const targetMessageIdx = oldSortedMessages.findIndex((item) => item.id === id);
if (oldSortedMessages[targetMessageIdx].content !== null) {
return;
Expand Down
32 changes: 29 additions & 3 deletions src/components/app/Messaging/Inbox.css
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,24 @@
padding: 10px;
border-left: 4px solid rgb(var(--text-color-alt), .5);
border-bottom: 1px solid rgb(var(--text-color-alt), .5);
opacity: .6;
opacity: 0;
--opacity: .6;
outline: none;
cursor: pointer;
animation: jump-in 0.5s var(--timing-function-spring-effect) forwards;
animation-delay: calc(var(--order) * 60ms);
}

@keyframes jump-in {
from {
opacity: 0;
transform: translateY(-20px);
}

to {
opacity: var(--opacity);
transform: translateY(0);
}
}

#inbox .message-container:last-child {
Expand All @@ -55,14 +70,14 @@
#inbox .message-container[data-read=false] {
border-left: 4px solid rgb(var(--text-color-alt));
padding-left: 6px;
opacity: 1;
--opacity: 1;
}

#inbox .message-container:is(:hover, :focus-visible) {
background-color: rgba(var(--background-color-0), .2);
}
#inbox .message-container.selected {
opacity: .8;
--opacity: .8;
background-color: rgba(var(--background-color-focus));
}

Expand Down Expand Up @@ -128,3 +143,14 @@
:fullscreen #inbox .message-container:last-child {
border-bottom: none;
}


#inbox .no-message-received {
color: rgb(var(--text-color-alt));
display: flex;
height: 100%;
padding: 75px 20px;
align-items: center;
justify-content: center;
text-align: center;
}
59 changes: 47 additions & 12 deletions src/components/app/Messaging/Inbox.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect, useContext } from "react";

import { useState, useEffect, useRef, useContext } from "react";
import ContentLoader from "react-content-loader";
import { AppContext } from "../../../App";

import "./Inbox.css";
Expand All @@ -12,31 +12,34 @@ import MarkAsUnread from "../../graphics/MarkAsUnread";

export default function Inbox({ selectedMessage, setSelectedMessage, fetchMessageMarkAsUnread }) {
// States
const { useUserData } = useContext(AppContext);
const { useUserData, actualDisplayTheme, useUserSettings } = useContext(AppContext);
const settings = useUserSettings();
const [search, setSearch] = useState("");
const messages = useUserData("sortedMessages");

const contentLoadersRandomValues = useRef({ authorWidth: Array.from({ length: 13 }, (_) => Math.round(Math.random() * 100) + 100), subjectWidth: Array.from({ length: 13 }, (_) => Math.floor(Math.random() * 150) + 150), dateWidth: Array.from({ length: 13 }, (_) => Math.floor(Math.random() * 50) + 50), containsFiles: Array.from({ length: 13 }, (_) => (Math.random() > .6)) })

// behavior
const handleClick = (message) => {
setSelectedMessage(message.id);
}

const handleKeyDown = (event, msg) => {
if (event.key === "Enter" || event.key === " ") {
handleClick(msg);
}
}

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 = messages.get();
const msgIdx = oldMsg.findIndex((item) => item.id === msg.id);
Expand All @@ -54,7 +57,7 @@ export default function Inbox({ selectedMessage, setSelectedMessage, fetchMessag
let regexp;
try {
regexp = new RegExp(removeAccents(search.toLowerCase()));
} catch {return -1}
} catch { return -1 }
const filterBy = [message.subject, message.from.name, message.content?.content, message.files?.map((file) => file.name)].flat();
for (let filter of filterBy) {
if (filter) {
Expand All @@ -75,8 +78,8 @@ export default function Inbox({ selectedMessage, setSelectedMessage, fetchMessag
? (messages.get().length > 0
? <ScrollShadedDiv className="messages-container">
<ul>
{messages.get().filter(filterResearch).map((message) => <li className={"message-container" + (selectedMessage === message.id ? " selected" : "")} data-read={message.read} onClick={() => handleClick(message)} onKeyDown={(event) => handleKeyDown(event, message)} key={message.id} role="button" tabIndex={0}>
<h4 className="message-subject"><span className="author-name">{message.from.name}</span> <span className="actions"><button disabled={!message.read} onClick={(event) => handleMarkAsUnread(event, message)} className="mark-as-unread" title="Marquer comme non lu"><MarkAsUnread className="mark-as-unread-icon"/></button> {message.files?.length > 0 && <AttachmentIcon className="attachment-icon" />}</span></h4>
{messages.get().filter(filterResearch).map((message, index) => <li style={{ "--order": index }} className={"message-container" + (selectedMessage === message.id ? " selected" : "")} data-read={message.read} onClick={() => handleClick(message)} onKeyDown={(event) => handleKeyDown(event, message)} key={message.id} role="button" tabIndex={0}>
<h4 className="message-subject"><span className="author-name">{message.from.name}</span> <span className="actions"><button disabled={!message.read} onClick={(event) => handleMarkAsUnread(event, message)} className="mark-as-unread" title="Marquer comme non lu"><MarkAsUnread className="mark-as-unread-icon" /></button> {message.files?.length > 0 && <AttachmentIcon className="attachment-icon" />}</span></h4>
<p className="message-author">{message.subject}</p>
<p className="message-date">{(new Date(message.date)).toLocaleDateString("fr-FR", {
month: "long",
Expand All @@ -87,9 +90,41 @@ export default function Inbox({ selectedMessage, setSelectedMessage, fetchMessag
</li>)}
</ul>
</ScrollShadedDiv>
: <p>Vous n'avez reçu aucun message. Profitez bien de votre isolement social ^^</p>
: <p className="no-message-received">Vous n'avez reçu aucun message. Profitez bien de votre isolement social ^^</p>
)
: <p>content-loader</p>
: <ScrollShadedDiv className="messages-container">
<ul>
{Array.from({ length: 13 }, (_, index) => <li key={index} style={{ "--order": -69 /* skip the animation */ }} className={"message-container"}>
<h4 className="message-subject"><span className="author-name"><ContentLoader
animate={settings.get("displayMode") === "quality"}
speed={1}
backgroundColor={actualDisplayTheme === "dark" ? "#7878ae" : "#75759a"}
foregroundColor={actualDisplayTheme === "dark" ? "#9292d4" : "#9292c0"}
style={{ width: `min(${contentLoadersRandomValues.current.authorWidth[index]}px, 100%)`, maxHeight: "20px" }}
>
<rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" />
</ContentLoader></span><span className="actions">{contentLoadersRandomValues.current.containsFiles[index] && <AttachmentIcon className="attachment-icon" />}</span></h4>
<p className="message-author"><ContentLoader
animate={settings.get("displayMode") === "quality"}
speed={1}
backgroundColor={actualDisplayTheme === "dark" ? "#63638c" : "#9d9dbd"}
foregroundColor={actualDisplayTheme === "dark" ? "#7e7eb2" : "#bcbce3"}
style={{ width: `min(${contentLoadersRandomValues.current.subjectWidth[index]}px, 60%)`, maxHeight: "16px" }}
>
<rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" />
</ContentLoader></p>
<p className="message-date"><ContentLoader
animate={settings.get("displayMode") === "quality"}
speed={1}
backgroundColor={actualDisplayTheme === "dark" ? "#63638c" : "#9d9dbd"}
foregroundColor={actualDisplayTheme === "dark" ? "#7e7eb2" : "#bcbce3"}
style={{ width: `min(${contentLoadersRandomValues.current.dateWidth[index]}px, 30%)`, maxHeight: "16px" }}
>
<rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" />
</ContentLoader></p>
</li>)}
</ul>
</ScrollShadedDiv>
}
</div>
)
Expand Down
11 changes: 11 additions & 0 deletions src/components/app/Messaging/MessageReader.css
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,14 @@
#message-reader .attachments-container .attachment .download-icon {
height: 20px;
}

#message-reader .no-selected-message-placeholder {
color: rgb(var(--text-color-alt));
width: 100%;
padding: 75px 20px;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
43 changes: 35 additions & 8 deletions src/components/app/Messaging/MessageReader.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect, useContext } from "react";

import ContentLoader from "react-content-loader";
import { AppContext } from "../../../App";

import "./MessageReader.css";
Expand All @@ -12,7 +12,8 @@ import DownloadIcon from "../../graphics/DownloadIcon";

export default function MessageReader({ selectedMessage }) {
// States
const { useUserData, actualDisplayTheme } = useContext(AppContext);
const { useUserData, actualDisplayTheme, useUserSettings } = useContext(AppContext);
const settings = useUserSettings();
const messages = useUserData("sortedMessages").get();
const message = messages ? messages.find((item) => item.id === selectedMessage) : null;

Expand All @@ -21,8 +22,7 @@ export default function MessageReader({ selectedMessage }) {
// JSX
return (
<div id="message-reader">
{selectedMessage !== null
? message?.content
{selectedMessage !== null && messages && messages.length > 0
? <div className="message-container">
<div className="email-header">
<p className="author">{message && message?.from?.name}</p>
Expand All @@ -35,9 +35,37 @@ export default function MessageReader({ selectedMessage }) {
}))}</p>
</div>
<hr />
<ScrollShadedDiv className="message-content-container" key={selectedMessage}>
<ScrollShadedDiv className="message-content-container" key={message?.content ? selectedMessage + "-content" /* trigger a rerender so that the ScrollShadedDiv detect overflow and display shadows */ : selectedMessage}>
{message?.content
? <EncodedHTMLDiv className="message-content" backgroundColor={actualDisplayTheme === "dark" ? "#303047" : "#d6d6f8"}>{message?.content && message?.content?.content}</EncodedHTMLDiv>
: <ContentLoader
className="message-content"
animate={settings.get("displayMode") === "quality"}
speed={1}
backgroundColor={actualDisplayTheme === "dark" ? "#63638c" : "#9d9dbd"}
foregroundColor={actualDisplayTheme === "dark" ? "#7e7eb2" : "#bcbce3"}
style={{ display: "block", width: "min(800px, 100%)", margin: "0 auto", height: "575px" }}
>
<rect x="0" y="0" rx="8" ry="8" width="30%" height="20px" />

<rect x="0" y="60" rx="8" ry="8" width="100%" height="20px" />
<rect x="0" y="90" rx="8" ry="8" width="70%" height="20px" />

<rect x="0" y="150" rx="8" ry="8" width="100%" height="20px" />
<rect x="0" y="180" rx="8" ry="8" width="100%" height="20px" />
<rect x="0" y="210" rx="8" ry="8" width="100%" height="20px" />
<rect x="0" y="240" rx="8" ry="8" width="50%" height="20px" />

<rect x="0" y="300" rx="8" ry="8" width="100%" height="20px" />
<rect x="0" y="330" rx="8" ry="8" width="40%" height="20px" />

<rect x="0" y="390" rx="8" ry="8" width="40%" height="20px" />
<rect x="0" y="420" rx="8" ry="8" width="60%" height="20px" />
<rect x="0" y="450" rx="8" ry="8" width="30%" height="20px" />

<EncodedHTMLDiv className="message-content" backgroundColor={actualDisplayTheme === "dark" ? "#303047" : "#d6d6f8"}>{message?.content && message?.content?.content}</EncodedHTMLDiv>
<rect x="0" y="510" rx="8" ry="8" width="20%" height="20px" />
</ContentLoader>
}
</ScrollShadedDiv>
{message && (message?.files?.length > 0
? <>
Expand All @@ -51,8 +79,7 @@ export default function MessageReader({ selectedMessage }) {
: null)}

</div>
: <p>content-loader</p>
: <p>Sélectionnez un message dans votre boîte de réception pour le visualiser ici !</p>
: <p className="no-selected-message-placeholder">Sélectionnez un message dans votre boîte de réception pour le visualiser ici</p>
}
</div>
)
Expand Down
6 changes: 4 additions & 2 deletions src/components/app/Messaging/Messaging.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe
if (isLoggedIn) {
if (messages.get() === undefined) {
fetchMessages(controller);
setSelectedMessage(null);
}
}

Expand All @@ -48,6 +47,9 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe
}, [isLoggedIn, activeAccount, messages.get()]);

useEffect(() => {
if (messages.get() === undefined) {
return;
}
const controller = new AbortController();
if (selectedMessage !== null) {
fetchMessageContent(selectedMessage, controller);
Expand All @@ -65,7 +67,7 @@ export default function Messaging({ isLoggedIn, activeAccount, fetchMessages, fe
return () => {
controller.abort();
}
}, [location, selectedMessage]);
}, [location, selectedMessage, messages.get()]);

useEffect(() => {
if (oldSelectedMessage.current !== selectedMessage) {
Expand Down
Loading

0 comments on commit bec283f

Please sign in to comment.