31
loading...
This website collects cookies to deliver better user experience
mkdir Strapi-ReactApp && cd Strapi-ReactApp
*Strapi-ReactApp*
director, go ahead and create our Strapi backend with the command below:npx create-strapi-app strapi-server --quickstart
strapi
-server
directory in the *Strapi-ReactApp*
directory we created, with the files and configurations required for our backend.http://localhost:1337/admin
to open the admin page for our project. Fill in your details in the form Strapi provides and press the LET’S START button.Business
as the content-type display name and click the Continue button to proceed. A modal will pop up for you to choose the fields you want in the collection. fullname
, choose the short text type since we will save the user’s full name in this field. Click on the add another field button, and repeat the step for the role field, but this time, the field name should be called role
. The role field will enable differentiate our normal users from the admin users.email
, and it should be of short text type. password
, and it will be of short text type.businesses
and make it have a One-to-Many relationship with the Business content-type by selecting Business content-type in the select field at the right hand of the page.Comment
, and click the Continue button to proceed. We will be using the Text and Number field types in our comment content-type. The Text type for the comment **and **user field, then the Number type for the businessId
.cd ..
npx create-react-app strapi-client
create-react-app --version
strapi-client
, and delete the boilerplate code/files from the codebasecd strapi-client
npm install axios [email protected]
npm run start
local
h
ost:3000
to view the application.strapi-client/src
folder, create a components
directory. We will separate our authentication components from other components by creating an authentication
folder in the components
directory. Then, create Signup.jsx
file in the authentication
folder.import axios from "axios";
import { useState } from "react";
import { useHistory } from "react-router";
function SignUp(props) {
return (
<section>
<div>
<form action="" onSubmit={(e) => handleSubmit(e)}>
<input
type="text"
placeholder="Fullname"
onChange={(e) => setName(e.target.value)}
name="Name"
/>
<input
type="text"
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
name="Email"
/>
<input
type="password"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
name="Password"
/>
<button type="submit">Login</button>
</form>
</div>
</section>
);
}
export default SignUp;
Axios
, to enable sending API requests to the backend. Then we imported useState and useH
i
story
. The useState hook will enable us to handle our application states, while useHistory will enable us to redirect our users on successful login to our application.Signup.jsx
file, before the return keyword, add the code below:const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const history = useHistory()
const { setActiveUser, setLoggedIn } = props;
const handleSubmit = async (e) => {
e.preventDefault();
const reqBody = {
fullname: name,
email,
password,
};
const res = await axios.post(
"http://localhost:1337/users-details",
reqBody
);
if (res.statusText === "OK") {
setActiveUser(res.data);
setLoggedIn(true);
history.push('/')
}
};
activeUser
state and reset the isLoggedIn
state which we will be creating on our App component later in the section to true, to update our components that a user is logged in.Signin.jsx
file in the authentication folder we created, and add the following code:import axios from "axios";
import { useState } from "react";
import { useHistory } from "react-router";
import { Link } from "react-router-dom";
function SignIn(props) {
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const [errorMessage, setErrorMessage] = useState("");
const history = useHistory();
const { setActiveUser, setLoggedIn } = props;
const handleSubmit = async (e) => {
e.preventDefault();
const res = await axios.get(
`http://localhost:1337/users-details?email=${email}&password=${password}`
);
if (res.data.length === 0) {
setErrorMessage("Incorrect Email or password");
} else {
setActiveUser(res.data);
setLoggedIn(true);
history.push("/");
}
};
return (
<section>
<div>
<form action="" onSubmit={(e) => handleSubmit(e)}>
<input
type="text"
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
/>
{errorMessage && <p>{errorMessage},<Link to="/signup"> Signup </Link>instead</p>}
<button type="submit">Login</button>
</form>
</div>
</section>
);
}
export default SignIn;
handleSubmit
function to handle form submissions, but this time we're sending a Get request and passing the user's email and password as query parameters. If the user's email and password match any record in our Strapi User_details content-type collection, we add the user's data to the active user's state and reset the isLoggedIn state to true.Business
folder in our components folder for all our business-related components. Then we’ll create three components Business.jsx
BusinessList.jsx
, and BusinessDetails.jx
file in the Business folder.import BusinessList from "./BusinessList";
import { useState } from "react";
import Modal from "../Modal";
function Business(props) {
const { isLoggedIn, business } = props;
const [showModal, setShowModal] = useState(false);
return (
<section className="container">
<h4>Business Listings</h4>
<div className={"form"}>
{isLoggedIn && <button className={"btn-danger"} onClick={() => setShowModal(true)}>Add business</button>}
<input type="text" name="" id="" />
<button className={"btn-info"}>Search</button>
</div>
<div className={"row"}>
{business.map((data) => (
<BusinessList business={data} />
))}
</div>
</section>
);
}
export default Business;
import { Link } from "react-router-dom";
function BusinessList(props) {
const { business } = props;
return (
<section>
<div className={"row"}>
<div className={"card"}>
<div className={"col-md-12"}>
<h4>
<Link to={`/business/${business.id}`}>{business.name}</Link>
</h4>
</div>
<div className={"col-md-12"}>
<p>{business.slogan}</p>
</div>
<div className={"handles"}>
<button>City: {business.city}</button>
<button>Call:{business.phone}</button>
</div>
</div>
</div>
</section>
);
}
export default BusinessList;
Link
Component from react-router-dom, which we know allows linking our Components together. Then we also inherited the business state from our Business Component to have access to the business listings.Link
, and useParams
Hooks from react-router-dom. The useParams Hook will enable getting the business id from the URL params. Then we import useState, and useEffect hooks for state management. We get the business id from the URL parameters const { id } = useParams();
, so for each business, we will access their details from theirs ids.BusinessDetails
Component with the code below:import { Link, useParams } from "react-router-dom";
import { useState, useEffect } from "react";
import axios from "axios";
function BusinessDetails(props) {
const { id } = useParams();
const [comment, setComment] = useState();
const [comments, setComments] = useState();
const { business, activeUser, isLoggedIn } = props;
const businessDetail = business.filter((data) => data.id == id);
return (
<section className={"container"}>
<div className={"details"}>
<h4>{businessDetail[0]?.name}</h4>
<div className={"location"}>
<p>Call:{businessDetail[0]?.phone}</p>
<p>City: {businessDetail[0]?.city}</p>
<p>Street: {businessDetail[0]?.street}</p>
</div>
</div>
</section>
);
}
export default BusinessDetails;
comment
, and a comments
state, we will use the comment state to get the users to comment from the comment form, and the comments state will be we will use to save the user's comments on a particular business. BusinessDetails
Component, inside the <section>
jsx element.<div className={"comments"}>
{comments?.length > 0 ? (
<div>
{comments.map((comment) => (
<p>
<span>{comment.user}: </span>
{comment.comment}
</p>
))}
</div>
) : (
<p>No comments</p>
)}
<form action="" onSubmit={(e) => handleSumbit(e)}>
<textarea
name=""
id=""
cols="40"
rows="3"
onChange={(e) => setComment(e.target.value)}
></textarea>
<button className={"btn-info"}>
{isLoggedIn ? "Send" : <Link to="/signin">Send</Link>}
</button>
</form>
</div>
useEffect(() => {
async function fetchData() {
const response = await axios.get(
`http://localhost:1337/comments?businessId=${id}`
);
setComments(response.data);
}
fetchData();
}, []);
const handleSumbit = async (e) => {
e.preventDefault();
const reqBody = {
user: activeUser[0].fullname,
comment,
businessId: id,
};
const resComment = await axios.post(
"http://localhost:1337/comments",
reqBody
);
setComments([...comments, resComment.data]);
};
Axios
to send requests to our Strapi backend. Then we add a close button to hide the modal when clicked, and we create a Business form with the following field:import { useState } from "react";
import axios from "axios";
const Modal = (props) => {
return (
<div className="modal">
<div className="close" onClick={() => props.setShowModal(false)}>
X
</div>
<hr />
<form onSubmit={(e) => handleSubmit(e)}>
<label className="control"> Name: </label>
<input
className="control"
type="text"
onChange={(e) => setName(e.target.value)}
/>
<label className="control"> Slogan: </label>
<input
className="control"
type="text"
onChange={(e) => setSlogan(e.target.value)}
/>
<label className="control"> Phone: </label>
<input
className="control"
type="text"
onChange={(e) => setPhone(e.target.value)}
/>
<label className="control"> Street: </label>
<input
className="control"
type="text"
onChange={(e) => setStreet(e.target.value)}
/>
<label className="control"> Postal Code: </label>
<input
className="control"
type="text"
onChange={(e) => setCode(e.target.value)}
/>
<label className="control"> City: </label>
<input
type="text"
className="control"
onChange={(e) => setCity(e.target.value)}
/>
<button className="control-1">Submit</button>
</form>
</div>
);
};
export default Modal;
handleSubmit
function.handleSubmit
function, we will create a reqBody object where we will save all the user's input values, and send a Post request to our Strapi backend to save the records.const [name, setName] = useState();
const [slogan, setSlogan] = useState();
const [phone, setPhone] = useState();
const [city, setCity] = useState();
const [street, setStreet] = useState();
const [code, setCode] = useState();
const handleSubmit = async (e) => {
e.preventDefault();
const reqBody = {
name,
slogan,
phone,
city,
street,
postal_code: code,
isApproved: false,
};
await axios.post("http://localhost:1337/businesses", reqBody);
};
import React, { useEffect, useState } from "react";
import axios from "axios";
import Header from "./components/Header";
import Home from "./components/Home";
import Business from "./components/Business/Business";
import SignIn from "./components/Authentication/Signin";
import SignUp from "./components/Authentication/Signup";
import Profile from "./components/Profile";
import BusinessDetails from "./components/Business/BusinessDetails";
import { Switch, Route } from "react-router-dom";
function App() {
return (
<div className="App">
<Header isLoggedIn={isLoggedIn} setLoggedIn={setLoggedIn} setActiveUser={setActiveUser}/>
<Switch>
<Route path="/" component={Home} exact />
<Route path="/business" exact>
<Business isLoggedIn={isLoggedIn} business={business} />
</Route>
<Route path="/business/:id">
<BusinessDetails business={business} activeUser={activeUser} isLoggedIn={isLoggedIn}/>
</Route>
<Route path="/signin">
<SignIn setActiveUser={setActiveUser} setLoggedIn={setLoggedIn} />
</Route>
<Route path="/signup">
<SignUp setActiveUser={setActiveUser} setLoggedIn={setLoggedIn} />
</Route>
<Route path="/profile">
<Profile business={business} activeUser={activeUser}/>
</Route>
</Switch>
</div>
);
}
export default App;
/
, /business
/business/:id
, /signin
, /signup
, and /profile
. The /
toute will render our Home, /business
route will render the Business Component, the /business/:id
route will render the BusinessDetail Component, the /signin
route will render our Signin component, the /signup
route will render our Signup Component.Switch
component wraps the dynamic routes and the Route
configures the specific routes and wraps the component the route will render. Then ourHeader.jsx
and Home.jsx
component in our component
directory. Header.jsx
component.import { Link } from "react-router-dom";
function Header(props) {
const { isLoggedIn, setLoggedIn, setActiveUser } = props;
const handleLogout = () => {
setLoggedIn((prev) => !prev);
setActiveUser([]);
};
return (
<header>
<div className={"logo"}>
<h4>Biza</h4>
</div>
<div className={"navbar"}>
<ul>
<li>
<Link to="/"> Home </Link>
</li>
<li>
<Link to="/business"> Business </Link>
</li>
{isLoggedIn ? (
<>
<li onClick={handleLogout}>Logout</li>
</>
) : (
<>
<li>
<Link to="/signin"> Signin </Link>
</li>
<li>
<Link to="/signup"> Signup </Link>
</li>
</>
)}
</ul>
</div>
</header>
);
}
export default Header;
Link
component from react-router-dom
, destructure our isLoggedIn
, setLoggedIn
, setActiveUser
from our props. We’ll use conditional rendering to display the Logout link only when a user is logged in our application, then display the Signup and Sign in links when they are not.Home.jsx
component.function Home(){
return(
<section className={'homepage'}>
<h4><span>Tell the World</span> about your Business</h4>
<button>Get Started</button>
</section>
)
}
export default Home;
isLoggedIn
, activeUser
, and business
state. Our isLoggedIn state will help us know if a user is logged in to our application, the activeUser state will enable us save the details of the currently logged in user, and our business state will enable use save all the approved business from our Business content-type collection. Because when a user is logged into our application, we need to persist their data to get it accross all the components where they will be used. const [isLoggedIn, setLoggedIn] = useState(false);
const [activeUser, setActiveUser] = useState();
const [business, setBusiness] = useState([]);
useEffect(() => {
async function fetchData() {
// You can await here
const response = await axios.get(`http://localhost:1337/businesses?isApproved=${true}`);
setBusiness(response.data);
}
fetchData();
}, []);
Index.js
Component with the code below:BrouserRouter
from react-router-dom module, the BrowserRouter component will initialize the routing system for our Components.import React from "react";
import ReactDOM from "react-dom";
import "./style.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
style.css
file in our src directory. Copy the styles from the Github repository of this project and paste them into the style.css file.http://localhost:3000/
, feel to test all the routes./signup
/signin
/business
/business/id
/profile