Here is my App.js has code for all the categories including the Home.js that has links to the categories
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Header from './components/layouts/Header'
import Footer from './components/layouts/Footer'
import Home from './components/Home'
import Ceiling from './components/Ceiling'
import Floor from './components/Floor'
import Walls from './components/Walls'
import ProjectDetails from './components/project/ProjectDetails'
import './App.css';
function App() {
return (
<Router>
<div className="App">
<Header />
<div className="container ">
<Route path="/" component={Home} exact/>
<Route path="/ceiling" component={Ceiling} exact/>
<Route path="/floor" component={Floor} exact/>
<Route path="/walls" component={Walls} exact/>
<Route path="/project/:id" component={ProjectDetails} exact/>
</div>
<Footer />
</div>
</Router>
);
}
export default App;
Here is the Home page with code that links to the categories
import React, { Fragment } from 'react'
//import React, { Fragment, useState, useEffect } from "react";
import { Link } from 'react-router-dom'
import MetaData from './layouts/MetaData'
const Home = () => {
return (
<Fragment>
<MetaData title={'See my projects'}/>
<h6 className='top-tag font-size-16 font-rale text-dark sticky2 bg-light py-3'>See my <strong>projects</strong> below...</h6>
<div className='page-container'>
<div className="page-list text-center">
<Link to={`./Ceiling`}><img src="./images/moodceiling.jpg" className="thumbnail image-resize2"/></Link>
<div className="flex-div">
<div className="page-info">
<Link to={`./Ceiling`} className="text-dark font-rubik font-size-16">Ceiling design (8)</Link>
</div>
</div>
</div>
<div className="page-list text-center">
<Link to={`./Walls`}><img src="./images/walls.jpg" className="thumbnail image-resize2"/></Link>
<div className="flex-div">
<div className="page-info">
<Link to={`./Walls`} className="text-dark font-rubik font-size-16">Wall finishes (25)</Link>
</div>
</div>
</div>
<div className="page-list text-center">
<Link to={`./Floor`}><img src="./images/epoxxy.jpeg" className="thumbnail image-resize2"/></Link>
<div className="flex-div">
<div className="page-info">
<Link to={`./Floor`} className="text-dark font-rubik font-size-16">Floor finishes (73)</Link>
</div>
</div>
</div>
</div>
</Fragment>
)
}
export default Home
My Ceiling.js page returns all projects from all categories on screen. I want it to render images of projects under ceiling category only. same to walls and floors
import React, { Fragment, useState, useEffect } from "react";
import Pagination from "react-js-pagination";
import MetaData from "./layouts/MetaData";
import Project from "./project/Project";
import Loader from "./layouts/Loader";
import { useDispatch, useSelector } from "react-redux";
import { useAlert } from "react-alert";
import { getProjects } from "../actions/projectActions";
const Ceiling = ({ match }) => {
const [currentPage, setCurrentPage] = useState(1);
const alert = useAlert();
const dispatch = useDispatch();
const { loading, projects, error, projectsCount, resPerPage } = useSelector(
(state) => state.projects
);
const keyword = match.params.keyword;
useEffect(() => {
if (error) {
return alert.error(error);
}
dispatch(getProjects( currentPage));
}, [dispatch, alert, error, currentPage]);
function setCurrentPageNo(pageNumber) {
setCurrentPage(pageNumber);
}
return (
<Fragment>
{loading ? (
<Loader />
) : (
<Fragment>
<MetaData title={"Ceilings"} />
<div className="sticky2 bg-light">
<h6 className="top-tag font-size-16 font-rale text-dark ">
See the projects on <strong>Ceilings</strong> below...
</h6>
</div>
<div className="page-container ">
{projects &&
projects.map((project) => (
<Project key={project._id} project={project} />
))}
</div>
{resPerPage <= projectsCount && (
<div className="d-flex justify-content-center mt-5">
<Pagination
activePage={currentPage}
itemsCountPerPage={resPerPage}
totalItemsCount={projectsCount}
onChange={setCurrentPageNo}
nextPageText={"Next"}
prevPageText={"Prev"}
firstPageText={"First"}
lastPageText={"Last"}
itemClass="page-item"
linkClass="page-link"
/>
</div>
)}
</Fragment>
)}
</Fragment>
);
};
export default Ceiling;
similarly my Walls.js page does the same, renders images of all projects on the frontend.
import React, { Fragment, useState, useEffect } from "react";
import Pagination from 'react-js-pagination'
import MetaData from "./layouts/MetaData";
import Project from "./project/Project";
import Loader from "./layouts/Loader";
import { useDispatch, useSelector } from "react-redux";
import { useAlert } from 'react-alert'
import { getProjects } from "../actions/projectActions";
const Walls = ({ match }) => {
const [currentPage, setCurrentPage] = useState(1)
const alert = useAlert();
const dispatch = useDispatch();
const { loading, projects, error, projectsCount, resPerPage } = useSelector(state => state.projects)
const keyword = match.params.keyword
useEffect(() => {
if(error) {
return alert.error(error)
}
dispatch(getProjects(keyword, currentPage));
}, [dispatch, alert, error, keyword, currentPage]);
function setCurrentPageNo(pageNumber) {
setCurrentPage(pageNumber)
}
return (
<Fragment>
{loading ? <Loader/> : (
<Fragment>
<MetaData title={"Walls"} />
<div className="sticky2 bg-light">
<h6 className="top-tag font-size-16 font-rale text-dark ">
See projects on <strong>Wall Finishes</strong> below...
</h6>
</div>
<div className="page-container ">
{projects && projects.map(project => (
<Project key={project._id} project={project}/>
))}
</div>
{resPerPage <= projectsCount && (
<div className="d-flex justify-content-center mt-5">
<Pagination
activePage={currentPage}
itemsCountPerPage={resPerPage}
totalItemsCount={projectsCount}
onChange={setCurrentPageNo}
nextPageText ={'Next'}
prevPageText ={'Prev'}
firstPageText ={'First'}
lastPageText ={'Last'}
itemClass='page-item'
linkClass="page-link"
/>
</div>
)}
</Fragment>
)}
</Fragment>
)
}
export default Walls
For convenience below is my model for projects
const mongoose = require('mongoose')
const projectSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter project name'],
trim: true,
maxLength: [200, 'image name cannot exceed 200 characters']
},
description: {
type: String,
required: [true, 'Please enter project description'],
},
images: [
{
public_id: {
type: String,
required: true,
},
url: {
type: String,
required: true,
},
}
],
category: {
type: String,
required: [true, 'Please select category for this project'],
enum: {
values: [
'Floor finishes',
'Ceiling design',
'Wall finishes',
],
message: 'Please select correct category for project'
}
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Project', projectSchema);
For the backend, this is my API that fetches projects from database
// Get all projects => /api/v1/projects?keyword=curtain
exports.getProjects = catchAsyncErrors ( async (req, res, next) => {
const resPerPage = 12;
const projectsCount = await Project.countDocuments();
const apiFeatures = new APIFeatures(Project.find(), req.query)
.search()
.filter()
.pagination(resPerPage)
const projects = await apiFeatures.query;
res.status(200).json({
success: true,
projectsCount,
resPerPage,
projects
})
})