Learn to Develop a LetGo Clone with React and Material UI

5/5 - (1 vote)

LetGo is one of the most popular marketplace apps for local buying and selling. In this article, we will learn how to build a full-fledged LetGo Clone using the React JavaScript library and Material UI framework.

The app we will build will have all the core features of LetGo like user authentication, listing products, searching and filtering listings, messaging between users, payment integration and more.

We’ll cover the full development process in a step-by-step manner with detailed code snippets at each step. By the end of this article, you’ll have a strong understanding of full-stack web development with MERN stack.

So without further ado, let’s get started!

Start Your Entrepreneurial Journey Today With Zipprr

1. Setting Up the Development Environment

The first step is to set up our development environment. We’ll be using:

  • Node.js and NPM for package management
  • React for building the frontend UI
  • Material UI for styled UI components
  • MongoDB and Mongoose ORM for the database

Create a folder and initialize an NPM project:

mkdir letgo-clone 
cd letgo-clone
npm init

Install required packages:

npm install react react-dom
npm install @material-ui/core
npm install express mongoose bcryptjs jsonwebtoken

Create client/ and server/ folders. In client/, create App.jsx and render a React component. In server/, create server.js and add Express server code.

Now our dev environment is ready!

2. Designing the UI and App Layout

In this step, we’ll design the UI using Material UI.

Import AppBarToolbarGrid etc from Material UI in App.jsx.

Create route components like HomeProducts etc and render routes in App.jsx:

<BrowserRouter>
  <AppBar>
    <Toolbar>
      <Button>Products</Button>  
    </Toolbar>
  </AppBar>
  
  <Routes>
    <Route path="/" element={<Home/>} />
    <Route path="/products" element={<Products/>} />
  </Routes>
</BrowserRouter>

Import ContainerCardCardMedia etc to build product cards:

<Grid container spacing={2}>
  <Grid item xs={3}>
    <Card>
      <CardMedia 
        image="/product.jpg"
      />
    </Card>
  </Grid>
</Grid>

Import styled components to design pages. Our basic UI is ready!

3. Building the Authentication System

Now let’s add authentication using MongoDB, Mongoose and JWT.

First, define a User model and auth routes in server.js:

const userSchema = new Schema({
  name: String,
  email: String, 
  password: String
});

app.post('/register', async (req, res) => {
  // Hash password and create user
});

app.post('/login', async (req, res) => {
  // Validate user and return JWT
});

In client, create Login.jsx component with a login form:

const Login = () => {
  const [email, setEmail] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();

    try {
      const res = await axios.post('/login', {
        email,
        password
      });

      // Save token
    } catch (err) {
      console.error(err);
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input 
        name="email"
        value={email}
        onChange={e => setEmail(e.target.value)} 
      />

      <button type="submit">Login</button>
    </form>
  )
}

Similarly, build registration page. Now users can register and login!

4. Developing Listings Feature

Now let’s add the core listing feature to sell products.

First, define a Product model:

const productSchema = new Schema({
  name: String,
  price: Number,
  description: String,
  images: [String],
  userId: {type: Schema.Types.ObjectId, ref: 'User'} 
});

Create CRUD routes to add/get products.

In Products.jsx, import AvatarButton etc:

const Products = () => {

  const [products, setProducts] = useState([]);

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

  const fetchProducts = async () => {
    const res = await axios.get('/products');
    setProducts(res.data);
  }

  return (
    <Grid>
      {products.map(product => (
        <Card key={product._id}>  
          <CardMedia
            image={product.images[0]} 
          />
          
          <CardContent>
            <Typography>{product.name}</Typography>
          </CardContent>
        </Card>
      ))}
    </Grid>
  )
}

Now users can view listings! Let’s create an AddProduct.jsx form next.

5. Implementing Search & Filter

To search and filter listings, add a SearchBar component:

const SearchBar = ({setSearchTerm}) => {

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
  }

  return (
    <TextField 
      label="Search"
      onChange={handleChange}
    />
  )
}

Then filter products on frontend:

const Products = () => {

  const [searchTerm, setSearchTerm] = useState('');

  const handleSearch = (products) => {
    return products.filter(product => 
      product.name.toLowerCase().includes(searchTerm)
    )
  }

  return (
    <>
      <SearchBar setSearchTerm={setSearchTerm}/>

      {handleSearch(products).map(product => (
        // product cards  
      ))}
    </>
  )
}

Add location, category filters similarly. Search and filters work!

