// @flow import { observer } from "mobx-react"; import { LinkIcon, CloseIcon } from "outline-icons"; import * as React from "react"; import { useTranslation, Trans } from "react-i18next"; import { Link } from "react-router-dom"; import styled from "styled-components"; import type { Role } from "shared/types"; import Button from "components/Button"; import CopyToClipboard from "components/CopyToClipboard"; import Flex from "components/Flex"; import HelpText from "components/HelpText"; import Input from "components/Input"; import InputSelectRole from "components/InputSelectRole"; import NudeButton from "components/NudeButton"; import Tooltip from "components/Tooltip"; import useCurrentTeam from "hooks/useCurrentTeam"; import useCurrentUser from "hooks/useCurrentUser"; import useStores from "hooks/useStores"; import useToasts from "hooks/useToasts"; const MAX_INVITES = 20; type Props = {| onSubmit: () => void, |}; type InviteRequest = { email: string, name: string, role: Role, }; function Invite({ onSubmit }: Props) { const [isSaving, setIsSaving] = React.useState(); const [linkCopied, setLinkCopied] = React.useState(false); const [invites, setInvites] = React.useState([ { email: "", name: "", role: "member" }, { email: "", name: "", role: "member" }, { email: "", name: "", role: "member" }, ]); const { users, policies } = useStores(); const { showToast } = useToasts(); const user = useCurrentUser(); const team = useCurrentTeam(); const { t } = useTranslation(); const predictedDomain = user.email.split("@")[1]; const can = policies.abilities(team.id); const handleSubmit = React.useCallback( async (ev: SyntheticEvent<>) => { ev.preventDefault(); setIsSaving(true); try { await users.invite(invites); onSubmit(); showToast(t("We sent out your invites!"), { type: "success" }); } catch (err) { showToast(err.message, { type: "error" }); } finally { setIsSaving(false); } }, [onSubmit, showToast, invites, t, users] ); const handleChange = React.useCallback((ev, index) => { setInvites((prevInvites) => { const newInvites = [...prevInvites]; newInvites[index][ev.target.name] = ev.target.value; return newInvites; }); }, []); const handleAdd = React.useCallback(() => { if (invites.length >= MAX_INVITES) { showToast( t("Sorry, you can only send {{MAX_INVITES}} invites at a time", { MAX_INVITES, }), { type: "warning" } ); } setInvites((prevInvites) => { const newInvites = [...prevInvites]; newInvites.push({ email: "", name: "", role: "member" }); return newInvites; }); }, [showToast, invites, t]); const handleRemove = React.useCallback( (ev: SyntheticEvent<>, index: number) => { ev.preventDefault(); setInvites((prevInvites) => { const newInvites = [...prevInvites]; newInvites.splice(index, 1); return newInvites; }); }, [] ); const handleCopy = React.useCallback(() => { setLinkCopied(true); showToast(t("Share link copied"), { type: "success", }); }, [showToast, t]); const handleRoleChange = React.useCallback((ev, index) => { setInvites((prevInvites) => { const newInvites = [...prevInvites]; newInvites[index]["role"] = ev.target.value; return newInvites; }); }, []); return (
{team.guestSignin ? ( ) : ( {" "} {can.update && ( As an admin you can also{" "} enable email sign-in. )} )} {team.subdomain && (   


)} {invites.map((invite, index) => ( handleChange(ev, index)} placeholder={`example@${predictedDomain}`} value={invite.email} required={index === 0} autoFocus={index === 0} flex /> handleChange(ev, index)} value={invite.name} required={!!invite.email} /> handleRoleChange(ev, index)} value={invite.role} labelHidden={index !== 0} short /> {index !== 0 && ( handleRemove(ev, index)}> )} ))} {invites.length <= MAX_INVITES ? ( ) : ( )}
); } const CopyBlock = styled("div")` margin: 2em 0; font-size: 14px; `; const Remove = styled("div")` margin-top: 6px; position: absolute; right: -32px; `; export default observer(Invite);