Skip to content

Commit

Permalink
feat(savebutton): add auth and project ownership states to save button
Browse files Browse the repository at this point in the history
  • Loading branch information
sra405 committed Dec 4, 2023
1 parent f3817ec commit b149dc4
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 76 deletions.
2 changes: 1 addition & 1 deletion src/assets/stylesheets/SaveStatus.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
display: flex;
justify-content: flex-end;
margin-block: 0;
margin-inline: $space-1 $space-0-5;
padding-inline: $space-1;
}

.save-status--mobile {
Expand Down
12 changes: 6 additions & 6 deletions src/components/ProjectBar/ProjectBar.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ describe("When logged in and user owns project", () => {
expect(screen.queryByText("header.download")).toBeInTheDocument();
});

test("Save button shown", () => {
expect(screen.queryByText("header.save")).toBeInTheDocument();
test("Save button is not shown", () => {
expect(screen.queryByText("header.save")).not.toBeInTheDocument();
});
});

Expand Down Expand Up @@ -98,8 +98,8 @@ describe("When logged in and no project identifier", () => {
expect(screen.queryByText(project.name)).toBeInTheDocument();
});

test("Save button shown", () => {
expect(screen.queryByText("header.save")).toBeInTheDocument();
test("Save button is not shown", () => {
expect(screen.queryByText("header.save")).not.toBeInTheDocument();
});
});

Expand Down Expand Up @@ -136,8 +136,8 @@ describe("When not logged in", () => {
expect(screen.queryByText(project.name)).toBeInTheDocument();
});

test("Save button shown", () => {
expect(screen.queryByText("header.save")).toBeInTheDocument();
test("Login to save button shown", () => {
expect(screen.queryByText("header.loginToSave")).toBeInTheDocument();
});
});

Expand Down
14 changes: 9 additions & 5 deletions src/components/SaveButton/SaveButton.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState, useCallback } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
import classNames from "classnames";

import { logInEvent } from "../../events/WebComponentCustomEvents";
import { isOwner } from "../../utils/projectHelpers";

