Tutoriel Next.js et Firebase – Comment construire un clone d’Evernote

Next.js est un cadre de rendu côté serveur basé sur React, qui est optimisé pour les moteurs de recherche.

Construisons donc un clone d’Evernote en utilisant Next.js pour apprendre comment il fonctionne.

Nous allons utiliser la pile technologique suivante :

  1. Next.js pour l’interface utilisateur
  2. Firebase pour la base de données et l’hébergement de notre application
  3. SASS pour les feuilles de style

Alors, commençons.

Comment créer une application Next

Tout comme la commande que nous utilisons pour créer une application React, nous avons également une commande pour créer rapidement une application Next. Cela ressemble à ceci :

npx create-next-app@latest
# ou
yarn create next-app

Si vous utilisez npm, utilisez npx create-next-app@latest. Ou bien, si vous utilisez le gestionnaire de paquets Yarn, utilisez yarn create next-app.

Mais d’abord, vous devez avoir Node.js installé sur votre système. Allez sur https://nodejs.org/en/download/ pour télécharger et installer Node.

Screenshot-2022-01-30-185459

Donnez un nom au projet, qui est evernote-clone dans notre cas.

Après que le projet ait fini de se créer, nous trouverons une structure de fichiers semblable à celle que nous voyons dans React.

Screenshot-2022-01-30-185727

Démarrons l’application maintenant. Tapez simplement npm run dev, et voici ce que vous verrez dans votre terminal :

Screenshot-2022-01-30-185921

Et tout comme React, Next est livré avec du code standard.

Screenshot-2022-01-30-190055

Supprimons tout ce code et commençons par le tout début.

Ouvrez index.js dans le dossier pages, et vous verrez tout ce code :

import Head de 'next/head
import Image de 'next/image
importation de styles de '../styles/Home.module.css'

export default function Home() {
  return (
) } 

Effacez-le pour pouvoir repartir de zéro. Voici ce que vous devriez avoir maintenant :

importe Head de 'next/head'
importe les styles de '../styles/Home.module.css'

export default function Home() {
  return (


  )
}

Ce code nettoyé contient les balises Title et les balises Main, où nous pouvons écrire notre code.

importe Head de 'next/head'
importe les styles de '../styles/Home.module.css'

export default function Home() {
  return (


  )
}

Tous nos styles se trouvent dans Home.module.css, et c’est ainsi que nous créons une feuille de style.

Comment installer SASS, Firebase et React Quill ?

Installons maintenant SASS et Firebase.

npm i firebase sass react-quill

Utilisez la commande ci-dessus qui les installera tous en une seule fois.

Laissez-moi vous expliquer comment nous allons utiliser chacun de ces outils :

  1. Firebase – Pour stocker nos données de notes dans le backend
  2. SASS – Nous utilisons SASS au lieu de CSS, car il fournit beaucoup de fonctionnalités différentes que nous n’avons pas en CSS.
  3. React Quill – Un éditeur de zone de texte riche pour les notes.

Maintenant que vous les avez installés, continuons.

Nous devons diviser notre écran en deux parties. La partie gauche contiendra l’option permettant de créer de nouvelles notes, tandis que la partie droite les affichera.

Créez un div à l’intérieur du main, qui contiendra deux autres div. Chaque div pointe vers sa classe respective dans la feuille de style.

Gauche
Droite

Maintenant, nous allons créer un fichier de feuille de style. Nommez-le Evernote.modules.scss.

Screenshot-2022-01-30-191605

Et c’est le fichier où nous allons faire notre style.

Arrangeons maintenant notre conteneur comme flex.

.container {
    display : flex ;
    margin : 10px ;
}

.left{
    largeur : 20rem ;
}

Nous avons un affichage de flex dans le conteneur, et une largeur de 20 rem pour le conteneur gauche. Cela donne le résultat suivant :

Screenshot-2022-01-30-192230

Maintenant, créez un dossier dans les pages appelé components. Il contiendra tous nos micro-composants.

Et dans le dossier components, créez un fichier appelé NoteOperations.js.

Ensuite, importez ce composant dans le fichier principal index.js, et renvoyez-le dans le fichier principal.

import NoteOperations de './components/NoteOperations' ;

