forked from Transparency/kgroad-frontend2
225 lines
6.1 KiB
TypeScript
225 lines
6.1 KiB
TypeScript
"use client";
|
||
|
||
import "./ReviewSection.scss";
|
||
import { apiInstance } from "@/shared/config/apiConfig";
|
||
import { IReviewList } from "@/shared/types/review-type";
|
||
import { signIn, useSession } from "next-auth/react";
|
||
import { useEffect, useRef, useState } from "react";
|
||
import calendar from "./icons/calendar.svg";
|
||
import Image from "next/image";
|
||
import {
|
||
Link,
|
||
usePathname,
|
||
useRouter,
|
||
} from "@/shared/config/navigation";
|
||
import Loader from "@/shared/ui/components/Loader/Loader";
|
||
|
||
interface IReviewsSectionProps {
|
||
endpoint: string;
|
||
id: number;
|
||
}
|
||
|
||
const ReviewSection: React.FC<IReviewsSectionProps> = ({
|
||
endpoint,
|
||
id,
|
||
}: IReviewsSectionProps) => {
|
||
const lastElement = useRef<HTMLDivElement | null>(null);
|
||
const observer = useRef<IntersectionObserver | null>(null);
|
||
const [reviews, setReviews] = useState<IReviewList>({
|
||
count: 0,
|
||
next: null,
|
||
previous: null,
|
||
results: [
|
||
{
|
||
id: 0,
|
||
author: {
|
||
image: "",
|
||
id: 0,
|
||
first_name: "",
|
||
last_name: "",
|
||
govern_status: null,
|
||
},
|
||
review: "",
|
||
created_at: "",
|
||
},
|
||
],
|
||
});
|
||
const [pageSize, setPageSize] = useState<number>(8);
|
||
const [reviewCount, setReviewCount] = useState<number>(0);
|
||
const [loader, setLoader] = useState<boolean>(false);
|
||
const pathname = usePathname();
|
||
const session = useSession();
|
||
const handleSubmit: React.MouseEventHandler<
|
||
HTMLFormElement
|
||
> = async (e) => {
|
||
e.preventDefault();
|
||
const Authorization = `Bearer ${session.data?.access_token}`;
|
||
|
||
const formData = new FormData(e.currentTarget);
|
||
|
||
const config = {
|
||
headers: {
|
||
Authorization,
|
||
},
|
||
};
|
||
|
||
if (session.status === "unauthenticated") {
|
||
signIn(undefined, { callbackUrl: pathname });
|
||
}
|
||
|
||
if (!formData.get("review")) {
|
||
return;
|
||
}
|
||
|
||
formData.append("news", id.toString());
|
||
|
||
try {
|
||
const res = await apiInstance.post(
|
||
`/${endpoint}/${id}/reviews/`,
|
||
formData,
|
||
config
|
||
);
|
||
|
||
getReviews();
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
};
|
||
|
||
const getReviews = async () => {
|
||
setLoader(true);
|
||
const response = await apiInstance.get<IReviewList>(
|
||
`/${endpoint}/${id}/reviews/?page_size=${pageSize}`
|
||
);
|
||
|
||
setReviewCount(response.data.count);
|
||
setLoader(false);
|
||
setReviews({
|
||
count: response.data.count,
|
||
next: response.data.next,
|
||
previous: response.data.previous,
|
||
results: [...reviews?.results, ...response.data.results],
|
||
});
|
||
setReviews(response?.data);
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (loader) return;
|
||
if (observer.current) observer.current.disconnect();
|
||
const callback = function (entries: any) {
|
||
if (
|
||
entries[0].isIntersecting &&
|
||
(reviews?.results.length as number) <= reviewCount
|
||
) {
|
||
if (pageSize < reviewCount) {
|
||
setPageSize((prev) => prev + 8);
|
||
} else {
|
||
setPageSize(reviewCount);
|
||
}
|
||
}
|
||
};
|
||
observer.current = new IntersectionObserver(callback);
|
||
observer.current.observe(lastElement.current as HTMLDivElement);
|
||
}, [loader]);
|
||
|
||
useEffect(() => {
|
||
getReviews();
|
||
}, [pageSize]);
|
||
|
||
const months: Record<string, string> = {
|
||
"01": "Январь",
|
||
"02": "Февраль",
|
||
"03": "Март",
|
||
"04": "Апрель",
|
||
"05": "Май",
|
||
"06": "Июнь",
|
||
"07": "Июль",
|
||
"08": "Август",
|
||
"09": "Сентябрь",
|
||
"10": "Октябрь",
|
||
"11": "Ноябрь",
|
||
"12": "Декабрь",
|
||
};
|
||
|
||
return (
|
||
<section className="review-section">
|
||
<h3>
|
||
<span id="blue-point" /> Написать комментарий
|
||
</h3>
|
||
|
||
{session.status === "authenticated" ? (
|
||
<form onSubmit={handleSubmit}>
|
||
<textarea name="review" />
|
||
<button type="submit">Отправить</button>
|
||
</form>
|
||
) : (
|
||
<p className="review-section__auth-warning">
|
||
Перед тем как оставить комментарий, пожалуйста
|
||
<button
|
||
onClick={() =>
|
||
signIn(undefined, { callbackUrl: pathname })
|
||
}
|
||
>
|
||
войдите в аккаунт
|
||
</button>
|
||
</p>
|
||
)}
|
||
|
||
<div className="review-section__list">
|
||
<h3>
|
||
<span id="blue-point" /> Комментарии
|
||
</h3>
|
||
|
||
{reviews?.results.length !== 0 ? (
|
||
<ul key="unuqie key">
|
||
{reviews?.results.map((review) => (
|
||
<li key={review.id} className="review">
|
||
<div className="review__author">
|
||
<img
|
||
id="author-img"
|
||
src={review.author.image}
|
||
alt="Author Image"
|
||
/>
|
||
<div className="review__header">
|
||
<h5 className="review__author-name">
|
||
{review.author.first_name}{" "}
|
||
{review.author.last_name}
|
||
</h5>
|
||
<div className="review__date">
|
||
<Image src={calendar} alt="Calendar Icon" />
|
||
<p>
|
||
{months[review.created_at.slice(5, 7)]}{" "}
|
||
{review.created_at.slice(5, 7).slice(0, 1) ===
|
||
"0"
|
||
? review.created_at.slice(6, 7)
|
||
: review.created_at.slice(5, 7)}
|
||
, {review.created_at.slice(0, 4)}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p className="review__description">{review.review}</p>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
) : (
|
||
<p className="review-section__warning">
|
||
Оставьте комментарий первым :)
|
||
</p>
|
||
)}
|
||
{loader ? (
|
||
<div className="review-section__loader">
|
||
<Loader color="#000" />
|
||
</div>
|
||
) : null}
|
||
<div
|
||
ref={lastElement}
|
||
className="review-section__list_bottom"
|
||
></div>
|
||
</div>
|
||
</section>
|
||
);
|
||
};
|
||
|
||
export default ReviewSection;
|