mirror of
https://github.com/stonith404/pingvin-share.git
synced 2025-02-19 01:55:48 -05:00
feat: Adding more informations on My Shares page (table and modal) (#174)
* Adding an information button to the shares and corrected MyShare interface * Adding other informations and disk usage * Adding description, disk usage * Add case if the expiration is never * Adding file size and better UI * UI changes to Information Modal * Adding description to the My Shares page * Ran format * Remove string type Co-authored-by: Elias Schneider <login@eliasschneider.com> * Remove string type check Co-authored-by: Elias Schneider <login@eliasschneider.com> * Remove string type conversion Co-authored-by: Elias Schneider <login@eliasschneider.com> * Variable name changes Co-authored-by: Elias Schneider <login@eliasschneider.com> * Remove color Co-authored-by: Elias Schneider <login@eliasschneider.com> * Requested changes made * Ran format * Adding MediaQuery --------- Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
parent
348852cfa4
commit
1466240461
5 changed files with 134 additions and 6 deletions
|
@ -1,7 +1,13 @@
|
|||
import { Expose, plainToClass } from "class-transformer";
|
||||
import { Expose, plainToClass, Type } from "class-transformer";
|
||||
import { ShareDTO } from "./share.dto";
|
||||
import {FileDTO} from "../../file/dto/file.dto";
|
||||
import {OmitType} from "@nestjs/swagger";
|
||||
|
||||
export class MyShareDTO extends ShareDTO {
|
||||
export class MyShareDTO extends OmitType(ShareDTO, [
|
||||
"files",
|
||||
"from",
|
||||
"fromList",
|
||||
] as const) {
|
||||
@Expose()
|
||||
views: number;
|
||||
|
||||
|
@ -11,6 +17,10 @@ export class MyShareDTO extends ShareDTO {
|
|||
@Expose()
|
||||
recipients: string[];
|
||||
|
||||
@Expose()
|
||||
@Type(() => OmitType(FileDTO, ["share", "from"] as const))
|
||||
files: Omit<FileDTO, "share" | "from">[];
|
||||
|
||||
from(partial: Partial<MyShareDTO>) {
|
||||
return plainToClass(MyShareDTO, partial, { excludeExtraneousValues: true });
|
||||
}
|
||||
|
@ -20,4 +30,4 @@ export class MyShareDTO extends ShareDTO {
|
|||
plainToClass(MyShareDTO, part, { excludeExtraneousValues: true })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -195,7 +195,7 @@ export class ShareService {
|
|||
orderBy: {
|
||||
expiration: "desc",
|
||||
},
|
||||
include: { recipients: true },
|
||||
include: { recipients: true, files: true },
|
||||
});
|
||||
|
||||
return shares.map((share) => {
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
import { Text, Divider, Progress, Stack, Group, Flex } from "@mantine/core";
|
||||
import { ModalsContextProps } from "@mantine/modals/lib/context";
|
||||
import { MyShare } from "../../types/share.type";
|
||||
import moment from "moment";
|
||||
import { byteToHumanSizeString } from "../../utils/fileSize.util";
|
||||
import CopyTextField from "../upload/CopyTextField";
|
||||
import { FileMetaData } from "../../types/File.type";
|
||||
|
||||
const showShareInformationsModal = (
|
||||
modals: ModalsContextProps,
|
||||
share: MyShare,
|
||||
appUrl: string,
|
||||
maxShareSize: number
|
||||
) => {
|
||||
const link = `${appUrl}/share/${share.id}`;
|
||||
|
||||
let shareSize: number = 0;
|
||||
for (let file of share.files as FileMetaData[])
|
||||
shareSize += parseInt(file.size);
|
||||
|
||||
const formattedShareSize = byteToHumanSizeString(shareSize);
|
||||
const formattedMaxShareSize = byteToHumanSizeString(maxShareSize);
|
||||
const shareSizeProgress = (shareSize / maxShareSize) * 100;
|
||||
|
||||
const formattedCreatedAt = moment(share.createdAt).format("LLL");
|
||||
const formattedExpiration =
|
||||
moment(share.expiration).unix() === 0
|
||||
? "Never"
|
||||
: moment(share.expiration).format("LLL");
|
||||
|
||||
return modals.openModal({
|
||||
title: "Share informations",
|
||||
|
||||
children: (
|
||||
<Stack align="stretch" spacing="md">
|
||||
<Text size="sm" color="lightgray">
|
||||
<b>ID:</b> {share.id}
|
||||
</Text>
|
||||
|
||||
<Text size="sm" color="lightgray">
|
||||
<b>Description:</b> {share.description || "No description"}
|
||||
</Text>
|
||||
|
||||
<Text size="sm" color="lightgray">
|
||||
<b>Created at:</b> {formattedCreatedAt}
|
||||
</Text>
|
||||
|
||||
<Text size="sm" color="lightgray">
|
||||
<b>Expires at:</b> {formattedExpiration}
|
||||
</Text>
|
||||
|
||||
<Divider />
|
||||
|
||||
<CopyTextField link={link} />
|
||||
|
||||
<Divider />
|
||||
|
||||
<Text size="sm" color="lightgray">
|
||||
<b>Size:</b> {formattedShareSize} / {formattedMaxShareSize} (
|
||||
{shareSizeProgress.toFixed(1)}%)
|
||||
</Text>
|
||||
|
||||
<Flex align="center" justify="center">
|
||||
{shareSize / maxShareSize < 0.1 && (
|
||||
<Text size="xs" color="lightgray" style={{ marginRight: "4px" }}>
|
||||
{formattedShareSize}
|
||||
</Text>
|
||||
)}
|
||||
<Progress
|
||||
value={shareSizeProgress}
|
||||
label={shareSize / maxShareSize >= 0.1 ? formattedShareSize : ""}
|
||||
style={{ width: shareSize / maxShareSize < 0.1 ? "70%" : "80%" }}
|
||||
size="xl"
|
||||
radius="xl"
|
||||
/>
|
||||
<Text size="xs" color="lightgray" style={{ marginLeft: "4px" }}>
|
||||
{formattedMaxShareSize}
|
||||
</Text>
|
||||
</Flex>
|
||||
</Stack>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
export default showShareInformationsModal;
|
|
@ -4,6 +4,7 @@ import {
|
|||
Button,
|
||||
Center,
|
||||
Group,
|
||||
MediaQuery,
|
||||
Space,
|
||||
Stack,
|
||||
Table,
|
||||
|
@ -15,7 +16,7 @@ import { useModals } from "@mantine/modals";
|
|||
import moment from "moment";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
import { TbLink, TbTrash } from "react-icons/tb";
|
||||
import { TbLink, TbTrash, TbInfoCircle } from "react-icons/tb";
|
||||
import showShareLinkModal from "../../components/account/showShareLinkModal";
|
||||
import CenterLoader from "../../components/core/CenterLoader";
|
||||
import Meta from "../../components/Meta";
|
||||
|
@ -23,6 +24,7 @@ import useConfig from "../../hooks/config.hook";
|
|||
import shareService from "../../services/share.service";
|
||||
import { MyShare } from "../../types/share.type";
|
||||
import toast from "../../utils/toast.util";
|
||||
import showShareInformationsModal from "../../components/account/showShareInformationsModal";
|
||||
|
||||
const MyShares = () => {
|
||||
const modals = useModals();
|
||||
|
@ -60,6 +62,10 @@ const MyShares = () => {
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<MediaQuery smallerThan="md" styles={{ display: "none" }}>
|
||||
<th>Description</th>
|
||||
</MediaQuery>
|
||||
|
||||
<th>Visitors</th>
|
||||
<th>Expires at</th>
|
||||
<th></th>
|
||||
|
@ -69,6 +75,18 @@ const MyShares = () => {
|
|||
{shares.map((share) => (
|
||||
<tr key={share.id}>
|
||||
<td>{share.id}</td>
|
||||
<MediaQuery smallerThan="sm" styles={{ display: "none" }}>
|
||||
<td
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: "300px",
|
||||
}}
|
||||
>
|
||||
{share.description || ""}
|
||||
</td>
|
||||
</MediaQuery>
|
||||
<td>{share.views}</td>
|
||||
<td>
|
||||
{moment(share.expiration).unix() === 0
|
||||
|
@ -77,6 +95,21 @@ const MyShares = () => {
|
|||
</td>
|
||||
<td>
|
||||
<Group position="right">
|
||||
<ActionIcon
|
||||
color="blue"
|
||||
variant="light"
|
||||
size={25}
|
||||
onClick={() => {
|
||||
showShareInformationsModal(
|
||||
modals,
|
||||
share,
|
||||
config.get("general.appUrl"),
|
||||
parseInt(config.get("share.maxSize"))
|
||||
);
|
||||
}}
|
||||
>
|
||||
<TbInfoCircle />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
color="victoria"
|
||||
variant="light"
|
||||
|
|
|
@ -24,7 +24,7 @@ export type ShareMetaData = {
|
|||
|
||||
export type MyShare = Share & {
|
||||
views: number;
|
||||
cratedAt: Date;
|
||||
createdAt: Date;
|
||||
};
|
||||
|
||||
export type MyReverseShare = {
|
||||
|
|
Loading…
Add table
Reference in a new issue