DEV Community

Cover image for How to make Trello system clone whit React, Firebase, Redux.
DenSpec
DenSpec

Posted on • Updated on

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

Image description
Hi ! Today we will see How to make Trello system clone whit R-F-R

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

Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
    )

Enter fullscreen mode Exit fullscreen mode

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

Image description

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}
  />
))}
)
Enter fullscreen mode Exit fullscreen mode

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>
)
Enter fullscreen mode Exit fullscreen mode

🐱‍🚀 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,
  },
});
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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')
);
Enter fullscreen mode Exit fullscreen mode

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>
)

Enter fullscreen mode Exit fullscreen mode

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} />
)
Enter fullscreen mode Exit fullscreen mode

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>
    )

Enter fullscreen mode Exit fullscreen mode

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>
</>

  );
})}
Enter fullscreen mode Exit fullscreen mode

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

Github

Discussion (0)