Skip to content

Commit

Permalink
Implement members list (#776)
Browse files Browse the repository at this point in the history
It implements team members list
  • Loading branch information
selankon authored Oct 1, 2024
1 parent 82edc24 commit c34f7c9
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 4 deletions.
5 changes: 3 additions & 2 deletions src/components/Auth/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum ApiEndpoints {
VERIFY = 'users/verify',
RESEND_VERIFICATION = 'users/verify/code',
ACCOUNT_CREATE = 'organizations',
TEAM_MEMBERS = 'organizations/{address}/members',
}

interface IApiError {
Expand Down Expand Up @@ -44,8 +45,8 @@ export type ApiParams = {
}

export const api = <T>(
path: ApiEndpoints,
{ body, method = 'GET', headers = new Headers({}) }: ApiParams
path: string,
{ body, method = 'GET', headers = new Headers({}) }: ApiParams = {}
): Promise<T> => {
headers.append('Content-Type', 'application/json')
return fetch(`${import.meta.env.SAAS_URL}${path}`, {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Auth/useAuthProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const useAuthProvider = () => {
const { mutate: updateSigner, isIdle: signerIdle, isPending: signerPending, data: signerAddress } = useSigner()

const bearedFetch = useCallback(
<T>(path: ApiEndpoints, { headers = new Headers({}), ...params }: ApiParams) => {
<T>(path: string, { headers = new Headers({}), ...params }: ApiParams = {}) => {
if (!bearer) {
logout()
throw new Error('No bearer token')
Expand Down
28 changes: 28 additions & 0 deletions src/components/Layout/ErrorComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Flex, FlexProps, Text } from '@chakra-ui/react'
import { WarningIcon } from '@chakra-ui/icons'
import { useTranslation } from 'react-i18next'

const ErrorComponent = ({ error, ...props }: { error: Error } & FlexProps) => {
const { t } = useTranslation()

return (
<Flex
flexDirection='column'
gap={4}
alignItems='center'
mt={12}
mb={44}
px={{
base: 10,
sm: 14,
}}
{...props}
>
<WarningIcon />
<Text>{t('error.loading_page')}</Text>
<Text>{error.toString()}</Text>
</Flex>
)
}

export default ErrorComponent
118 changes: 117 additions & 1 deletion src/components/OrganizationSaas/Dashboard/Team.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,121 @@
import { Button, Flex } from '@chakra-ui/react'
import {
Avatar,
Badge,
Box,
Button,
Flex,
Heading,
Table,
TableContainer,
Tbody,
Td,
Text,
Th,
Thead,
Tr,
} from '@chakra-ui/react'
import { useState } from 'react'
import Invite from './Invite'
import { useAuth } from '~components/Auth/useAuth'
import { useQuery, UseQueryOptions } from '@tanstack/react-query'
import { ApiEndpoints } from '~components/Auth/api'
import { Loading } from '~src/router/SuspenseLoader'
import ErrorComponent from '~components/Layout/ErrorComponent'
import { Trans, useTranslation } from 'react-i18next'

type UserInfo = {
email: string
firstName: string
lastName: string
}

type ITeamMembersResponse = {
members: {
info: UserInfo
role: string
}[]
}

const useTeamMembers = ({
options,
}: {
options?: Omit<UseQueryOptions<ITeamMembersResponse>, 'queryKey' | 'queryFn'>
} = {}) => {
const { bearedFetch, signerAddress } = useAuth()
return useQuery({
queryKey: ['organizations', 'members', signerAddress],
queryFn: () => bearedFetch<ITeamMembersResponse>(ApiEndpoints.TEAM_MEMBERS.replace('{address}', signerAddress)),
...options,
})
}

const TeamList = () => {
const { t } = useTranslation()
const { data, isLoading, isError, error } = useTeamMembers()

if (isLoading) {
return <Loading minHeight={1} />
}
if (isError) {
return <ErrorComponent error={error} />
}
if (!data.members) {
return null
}

const members = data.members

return (
<Flex display={'column'}>
<Text fontWeight={'bold'}>
<Trans i18nKey={'team.team_members'}>Team members</Trans>
<Badge ml='1' colorScheme='green'>
{members.length}
</Badge>
</Text>
<TableContainer>
<Table>
<Thead>
<Tr>
<Th>
<Trans i18nKey={'team.member_name'}>Name</Trans>
</Th>
<Th>
<Trans i18nKey={'team.member_permission'}>Permission</Trans>
</Th>
</Tr>
</Thead>
<Tbody>
{members.map((member, i) => {
return (
<Tr key={i}>
<Td>
<Flex>
<Avatar
// src={member.info.}
name={member.info.firstName}
size='sm'
/>
<Box ml='3'>
<Text fontWeight='bold'>
{member.info.firstName} {member.info.lastName}
</Text>
<Text fontSize='sm'>{member.info.email}</Text>
</Box>
</Flex>
</Td>
<Td>
<Badge>{member.role}</Badge>
</Td>
</Tr>
)
})}
</Tbody>
</Table>
</TableContainer>
</Flex>
)
}

const Team = () => {
const [inviteView, setInviteView] = useState(false)
Expand All @@ -11,6 +126,7 @@ const Team = () => {
{!inviteView && <Button onClick={() => setInviteView(true)}>Invite People</Button>}
</Flex>
{inviteView && <Invite setInviteView={setInviteView} />}
<TeamList />
</>
)
}
Expand Down

2 comments on commit c34f7c9

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.