search result
This commit is contained in:
parent
4b8a42f2a1
commit
cd0594f25b
|
|
@ -15,6 +15,7 @@ import "./styles/style.scss";
|
|||
import Main from "./pages/Main";
|
||||
import NewsArticle from "./pages/NewsArticle";
|
||||
import Category from "./pages/Category";
|
||||
import SearchResult from "./pages/SearchResult";
|
||||
|
||||
// Components
|
||||
import Header from "./components/header/Header";
|
||||
|
|
@ -31,6 +32,7 @@ const App = () => {
|
|||
<Route path="/" element={<Main />} />
|
||||
<Route path="/category/:category" element={<Category />} />
|
||||
<Route path="/news/:id" element={<NewsArticle />} />
|
||||
<Route path="/search/:word" element={<SearchResult />} />
|
||||
</Routes>
|
||||
</AnimatePresence>
|
||||
<Footer />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.999 22L19.999 20M11.499 21C12.7466 21 13.9819 20.7543 15.1345 20.2769C16.2871 19.7994 17.3344 19.0997 18.2165 18.2175C19.0987 17.3354 19.7985 16.2881 20.2759 15.1355C20.7533 13.9829 20.999 12.7476 20.999 11.5C20.999 10.2524 20.7533 9.0171 20.2759 7.86451C19.7985 6.71191 19.0987 5.66464 18.2165 4.78249C17.3344 3.90033 16.2871 3.20056 15.1345 2.72314C13.9819 2.24572 12.7466 2 11.499 2C8.97947 2 6.56311 3.00089 4.78151 4.78249C2.99991 6.56408 1.99902 8.98044 1.99902 11.5C1.99902 14.0196 2.99991 16.4359 4.78151 18.2175C6.56311 19.9991 8.97947 21 11.499 21V21Z" stroke="#272727" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 764 B |
|
|
@ -0,0 +1,52 @@
|
|||
// Modules
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
// Components
|
||||
import News from "../news/News";
|
||||
import Loader from "./Loader";
|
||||
|
||||
// Types
|
||||
import { IPostsData } from "../../types/data.types";
|
||||
|
||||
interface IProps {
|
||||
data: IPostsData[];
|
||||
word: string | undefined;
|
||||
}
|
||||
|
||||
const CustomNewsScroll = ({ data, word }: IProps) => {
|
||||
return (
|
||||
<div className="news-scroll">
|
||||
<div className="news-scroll-wrapper">
|
||||
<div className="news-scroll-inner">
|
||||
{data.length > 0 ? (
|
||||
data[0].id > -1 ? (
|
||||
data.map((dataEl) => {
|
||||
return (
|
||||
<News
|
||||
key={uuidv4()}
|
||||
id={dataEl.id}
|
||||
title={dataEl.title}
|
||||
text={dataEl.excerpt}
|
||||
date={dataEl.published_at}
|
||||
categories={dataEl.categories}
|
||||
img={
|
||||
dataEl.featured_images[0]
|
||||
? dataEl.featured_images[0].path
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Loader />
|
||||
)
|
||||
) : (
|
||||
<p className="scroll-empty">Нет новостей для "{word || ""}" </p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomNewsScroll;
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
import { Dispatch, SetStateAction } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
// Animations
|
||||
import {
|
||||
|
|
@ -32,12 +33,15 @@ const Search = ({ isSmall, isInputFocused, setIsInputFocused }: IProps) => {
|
|||
(state) => state.search.value
|
||||
);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<motion.form
|
||||
className="search"
|
||||
onSubmit={(event: React.FormEvent<HTMLFormElement>) =>
|
||||
event.preventDefault()
|
||||
}
|
||||
onSubmit={(event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
navigate(`/search/${inputValue}`);
|
||||
}}
|
||||
variants={searchMobileMotion}
|
||||
initial={isSmall ? "borderRest" : {}}
|
||||
animate={isSmall ? (isInputFocused ? "borderActive" : "borderRest") : {}}
|
||||
|
|
@ -53,6 +57,7 @@ const Search = ({ isSmall, isInputFocused, setIsInputFocused }: IProps) => {
|
|||
}}
|
||||
onBlur={() => {
|
||||
setIsInputFocused(false);
|
||||
onInputChange("");
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
// Modules
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Api } from "../api/Api";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { IPostData, RootState } from "../types/store.types";
|
||||
|
||||
// Icons
|
||||
import { ReactComponent as LoopBlack } from "../assets/icons/loop-black.svg";
|
||||
import { IurlParamAdder } from "../types/api.types";
|
||||
import { setNewsScroll } from "../actions/setData";
|
||||
|
||||
// Components
|
||||
import CustomNewsScroll from "../components/global/CustomNewsScroll";
|
||||
import { IPostsData } from "../types/data.types";
|
||||
|
||||
const SearchResult = () => {
|
||||
const { word } = useParams();
|
||||
const [params, setParams] = useState<IurlParamAdder[]>([
|
||||
{
|
||||
name: "s",
|
||||
value: word || "",
|
||||
},
|
||||
{
|
||||
name: "count",
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
name: "page",
|
||||
value: 1,
|
||||
},
|
||||
]);
|
||||
const api = new Api("/post", params);
|
||||
const language = api.language;
|
||||
const [lastLanguage, setLastLanguage] = useState(language);
|
||||
|
||||
// redux
|
||||
const data = useSelector<RootState, RootState["searchData"]["data"]>(
|
||||
(state) => state.searchData.data
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
api.get(data, (data: IPostsData[]) => dispatch(setNewsScroll(data)));
|
||||
}, [params]);
|
||||
return (
|
||||
<main className="sresult">
|
||||
<div className="container">
|
||||
<div className="sresult-inner">
|
||||
<div className="sresult-title">
|
||||
<LoopBlack />
|
||||
<h1>Результаты по поиску "{word}"</h1>
|
||||
</div>
|
||||
<div className="sresult-content">
|
||||
<CustomNewsScroll data={data as any} word={word} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchResult;
|
||||
|
|
@ -127,3 +127,17 @@ export const postReducer = (
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const searchDataReducer = (
|
||||
state: IPostData = postInitialState,
|
||||
action: IPostDataAction
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case "SET_POST": {
|
||||
return { ...state, data: action.payload };
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ import { combineReducers, configureStore } from "@reduxjs/toolkit";
|
|||
// Reducers
|
||||
import { activeLinkReducer } from "../reducers/activeLink.reducer";
|
||||
import { languageReducer } from "../reducers/language.reducer";
|
||||
import { newsScrollReducer, postReducer } from "../reducers/dataReducer";
|
||||
import {
|
||||
newsScrollReducer,
|
||||
postReducer,
|
||||
searchDataReducer,
|
||||
} from "../reducers/dataReducer";
|
||||
import { searchReducer } from "../reducers/searchReducer";
|
||||
|
||||
export const allReducers = combineReducers({
|
||||
|
|
@ -13,6 +17,7 @@ export const allReducers = combineReducers({
|
|||
newsScroll: newsScrollReducer,
|
||||
post: postReducer,
|
||||
search: searchReducer,
|
||||
searchData: searchDataReducer,
|
||||
});
|
||||
|
||||
export const functionalityStore = configureStore({
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
|
||||
span {
|
||||
width: fit-content;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
.sresult-inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5.6rem;
|
||||
padding: 5.6rem 0;
|
||||
}
|
||||
|
||||
.sresult-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2.4rem;
|
||||
|
||||
h1 {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,3 +14,4 @@
|
|||
@import "./category";
|
||||
@import "./calendar";
|
||||
@import "./loader";
|
||||
@import "./search-result";
|
||||
|
|
|
|||
Loading…
Reference in New Issue