Files
pingvin-share/frontend/src/pages/account/reverseShares.tsx
2024-11-26 20:58:32 +01:00

260 lines
9.6 KiB
TypeScript

import {
Accordion,
ActionIcon,
Anchor,
Box,
Button,
Center,
Group,
Stack,
Table,
Text,
Title,
Tooltip,
} from "@mantine/core";
import { useClipboard } from "@mantine/hooks";
import { useModals } from "@mantine/modals";
import moment from "moment";
import { useEffect, useState } from "react";
import { TbInfoCircle, TbLink, TbPlus, TbTrash } from "react-icons/tb";
import { FormattedMessage } from "react-intl";
import Meta from "../../components/Meta";
import showReverseShareLinkModal from "../../components/account/showReverseShareLinkModal";
import showShareLinkModal from "../../components/account/showShareLinkModal";
import CenterLoader from "../../components/core/CenterLoader";
import showCreateReverseShareModal from "../../components/share/modals/showCreateReverseShareModal";
import useConfig from "../../hooks/config.hook";
import useTranslate from "../../hooks/useTranslate.hook";
import shareService from "../../services/share.service";
import { MyReverseShare } from "../../types/share.type";
import { byteToHumanSizeString } from "../../utils/fileSize.util";
import toast from "../../utils/toast.util";
const MyShares = () => {
const modals = useModals();
const clipboard = useClipboard();
const t = useTranslate();
const config = useConfig();
const [reverseShares, setReverseShares] = useState<MyReverseShare[]>();
const getReverseShares = () => {
shareService
.getMyReverseShares()
.then((shares) => setReverseShares(shares));
};
useEffect(() => {
getReverseShares();
}, []);
if (!reverseShares) return <CenterLoader />;
return (
<>
<Meta title={t("account.reverseShares.title")} />
<Group position="apart" align="baseline" mb={20}>
<Group align="center" spacing={3} mb={30}>
<Title order={3}>
<FormattedMessage id="account.reverseShares.title" />
</Title>
<Tooltip
position="bottom"
multiline
width={220}
label={t("account.reverseShares.description")}
events={{ hover: true, focus: false, touch: true }}
>
<ActionIcon>
<TbInfoCircle />
</ActionIcon>
</Tooltip>
</Group>
<Button
onClick={() =>
showCreateReverseShareModal(
modals,
config.get("smtp.enabled"),
config.get("share.maxExpiration"),
getReverseShares,
)
}
leftIcon={<TbPlus size={20} />}
>
<FormattedMessage id="common.button.create" />
</Button>
</Group>
{reverseShares.length == 0 ? (
<Center style={{ height: "70vh" }}>
<Stack align="center" spacing={10}>
<Title order={3}>
<FormattedMessage id="account.reverseShares.title.empty" />
</Title>
<Text>
<FormattedMessage id="account.reverseShares.description.empty" />
</Text>
</Stack>
</Center>
) : (
<Box sx={{ display: "block", overflowX: "auto" }}>
<Table>
<thead>
<tr>
<th>
<FormattedMessage id="account.reverseShares.table.shares" />
</th>
<th>
<FormattedMessage id="account.reverseShares.table.remaining" />
</th>
<th>
<FormattedMessage id="account.reverseShares.table.max-size" />
</th>
<th>
<FormattedMessage id="account.reverseShares.table.expires" />
</th>
<th></th>
</tr>
</thead>
<tbody>
{reverseShares.map((reverseShare) => (
<tr key={reverseShare.id}>
<td style={{ width: 220 }}>
{reverseShare.shares.length == 0 ? (
<Text color="dimmed" size="sm">
<FormattedMessage id="account.reverseShares.table.no-shares" />
</Text>
) : (
<Accordion>
<Accordion.Item
value="customization"
sx={{ borderBottom: "none" }}
>
<Accordion.Control p={0}>
<Text size="sm">
{reverseShare.shares.length == 1
? `1 ${t(
"account.reverseShares.table.count.singular",
)}`
: `${reverseShare.shares.length} ${t(
"account.reverseShares.table.count.plural",
)}`}
</Text>
</Accordion.Control>
<Accordion.Panel>
{reverseShare.shares.map((share) => (
<Group key={share.id} mb={4}>
<Anchor
href={`${window.location.origin}/share/${share.id}`}
target="_blank"
>
<Text maw={120} truncate>
{share.id}
</Text>
</Anchor>
<ActionIcon
color="victoria"
variant="light"
size={25}
onClick={() => {
if (window.isSecureContext) {
clipboard.copy(
`${window.location.origin}/s/${share.id}`,
);
toast.success(
t("common.notify.copied-link"),
);
} else {
showShareLinkModal(modals, share.id);
}
}}
>
<TbLink />
</ActionIcon>
</Group>
))}
</Accordion.Panel>
</Accordion.Item>
</Accordion>
)}
</td>
<td>{reverseShare.remainingUses}</td>
<td>
{byteToHumanSizeString(parseInt(reverseShare.maxShareSize))}
</td>
<td>
{moment(reverseShare.shareExpiration).unix() === 0
? "Never"
: moment(reverseShare.shareExpiration).format("LLL")}
</td>
<td>
<Group position="right">
<ActionIcon
color="victoria"
variant="light"
size={25}
onClick={() => {
if (window.isSecureContext) {
clipboard.copy(
`${window.location.origin}/upload/${
reverseShare.token
}`,
);
toast.success(t("common.notify.copied-link"));
} else {
showReverseShareLinkModal(
modals,
reverseShare.token,
);
}
}}
>
<TbLink />
</ActionIcon>
<ActionIcon
color="red"
variant="light"
size={25}
onClick={() => {
modals.openConfirmModal({
title: t(
"account.reverseShares.modal.delete.title",
),
children: (
<Text size="sm">
<FormattedMessage id="account.reverseShares.modal.delete.description" />
</Text>
),
confirmProps: {
color: "red",
},
labels: {
confirm: t("common.button.delete"),
cancel: t("common.button.cancel"),
},
onConfirm: () => {
shareService.removeReverseShare(reverseShare.id);
setReverseShares(
reverseShares.filter(
(item) => item.id !== reverseShare.id,
),
);
},
});
}}
>
<TbTrash />
</ActionIcon>
</Group>
</td>
</tr>
))}
</tbody>
</Table>
</Box>
)}
</>
);
};
export default MyShares;