Add news page
This commit is contained in:
parent
3b510b6d42
commit
d601659289
@ -6,8 +6,8 @@ const nextConfig = {
|
|||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
protocol: "https",
|
protocol: "http",
|
||||||
hostname: "**",
|
hostname: "***",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
22
src/app/[locale]/news/page.tsx
Normal file
22
src/app/[locale]/news/page.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Container, Title } from "@/shared/ui";
|
||||||
|
import NewsList from "@/widgets/NewsList/NewsList";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const News = ({
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
searchParams: {
|
||||||
|
["страница-новостей"]: string;
|
||||||
|
};
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col bg-[#FAFCFF]">
|
||||||
|
<Container>
|
||||||
|
<Title text="Новости" className="mb-[40px]" />
|
||||||
|
<NewsList searchParams={searchParams} />
|
||||||
|
</Container>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default News;
|
50
src/entities/NewsCard.tsx
Normal file
50
src/entities/NewsCard.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { Title } from "@/shared/ui";
|
||||||
|
import Image, { StaticImageData } from "next/image";
|
||||||
|
|
||||||
|
interface INewsCard {
|
||||||
|
id: number;
|
||||||
|
image: StaticImageData | string;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
const NewsCard = ({ id, image, title, content, date }: INewsCard) => {
|
||||||
|
const sliceTitle = (title: string) => {
|
||||||
|
if (title.length > 35) {
|
||||||
|
return `${title.slice(0, 35)}...`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return title;
|
||||||
|
};
|
||||||
|
const sliceDescription = (content: string) => {
|
||||||
|
if (content.length > 65) {
|
||||||
|
return `${content.slice(0, 65)}...`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
};
|
||||||
|
const sliceDate = (date: string) => {
|
||||||
|
return `${date.slice(8, 10)}/${date.slice(5, 7)}/${date.slice(0, 4)}`;
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="w-[393px] h-[508px] bg-white shadow-sm p-6 flex flex-col">
|
||||||
|
<Image
|
||||||
|
src={image}
|
||||||
|
alt="Card image"
|
||||||
|
width={345}
|
||||||
|
height={240}
|
||||||
|
className="mb-[32px]"
|
||||||
|
/>
|
||||||
|
<Title
|
||||||
|
text={sliceTitle(title)}
|
||||||
|
className="text-[24px] font-semibold mb-[12px]"
|
||||||
|
/>
|
||||||
|
<p className="leading-6 text-gray-600 mb-[46px]">
|
||||||
|
{sliceDescription(content)}
|
||||||
|
</p>
|
||||||
|
<p className="text-[14px] text-gray-600">{sliceDate(date)}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NewsCard;
|
13
src/shared/types/news-type.ts
Normal file
13
src/shared/types/news-type.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { IList } from "./list-type";
|
||||||
|
|
||||||
|
export interface INews {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
image: string;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface INewsList extends IList {
|
||||||
|
results: INews[];
|
||||||
|
}
|
56
src/widgets/NewsList/NewsList.tsx
Normal file
56
src/widgets/NewsList/NewsList.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useNewsStore } from "./newsStore";
|
||||||
|
import NewsCard from "@/entities/NewsCard";
|
||||||
|
import Pagination from "@/features/Pagination/Pagination";
|
||||||
|
|
||||||
|
interface INewsListProps {
|
||||||
|
searchParams: {
|
||||||
|
["страница-новостей"]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const NewsList: React.FC<INewsListProps> = ({
|
||||||
|
searchParams,
|
||||||
|
}: INewsListProps) => {
|
||||||
|
const [activePage, setActivePage] = useState<number>(
|
||||||
|
+searchParams["страница-новостей"] || 1
|
||||||
|
);
|
||||||
|
const { data: news, getNews, isLoading, error } = useNewsStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getNews(activePage);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<ul className="flex gap-[30px] flex-wrap mb-[96px]">
|
||||||
|
{news.results.map((news) => (
|
||||||
|
<li key={news.id}>
|
||||||
|
<NewsCard
|
||||||
|
id={news.id}
|
||||||
|
title={news.title}
|
||||||
|
content={news.content}
|
||||||
|
image={news.image}
|
||||||
|
date={news.created_at}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<hr></hr>
|
||||||
|
<div className="mx-auto mb-[96px]">
|
||||||
|
<Pagination
|
||||||
|
activePage={activePage}
|
||||||
|
setActivePage={setActivePage}
|
||||||
|
prev={news.previous}
|
||||||
|
next={news.next}
|
||||||
|
count={news.count as number}
|
||||||
|
current_count={news.results.length}
|
||||||
|
limit={20}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NewsList;
|
38
src/widgets/NewsList/newsStore.ts
Normal file
38
src/widgets/NewsList/newsStore.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { apiInstance } from "@/shared/config/apiConfig";
|
||||||
|
import { IFetch } from "@/shared/types/fetch-type";
|
||||||
|
import { INewsList } from "@/shared/types/news-type";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
import { create } from "zustand";
|
||||||
|
|
||||||
|
interface useNewsStore extends IFetch {
|
||||||
|
data: INewsList;
|
||||||
|
getNews: (page: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNewsStore = create<useNewsStore>((set) => ({
|
||||||
|
data: {
|
||||||
|
count: 0,
|
||||||
|
previous: null,
|
||||||
|
next: null,
|
||||||
|
results: [],
|
||||||
|
},
|
||||||
|
error: "",
|
||||||
|
isLoading: false,
|
||||||
|
getNews: async (page: number) => {
|
||||||
|
try {
|
||||||
|
set({ isLoading: true });
|
||||||
|
|
||||||
|
const res = await apiInstance.get(`/news/`);
|
||||||
|
|
||||||
|
set({ data: res.data });
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof AxiosError) {
|
||||||
|
set({ error: error.message });
|
||||||
|
} else {
|
||||||
|
set({ error: "An error ocured" });
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
set({ isLoading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
Loading…
Reference in New Issue
Block a user