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;
+ }
}