import type {ReactNode} from 'react';
import {Fragment} from 'react';
import {css} from '@emotion/react';
import styled from '@emotion/styled';
import type {ModalRenderProps} from 'sentry/actionCreators/modal';
import Alert from 'sentry/components/alert';
import {Button} from 'sentry/components/button';
import ButtonBar from 'sentry/components/buttonBar';
import InviteButton from 'sentry/components/modals/inviteMembersModal/inviteButton';
import InviteRowControl from 'sentry/components/modals/inviteMembersModal/inviteRowControl';
import InviteStatusMessage from 'sentry/components/modals/inviteMembersModal/inviteStatusMessage';
import type {
InviteRow,
InviteStatus,
NormalizedInvite,
} from 'sentry/components/modals/inviteMembersModal/types';
import {ORG_ROLES} from 'sentry/constants';
import {IconAdd} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Member} from 'sentry/types/organization';
interface Props {
Footer: ModalRenderProps['Footer'];
addInviteRow: () => void;
canSend: boolean;
closeModal: ModalRenderProps['closeModal'];
complete: boolean;
headerInfo: ReactNode;
inviteStatus: InviteStatus;
invites: NormalizedInvite[];
member: Member | undefined;
pendingInvites: InviteRow[];
removeInviteRow: (index: number) => void;
reset: () => void;
sendInvites: () => void;
sendingInvites: boolean;
setEmails: (emails: string[], index: number) => void;
setRole: (role: string, index: number) => void;
setTeams: (teams: string[], index: number) => void;
willInvite: boolean;
error?: string;
}
export default function InviteMembersModalView({
addInviteRow,
canSend,
closeModal,
complete,
Footer,
headerInfo,
invites,
inviteStatus,
member,
pendingInvites,
removeInviteRow,
reset,
sendingInvites,
sendInvites,
setEmails,
setRole,
setTeams,
willInvite,
error,
}: Props) {
const disableInputs = sendingInvites || complete;
const inviteEmails = invites.map(inv => inv.email);
const hasDuplicateEmails = inviteEmails.length !== new Set(inviteEmails).size;
const isValidInvites = invites.length > 0 && !hasDuplicateEmails;
const errorAlert = error ? (
{error}
) : null;
return (
{errorAlert}
{t('Invite New Members')}
{willInvite ? (
{t('Invite new members by email to join your organization.')}
) : (
{t(
'You can’t invite users directly, but we’ll forward your request to an org owner or manager for approval.'
)}
)}
{headerInfo}
{t('Email addresses')}
{t('Role')}
{t('Add to team')}
{pendingInvites.map(({emails, role, teams}, i) => (
removeInviteRow(i)}
onChangeEmails={opts => setEmails(opts?.map(v => v.value) ?? [], i)}
onChangeRole={value => setRole(value?.value, i)}
onChangeTeams={opts => setTeams(opts ? opts.map(v => v.value) : [], i)}
disableRemove={disableInputs || pendingInvites.length === 1}
/>
))}
}
>
{t('Add another')}
);
}
const Heading = styled('h1')`
font-weight: ${p => p.theme.fontWeightNormal};
font-size: ${p => p.theme.headerFontSize};
margin-top: 0;
margin-bottom: ${space(0.75)};
`;
const Subtext = styled('p')`
color: ${p => p.theme.subText};
margin-bottom: ${space(3)};
`;
const inviteRowGrid = css`
display: grid;
gap: ${space(1.5)};
grid-template-columns: 3fr 180px 2fr 0.5fr;
align-items: start;
`;
const InviteeHeadings = styled('div')`
${inviteRowGrid};
margin-bottom: ${space(1)};
font-weight: ${p => p.theme.fontWeightBold};
text-transform: uppercase;
font-size: ${p => p.theme.fontSizeSmall};
`;
const Rows = styled('ul')`
list-style: none;
padding: 0;
margin: 0;
`;
const StyledInviteRow = styled(InviteRowControl)`
${inviteRowGrid};
margin-bottom: ${space(1.5)};
`;
const AddButton = styled(Button)`
margin-top: ${space(3)};
`;
const FooterContent = styled('div')`
display: flex;
gap: ${space(1)};
align-items: center;
justify-content: space-between;
flex: 1;
`;