A job board is a platform to post job vacancies and search for jobs. It allows employers to find employees faster by searching for potential global candidates. A typical job board platform supports searching and filtering open jobs and has a form for applying for positions. Examples of standard job boards are Strapi, Upwork, Indeed, or Fiverr.
Strapi is an open-source headless CMS based on Node.js, where you can host and manage content. Strapi supports Jamstack technology, and it is easy to serve content to the front-end across different platforms via restful API calls. Strapi has made it easy for developers to manage their application content without writing complex code.
React is also an open-source JavaScript front-end framework for creating interactive user interfaces. React allows developers to create reusable components that, when combined, form the entire application user interface.
In this tutorial, you will learn about Strapi and walk through a step-by-step guide on creating a complete job board website with React and Strapi.
Let's have a look at what we'll accomplish at the end of this tutorial:
To complete this tutorial, you'll need the following software installed:
v14
or v16
Set up Strapi on our local machine using Strapi CLI (Command Line Interface). In your terminal, navigate to the folder where you wish to install Strapi. Run the command below.
npx create-strapi-app <app-name> --quickstart
Once the installation is complete, the Strapi app should automatically launch in the browser. If not, you can start the Strapi server on your browser by running the command below in the terminal.
npm run develop
Once you have started the server, open your browser and enter http://localhost:1337/admin. You must register as an admin and then log in to your dashboard.
Complete the form with your details and press the submit button. You will then be redirected to your dashboard, as shown below.
We will create two collection types for our application: applicantlist
and joblist
.
applicantlist
Collection Type: This will contain all the information submitted by the candidates and the status of each application, whether it is accepted or not.
Follow the following steps to create applicantlist
Collection Type:
Step 1
applicantlist
),Step 2
What we need to do next is to add the necessary fields to the collection type. The applicantlist
content type will contain the following fields:
Joblist
Collection Type: This collection will contain open jobs and employer details. Follow the following steps to create the collection type:
Step 1
Joblist
),Step 2
We need to add the necessary fields to the collection type. The joblist
content type will contain the following fields:
Next, we need to be able to interact with the two collections via an API call by changing the permission role of the type. To change the permission role for the collection types, follow the steps below:
applicantlist
and joblist
, and select all, respectively Now that we have set up the back-end, we will start building the application interface and its functionalities next.
Open a new terminal and install react with the command below.
npx create-react-app job-board
cd job-board
npm start
Next, let's break the job board application into two sections: the candidate and admin interface. React is a single-page application, but we'll leverage the react route to navigate between the application pages in the browser.
React Router is an external library that enables us to navigate through various components in a React application by changing the browser URL and keeping the UI in sync with the URL. We can install the react route with the command below:
npm install react-router-dom@6
This part will have the following features: a search bar for searching for a job, filter options for the job type, and a form to apply for jobs. Navigate to src/pages, open app.js in any code editor, paste the following code, and then save it.
1 import './style.css';
2 import { useState, useEffect } from 'react';
3 import { Link } from 'react-router-dom';
4
5
6 function App() {
7 const [todos, setTodos] = useState([]);
8 const [search, setSearch] = useState("");
9
10
11 function update() {
12 fetch("http://localhost:1337/api/jobslists")
13 .then(res => res.json())
14 .then(todo => {
15 setTodos(todo.data);
16 })
17 }
18 useEffect(() => {
19 update();
20 }, [])
21
22
23 return (
24 <div>
25
26 <div className="header">
27 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"></link>
28 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
29 <div >
30
31 <div className="menu1">
32 <Link to="/">Job Board</Link>
33
34
35 </div>
36
37 <div className="menu2">
38 <Link to="/login">Login</Link>
39 </div>
40
41 </div></div>
42 <br></br>
43
44
45 <div>
46 <div className="margin">
47 <br />
48
49
50 </div>
51 <div className="filter">
52 <br />
53 <div>
54 <button className="filter2 btn btn-info">filter Job list</button><br /><br />
55 <form className="filter3" method="get">
56 <input type="radio" onChange={(event) => setSearch(event.target.value.toLowerCase())} name="c" value="" />
57 <label>All Jobs</label><br />
58 <input type="radio" name="c" value="Backend" onChange={(event) => setSearch(event.target.value.toLowerCase())} />
59 <label>Part Time</label><br />
60 <input type="radio" name="c" value="Internship" />
61 <label>Internship</label><br />
62 <input type="radio" name="c" />
63 <label>Freelance</label>
64 </form>
65 </div>
66 </div>
67
68 <div className="job">
69 <div><br />
70 <div className="form-group">
71 <label >Search:</label>
72 <input type="text" placeholder="Search Job Title..." value={search} className="form-control" onChange={(event) => setSearch(event.target.value.toLowerCase())} />
73 </div>
74 </div>
75 <br />
76 <br />
77 {
78 todos.map((todo, i) => {
79 const link = "apply?jobid=" + todo.id;
80 const filter = JSON.stringify(todo.attributes).toLowerCase()
81 if(filter.includes(search)){
82 return (
83 <div key={i}>
84 <div>
85 <div className="detaills">
86 <img src='https://super-static-assets.s3.amazonaws.com/e7c0f16c-8bd3-4c76-8075-4c86f986e1b2/uploads/favicon/9c68ae10-0a8a-4e3f-9084-3625b19df9cb.png' className="logo"/>
87 <div className="description">
88 <span className="span1">{todo.attributes.JobPosition}</span>
89 <span className='right'> {todo.attributes.Location}</span>
90 <span className="span2">
91 {todo.attributes.JobStatus}
92 </span><br /><br />
93 <span className="span1">{todo.attributes.Agency}</span>
94 </div>
95 </div>
96 <div className="apply">
97 <a href={link }><button className="ap1">Apply Now
98 </button></a>
99 <div className="ap2">{todo.attributes.Experience}</div>
100 </div>
101 </div> <br />
102 </div>
103 )
104 }else{}
105 })
106 }
107 </div>
108 </div>
109 </div>
110 );
111 }
112
113 export default App;
Now, if we try to run the application in the browser, it will generate an error because we have not set up the navigation URL for our React app. To do that, from your application root folder, open index.js and replace it with the following code:
1 import React from 'react';
2 import ReactDOM from 'react-dom/client';
3 import './index.css';
4 import App from './App';
5 import Apply from './pages/apply';
6 import reportWebVitals from './reportWebVitals';
7 import { BrowserRouter,Routes,Route} from 'react-router-dom';
8
9 const root = ReactDOM.createRoot(document.getElementById('root'));
10 root.render(
11 <React.StrictMode>
12 <BrowserRouter>
13 <Routes>
14 <Route path="/" element={<App />} />
15 <Route path="apply" element={<Apply />} />
16 </Routes>
17 </BrowserRouter>
18 </React.StrictMode>
19 );
20
21 // If you want to start measuring performance in your app, pass a function
22 // to log results (for example: reportWebVitals(console.log))
23 // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
24 reportWebVitals();
Next, let's add style to the application. Inside the src folder, create a style.css
file and add the following:
1 .header {
2 height: 50px;
3 width: 100%;
4 background-color: #24cef0;
5 position: fixed;
6 }
7
8 .menu1 {
9 margin-top: 10px;
10 margin-left: 80px;
11 font-size: 20px;
12 width: 400px;
13 float: left;
14 color: black;
15
16 }
17
18 .menu2 {
19 margin-top: 10px;
20 margin-right: 80px;
21 font-size: 20px;
22 width: 100px;
23 float: right;
24 color: black;
25 }
26
27 .menu3 {
28 margin-top: 10px;
29 margin-right: 80px;
30 font-size: 20px;
31 width: 70px;
32 float: right;
33 color: black;
34 }
35
36 .right {
37 float: right;
38 }
39
40 .color {
41 background-color: #f1f1f1;
42 }
43
44 .margin {
45 margin-right: 100px;
46 }
47
48
49 body {
50 font-family: Arial, Helvetica, sans-serif;
51 background-color: #f5f5f5;
52 opacity: 0.9;
53 scroll-behavior: auto;
54 }
55
56 input[type=text],
57 input[type=password] {
58 width: 100%;
59 padding: 12px 20px;
60 margin: 8px 0;
61 display: inline-block;
62 border: 1px solid #ccc;
63 box-sizing: border-box;
64 }
65
66
67
68 .cancelbtn {
69 width: auto;
70 padding: 10px 18px;
71 background-color: #f44336;
72 }
73
74 .imgcontainer {
75 text-align: center;
76 margin: 24px 0 12px 0;
77 position: relative;
78 }
79
80
81
82 .container {
83 padding: 16px;
84 }
85
86 span.psw {
87 float: right;
88 padding-top: 16px;
89 }
90
91 /* The Modal (background) */
92 .modal {
93 display: none;
94 position: fixed;
95 z-index: 1;
96 left: 0;
97 top: 0;
98 width: 100%;
99 height: 100%;
100 overflow: auto;
101 background-color: rgb(0, 0, 0);
102 background-color: rgba(0, 0, 0, 0.4);
103 padding-top: 60px;
104 }
105
106 .modal-content {
107 background-color: #fefefe;
108 margin: 5% auto 15% auto;
109 border: 1px solid #888;
110 width: 80%;
111 }
112
113 .close {
114 position: absolute;
115 right: 25px;
116 top: 0;
117 color: #000;
118 font-size: 35px;
119 font-weight: bold;
120 cursor: pointer;
121 }
122
123 .job {
124 /* min-height: 180px; */
125 width: 700px;
126 border-radius: 10px;
127 float: right;
128 margin-right: 310px;
129 }
130
131 .job2 {
132 /* background-color: red; */
133 min-height: 180px;
134 width: 700px;
135 border-radius: 10px;
136 float: right;
137 margin-right: 100px;
138 }
139
140 .detaills {
141 background-color: white;
142 height: 140px;
143 width: 100%;
144 border: 3px solid #f8f9fc;
145 border-top-left-radius: 9px;
146 border-top-right-radius: 9px;
147 }
148
149 .detaills_ {
150 background-color: white;
151 height: 230px;
152 width: 100%;
153 border: 3px solid #f8f9fc;
154
155 border-top-left-radius: 9px;
156 border-top-right-radius: 9px;
157 }
158
159 .apply {
160 background-color: #f8f9fc;
161 height: 40px;
162 width: 100%;
163 border-bottom-left-radius: 10px;
164 border-bottom-right-radius: 10px;
165 border: 3px solid #f8f9fc;
166 }
167
168 .ap1 {
169 float: right;
170 margin-right: 14px;
171 margin-top: 10px;
172 background-color: transparent;
173 border-width: 0px;
174
175 }
176
177 .ap2 {
178 float: left;
179 margin-left: 14px;
180 margin-top: 10px;
181 background-color: transparent;
182 border-width: 0px;
183
184 }
185
186 .logo {
187 width: 100px;
188 height: 100px;
189 border: 3px solid pink;
190 margin-left: 40px;
191 margin-top: 18px;
192 border-radius: 10px;
193 float: left;
194 }
195
196 .description {
197 float: left;
198 margin-top: 27px;
199 margin-left: 18px;
200 width: 70%;
201 }
202
203 .span2 {
204 font-size: 14px;
205 margin-left: 30px;
206 }
207
208 .span1 {
209 font-size: 18px;
210 }
211
212 .filter {
213 width: 240px;
214 /* background-color: #f44336; */
215 height: 300px;
216 float: left;
217 margin-left: 30px;
218
219 }
220
221 .filter2 {
222 margin-top: 30px;
223 font-size: 18px;
224 }
225
226 .filter3 {
227 margin-left: 20px;
228 }
229
230 .select {
231 width: 200px;
232 border-radius: 10px;
233 font-size: 17px;
234 }
235
236 .logo_ {
237 width: 40px;
238 height: 40px;
239 border: 3px solid pink;
240 margin-left: 40px;
241 margin-top: 18px;
242 border-radius: 10px;
243 float: left;
244 }
245
246
247 .span1_ {
248 font-size: 14px;
249 }
250
251 .filter_ {
252 width: 240px;
253 height: 300px;
254 float: right;
255 margin-left: 30px;
256
257 }
258
259 .filter3_ {
260 width: 100px;
261 margin-left: 30px;
262
263 }
264
265 .filter2_ {
266 margin-top: 20px;
267 font-size: 18px;
268 margin-left: 20px;
269 }
We need to create a component that will handle job application submission and send it to the backend. Inside the src/pages, create a component called apply.js and the following code:
1 import { useState, useEffect } from 'react';
2 import { Link } from 'react-router-dom';
3
4 function Apply() {
5 const queryParams = new URLSearchParams(window.location.search);
6 const jobid = queryParams.get('jobid');
7 const [job, setJob] = useState([]);
8 const[fullname,setFullname] = useState("")
9 const[email,setEmail] = useState("")
10 const[link,setLink] = useState("")
11 const[message,setMessage] = useState("")
12
13
14 const update = async () => {
15 fetch("http://localhost:1337/api/jobslists/"+jobid)
16 .then(res => res.json())
17 .then(job_info => {
18 setJob(job_info.data.attributes);
19 console.log(job_info.data.attributes);
20 })
21 }
22 useEffect(() => {
23 update();
24 console.log(job);
25 }, [])
26
27 const subbmit = async () => {
28 const requestOptions = {
29 method: 'POST',
30 headers: { 'Content-Type': 'application/json' },
31 body: JSON.stringify({
32 "data": {
33 "Name": fullname,
34 "Email": email,
35 "Message": message,
36 "Portfolio_Link": link,
37 "Status": "Pending",
38 "JobID": jobid
39 }
40 })
41 };
42
43 fetch('http://localhost:1337/api/applicantlists', requestOptions)
44 .then(response => response.json())
45
46 alert("Application Submited Successful...");
47 }
48
49 return (
50 <div>
51 <div className="header">
52 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"></link>
53 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
54 <div >
55
56 <div className="menu1">
57 <Link to="/">Job Board</Link>
58
59
60 </div>
61
62 <div className="menu2">
63 <Link to="/login">Login</Link>
64 </div>
65
66 </div></div>
67 <br/><br/>
68 <div>
69
70 <div className="job2" style={{float:'left',marginLeft:'150px',width:'600px'}}>
71 <br/><br/>
72 <div>
73 <div className="detailds_" style={{backgroundColor:'white',height:'500px',width:'100%',border:'3px solid #f8f9fc',borderTopLeftRadius:'9px',borderTopRightRadius:'9px'}}>
74 <img src='https://super-static-assets.s3.amazonaws.com/e7c0f16c-8bd3-4c76-8075-4c86f986e1b2/uploads/favicon/9c68ae10-0a8a-4e3f-9084-3625b19df9cb.png' style={{width:'80px', height:'80px',border:'3px solid pink',marginLeft:'40px',marginTop:'18px',borderRadius:'10px',marginLeft:'44%'}}/>
75 {/* </div> */}
76 <div className={{float:'left',marwginTop:'27px',marginLeft:'18px',width:'100%'}}>
77 <center><span className="span1_"><b>{job.JobPosition}</b></span><br/>
78
79 <span className="span1_">{job.Location}</span><br/><br/>
80 <span>{job.JobDescription} </span>
81
82
83 </center><br/><br/><br/><br/>
84 <div>
85 <span><b>{job.Experience}</b></span> <br/><br/>
86 <span><b>Category : {job.Category}</b></span> <br/><br/>
87 <span><b>Company : {job.Agency}</b></span>
88 </div>
89 </div>
90
91 </div>
92
93 </div>
94
95 </div>
96
97
98 <div clas="job2" style={{float:'right',marginLeft:'20px',height:'500px',width:'400px',borderRadius:'10px',marginRight:'160px'}}>
99 <br/><br/>
100 <div>
101 <div className="details_" style={{backgroundColor:'white',height:'500px',width:'100%',border:'3px solid #f8f9fc',borderTopLeftRadius:'9px',borderTopRightRadius:'9px'}}>
102 <center><br/>
103 <h4>Application form</h4>
104 <form action="">
105 <div className="form-group">
106 <input type="text" onChange={(event) => setFullname(event.target.value)} className="form-control" placeholder="Enter Fullname" style={{borderRadius:'10px'}} id="usr"/>
107 </div> <br/>
108 <div className="form-group">
109 <input type="email" onChange={(event) => setEmail(event.target.value)} className="form-control" placeholder="Enter Email Address" style={{borderRadius:'10px'}} id="usr"/>
110 </div><br/>
111 <div className="form-group">
112 <input type="url" onChange={(event) => setLink(event.target.value)} className="form-control" placeholder="Link to Your Portfolio" style={{borderRadius:'10px'}} id="usr"/>
113 </div><br/>
114 <div className="form-group">
115 <textarea name="" onChange={(event) => setMessage(event.target.value)} className="form-control" rows="6" placeholder="Tell us more about you and your experience" style={{borderRadius:'10px'}}></textarea>
116 <br/>
117
118 <input type="button" onClick={() => subbmit()} className="form-control" value="Submit" />
119
120
121 </div>
122 </form>
123
124 </center>
125
126 </div>
127
128 </div>
129
130 </div>
131
132
133 </div>
134 </div>
135 );
136 }
137
138
139
140 export default Apply;
To confirm that the candidate interface that we just built is working fine, let's add some open jobs to the application, as demonstrated in the image below:
Next, enter npm run start on the terminal and open [http://localhost:3000/](http://localhost:3000/)
in the browser. It should look like this:
Now, let's create the admin page where the admin user can log in, view candidate profiles, and decide whether to approve or decline candidates' applications. Let's start with the login page. Inside the pages folder, create login.js and add the following code to it, then save.
1 import { useState, useEffect } from 'react';
2 import { Navigate } from "react-router-dom";
3
4 export default function Expenses() {
5
6 const queryParams = new URLSearchParams(window.location.search);
7 const id = queryParams.get('id');
8 const [auth, setAuth] = useState('');
9 const [Email, setEmail] = useState('test@gmail.com');
10 const [Password, setPassword] = useState('pass123');
11 const [submit, setsubmit] = useState();
12 const update = async () => {
13
14 const requestOptions = {
15 method: 'POST',
16 headers: { 'Content-Type': 'application/json' },
17 body: JSON.stringify({identifier:Email,password:Password})
18 };
19 fetch('http://localhost:1337/api/auth/local', requestOptions)
20 .then(response => response.json())
21 .then(data => setAuth(data));
22 }
23
24 console.log(auth.jwt)
25 if(typeof(auth.jwt)!=="undefined"){
26 const url = "/dashboard?token="+auth.jwt;
27 return <Navigate to={url}/>;
28 }
29
30 return (
31
32 <div className="container">
33
34
35 <center>
36 <div style={{ width: '270px', marginLeft: '0px', marginTop: '200px' }}>
37 <h2>Login</h2>
38 <p>login as{id} agent</p>
39 <form role="form">
40 <div className="form-group">
41 <label for="usr">Email:</label>
42 <input type="text" className="form-control" id="usr" onChange={(event) => setEmail(event.target.value)} />
43 </div>
44 <div className="form-group">
45 <label for="pwd">Password:</label>
46 <input type="password" className="form-control" id="pwd" onChange={(event) => setPassword(event.target.value)} />
47 </div>
48 <div className="form-groug">
49 <br />
50 <a className="form-control" value="login" onClick={() => update()} >Login</a>
51
52 </div>
53 </form>
54 </div></center>
55 </div>
56
57 );
58 }
If the login details are correct from the login page, the admin will be redirected to the dashboard.
Next, inside the src/pages
folder, create a dashboard.js
file and add the following code.
1 import { useState, useEffect } from 'react';
2 import { Navigate } from "react-router-dom";
3 import { Link } from 'react-router-dom';
4
5 export default function Dashboard() {
6 const [state, setState] = useState("")
7 const [Applicant, setApplicants] = useState([]);
8 const [jobTitle, setjobTitle] = useState("")
9 const [jobCategory, setjobCategory] = useState("")
10 const [jobLocation, setjobLocation] = useState("")
11 const [jobDescription, setjobDescription] = useState("")
12 const [jobExpreience, setjobExpreience] = useState("")
13 const [openJob, setOpenJob] = useState([])
14 const queryParams = new URLSearchParams(window.location.search);
15 const token = queryParams.get('token');
16
17 function Applicants() {
18 fetch("http://localhost:1337/api/applicantlists")
19 .then(res => res.json())
20 .then(list => {
21 setApplicants(list.data);
22 })
23
24 }
25
26 function open() {
27 fetch("http://localhost:1337/api/jobslists")
28 .then(res => res.json())
29 .then(list => {
30 setOpenJob(list.data);
31 })
32
33 }
34
35 const update = async (id) => {
36 const requestOptions = {
37 method: 'PUT',
38 headers: { 'Content-Type': 'application/json' },
39 body: '{"data":{"Status":"Approved"}}'
40 };
41 console.log(requestOptions)
42 fetch('http://localhost:1337/api/applicantlists/' + id, requestOptions)
43 .then(response => response.json())
44 .then(data => this.setState("1"));
45
46
47 }
48 const delete1 = async (id) => {
49 const requestOptions = {
50 method: 'DELETE',
51 headers: { 'Content-Type': 'application/json' }
52 };
53 console.log(requestOptions)
54 fetch('http://localhost:1337/api/applicantlists/' + id, requestOptions)
55 .then(response => response.json())
56 .then(data => this.setState("1"));
57
58
59 }
60
61 useEffect(() => {
62 Applicants();
63 open();
64 }, [])
65
66 if (typeof (Applicant.id) === "undefinsed") {
67 const url = "/login";
68 return <Navigate to={url} />;
69 }
70
71
72 const addjob = async () => {
73 const requestOptions = {
74 method: 'POST',
75 headers: { 'Content-Type': 'application/json' },
76 body: JSON.stringify({
77 "data": {
78 "JobPosition": jobTitle,
79 "Category": jobCategory,
80 "Location": jobLocation,
81 "Experience": jobExpreience,
82 "JobDescription":jobDescription,
83 "JobStatus": "Open",
84 "Agency": "Strapi"
85 }
86 })
87 };
88 // console.log(requestOptions)
89 fetch('http://localhost:1337/api/jobslists', requestOptions)
90 .then(response => response.json())
91 // .then(data => this.setState(data ));
92
93 alert("Job Added Successful...");
94 }
95
96 return (
97 <div>
98 <div className="header">
99 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"></link>
100 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
101 <div >
102
103 <div className="menu1">
104 <Link to="/">Job Board</Link>
105
106
107 </div>
108
109 <div className="menu2">
110 <Link to="/">Logout</Link>
111 </div>
112
113 </div>
114 </div>
115 <br /><br />
116
117 <div className="filter_">
118 <br />
119
120 <div className="filter2_">
121 <span>Open Positions</span>
122 <hr />
123 {
124 openJob.map((list, i) => {
125
126 if (list.attributes.JobStatus == "Open") {
127 return (
128 <div key={i}>
129 <span style={{ fontSize: '17px' }}>{list.attributes.JobPosition}</span>
130 <hr />
131 </div>
132 )
133 }
134 })
135 }
136
137
138 </div>
139
140 </div>
141 <div className="job2">
142 <br /><br />
143
144 {
145 Applicant.map((list, i) => {
146
147 if (list.attributes.Status == "Pending") {
148 return (
149 <div key={i}>
150 <div>
151 <div className="detaills_">
152 <div className="logo_"></div>
153 <div className="description">
154 <span className="span1_">{list.attributes.Name}</span>
155 <span style={{ float: 'right' }}>{list.attributes.Status}</span>
156 <br />
157 <span className="span1_">{list.attributes.Email}</span>
158 <textarea style={{ borderWidth: '0px' }} readonly id="" cols="70"
159 rows="3">{list.attributes.Message}</textarea>
160 <center>
161 <a target={"_blank"} href={list.attributes.Portfolio_Link}>View Portfolio</a> <br />
162 <button className="btn-success" onClick={() => update(list.id)} >Approve</button>
163 <button className="btn-danger" onClick={() => delete1(list.id)}>Decline</button>
164 </center>
165 </div>
166
167 </div>
168
169 </div> <br />
170 </div>
171 )
172
173 }
174 })
175 }
176 </div>
177
178 <div className="filt">
179 <br />
180
181 <div className="filter2_">
182 <span>Post New Position</span><br /><br />
183 <form className="filter3_" method="get">
184 <input type="text" onChange={(event) => setjobTitle(event.target.value)} placeholder="Job Title" style={{ width: '200px', borderRadius: '10px' }} />
185 <input type="text" onChange={(event) => setjobCategory(event.target.value)} placeholder="Enter Job Category" style={{ width: '200px', borderRadius: '10px' }} />
186 <br />
187 <input type="text" onChange={(event) => setjobLocation(event.target.value)} placeholder="Location" style={{ width: '200px', borderRadius: '10px' }} id="" />
188 <br />
189
190 <textarea onChange={(event) => setjobDescription(event.target.value)} style={{ width: '200px', borderRadius: '10px' }}
191 placeholder="Job description"></textarea>
192 <br />
193
194 <select onChange={(event) => setjobExpreience(event.target.value)} className="select">
195 <option disabled selected>Requirement</option>
196 <option value="Experience : 0 - 1 year">Experience : 1 - 3 years</option>
197 <option value="Experience : 2 - 3 years">Experience : 1 - 3 years</option>
198 <option value="Experience : 4 - 7 years">Experience : 4 - 7 years</option>
199 </select><br /><br />
200
201
202 <center>
203 <input type="button" onClick={() => addjob()} className="form-control" value="Add Job" />
204 </center>
205
206 </form>
207 </div>
208
209 </div>
210
211
212 </div>
213
214 );
215 }
Let's finish the front end by adding the new pages we created into index.js
. Update src/index.js
with the code below:
1 import React from 'react';
2 import ReactDOM from 'react-dom/client';
3 import './index.css';
4 import App from './App';
5 import Login from "./pages/Login";
6 import Test from "./pages/test";
7 import Dashboard from "./pages/dashboard";
8 import reportWebVitals from './reportWebVitals';
9 import { BrowserRouter,Routes,Route} from 'react-router-dom';
10 import Apply from './pages/apply';
11
12 const root = ReactDOM.createRoot(document.getElementById('root'));
13 root.render(
14 <React.StrictMode>
15 <BrowserRouter>
16 <Routes>
17 <Route path="/" element={<App />} />
18 <Route path="login" element={<Login />} />
19 <Route path="test" element={<Test />} />
20 <Route path="dashboard" element={<Dashboard />} />
21 <Route path="apply" element={<Apply />} />
22 </Routes>
23 </BrowserRouter>
24 </React.StrictMode>
25 );
26
27 // If you want to start measuring performance in your app, pass a function
28 // to log results (for example: reportWebVitals(console.log))
29 // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
30 reportWebVitals();
Now let's add a new admin user. From your Strapi dashboard menu, navigate through Content Manager
to User
and create a new user, as shown in the image below.
The admin dashboard (localhost:3000/login ) should function as shown below.
Now we have successfully built a complete job board website from scratch. This tutorial explains what Strapi is, how to get started and how to use it with React to build a complete job board application.
You can find the source code for the job board application here: