Files
LiquidCode_Frontend/src/views/home/account/articles/ArticlesBlock.tsx
Виталий Лавшонок fd34761745 add contests
2025-12-05 23:42:18 +03:00

149 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { FC, useEffect, useState } from 'react';
import { useAppDispatch, useAppSelector } from '../../../../redux/hooks';
import { setMenuActiveProfilePage } from '../../../../redux/slices/store';
import { cn } from '../../../../lib/cn';
import { ChevroneDown, Edit } from '../../../../assets/icons/groups';
import { useNavigate } from 'react-router-dom';
export interface ArticleItemProps {
id: number;
name: string;
createdAt: string;
}
export const formatDate = (isoDate?: string): string => {
if (!isoDate) return '';
const date = new Date(isoDate);
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
return `${day}.${month}.${year}`;
};
const ArticleItem: FC<ArticleItemProps> = ({ id, name, createdAt }) => {
const navigate = useNavigate();
return (
<div
className={cn(
'w-full relative rounded-[10px] text-liquid-white mb-[20px]',
'gap-[20px] px-[20px] py-[10px] box-border',
'border-b-[1px] border-b-liquid-lighter cursor-pointer hover:bg-liquid-lighter transition-all duration-300',
)}
onClick={() =>
navigate(`/article/${id}?back=/home/account/articles`)
}
>
<div className="h-[23px] flex">
<div className="text-[18px] font-bold w-[60px] mr-[20px] flex items-center">
#{id}
</div>
<div className="text-[18px] font-bold flex items-center">
{name}
</div>
</div>
<div className="text-[18px] flex text-liquid-light gap-[10px] mt-[20px]">
{`Опубликована ${formatDate(createdAt)}`}
</div>
<img
className="absolute right-[10px] top-[10px] h-[24px] w-[24px] hover:bg-liquid-light rounded-[5px] transition-all duration-300"
src={Edit}
alt="Редактировать"
onClick={(e) => {
e.stopPropagation();
navigate(
`/article/create?back=/home/account/articles&articleId=${id}`,
);
}}
/>
</div>
);
};
interface ArticlesBlockProps {
className?: string;
}
const ArticlesBlock: FC<ArticlesBlockProps> = ({ className = '' }) => {
const dispatch = useAppDispatch();
const [active, setActive] = useState<boolean>(true);
const { data: articleData } = useAppSelector(
(state) => state.profile.articles,
);
useEffect(() => {
dispatch(setMenuActiveProfilePage('articles'));
}, [dispatch]);
return (
<div className="h-full w-full relative p-[20px]">
<div
className={cn(
'border-b-[1px] border-b-liquid-lighter rounded-[10px]',
className,
)}
>
{/* Заголовок */}
<div
className={cn(
'h-[40px] text-[24px] font-bold flex gap-[10px] border-b-[1px] border-b-transparent items-center cursor-pointer transition-all duration-300',
active && 'border-b-liquid-lighter',
)}
onClick={() => setActive(!active)}
>
<span>Мои статьи</span>
<img
src={ChevroneDown}
alt="toggle"
className={cn(
'transition-all duration-300',
active && 'rotate-180',
)}
/>
</div>
{/* Контент */}
<div
className={cn(
'grid grid-flow-row grid-rows-[0fr] opacity-0 transition-all duration-300',
active && 'grid-rows-[1fr] opacity-100',
)}
>
<div className="overflow-hidden">
<div className="grid gap-[20px] pt-[20px] pb-[20px] box-border">
{status === 'loading' && (
<div className="text-liquid-light">
Загрузка статей...
</div>
)}
{status === 'failed' && (
<div className="text-liquid-red">Ошибка: </div>
)}
{status === 'successful' &&
articleData?.articles.items.length === 0 && (
<div className="text-liquid-light">
У вас пока нет статей
</div>
)}
{articleData?.articles.items.map((v, i) => (
<ArticleItem
key={i}
id={v.articleId}
name={v.title}
createdAt={v.createdAt}
/>
))}
</div>
</div>
</div>
</div>
</div>
);
};
export default ArticlesBlock;