Skip to content

Commit

Permalink
feat: Add new team editor - button and modal only (#3495)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamdelion authored Aug 12, 2024
1 parent b01ac93 commit 51031bf
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 12 deletions.
1 change: 1 addition & 0 deletions editor.planx.uk/src/lib/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const AVAILABLE_FEATURE_FLAGS = [
"SEARCH",
"OVERRIDE_CONSTRAINTS",
"TREES",
"ADD_NEW_EDITOR",
] as const;

type FeatureFlag = (typeof AVAILABLE_FEATURE_FLAGS)[number];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import Container from "@mui/material/Container";
import Typography from "@mui/material/Typography";
import React from "react";
import React, { useState } from "react";
import SettingsSection from "ui/editor/SettingsSection";

import { MembersTable } from "./MembersTable";
import { Props, TeamMember } from "./types";
import { AddNewEditorModal } from "./components/AddNewEditorModal";
import { MembersTable } from "./components/MembersTable";
import { TeamMember, TeamMembersProps } from "./types";

export const TeamMembers = ({ teamMembersByRole }: TeamMembersProps) => {
const [showModal, setShowModal] = useState(false);

export const TeamMembers: React.FC<Props> = ({ teamMembersByRole }) => {
const platformAdmins = (teamMembersByRole.platformAdmin || []).filter(
(member) => member.email,
);
Expand All @@ -24,14 +27,18 @@ export const TeamMembers: React.FC<Props> = ({ teamMembersByRole }) => {

return (
<Container maxWidth="contentWrap">
<SettingsSection>
<SettingsSection testId="team-editors">
<Typography variant="h2" component="h3" gutterBottom>
Team editors
</Typography>
<Typography variant="body1">
Editors have access to edit your services.
</Typography>
<MembersTable members={activeMembers} />
<MembersTable
members={activeMembers}
showAddMemberButton
setShowModal={setShowModal}
/>
</SettingsSection>
<SettingsSection>
<Typography variant="h2" component="h3" gutterBottom>
Expand All @@ -54,6 +61,9 @@ export const TeamMembers: React.FC<Props> = ({ teamMembersByRole }) => {
<MembersTable members={archivedMembers} />
</SettingsSection>
)}
{showModal && (
<AddNewEditorModal showModal={showModal} setShowModal={setShowModal} />
)}
</Container>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import Typography from "@mui/material/Typography";
import React from "react";
import InputGroup from "ui/editor/InputGroup";
import InputLabel from "ui/editor/InputLabel";
import Input from "ui/shared/Input";

import { AddNewEditorModalProps } from "../types";

export const AddNewEditorModal = ({
showModal,
setShowModal,
}: AddNewEditorModalProps) => (
<Dialog
aria-labelledby="dialog-heading"
PaperProps={{
sx: (theme) => ({
width: "100%",
maxWidth: theme.breakpoints.values.md,
borderRadius: 0,
borderTop: `20px solid ${theme.palette.primary.main}`,
background: "#FFF",
margin: theme.spacing(2),
}),
}}
open={showModal}
onClose={() => setShowModal(false)}
>
<form>
<DialogContent>
<Box sx={{ mt: 1, mb: 4 }}>
<Typography variant="h3" component="h2" id="dialog-heading">
Add a new editor
</Typography>
</Box>
<InputGroup flowSpacing>
<InputLabel label="First name" htmlFor="firstname">
<Input
name="firstname"
onChange={() => {
console.log("bla"); // TODO in next PR
}}
value={""}
errorMessage={""}
id="firstname"
/>
</InputLabel>
<InputLabel label="Last name" htmlFor="lastname">
<Input
name="lastname"
onChange={() => {
console.log("bla"); // TODO in next PR
}}
value={""}
errorMessage={""}
id="lastname"
/>
</InputLabel>
<InputLabel label="Email address" htmlFor="email">
<Input
name="email"
onChange={() => {
console.log("bla"); // TODO in next PR
}}
value={""}
errorMessage={""}
id="email"
/>
</InputLabel>
</InputGroup>
</DialogContent>
<DialogActions
sx={{
display: "flex",
justifyContent: "flex-start",
padding: 2,
}}
>
<Box>
<Button
variant="contained"
color="prompt"
onClick={() => setShowModal(false)} // nothing yet
data-testid="modal-create-user-button"
>
Create user
</Button>
<Button
variant="contained"
color="secondary"
sx={{ ml: 1.5 }}
onClick={() => setShowModal(false)}
data-testid="modal-cancel-button"
>
Cancel
</Button>
</Box>
</DialogActions>
</form>
</Dialog>
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import { hasFeatureFlag } from "lib/featureFlags";
import { AddButton } from "pages/Team";
import React from "react";

import { StyledAvatar, StyledTableRow } from "./styles";
import { TeamMember } from "./types";
import { StyledAvatar, StyledTableRow } from "./../styles";
import { MembersTableProps } from "./../types";

export const MembersTable: React.FC<{ members: TeamMember[] }> = ({
export const MembersTable = ({
members,
}) => {
showAddMemberButton,
setShowModal = () => true,
}: MembersTableProps) => {
const roleLabels: Record<string, string> = {
platformAdmin: "Admin",
teamEditor: "Editor",
Expand Down Expand Up @@ -79,6 +83,15 @@ export const MembersTable: React.FC<{ members: TeamMember[] }> = ({
<TableCell>{member.email}</TableCell>
</StyledTableRow>
))}
{showAddMemberButton && hasFeatureFlag("ADD_NEW_EDITOR") && (
<TableRow>
<TableCell colSpan={3}>
<AddButton onClick={() => setShowModal(true)}>
Add a new editor
</AddButton>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable jest/expect-expect */
import { screen, within } from "@testing-library/react";

import { setupTeamMembersScreen } from "./helpers/setupTeamMembersScreen";

jest.mock("lib/featureFlags.ts", () => ({
hasFeatureFlag: jest.fn().mockReturnValue(true),
}));

describe("when a user views the Team members screen with the ADD_NEW_EDITOR feature flag enabled", () => {
beforeEach(async () => {
await setupTeamMembersScreen();
});
it("shows the 'add new editor' button", async () => {
const teamEditorsTable = screen.getByTestId("team-editors");
await within(teamEditorsTable).findByText("Add a new editor");
});
});

describe("when a user with the ADD_NEW_EDITOR feature flag enabled presses 'add a new editor'", () => {
beforeEach(async () => {
const user = await setupTeamMembersScreen();
const teamEditorsTable = screen.getByTestId("team-editors");
const addEditorButton = await within(teamEditorsTable).findByText(
"Add a new editor"
);
user.click(addEditorButton);
});
it("opens the modal and displays the input fields", async () => {
expect(await screen.findByTestId("modal-create-user-button")).toBeVisible();
expect(await screen.findByLabelText("First name")).toBeVisible();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Role } from "@opensystemslab/planx-core/types";

import { TeamMember } from "../types";

export const exampleTeamMembersData: Record<Role, TeamMember[]> = {
platformAdmin: [
{
firstName: "Donella",
lastName: "Meadows",
email: "[email protected]",
id: 1,
role: "platformAdmin",
},
],
teamEditor: [
{
firstName: "Bill",
lastName: "Sharpe",
email: "[email protected]",
id: 2,
role: "teamEditor",
},
],
teamViewer: [],
public: [],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { screen } from "@testing-library/react";
import React from "react";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";

import { setup } from "../../../../../../testUtils";
import { TeamMembers } from "../../TeamMembers";
import { exampleTeamMembersData } from "./../exampleTeamMembersData";

export async function setupTeamMembersScreen() {
const { user } = setup(
<DndProvider backend={HTML5Backend}>
<TeamMembers teamMembersByRole={exampleTeamMembersData} />
</DndProvider>
);
await screen.findByText("Team editors");
return user;
}
12 changes: 11 additions & 1 deletion editor.planx.uk/src/pages/FlowEditor/components/Team/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { Role, User } from "@opensystemslab/planx-core/types";
import React, { SetStateAction } from "react";

export type TeamMember = Omit<User, "teams" | "isPlatformAdmin"> & {
role: Role;
};

export interface Props {
export interface TeamMembersProps {
teamMembersByRole: Record<string, TeamMember[]>;
}
export interface MembersTableProps {
members: TeamMember[];
showAddMemberButton?: boolean;
setShowModal?: React.Dispatch<SetStateAction<boolean>>;
}
export type AddNewEditorModalProps = {
showModal: boolean;
setShowModal: React.Dispatch<SetStateAction<boolean>>;
};
9 changes: 8 additions & 1 deletion editor.planx.uk/src/ui/editor/SettingsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, { ReactNode } from "react";

interface RootProps extends BoxProps {
background?: boolean;
"data-testid"?: string;
}

const Root = styled(Box, {
Expand All @@ -31,9 +32,15 @@ const Root = styled(Box, {
export default function SettingsSection({
children,
background,
testId,
}: {
children: ReactNode;
background?: boolean;
testId?: string;
}) {
return <Root background={background}>{children}</Root>;
return (
<Root data-testid={testId} background={background}>
{children}
</Root>
);
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@
"tests": "./scripts/start-containers-for-tests.sh",
"analytics": "docker compose -f ./docker-compose.yml -f ./docker-compose.local.yml --profile mock-services --profile analytics up -d --quiet-pull",
"logs": "docker compose logs --tail 30 -f"
},
"devDependencies": {
"typescript": "5.4.3"
}
}
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 51031bf

Please sign in to comment.