Files

167 lines
4.8 KiB
TypeScript

import { useState } from "react";
import { useTeam } from "@/context/team-context";
import { toast } from "sonner";
import { mutate } from "swr";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import { useAnalytics } from "@/lib/analytics";
export function AddGroupMemberModal({
dataroomId,
groupId,
open,
setOpen,
children,
}: {
dataroomId: string;
groupId: string;
open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
children?: React.ReactNode;
}) {
const [inputValue, setInputValue] = useState<string>("");
const [loading, setLoading] = useState<boolean>(false);
const teamInfo = useTeam();
const teamId = teamInfo?.currentTeam?.id;
const analytics = useAnalytics();
// Email validation regex pattern
const validateEmail = (email: string) => {
return email.match(
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
);
};
// Domain validation regex pattern
const validateDomain = (domain: string) => {
return domain.match(/^@([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/);
};
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const inputValue = e.target.value;
setInputValue(inputValue);
};
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
event.stopPropagation();
const inputs = inputValue
.split(",")
.map((input) => input.trim().toLowerCase())
.filter((input) => input);
if (inputs.length === 0) return;
setLoading(true);
// Separate domains and emails
const domains = inputs.filter((input) => input.startsWith("@"));
const emails = inputs.filter((input) => !input.startsWith("@"));
// validate emails
const invalidEmails = emails.filter((email) => !validateEmail(email));
if (invalidEmails.length > 0) {
setLoading(false);
toast.error("Found one or more invalid email addresses.");
return;
}
// validate domains
const invalidDomains = domains.filter((domain) => !validateDomain(domain));
if (invalidDomains.length > 0) {
setLoading(false);
toast.error(
"Found one or more invalid domains. Domains should be in format @example.org",
);
return;
}
// POST request with emails and domains
const response = await fetch(
`/api/teams/${teamId}/datarooms/${dataroomId}/groups/${groupId}/members`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
emails,
domains,
}),
},
);
if (!response.ok) {
const error = await response.json();
setLoading(false);
setOpen(false);
toast.error(error.message || "Failed to add group members.");
return;
}
analytics.capture("Dataroom Group Member Added", {
emailCount: emails.length,
domainCount: domains.length,
teamId: teamId,
dataroomId: dataroomId,
groupId: groupId,
});
mutate(`/api/teams/${teamId}/datarooms/${dataroomId}/groups/${groupId}`);
toast.success("Group members added successfully!");
setOpen(false);
setInputValue("");
setLoading(false);
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader className="text-start">
<DialogTitle>Add members</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit}>
<Label htmlFor="email">Email addresses or domains</Label>
<div className="flex flex-col gap-2 py-2 text-sm">
<Textarea
value={inputValue}
onChange={handleInputChange}
rows={5}
id="email"
placeholder="[email protected], [email protected], @example.org"
className="flex-1 bg-muted"
autoComplete="off"
/>
<small className="text-xs text-muted-foreground">
Use comma to separate multiple email addresses or domains. For
domains, use format @example.org
</small>
</div>
<DialogFooter>
<Button type="submit" className="mt-6 h-9 w-full" loading={loading}>
{loading ? "Adding members..." : "Add members"}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}