Overview: All views and functionality related to the Company, all funcs called are coming from the authSlice
reducer.
Company Route Page
inside routes > company > company-page.tsx
imports that assist with components to render, and functions to call from companyReducer
. useParams
will be used to get the id
of the company that's passed in the url. -> company/:id
route. On mount, I fetch the appropriate company in DB by id. To clarify, when I fetch this data I set it to state.
import { useEffect } from 'react';
import { useParams } from 'react-router';
import BeatLoader from 'react-spinners/BeatLoader';
import { getCompany } from '../../app/features/company/companySlice';
import { useAppDispatch, useAppSelector } from '../../app/hooks';
import ViewCompany from '../../components/company/view-company.component';
const CompanyPage = () => {
const { id } = useParams();
const dispatch = useAppDispatch();
const { isLoading } = useAppSelector((state) => state.company);
useEffect(() => {
dispatch(getCompany(id));
}, [id, dispatch]);
return <>{isLoading ? <BeatLoader /> : <ViewCompany />}</>;
};
export default CompanyPage;
View Company Component
inside components > company > view-company.component.tsx
I created a helper method truncateString
for text that's too long. If text reaches max length it shows ...
import { useAppSelector } from '../../app/hooks';
import { truncateString } from '../../utils/truncateString';
Functionality
get company state from companyReducer
const ViewCompany = () => {
const { company } = useAppSelector((state) => state.company);
return ({/* removed for simplicity */});
};
export default ViewCompany;
UI
In a nutshell, it renders company details(who they are, location, hiring, etc.), along with the jobs they posted.
const ViewCompany = () => {
const { company } = useAppSelector((state) => state.company);
return (
<>
<section style={{ backgroundColor: '#252731' }} className="mb-3">
<div className="container mx-auto py-5 px-5 md:px-0 text-right text-white flex justify-between">
<div className="flex justify-center text-md text-slate-200">
{company.isHiring ? (
<p>We are hiring!</p>
) : (
<p>Not hiring at the moment</p>
)}
</div>
</div>
<div className="md:px-12 lg:px-24 max-w-7xl relative items-center w-full px-5 py-5 mx-auto">
<div className="mx-auto flex flex-col w-full max-w-lg mb-12 text-center">
<p className="mb-5 font-medium text-2xl text-white">
{company.companyName}
</p>
<img
alt="testimonial"
className="inline-block object-cover object-center w-20 h-20 mx-auto mb-8 rounded-full"
src="https://picsum.photos/200"
/>
<div className="flex justify-center">
{company.companyUrl ? (
<a
href={company.companyUrl}
className="text-base leading-relaxed text-indigo-500 border-r-2 border-gray-500 pr-2"
>
Company Website
</a>
) : null}
{company.companySize ? (
<p className="text-base leading-relaxed font-color pl-2">
Company size: {company.companySize}
</p>
) : null}
</div>
</div>
</div>
</section>
<ul
className="nav nav-tabs flex flex-col md:flex-row flex-wrap list-none border-b-0 pl-0 mb-4 text-white"
id="tabs-tabFill"
role="tablist"
>
<li className="nav-item flex-auto text-center" role="presentation">
<a
href="#tabs-homeFill"
className="
nav-link
w-full
block
font-medium
text-sm
leading-tight
uppercase
border-x-0 border-t-0 border-b-2 border-transparent
px-6
py-3
my-2
hover:border-transparent hover:bg-transparent
focus:border-transparent
active
"
id="tabs-home-tabFill"
data-bs-toggle="pill"
data-bs-target="#tabs-homeFill"
role="tab"
aria-controls="tabs-homeFill"
aria-selected="true"
>
About the company
</a>
</li>
<li className="nav-item flex-auto text-center" role="presentation">
<a
href="#tabs-profileFill"
className="
nav-link
w-full
block
font-medium
text-sm
leading-tight
uppercase
border-x-0 border-t-0 border-b-2 border-transparent
px-6
py-3
my-2
hover:border-transparent hover:bg-transparent
focus:border-transparent
"
id="tabs-profile-tabFill"
data-bs-toggle="pill"
data-bs-target="#tabs-profileFill"
role="tab"
aria-controls="tabs-profileFill"
aria-selected="false"
>
Jobs Posted
</a>
</li>
</ul>
<div className="tab-content font-color" id="tabs-tabContentFill">
<div
className="tab-pane fade show active w-full max-w-4xl"
id="tabs-homeFill"
role="tabpanel"
aria-labelledby="tabs-home-tabFill"
>
<p className="text-md px-10">{company.companyDescription}</p>
</div>
<div
className="tab-pane fade"
id="tabs-profileFill"
role="tabpanel"
aria-labelledby="tabs-profile-tabFill"
>
{company.jobs.length ? (
<section className="text-gray-600 body-font">
<div className="container py-5 mx-auto">
<div className="flex flex-wrap -m-4">
{company.jobs.map((job, index) => {
return (
<div className="p-4 md:w-1/2 w-full" key={index}>
<div className="h-full secondary-bg-color p-8 rounded">
<h2 className="mb-3 text-indigo-500">
<a href={job.applyUrl}>APPLY FOR JOB</a>
</h2>
<p className="leading-relaxed mb-6 font-color">
{truncateString(job.description, 250)}
</p>
<span className="flex-grow flex flex-col">
<span className="title-font font-medium text-white">
{job.position}
</span>
<div className="flex font-color">
<span className="text-sm">
{job.location.toUpperCase()}
</span>
<span className="text-sm mx-2">
{job.jobType.toUpperCase()}
</span>
<span className="text-sm">
${job.salary.toUpperCase()}
</span>
</div>
</span>
</div>
</div>
);
})}
</div>
</div>
</section>
) : (
<p className="text-md">No Jobs posted </p>
)}
</div>
</div>
</>
);
};
export default ViewCompany;
Screenshots
That's all for the UI/Company portion of the project, stay tuned!
Top comments (0)