improve files upload ui, and files fetching

This commit is contained in:
renzynx 2022-12-22 11:02:09 +07:00
parent 958ec11366
commit 541ee30239
10 changed files with 99 additions and 127 deletions

View File

View File

View File

View File

@ -71,6 +71,7 @@ export class UsersController {
(req.session as CustomSession).userId,
{
skip: +skip,
// @ts-ignore
take: take === "all" ? "all" : +take,
currentPage: +currentPage,
sort,

View File

@ -365,7 +365,7 @@ export class UsersService implements IUserService {
search = "",
}: {
skip: number;
take: number | "all";
take: number;
currentPage: number;
sort?: string;
search?: string;
@ -375,36 +375,13 @@ export class UsersService implements IUserService {
if (!user) {
throw new UnauthorizedException("not authorized");
}
const total = await this.prisma.file.count({
where: {
userId: id,
},
});
const total = await this.prisma.file.count({ where: { userId: id } });
if (take === "all") {
const files = await this.prisma.file.findMany({
where: {
userId: id,
filename: {
contains: search,
},
slug: {
contains: search,
},
},
orderBy: {
createdAt: sort === "newest" ? "asc" : "desc",
},
});
let finalSkip!: number;
let finalTake!: number;
return {
files,
totalFiles: total,
pages: 1,
};
}
const pages = Math.ceil(total / take);
// @ts-ignore
const pages = take === "all" ? 1 : Math.ceil(total / take);
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
// ^^
@ -412,10 +389,8 @@ export class UsersService implements IUserService {
// 1 to 10 is page 1
// total = 20, take = 10, skip = 0
let finalSkip!: number;
let finalTake!: number;
if (sort === "newest") {
// @ts-ignore
if (sort === "newest" && take !== "all") {
// total = 20, take = 10, skip = 0 page: 1
// total = 20, take = 12, skip = 10 page: 2 error
// take = total - skip
@ -427,65 +402,20 @@ export class UsersService implements IUserService {
finalTake = take;
}
} else {
finalSkip = skip;
finalTake = take;
}
if (search) {
const files = await this.prisma.file
.findMany({
where: {
userId: id,
OR: [
{
filename: {
contains: search,
},
},
{
slug: {
contains: search,
},
},
],
},
orderBy: {
createdAt: sort === "newest" ? "asc" : "desc",
},
})
.then((files) => {
switch (sort) {
case "largest":
files.sort((a, b) => b.size - a.size);
break;
case "smallest":
files.sort((a, b) => a.size - b.size);
break;
case "a-z":
files.sort((a, b) => a.filename.localeCompare(b.filename));
break;
case "z-a":
files.sort((a, b) => b.filename.localeCompare(a.filename));
break;
}
return files.map((file) => ({
...file,
size: formatBytes(file.size),
}));
});
return {
files,
totalFiles: files.length,
totalPages: 1,
};
// @ts-ignore
finalSkip = take === "all" ? 0 : skip;
// @ts-ignore
finalTake = take === "all" ? total : take;
}
const files = await this.prisma.file
.findMany({
where: {
userId: id,
OR: [
{ filename: { contains: search } },
{ slug: { contains: search } },
],
},
skip: finalSkip,
take: finalTake,
@ -507,6 +437,8 @@ export class UsersService implements IUserService {
case "z-a":
files.sort((a, b) => b.filename.localeCompare(a.filename));
break;
case "newest":
take !== total && files.reverse();
}
return files.map((file) => ({
...file,

View File

View File

@ -103,6 +103,7 @@ const FileViewer = () => {
onChange={(value) => {
if (!files?.length) return;
setLimit(value === 'all' ? 'all' : parseInt(value!));
value === 'all' ? setPage(1) : null;
}}
/>
<Select
@ -162,7 +163,7 @@ const FileViewer = () => {
<SimpleGrid
cols={3}
breakpoints={[
{ maxWidth: 1280, cols: 3, spacing: 'md' },
{ maxWidth: 1024, cols: 2, spacing: 'md' },
{ maxWidth: 840, cols: 2, spacing: 'sm' },
{ maxWidth: 600, cols: 1, spacing: 'sm' },
]}

View File

@ -1,27 +1,30 @@
import { Paper, Progress, Stack, Text } from '@mantine/core';
import { Group, Paper, Progress, Stack, Text } from '@mantine/core';
import { FC } from 'react';
const ProgressCard: FC<{ progress: number; filename: string }> = ({
filename,
progress,
}) => {
const ProgressCard: FC<{
progress: number;
filename: string;
speed: string;
}> = ({ filename, progress, speed }) => {
return (
<>
<Paper withBorder p="lg" my="xs" sx={{ width: '100%' }}>
<Stack>
<Text size="lg" weight="bold">
{filename}
</Text>
<Progress
size="xl"
sections={[
{
value: progress,
color: progress === 100 ? 'teal' : 'blue',
label: progress === 100 ? 'Done' : `${progress}%`,
},
]}
/>
<Stack justify="space-between">
<Group position="apart">
<Text
size="md"
weight="bold"
sx={{
msWordBreak: 'break-all',
}}
>
{filename.length > 67 ? filename.slice(0, 67) + '...' : filename}
</Text>
<Text size="sm" color="dimmed">
{speed} - {progress}%
</Text>
</Group>
<Progress size="sm" value={progress} />
</Stack>
</Paper>
</>

View File

@ -1,4 +1,10 @@
import { Button, Group, Text, useMantineTheme } from '@mantine/core';
import {
Button,
Group,
SimpleGrid,
Text,
useMantineTheme,
} from '@mantine/core';
import { Dropzone } from '@mantine/dropzone';
import { IconCheck, IconCloudUpload, IconDownload, IconX } from '@tabler/icons';
import dynamic from 'next/dynamic';
@ -11,6 +17,7 @@ import { userAtom } from '@lib/atoms';
import { showNotification } from '@mantine/notifications';
const ProgressCard = dynamic(() => import('./ProgressCard'));
import { ACCEPT_TYPE } from '@lib/constants';
import { formatBytes } from '@lib/utils';
const UploadZone = () => {
const [user] = useAtom(userAtom);
@ -39,10 +46,19 @@ const UploadZone = () => {
Authorization: user?.apiKey,
};
axios
.post(API_URL + API_ROUTES.UPLOAD_FILE, data, { headers })
.post(API_URL + API_ROUTES.UPLOAD_FILE, data, {
headers,
onUploadProgress: (evt) => {
// @ts-ignore
// prettier-ignore
file.speed = evt.loaded / ((new Date().getTime() - file.start) / 1000);
},
})
.then((response) => {
const file = files[currentFileIndex!];
const filesize = file.size;
// @ts-ignore
file.start = new Date().getTime();
const chunks = Math.ceil(filesize / CHUNK_SIZE) - 1;
const isLastChunk = currentChunkIndex === chunks;
if (isLastChunk) {
@ -61,8 +77,8 @@ const UploadZone = () => {
const isLastFile = currentFileIndex === files.length - 1;
if (isLastFile) {
setCurrentFileIndex(null);
setLastUploadedFileIndex(currentFileIndex);
setCurrentFileIndex(null);
}
} else {
setCurrentChunkIndex(currentChunkIndex! + 1);
@ -187,26 +203,34 @@ const UploadZone = () => {
Select files
</Button>
</div>
{files.map((file, idx) => {
let progress = 0;
// @ts-ignore
if (file.final) {
progress = 100;
} else {
const uploading = idx === currentFileIndex;
const chunks = Math.ceil(file.size / CHUNK_SIZE);
if (uploading) {
const rounder = (currentChunkIndex! / chunks) * 100;
progress = +rounder.toFixed(2);
<SimpleGrid cols={2} breakpoints={[{ maxWidth: 768, cols: 1 }]}>
{files.map((file, idx) => {
let progress = 0;
// @ts-ignore
if (file.final) {
progress = 100;
} else {
progress = 0;
const uploading = idx === currentFileIndex;
const chunks = Math.ceil(file.size / CHUNK_SIZE);
if (uploading) {
const rounder = (currentChunkIndex! / chunks) * 100;
progress = +rounder.toFixed(2);
} else {
progress = 0;
}
}
}
return (
<ProgressCard key={idx} filename={file.name} progress={progress} />
);
})}
return (
<ProgressCard
key={idx}
filename={file.name}
progress={progress}
// @ts-ignore
speed={file.speed ? `${formatBytes(file.speed)}/s` : 'Waiting...'}
/>
);
})}
</SimpleGrid>
</>
);
};

View File

@ -80,3 +80,14 @@ export const serializeURL = (url: string) => {
// remove http(s)://
return url.replace(/(^\w+:|^)\/\//, '');
};
export const formatBytes = (bytes: number, decimals = 2) => {
if (bytes === 0) return '0 Bytes';
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return parseFloat(
(bytes / Math.pow(1024, i)).toFixed(decimals < 0 ? 0 : decimals)
)
.toString()
.concat(` ${sizes[i]}`);
};