Droite

Mais vous verrez tout de suite une erreur, parce que nous n’avons rien dans le composant NoteOperations.

Screenshot-2022-01-30-192735

Créons un composant fonctionnel NoteOperation.js.

export default function NoteOperations() {
    return (
        <>
        
    )
}

Pour l’instant, il renvoie un fragment vide. Donc, créons un bouton pour ajouter de nouvelles notes.

importez styles de "../../styles/Evernote.module.scss"

export default function NoteOperations() {
    return (
        <>


        
    )
}
Screenshot-2022-01-30-193707

Ce sera notre sortie pour l’instant. Concevons notre bouton pour qu’il soit un peu plus joli.

.button {
    width : 15rem ;
    hauteur : 2rem ;
    curseur : pointeur ;
    couleur de fond : noir ;
    couleur : whitesmoke ;
    border : black ;
}

Ces styles nous permettront d’obtenir le bouton suivant :

Screenshot-2022-01-30-194323

Importons la police Roboto de Google Fonts pour l’utiliser dans nos notes.

@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap') ;

Mettez-le en haut du fichier de la feuille de style afin d’utiliser la police, comme ceci :

.button {
    largeur : 15rem ;
    hauteur : 2rem ;
    curseur : pointeur ;
    background-color : black ;
    couleur : whitesmoke ;
    bordure : noir ;
    font-family : 'Roboto' ;
}

Et maintenant vous verrez le changement de la police du bouton.

Maintenant, ajoutons la fonction du bouton. Lorsque nous cliquons sur le bouton Ajouter une nouvelle note, une entrée de texte doit apparaître en bas.

Tout d’abord, créons ce champ de texte :

importe les styles de '../../styles/Evernote.module.scss'

export default function NoteOperations() {
    return (
        <>


        
    )
}

Ajoutons un peu de style à cet élément d’entrée :

.input{
    largeur : 15rem ;
    hauteur : 2rem ;
    outline : none ;
    border-radius : 5px ;
    border : 1px solid gray ;
    margin : 5px 0 ;
}

Voici à quoi ressemble notre entrée maintenant :

Screenshot-2022-01-30-195052

Mais ce bouton ne doit apparaître que lorsque nous cliquons sur le bouton Ajouter une nouvelle note. Nous devons donc utiliser React State pour cela.

import { useState } from 'react' (en anglais)

const [isInputVisible, setInputVisible] = useState(false) ;

Nous importons donc le hook useState de React et nous avons un état de isInputVisible.

Nous avons également besoin d’une fonction qui sera déclenchée lorsque nous cliquerons sur le bouton.

importez styles de '../../styles/Evernote.module.scss'
import { useState } from 'react' (en anglais)
export default function NoteOperations() {
    const [isInputVisible, setInputVisible] = useState(false) ;
    const inputToggle = () => {
        setInputVisible(!isInputVisible)
    }
    return (
        <>


        
    )
}

Ainsi, lorsque nous cliquons sur le bouton Ajouter une nouvelle note, l’état IsInputVisible bascule entre vrai et faux. Et en fonction de cette condition, nous devons afficher notre élément d’entrée.

{isInputVisible ? (


            ) : (
                <>
            )}

Nous utilisons donc un opérateur ternaire pour vérifier. Si l’état IsInputVisible est vrai, le champ de saisie sera affiché, sinon il sera masqué.

Voir aussi :  Comment créer des formulaires dynamiques en React

Voici l’ensemble du code jusqu’à ce point :

import styles de '../../styles/Evernote.module.scss'
import { useState } from 'react' (en anglais)
export default function NoteOperations() {
    const [isInputVisible, setInputVisible] = useState(false) ;
    const inputToggle = () => {
        setInputVisible(!isInputVisible)
    }
    return (
        <>



            {isInputVisible ? (


            ) : (
                <>
            )}
        
    )
}

Maintenant, nous avons besoin de récupérer les données du champ de saisie. Donc, nous avons besoin d’un état supplémentaire.

Créons un état et lions la fonction setState au champ de saisie en utilisant l’événement onChange. Cela signifie qu’à chaque fois que notre entrée change, ou lorsque nous tapons, la valeur de l’état sera mise à jour.

