diff --git a/front/src/App.tsx b/front/src/App.tsx index a652c5c51..595825395 100644 --- a/front/src/App.tsx +++ b/front/src/App.tsx @@ -15,6 +15,7 @@ import { Companies } from '~/pages/companies/Companies'; import { Opportunities } from '~/pages/opportunities/Opportunities'; import { People } from '~/pages/people/People'; import { SettingsProfile } from '~/pages/settings/SettingsProfile'; +import { SettingsWorkspaceMembers } from '~/pages/settings/SettingsWorkspaceMembers'; import { AppInternalHooks } from './AppInternalHooks'; @@ -71,6 +72,10 @@ export function App() { element={ } /> + } + /> } /> diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index 54e415872..630126b32 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -2288,6 +2288,7 @@ export type Query = { __typename?: 'Query'; clientConfig: ClientConfig; currentUser: User; + currentWorkspace: Workspace; findManyCommentThreads: Array; findManyCompany: Array; findManyPerson: Array; @@ -3061,6 +3062,11 @@ export type UpdateUserMutationVariables = Exact<{ export type UpdateUserMutation = { __typename?: 'Mutation', updateUser: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }; +export type GetCurrentWorkspaceQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetCurrentWorkspaceQuery = { __typename?: 'Query', currentWorkspace: { __typename?: 'Workspace', id: string, workspaceMember?: Array<{ __typename?: 'WorkspaceMember', id: string, user: { __typename?: 'User', id: string, email: string, avatarUrl?: string | null, firstName?: string | null, lastName?: string | null } }> | null } }; + export type UpdateWorkspaceMutationVariables = Exact<{ data: WorkspaceUpdateInput; }>; @@ -4508,6 +4514,50 @@ export function useUpdateUserMutation(baseOptions?: Apollo.MutationHookOptions; export type UpdateUserMutationResult = Apollo.MutationResult; export type UpdateUserMutationOptions = Apollo.BaseMutationOptions; +export const GetCurrentWorkspaceDocument = gql` + query GetCurrentWorkspace { + currentWorkspace { + id + workspaceMember { + id + user { + id + email + avatarUrl + firstName + lastName + } + } + } +} + `; + +/** + * __useGetCurrentWorkspaceQuery__ + * + * To run a query within a React component, call `useGetCurrentWorkspaceQuery` and pass it any options that fit your needs. + * When your component renders, `useGetCurrentWorkspaceQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetCurrentWorkspaceQuery({ + * variables: { + * }, + * }); + */ +export function useGetCurrentWorkspaceQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetCurrentWorkspaceDocument, options); + } +export function useGetCurrentWorkspaceLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetCurrentWorkspaceDocument, options); + } +export type GetCurrentWorkspaceQueryHookResult = ReturnType; +export type GetCurrentWorkspaceLazyQueryHookResult = ReturnType; +export type GetCurrentWorkspaceQueryResult = Apollo.QueryResult; export const UpdateWorkspaceDocument = gql` mutation UpdateWorkspace($data: WorkspaceUpdateInput!) { updateWorkspace(data: $data) { diff --git a/front/src/modules/settings/components/SettingsNavbar.tsx b/front/src/modules/settings/components/SettingsNavbar.tsx index 9a988a97d..a3b7b14dc 100644 --- a/front/src/modules/settings/components/SettingsNavbar.tsx +++ b/front/src/modules/settings/components/SettingsNavbar.tsx @@ -8,6 +8,7 @@ import { IconLogout, IconSettings, IconUser, + IconUsers, } from '@/ui/icons/index'; import NavItem from '@/ui/layout/navbar/NavItem'; import NavItemsContainer from '@/ui/layout/navbar/NavItemsContainer'; @@ -51,6 +52,18 @@ export function SettingsNavbar() { } /> + } + soon={false} + active={ + !!useMatch({ + path: useResolvedPath('/settings/workspace-members').pathname, + end: true, + }) + } + /> theme.background.secondary}; + border: 1px solid ${({ theme }) => theme.border.color.medium}; + border-radius: ${({ theme }) => theme.spacing(2)}; + display: flex; + flex-direction: row; + margin-bottom: ${({ theme }) => theme.spacing(0)}; + margin-top: ${({ theme }) => theme.spacing(4)}; +`; + +const AvatarContainer = styled.div` + margin: ${({ theme }) => theme.spacing(3)}; +`; + +const TextContainer = styled.div` + display: flex; + flex-direction: column; + justify-content: center; +`; + +const NameAndEmailContainer = styled.div` + display: flex; + flex-direction: column; +`; + +const NameText = styled.span` + color: ${({ theme }) => theme.font.color.primary}; +`; + +const EmailText = styled.span` + color: ${({ theme }) => theme.font.color.tertiary}; +`; + +type OwnProps = { + workspaceMember: { + user: Pick; + }; +}; + +export function WorkspaceMemberCard({ workspaceMember }: OwnProps) { + return ( + + + + + + + + {workspaceMember.user.firstName} {workspaceMember.user.lastName}{' '} + + {workspaceMember.user.email} + + + + ); +} diff --git a/front/src/modules/workspace/services/index.ts b/front/src/modules/workspace/queries/index.ts similarity index 50% rename from front/src/modules/workspace/services/index.ts rename to front/src/modules/workspace/queries/index.ts index c37c258c7..18c6c2f7d 100644 --- a/front/src/modules/workspace/services/index.ts +++ b/front/src/modules/workspace/queries/index.ts @@ -1 +1,2 @@ +export * from './select'; export * from './update'; diff --git a/front/src/modules/workspace/queries/select.ts b/front/src/modules/workspace/queries/select.ts new file mode 100644 index 000000000..168d49723 --- /dev/null +++ b/front/src/modules/workspace/queries/select.ts @@ -0,0 +1,19 @@ +import { gql } from '@apollo/client'; + +export const GET_CURRENT_WORKSPACE = gql` + query GetCurrentWorkspace { + currentWorkspace { + id + workspaceMember { + id + user { + id + email + avatarUrl + firstName + lastName + } + } + } + } +`; diff --git a/front/src/modules/workspace/services/update.ts b/front/src/modules/workspace/queries/update.ts similarity index 100% rename from front/src/modules/workspace/services/update.ts rename to front/src/modules/workspace/queries/update.ts diff --git a/front/src/pages/settings/SettingsWorkspaceMembers.tsx b/front/src/pages/settings/SettingsWorkspaceMembers.tsx new file mode 100644 index 000000000..a349b8373 --- /dev/null +++ b/front/src/pages/settings/SettingsWorkspaceMembers.tsx @@ -0,0 +1,39 @@ +import styled from '@emotion/styled'; + +import { MainSectionTitle } from '@/ui/components/section-titles/MainSectionTitle'; +import { SubSectionTitle } from '@/ui/components/section-titles/SubSectionTitle'; +import { NoTopBarContainer } from '@/ui/layout/containers/NoTopBarContainer'; +import { WorkspaceMemberCard } from '@/workspace/components/WorkspaceMemberCard'; +import { useGetCurrentWorkspaceQuery } from '~/generated/graphql'; + +const StyledContainer = styled.div` + display: flex; + flex-direction: column; + padding: ${({ theme }) => theme.spacing(8)}; + width: 350px; + > * + * { + margin-top: ${({ theme }) => theme.spacing(8)}; + } +`; + +export function SettingsWorkspaceMembers() { + const { data } = useGetCurrentWorkspaceQuery(); + + return ( + + + Members + + {data?.currentWorkspace?.workspaceMember?.map((member) => ( + + ))} + + + ); +} diff --git a/server/src/core/workspace/resolvers/workspace.resolver.ts b/server/src/core/workspace/resolvers/workspace.resolver.ts index fcc480e69..e127036d6 100644 --- a/server/src/core/workspace/resolvers/workspace.resolver.ts +++ b/server/src/core/workspace/resolvers/workspace.resolver.ts @@ -1,4 +1,4 @@ -import { Args, Mutation, Resolver } from '@nestjs/graphql'; +import { Query, Args, Mutation, Resolver } from '@nestjs/graphql'; import { UseGuards } from '@nestjs/common'; import { Workspace } from 'src/core/@generated/workspace/workspace.model'; import { WorkspaceService } from '../services/workspace.service'; @@ -10,6 +10,7 @@ import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator'; import { WorkspaceUpdateInput } from 'src/core/@generated/workspace/workspace-update.input'; import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; import { Prisma } from '@prisma/client'; +import { assert } from 'src/utils/assert'; @UseGuards(JwtAuthGuard) @Resolver(() => Workspace) @@ -33,4 +34,21 @@ export class WorkspaceResolver { select: prismaSelect.value, } as Prisma.WorkspaceUpdateArgs); } + + @Query(() => Workspace) + async currentWorkspace( + @AuthWorkspace() workspace: Workspace, + @PrismaSelector({ modelName: 'User' }) + prismaSelect: PrismaSelect<'User'>, + ) { + const selectedWorkspace = await this.workspaceService.findUnique({ + where: { + id: workspace.id, + }, + select: prismaSelect.value, + }); + assert(selectedWorkspace, 'User not found'); + + return selectedWorkspace; + } }