import {
Accordion,
Alert,
Button,
Checkbox,
Col,
Grid,
Group,
MultiSelect,
NumberInput,
PasswordInput,
Select,
Stack,
Text,
Textarea,
TextInput,
} from "@mantine/core";
import { useForm, yupResolver } from "@mantine/form";
import { useModals } from "@mantine/modals";
import { ModalsContextProps } from "@mantine/modals/lib/context";
import moment from "moment";
import React, { useState } from "react";
import { TbAlertCircle } from "react-icons/tb";
import { FormattedMessage } from "react-intl";
import * as yup from "yup";
import useTranslate, {
translateOutsideContext,
} from "../../../hooks/useTranslate.hook";
import shareService from "../../../services/share.service";
import { FileUpload } from "../../../types/File.type";
import { CreateShare } from "../../../types/share.type";
import { getExpirationPreview } from "../../../utils/date.util";
import toast from "../../../utils/toast.util";
const showCreateUploadModal = (
modals: ModalsContextProps,
options: {
isUserSignedIn: boolean;
isReverseShare: boolean;
allowUnauthenticatedShares: boolean;
enableEmailRecepients: boolean;
maxExpirationInHours: number;
shareIdLength: 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: (
),
});
}
return modals.openModal({
title: t("upload.modal.title"),
children: (
),
});
};
const generateShareId = (length: number = 16) => {
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
const randomArray = new Uint8Array(length >= 3 ? length : 3);
crypto.getRandomValues(randomArray);
randomArray.forEach((number) => {
result += chars[number % chars.length];
});
return result;
};
const generateAvailableLink = async (
shareIdLength: number,
times: number = 10,
): Promise => {
if (times <= 0) {
throw new Error("Could not generate available link");
}
const _link = generateShareId(shareIdLength);
if (!(await shareService.isShareIdAvailable(_link))) {
return await generateAvailableLink(shareIdLength, times - 1);
} else {
return _link;
}
};
const CreateUploadModalBody = ({
uploadCallback,
files,
options,
}: {
files: FileUpload[];
uploadCallback: (createShare: CreateShare, files: FileUpload[]) => void;
options: {
isUserSignedIn: boolean;
isReverseShare: boolean;
allowUnauthenticatedShares: boolean;
enableEmailRecepients: boolean;
maxExpirationInHours: number;
shareIdLength: number;
};
}) => {
const modals = useModals();
const t = useTranslate();
const generatedLink = generateShareId(options.shareIdLength);
const [showNotSignedInAlert, setShowNotSignedInAlert] = useState(true);
const validationSchema = yup.object().shape({
link: yup
.string()
.required(t("common.error.field-required"))
.min(3, t("common.error.too-short", { length: 3 }))
.max(50, t("common.error.too-long", { length: 50 }))
.matches(new RegExp("^[a-zA-Z0-9_-]*$"), {
message: t("upload.modal.link.error.invalid"),
}),
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 })),
password: yup
.string()
.transform((value) => value || undefined)
.min(3, t("common.error.too-short", { length: 3 }))
.max(30, t("common.error.too-long", { length: 30 })),
maxViews: yup
.number()
.transform((value) => value || undefined)
.min(1),
});
const form = useForm({
initialValues: {
name: undefined,
link: generatedLink,
recipients: [] as string[],
password: undefined,
maxViews: undefined,
description: undefined,
expiration_num: 1,
expiration_unit: "-days",
never_expires: false,
},
validate: yupResolver(validationSchema),
});
const onSubmit = form.onSubmit(async (values) => {
if (!(await shareService.isShareIdAvailable(values.link))) {
form.setFieldError("link", t("upload.modal.link.error.taken"));
} else {
const expirationString = form.values.never_expires
? "never"
: form.values.expiration_num + form.values.expiration_unit;
const expirationDate = moment().add(
form.values.expiration_num,
form.values.expiration_unit.replace(
"-",
"",
) as moment.unitOfTime.DurationConstructor,
);
if (
options.maxExpirationInHours != 0 &&
(form.values.never_expires ||
expirationDate.isAfter(
moment().add(options.maxExpirationInHours, "hours"),
))
) {
form.setFieldError(
"expiration_num",
t("upload.modal.expires.error.too-long", {
max: moment
.duration(options.maxExpirationInHours, "hours")
.humanize(),
}),
);
return;
}
uploadCallback(
{
id: values.link,
name: values.name,
expiration: expirationString,
recipients: values.recipients,
description: values.description,
security: {
password: values.password || undefined,
maxViews: values.maxViews || undefined,
},
},
files,
);
modals.closeAll();
}
});
return (
<>
{showNotSignedInAlert && !options.isUserSignedIn && (
setShowNotSignedInAlert(false)}
icon={}
title={t("upload.modal.not-signed-in")}
color="yellow"
>
)}
>
);
};
const SimplifiedCreateUploadModalModal = ({
uploadCallback,
files,
options,
}: {
files: FileUpload[];
uploadCallback: (createShare: CreateShare, files: FileUpload[]) => void;
options: {
isUserSignedIn: boolean;
isReverseShare: boolean;
allowUnauthenticatedShares: boolean;
enableEmailRecepients: boolean;
maxExpirationInHours: number;
shareIdLength: 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(options.shareIdLength).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 (
{showNotSignedInAlert && !options.isUserSignedIn && (
setShowNotSignedInAlert(false)}
icon={}
title={t("upload.modal.not-signed-in")}
color="yellow"
>
)}
);
};
export default showCreateUploadModal;