243 lines
8.3 KiB
TypeScript
243 lines
8.3 KiB
TypeScript
// React
|
|
import React, { FC, useEffect } from 'react'
|
|
import { Link } from 'react-router-dom'
|
|
|
|
// Redux
|
|
import { useDispatch, useSelector } from 'react-redux'
|
|
import { ApplicationState } from '../../store'
|
|
import { actionCreators as loaderActionCreators } from '../../store/reducers/Loader'
|
|
import { actionCreators as blogFeaturedActionCreators } from '../../store/reducers/BlogFeatured'
|
|
import { actionCreators as headerActionCreators } from '../../store/reducers/Header'
|
|
|
|
// Reactstrap
|
|
import { Card, CardBody, CardFooter, CardImg, Col, Container, Row } from 'reactstrap'
|
|
|
|
// Models (interfaces)
|
|
import { CallToActionSectionModel, FeaturedBlogsSectionModel, FeaturesSectionModel, TestimonialsSectionModel, TitleSectionModel } from '../../models/pageSections'
|
|
import { BlogItemModel, FeatureModel, HeaderModel, TestimonialModel } from '../../models'
|
|
|
|
// Custom components
|
|
import { FeatherIcon } from '../../components/FeatherIcons'
|
|
|
|
// Functions
|
|
import { dateFormat } from '../../functions'
|
|
|
|
// CSS Modules
|
|
import style from './scss/style.module.scss'
|
|
|
|
const TitleSection : FC<TitleSectionModel> = ({
|
|
title = "",
|
|
text = ""
|
|
}) => {
|
|
return <header className="py-5 bg-dark">
|
|
<Container fluid className="px-5">
|
|
<Row className="gx-5 align-items-center justify-content-center">
|
|
<Col className="lg-8 xl-7 xxl-6">
|
|
<div className="my-5 text-center text-xl-start">
|
|
<h1 className="display-5 fw-bolder text-white mb-2">{title}</h1>
|
|
<span className="lead fw-normal text-white-50 mb-4" dangerouslySetInnerHTML={{ __html: text }}>
|
|
|
|
</span>
|
|
<div className="d-grid gap-3 d-sm-flex justify-content-sm-center justify-content-xl-start">
|
|
<a className="btn btn-primary btn-lg px-4 me-sm-3" href="#features">Get Started</a>
|
|
<a className="btn btn-outline-light btn-lg px-4" href="#!">Learn More</a>
|
|
</div>
|
|
</div>
|
|
</Col>
|
|
<div className="col-xl-5 col-xxl-6 d-none d-xl-block text-center"><img className="img-fluid rounded-3 my-5" src="https://dummyimage.com/600x400/343a40/6c757d" alt="..." /></div>
|
|
</Row>
|
|
</Container>
|
|
</header>
|
|
}
|
|
|
|
interface Fetures {
|
|
title?: string,
|
|
items?: FeatureModel []
|
|
}
|
|
|
|
const FeaturesSection: FC<Fetures> = ({
|
|
title = "",
|
|
items = []
|
|
}) => {
|
|
return <section className="py-5" id="features">
|
|
<Container fluid className="px-5 my-5">
|
|
<Row className="gx-5">
|
|
<Col className="lg-4 mb-5 mb-lg-0">
|
|
<h2 className="fw-bolder mb-0">{title ? title : ''}</h2>
|
|
</Col>
|
|
<Col className="lg-8">
|
|
<Row className="gx-5 cols-1 cols-md-2">
|
|
{items ? items.map((item, index) => <Col key={index} className="mb-5 h-100">
|
|
<div className={`${style.feature} bg-primary bg-gradient text-white rounded-3 mb-3`}>
|
|
<FeatherIcon icon={item.icon} />
|
|
</div>
|
|
<h2 className="h5">{item.title}</h2>
|
|
<p className="mb-0" dangerouslySetInnerHTML={{ __html: item.text }}></p>
|
|
</Col>) : ''}
|
|
</Row>
|
|
</Col>
|
|
</Row>
|
|
</Container>
|
|
</section>
|
|
}
|
|
|
|
interface Testimonials {
|
|
items?: TestimonialModel []
|
|
}
|
|
|
|
const TestimonialsSection: FC<Testimonials> = ({
|
|
items = []
|
|
}) => {
|
|
const item = items[0]
|
|
|
|
return <section className="py-5 bg-light">
|
|
<Container fluid className="px-5 my-5">
|
|
<Row className="gx-5 justify-content-center">
|
|
<Col className="lg-10 xl-7">
|
|
{ item
|
|
? <div className="text-center">
|
|
<div className="fs-4 mb-4 fst-italic" dangerouslySetInnerHTML={{ __html: item.text }}></div>
|
|
<div className="d-flex align-items-center justify-content-center">
|
|
<img className="rounded-circle me-3" {...item.reviewer.image} />
|
|
<div className="fw-bold">{item.reviewer.fullName}<span className="fw-bold text-primary mx-1">/</span>{item.reviewer.position}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
: '' }
|
|
</Col>
|
|
</Row>
|
|
</Container>
|
|
</section>
|
|
|
|
}
|
|
|
|
interface FeaturedBlogs extends FeaturedBlogsSectionModel {
|
|
items?: BlogItemModel []
|
|
}
|
|
const FeaturedBlogsSection: FC<FeaturedBlogs> = ({
|
|
title = "",
|
|
text = "",
|
|
items = [] }) => <section className="py-5">
|
|
<Container fluid className="px-5 my-5">
|
|
<Row className="gx-5 justify-content-center">
|
|
<Col className="lg-8 xl-6">
|
|
<div className="text-center">
|
|
<h2 className="fw-bolder">{title}</h2>
|
|
<p className="lead fw-normal text-muted mb-5" dangerouslySetInnerHTML={{ __html: text }}></p>
|
|
</div>
|
|
</Col>
|
|
</Row>
|
|
<Row className="gx-5">
|
|
{items.map((item, index) => <Col key={index} className="lg-4 mb-5">
|
|
<Card className="h-100 shadow border-0">
|
|
<CardImg top {...item.image} />
|
|
<CardBody className="p-4">
|
|
<div className="badge bg-primary bg-gradient rounded-pill mb-2">{item.badges}</div>
|
|
<Link className="text-decoration-none link-dark stretched-link" to="#!">
|
|
<h5 className="card-title mb-3">{item.title}</h5>
|
|
</Link>
|
|
<p className="card-text mb-0" dangerouslySetInnerHTML={{ __html: text ? text : '' }}></p>
|
|
</CardBody>
|
|
<CardFooter className="p-4 pt-0 bg-transparent border-top-0">
|
|
<div className="d-flex align-items-end justify-content-between">
|
|
<div className="d-flex align-items-center">
|
|
<img className="rounded-circle me-3" {...item.author.image} />
|
|
<div className="small">
|
|
<div className="fw-bold">{item.author.nickName}</div>
|
|
<div className="text-muted">{dateFormat(item.created)} · {item.readTime}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardFooter>
|
|
</Card>
|
|
</Col>)}
|
|
</Row>
|
|
</Container>
|
|
</section>
|
|
|
|
const CallToActionSection: FC<CallToActionSectionModel> = ({
|
|
title,
|
|
text,
|
|
privacyDisclaimer,
|
|
email = {
|
|
placeHolder: "",
|
|
title: ""
|
|
}
|
|
}) => {
|
|
|
|
return <section className="py-5">
|
|
<Container fluid className="px-5 my-5">
|
|
<aside className="bg-primary bg-gradient rounded-3 p-4 p-sm-5 mt-5">
|
|
<div className="d-flex align-items-center justify-content-between flex-column flex-xl-row text-center text-xl-start">
|
|
<div className="mb-4 mb-xl-0">
|
|
<div className="fs-3 fw-bold text-white">{title}</div>
|
|
<div className="text-white-50">{text}</div>
|
|
</div>
|
|
<div className="ms-xl-4">
|
|
<div className="input-group mb-2">
|
|
<input className="form-control" type="text" placeholder={email.placeHolder ? email.placeHolder : ''} aria-label={email.placeHolder ? email.placeHolder : ''} aria-describedby="button-newsletter" />
|
|
<button className="btn btn-outline-light" id="button-newsletter" type="button">{email.title ? email.title : ''}</button>
|
|
</div>
|
|
<div className="small text-white-50">{privacyDisclaimer}</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</Container>
|
|
</section>
|
|
}
|
|
|
|
const Home = () => {
|
|
const dispatch = useDispatch()
|
|
const { content, blogFeatured } = useSelector((state: ApplicationState) => state)
|
|
const page = content?.homePage
|
|
|
|
useEffect(() => {
|
|
dispatch(blogFeaturedActionCreators.requestBlogFeatured())
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
content?.isLoading || blogFeatured?.isLoading
|
|
? dispatch(loaderActionCreators.show())
|
|
: setTimeout(() => {
|
|
dispatch(loaderActionCreators.hide())
|
|
}, 1000)
|
|
}, [content?.isLoading, blogFeatured?.isLoading])
|
|
|
|
const {
|
|
header = {},
|
|
titleSection = {
|
|
title: "",
|
|
text: ""
|
|
},
|
|
featuresSection = {},
|
|
testimonialsSection = {},
|
|
featuredBlogsSection = {},
|
|
callToActionSection = {
|
|
title: "",
|
|
text: "",
|
|
privacyDisclaimer: "",
|
|
email: {
|
|
placeHolder: "",
|
|
title: ""
|
|
}
|
|
}
|
|
} = content?.homePage ? content.homePage : {}
|
|
|
|
useEffect(() => {
|
|
dispatch(headerActionCreators.updateHeader(header as HeaderModel))
|
|
}, [header])
|
|
|
|
|
|
return <>
|
|
<TitleSection {...titleSection} />
|
|
<FeaturesSection {...featuresSection} />
|
|
<TestimonialsSection {...testimonialsSection} />
|
|
<FeaturedBlogsSection items={blogFeatured?.items} {...featuredBlogsSection} />
|
|
<CallToActionSection {...callToActionSection} />
|
|
</>
|
|
}
|
|
|
|
export {
|
|
Home
|
|
}
|