This commit is contained in:
Manav Rathi
2024-11-09 16:34:05 +05:30
parent 6b4c514010
commit 6265a56128
3 changed files with 269 additions and 275 deletions

View File

@@ -4,7 +4,7 @@ import { PublicLinkCreated } from "@/new/photos/components/share/PublicLinkCreat
import { useEffect, useState } from "react";
import { appendCollectionKeyToShareURL } from "utils/collection";
import EnablePublicShareOptions from "./EnablePublicShareOptions";
import ManagePublicShare from "./managePublicShare";
import { ManagePublicShare } from "./managePublicShare";
export default function PublicShare({
collection,

View File

@@ -1,266 +0,0 @@
import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu";
import { SidebarDrawer } from "@/base/components/mui/SidebarDrawer";
import { Titlebar } from "@/base/components/Titlebar";
import type {
Collection,
PublicURL,
UpdatePublicURL,
} from "@/media/collection";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import ChevronRight from "@mui/icons-material/ChevronRight";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import RemoveCircleOutline from "@mui/icons-material/RemoveCircleOutline";
import { DialogProps, Stack, Typography } from "@mui/material";
import { t } from "i18next";
import { GalleryContext } from "pages/gallery";
import { useContext, useMemo, useState } from "react";
import {
deleteShareableURL,
updateShareableURL,
} from "services/collectionService";
import { SetPublicShareProp } from "types/publicCollection";
import { getDeviceLimitOptions } from "utils/collection";
import { handleSharingErrors } from "utils/error/ui";
import { ManageDownloadAccess } from "./downloadAccess";
import { ManageLinkExpiry } from "./linkExpiry";
import { ManageLinkPassword } from "./linkPassword";
import { ManagePublicCollect } from "./publicCollect";
interface ManagePublicShareOptionsProps {
publicShareProp: PublicURL;
collection: Collection;
setPublicShareProp: SetPublicShareProp;
open: boolean;
onClose: () => void;
onRootClose: () => void;
publicShareUrl: string;
}
export const ManagePublicShareOptions: React.FC<
ManagePublicShareOptionsProps
> = ({
publicShareProp,
collection,
setPublicShareProp,
open,
onClose,
onRootClose,
publicShareUrl,
}) => {
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason === "backdropClick") {
onRootClose();
} else {
onClose();
}
};
const galleryContext = useContext(GalleryContext);
const [sharableLinkError, setSharableLinkError] = useState(null);
const updatePublicShareURLHelper = async (req: UpdatePublicURL) => {
try {
galleryContext.setBlockingLoad(true);
const response = await updateShareableURL(req);
setPublicShareProp(response);
galleryContext.syncWithRemote(false, true);
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
galleryContext.setBlockingLoad(false);
}
};
const disablePublicSharing = async () => {
try {
galleryContext.setBlockingLoad(true);
await deleteShareableURL(collection);
setPublicShareProp(null);
galleryContext.syncWithRemote(false, true);
onClose();
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
galleryContext.setBlockingLoad(false);
}
};
const copyToClipboardHelper = (text: string) => () => {
navigator.clipboard.writeText(text);
};
return (
<SidebarDrawer anchor="right" open={open} onClose={handleDrawerClose}>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
onClose={onClose}
title={t("share_album")}
onRootClose={onRootClose}
/>
<Stack py={"20px"} px={"8px"} spacing={"32px"}>
<Stack spacing={3}>
<ManagePublicCollect
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<ManageLinkExpiry
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
onRootClose={onRootClose}
/>
<MenuItemGroup>
<ManageDeviceLimit
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
onRootClose={onRootClose}
/>
<MenuItemDivider />
<ManageDownloadAccess
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<MenuItemDivider />
<ManageLinkPassword
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
</MenuItemGroup>
<MenuItemGroup>
<EnteMenuItem
startIcon={<ContentCopyIcon />}
onClick={copyToClipboardHelper(publicShareUrl)}
label={t("copy_link")}
/>
</MenuItemGroup>
<MenuItemGroup>
<EnteMenuItem
color="critical"
startIcon={<RemoveCircleOutline />}
onClick={disablePublicSharing}
label={t("REMOVE_LINK")}
/>
</MenuItemGroup>
</Stack>
{sharableLinkError && (
<Typography
textAlign={"center"}
variant="small"
sx={{
color: (theme) => theme.colors.danger.A700,
mt: 0.5,
}}
>
{sharableLinkError}
</Typography>
)}
</Stack>
</Stack>
</SidebarDrawer>
);
};
interface ManageDeviceLimitProps {
publicShareProp: PublicURL;
collection: Collection;
updatePublicShareURLHelper: (req: UpdatePublicURL) => Promise<void>;
onRootClose: () => void;
}
export const ManageDeviceLimit: React.FC<ManageDeviceLimitProps> = ({
collection,
publicShareProp,
updatePublicShareURLHelper,
onRootClose,
}) => {
const updateDeviceLimit = async (newLimit: number) => {
return updatePublicShareURLHelper({
collectionID: collection.id,
deviceLimit: newLimit,
});
};
const [isChangeDeviceLimitVisible, setIsChangeDeviceLimitVisible] =
useState(false);
const deviceLimitOptions = useMemo(() => getDeviceLimitOptions(), []);
const closeDeviceLimitChangeModal = () =>
setIsChangeDeviceLimitVisible(false);
const openDeviceLimitChangeModalView = () =>
setIsChangeDeviceLimitVisible(true);
const changeDeviceLimitValue = (value: number) => async () => {
await updateDeviceLimit(value);
setIsChangeDeviceLimitVisible(false);
};
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason === "backdropClick") {
onRootClose();
} else {
closeDeviceLimitChangeModal();
}
};
return (
<>
<EnteMenuItem
label={t("LINK_DEVICE_LIMIT")}
variant="captioned"
subText={
publicShareProp.deviceLimit === 0
? t("NO_DEVICE_LIMIT")
: publicShareProp.deviceLimit.toString()
}
onClick={openDeviceLimitChangeModalView}
endIcon={<ChevronRight />}
/>
<SidebarDrawer
anchor="right"
open={isChangeDeviceLimitVisible}
onClose={handleDrawerClose}
>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
onClose={closeDeviceLimitChangeModal}
title={t("LINK_DEVICE_LIMIT")}
onRootClose={onRootClose}
/>
<Stack py={"20px"} px={"8px"} spacing={"32px"}>
<MenuItemGroup>
{deviceLimitOptions.map((item, index) => (
<>
<EnteMenuItem
fontWeight="normal"
key={item.label}
onClick={changeDeviceLimitValue(
item.value,
)}
label={item.label}
/>
{index !==
deviceLimitOptions.length - 1 && (
<MenuItemDivider />
)}
</>
))}
</MenuItemGroup>
</Stack>
</Stack>
</SidebarDrawer>
</>
);
};

