Ardoise

Ce projet de conception de jeu à été réalisé en équipe de 5 contenant 2 artistes et 3 programmeurs.
Le but de ce projet était de créer un projet permettant la gestion du temps en équipe. Cet outil permet de créer des projets, d’y ajouter des partenaires, clients ainsi que d’ajouter l’historique des tâches de chacun. Une tâche peut être créée avec sa description et être visible par les coéquipiers.
Lors de ce travail d’équipe, mes tâches étaient de :
- Organiser mes tâches selon ma méthode « Kanban » grâce à Freedcamp.
- Concevoir le système de notifications (reliées à une bases de donnée pour les recevoir lors de la connexion).
- Concevoir le système de création et modification des projets.
- Mise en place du système de connexion grâce aux services Google.
- Permettre l’ajout de clients aux projets.
Exemples de code conçus lors de ce projet
Composant permettant la création d’un projet dans la base de donnée de Firebase.
import { addDoc, collection, query, setDoc, where } from '@firebase/firestore';
import { useEffect, useState } from 'react';
import { useHistory } from 'react-router';
import { db } from '../../../config/firebase';
import { useAuth } from '../../../context/authContext';
import Form from 'react-bootstrap/Form';
import "../../Formulaire/FormCreate.scss";
import "../../Formulaire/Formulaire.scss";
import { onSnapshot } from 'firebase/firestore';
import { useNotifs } from '../../../context/notificationsContext';
import { Link } from 'react-router-dom';
// import { doc, updateDoc, arrayUnion, arrayRemove } from "firebase/firestore";
const ProjetsCreate = () => {
const {user} = useAuth();
const {updateNotif, sendAjoutProjetNotifs} = useNotifs();
const history = useHistory();
const [projet,setProjet] = useState(
{
titreProjet: "",
couleur : "",
dateLivraison : "",
participants : [],
participantsId : [],
idClient : "",
client : [],
adminId: user.id,
}
);
// liste des participants presents dans le user
const [partenairesListe, setPartenairesListe] = useState([]);
useEffect(() => {
// initie la liste des partenaires contenus dans le user
const unsub = onSnapshot(collection(db, 'users', user.id, 'partenaires'), (snapshot) => {
// retourne un tableau des partenaires avec toute les proprietes
const tableau = snapshot.docs.map(
doc => doc.data()
);
// s'il y a une valeur dans le tableau
if(tableau.length > 0){
// set la liste initiale de partenaires a sa valeur
setPartenairesListe(tableau);
}
});
},[]);
// obtention des clients du user
const [clients, setClients] = useState([]);
const [currentClient, setCurrentClient] = useState({});
const q = query(collection(db, "clients"), where("createurId", "==", user.id));
useEffect(() => {
const unsub = onSnapshot(q, (snapshot) => {
setClients(
snapshot.docs.map(doc => {
return {
...doc.data(),
id: doc.id
}
})
);
});
}, []);
// enregistre le projet
const addProjet = async() => {
if(projet.titreProjet === ""){
updateNotif(`Le projet doit avoir un nom!`, true);
}
else if(projet.couleur === ""){
updateNotif(`Le projet doit avoir une couleur!`, true);
}
else{
updateNotif(`Projet ${projet.titreProjet} créé!`, false);
let client = getCurrentClient();
let participantsId = getParticipantsId();
const docRef = await addDoc(collection(db, 'projets'), {
titreProjet: projet.titreProjet,
couleur: projet.couleur,
participants: projet.participants,
participantsId: participantsId,
dateLivraison: projet.dateLivraison,
idClient: currentClient,
client : client,
adminId: user.id,
}).then( (projetRef) =>
sendAjoutProjetNotifs( {...projet, projetId : projetRef.id})
);
history.push("/projets");
}
};
const getParticipantsId = () => {
let participantsId = [];
projet.participants.forEach(
(participant) => {
participantsId.push(participant.id);
}
);
return participantsId;
}
const getCurrentClient = () => {
let leClient = {};
clients.forEach(client => {
if(client.id == currentClient){
leClient = client;
}
});
console.log(leClient);
return leClient;
}
const updateProjetHandler = (value, prop) => {
setProjet(
(current) => ({
...current,
[prop] : value,
})
)
}
const updateParticipantsProjet = (participantId) => {
// filtre la liste des participants contenus dans le user pour trouver celui lié au Id reçus en parametre
const participant = partenairesListe.filter(unPartenaire => unPartenaire.id == participantId);
setProjet(
(current) => (
{
...current,
// participant [0] puisque filter retourne un array et qu'il ne peut posseder qu'une seule valeur avec le filtre
participants : [...projet.participants, participant[0]]
}
)
);
console.log(participant[0]);
}
const verifierPartenaireAjoute = (partenaire) => {
let estAjoute = false;
projet.participants.forEach(participant => {
if(partenaire.id === participant.id){
estAjoute = true;
}
});
return estAjoute;
}
const retirerParticipantAjoute = (participant) => {
// filtre le tableau des participants pour ne garder que les participants n'etant pas celui supprime
const nouvelArraySansLeParticipant = projet.participants.filter(unParticipant => unParticipant.id !== participant.id);
// modifie la valeur du state du projet pour que le participant soit retire
setProjet(
(current) => (
{
...current,
participants : nouvelArraySansLeParticipant
}
)
);
}
const submitHandler = (e) =>{
e.preventDefault();
}
return(
<div className="bgForm">
<form className="nouveauItem" onSubmit={submitHandler} noValidate>
<div className="titleCreationForm">
<h2>Création d'un projet </h2>
<Link to="/projets"><i className="material-icons">close</i></Link>
</div>
<div className="formAffichage">
<div className="form-group">
<Form.Label><label>Titre du projet : </label></Form.Label>
<input type="text" onChange={(e) => updateProjetHandler(e.target.value,"titreProjet")} value={projet.titreProjet} className="" required></input>
</div>
<p>Choisir une couleur</p>
<div className="choixCouleur">
<div>
{/* jaune */}
<button onClick = {(e) => updateProjetHandler(e.target.value,"couleur")} style={projet.couleur == "#ffff00" ? {backgroundColor:"#cccc00"} : {backgroundColor:"#ffff24"}} value = "#ffff00"></button>
</div>
<div>
{/* rose */}
<button onClick = {(e) => updateProjetHandler(e.target.value,"couleur")} style={projet.couleur == "#ff00ff" ? {backgroundColor:"#99003d"} : {backgroundColor:"#ff00ff"}} value = "#ff00ff"></button>
</div>
<div>
{/* vert */}
<button onClick = {(e) => updateProjetHandler(e.target.value,"couleur")} style={projet.couleur == "#00ff00" ? {backgroundColor:"#009900"} : {backgroundColor:"#00ff00"}} value = "#00ff00"></button>
</div>
<div>
{/* rouge */}
<button onClick = {(e) => updateProjetHandler(e.target.value,"couleur")} style={projet.couleur == "#ff0000" ? {backgroundColor:"#b30000"} : {backgroundColor:"#ff0000"}} value = "#ff0000"></button>
</div>
<div>
{/* lightblue */}
<button onClick = {(e) => updateProjetHandler(e.target.value,"couleur")} style={projet.couleur == "#00ffff" ? {backgroundColor:"#00b3b3"} : {backgroundColor:"#00ffff"}} value = "#00ffff"></button>
</div>
</div>
<div className="form-group">
<label>Date de livraison : </label>
<input type="date" onChange={(e) => updateProjetHandler(e.target.value,"dateLivraison")} value={projet.dateLivraison} className="" required></input>
</div>
{
// si le user contient des id de partenaires
partenairesListe.length > 0 ?
<div className="partnerAdd">
<select value="" onChange={ (e) => (updateParticipantsProjet(e.target.value)) }>
{/* Option de base pour permettre le fonctionnement du select et mettre un message au user */}
<option value="">- Ajouter un partenaire -</option>
{
partenairesListe.map(
(partenaire) => (
// si le le partenaire n'est pas deja ajoute
!verifierPartenaireAjoute(partenaire) ?
// donne au user l'acces a une option pour selectionner le participant
<option key={partenaire.id} value={partenaire.id}>{partenaire.nom}</option>
:
null
)
)
}
</select>
</div>
:
null
}
<p>Partenaires ajoutés :</p>
{
<div className="affichagePartenaires">
{
projet.participants.length > 0 ?
projet.participants.map(
(participant)=> (
<div className="boutonForm" key={participant.id}>
<div>{participant.nom}</div>
<button onClick={ () => (retirerParticipantAjoute(participant))}><i className="material-icons">close</i></button>
</div>
)
)
:
null
}
</div>
}
{
// si le user est lie a des clients dans la db
clients != [] ?
<div className="choixClient">
<div>Client :</div>
<select onChange={ (e) => (setCurrentClient(e.target.value))} value={currentClient}>
<option value="">Aucun client</option>
{
clients.map(
(client) => (
<option key={client.nom} value={client.id}>{client.nom}</option>
)
)
}
</select>
</div>
:
null
}
</div>
<div className="footerForm">
<div className="btnAjouter">
<button onClick={addProjet} type="submit">Créer</button>
</div>
</div>
</form>
</div>
);
}
export default ProjetsCreate;
Composant d’affichage de notifications à partir d’un contexte.
import "./Notifications.scss";
import { useNotifs } from "../../context/notificationsContext";
import { useEffect, useState } from "react";
import { collection, onSnapshot, query, where } from "firebase/firestore";
import { db } from "../../config/firebase";
const Notifications = ({user}) => {
const {texteNotif, closeNotif, closeAjoutProjetNotif, notifEstErreur} = useNotifs();
const [ajoutProjetNotif, setAjoutProjetNotif] = useState([]);
const [notifIsLoading, setNotifsIsLoading] = useState(true);
useEffect(() => {
const q = query(collection(db, "notifs"), where("user", "==", user.id), where("eteVu", "==", "false"));
const unsub = onSnapshot(q,
(querySnapshot) => (
setAjoutProjetNotif(
querySnapshot.docs.map(
(doc) => {
return {
...doc.data(),
id : doc.id
}
}
)
)
)
)
setNotifsIsLoading(false);
},[])
if(!notifIsLoading){
// Affiche les notifs d'ajout a un projet s'il y a une ref
if(ajoutProjetNotif.length > 0){
return(
<div className="notifContainer animate__animated animate__fadeInDown">
<div className="notifBody">
<div className="notifHeader">
<div className="notifTriangle">O</div>
<h3>Notifications</h3>
<button href="#" onClick={ () => (closeAjoutProjetNotif(ajoutProjetNotif))}><i className="material-icons">highlight_off</i></button>
</div>
<div className="notifContent">
{/* <p className="notifTime">00:00</p> */}
<p>{`Vous avez été ajouté au projet${ajoutProjetNotif.length > 1 ? "s" : ""} suivant${ajoutProjetNotif.length > 1 ? "s" : ""} :`}</p>
<ul>
{
ajoutProjetNotif.map(
(projetNotif) => (
<li key={projetNotif.titreProjet}>{projetNotif.titreProjet}</li>
)
)
}
</ul>
</div>
</div>
</div>
);
}
// sinon affiche les notifs en runtim de feedback
else if(texteNotif !== "") {
// si la notif n'est pas de type d'erreur
if(!notifEstErreur){
return(
<div className="notifContainer animate__animated animate__fadeInDown">
<div className="notifBody">
<div className="notifHeader">
<div className="notifTriangle">O</div>
<h3>Notifications</h3>
<button href="#" onClick={closeNotif}><i className="material-icons">highlight_off</i></button>
</div>
<div className="notifContent">
{/* <p className="notifTime">00:00</p> */}
<p>{texteNotif}</p>
</div>
</div>
</div>
);
}
// si la notification est de type erreur
else{
return(
<div className="notifContainer animate__animated animate__fadeInDown">
<div className="notifBody">
<div className="notifHeader">
<div className="notifTriangle">O</div>
<h3 style={{color: "red"}}>Notifications</h3>
<button href="#" onClick={closeNotif}><i className="material-icons">highlight_off</i></button>
</div>
<div className="notifContent">
{/* <p className="notifTime">00:00</p> */}
<p>{texteNotif}</p>
</div>
</div>
</div>
);
}
}
else{
return null;
}
}
else{
return null;
}
}
export default Notifications;