const [noteTitle, setNoteTitle] = useState('') ;
setNoteTitle(e.target.value)} />

Comment envoyer les données à Firebase

Maintenant, envoyons nos données au Firebase Firestore.

Allez sur https://firebase.google.com/ et créez un nouveau projet.

Screenshot-2022-01-30-200136

Il retournera toutes les données de configuration que nous devons ajouter à notre Next App.

Si vous voulez apprendre comment tout cela fonctionne, j’ai une liste de lecture complète pour cela sur YouTube. Assurez-vous de la regarder ici.

Screenshot-2022-01-30-200350

Donc, après avoir créé un projet, nous devons créer une application. Et après avoir créé une application, elle nous renverra des données de configuration.

// Importez les fonctions dont vous avez besoin depuis les SDK dont vous avez besoin
import { initializeApp } de "firebase/app" ;
// TODO : Ajoutez les SDKs des produits Firebase que vous voulez utiliser
// https://firebase.google.com/docs/web/setup#available-libraries

// La configuration Firebase de votre application web
const firebaseConfig = {
  apiKey : "AIzaSyAaLhtQ-B698GWyLNihGVRaNWBOKtBH8wU",
  authDomain : "evernoteclone-7682f.firebaseapp.com",
  projectId : "evernoteclone-7682f",
  storageBucket : "evernoteclone-7682f.appspot.com",
  messagingSenderId : "332984082327",
  appId : "1:332984082327:web:ae2776c3a56f4d98816ed2"
} ;

// Initialisation de Firebase
const app = initializeApp(firebaseConfig) ;

Créer un nouveau fichier appelé firebaseConfig.js dans notre Next App et les ajouter là. Le fichier ressemblera à quelque chose comme ceci :

Screenshot-2022-01-30-200803

Puisque nous allons utiliser la base de données Firestore, nous devons également importer les fonctions Firestore.

Screenshot-2022-01-30-201008

Nous devons également les exporter. Nous pouvons maintenant utiliser la base de données Firestore dans notre application.

Comment ajouter nos notes à Firestore

Maintenant, ajoutons nos notes à la base de données Firestore.

Dans le fichier NoteOperations.js, importez le fichier de configuration de firebase.

import { app, database } from '../../firebaseConfig' ;

Nous avons également besoin de quelques fonctions de Firebase Firestore, alors importons-les.

import { collection, addDoc } de 'firebase/firestore' ;

Ici, nous utiliserons collection pour créer une collection, et addDoc pour ajouter nos données à cette collection.

Commençons par créer une collection. Nous allons nommer cette collection dbInstance.

const dbInstance = collection(database, 'notes') ;

Elle prend la base de données de l’import firebaseConfig et le nom de la collection.

Créons un bouton pour sauvegarder les notes dans la base de données Firestore.

Et maintenant nous allons ajouter les styles de bouton de sauvegarde des notes.

.saveBtn{
    largeur : 15rem ;
    hauteur : 2rem ;
    curseur : pointeur ;
    couleur de fond : rgb(119, 27, 27) ;
    couleur : whitesmoke ;
    bordure : rgb(119, 27, 27) ;
    font-family : 'Roboto' ;
}

Mais attendez – puisque nous utilisons SASS, nous pouvons définir des variables pour nos couleurs.

$rouge foncé : rgb(119, 27, 27) ;
$black : noir ;
$whiteSmoke : whiteSmoke ;

Maintenant, nous pouvons utiliser ces couleurs n’importe où.

@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap") ;

$dark-red : rgb(119, 27, 27) ;
$black : noir ;
$whiteSmoke : whiteSmoke ;
$gray : gris ;

.container {
    display : flex ;
}

.left {
    largeur : 20rem ;
}

.button {
    largeur : 15rem ;
    hauteur : 2rem ;
    curseur : pointeur ;
    couleur de fond : $black ;
    couleur : $whiteSmoke ;
    border : $noir ;
    font-family : "Roboto" ;
}

.input {
    width : 15rem ;
    hauteur : 2rem ;
    outline : none ;
    border-radius : 5px ;
    border : 1px solid $gray ;
    margin : 5px 0 ;
}