import DesignSystemButton from "../DesignSystemButton/DesignSystemButton";
import SaveIcon from "../../assets/icons/save.svg";
Expand All @@ -17,26 +18,29 @@ const SaveButton = ({ className, type }) => {
const loading = useSelector((state) => state.editor.loading);
const webComponent = useSelector((state) => state.editor.webComponent);
const user = useSelector((state) => state.auth.user);
const project = useSelector((state) => state.editor.project);

useEffect(() => {
if (!type) {
setButtonType(!!webComponent ? "primary" : "secondary");
}
}, [webComponent, type]);

const onClickSave = async () => {
const onClickSave = useCallback(async () => {
if (window.plausible) {
window.plausible("Save button");
}
if (!user) {
document.dispatchEvent(logInEvent);
}
dispatch(triggerSave());
};
}, [dispatch, user]);

const projectOwner = isOwner(user, project);

return (
loading === "success" &&
!user &&
!projectOwner &&
buttonType && (
<DesignSystemButton
className={classNames(className, {
Expand All @@ -45,7 +49,7 @@ const SaveButton = ({ className, type }) => {
"btn--tertiary": buttonType === "tertiary",
})}
onClick={onClickSave}
text={t("header.save")}
text={t(user ? "header.save" : "header.loginToSave")}
textAlways
icon={<SaveIcon />}
type={buttonType}
Expand Down
206 changes: 143 additions & 63 deletions src/components/SaveButton/SaveButton.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,108 @@ import SaveButton from "./SaveButton";

const logInHandler = jest.fn();

beforeAll(() => {
document.addEventListener("editor-logIn", logInHandler);
});

describe("When project is loaded", () => {
describe("with webComponent=false", () => {
beforeAll(() => {
document.addEventListener("editor-logIn", logInHandler);
});

describe("With logged in user", () => {
let store;

describe("who doesn't own the project", () => {
beforeEach(() => {
const middlewares = [];
const mockStore = configureStore(middlewares);
const initialState = {
editor: {
loading: "success",
webComponent: true,
project: {
identifier: "hot-diggity-dog",
user_id: "some-other-user",
},
},
auth: {
user: {
profile: {
user: "some-dummy-user",
},
},
},
};
store = mockStore(initialState);
render(
<Provider store={store}>
<SaveButton />
</Provider>,
);
});

test("Save button renders", () => {
expect(screen.queryByText("header.save")).toBeInTheDocument();
});

test("Does not render a login to save button", () => {
expect(
screen.queryByText("header.loginToSave"),
).not.toBeInTheDocument();
});

test("Clicking save dispatches trigger save action", () => {
const saveButton = screen.queryByText("header.save");
fireEvent.click(saveButton);
expect(store.getActions()).toEqual([triggerSave()]);
});

test("Clicking save does not trigger a logInHandler event", () => {
const saveButton = screen.queryByText("header.save").parentElement;
fireEvent.click(saveButton);
expect(logInHandler).not.toHaveBeenCalled();
});
});

describe("who does own the project", () => {
beforeEach(() => {
const middlewares = [];
const mockStore = configureStore(middlewares);
const initialState = {
editor: {
loading: "success",
webComponent: true,
project: {
identifier: "hot-diggity-dog",
user_id: "some-dummy-user",
},
},
auth: {
user: {
profile: {
user: "some-dummy-user",
},
},
},
};
store = mockStore(initialState);
render(
<Provider store={store}>
<SaveButton />
</Provider>,
);
});

test("Does not render save button", () => {
expect(screen.queryByText("header.save")).not.toBeInTheDocument();
});

test("Does not render a login to save button", () => {
expect(
screen.queryByText("header.loginToSave"),
).not.toBeInTheDocument();
});
});
});

describe("Without a logged in user", () => {
let store;

beforeEach(() => {
Expand All @@ -33,29 +129,27 @@ describe("When project is loaded", () => {
);
});

test("Save button renders", () => {
expect(screen.queryByText("header.save")).toBeInTheDocument();
test("Login to save button renders", () => {
expect(screen.queryByText("header.loginToSave")).toBeInTheDocument();
});

test("Does not render a save button", () => {
expect(screen.queryByText("header.save")).not.toBeInTheDocument();
});

test("Clicking save dispatches trigger save action", () => {
const saveButton = screen.queryByText("header.save");
const saveButton = screen.queryByText("header.loginToSave");
fireEvent.click(saveButton);
expect(store.getActions()).toEqual([triggerSave()]);
});

test("renders a secondary button", () => {
const saveButton = screen.queryByText("header.save").parentElement;
expect(saveButton).toHaveClass("btn--secondary");
});

test("Clicking save triggers a logInHandler event", () => {
const saveButton = screen.queryByText("header.save").parentElement;
const saveButton = screen.queryByText("header.loginToSave").parentElement;
fireEvent.click(saveButton);
expect(logInHandler).toHaveBeenCalled();
});
});

describe("with webComponent=true", () => {
describe("with webComponent=false", () => {
let store;

beforeEach(() => {
Expand All @@ -64,7 +158,7 @@ describe("When project is loaded", () => {
const initialState = {
editor: {
loading: "success",
webComponent: true,
webComponent: false,
},
auth: {},
};
Expand All @@ -76,26 +170,41 @@ describe("When project is loaded", () => {
);
});

test("Save button renders", () => {
expect(screen.queryByText("header.save")).toBeInTheDocument();
test("Renders a secondary button", () => {
const saveButton = screen.queryByText("header.loginToSave").parentElement;
expect(saveButton).toHaveClass("btn--secondary");
});
});

test("Clicking save dispatches trigger save action", () => {
const saveButton = screen.queryByText("header.save");
fireEvent.click(saveButton);
expect(store.getActions()).toEqual([triggerSave()]);
describe("with webComponent=true", () => {
let store;

beforeEach(() => {
const middlewares = [];
const mockStore = configureStore(middlewares);
const initialState = {
editor: {
loading: "success",
webComponent: true,
},
auth: {},
};
store = mockStore(initialState);
render(
<Provider store={store}>
<SaveButton />
</Provider>,
);
});

test("renders a primary button", () => {
const saveButton = screen.queryByText("header.save").parentElement;
test("Renders a primary button", () => {
const saveButton = screen.queryByText("header.loginToSave").parentElement;
expect(saveButton).toHaveClass("btn--primary");
});
});

test("Clicking save triggers a logInHandler event", () => {
const saveButton = screen.queryByText("header.save").parentElement;
fireEvent.click(saveButton);
expect(logInHandler).toHaveBeenCalled();
});
afterAll(() => {
document.removeEventListener("editor-logIn", logInHandler);
});
});

Expand All @@ -113,41 +222,12 @@ describe("When project is not loaded", () => {
</Provider>,
);
});
test("Does not render save button", () => {
expect(screen.queryByText("header.save")).not.toBeInTheDocument();
});
});

describe("With an auth object", () => {
beforeEach(() => {
const middlewares = [];
const mockStore = configureStore(middlewares);
const initialState = {
editor: {
loading: "success",
webComponent: true,
},
auth: {
user: {
access_token: "some-dummy-token",
},
},
};
const store = mockStore(initialState);
render(
<Provider store={store}>
<SaveButton />
</Provider>,
);
test("Does not render a login to save button", () => {
expect(screen.queryByText("header.loginToSave")).not.toBeInTheDocument();
});

test("Clicking save does not trigger a logInHandler event", () => {
const saveButton = screen.queryByText("header.save").parentElement;
fireEvent.click(saveButton);
expect(logInHandler).not.toHaveBeenCalled();
test("Does not render a save button", () => {
expect(screen.queryByText("header.save")).not.toBeInTheDocument();
});
});

afterAll(() => {
document.removeEventListener("editor-logIn", logInHandler);
});
3 changes: 2 additions & 1 deletion src/utils/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ i18n
projects: "Your projects",
renameProject: "Edit project name",
renameSave: "Save project name",
save: "Log in to save",
save: "Save",
loginToSave: "Log in to save",
settings: "Settings",
},
imagePanel: {
Expand Down

0 comments on commit b149dc4

Please sign in to comment.