View File

@@ -1,22 +1,42 @@
import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu";
import type { Collection, PublicURL } from "@/media/collection";
import { SidebarDrawer } from "@/base/components/mui/SidebarDrawer";
import { Titlebar } from "@/base/components/Titlebar";
import type {
Collection,
PublicURL,
UpdatePublicURL,
} from "@/media/collection";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import {
default as ChevronRight,
default as ChevronRightIcon,
} from "@mui/icons-material/ChevronRight";
import ContentCopyIcon from "@mui/icons-material/ContentCopyOutlined";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import LinkIcon from "@mui/icons-material/Link";
import PublicIcon from "@mui/icons-material/Public";
import { Stack, Typography } from "@mui/material";
import RemoveCircleOutline from "@mui/icons-material/RemoveCircleOutline";
import { DialogProps, Stack, Typography } from "@mui/material";
import { t } from "i18next";
import { useState } from "react";
import { GalleryContext } from "pages/gallery";
import { useContext, useMemo, useState } from "react";
import {
deleteShareableURL,
updateShareableURL,
} from "services/collectionService";
import { SetPublicShareProp } from "types/publicCollection";
import {ManagePublicShareOptions} from "./manage";
import { getDeviceLimitOptions } from "utils/collection";
import { handleSharingErrors } from "utils/error/ui";
import { ManageDownloadAccess } from "./manage/downloadAccess";
import { ManageLinkExpiry } from "./manage/linkExpiry";
import { ManageLinkPassword } from "./manage/linkPassword";
import { ManagePublicCollect } from "./manage/publicCollect";
export const isLinkExpired = (validTill: number) => {
return validTill && validTill < Date.now() * 1000;
};
interface Iprops {
interface ManagePublicShareProps {
publicShareProp: PublicURL;
collection: Collection;
setPublicShareProp: SetPublicShareProp;
@@ -24,14 +44,15 @@ interface Iprops {
publicShareUrl: string;
copyToClipboardHelper: () => void;
}
export default function ManagePublicShare({
export const ManagePublicShare: React.FC<ManagePublicShareProps> = ({
publicShareProp,
setPublicShareProp,
collection,
onRootClose,
publicShareUrl,
copyToClipboardHelper,
}: Iprops) {
}) => {
const [manageShareView, setManageShareView] = useState(false);
const closeManageShare = () => setManageShareView(false);
const openManageShare = () => setManageShareView(true);
@@ -80,4 +101,243 @@ export default function ManagePublicShare({
/>
</>
);
};
interface ManagePublicShareOptionsProps {
publicShareProp: PublicURL;
collection: Collection;
setPublicShareProp: SetPublicShareProp;
open: boolean;
onClose: () => void;
onRootClose: () => void;
publicShareUrl: string;
}
export const ManagePublicShareOptions: React.FC<
ManagePublicShareOptionsProps
> = ({
publicShareProp,
collection,
setPublicShareProp,
open,
onClose,
onRootClose,
publicShareUrl,
}) => {
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason === "backdropClick") {
onRootClose();
} else {
onClose();
}
};
const galleryContext = useContext(GalleryContext);
const [sharableLinkError, setSharableLinkError] = useState(null);
const updatePublicShareURLHelper = async (req: UpdatePublicURL) => {
try {
galleryContext.setBlockingLoad(true);
const response = await updateShareableURL(req);
setPublicShareProp(response);
galleryContext.syncWithRemote(false, true);
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
galleryContext.setBlockingLoad(false);
}
};
const disablePublicSharing = async () => {
try {
galleryContext.setBlockingLoad(true);
await deleteShareableURL(collection);
setPublicShareProp(null);
galleryContext.syncWithRemote(false, true);
onClose();
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
galleryContext.setBlockingLoad(false);
}
};
const copyToClipboardHelper = (text: string) => () => {
navigator.clipboard.writeText(text);
};
return (
<SidebarDrawer anchor="right" open={open} onClose={handleDrawerClose}>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
onClose={onClose}
title={t("share_album")}
onRootClose={onRootClose}
/>
<Stack py={"20px"} px={"8px"} spacing={"32px"}>
<Stack spacing={3}>
<ManagePublicCollect
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<ManageLinkExpiry
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
onRootClose={onRootClose}
/>
<MenuItemGroup>
<ManageDeviceLimit
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
onRootClose={onRootClose}
/>
<MenuItemDivider />
<ManageDownloadAccess
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<MenuItemDivider />
<ManageLinkPassword
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
</MenuItemGroup>
<MenuItemGroup>
<EnteMenuItem
startIcon={<ContentCopyIcon />}
onClick={copyToClipboardHelper(publicShareUrl)}
label={t("copy_link")}
/>
</MenuItemGroup>
<MenuItemGroup>
<EnteMenuItem
color="critical"
startIcon={<RemoveCircleOutline />}
onClick={disablePublicSharing}
label={t("REMOVE_LINK")}
/>
</MenuItemGroup>
</Stack>
{sharableLinkError && (
<Typography
textAlign={"center"}
variant="small"
sx={{
color: (theme) => theme.colors.danger.A700,
mt: 0.5,
}}
>
{sharableLinkError}
</Typography>
)}
</Stack>
</Stack>
</SidebarDrawer>
);
};
interface ManageDeviceLimitProps {
publicShareProp: PublicURL;
collection: Collection;
updatePublicShareURLHelper: (req: UpdatePublicURL) => Promise<void>;
onRootClose: () => void;
}
export const ManageDeviceLimit: React.FC<ManageDeviceLimitProps> = ({
collection,
publicShareProp,
updatePublicShareURLHelper,
onRootClose,
}) => {
const updateDeviceLimit = async (newLimit: number) => {
return updatePublicShareURLHelper({
collectionID: collection.id,
deviceLimit: newLimit,
});
};
const [isChangeDeviceLimitVisible, setIsChangeDeviceLimitVisible] =
useState(false);
const deviceLimitOptions = useMemo(() => getDeviceLimitOptions(), []);
const closeDeviceLimitChangeModal = () =>
setIsChangeDeviceLimitVisible(false);
const openDeviceLimitChangeModalView = () =>
setIsChangeDeviceLimitVisible(true);
const changeDeviceLimitValue = (value: number) => async () => {
await updateDeviceLimit(value);
setIsChangeDeviceLimitVisible(false);
};
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason === "backdropClick") {
onRootClose();
} else {
closeDeviceLimitChangeModal();
}
};
return (
<>
<EnteMenuItem
label={t("LINK_DEVICE_LIMIT")}
variant="captioned"
subText={
publicShareProp.deviceLimit === 0
? t("NO_DEVICE_LIMIT")
: publicShareProp.deviceLimit.toString()
}
onClick={openDeviceLimitChangeModalView}
endIcon={<ChevronRight />}
/>
<SidebarDrawer
anchor="right"
open={isChangeDeviceLimitVisible}
onClose={handleDrawerClose}
>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
onClose={closeDeviceLimitChangeModal}
title={t("LINK_DEVICE_LIMIT")}
onRootClose={onRootClose}
/>
<Stack py={"20px"} px={"8px"} spacing={"32px"}>
<MenuItemGroup>
{deviceLimitOptions.map((item, index) => (
<>
<EnteMenuItem
fontWeight="normal"
key={item.label}
onClick={changeDeviceLimitValue(
item.value,
)}
label={item.label}
/>
{index !==
deviceLimitOptions.length - 1 && (
<MenuItemDivider />
)}
</>
))}
</MenuItemGroup>
</Stack>
</Stack>
</SidebarDrawer>
</>
);
};