diff --git a/backend/src/share/dto/myShare.dto.ts b/backend/src/share/dto/myShare.dto.ts index ef29c22e0..8b75883f0 100644 --- a/backend/src/share/dto/myShare.dto.ts +++ b/backend/src/share/dto/myShare.dto.ts @@ -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[]; + from(partial: Partial) { return plainToClass(MyShareDTO, partial, { excludeExtraneousValues: true }); } @@ -20,4 +30,4 @@ export class MyShareDTO extends ShareDTO { plainToClass(MyShareDTO, part, { excludeExtraneousValues: true }) ); } -} +} \ No newline at end of file diff --git a/backend/src/share/share.service.ts b/backend/src/share/share.service.ts index 43927cc72..b75218be2 100644 --- a/backend/src/share/share.service.ts +++ b/backend/src/share/share.service.ts @@ -195,7 +195,7 @@ export class ShareService { orderBy: { expiration: "desc", }, - include: { recipients: true }, + include: { recipients: true, files: true }, }); return shares.map((share) => { diff --git a/frontend/src/components/account/showShareInformationsModal.tsx b/frontend/src/components/account/showShareInformationsModal.tsx new file mode 100644 index 000000000..6ec4064bc --- /dev/null +++ b/frontend/src/components/account/showShareInformationsModal.tsx @@ -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: ( + + + ID: {share.id} + + + + Description: {share.description || "No description"} + + + + Created at: {formattedCreatedAt} + + + + Expires at: {formattedExpiration} + + + + + + + + + + Size: {formattedShareSize} / {formattedMaxShareSize} ( + {shareSizeProgress.toFixed(1)}%) + + + + {shareSize / maxShareSize < 0.1 && ( + + {formattedShareSize} + + )} + = 0.1 ? formattedShareSize : ""} + style={{ width: shareSize / maxShareSize < 0.1 ? "70%" : "80%" }} + size="xl" + radius="xl" + /> + + {formattedMaxShareSize} + + + + ), + }); +}; + +export default showShareInformationsModal; diff --git a/frontend/src/pages/account/shares.tsx b/frontend/src/pages/account/shares.tsx index abd4d446c..c54333dee 100644 --- a/frontend/src/pages/account/shares.tsx +++ b/frontend/src/pages/account/shares.tsx @@ -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 = () => { Name + + Description + + Visitors Expires at @@ -69,6 +75,18 @@ const MyShares = () => { {shares.map((share) => ( {share.id} + + + {share.description || ""} + + {share.views} {moment(share.expiration).unix() === 0 @@ -77,6 +95,21 @@ const MyShares = () => { + { + showShareInformationsModal( + modals, + share, + config.get("general.appUrl"), + parseInt(config.get("share.maxSize")) + ); + }} + > + +