Skip to content

Commit

Permalink
Merge branch 'main' into issues/841-Integration_Margin_between_elemen…
Browse files Browse the repository at this point in the history
…ts_should_be_24px_rem_eqv
  • Loading branch information
loiswells97 committed Dec 22, 2023
2 parents f6bb996 + b7c206f commit 76ee828
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 33 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

### Changed

- Auth web component from user in local storage (#852)
- Save and download panel copy (#784)
- Application of styles in the web component to remove `sass-to-string` (#788)
- Info panel links open in a new tab (#803)
Expand Down
17 changes: 3 additions & 14 deletions src/containers/WebComponentLoader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { setInstructions } from "../redux/InstructionsSlice";
import { useProject } from "../hooks/useProject";
import { useEmbeddedMode } from "../hooks/useEmbeddedMode";
import { useProjectPersistence } from "../hooks/useProjectPersistence";
import { removeUser, setUser } from "../redux/WebComponentAuthSlice";
import { SettingsContext } from "../utils/settings";
import { useCookies } from "react-cookie";
import NewFileModal from "../components/Modals/NewFileModal";
Expand Down Expand Up @@ -39,7 +38,7 @@ const WebComponentLoader = (props) => {
const dispatch = useDispatch();
const { t } = useTranslation();
const [projectIdentifier, setProjectIdentifier] = useState(identifier);
const localStorageUser = JSON.parse(localStorage.getItem(authKey));
localStorage.setItem("authKey", authKey);
const user = useSelector((state) => state.auth.user);
const [loadCache, setLoadCache] = useState(!!!user);
const [loadRemix, setLoadRemix] = useState(!!user);
Expand Down Expand Up @@ -77,16 +76,6 @@ const WebComponentLoader = (props) => {
}
}, [theme, setCookie, dispatch]);

useEffect(() => {
if (JSON.stringify(user) !== JSON.stringify(localStorageUser)) {
if (localStorageUser) {
dispatch(setUser(localStorageUser));
} else {
dispatch(removeUser());
}
}
}, [user, localStorageUser, dispatch]);

useEffect(() => {
if (remixLoadFailed) {
setLoadCache(true);
Expand All @@ -106,14 +95,14 @@ const WebComponentLoader = (props) => {
useProject({
projectIdentifier: projectIdentifier,
code,
accessToken: user?.access_token || localStorageUser?.access_token,
accessToken: user?.access_token,
loadRemix,
loadCache,
remixLoadFailed,
});

useProjectPersistence({
user: user?.accessToken ? user : localStorageUser,
user,
project,
justLoaded,
hasShownSavePrompt,
Expand Down
36 changes: 22 additions & 14 deletions src/containers/WebComponentLoader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { Provider } from "react-redux";
import configureStore from "redux-mock-store";
import WebComponentLoader from "./WebComponentLoader";
import { disableTheming, setSenseHatAlwaysEnabled } from "../redux/EditorSlice";
import { removeUser, setUser } from "../redux/WebComponentAuthSlice";
import { setInstructions } from "../redux/InstructionsSlice";
import { setUser } from "../redux/WebComponentAuthSlice";
import { useProject } from "../hooks/useProject";
import { useProjectPersistence } from "../hooks/useProjectPersistence";
import localStorageUserMiddleware from "../redux/middlewares/localStorageUserMiddleware";
import { Cookies, CookiesProvider } from "react-cookie";

jest.mock("../hooks/useProject", () => ({
Expand All @@ -27,9 +28,9 @@ const instructions = { currentStepPosition: 3, project: { steps: steps } };
const authKey = "my_key";
const user = { access_token: "my_token" };

describe("When loaded as a cold user", () => {
describe("When no user is in state", () => {
beforeEach(() => {
const middlewares = [];
const middlewares = [localStorageUserMiddleware(setUser)];
const mockStore = configureStore(middlewares);
const initialState = {
editor: {
Expand All @@ -51,7 +52,7 @@ describe("When loaded as a cold user", () => {
cookies = new Cookies();
});

describe("When props are set - logged out", () => {
describe("with no user in local storage", () => {
beforeEach(() => {
render(
<Provider store={store}>
Expand Down Expand Up @@ -87,7 +88,7 @@ describe("When loaded as a cold user", () => {
},
hasShownSavePrompt: false,
justLoaded: false,
user: null,
user: undefined,
saveTriggered: false,
});
});
Expand All @@ -113,11 +114,18 @@ describe("When loaded as a cold user", () => {
test("Sets theme correctly", () => {
expect(cookies.cookies.theme).toEqual("light");
});

test("Sets the user in state", () => {
expect(store.getActions()).toEqual(
expect.arrayContaining([setUser(null)]),
);
});
});

describe("When props are set - logged in", () => {
describe("with user set in local storage", () => {
beforeEach(() => {
localStorage.setItem(authKey, JSON.stringify(user));
localStorage.setItem("authKey", authKey);
render(
<Provider store={store}>
<CookiesProvider cookies={cookies}>
Expand All @@ -138,7 +146,7 @@ describe("When loaded as a cold user", () => {
expect(useProject).toHaveBeenCalledWith({
projectIdentifier: identifier,
code,
accessToken: "my_token",
accessToken: undefined,
loadRemix: false,
loadCache: true,
remixLoadFailed: false,
Expand All @@ -147,7 +155,7 @@ describe("When loaded as a cold user", () => {

test("Calls useProjectPersistence hook with correct attributes", () => {
expect(useProjectPersistence).toHaveBeenCalledWith({
user,
user: undefined,
project: { components: [] },
hasShownSavePrompt: false,
justLoaded: false,
Expand Down Expand Up @@ -196,11 +204,11 @@ describe("When loaded as a cold user", () => {
});
});

describe("When the user object is set", () => {
describe("When user is in state", () => {
describe("before a remix load attempt", () => {
beforeEach(() => {
localStorage.setItem(authKey, JSON.stringify(user));
const middlewares = [];
const middlewares = [localStorageUserMiddleware(setUser)];
const mockStore = configureStore(middlewares);
const initialState = {
editor: {
Expand All @@ -222,7 +230,7 @@ describe("When the user object is set", () => {
cookies = new Cookies();
});

describe("When the user object is deleted", () => {
describe("when user in local storage is removed", () => {
beforeEach(() => {
localStorage.removeItem(authKey);
render(
Expand All @@ -236,12 +244,12 @@ describe("When the user object is set", () => {

test("Removes the user from state", () => {
expect(store.getActions()).toEqual(
expect.arrayContaining([removeUser()]),
expect.arrayContaining([setUser(null)]),
);
});
});

describe("When props are set - logged in", () => {
describe("when user is set in local storage", () => {
beforeEach(() => {
render(
<Provider store={store}>
Expand Down Expand Up @@ -316,7 +324,7 @@ describe("When the user object is set", () => {
cookies = new Cookies();
});

describe("When props are set - logged in", () => {
describe("when user in state and local storage", () => {
beforeEach(() => {
render(
<Provider store={store}>
Expand Down
18 changes: 18 additions & 0 deletions src/redux/middlewares/localStorageUserMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const localStorageUserMiddleware =
(setUser) => (store) => (next) => (action) => {
if (action.type.startsWith("editor")) {
const authKey = localStorage.getItem("authKey");
if (authKey) {
const localStorageUser = JSON.parse(localStorage.getItem(authKey));
if (
JSON.stringify(store.getState().auth.user) !==
JSON.stringify(localStorageUser)
) {
store.dispatch(setUser(localStorageUser));
}
}
}
next(action);
};

export default localStorageUserMiddleware;
94 changes: 94 additions & 0 deletions src/redux/middlewares/localStorageUserMiddleware.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import configureStore from "redux-mock-store";

import localStorageUserMiddleware from "./localStorageUserMiddleware";

describe(`localStorageUserMiddleware`, () => {
let store;
let next = jest.fn();
let setUser = jest.fn();
let user = { user: "some-user" };
const middleware = [localStorageUserMiddleware(setUser)];
const mockStore = configureStore({
reducer: setUser,
middleware,
});

describe("as a cold user", () => {
beforeEach(() => {
const initialState = {
editor: {},
auth: {},
};
store = mockStore(initialState);
store.dispatch = jest.fn();
});

describe(`when user is set in local storage`, () => {
beforeEach(() => {
localStorage.setItem("authKey", "some-key");
localStorage.setItem("some-key", JSON.stringify(user));
});

it(`expects setUser to be called`, () => {
localStorageUserMiddleware(setUser)(store)(next)({
type: "editor/someAction",
});
expect(setUser).toBeCalledWith(user);
});
});

describe(`when authKey is not set in local storage`, () => {
beforeEach(() => {
localStorage.removeItem("authKey");
});

it(`expects setUser to not be called`, () => {
localStorageUserMiddleware(setUser)(store)(next)({
type: "editor/someAction",
});
expect(setUser).not.toBeCalled();
});
});
});

describe("as a logged in user", () => {
const updatedUser = { user: "updated-user" };

beforeEach(() => {
const initialState = {
editor: {},
auth: { user },
};
store = mockStore(initialState);
store.dispatch = jest.fn();
});

describe(`when user in local storage has been updated`, () => {
beforeEach(() => {
localStorage.setItem("authKey", "some-key");
localStorage.setItem("some-key", JSON.stringify(updatedUser));
});

it(`expects setUser to be called`, () => {
localStorageUserMiddleware(setUser)(store)(next)({
type: "editor/someAction",
});
expect(setUser).toBeCalledWith(updatedUser);
});
});

describe(`when authKey is not set in local storage`, () => {
beforeEach(() => {
localStorage.removeItem("authKey");
localStorage.setItem("some-key", JSON.stringify(updatedUser));
});

it(`expects setUser to not be called`, () => {
localStorageUserMiddleware(setUser)(store)(next)({
type: "editor/someAction",
});
expect(setUser).not.toBeCalled();
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { configureStore } from "@reduxjs/toolkit";
import EditorReducer from "../redux/EditorSlice";
import InstructionsReducer from "../redux/InstructionsSlice";
import WebComponentAuthReducer from "../redux/WebComponentAuthSlice";
import EditorReducer from "../EditorSlice";
import InstructionsReducer from "../InstructionsSlice";
import WebComponentAuthReducer, { setUser } from "../WebComponentAuthSlice";
import userMiddleWare from "../middlewares/localStorageUserMiddleware";

const store = configureStore({
reducer: {
Expand All @@ -18,7 +19,7 @@ const store = configureStore({
],
ignoredPaths: ["auth.user"],
},
}),
}).concat(userMiddleWare(setUser)),
});

export default store;
2 changes: 1 addition & 1 deletion src/web-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as ReactDOMClient from "react-dom/client";
import * as Sentry from "@sentry/react";
import { BrowserTracing } from "@sentry/tracing";
import WebComponentLoader from "./containers/WebComponentLoader";
import store from "./app/WebComponentStore";
import store from "./redux/stores/WebComponentStore";
import { Provider } from "react-redux";
import "./utils/i18n";
import camelCase from "camelcase";
Expand Down

0 comments on commit 76ee828

Please sign in to comment.