From 318e13074b4d94037f0e10e2e62281634903fd23 Mon Sep 17 00:00:00 2001 From: Kakabay Date: Tue, 28 Feb 2023 15:28:51 +0500 Subject: [PATCH] video section --- src/actions/setData.ts | 31 ++--- src/api/params.ts | 33 +++-- src/components/aside/AsideLast.tsx | 7 ++ src/components/global/NewsCategory.tsx | 2 +- src/components/global/NewsScroll.tsx | 50 ++++---- src/components/videos/Videos.tsx | 67 +++++----- src/components/videos/VideosItem.tsx | 20 ++- src/pages/Main.tsx | 17 ++- src/pages/NewsArticle.tsx | 61 ++++----- src/reducers/dataReducer.ts | 163 +++++++++++++------------ src/store/functionality.ts | 12 +- src/styles/_news.scss | 2 +- src/types/store.types.ts | 40 +++--- src/types/videos.types.ts | 2 + 14 files changed, 266 insertions(+), 241 deletions(-) create mode 100644 src/components/aside/AsideLast.tsx diff --git a/src/actions/setData.ts b/src/actions/setData.ts index 25e7f25..85de568 100644 --- a/src/actions/setData.ts +++ b/src/actions/setData.ts @@ -8,34 +8,35 @@ import { IPostDataAction, ISearchResult, ISearchResultAction, -} from "../types/store.types"; + IVideoData, + IVideoDataAction, +} from '../types/store.types'; // NewsScroll -export const setNewsScroll = ( - data: INewsScroll["data"] -): INewsScrollAction => ({ - type: "SET_NEWS_SCROLL", +export const setNewsScroll = (data: INewsScroll['data']): INewsScrollAction => ({ + type: 'SET_NEWS_SCROLL', payload: data, }); -export const setSearchResult = ( - data: ISearchResult["data"] -): ISearchResultAction => ({ - type: "SET_SEARCH_DATA", +export const setSearchResult = (data: ISearchResult['data']): ISearchResultAction => ({ + type: 'SET_SEARCH_DATA', payload: data, }); // Post -export const setPost = (data: IPostData["data"]): IPostDataAction => ({ - type: "SET_POST", +export const setPost = (data: IPostData['data']): IPostDataAction => ({ + type: 'SET_POST', payload: data, }); -export const setFeatured = ( - data: IFeaturedData["data"] -): IFeaturedDataAction => ({ - type: "SET_FEATURED", +export const setVideo = (data: IVideoData['data']): IVideoDataAction => ({ + type: 'SET_VIDEO', + payload: data, +}); + +export const setFeatured = (data: IFeaturedData['data']): IFeaturedDataAction => ({ + type: 'SET_FEATURED', payload: data, }); diff --git a/src/api/params.ts b/src/api/params.ts index 7118b67..224c031 100644 --- a/src/api/params.ts +++ b/src/api/params.ts @@ -1,38 +1,53 @@ -import { IurlParamAdder } from "../types/api.types"; +import { IurlParamAdder } from '../types/api.types'; export const newsScrollParams: IurlParamAdder[] = [ { - name: "count", + name: 'count', value: 5, }, { - name: "page", + name: 'page', value: 1, }, ]; export const categoriesParams: IurlParamAdder[] = [ { - name: "count", + name: 'count', value: 100, }, { - name: "page", + name: 'page', value: 1, }, ]; export const featuredParams: IurlParamAdder[] = [ { - name: "count", + name: 'count', value: 5, }, { - name: "page", + name: 'page', value: 1, }, { - name: "featured", - value: "true", + name: 'featured', + value: 'true', + }, +]; + +export const videoParams: IurlParamAdder[] = [ + { + name: 'count', + value: 5, + }, + { + name: 'page', + value: 1, + }, + { + name: 'type', + value: 'video', }, ]; diff --git a/src/components/aside/AsideLast.tsx b/src/components/aside/AsideLast.tsx new file mode 100644 index 0000000..acaa3d1 --- /dev/null +++ b/src/components/aside/AsideLast.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const AsideLast = () => { + return
AsideLast
; +}; + +export default AsideLast; diff --git a/src/components/global/NewsCategory.tsx b/src/components/global/NewsCategory.tsx index 22577b0..d216f28 100644 --- a/src/components/global/NewsCategory.tsx +++ b/src/components/global/NewsCategory.tsx @@ -1,5 +1,5 @@ // Modules -import { Link } from "react-router-dom"; +// import { Link } from "react-router-dom"; interface Props { title: string; diff --git a/src/components/global/NewsScroll.tsx b/src/components/global/NewsScroll.tsx index 8d5179e..a6e98c7 100644 --- a/src/components/global/NewsScroll.tsx +++ b/src/components/global/NewsScroll.tsx @@ -1,24 +1,24 @@ // Modules -import { useEffect, useState } from "react"; -import { v4 as uuidv4 } from "uuid"; -import { useSelector, useDispatch } from "react-redux"; +import { useEffect, useState } from 'react'; +import { v4 as uuidv4 } from 'uuid'; +import { useSelector, useDispatch } from 'react-redux'; // Components -import News from "../news/News"; -import SectionTitle from "./SectionTitle"; -import Loader from "./Loader"; +import News from '../news/News'; +import SectionTitle from './SectionTitle'; +import Loader from './Loader'; // Api -import { url } from "../../url"; -import { Api } from "../../api/Api"; -import { newsScrollParams } from "../../api/params"; +import { url } from '../../url'; +import { Api } from '../../api/Api'; +import { newsScrollParams } from '../../api/params'; // Types -import { IPostsData } from "../../types/data.types"; -import { RootState } from "../../types/store.types"; +import { IPostsData } from '../../types/data.types'; +import { RootState } from '../../types/store.types'; // Actions -import { setNewsScroll } from "../../actions/setData"; +import { setNewsScroll } from '../../actions/setData'; interface Props { title: boolean; @@ -27,15 +27,15 @@ interface Props { const NewsScroll = ({ title, category }: Props) => { const params = newsScrollParams.slice(); - category ? params.push({ name: "category", value: category }) : null; + category ? params.push({ name: 'category', value: category }) : null; - const api = new Api(url + "/posts", params); + const api = new Api(url + '/posts', params); const language = api.language; const [lastLanguage, setLastLanguage] = useState(language); // redux - const rawData = useSelector( - (state) => state.newsScroll.data + const rawData = useSelector( + (state) => state.newsScroll.data, ); const dispatch = useDispatch(); @@ -46,12 +46,8 @@ const NewsScroll = ({ title, category }: Props) => { useEffect(() => { if (rawData.length > 0) { - if ( - !((rawData as IPostsData[])[0].id > -1 && lastLanguage === language) - ) { - api.get(rawData, (rawData: IPostsData[]) => - dispatch(setNewsScroll(rawData)) - ); + if (!((rawData as IPostsData[])[0].id > -1 && lastLanguage === language)) { + api.get(rawData, (rawData: IPostsData[]) => dispatch(setNewsScroll(rawData))); setLastLanguage(language); } } @@ -61,7 +57,7 @@ const NewsScroll = ({ title, category }: Props) => { useEffect(() => { const filtered = rawData.filter((el, index) => { - if (index > 0) { + if (index >= 0) { return el; } }); @@ -74,7 +70,7 @@ const NewsScroll = ({ title, category }: Props) => { {title === true ? ( ) : null}
@@ -89,11 +85,7 @@ const NewsScroll = ({ title, category }: Props) => { text={dataEl.excerpt} date={dataEl.published_at} categories={dataEl.categories} - img={ - dataEl.featured_images[0] - ? dataEl.featured_images[0].path - : "" - } + img={dataEl.featured_images[0] ? dataEl.featured_images[0].path : ''} /> ); }) diff --git a/src/components/videos/Videos.tsx b/src/components/videos/Videos.tsx index 16f2259..76ee61c 100644 --- a/src/components/videos/Videos.tsx +++ b/src/components/videos/Videos.tsx @@ -1,58 +1,61 @@ // Modules -// import { v4 as uuiv4 } from "uuid"; +import { useEffect, useState } from 'react'; +import { v4 as uuiv4 } from 'uuid'; +import { useSelector, useDispatch } from 'react-redux'; // Components -import SectionTitle from "../global/SectionTitle"; -// import VideosItem from "./VideosItem"; - -// // Videos -// import VideoPlaceholder from "../../assets/videos/placeholder.mp4"; +import SectionTitle from '../global/SectionTitle'; +import VideosItem from './VideosItem'; // Types -// import { videosDataType } from "../../types/videos.types"; +import { RootState } from '../../types/store.types'; -// const videosData: videosDataType[] = [ -// { -// placeholder: Placeholder, -// url: VideoPlaceholder, -// }, -// { -// placeholder: Placeholder, -// url: VideoPlaceholder, -// }, -// { -// placeholder: Placeholder, -// url: VideoPlaceholder, -// }, -// { -// placeholder: Placeholder, -// url: VideoPlaceholder, -// }, -// ]; +// Api +import { Api } from '../../api/Api'; +import { url } from '../../url'; +import { videoParams } from '../../api/params'; + +// Actions +import { setVideo } from '../../actions/setData'; const Videos = () => { + const data = useSelector((state) => state.video.data); + const api = new Api(url + '/posts', videoParams); + const language = api.language; + const dispatch = useDispatch(); + const [lastLanguage, setLastLanguage] = useState(language); + + useEffect(() => { + if (!(lastLanguage === language && data[0].id > -1)) { + api.get(data, (data) => dispatch(setVideo(data))); + setLastLanguage(language); + } + }, [lastLanguage, language]); + return (
- {/*
*/}
- {/* {videosData.map((videosDataItem: videosDataType) => { + {data.map((videosDataItem) => { return ( ); - })} */} + })}
- {/*
*/}
); }; diff --git a/src/components/videos/VideosItem.tsx b/src/components/videos/VideosItem.tsx index 8fbc195..db57308 100644 --- a/src/components/videos/VideosItem.tsx +++ b/src/components/videos/VideosItem.tsx @@ -1,26 +1,20 @@ // Modules -import ReactPlayer from "react-player"; -import { LazyLoadComponent } from "react-lazy-load-image-component"; +import ReactPlayer from 'react-player'; +import { LazyLoadComponent } from 'react-lazy-load-image-component'; // Types -import { videosDataType } from "../../types/videos.types"; +import { videosDataType } from '../../types/videos.types'; -const VideosItem = ({ url, placeholder }: videosDataType) => { +const VideosItem = ({ url, placeholder, date, excerpt }: videosDataType) => { return (
- +
- 11.01.2023 -

