/* eslint-disable react-hooks/rules-of-hooks */
import { useCallback, useEffect, useMemo, useState } from 'react';
import {
Avatar,
Button,
ButtonGroup,
Flex,
Icon,
IconButton,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Skeleton,
Table,
TableContainer,
Tbody,
Td,
Text,
Th,
Thead,
Tooltip,
Tr,
useColorModeValue,
useToast
} from '@chakra-ui/react';
import { Link } from '@chakra-ui/next-js';
import { useAuthContext } from '@/contexts/AuthContext';
import { Organization, OrganizationInvitation } from '@/types';
import { useRouter } from 'next/router';
import { BiRefresh } from 'react-icons/bi';
const moment = require('moment');
function TableEntry({ key, invitation, skeleton, action }: { key: number | string, invitation?: OrganizationInvitation, skeleton?: boolean, action: any }) {
const toRelativeTime = useMemo(() => (date: any) => {
return moment(new Date(date)).fromNow();
}, []);
return <>
{!skeleton ? invitation?.recipient?.displayName : "N/A"}
@{invitation?.recipient?.username}
|
{!skeleton ? toRelativeTime(invitation?.createdAt) : 'N/A'}
|
{!skeleton ? invitation?.createdBy?.displayName : "N/A"}
@{invitation?.createdBy?.username}
|
|
>
}
export default function OrganizationInvitationsModal({
isOpen,
onClose,
organization,
onRefresh
}: {
isOpen: boolean;
onClose: () => void;
organization?: Organization | null;
onRefresh: () => void;
}) {
const toast = useToast();
const { push } = useRouter();
const { user } = useAuthContext();
const [invitationsLoading, setInvitationsLoading] = useState(true);
const [invitations, setInvitations] = useState([]);
const fetchInvitations = useCallback(async () => {
setInvitationsLoading(true);
user.getIdToken().then(async (token: string) => {
await fetch(`/api/v1/organizations/${organization?.id}/invitations`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
}).then(async (res) => {
const data = await res.json();
if (res.status === 200) {
setInvitations(data || []);
} else {
toast({
title: "There was an error fetching the organization's invitations.",
description: data.message,
status: "error",
duration: 9000,
isClosable: true,
});
}
}).finally(() => {
setInvitationsLoading(false);
});
});
}, [user, toast, organization]);
const actOnInvitation = useCallback(async (invitation: OrganizationInvitation, action: 'withdraw') => {
setInvitationsLoading(true);
await user.getIdToken().then(async (token: string) => {
await fetch(`/api/v1/organizations/${organization?.id}/invitations/${invitation.id}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
}).then(async (res) => {
const data = await res.json();
if (res.status === 200) {
await fetchInvitations();
toast({
title: data.message,
status: "success",
duration: 5000,
isClosable: true,
});
} else {
toast({
title: "There was an error taking action on an invitation.",
description: data.message,
status: "error",
duration: 5000,
isClosable: true,
});
}
}).finally(() => {
setInvitationsLoading(false);
});
});
}, [user, toast, fetchInvitations, organization?.id]);
useEffect(() => {
if (!user) return;
if (!organization) return;
if (!isOpen) return;
fetchInvitations();
}, [user, fetchInvitations, organization, isOpen]);
return (
<>
Invitations
} />
Recipient |
Invite Date |
Inviter |
Actions |
{
invitationsLoading ? (
Array.from({ length: 6 }).map((_, i) => (
))
) : (invitations.map((invitation: OrganizationInvitation) => (
)))
}
{
!invitationsLoading && invitations.length === 0 && (
There are no outgoing invitations.
)
}
>
);
}