.saveBtn {
    width : 15rem ;
    hauteur : 2rem ;
    curseur : pointeur ;
    background-color : $dark-red ;
    couleur : $whiteSmoke ;
    border : $dark-red ;
    font-family : "Roboto" ;
}

Et voici à quoi ressemble notre sortie maintenant.

Screenshot-2022-01-30-214046

Créons une fonction qui enregistrera la note sur Firebase, et cette fonction s’exécutera lorsque nous cliquerons sur le bouton Enregistrer la note.

const saveNote = () => {

}

Et dans le bouton Save Note, ajoutez le code suivant :

Maintenant, dans la fonction saveNote, nous allons utiliser la fonction addDoc.

const saveNote = () => {
        addDoc(dbInstance, {
            noteTitle : noteTitle
        })
    }

Cette fonction addDoc prend deux paramètres. Le premier est la dbInstance, que nous avons créée précédemment. Le second est la donnée que nous voulons envoyer. Ajoutez-les entre crochets.

Maintenant, testons ceci en créant une nouvelle note.

Screenshot-2022-01-30-214834

Donc, ajoutez une nouvelle note qui est la Note 1. Et nous allons la voir dans notre Firebase Firestore.

Screenshot-2022-01-30-214915

Comment créer le corps de la note

Créons maintenant le corps de la note. Et pour cela, nous allons utiliser React Quill que nous avons installé précédemment.

importez ReactQuill de 'react-quill' ;
importez 'react-quill/dist/quill.snow.css' ;

Importez-les en haut de votre composant.

Puis, renvoyez-le après le champ de saisie.


J’ai aussi ajouté quelques styles pour React Quill.

.ReactQuill{
    largeur : 15rem ;
}
Screenshot-2022-01-30-215508

Et voici notre résultat maintenant.

Récupérons les valeurs de l’éditeur React Quill. Nous avons besoin d’une fonction pour cela, et d’un état.

const [noteDesc, setNoteDesc] = useState('')

const addDesc = (valeur) => {
  setNoteDesc(valeur)
}

Ajoutez cette fonction addDesc à notre éditeur React Quill comme un événement onChange.

Ainsi, chaque fois que nous tapons quelque chose dans notre éditeur, il sera enregistré dans l’état noteDesc.

Maintenant, tout comme nous avons envoyé le titre de la note dans la fonction addDoc, nous devons envoyer ceci aussi.

const saveNote = () => {
        addDoc(dbInstance, {
            noteTitle : noteTitle,
            noteDesc : noteDesc
        })
    }

Testons cela maintenant.

Ajoutez un titre et une description, puis cliquez sur Enregistrer la note.

Screenshot-2022-01-30-220032
Screenshot-2022-01-30-220118

Vous verrez que nous avons un nouveau document avec un titre et une description.

Mais le problème ici est que lorsque nous ajoutons une nouvelle note, les données précédentes sont toujours présentes dans le champ de texte et dans l’éditeur React Quill. Nous devons les effacer lorsque nous cliquons sur Save Note.

Voir aussi :  Comment créer un jeu de serpent avec React, Redux et Redux Saga ?

Donc, effacez les états lorsque nous cliquons sur le bouton Save Note. Il suffit de les rendre vides.

const saveNote = () => {
        addDoc(dbInstance, {
            noteTitle : noteTitle,
            noteDesc : noteDesc
        })
            .then(() => {
                setNoteTitle('')
                setNoteDesc('')
            })
    }

Ajoutez également les états à leurs entrées respectives en utilisant la valeur.

 setNoteTitle(e.target.value)}
                        valeur={noteTitle}
                    />

Voici l’ensemble du code jusqu’à ce point :

importez styles de '../../styles/Evernote.module.scss'
import { useState } de 'react' ;
import { app, database } from '../../firebaseConfig' ;
import { collection, addDoc } de 'firebase/firestore' ;
import ReactQuill de 'react-quill' ;
importez 'react-quill/dist/quill.snow.css' ;

