feat: add more options to reverse shares (#495)
* feat(reverse-share): optional simplified interface for reverse sharing. issue #155. * chore: Remove useless form validation. * feat: Share Ready modal adds a prompt that an email has been sent to the reverse share creator. * fix: Simplified reverse shared interface elements lack spacing when not logged in. * fix: Share Ready modal prompt contrast is too low in dark mode. * feat: add public access options to reverse share. * feat: remember reverse share simplified and publicAccess options in cookies. * style: npm run format. * chore(i18n): Improve translation. Co-authored-by: Elias Schneider <login@eliasschneider.com> Update frontend/src/i18n/translations/en-US.ts Co-authored-by: Elias Schneider <login@eliasschneider.com> Update frontend/src/i18n/translations/en-US.ts Co-authored-by: Elias Schneider <login@eliasschneider.com> chore(i18n): Improve translation. * chore: Improved variable naming. * chore(i18n): Improve translation. x2. * fix(backend/shares): Misjudged the permission of the share of the reverse share.
This commit is contained in:
@@ -31,6 +31,7 @@ import { FileUpload } from "../../../types/File.type";
|
||||
import { CreateShare } from "../../../types/share.type";
|
||||
import { getExpirationPreview } from "../../../utils/date.util";
|
||||
import React from "react";
|
||||
import toast from "../../../utils/toast.util";
|
||||
|
||||
const showCreateUploadModal = (
|
||||
modals: ModalsContextProps,
|
||||
@@ -41,12 +42,26 @@ const showCreateUploadModal = (
|
||||
allowUnauthenticatedShares: boolean;
|
||||
enableEmailRecepients: boolean;
|
||||
maxExpirationInHours: number;
|
||||
simplified: boolean;
|
||||
},
|
||||
files: FileUpload[],
|
||||
uploadCallback: (createShare: CreateShare, files: FileUpload[]) => void,
|
||||
) => {
|
||||
const t = translateOutsideContext();
|
||||
|
||||
if (options.simplified) {
|
||||
return modals.openModal({
|
||||
title: t("upload.modal.title"),
|
||||
children: (
|
||||
<SimplifiedCreateUploadModalModal
|
||||
options={options}
|
||||
files={files}
|
||||
uploadCallback={uploadCallback}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return modals.openModal({
|
||||
title: t("upload.modal.title"),
|
||||
children: (
|
||||
@@ -59,6 +74,23 @@ const showCreateUploadModal = (
|
||||
});
|
||||
};
|
||||
|
||||
const generateLink = () =>
|
||||
Buffer.from(Math.random().toString(), "utf8")
|
||||
.toString("base64")
|
||||
.substring(10, 17);
|
||||
|
||||
const generateAvailableLink = async (times = 10): Promise<string> => {
|
||||
if (times <= 0) {
|
||||
throw new Error("Could not generate available link");
|
||||
}
|
||||
const _link = generateLink();
|
||||
if (!(await shareService.isShareIdAvailable(_link))) {
|
||||
return await generateAvailableLink(times - 1);
|
||||
} else {
|
||||
return _link;
|
||||
}
|
||||
};
|
||||
|
||||
const CreateUploadModalBody = ({
|
||||
uploadCallback,
|
||||
files,
|
||||
@@ -78,9 +110,7 @@ const CreateUploadModalBody = ({
|
||||
const modals = useModals();
|
||||
const t = useTranslate();
|
||||
|
||||
const generatedLink = Buffer.from(Math.random().toString(), "utf8")
|
||||
.toString("base64")
|
||||
.substr(10, 7);
|
||||
const generatedLink = generateLink();
|
||||
|
||||
const [showNotSignedInAlert, setShowNotSignedInAlert] = useState(true);
|
||||
|
||||
@@ -202,14 +232,7 @@ const CreateUploadModalBody = ({
|
||||
<Button
|
||||
style={{ flex: "0 0 auto" }}
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
form.setFieldValue(
|
||||
"link",
|
||||
Buffer.from(Math.random().toString(), "utf8")
|
||||
.toString("base64")
|
||||
.substr(10, 7),
|
||||
)
|
||||
}
|
||||
onClick={() => form.setFieldValue("link", generateLink())}
|
||||
>
|
||||
<FormattedMessage id="common.button.generate" />
|
||||
</Button>
|
||||
@@ -429,4 +452,108 @@ const CreateUploadModalBody = ({
|
||||
);
|
||||
};
|
||||
|
||||
const SimplifiedCreateUploadModalModal = ({
|
||||
uploadCallback,
|
||||
files,
|
||||
options,
|
||||
}: {
|
||||
files: FileUpload[];
|
||||
uploadCallback: (createShare: CreateShare, files: FileUpload[]) => void;
|
||||
options: {
|
||||
isUserSignedIn: boolean;
|
||||
isReverseShare: boolean;
|
||||
appUrl: string;
|
||||
allowUnauthenticatedShares: boolean;
|
||||
enableEmailRecepients: boolean;
|
||||
maxExpirationInHours: number;
|
||||
};
|
||||
}) => {
|
||||
const modals = useModals();
|
||||
const t = useTranslate();
|
||||
|
||||
const [showNotSignedInAlert, setShowNotSignedInAlert] = useState(true);
|
||||
|
||||
const validationSchema = yup.object().shape({
|
||||
name: yup
|
||||
.string()
|
||||
.transform((value) => value || undefined)
|
||||
.min(3, t("common.error.too-short", { length: 3 }))
|
||||
.max(30, t("common.error.too-long", { length: 30 })),
|
||||
});
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
name: undefined,
|
||||
description: undefined,
|
||||
},
|
||||
validate: yupResolver(validationSchema),
|
||||
});
|
||||
|
||||
const onSubmit = form.onSubmit(async (values) => {
|
||||
const link = await generateAvailableLink().catch(() => {
|
||||
toast.error(t("upload.modal.link.error.taken"));
|
||||
return undefined;
|
||||
});
|
||||
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
|
||||
uploadCallback(
|
||||
{
|
||||
id: link,
|
||||
name: values.name,
|
||||
expiration: "never",
|
||||
recipients: [],
|
||||
description: values.description,
|
||||
security: {
|
||||
password: undefined,
|
||||
maxViews: undefined,
|
||||
},
|
||||
},
|
||||
files,
|
||||
);
|
||||
modals.closeAll();
|
||||
});
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
{showNotSignedInAlert && !options.isUserSignedIn && (
|
||||
<Alert
|
||||
withCloseButton
|
||||
onClose={() => setShowNotSignedInAlert(false)}
|
||||
icon={<TbAlertCircle size={16} />}
|
||||
title={t("upload.modal.not-signed-in")}
|
||||
color="yellow"
|
||||
>
|
||||
<FormattedMessage id="upload.modal.not-signed-in-description" />
|
||||
</Alert>
|
||||
)}
|
||||
<form onSubmit={onSubmit}>
|
||||
<Stack align="stretch">
|
||||
<Stack align="stretch">
|
||||
<TextInput
|
||||
variant="filled"
|
||||
placeholder={t(
|
||||
"upload.modal.accordion.name-and-description.name.placeholder",
|
||||
)}
|
||||
{...form.getInputProps("name")}
|
||||
/>
|
||||
<Textarea
|
||||
variant="filled"
|
||||
placeholder={t(
|
||||
"upload.modal.accordion.name-and-description.description.placeholder",
|
||||
)}
|
||||
{...form.getInputProps("description")}
|
||||
/>
|
||||
</Stack>
|
||||
<Button type="submit" data-autofocus>
|
||||
<FormattedMessage id="common.button.share" />
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default showCreateUploadModal;
|
||||
|
||||
Reference in New Issue
Block a user