How to make Trello system clone whit React, Firebase, Redux.

In this tutorial there will be:

  • Create a project then entered it whit Redux
  • Create a card in the project then put lists

File structure

src 
  └──app
     └── components 
        ├── Home.js
        ├── InProject.js
        ├── ShowCards.js
  └──store
     ├── store.js
     ├── ProjectSlice.js

   ├── app(router).js

Packages

Install the packages below :

🤘 Redux 
    "@reduxjs/toolkit": "^1.6.2"
    "react-redux": "^7.2.6"

🔥 Firebase
    "firebase": "^9.5.0"
    "react-firebase-hooks": "^4.0.1"

⬅⬇➡ Router 
"react-router": "^5.2.1"
"react-router-dom": "^5.3.0"

Router

Create the following files in your src folder:

  • Home.js
  • InProject

Then put them in the router.

app(router).js
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import home from './Home'
import project from './InProject'
<Router>
         <Switch>
          <Route exact path="/" component={home} />
          <Route exact path="/project" component={project} />
        </Switch>
        </div>
</Router>

Create a project

Go to the Home.js file
We are going to create a new function which will be called {createProject}. With Firestore, we will create a new document in the 'project' collection.
In it, we will put two different fields, one for the creation date timestamp, and the other titleProject which will be the value of the input (defined by a Ref)

Home.js
const inputTitleProject = useRef(""); 

    const db = firebase.firestore();
    const createProject = useCallback(async event => {
        event.preventDefault();
        if (inputTitle.current.value !== "") {
            db.collection("project").add({
              timestamp: firebase.firestore.FieldValue.serverTimestamp(),
              titleProject: inputTitle.current.value,
            }); 
        }
    })

    return (
/* the onSubmit will execute the "createProject" function. */    
   <form onSubmit={createProject}>
    <input
    ref={inputTitleProject}
    placeholder="Your title project"
    >
    <button type="submit">
    Create the project !
    </button>
    </form>
    )

When you go to Firestore console.firebase.google.com it would look like this:

Display all project

With the useCollection function, we can choose any collection. For this case, we're going to use the 'project' collection. Then, we will make a docs.map, where we will put all the fields.

To be able to read the project, we will create a file named ShowProject.js, we will display the project inside.

Home.js
import { useCollection } from "react-firebase-hooks/firestore"
import ShowProject from './ShowProject.js'
    const db = firebase.firestore();
    const [listproject] = useCollection(
      db
      .collection("project")
      );  

return( 

/* Don't forget to keep the key and the id, it will be important for the future. */

       {projectlist?.docs.map((doc) => (

  <ShowProject
  key={doc.id}
  id={doc.id}
  titleProject={doc.data().titleProject}
  />
))}
)

We will import everything we put in the MessageShow, then we just have to use {title} so that the text of the field is displayed.

ShowProjects.js
function ShowProject({id, titleProject}) {

return (
<div>
<p>{titleProject}</p>
</div>
)

🐱‍🚀 Redux joinded the chat

Create a new Store folder. In it, you will create a file named Store.js. We will inserted a small-code

store.js
/* We import the configureStore from redux */
import { configureStore } from "@reduxjs/toolkit";
import projectSlice from "./ProjectSlice";
export const store = configureStore({
  reducer: {
    project: projectSlice,
  },
});

Then you create a new file ProjectSlice.js

ProjectSlice.js
import { createSlice } from "@reduxjs/toolkit";

/* We define the initial state */
const initialState = {
  projectId: null,
};

export const projectSlice = createSlice({
  name: "project",
  initialState,
  reducers: {
    setProject: (state, action) => {
      state.projectId = action.payload.projectId;
      state.projectName = action.payload.projectName;
    },
  },
});

export const { setProjectInfo } = projectSlice.actions;

export const selectProjectId = (state) => state.project.projectId;
export const selectProjectName = (state) => state.project.projectName;

export default projectSlice.reducer;

We modify our index.js

index.js
/* We import our redux tools */

import { Provider } from "react-redux"
import { store } from "./store/Store"

/* We add a provider */

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
    <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

Now, we come back to our ShowProject.js file

ShowProject.js
function ShowProject({id, title, name, photoURL}) {
 const setProject = () => {
        dispatch(
          setProjectInfo({
            projectId: id,
          })
        );

        history.push(`/project/{$id}`);
      };
return (

/* We modify our div, and when we click on it, it executes the 'setProject' function
We also define the cursor as a pointer
*/

<div onClick={setProject} style={{cursor: 'pointer'}}>
<p> {title} </p>
</div>
)

We now come back to our app (router).js

app(router).js
/* You just add these two little lines.
We can  put the id in the router. When it is on the url /project/{id}/, it will display the component 'InProject.js'
*/

import InProject from './InProject.js'
return ( 
          <Route exact path="/project/:id" component={InProject} />
)

In Project

Create Card

Go to the InProject.js file
The system will be almost the same as for the Home.js
We are going to create a new function which will be called {createCard}. With Firestore, we will create a new document in the collection project/{projectId}/card/
In it, we will put two different fields, one for the creation date timestamp, and the other titleCard which will be the value of the input (defined by a Ref)

InProject.js
import { useCollection } from "react-firebase-hooks/firestore"
import { selectProjectId } from  './store/ProjectSlice.js'
import { useSelector } from "react-redux";

    const inputTitleCard = useRef(""); 
    const db = firebase.firestore();
    const projectId  = useSelector(postId);
    const createCard = useCallback(async event => {
        event.preventDefault();
        if (inputTitle.current.value !== "") {
            db.collection("project").doc(projectId).collecton("card").add({
              timestamp: firebase.firestore.FieldValue.serverTimestamp(),
              titleProject: inputTitle.current.value,
            }); 
        }
    })

    return (
/* the onSubmit will execute the "createCard" function. */    
   <form onSubmit={createCard}>
    <input
    ref={inputTitleCard}
    placeholder="Title of your card"
    >
    <button type="submit">
    Create the Card !
    </button>
    </form>
    )

Read Card

It is almost identical to Home.js
With the useCollection function, we can choose any collection. For this case, we're going to use the project/{projectId}/card collection. Then, we will make a docs.map, where we will put all the fields.

InProject.js
import { useCollection } from "react-firebase-hooks/firestore"
    const db = firebase.firestore();
    const [listcard] = useCollection(
      db
      .collection("project")
      .doc(projectId)
      .collection("card")
      );  

return( 

         {frontmessagez?.docs.map((doc) => {
         const { titleCard} = doc.data()
       return (            
<>
<div>
   <p>  {titleCard} </p>
</div>
</>

  );
})}

CreateList & ReadList

The system is the same as for the Home.js & InProject.js

🥖 Et voilà !

You've finished your Trello system clone whit React, Firebase, Redux.
, now all you have to do is put css ✨?

Donations-Support

Bitcoin Ethereum
3FahtNWC4tmZh1B72vz44TvBN2jHaQSnh4 0x7cad12dfd11bce3f29b96260b4739caa32c89a86

19