const dbInstance = collection(database, 'notes') ;
export default function NoteOperations() {
    const [isInputVisible, setInputVisible] = useState(false) ;
    const [noteTitle, setNoteTitle] = useState('') ;
    const [noteDesc, setNoteDesc] = useState('')
    const inputToggle = () => {
        setInputVisible(!isInputVisible)
    }

    const addDesc = (valeur) => {
        setNoteDesc(valeur)
    }

    const saveNote = () => {
        addDoc(dbInstance, {
            noteTitle : noteTitle,
            noteDesc : noteDesc
        })
            .then(() => {
                setNoteTitle('')
                setNoteDesc('')
            })
    }
    return (
        <>



            {isInputVisible ? (
setNoteTitle(e.target.value)} valeur={noteTitle} />



            ) : (
                <>
            )}
        
    )
}

Et les styles :

@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap") ;

$dark-red : rgb(119, 27, 27) ;
$black : noir ;
$whiteSmoke : whiteSmoke ;
$gray : gris ;

.container {
    display : flex ;
}

.left {
    largeur : 20rem ;
}

.button {
    largeur : 15rem ;
    hauteur : 2rem ;
    curseur : pointeur ;
    couleur de fond : $black ;
    couleur : $whiteSmoke ;
    border : $noir ;
    font-family : "Roboto" ;
}

.input {
    width : 15rem ;
    hauteur : 2rem ;
    outline : none ;
    border-radius : 5px ;
    border : 1px solid $gray ;
    margin : 5px 0 ;
}

.saveBtn {
    width : 15rem ;
    hauteur : 2rem ;
    curseur : pointeur ;
    background-color : $dark-red ;
    couleur : $whiteSmoke ;
    border : $dark-red ;
    font-family : "Roboto" ;
}

.ReactQuill{
    largeur : 15rem ;
}

Comment lire les données de Firestore

Maintenant, récupérons les notes que nous enregistrons dans Firestore. Pour cela, nous avons besoin de la fonction getDocs, qui est similaire à la fonction addDoc.

Importez-les de Firestore :

import { collection, addDoc, getDocs } de 'firebase/firestore' ;

Ensuite, créez une fonction appelée getNotes.

const getNotes = () => {
        getDocs(dbInstance)
            .then((data) => {
                console.log(données) ;
            })
    }

La fonction getDocs prend dbInstance comme paramètre, et retourne les données de la collection.

Mais nous devons faire une chose de plus. Nous avons besoin d’un Hook useEffect qui va exécuter cette fonction à chaque fois que notre page se charge. Donc, importons-le et ajoutons-le.

import { useState, useEffect } de 'react' ;

useEffect(() => {
    getNotes() ;
}, [])

Si nous vérifions notre console, nous obtiendrons ce qui suit :

Screenshot-2022-01-30-221127

Les données que nous avons obtenues sont illisibles. Nous devons donc les filtrer pour obtenir les éléments qui sont réellement utiles.

const getNotes = () => {
        getDocs(dbInstance)
            .then((data) => {
                console.log(données.docs.map((item) => {
                    return { ...item.data(), id : item.id }
                })) ;
            })
    }

Nous mappons les documents dans nos données, qui renvoient un élément. Ensuite, nous retournons les données dans l’élément, couplé avec l’id.

Cela donnera le résultat suivant :

Screenshot-2022-01-30-221407

Et c’est ce dont nous avons besoin. Stockons ces données dans un tableau d’état.

 const [notesArray, setNotesArray] = useState([]) ;
 
 const getNotes = () => {
        getDocs(dbInstance)
            .then((data) => {
                setNotesArray(data.docs.map((item) => {
                    return { ...item.data(), id : item.id }
                })) ;
            })
    }

Maintenant, nous devons mapper ce notesArray pour voir nos données dans l’interface utilisateur.

{notesArray.map((note) => { return (

{note.noteTitle}

{note.noteDesc} ) })}


La fonction Array.map va cibler chaque élément du tableau et retourner son contenu.

Screenshot-2022-01-30-221852

Maintenant, donnons un peu de style à la façon dont nous affichons nos notes.

{notesArray.map((note) => { return (

{note.noteTitle}

{note.noteDesc} ) })}


J’ai ajouté un className aux divs, ainsi qu’un peu de style.

.notesInner{
    margin-top : 0.5rem ;
    border : 1px solid $dark-red ;
    border-radius : 10px ;
    largeur : 15rem ;
    text-align : center ;
    curseur : pointeur ;
    font-family : "Roboto" ;
}