В Туркменистане отметили Новый год

+ {date} +

{excerpt}

diff --git a/src/pages/Main.tsx b/src/pages/Main.tsx index cdbf443..91579d4 100644 --- a/src/pages/Main.tsx +++ b/src/pages/Main.tsx @@ -1,11 +1,11 @@ // Modules -import { motion } from "framer-motion"; +import { motion } from 'framer-motion'; // Components -import Aside from "../components/aside/Aside"; -import NewsScroll from "../components/global/NewsScroll"; -// import Videos from "../components/videos/Videos"; -import MainContent from "../components/main/MainContent"; +import Aside from '../components/aside/Aside'; +import NewsScroll from '../components/global/NewsScroll'; +import Videos from '../components/videos/Videos'; +import MainContent from '../components/main/MainContent'; const Main = () => { return ( @@ -13,9 +13,8 @@ const Main = () => { className="main" initial={{ opacity: 0, scale: 0.8 }} animate={{ opacity: 1, scale: 1, transition: { duration: 0.15 } }} - exit={{ opacity: 0, scale: 0.8, transition: { duration: 0.15 } }} - > -

Туркменистан новостной портал

+ exit={{ opacity: 0, scale: 0.8, transition: { duration: 0.15 } }}> +

Туркменистан новостной портал

