reactredux/webapi/ClientApp/src/pages/Home/index.tsx

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)} &middot; {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
}