Skip to content

Commit

Permalink
feat: Adding a new user in the demo team automatically asigns the `de…
Browse files Browse the repository at this point in the history
…moUser` role
  • Loading branch information
DafyddLlyr committed Oct 29, 2024
1 parent 18ac5a9 commit 4332d5f
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
optimisticallyUpdateExistingMember,
} from "./lib/optimisticallyUpdateMembersTable";

export const DEMO_TEAM_ID = 32;

export const EditorUpsertModal = ({
setShowModal,
showModal,
Expand All @@ -34,6 +36,8 @@ export const EditorUpsertModal = ({
}: EditorModalProps) => {
const [showUserAlreadyExistsError, setShowUserAlreadyExistsError] =
useState<boolean>(false);
const [ teamId, teamSlug ] = useStore(state => [state.teamId, state.teamSlug])

Check failure on line 39 in editor.planx.uk/src/pages/FlowEditor/components/Team/components/EditorUpsertModal.tsx

View workflow job for this annotation

GitHub Actions / Run React Tests

src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx > when the addNewEditor modal is rendered > should not have any accessibility issues

TypeError: Cannot read properties of undefined (reading 'teamId') ❯ src/pages/FlowEditor/components/Team/components/EditorUpsertModal.tsx:39:57 ❯ memoizedSelector node_modules/.pnpm/[email protected][email protected]/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js:79:30 ❯ getSnapshotWithSelector node_modules/.pnpm/[email protected][email protected]/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js:134:14 ❯ mountSyncExternalStore node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom.development.js:16799:20 ❯ Object.useSyncExternalStore node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom.development.js:17727:14 ❯ useSyncExternalStore node_modules/.pnpm/[email protected]/node_modules/react/cjs/react.development.js:1676:21 ❯ useSyncExternalStoreWithSelector node_modules/.pnpm/[email protected][email protected]/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js:145:15 ❯ useStore node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/zustand/esm/index.mjs:17:17 ❯ Module.useBoundStore node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/zustand/esm/index.mjs:34:51 ❯ EditorUpsertModal src/pages/FlowEditor/components/Team/components/EditorUpsertModal.tsx:39:32
const isDemoTeam = teamId === DEMO_TEAM_ID;

const toast = useToast();

Expand All @@ -56,15 +60,11 @@ export const EditorUpsertModal = ({
};

const handleSubmitToAddNewUser = async () => {
const { teamId, teamSlug } = useStore.getState();

const createUserResult = await createAndAddUserToTeam(
formik.values.email,
formik.values.firstName,
formik.values.lastName,
const createUserResult = await createAndAddUserToTeam({
newUser: formik.values,
teamId,
teamSlug,
).catch((err) => {
}).catch((err) => {
if (isUserAlreadyExistsError(err.message)) {
setShowUserAlreadyExistsError(true);
}
Expand Down Expand Up @@ -114,6 +114,8 @@ export const EditorUpsertModal = ({
firstName: initialValues?.firstName || "",
lastName: initialValues?.lastName || "",
email: initialValues?.email || "",
// Users within the Demo team are granted a role with a restricted permission set
role: isDemoTeam ? "demoUser" : "teamEditor",
},
validationSchema: upsertEditorSchema,
onSubmit: handleSubmit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export const optimisticallyAddNewMember = async (
const existingMembers = useStore.getState().teamMembers;
const newMember: TeamMember = {
...values,
role: "teamEditor",
id: userId,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,41 @@ import { FetchResult, gql } from "@apollo/client";
import { GET_USERS_FOR_TEAM_QUERY } from "routes/teamMembers";

import { client } from "../../../../../lib/graphql";
import { AddNewEditorFormValues } from "../types";

type CreateAndAddUserResponse = FetchResult<{
insert_users_one: { id: number; __typename: "users" };
insertUsersOne: { id: number; __typename: "users" };
}>;

export const createAndAddUserToTeam = async (
email: string,
firstName: string,
lastName: string,
teamId: number,
teamSlug: string
export const createAndAddUserToTeam = async ({
newUser,
teamId,
teamSlug,
}: { newUser: AddNewEditorFormValues, teamId: number, teamSlug: string }
) => {
// NB: the user is hard-coded with the 'teamEditor' role for now
const response: CreateAndAddUserResponse = await client.mutate({
mutation: gql`
mutation CreateAndAddUserToTeam(
$email: String!
$firstName: String!
$lastName: String!
$teamId: Int!
$role: user_roles_enum!
) {
insert_users_one(
insertUsersOne: insert_users_one(
object: {
email: $email
first_name: $firstName
last_name: $lastName
teams: { data: { role: teamEditor, team_id: $teamId } }
teams: { data: { role: $role, team_id: $teamId } }
}
) {
id
}
}
`,
variables: {
email,
firstName,
lastName,
...newUser,
teamId,
},
refetchQueries: [
Expand All @@ -47,7 +45,7 @@ export const createAndAddUserToTeam = async (
});

if (response.data) {
return response.data.insert_users_one;
return response.data.insertUsersOne;
}
throw new Error("Unable to create user");
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { waitFor, within } from "@testing-library/react";
import { useStore } from "pages/FlowEditor/lib/store";
import { vi } from "vitest";

import { DEMO_TEAM_ID } from "../components/EditorUpsertModal";
import { setupTeamMembersScreen } from "./helpers/setupTeamMembersScreen";
import { userTriesToAddNewEditor } from "./helpers/userTriesToAddNewEditor";
import { mockTeamMembersData } from "./mocks/mockTeamMembersData";
import { mockPlatformAdminUser } from "./mocks/mockUsers";

const { setState, getState } = useStore;

vi.mock(
"pages/FlowEditor/components/Team/queries/createAndAddUserToTeam.tsx",
async () => ({
createAndAddUserToTeam: vi.fn().mockResolvedValue({
id: 1,
__typename: "users",
}),
})
);

describe("adding a new user to the Demo team", () => {
beforeEach(async () => {
setState({
user: mockPlatformAdminUser,
teamMembers: mockTeamMembersData,
teamId: DEMO_TEAM_ID,
});
});

it("assigns the `demoUser` role automatically", async () => {
let currentUsers = getState().teamMembers
expect(currentUsers).toHaveLength(3);

const { user, getByTestId } = await setupTeamMembersScreen();
await userTriesToAddNewEditor(user);

const membersTable = getByTestId("members-table-add-editor");

await waitFor(() => {
expect(
within(membersTable).getByText(/Mickey Mouse/),
).toBeInTheDocument();
});

currentUsers = getState().teamMembers
expect(currentUsers).toHaveLength(4);

// Role correctly assigned to user
const newUser = getState().teamMembers[3];
expect(newUser.role).toBe("demoUser");

// Use role tag displayed in table
expect(within(membersTable).getByText("demoUser")).toBeVisible();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe("when a user presses 'add a new editor'", () => {
teamMembers: mockTeamMembersData,
user: mockPlatformAdminUser,
teamSlug: "planx",
teamId: 1,
});
const { user } = await setupTeamMembersScreen();

Expand All @@ -59,6 +60,7 @@ describe("when a user fills in the 'add a new editor' form correctly", () => {
teamMembers: mockTeamMembersData,
user: mockPlatformAdminUser,
teamSlug: "planx",
teamId: 1,
});
const { user } = await setupTeamMembersScreen();
await userTriesToAddNewEditor(user);
Expand Down Expand Up @@ -112,6 +114,7 @@ describe("'add a new editor' button is hidden from Templates team", () => {
teamMembers: mockTeamMembersData,
user: mockPlatformAdminUser,
teamSlug: "templates",
teamId: 2,
});
});

Expand All @@ -130,6 +133,7 @@ describe("when a user is not a platform admin", () => {
teamMembers: mockTeamMembersData,
user: mockPlainUser,
teamSlug: "trumptonshire",
teamId: 3,
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe("when a user presses 'remove' button", () => {
teamMembers: mockTeamMembersData,
user: mockPlatformAdminUser,
teamSlug: "planx",
teamId: 1,
});
const { user, container } = await setupTeamMembersScreen();

Expand Down Expand Up @@ -74,6 +75,7 @@ describe("when a user clicks 'Remove user' button", () => {
teamMembers: mockTeamMembersData,
user: mockPlatformAdminUser,
teamSlug: "planx",
teamId: 1,
});
const { user } = await setupTeamMembersScreen();

Expand Down Expand Up @@ -119,6 +121,7 @@ describe("'remove' button is hidden from Templates team", () => {
teamMembers: mockTeamMembersData,
user: mockPlatformAdminUser,
teamSlug: "templates",
teamId: 2,
});
});

Expand All @@ -137,6 +140,7 @@ describe("when a user is not a platform admin", () => {
teamMembers: mockTeamMembersData,
user: mockPlainUser,
team: "planx",
teamId: 1,
});

await setupTeamMembersScreen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe("when a user presses 'edit button'", () => {
teamMembers: mockTeamMembersData,
user: mockPlatformAdminUser,
teamSlug: "planx",
teamId: 1,
});

const { user } = await setupTeamMembersScreen();
Expand Down Expand Up @@ -171,6 +172,7 @@ describe("'edit' button is hidden from Templates team", () => {
teamMembers: mockTeamMembersData,
user: mockPlatformAdminUser,
teamSlug: "templates",
teamId: 3,
});
});

Expand All @@ -188,6 +190,7 @@ describe("when a user is not a platform admin", () => {
teamMembers: mockTeamMembersData,
user: mockPlainUser,
team: "planx",
teamId: 1,
});

await setupTeamMembersScreen();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Role, User } from "@opensystemslab/planx-core/types";
import { Role, TeamRole, User } from "@opensystemslab/planx-core/types";
import React, { SetStateAction } from "react";

export type TeamMember = ActiveTeamMember | ArchivedTeamMember;
Expand All @@ -25,6 +25,7 @@ export interface AddNewEditorFormValues {
email: string;
firstName: string;
lastName: string;
role: TeamRole;
}

export interface UpdateEditorFormValues {
Expand Down

0 comments on commit 4332d5f

Please sign in to comment.