/* eslint-disable react-hooks/rules-of-hooks */
import { Key, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
Avatar,
Box,
Button,
ButtonGroup,
Container,
Flex,
Heading,
Icon,
IconButton,
Input,
Skeleton,
Spacer,
Stack,
Table,
TableContainer,
Tbody,
Td,
Text,
Th,
Thead,
Tooltip,
Tr,
useColorModeValue,
useDisclosure,
useToast
} from '@chakra-ui/react';
import { Link } from '@chakra-ui/next-js';
import { MdMail, MdOutlineAddCircle, MdOutlineJoinRight } from 'react-icons/md';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { useAuthContext } from '@/contexts/AuthContext';
import Layout from '@/layouts/PlatformLayout';
import CreateOrganizationDialog from '@/components/CreateOrganizationDialog';
import JoinOrganizationDialog from '@/components/JoinOrganizationDialog';
import UserInvitationsModal from '@/components/UserInvitationsModal';
import { Organization, OrganizationMember } from '@/types';
import moment from 'moment';
import { AiFillSetting } from 'react-icons/ai';
import { BiGrid, BiRefresh } from 'react-icons/bi';
import { BsListUl } from 'react-icons/bs';
const toRelativeTime = (date: string) => {
return moment(new Date(date)).fromNow();
};
const toActualTime = (date: string) => {
return moment(new Date(date)).format('MMMM Do YYYY, h:mm:ss a');
}
function GridEntry({ key, organization }: { key: Key, organization?: Organization }) {
return <>
{/* icon */}
{/* text */}
{organization?.name || "Organization"}
by{' '}
{organization?.owner?.displayName}
{
toRelativeTime(organization?.updatedAt as string)
}
>
}
function TableEntry({ key, organization, skeleton }: { key: number | string, organization?: Organization, skeleton?: boolean }) {
const { push } = useRouter();
return <>
{!skeleton ? organization?.name : "Organization Name"}
Owned by {!skeleton ? {organization?.owner?.displayName} : "Organization Owner"}
{!skeleton ? toRelativeTime(organization?.updatedAt) : "Last Updated"}
{!skeleton && organization?.updatedBy && " by "}
{!skeleton ? {organization?.updatedBy?.displayName} : "Organization Owner"}
{!skeleton ? organization?.description : "Organization Description"}
|
|
>
}
export default function PlatformOrganizations() {
const { user, currentUser } = useAuthContext();
const { push, query } = useRouter();
const toast = useToast();
const [queryLoading, setQueryLoading] = useState(true);
const [organizationsLoading, setOrganizationsLoading] = useState(true);
const [organizations, setOrganizations] = useState([]);
const [filteredOrganizations, setFilteredOrganizations] = useState([]);
const [initialInviteCodeValue, setInitialInviteCodeValue] = useState(null);
const searchRef = useRef(null);
const [view, setView] = useState<'list' | 'grid' | null>(null);
// modal disclosure hooks
const {
isOpen: isCreateOrganizationModalOpen,
onOpen: onCreateOrganizationModalOpen,
onClose: onCreateOrganizationModalClose
} = useDisclosure();
const {
isOpen: isJoinOrganizationModalOpen,
onOpen: onJoinOrganizationModalOpen,
onClose: onJoinOrganizationModalClose
} = useDisclosure();
const {
isOpen: isViewInvitationsModalOpen,
onOpen: onViewInvitationsModalOpen,
onClose: onViewInvitationsModalClose
} = useDisclosure();
const refreshData = useCallback(async () => {
setOrganizationsLoading(true);
const token = await user?.getIdToken().then((token: string) => token);
await fetch('/api/v1/me/organizations', {
method: 'GET',
headers: { Authorization: `Bearer ${token}` }
}).then((res) => {
if (res.status !== 200) {
throw new Error('Failed to fetch organizations.');
}
res
.json()
.then((data) => {
setTimeout(() => {
setOrganizations(data.organizations);
setOrganizationsLoading(false);
}, 100);
})
.catch((err) => {
toast({
title: 'Error',
description: err.message,
status: 'error',
duration: 5000,
isClosable: true
});
});
}).catch((err) => {
toast({
title: 'There was an error fetching your organizations.',
description: err.message,
status: 'error',
duration: 5000,
isClosable: true
});
});
}, [toast, user]);
useEffect(() => {
if (!user) return;
refreshData();
}, [user, refreshData]);
const joinOrganizationPrompt = useCallback(async (inviteCode: string) => {
setQueryLoading(true);
setInitialInviteCodeValue(inviteCode);
setQueryLoading(false);
onJoinOrganizationModalOpen();
}, [onJoinOrganizationModalOpen]);
useEffect(() => {
if (!query) return;
if (query.invitation) {
joinOrganizationPrompt(query.invitation as string);
} else {
setTimeout(() => {
setQueryLoading(false);
}, 100);
}
}, [query.invitation, joinOrganizationPrompt, query]);
const filterOrganizations = useCallback((query: string) => {
if (!query) {
setFilteredOrganizations(organizations);
return;
}
const filtered = organizations.filter((organization: Organization) => {
return organization.name.toLowerCase().includes(query.toLowerCase()) || organization.owner?.displayName?.toLowerCase().includes(query.toLowerCase());
});
setFilteredOrganizations(filtered);
}, [organizations]);
const toRelativeTime = useMemo(() => (date: string) => {
return moment(new Date(date)).fromNow();
}, []);
useEffect(() => {
// load view option from local storage
const viewOption = localStorage.getItem('organizationView');
if (viewOption) {
setView(viewOption as 'list' | 'grid');
} else {
setView('list');
localStorage.setItem('organizationView', 'list');
}
}, []);
useEffect(() => {
// cache view option in local storage
if (!view) return;
localStorage.setItem('organizationView', view);
}, [view]);
useEffect(() => {
if (!organizations) return;
setFilteredOrganizations(organizations);
}, [organizations]);
return (
<>
Organizations - Amperra Wyre
{
push(`/organizations/${id}/settings`);
}}
/>
{!queryLoading && (
{
push(`/organizations/${id}/settings`);
}}
initialValue={initialInviteCodeValue || ''}
/>
)}
Organizations
}
onClick={onCreateOrganizationModalOpen}
>
New Organization
}
onClick={onJoinOrganizationModalOpen}
>
Join Organization
}
onClick={onViewInvitationsModalOpen}
>
View Invitations
{" "}{currentUser?.statistics?.organizationInvitations || 0}
{
filterOrganizations(e.target.value);
}}
/>
}
onClick={refreshData}
/>
{ setView('list') }} icon={} />
{ setView('grid') }} icon={} />
{
view === 'list' ? (
Organization |
Actions |
{/* display list of organizations */}
{
organizationsLoading ? (
Array.from({ length: 6 }).map((_, i) => (
))
) : (filteredOrganizations.map((organization: Organization) => (
)))
}
) : (
{
organizationsLoading ? (
Array.from({ length: 6 }).map((_, i) => (
))
) : (
filteredOrganizations.map((organization: Organization) => (
))
)
}
)}
{
!organizationsLoading && filteredOrganizations.length === 0 && (
No Organizations Found
Try adjusting your search query or create a new organization.
)
}
>
);
}
PlatformOrganizations.getLayout = (page: any) => {page};