reactredux/webapi/ClientApp/src/pages/Blog/Catalog/index.tsx

203 lines
5.9 KiB
TypeScript

import React, { FC, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { ApplicationState } from '../../../store'
import { actionCreators as contentActionCreators } from '../../../store/reducers/Content'
import { actionCreators as loaderActionCreators } from '../../../store/reducers/Loader'
import { actionCreators as blogCatalogActionCreators } from '../../../store/reducers/BlogCatalog'
import { actionCreators as blogFeaturedActionCreators } from '../../../store/reducers/BlogFeatured'
import { actionCreators as blogCategoriesActionCreators } from '../../../store/reducers/BlogCategories'
import { Link, useNavigate, useParams } from 'react-router-dom'
import { Card, CardBody, CardFooter, CardImg, Col, Container, Row } from 'reactstrap'
import { dateFormat, findRoutes } from '../../../functions'
import { Categories, Empty, Search } from '../../../components/SideWidgets'
import { Pagination } from '../../../components/Pagination'
import { BlogItemModel } from '../../../models'
import { TitleSectionModel } from '../../../models/pageSections'
const TitleSection: FC<TitleSectionModel> = (props) => {
const { title, text } = props
return <header className="py-5 bg-light border-bottom mb-4">
<Container fluid>
<div className="text-center my-5">
<h1 className="fw-bolder">{title ? title : ''}</h1>
<p className="lead mb-0">{text ? text : ''}</p>
</div>
</Container>
</header>
}
interface FeaturedBlog {
path?: string,
currentPage?: number
item?: BlogItemModel,
readTime?: string
}
const FeaturedBlogSection: FC<FeaturedBlog> = ({
currentPage = 1,
path = "",
item = {
id: "",
slug: "demo-post",
badges: [],
image: {
src: "https://dummyimage.com/850x350/dee2e6/6c757d.jpg",
alt: "..."
},
title: "",
shortText: "",
author: {
id: "",
nickName: "",
image: {
src: "https://dummyimage.com/40x40/ced4da/6c757d",
alt: "..."
}
},
created: new Date().toString(),
tags: [],
likes: 0
},
readTime = ""
}) => {
return <Card className="mb-4 shadow border-0">
<CardImg top {...item.image} />
<CardBody className="p-4">
{item.badges.map((badge, index) => <div key={index} className="badge bg-primary bg-gradient rounded-pill mb-2">{badge}</div>)}
<Link className="text-decoration-none link-dark stretched-link" to={`${path}/${currentPage}/${item.slug}`}>
<h5 className="card-title mb-3">{item.title}</h5>
</Link>
<p className="card-text mb-0" dangerouslySetInnerHTML={{ __html: item.shortText ? item.shortText : '' }}></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">{readTime}</div>
</div>
</div>
</div>
</CardFooter>
</Card>
}
interface BlogItems {
path?: string
totalPages?: number,
currentPage?: number,
items?: BlogItemModel []
}
const BlogItemsSection: FC<BlogItems> = ({
path = "",
totalPages = 1,
currentPage = 1,
items = []
}) => {
const dispatch = useDispatch()
const navigate = useNavigate()
return <>
{items.map((item, index) => <Col key={index} className="lg-6">
<Card className="mb-4">
<CardImg top {...item.image} />
<CardBody>
<div className="small text-muted">{dateFormat(item.created)}</div>
<h2 className="card-title h4">{item.title}</h2>
<p className="card-text">{item.shortText}</p>
<Link to={`${path}/${currentPage}/${item.slug}`} className="btn btn-primary">Read more </Link>
</CardBody>
</Card>
</Col>)}
<Pagination {...{
totalPages: totalPages,
currentPage: currentPage,
onClick: (nextPage) => {
dispatch(blogCatalogActionCreators.requestBlogCatalog({
currentPage: nextPage + ""
}))
navigate(`${path}/${nextPage}`)
}
}} />
</>
}
const BlogCatalog = () => {
const params = useParams()
const dispatch = useDispatch()
const { content, blogCatalog, blogCategories, blogFeatured } = useSelector((state: ApplicationState) => state)
const page = content?.blogCatalog
const path = findRoutes(content?.routes, 'BlogCatalog')[0]?.targets[0]
useEffect(() => {
// dispatch(blogCatalogActionCreators.requestBlogCatalog({
// currentPage: params?.page ? params.page : "1"
// }))
// dispatch(blogFeaturedActionCreators.requestBlogFeatured())
dispatch(blogCategoriesActionCreators.requestBlogCategories())
}, [])
useEffect(() => {
// blogCatalog?.isLoading
// ? dispatch(loaderActionCreators.show())
// : setTimeout(() => {
// dispatch(loaderActionCreators.hide())
// }, 1000)
}, [blogCatalog?.isLoading])
const blogItem = blogFeatured?.items[0]
const featuredBlog: FeaturedBlog = {
path: path,
currentPage: blogCatalog?.currentPage,
item: blogItem,
readTime: page?.featuredBlogSection?.readTime
}
if(featuredBlog.readTime && blogItem?.created && blogItem?.readTime)
featuredBlog.readTime = featuredBlog.readTime?.replace('{date}', dateFormat(blogItem.created))
.replace('{readTime}', `${blogItem.readTime}`)
return <>
<TitleSection {...page?.titleSection} />
<Container fluid>
<Row>
<Col>
<FeaturedBlogSection {...featuredBlog} />
<Row>
<BlogItemsSection path={path} {...blogCatalog} />
</Row>
</Col>
<Col lg="4">
<Search />
<Categories {...blogCategories} />
<Empty/>
</Col>
</Row>
</Container>
</>
}
export {
BlogCatalog
}