6. Building Chat Feature

Now let’s build real time chat between users using Socket.IO:

// server
const io = require('socket.io')(server);

io.on('connection', (socket) => {

  socket.on('newMessage', ({from, to, message}) => {
    // Broadcast message
  });

});

Create Message.jsx model and routes.

In Chat.jsx:

const [messages, setMessages] = useState([]); 
const [newMessage, setNewMessage] = useState('');

useEffect(() => {
  socket.on('newMessage', message => {
    setMessages([...messages, message]);
  });
}, [messages]);

const handleSubmit = async () => {
  socket.emit('newMessage', {
    from: user._id,
    to, 
    message: newMessage
  });

  setNewMessage('');
}

return (
  <div>
    {/* messages */}

    <input  
      value={newMessage}
      onChange={e => setNewMessage(e.target.value)} 
    />

    <button onClick={handleSubmit}>Send</button>
  </div>
)

Now chat in real time!

7. Integrating Payments

For payments, we’ll integrate with PayPal sandbox.

Create Order model to store order details:

const orderSchema = new Schema({
  product: {type: ObjectId, ref: 'Product'},
  userId: {type: ObjectId, ref: 'User'},
  price: Number,
  // etc
});

Configure PayPal credentials in server. Handle payment on frontend:

const handlePayment = async () => {

  // Call API to create order

  const response = await axios.post('/create-payment', {
    // order details  
  });

  // Redirect to PayPal checkout
}

return (
  <PayPalButtons 
    createOrder={(data, actions) => actions.order.create({
      // order details
    })}
    onApprove={() => handlePayment()} 
  />
)

On success, call API to capture payment. Now payments work!

8. Adding User Profile

Let’s build a profile page to view user details and listings.

Create Profile.jsx component to get user and listings:

// server.js

app.get('/me', auth, async (req, res) => {
  const user = await User.findById(req.user._id);
  res.json({ user });
});

We’ll make a request to this route from our profile component to populate the user data:

// Profile.jsx

const Profile = () => {

  const [user, setUser] = useState({});

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

  const fetchUser = async () => {
    const res = await axios.get('/me');
    setUser(res.data.user);
  }

  return (
    <div>
      <h2>{user.name}</h2>
    </div>
  )

}

Next, we’ll build out the edit profile form. We’ll keep the existing user data in state:

const [name, setName] = useState(user.name);
const [email, setEmail] = useState(user.email);

const handleSubmit = async (e) => {
  e.preventDefault();

  try {
    await axios.patch('/me', {
      name,
      email
    });
  } catch (err) {
    // handle error
  }
}

return (
  <form onSubmit={handleSubmit}>
    <input 
      value={name}
      onChange={(e) => setName(e.target.value)} 
    />

    <input
      value={email}  
      onChange={(e) => setEmail(e.target.value)}
    />

    <button type="submit">Update</button>
  </form>
)

This allows the user to view and edit their profile details.

9. Deploying to Production

To deploy our app, we’ll use Heroku for the backend and Vercel for the frontend.

First, modify server code for production:

  1. Add env variables for keys
  2. Use MongoDB Atlas instead of local db
  3. Add CORS middleware
  4. Use production middleware
if(process.env.NODE_ENV === 'production') {
  app.use(prodMidddleware);
}

Add build script to package.json for production build:

"scripts": {
  "start": "node index.js",
  "build": "cd client && npm run build"
}

Now deploy to Heroku:

heroku create
git push heroku main
heroku open

For frontend, deploy React app to Vercel:

vercel

That’s it! Our LetGo clone is now live on Heroku+Vercel.

Wrapping Up

In this article we learned how to develop a full-fledged LetGo clone application using React, Material UI and Node.js. The step-by-step guide covered setting up authentication, building product listings, implementing search and chat along with payments integration. Following this tutorial one can now develop a powerful classifieds marketplace of their own to facilitate local buying and selling within their community.

Interested to acquire Business? 😎

let me know about your queries.





     

    Prasad Venkatachalam

    Prasad Venkatachalam is a professional writer with over 10 years of expertise in web and mobile app development. With a solid background in the field, Prasad has accumulated a decade of experience, honing his skills and staying up-to-date with the latest trends and technologies. His extensive experience in software development allows him to navigate the intricacies of the process, ensuring efficient and high-quality solutions. Currently, Prasad is a valuable member of the Zipprr team, where he continues to contribute his 10 years of expertise to develop innovative on-demand solutions.