This commit is contained in:
grimsi
2025-07-19 23:03:37 +02:00
parent ce7729ed6d
commit dccb15de71
2 changed files with 73 additions and 39 deletions
@@ -1,6 +1,5 @@
import {Card, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, useDisclosure} from "@heroui/react";
import {DotsThreeVertical} from "@phosphor-icons/react";
import {useAuth} from "Frontend/util/auth";
import {useEffect, useState} from "react";
import {MessageEndpoint, PasswordResetEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
import {AvatarEndpoint} from "Frontend/endpoints/endpoints";
@@ -20,7 +19,6 @@ export function UserManagementCard({user}: { user: UserInfoDto }) {
const [disabledKeys, setDisabledKeys] = useState<string[]>([]);
const [dropdownItems, setDropdownItems] = useState<any[]>([]);
const [passwordResetToken, setPasswordResetToken] = useState<TokenDto>();
const auth = useAuth();
useEffect(() => {
setUserEnabled(user.enabled);
@@ -1,6 +1,10 @@
import React, {useEffect, useState} from "react";
import {addToast, Button, Input, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {RegistrationEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
import {addToast, Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, Snippet} from "@heroui/react";
import {MessageEndpoint, RegistrationEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
import TokenDto from "Frontend/generated/org/gameyfin/app/shared/token/TokenDto";
import {Form, Formik, FormikErrors} from "formik";
import Input from "Frontend/components/general/input/Input";
import * as Yup from "yup";
interface InviteUserModalProps {
isOpen: boolean;
@@ -8,56 +12,88 @@ interface InviteUserModalProps {
}
export default function InviteUserModal({isOpen, onOpenChange}: InviteUserModalProps) {
const [email, setEmail] = useState<string | null>();
const [error, setError] = useState<string | null>();
const [token, setToken] = useState<TokenDto | null>(null);
const [isMessageServiceEnabled, setIsMessageServiceEnabled] = useState<boolean>(false);
useEffect(() => {
setEmail(null);
setError(null);
}, []);
setToken(null);
MessageEndpoint.isEnabled().then(enabled => {
setIsMessageServiceEnabled(enabled);
});
}, [isOpen]);
async function inviteUser(onClose: () => void) {
async function inviteUser(email: string, setErrors: (errors: FormikErrors<any>) => void, onClose: () => void) {
if (!email) return;
if (await UserEndpoint.existsByMail(email)) {
setError("User with this email already exists");
setErrors({email: "User with this email already exists"});
return;
}
try {
await RegistrationEndpoint.createInvitation(email);
addToast({
title: "Invitation sent",
description: "The user will receive an email with further instructions shortly.",
color: "success"
});
onClose();
} catch (e) {
setError("Failed to create invitation");
if (!isMessageServiceEnabled) {
let token = await RegistrationEndpoint.createInvitation(email);
setToken(token);
return;
}
await RegistrationEndpoint.createInvitation(email);
addToast({
title: "Invitation sent",
description: "The user will receive an email with further instructions shortly.",
color: "success"
});
onClose();
}
return (
<Modal isOpen={isOpen} onOpenChange={onOpenChange} backdrop="opaque" size="lg">
<Modal isOpen={isOpen} onOpenChange={onOpenChange} backdrop="opaque" size="4xl">
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">Invite a new user</ModalHeader>
<ModalBody>
<p>Enter the email address of the user you want to invite:</p>
<Input errorMessage={error} onChange={(e) => setEmail(e.target.value)} type="email"/>
{error && <small className="text-danger">{error}</small>}
</ModalBody>
<ModalFooter>
<Button variant="light" onPress={onClose}>
Cancel
</Button>
<Button color="success" onPress={() => inviteUser(onClose)}
isDisabled={email === null || email === undefined || email.length < 1}>
Send invitation
</Button>
</ModalFooter>
</>
<Formik
initialValues={{email: ""}}
isInitialValid={false}
validationSchema={Yup.object({
email: Yup.string()
.email("Invalid email address")
.required("Email is required")
})}
onSubmit={async (values: any, {setErrors}) => {
await inviteUser(values.email, setErrors, onClose);
}}
>
{(formik) => (
<Form>
<ModalHeader className="flex flex-col gap-1">Invite a new user</ModalHeader>
<ModalBody>
<p>Enter the email address of the user you want to invite:</p>
<Input label="E-Mail" name="email" type="email"/>
{token && (
<div className="flex flex-col gap-2">
<p>The user can accept the invitation using the following link:</p>
<Snippet symbol="">
{`${document.baseURI}accept-invitation?token=${token.secret}`}
</Snippet>
</div>
)}
</ModalBody>
<ModalFooter>
<Button variant="light" onPress={onClose}>
Cancel
</Button>
<Button color="success"
type="submit"
isLoading={formik.isSubmitting}
isDisabled={!formik.isValid || token !== null}>
{isMessageServiceEnabled ?
<p>Send invitation</p> :
<p>Generate invitation link</p>
}
</Button>
</ModalFooter>
</Form>
)}
</Formik>
)}
</ModalContent>
</Modal>