add file preview and download file
This commit is contained in:
@@ -12,6 +12,19 @@ interface FileModerationModalProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const getLabel = (status: string) => {
|
||||
switch (status) {
|
||||
case 'BLOCKED':
|
||||
return 'Заблокировано';
|
||||
case 'MODERATION':
|
||||
return 'На модерации';
|
||||
case 'ACTIVE':
|
||||
return 'Одобрено';
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
const StatusBadge = ({ status }: { status: string }) => {
|
||||
const getBadgeClass = () => {
|
||||
switch (status) {
|
||||
@@ -19,29 +32,15 @@ const StatusBadge = ({ status }: { status: string }) => {
|
||||
return 'status-badge--blocked';
|
||||
case 'MODERATION':
|
||||
return 'status-badge--moderation';
|
||||
case 'APPROVED':
|
||||
case 'ACTIVE':
|
||||
return 'status-badge--approved';
|
||||
default:
|
||||
return 'status-badge--default';
|
||||
}
|
||||
};
|
||||
|
||||
const getLabel = () => {
|
||||
switch (status) {
|
||||
case 'BLOCKED':
|
||||
return 'Заблокировано';
|
||||
case 'MODERATION':
|
||||
return 'На модерации';
|
||||
case 'APPROVED':
|
||||
return 'Одобрено';
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<span className={getBadgeClass()}>
|
||||
{getLabel()}
|
||||
{getLabel(status)}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
@@ -107,11 +106,12 @@ export default function FileModerationModal({ file, onClose }: FileModerationMod
|
||||
<div className="file-moderation-modal__status-change-section">
|
||||
<label className="file-moderation-modal__status-change-label">Изменить статус</label>
|
||||
<DropDownList
|
||||
value={selectedStatus}
|
||||
value={getLabel(selectedStatus)}
|
||||
callBack={(value: string) => setSelectedStatus(value)}
|
||||
>
|
||||
<li value="MODERATION">На модерации</li>
|
||||
<li value="BLOCKED">Заблокировано</li>
|
||||
<li value="ACTIVE">Одобрено</li>
|
||||
</DropDownList>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
SortingState,
|
||||
ColumnFiltersState,
|
||||
} from '@tanstack/react-table';
|
||||
import { IconEye, IconDoubleArrowRight, IconArrowRight, IconDoubleArrowLeft, IconArrowLeft, IconArrowUp, IconArrowDown, IconFilter } from '@/app/ui/icons/icons';
|
||||
import { IconEye, IconDoubleArrowRight, IconArrowRight, IconDoubleArrowLeft, IconArrowLeft, IconArrowUp, IconArrowDown, IconFilter, IconFileDownload } from '@/app/ui/icons/icons';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import DropDownList from '@/app/components/dropDownList';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
@@ -19,6 +19,15 @@ import ModalWindow from '@/app/components/modalWindow';
|
||||
import { toast } from 'sonner';
|
||||
import { useContentForModeration, ModerationFile, ContentForModeration } from '@/app/hooks/react-query/useContentForModeration';
|
||||
import FileModerationModal from './FileModerationModal';
|
||||
import { FileTypeIcon } from '@/app/components/FileTypeIcon';
|
||||
import { getFileType } from '@/app/lib/getFileType';
|
||||
import Image from 'next/image';
|
||||
|
||||
const cutFileExtension = (fileName: string) => {
|
||||
const lastDotIndex = fileName.lastIndexOf('.');
|
||||
const extension = fileName.substring(lastDotIndex + 1);
|
||||
return extension;
|
||||
}
|
||||
|
||||
const cutFileName = (fileName: string) => {
|
||||
const MAX_FILE_NAME_LENGTH = 30;
|
||||
@@ -69,8 +78,8 @@ export default function ContentModerationTable({ permission }: { permission: num
|
||||
pageSize: 10,
|
||||
});
|
||||
const [openWindow, setOpenWindow] = useState<boolean>(false);
|
||||
const [openWindowChildren, setOpenWindowChildren] = useState<ReactNode>(null);
|
||||
const [selectedFile, setSelectedFile] = useState<ModerationFile | null>(null);
|
||||
const [isFileLoading, setIsFileLoading] = useState(false);
|
||||
|
||||
const t = useTranslations("Global");
|
||||
|
||||
@@ -82,7 +91,7 @@ export default function ContentModerationTable({ permission }: { permission: num
|
||||
|
||||
const sort = sorting[0];
|
||||
const sortByMap: Record<string, string> = {
|
||||
'fileName': 'fileName',
|
||||
'fileName': 'originalFileName',
|
||||
'userId': 'userId',
|
||||
'status': 'status',
|
||||
'createdAt': 'createdAt',
|
||||
@@ -124,6 +133,36 @@ export default function ContentModerationTable({ permission }: { permission: num
|
||||
setSelectedFile(null);
|
||||
}, []);
|
||||
|
||||
const handleDownload = async (file: any) => {
|
||||
setIsFileLoading(true);
|
||||
console.log(file.downloadUrl);
|
||||
|
||||
try {
|
||||
const response = await fetch(file.downloadUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Download failed');
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = file._original?.fileName || file.fileName || `file-${file.id}`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
|
||||
toast.success(`${t('file-is-downloading')} - ${file.fileName}`);
|
||||
} catch (error) {
|
||||
console.error('Download error:', error);
|
||||
toast.error(t('failed-to-download-file'));
|
||||
} finally {
|
||||
setIsFileLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
const columns = useMemo<ColumnDef<ModerationFile>[]>(() => {
|
||||
const allColumns: ColumnDef<ModerationFile>[] = [
|
||||
{
|
||||
@@ -147,9 +186,32 @@ export default function ContentModerationTable({ permission }: { permission: num
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center table-item">
|
||||
<div className="font-medium w-full truncate" title={row.original.fileName}>
|
||||
{cutFileName(row.original.fileName)}
|
||||
<div className="flex items-center space-x-2 table-item table-item-file-name">
|
||||
{getFileType(row.original.fileName) === 'image' && row.original?.image.length !== 0 ? (
|
||||
<span
|
||||
className="table-item-file-name-image-wrapper"
|
||||
>
|
||||
<Image
|
||||
sizes="40px"
|
||||
src={row.original?.image}
|
||||
alt={row.original?.fileName}
|
||||
unoptimized
|
||||
fill
|
||||
onError={(e) => {
|
||||
const target = e.target as HTMLImageElement;
|
||||
target.src = '/images/no-image.png';
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<FileTypeIcon type={row.original.fileName} />
|
||||
)}
|
||||
<div>
|
||||
<div className="font-medium w-full truncate" title={row.original.fileName}>
|
||||
<span className="font-semibold">
|
||||
{cutFileName(row.original.fileName)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
@@ -207,7 +269,7 @@ export default function ContentModerationTable({ permission }: { permission: num
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
/* {
|
||||
accessorKey: 'moderationInfo.hasActiveAppeal',
|
||||
header: ({ column }) => (
|
||||
<div className="column">
|
||||
@@ -236,7 +298,7 @@ export default function ContentModerationTable({ permission }: { permission: num
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
}
|
||||
} */
|
||||
];
|
||||
|
||||
if (permission === 3) {
|
||||
@@ -253,6 +315,15 @@ export default function ContentModerationTable({ permission }: { permission: num
|
||||
>
|
||||
<IconEye />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => handleDownload(row.original)}
|
||||
disabled={isFileLoading}
|
||||
className="table-action-download"
|
||||
title={t('download')}
|
||||
>
|
||||
<IconFileDownload />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user