@@ -24,7 +23,7 @@ const Main = () => {
- {/* */} +
diff --git a/src/pages/NewsArticle.tsx b/src/pages/NewsArticle.tsx index 51a768c..df48c20 100644 --- a/src/pages/NewsArticle.tsx +++ b/src/pages/NewsArticle.tsx @@ -1,29 +1,29 @@ // Modules -import { Link, useParams } from "react-router-dom"; -import { useEffect, useState } from "react"; -import { useSelector, useDispatch } from "react-redux"; -import { v4 as uuidv4 } from "uuid"; -import { motion } from "framer-motion"; +import { Link, useParams } from 'react-router-dom'; +import { useEffect, useState } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { v4 as uuidv4 } from 'uuid'; +import { motion } from 'framer-motion'; // Components -import Aside from "../components/aside/Aside"; -import NewsArticleSlider from "../components/news/NewsArticleSlider"; -import Loader from "../components/global/Loader"; -import VideosItem from "../components/videos/VideosItem"; +import Aside from '../components/aside/Aside'; +import NewsArticleSlider from '../components/news/NewsArticleSlider'; +import Loader from '../components/global/Loader'; +// import VideosItem from "../components/videos/VideosItem"; // Icons -import { ReactComponent as Share } from "../assets/icons/share.svg"; +import { ReactComponent as Share } from '../assets/icons/share.svg'; // Types -import { RootState } from "../types/store.types"; -import { IPostData } from "../types/store.types"; +import { RootState } from '../types/store.types'; +import { IPostData } from '../types/store.types'; // Actions -import { setPost } from "../actions/setData"; +import { setPost } from '../actions/setData'; // Api -import { Api } from "../api/Api"; -import { url } from "../url"; +import { Api } from '../api/Api'; +import { url } from '../url'; const NewsArticle = () => { const { id } = useParams(); @@ -35,27 +35,21 @@ const NewsArticle = () => { const [lastLanguage, setLastLanguage] = useState(language); // redux - const data = useSelector( - (state) => state.post.data - ); + const data = useSelector((state) => state.post.data); const dispatch = useDispatch(); useEffect(() => { - if ( - !(data.data.id === parseInt(id as string) && lastLanguage === language) - ) { - api.get(data, (data: IPostData["data"]) => dispatch(setPost(data))); + if (!(data.data.id === parseInt(id as string) && lastLanguage === language)) { + api.get(data, (data: IPostData['data']) => dispatch(setPost(data))); setLastLanguage(language); } }, [language, lastLanguage]); // SEO useEffect(() => { - const metaDescription: any = document.querySelector( - "meta#meta-description" - ); - const metaKeywords: any = document.querySelector("meta#meta-keywords"); - const title: any = document.querySelector("title"); + const metaDescription: any = document.querySelector('meta#meta-description'); + const metaKeywords: any = document.querySelector('meta#meta-keywords'); + const title: any = document.querySelector('title'); try { title.innerText = data.data.powerseo_title; metaDescription.content = data.data.powerseo_description; @@ -70,8 +64,7 @@ const NewsArticle = () => { className="news-article" initial={{ opacity: 0, scale: 0.8 }} animate={{ opacity: 1, scale: 1, transition: { duration: 0.15 } }} - exit={{ opacity: 0, scale: 0.8, transition: { duration: 0.15 } }} - > + exit={{ opacity: 0, scale: 0.8, transition: { duration: 0.15 } }}>
{data.data.id > -1 ? ( @@ -83,16 +76,13 @@ const NewsArticle = () => { + className="news-article-category"> {category.name} ))}
-

- {data.data.published_at} -

+

{data.data.published_at}

{data.data.title}

@@ -114,8 +104,7 @@ const NewsArticle = () => {

+ dangerouslySetInnerHTML={{ __html: data.data.content_html }}>

diff --git a/src/reducers/dataReducer.ts b/src/reducers/dataReducer.ts index 27a3d83..acb8135 100644 --- a/src/reducers/dataReducer.ts +++ b/src/reducers/dataReducer.ts @@ -8,7 +8,9 @@ import { IPostDataAction, ISearchResult, ISearchResultAction, -} from "../types/store.types"; + IVideoData, + IVideoDataAction, +} from '../types/store.types'; // NewsScroll @@ -16,54 +18,54 @@ export const newsScrollInitialState = { data: [ { id: -1, - title: "", - slug: "", - excerpt: "", - published_at: "", + title: '', + slug: '', + excerpt: '', + published_at: '', featured_images: [ { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, ], - content_html: "", + content_html: '', categories: [ { id: -1, - name: "", + name: '', }, ], video: null, - powerseo_title: "", - powerseo_description: "", - powerseo_keywords: "", + powerseo_title: '', + powerseo_description: '', + powerseo_keywords: '', }, ], }; export const newsScrollReducer = ( state: INewsScroll = newsScrollInitialState, - action: INewsScrollAction + action: INewsScrollAction, ) => { switch (action.type) { - case "SET_NEWS_SCROLL": { + case 'SET_NEWS_SCROLL': { return { ...state, data: action.payload }; } default: { @@ -78,54 +80,51 @@ export const postInitialState = { data: { data: { id: -1, - title: "", - slug: "", - excerpt: "", - published_at: "", + title: '', + slug: '', + excerpt: '', + published_at: '', video: null, featured_images: [ { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, ], - content_html: "", + content_html: '', categories: [ { id: -1, - name: "", + name: '', }, ], - powerseo_title: "", - powerseo_description: "", - powerseo_keywords: "", + powerseo_title: '', + powerseo_description: '', + powerseo_keywords: '', }, }, }; -export const postReducer = ( - state: IPostData = postInitialState, - action: IPostDataAction -) => { +export const postReducer = (state: IPostData = postInitialState, action: IPostDataAction) => { switch (action.type) { - case "SET_POST": { + case 'SET_POST': { return { ...state, data: action.payload }; } default: { @@ -138,54 +137,54 @@ export const featuredInitialState = { data: [ { id: -1, - title: "", - slug: "", - excerpt: "", - published_at: "", + title: '', + slug: '', + excerpt: '', + published_at: '', video: null, featured_images: [ { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, { id: -1, - disk_name: "", - file_name: "", - path: "", - extension: "", + disk_name: '', + file_name: '', + path: '', + extension: '', }, ], - content_html: "", + content_html: '', categories: [ { id: -1, - name: "", + name: '', }, ], - powerseo_title: "", - powerseo_description: "", - powerseo_keywords: "", + powerseo_title: '', + powerseo_description: '', + powerseo_keywords: '', }, ], }; export const featuredReducer = ( state: IFeaturedData = featuredInitialState, - action: IFeaturedDataAction + action: IFeaturedDataAction, ) => { switch (action.type) { - case "SET_FEATURED": { + case 'SET_FEATURED': { return { ...state, data: action.payload }; } default: { @@ -196,10 +195,10 @@ export const featuredReducer = ( export const searchDataReducer = ( state: ISearchResult = newsScrollInitialState, - action: ISearchResultAction + action: ISearchResultAction, ) => { switch (action.type) { - case "SET_SEARCH_DATA": { + case 'SET_SEARCH_DATA': { return { data: action.payload }; } default: { @@ -207,3 +206,17 @@ export const searchDataReducer = ( } } }; + +export const videoReducer = ( + state: IVideoData = newsScrollInitialState, + action: IVideoDataAction, +) => { + switch (action.type) { + case 'SET_VIDEO': { + return { ...state, data: action.payload }; + } + default: { + return state; + } + } +}; diff --git a/src/store/functionality.ts b/src/store/functionality.ts index d8c1a44..2db8002 100644 --- a/src/store/functionality.ts +++ b/src/store/functionality.ts @@ -1,16 +1,17 @@ // Modules -import { combineReducers, configureStore } from "@reduxjs/toolkit"; +import { combineReducers, configureStore } from '@reduxjs/toolkit'; // Reducers -import { activeLinkReducer } from "../reducers/activeLink.reducer"; -import { languageReducer } from "../reducers/language.reducer"; +import { activeLinkReducer } from '../reducers/activeLink.reducer'; +import { languageReducer } from '../reducers/language.reducer'; import { newsScrollReducer, postReducer, searchDataReducer, featuredReducer, -} from "../reducers/dataReducer"; -import { searchReducer } from "../reducers/searchReducer"; + videoReducer, +} from '../reducers/dataReducer'; +import { searchReducer } from '../reducers/searchReducer'; export const allReducers = combineReducers({ activeLink: activeLinkReducer, @@ -20,6 +21,7 @@ export const allReducers = combineReducers({ search: searchReducer, searchData: searchDataReducer, featured: featuredReducer, + video: videoReducer, }); export const functionalityStore = configureStore({ diff --git a/src/styles/_news.scss b/src/styles/_news.scss index 2f28406..e1a4703 100644 --- a/src/styles/_news.scss +++ b/src/styles/_news.scss @@ -1,7 +1,7 @@ .news-wrapper { display: grid; grid-template-columns: 32rem 1fr; - grid-template-rows: 20rem; + grid-template-rows: 22rem; gap: 1.6rem; .loader { diff --git a/src/types/store.types.ts b/src/types/store.types.ts index 75ff779..cfe9ef0 100644 --- a/src/types/store.types.ts +++ b/src/types/store.types.ts @@ -1,26 +1,26 @@ // Reducers -import { allReducers } from "../store/functionality"; +import { allReducers } from '../store/functionality'; // Types -import { IPostsData } from "./data.types"; +import { IPostsData } from './data.types'; // NavLink export interface ActiveLinkType { active: number; } export interface ActiveLinkActionType { - type: "SET_ACTIVE_LINK"; + type: 'SET_ACTIVE_LINK'; payload: number; } // Language export interface ILanguage { - title: "RU" | "EN" | "TM"; + title: 'RU' | 'EN' | 'TM'; } export interface ILanguageAction { - type: "SET_LANGUAGE"; - payload: "RU" | "EN" | "TM"; + type: 'SET_LANGUAGE'; + payload: 'RU' | 'EN' | 'TM'; } // NewsScroll @@ -29,8 +29,8 @@ export interface INewsScroll { data: IPostsData[]; } export interface INewsScrollAction { - type: "SET_NEWS_SCROLL"; - payload: INewsScroll["data"]; + type: 'SET_NEWS_SCROLL'; + payload: INewsScroll['data']; } // Post @@ -42,16 +42,24 @@ export interface IPostData { } export interface IPostDataAction { - type: "SET_POST"; - payload: IPostData["data"]; + type: 'SET_POST'; + payload: IPostData['data']; +} +export interface IVideoData { + data: IPostsData[]; +} + +export interface IVideoDataAction { + type: 'SET_VIDEO'; + payload: INewsScroll['data']; } export interface IFeaturedData { data: IPostsData[]; } export interface IFeaturedDataAction { - type: "SET_FEATURED"; - payload: IFeaturedData["data"]; + type: 'SET_FEATURED'; + payload: IFeaturedData['data']; } // @@ -60,16 +68,16 @@ export interface ISearchData { value: string; } export interface ISearchDataAction { - type: "SET_SEARCH"; - payload: ISearchData["value"]; + type: 'SET_SEARCH'; + payload: ISearchData['value']; } export interface ISearchResult { data: IPostsData[]; } export interface ISearchResultAction { - type: "SET_SEARCH_DATA"; - payload: ISearchResult["data"]; + type: 'SET_SEARCH_DATA'; + payload: ISearchResult['data']; } // ALL TYPES BEFORE THIS LINE ================== diff --git a/src/types/videos.types.ts b/src/types/videos.types.ts index 8a925fd..106e81f 100644 --- a/src/types/videos.types.ts +++ b/src/types/videos.types.ts @@ -1,4 +1,6 @@ export interface videosDataType { url: string; placeholder: string; + date: string; + excerpt: string; }