.notesInner:hover{
    background-color : rgb(119, 27, 27) ;
    couleur : $whiteSmoke ;
}
Screenshot-2022-01-30-222429

Voici à quoi ressemble notre résultat maintenant :

Screenshot--836-

Il y a aussi un effet de survol. Ainsi, si nous survolons un élément particulier, sa couleur de fond change.

Maintenant, lorsque nous ajoutons une note, nous devons appeler la fonction getNotes. Cela permettra de s’assurer que nos nouvelles notes sont automatiquement rafraîchies. Ajoutez donc la fonction getNotes dans la fonction addDoc.

const saveNote = () => {
        addDoc(dbInstance, {
            noteTitle : noteTitle,
            noteDesc : noteDesc
        })
            .then(() => {
                setNoteTitle('')
                setNoteDesc('')
                getNotes() ;
            })
    }

Mais dans notre sortie, nous obtenons la description des notes avec des balises de paragraphe. C’est parce que React Quill envoie le style des balises, comme les balises d’en-tête, les balises de liste, et ainsi de suite. Si nous créons une liste en utilisant React Quill, il enverra les données dans des balises de liste.

Screenshot-2022-01-30-223117

Si nous sauvegardons cette note, nous obtiendrons ce qui suit

    1. et
  1. car nous avons ajouté une liste dans l’éditeur.
    Screenshot-2022-01-30-223206

    Maintenant, corrigeons ce format de sortie.

    Nous allons utiliser dangerouslySetInnerHTML pour rendre la sortie avec des balises.

    
    

    Et maintenant, notre sortie a été corrigée.

    Screenshot-2022-01-30-223440

    Afficher une note particulière dans la zone de droite.

    Maintenant, nous avons besoin d’afficher une note particulière dans le conteneur de droite lorsque nous cliquons sur cette note.

    Donc, supprimez le noteDesc du conteneur de gauche. Nous avons seulement besoin d’afficher le titre sur la gauche.

    Maintenant, nous avons besoin d’une fonction l’ID d’une note particulière lorsque nous cliquons sur cette note. Donc, créons la fonction.

    {note.noteTitle}

    Mais, nous avons besoin de la fonction dans notre fichier index.js principal, et nous la passerons comme props dans le composant NoteOperations.

    const getSingleNote = () => {
    
    }

    Et passons-la comme props dans le composant NoteOperations.

    Recevons-le dans le corps de la fonction du composant NoteOperations.

    export default function NoteOperations({getSingleNote}){
    	//Le reste du code ici...
    }

    Nous devons appeler cette fonction lorsque nous cliquons sur une note du côté gauche. Nous passons également l’ID de la note particulière lorsque nous cliquons dessus.

    getSingleNote(note.id)}>

    {note.noteTitle}

    Dans la fonction getSingleNote, dans notre fichier principal index.js, consoles.log notre id pour voir si ça marche ou pas.

    const getSingleNote = (id) => {
      console.log(id)
    }

    Cliquez sur le champ, nous devrions obtenir son ID dans la console.

    Screenshot-2022-01-30-224717

    Vous voyez, nous y arrivons.

    Comment afficher les notes en fonction de l’ID

    Maintenant, créons un autre composant qui sera rendu dans le bon conteneur. Nommez-le NoteDetails.js.

    export default function NoteDetails() {
        return (
            <>
        )
    }

    Et renvoyer ce composant dans le div conteneur droit.

    import NoteDetails de './components/NoteDetails' ;
    
    

    Nous devons passer cet ID à ce composant, mais d’abord nous devons le stocker dans un état.

    const [ID, setID] = useState(null) ;
    
    const getSingleNote = (id) => {
       setID(id)
    }

    Ensuite, passez-le dans le composant NoteDetails en tant que props.

    Nous devons importer la base de données et l’application du fichier firebaseConfig dans le composant NoteDetails. Importez également les paquets React Quill.

    import {app, database } from '../../firebaseConfig' (en anglais)
    import ReactQuill de 'react-quill' ;
    importez 'react-quill/dist/quill.snow.css' ;
    export default function NoteDetails() {
        return (
            <>
        )
    }

    Nous devons recevoir l’ID dans le corps de la fonction et le détruire.

    export default function NoteDetails({ID})

    Maintenant que nous avons l’ID, nous devons cibler cette note spécifique.

    Nous devons préciser quelle note afficher, en fonction de cet ID. Pour cela, nous avons besoin de doc et getDoc de Firebase Firestore. Importez également le hook useEffect.

    import { useEffect } from 'react' (en anglais)
    import { app, database } from '../../firebaseConfig' ;
    import { doc, getDoc } de 'firebase/firestore'
    import ReactQuill de 'react-quill' ;
    import 'react-quill/dist/quill.snow.css' ;

    Créons une fonction pour obtenir une seule note.

    const getSingleNote = () => {
            if (ID) {
                const singleNote = doc(database, 'notes', ID)
                const data = getDoc(singleNote)
                console.log({ ...données.données(), id : données.id })
            }
        }

    Nous ciblons cette note en utilisant la fonction doc, puis nous stockons les données dans une variable data, en utilisant getDoc. Nous créons également un contrôle. Le contenu de cette fonction ne sera exécuté que si nous avons l’ID.

    Placez cette fonction dans le Hook useEffect. Ajoutez également l’ID dans le tableau des dépendances. Cela signifie qu’à chaque fois que notre ID change, ce hook useEffect sera exécuté. Et il rafraîchira les données.

    useEffect(() => {
      getSingleNote() ;
    }, [ID])
    Screenshot-2022-01-30-235528

    Mais si nous cliquons sur une note, nous recevons une promesse. Donc, nous devons utiliser Async Await pour gérer cela.

    const getSingleNote = async () => {
            if (ID) {
                const singleNote = doc(database, 'notes', ID)
                const data = await getDoc(singleNote)
                console.log({ ...données.données(), id : données.id })
            }
        }

    Si nous cliquons maintenant sur une note, nous obtiendrons les données correctes.

    Screenshot-2022-01-31-000010

    Cette note est un objet. Nous devons donc créer un état d’objet.

    const [singleNote, setSingleNote] = useState({})

    Ensuite, définissez les données dans cet état.

    setSingleNote({ ...data.data(), id : data.id })

    Montrons maintenant nos notes dans l’interface utilisateur.

    return (
            <>

    {singleNote.noteTitle}

    
    
            
        )
    Screenshot-2022-01-31-000413

    Et voici notre résultat. Cliquez sur une note sur le côté gauche, elle sera affichée ici.

    Maintenant, si nous chargeons notre page, nous devons définir une note par défaut à afficher sur la droite. Nous devons donc récupérer toutes les notes dans le composant NoteDetails. Nous ajoutons le [0] pour obtenir le premier index du tableau.

    const getNotes = () => {
            getDocs(dbInstance)
                .then((data) => {
                    setSingleNote(data.docs.map((item) => {
                        return { ...item.data(), id : item.id }
                    })[0]) ;
                })
        }
    
        useEffect(() => {
            getNotes() ;
        }, [])

    Importez également tous les imports nécessaires dans le composant NoteDetails.

    Si nous rafraîchissons la page, nous obtiendrons la première Note sur notre droite.

    Screenshot-2022-01-31-001353

    Comment modifier et supprimer une note

    Ajoutons des fonctions pour modifier et supprimer une note. Nous avons donc besoin de deux boutons pour cela.

    Ajoutons un peu de style.

    
    
    .editBtn, .deleteBtn{
        largeur : 5rem ;
        hauteur : 2rem ;
        couleur de fond : rgb(119, 27, 27) ;
        couleur : $whiteSmoke ;
        border : none ;
        curseur : pointeur ;
        margin : 10px 10px 10px 0 ;
    }

    Et nous avons maintenant deux boutons, pour l’édition et la suppression.

    Screenshot-2022-01-31-003038

    Ajoutons la fonctionnalité d’édition. Puisque nous avons l’ID, nous pouvons l’utiliser.

    Nous voulons deux entrées et un bouton, et ils seront visibles lorsque nous cliquerons sur le bouton d’édition.

    const [isEdit, setIsEdit] = useState(false) ;

    Nous avons besoin d’un état pour cacher et afficher les champs de saisie. Et aussi une fonction pour mettre cet état à true.

    const getEditData = () => {
      setIsEdit(true) ;
    }

    Si cet état est vrai, nous afficherons nos entrées et notre bouton. Mais d’abord, créons-les.

    {isEdit ? (

    ) : (
    <>
    )}
    Nous avons également une condition. Si isEdit est vrai, nous allons afficher les données dans les champs de saisie. Si elle est fausse, nous ne montrerons rien.

    Maintenant, définissons les valeurs.

    {isEdit ? (

    ) : (
    <>
    )}
    Mais si nous changeons le titre et le contenu de la note, ils ne changeront pas. Nous devons donc les définir dans un état.

    const [noteTitle, setNoteTitle] = useState('') ;
    const [noteDesc, setNoteDesc] = useState('') ;
    setNoteTitle(e.target.value)}
                            valeur={singleNote.noteTitle}
                        />
    
    

    Mais les valeurs ne changeront toujours pas car l’état de onChange et la valeur sont différents. Cela signifie que si nous définissons les données à l’aide de setNoteTitle ou setNoteDesc, les valeurs doivent correspondre à leurs états respectifs.


    setNoteTitle(e.target.value)}
    value={noteTitle}
    />


    Et nous pouvons définir l’état dans la fonction getEditData.

    const getEditData = () => {
            setIsEdit(true) ;
            setNoteTitle(singleNote.noteTitle) ;
            setNoteDesc(singleNote.noteDesc)
        }

    Maintenant, si nous cliquons sur edit, nous devrions obtenir nos données dans le champ de saisie et l’éditeur de texte.

    Screenshot-2022-01-31-005800

    Maintenant, utilisons la fonction updateDoc pour mettre à jour le champ sélectionné.

    import { 
        doc, 
        getDoc, 
        getDocs, 
        collection,
        updateDoc
    } de 'firebase/firestore'
    

    Importez updateDoc de Firestore.

    Créez une fonction pour mettre à jour le document lorsqu’il est cliqué.

    const editNote = (id) => {
            const collectionById = doc(database, 'notes', id)
    
            updateDoc(collectionById, {
                noteTitle : noteTitle,
                noteDesc : noteDesc,
            })
        }

    Nous devons passer cet id comme paramètre lorsque nous cliquons sur le bouton. Ajoutez cette fonction au bouton de mise à jour de la note.

    Modifiez le titre ou le corps de la note et celle-ci sera modifiée.

    Screenshot-2022-01-31-010422

    Mais nous devons également modifier les données de notre interface utilisateur. Nous allons donc utiliser une méthode appelée window.location.reload qui va recharger notre page.

    const editNote = (id) => {
            const collectionById = doc(database, 'notes', id)
    
            updateDoc(collectionById, {
                noteTitle : noteTitle,
                noteDesc : noteDesc,
            })
                .then(() => {
                    window.location.reload()
                })
        }

    Enfin, ajoutons notre fonction de suppression pour supprimer une note.

    Tout comme la fonction editNote, nous aurons une fonction deleteNote.

    const deleteNote = (id) => {
            const collectionById = doc(database, 'notes', id)
    
            deleteDoc(collectionById)
                .then(() => {
                    window.location.reload()
                })
        }

    Cette fonction dispose d’une collectionById pour cibler le document à supprimer, puis le supprime à l’aide de la fonction deleteDoc.

    Ajoutez cette fonction au bouton de suppression, et passez l’identifiant singleNote.id comme identifiant.

    Si nous cliquons maintenant sur le bouton de suppression, cette note ne sera plus là.

    Félicitations – vous avez créé un clone d’EverNote !

    Conclusion

    Donc, c’était tout sur la façon de construire un clone d’Evernote en utilisant NextJS et Firebase.

    Vous pouvez améliorer ce projet en créant de meilleurs designs UI et UX comme vous le souhaitez.

    Vous pouvez consulter ma vidéo sur le même sujet à Let’s Build an Evernote Clone using NEXT JS and Firebase, qui se trouve sur ma chaîne YouTube.

    Et vous pouvez trouver le code complet ici : https://github.com/nishant-666/Evernote-Next-Alt

    Merci de nous avoir lu !

    Bon apprentissage.