Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adding more informations on My Shares page (table and modal) #174

Merged
merged 17 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions backend/src/share/dto/myShare.dto.ts
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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 });
}
Expand All @@ -20,4 +30,4 @@ export class MyShareDTO extends ShareDTO {
plainToClass(MyShareDTO, part, { excludeExtraneousValues: true })
);
}
}
}
2 changes: 1 addition & 1 deletion backend/src/share/share.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ export class ShareService {
orderBy: {
expiration: "desc",
},
include: { recipients: true },
include: { recipients: true, files: true },
});

return shares.map((share) => {
Expand Down
92 changes: 92 additions & 0 deletions frontend/src/components/account/showShareInformationsModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
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 | string
pierrbt marked this conversation as resolved.
Show resolved Hide resolved
) => {
const link = `${appUrl}/share/${share.id}`;

let shareSize: number = 0;
for (let file of share.files as FileMetaData[])
shareSize += parseInt(file.size);

if (typeof maxShareSize === "string") maxShareSize = parseInt(maxShareSize);
pierrbt marked this conversation as resolved.
Show resolved Hide resolved

const formattedShareSize = byteToHumanSizeString(shareSize);
const formattedMaxShareSize = byteToHumanSizeString(maxShareSize);
const shareProgress = (shareSize / maxShareSize) * 100;
pierrbt marked this conversation as resolved.
Show resolved Hide resolved

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>Creator:</b> You
</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} (
{shareProgress.toFixed(1)}%)
</Text>

<Flex align="center" justify="center">
{shareSize / maxShareSize < 0.1 && (
<Text size="xs" color="lightgray" style={{ marginRight: "4px" }}>
{formattedShareSize}
</Text>
)}
<Progress
value={shareProgress}
label={shareSize / maxShareSize >= 0.1 ? formattedShareSize : ""}
color="blue"
pierrbt marked this conversation as resolved.
Show resolved Hide resolved
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;
20 changes: 19 additions & 1 deletion frontend/src/pages/account/shares.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ 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";
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();
Expand Down Expand Up @@ -60,6 +61,7 @@ const MyShares = () => {
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Visitors</th>
<th>Expires at</th>
<th></th>
Expand All @@ -69,6 +71,7 @@ const MyShares = () => {
{shares.map((share) => (
<tr key={share.id}>
<td>{share.id}</td>
<td>{share.description || ""}</td>
<td>{share.views}</td>
<td>
{moment(share.expiration).unix() === 0
Expand All @@ -77,6 +80,21 @@ const MyShares = () => {
</td>
<td>
<Group position="right">
<ActionIcon
color="blue"
variant="light"
size={25}
onClick={() => {
showShareInformationsModal(
modals,
share,
config.get("general.appUrl"),
config.get("share.maxSize")
pierrbt marked this conversation as resolved.
Show resolved Hide resolved
);
}}
>
<TbInfoCircle />
</ActionIcon>
<ActionIcon
color="victoria"
variant="light"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/types/share.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type ShareMetaData = {

export type MyShare = Share & {
views: number;
cratedAt: Date;
createdAt: Date;
};

export type MyReverseShare = {
Expand Down