From c748ae6ce2a0e64160f5ca017385a638b2e9a832 Mon Sep 17 00:00:00 2001
From: Divyanshi Singh <divyanshipilot@gmail.com>
Date: Apr 02 2021 08:38:21 +0000
Subject: [PATCH 1/7] redux toolkit store configuration implemented


---

diff --git a/package.json b/package.json
index 20d0779..fab2975 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
   "private": true,
   "homepage": ".",
   "dependencies": {
+    "@reduxjs/toolkit": "^1.5.1",
     "bootstrap": "^4.4.1",
     "dateformat": "^3.0.3",
     "react": "^16.5.2",
diff --git a/src/configureStore.js b/src/configureStore.js
new file mode 100644
index 0000000..2252549
--- /dev/null
+++ b/src/configureStore.js
@@ -0,0 +1,14 @@
+import { configureStore } from '@reduxjs/toolkit';
+import logger from 'redux-logger';
+import thunkMiddleware from 'redux-thunk';
+import reducer from './reducers';
+
+export default function configureAppStore(initialState) {
+    const store = configureStore({
+        reducer,
+        middleware: [ logger,thunkMiddleware],
+        devTools: process.env.NODE_ENV !== 'production',
+        initialState,
+    })
+    return store;
+}
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 35f417c..6a8df27 100644
--- a/src/index.js
+++ b/src/index.js
@@ -9,17 +9,11 @@ import 'typeface-open-sans'
 import App from './App';
 import * as serviceWorker from './serviceWorker';
 
-import { createStore, applyMiddleware } from 'redux'
-import thunkMiddleware from 'redux-thunk'
-import { createLogger } from 'redux-logger'
-import { Provider } from 'react-redux'
-import reducer from './reducers'
+import { Provider } from 'react-redux';
+import configureAppStore from './configureStore';
+import { defaultState } from './reducers';
 
-const loggerMiddleware = createLogger();
-const store = createStore(reducer, applyMiddleware(
-  thunkMiddleware,
-  loggerMiddleware
-));
+const store= configureAppStore(defaultState);
 
 ReactDOM.render(
     <React.StrictMode>
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 5e628e0..4dfe6f1 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -1,6 +1,6 @@
 import ActionTypes from "../constants"
 
-const defaultState = {
+export const defaultState = {
   landing_page: {
     blockerbugs: {},
     devel: 0,
diff --git a/yarn.lock b/yarn.lock
index 85bfaa4..626a2c7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1359,6 +1359,16 @@
   resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
   integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
 
+"@reduxjs/toolkit@^1.5.1":
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.5.1.tgz#05daa2f6eebc70dc18cd98a90421fab7fa565dc5"
+  integrity sha512-PngZKuwVZsd+mimnmhiOQzoD0FiMjqVks6ituO1//Ft5UEX5Ca9of13NEjo//pU22Jk7z/mdXVsmDfgsig1osA==
+  dependencies:
+    immer "^8.0.1"
+    redux "^4.0.0"
+    redux-thunk "^2.3.0"
+    reselect "^4.0.0"
+
 "@svgr/babel-plugin-add-jsx-attribute@^4.2.0":
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1"
@@ -5236,6 +5246,11 @@ immer@1.10.0:
   resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
   integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
 
+immer@^8.0.1:
+  version "8.0.4"
+  resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.4.tgz#3a21605a4e2dded852fb2afd208ad50969737b7a"
+  integrity sha512-jMfL18P+/6P6epANRvRk6q8t+3gGhqsJ9EuJ25AXE+9bNTYtssvzeYbEd0mXRYWCmmXSIbnlpz6vd6iJlmGGGQ==
+
 import-cwd@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
@@ -8837,7 +8852,7 @@ redux-thunk@^2.3.0:
   resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
   integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
 
-redux@^4.0.5:
+redux@^4.0.0, redux@^4.0.5:
   version "4.0.5"
   resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
   integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
@@ -9017,6 +9032,11 @@ requires-port@^1.0.0:
   resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
   integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
 
+reselect@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
+  integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
+
 resolve-cwd@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"

From 8ac698fda28cb19aef47004023409ecd240cc3c9 Mon Sep 17 00:00:00 2001
From: Divyanshi Singh <divyanshipilot@gmail.com>
Date: Apr 02 2021 10:28:33 +0000
Subject: [PATCH 2/7] redux-toolkit: reducer splitting, actions implementation


---

diff --git a/src/actions/reduxActions.js b/src/actions/reduxActions.js
index 80a3461..306bca1 100644
--- a/src/actions/reduxActions.js
+++ b/src/actions/reduxActions.js
@@ -1,15 +1,8 @@
-import ActionTypes from '../constants';
+import { loadData, loadDataResp } from '../reducers/landingPageSlice';
+import { loadWizardDataResp, loadWizardData } from '../reducers/wizardSlice';
 
-export const loadDataResp = payload => ({
-    type: ActionTypes.LOAD_DATA_RESP,
-    payload: payload
-})
-
-export const loadData = payload => dispatch => {
-    dispatch({
-        type: ActionTypes.LOAD_DATA,
-        payload: payload
-    });
+export const fetchLandingPageData = (dispatch) => dispatch => {
+    dispatch(loadData());
 
     fetch(window.env.ORACULUM_API_URL_v1 + "landing_page")
     .then(blob => blob.json())
@@ -21,17 +14,8 @@ export const loadData = payload => dispatch => {
     });
 }
 
-export const loadWizardDataResp = payload => ({
-    type: ActionTypes.LOAD_WIZARD_DATA_RESP,
-    payload: payload
-})
-
-export const loadWizardData = payload => dispatch => {
-    dispatch({
-        type: ActionTypes.LOAD_WIZARD_DATA,
-        payload: payload
-    });
-
+export const fetchWizardData = payload => dispatch => {
+    dispatch(loadWizardData())
     fetch(window.env.ORACULUM_API_URL_v1 + "actions/all")
     .then(blob => blob.json())
     .then(data => {
diff --git a/src/configureStore.js b/src/configureStore.js
index 2252549..70c6cd6 100644
--- a/src/configureStore.js
+++ b/src/configureStore.js
@@ -1,7 +1,13 @@
-import { configureStore } from '@reduxjs/toolkit';
+import { configureStore, combineReducers } from '@reduxjs/toolkit';
 import logger from 'redux-logger';
 import thunkMiddleware from 'redux-thunk';
-import reducer from './reducers';
+import landingPageReducer from './reducers/landingPageSlice';
+import wizardReducer from './reducers/wizardSlice';
+
+const reducer = combineReducers({
+    landing_page: landingPageReducer,
+    wizard: wizardReducer
+})
 
 export default function configureAppStore(initialState) {
     const store = configureStore({
diff --git a/src/landingpage/LandingPage.js b/src/landingpage/LandingPage.js
index b1bee82..aec079a 100644
--- a/src/landingpage/LandingPage.js
+++ b/src/landingpage/LandingPage.js
@@ -11,7 +11,7 @@ import Hideable from "./Hideable"
 import _ from "lodash"
 
 import { connect } from "react-redux"
-import { loadData } from "../actions/reduxActions"
+import { fetchLandingPageData } from "../actions/reduxActions"
 
 import Cookies from "universal-cookie"
 
@@ -38,7 +38,7 @@ class LandingPage extends Component {
   }
 
   componentDidMount() {
-    this.props.dispatch(loadData())
+    this.props.dispatch(fetchLandingPageData())
   }
 
   toggle_config_mode(e) {
diff --git a/src/reducers/landingPageSlice.js b/src/reducers/landingPageSlice.js
new file mode 100644
index 0000000..d1e2cbb
--- /dev/null
+++ b/src/reducers/landingPageSlice.js
@@ -0,0 +1,28 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+const landingPageReducer = createSlice({
+  name: "landing_page",
+  initialState: {
+    blockerbugs: {},
+    devel: 0,
+    meetings: [],
+    schedule: [],
+    last_qa_meeting: {},
+    stable: 0,
+    config_mode: false,
+    enabled_components: ["events", "blockers", "minutes"],
+
+    loading: false
+  },
+  reducers: {
+    loadData(state, action) {
+      if (!state.loading) state.loading = true;
+    },
+    loadDataResp(state, action) {
+      state.loading = false;
+      Object.assign(state, { ...action.payload });
+    }
+  }
+});
+export const { loadData, loadDataResp } = landingPageReducer.actions;
+export default landingPageReducer.reducer;
diff --git a/src/reducers/wizardSlice.js b/src/reducers/wizardSlice.js
new file mode 100644
index 0000000..f48032b
--- /dev/null
+++ b/src/reducers/wizardSlice.js
@@ -0,0 +1,24 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+const wizardReducer = createSlice({
+  name: "wizard",
+  initialState: {
+    actions: [],
+    providers: [],
+    all_actions: [],
+
+    loading: false
+  },
+  reducers: {
+    loadWizardData(state, action) {
+      if (!state.loading) state.loading = true;
+    },
+    loadWizardDataResp(state, action) {
+      state.loading = false;
+      state.providers = action.payload.providers;
+      state.all_actions = action.payload.actions;
+    }
+  }
+});
+export const { loadWizardData, loadWizardDataResp } = wizardReducer.actions;
+export default wizardReducer.reducer;
diff --git a/src/wizard/Wizard.js b/src/wizard/Wizard.js
index a9ecb3e..1b136bd 100644
--- a/src/wizard/Wizard.js
+++ b/src/wizard/Wizard.js
@@ -6,7 +6,7 @@ import Actions from "./Actions"
 import { Container, Row } from "reactstrap"
 
 import { connect } from "react-redux"
-import { loadWizardData } from "../actions/reduxActions"
+import { fetchWizardData } from "../actions/reduxActions"
 
 class Wizard extends Component {
   constructor(props) {
@@ -26,7 +26,7 @@ class Wizard extends Component {
         })
       })
 
-    this.props.dispatch(loadWizardData())
+    this.props.dispatch(fetchWizardData())
   }
 
   show_actions(actions) {

From 042f3e751f7c8f89220c4437ce6716d36f952dcd Mon Sep 17 00:00:00 2001
From: Divyanshi Singh <divyanshipilot@gmail.com>
Date: Apr 04 2021 08:18:28 +0000
Subject: [PATCH 3/7] code splitting and project structure modification


---

diff --git a/src/App.js b/src/App.js
index b782aa0..3f55033 100644
--- a/src/App.js
+++ b/src/App.js
@@ -4,7 +4,7 @@ import { Route, Switch } from 'react-router';
 import { BrowserRouter } from 'react-router-dom'
 
 import Wizard from './wizard/Wizard';
-import LandingPage from './landingpage/LandingPage';
+import LandingPage from './Containers/LandingPage';
 import NotFound from './NotFound';
 
 
diff --git a/src/Components/Blockers/index.js b/src/Components/Blockers/index.js
new file mode 100644
index 0000000..3466cab
--- /dev/null
+++ b/src/Components/Blockers/index.js
@@ -0,0 +1,61 @@
+import React, { Component } from "react";
+import { Row } from "reactstrap";
+import SourceLink from "../SourceLinks";
+import Header from "../Header";
+import Table from "../Table";
+
+class Blockers extends Component {
+  constructor(props) {
+    super(props);
+    this.state = { blockerbugs: {}, release: 0 };
+  }
+
+  render() {
+    const { data } = this.props;
+    const tableContentBeta = [
+      ["Proposed Blockers", data.beta_blockers_proposed],
+      ["Accepted Blockers", data.beta_blockers],
+      ["Proposed FEs", data.beta_fe_proposed],
+      ["Accepted FEs", data.beta_fe]
+    ];
+
+    const tableContentFinal = [
+      ["Proposed Blockers", data.final_blockers_proposed],
+      ["Accepted Blockers", data.final_blockers],
+      ["Proposed FEs", data.final_fe_proposed],
+      ["Accepted FEs", data.final_fe]
+    ];
+    if (this.props.data)
+      return (
+        <div>
+          <Header
+            headerText={`Fedora ${this.props.release} blockers and FEs`}
+            headerLink="https://qa.fedoraproject.org/blockerbugs/"
+            headerClass="padded"
+          />
+
+          <Row>
+            <div className="col-md-6">
+							<Table 
+								className="events"
+								tableHead={['Beta']}
+								tableContent={tableContentBeta} 
+								customClass="bugscount"
+							/>
+            </div>
+
+            <div className="col-md-6">
+              <Table
+								className="events"
+								tableHead={['Final']}
+								tableContent={tableContentFinal}
+								customClass="bugscount"
+							/>
+            </div>
+          </Row>
+        </div>
+      );
+  }
+}
+
+export default Blockers;
diff --git a/src/Components/EventItems/index.js b/src/Components/EventItems/index.js
new file mode 100644
index 0000000..09a6d47
--- /dev/null
+++ b/src/Components/EventItems/index.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const EventItems = ({ start, summary, link, info }) => {
+  return (
+    <li key={start + summary}>
+      <b>{start}</b>
+      <br />
+      <a target="_blank" rel="noopener noreferrer" href={link}>
+        {summary}
+      </a>
+      <br />
+    </li>
+  );
+};
+export default EventItems;
diff --git a/src/Components/Events/index.js b/src/Components/Events/index.js
new file mode 100644
index 0000000..427e865
--- /dev/null
+++ b/src/Components/Events/index.js
@@ -0,0 +1,47 @@
+import React, { Component } from "react";
+import dateFormat from "dateformat";
+import Header from "../Header";
+import EventItems from "../EventItems";
+
+class Events extends Component {
+  constructor(props) {
+    super(props);
+    this.state = { meetings: [] };
+  }
+
+  render() {
+    const meetings = this.props.data.map(meeting => {
+      const old = new Date(meeting.start);
+      var meeting_start = dateFormat(
+        new Date(old.getTime() - old.getTimezoneOffset() * 60000),
+        "d mmm yyyy - HH:MM"
+      );
+      if (meeting.fullday) {
+        meeting_start = meeting_start.slice(0, -5) + "All day";
+      }
+      return (
+        <EventItems
+          key={meeting_start + meeting.summary}
+          start={meeting_start}
+          summary={meeting.summary}
+          link={meeting.link}
+          info={meeting.info}
+        />
+      );
+    });
+    return (
+      <div>
+        <Header
+          headerText="Meetings and testdays in the next 7 days"
+          headerLink="https://apps.fedoraproject.org/calendar/QA/"
+        />
+
+        <ul className="events">{meetings}</ul>
+      </div>
+    );
+  }
+}
+
+
+
+export default Events;
diff --git a/src/Components/Header/index.js b/src/Components/Header/index.js
new file mode 100644
index 0000000..b4d9a66
--- /dev/null
+++ b/src/Components/Header/index.js
@@ -0,0 +1,12 @@
+import React from "react";
+import SourceLink from "../SourceLinks";
+
+const Header = ({ headerText, headerLink }) => {
+  return (
+    <h1 className="padded">
+      {headerText}
+      {headerLink && <SourceLink href={headerLink} />}
+    </h1>
+  );
+};
+export default Header;
diff --git a/src/Components/Hideable/index.js b/src/Components/Hideable/index.js
new file mode 100644
index 0000000..aac075a
--- /dev/null
+++ b/src/Components/Hideable/index.js
@@ -0,0 +1,37 @@
+import React, { Component } from "react"
+import _ from "lodash"
+
+class Hideable extends Component {
+  constructor(props) {
+    super(props)
+    this.id = _.uniqueId("hideable-id-")
+  }
+
+  render() {
+    if (this.props.component_name === undefined) {
+      return <div key={this.id} />
+    }
+    return (
+      <div
+        key={this.id}
+        className={
+          this.props.config_mode
+            ? this.props.is_enabled
+              ? "border border-dark"
+              : "bgcl border border-dark"
+            : ""
+        }>
+        {this.props.children}
+        <a
+          href="#"
+          className={this.props.config_mode ? "d-block text-center badge badge-primary" : "d-none"}
+          onClick={(e) => this.props.toggle_handler(e, this.props.component_name)}
+          role="button">
+          {this.props.is_enabled ? "Disable" : "Enable"}
+        </a>
+      </div>
+    )
+  }
+}
+
+export default Hideable
diff --git a/src/Components/Line/index.js b/src/Components/Line/index.js
new file mode 100644
index 0000000..17f4d3e
--- /dev/null
+++ b/src/Components/Line/index.js
@@ -0,0 +1,17 @@
+import React, {Component} from 'react';
+
+const Line = ({ color, strokeWidth }) => {
+    const lineStyle={
+    stroke: color,
+    strokeWidth,
+
+};
+
+      return (
+        <svg width="150" height="20" version="1.1">
+          <line x1="0" y1="50%" x2="100%" y2="50%" style={lineStyle} />
+          <circle cx="50%" cy="50%" r="4" style={lineStyle} fill="#f8f9fa" />
+        </svg>
+      );
+};
+export default Line;  
\ No newline at end of file
diff --git a/src/Components/Minutes/index.js b/src/Components/Minutes/index.js
new file mode 100644
index 0000000..26f7f69
--- /dev/null
+++ b/src/Components/Minutes/index.js
@@ -0,0 +1,33 @@
+import React, { Component } from "react"
+import Header from "../Header";
+
+const Minutes = ( props ) => {
+  
+    return (
+      <div>
+          <Header
+            headerText="Fedora QA Meeting Minutes"
+            headerClass="padded"
+            />
+        
+        <div className="events">
+          <a target="_blank" href={props.data.link} rel="noopener noreferrer">
+            Latest minutes from {props.data.date}
+          </a>
+          <br />
+          Visit{" "}
+          <a
+            target="_blank"
+            href="https://meetbot.fedoraproject.org/sresults/?group_id=fedora-qa&type=team"
+            rel="noopener noreferrer">
+            meetbot
+          </a>{" "}
+          to see older.
+          <br />
+        </div>
+      </div>
+    )
+  
+}
+
+export default Minutes;
diff --git a/src/Components/SourceLinks/index.js b/src/Components/SourceLinks/index.js
new file mode 100644
index 0000000..76cfa0b
--- /dev/null
+++ b/src/Components/SourceLinks/index.js
@@ -0,0 +1,17 @@
+import React, {Component} from 'react'
+
+class SourceLink extends Component {
+    render() {
+        return (
+            <a
+                target="_blank"
+                rel="noopener noreferrer"
+                href={this.props.href}
+                className="smallsuper">
+                <i className="fas fa-external-link-alt"></i>
+            </a>
+        )
+    }
+}
+
+export default SourceLink
diff --git a/src/Components/Table/index.js b/src/Components/Table/index.js
new file mode 100644
index 0000000..4cec938
--- /dev/null
+++ b/src/Components/Table/index.js
@@ -0,0 +1,27 @@
+import React from "react";
+
+const Table = ({ className, tableHead, tableContent, customClass }) => {
+  return (
+    <table className={className}>
+      <thead>
+        <tr>
+          {tableHead.map((item, index) => (
+            <td colSpan="2" key={index}>
+              <b>{item}</b>
+            </td>
+          ))}
+        </tr>
+      </thead>
+      <tbody>
+        {tableContent.map((columns, i) => (
+          <tr key={i}>
+            {columns.map(column => (
+              <td className={customClass}>{column}</td>
+            ))}
+          </tr>
+        ))}
+      </tbody>
+    </table>
+  );
+};
+export default Table;
diff --git a/src/Components/Timeline/index.js b/src/Components/Timeline/index.js
new file mode 100644
index 0000000..98b19de
--- /dev/null
+++ b/src/Components/Timeline/index.js
@@ -0,0 +1,62 @@
+import React, { Component } from "react"
+import SourceLink from '../SourceLinks'
+import { get_title } from "./utils";
+import Line from "../Line";
+
+
+class Timeline extends Component {
+  constructor(props) {
+    super(props)
+    this.state = { schedule: [] }
+  }
+
+  render() {
+    const { data } = this.props;
+    const line = data.map((milestone) => {
+      return (
+        <td key={"line" + milestone.summary}>
+          <Line color={milestone.current ? "#2371ae" : "#dcdcdc"} strokeWidth='3' />
+        </td>
+      )
+    })
+
+    const dates = data.map((milestone) => {
+      return (
+        <td key={"dates" + milestone.summary} width="150">
+          <b>{milestone.date}</b>
+        </td>
+      )
+    })
+
+    const schedule = data.map((milestone) => {
+      return (
+        <td
+          key={"schedule" + milestone.summary}
+          title={get_title(milestone.summary)}
+          width="150">
+          {milestone.summary} <i className="fas fa-question-circle light"></i>
+        </td>
+      )
+    })
+    return (
+      <div>
+        <h1 className="padded">
+          Current development schedule{" "}
+          <SourceLink href="https://fedorapeople.org/groups/schedule/" />
+        </h1>
+        <div className="table-responsive">
+          <table className="timeline">
+            <tbody>
+              <tr>{line}</tr>
+              <tr>{dates}</tr>
+              <tr>{schedule}</tr>
+            </tbody>
+          </table>
+        </div>
+      </div>
+    )
+  }
+}
+
+
+export default Timeline
diff --git a/src/Components/Timeline/utils.js b/src/Components/Timeline/utils.js
new file mode 100644
index 0000000..e2b25bc
--- /dev/null
+++ b/src/Components/Timeline/utils.js
@@ -0,0 +1,11 @@
+export const get_title = (summary) => {
+    summary = summary.toLowerCase()
+    if (summary.includes("freeze"))
+      return "At the milestone freeze, pushes from the updates-testing to the stable repository are suspended until the release candidate is accepted."
+    if (summary === "rawhide")
+      return "Next Fedora release hasn't been branched yet from rolling release branch."
+    if (summary.includes("branch"))
+      return "Next version of Fedora that was 'branched' from the rolling Rawhide tree and in the future will become the next stable Fedora release."
+    if (summary.includes("release"))
+      return "Release candidate was accepted (violating no milestone criteria) and was released."
+  }
\ No newline at end of file
diff --git a/src/Containers/LandingPage/actions.js b/src/Containers/LandingPage/actions.js
new file mode 100644
index 0000000..00a0d1c
--- /dev/null
+++ b/src/Containers/LandingPage/actions.js
@@ -0,0 +1,14 @@
+import { loadData, loadDataResp } from "./reducer";
+
+export const fetchLandingPageData = (dispatch) => dispatch => {
+    dispatch(loadData());
+
+    fetch(window.env.ORACULUM_API_URL_v1 + "landing_page")
+    .then(blob => blob.json())
+    .then(data => {
+        dispatch(loadDataResp(data))
+    })
+    .catch((error) => {
+        console.error('Error:', error);
+    });
+}
\ No newline at end of file
diff --git a/src/Containers/LandingPage/index.js b/src/Containers/LandingPage/index.js
new file mode 100644
index 0000000..d10d133
--- /dev/null
+++ b/src/Containers/LandingPage/index.js
@@ -0,0 +1,141 @@
+import React, { Component } from "react"
+import { Container, Row } from "reactstrap"
+import { Link } from "react-router-dom"
+import Layout from "../../layout/Layout"
+import Timeline from "../../Components/Timeline"
+import Events from "../../Components/Events"
+import Blockers from "../../Components/Blockers"
+import Minutes from "../../Components/Minutes"
+import Hideable from "../../Components/Hideable"
+
+import _ from "lodash"
+
+import { connect } from "react-redux"
+import { fetchLandingPageData } from "./actions"
+
+import Cookies from "universal-cookie"
+
+class LandingPage extends Component {
+  constructor(props) {
+    super(props)
+    this.cookies = new Cookies()
+    this.available_components = ["events", "blockers", "minutes"]
+    let enabled_components = this.cookies.get("landingpage_enabled_components")
+    if (enabled_components === undefined) {
+      enabled_components = this.available_components.slice()
+      this.cookies.set("landingpage_enabled_components", enabled_components, { path: "/" })
+    }
+    this.state = {
+      blockerbugs: {},
+      devel: 0,
+      meetings: [],
+      schedule: [],
+      last_qa_meeting: {},
+      stable: 0,
+      config_mode: false,
+      enabled_components: enabled_components,
+    }
+  }
+
+  componentDidMount() {
+    this.props.dispatch(fetchLandingPageData())
+  }
+
+  toggle_config_mode(e) {
+    let config_mode = !this.state.config_mode
+    this.setState({ config_mode: config_mode })
+    e.preventDefault()
+  }
+
+  toggle_component_visibility(e, name) {
+    if (name === undefined) {
+      e.preventDefault()
+      return
+    }
+    let enabled_components = this.state.enabled_components
+    if (enabled_components.includes(name)) {
+      enabled_components.splice(enabled_components.indexOf(name), 1)
+    } else {
+      enabled_components.push(name)
+      enabled_components = this.available_components.filter((c) => enabled_components.includes(c))
+    }
+    this.cookies.set("landingpage_enabled_components", enabled_components, { path: "/" })
+    this.setState({ enabled_components: enabled_components })
+    e.preventDefault()
+  }
+
+  render() {
+    const available_components = {
+      events: <Events data={this.props.meetings} />,
+      blockers: <Blockers data={this.props.blockerbugs} release={this.props.devel} />,
+      minutes: <Minutes data={this.props.last_qa_meeting} />,
+    }
+    let components = _.chunk(
+      this.state.config_mode ? this.available_components : this.state.enabled_components,
+      2
+    )
+    components = components.map((row) => (
+      <Row>
+        {row.map((item) => (
+          <div className="col-md-6">
+            <Hideable
+              config_mode={this.state.config_mode}
+              toggle_handler={this.toggle_component_visibility.bind(this)}
+              component_name={item}
+              is_enabled={this.state.enabled_components.includes(item)}>
+              {available_components[item]}
+            </Hideable>
+          </div>
+        ))}
+      </Row>
+    ))
+    return (
+      <Layout loading={this.props.stable === 0}>
+        <div className="bluebox">
+          <Container>
+            <Row>
+              <div className="col-md-12">
+                <Timeline data={this.props.schedule} />
+              </div>
+            </Row>
+          </Container>
+        </div>
+        <Container>
+          {components}
+          <Row className="padded">
+            <div className="col-md-12 text-right">
+              <a
+                href="#"
+                onClick={(e) => this.toggle_config_mode(e)}
+                className="badge badge-secondary events"
+                role="button">
+                {this.state.config_mode
+                  ? "Save changes"
+                  : "Configure visibility of the info-cards"}
+              </a>
+            </div>
+          </Row>
+          <Row className="padded">
+            <div className="col-md-12 padded">
+              <Link
+                className="btn btn-primary btn-block btn-wrap-text btn-lg active"
+                to="/wizard"
+                role="button">
+                Do you have some spare time? Feeling like helping others? Wanna improve Fedora?
+                Click here!
+              </Link>
+            </div>
+          </Row>
+        </Container>
+      </Layout>
+    )
+  }
+}
+
+const mapStateToProps = (state) => {
+  return {
+    ...state.landing_page,
+  }
+}
+
+export default connect(mapStateToProps)(LandingPage)
diff --git a/src/Containers/LandingPage/reducer.js b/src/Containers/LandingPage/reducer.js
new file mode 100644
index 0000000..d1e2cbb
--- /dev/null
+++ b/src/Containers/LandingPage/reducer.js
@@ -0,0 +1,28 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+const landingPageReducer = createSlice({
+  name: "landing_page",
+  initialState: {
+    blockerbugs: {},
+    devel: 0,
+    meetings: [],
+    schedule: [],
+    last_qa_meeting: {},
+    stable: 0,
+    config_mode: false,
+    enabled_components: ["events", "blockers", "minutes"],
+
+    loading: false
+  },
+  reducers: {
+    loadData(state, action) {
+      if (!state.loading) state.loading = true;
+    },
+    loadDataResp(state, action) {
+      state.loading = false;
+      Object.assign(state, { ...action.payload });
+    }
+  }
+});
+export const { loadData, loadDataResp } = landingPageReducer.actions;
+export default landingPageReducer.reducer;
diff --git a/src/actions/reduxActions.js b/src/actions/reduxActions.js
index 306bca1..084894f 100644
--- a/src/actions/reduxActions.js
+++ b/src/actions/reduxActions.js
@@ -1,19 +1,5 @@
-import { loadData, loadDataResp } from '../reducers/landingPageSlice';
 import { loadWizardDataResp, loadWizardData } from '../reducers/wizardSlice';
 
-export const fetchLandingPageData = (dispatch) => dispatch => {
-    dispatch(loadData());
-
-    fetch(window.env.ORACULUM_API_URL_v1 + "landing_page")
-    .then(blob => blob.json())
-    .then(data => {
-        dispatch(loadDataResp(data))
-    })
-    .catch((error) => {
-        console.error('Error:', error);
-    });
-}
-
 export const fetchWizardData = payload => dispatch => {
     dispatch(loadWizardData())
     fetch(window.env.ORACULUM_API_URL_v1 + "actions/all")
diff --git a/src/api/api.users.js b/src/api/api.users.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/api/api.users.js
diff --git a/src/configureStore.js b/src/configureStore.js
index 70c6cd6..29d33ad 100644
--- a/src/configureStore.js
+++ b/src/configureStore.js
@@ -1,20 +1,38 @@
-import { configureStore, combineReducers } from '@reduxjs/toolkit';
-import logger from 'redux-logger';
-import thunkMiddleware from 'redux-thunk';
-import landingPageReducer from './reducers/landingPageSlice';
-import wizardReducer from './reducers/wizardSlice';
+import { configureStore, combineReducers } from "@reduxjs/toolkit";
+import logger from "redux-logger";
+import thunkMiddleware from "redux-thunk";
+import landingPageReducer from "./Containers/LandingPage/reducer";
+import wizardReducer from "./reducers/wizardSlice";
+
+export const defaultState = {
+  landing_page: {
+    blockerbugs: {},
+    devel: 0,
+    meetings: [],
+    schedule: [],
+    last_qa_meeting: {},
+    stable: 0,
+    config_mode: false,
+    enabled_components: ["events", "blockers", "minutes"]
+  },
+  wizard: {
+    actions: [],
+    providers: [],
+    all_actions: []
+  }
+};
 
 const reducer = combineReducers({
-    landing_page: landingPageReducer,
-    wizard: wizardReducer
-})
+  landing_page: landingPageReducer,
+  wizard: wizardReducer
+});
 
 export default function configureAppStore(initialState) {
-    const store = configureStore({
-        reducer,
-        middleware: [ logger,thunkMiddleware],
-        devTools: process.env.NODE_ENV !== 'production',
-        initialState,
-    })
-    return store;
-}
\ No newline at end of file
+  const store = configureStore({
+    reducer,
+    middleware: [logger, thunkMiddleware],
+    devTools: process.env.NODE_ENV !== "production",
+    initialState
+  });
+  return store;
+}
diff --git a/src/index.css b/src/index.css
index 27f6835..7bdb2de 100644
--- a/src/index.css
+++ b/src/index.css
@@ -82,7 +82,7 @@ h1 {
 }
 
 .bugscount {
-  padding-left: 2em;
+  padding-right: 2em;
 }
 
 .smallsuper {
diff --git a/src/index.js b/src/index.js
index 6a8df27..7bf6062 100644
--- a/src/index.js
+++ b/src/index.js
@@ -11,7 +11,7 @@ import * as serviceWorker from './serviceWorker';
 
 import { Provider } from 'react-redux';
 import configureAppStore from './configureStore';
-import { defaultState } from './reducers';
+import { defaultState } from './configureStore';
 
 const store= configureAppStore(defaultState);
 
diff --git a/src/landingpage/Blockers.js b/src/landingpage/Blockers.js
deleted file mode 100644
index 30b923a..0000000
--- a/src/landingpage/Blockers.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import React, { Component } from "react"
-import { Row } from "reactstrap"
-import SourceLink from "./SourceLink"
-
-class Blockers extends Component {
-  constructor(props) {
-    super(props)
-    this.state = { blockerbugs: {}, release: 0 }
-  }
-
-  render() {
-    if (this.props.data)
-      return (
-        <div>
-          <h1 className="padded">
-            Fedora {this.props.release} blockers and FEs{" "}
-            <SourceLink href="https://qa.fedoraproject.org/blockerbugs/" />
-          </h1>
-          <Row>
-            <div className="col-md-6">
-              <table className="events">
-                <thead>
-                  <tr>
-                    <td colSpan="2">
-                      <b>Beta</b>
-                    </td>
-                  </tr>
-                </thead>
-                <tbody>
-                  <tr>
-                    <td>Proposed Blockers</td>
-                    <td className="bugscount">{this.props.data.beta_blockers_proposed}</td>
-                  </tr>
-                  <tr>
-                    <td>Accepted Blockers</td>
-                    <td className="bugscount">{this.props.data.beta_blockers}</td>
-                  </tr>
-                  <tr>
-                    <td>Proposed FEs</td>
-                    <td className="bugscount">{this.props.data.beta_fe_proposed}</td>
-                  </tr>
-                  <tr>
-                    <td>Accepted FEs</td>
-                    <td className="bugscount">{this.props.data.beta_fe}</td>
-                  </tr>
-                </tbody>
-              </table>
-            </div>
-
-            <div className="col-md-6">
-              <table className="events">
-                <thead>
-                  <tr>
-                    <td colSpan="2">
-                      <b>Final</b>
-                    </td>
-                  </tr>
-                </thead>
-                <tbody>
-                  <tr>
-                    <td>Proposed Blockers</td>
-                    <td className="bugscount">{this.props.data.final_blockers_proposed}</td>
-                  </tr>
-                  <tr>
-                    <td>Accepted Blockers</td>
-                    <td className="bugscount">{this.props.data.final_blockers}</td>
-                  </tr>
-                  <tr>
-                    <td>Proposed FEs</td>
-                    <td className="bugscount">{this.props.data.final_fe_proposed}</td>
-                  </tr>
-                  <tr>
-                    <td>Accepted FEs</td>
-                    <td className="bugscount">{this.props.data.final_fe}</td>
-                  </tr>
-                </tbody>
-              </table>
-            </div>
-          </Row>
-        </div>
-      )
-  }
-}
-
-export default Blockers
diff --git a/src/landingpage/Events.js b/src/landingpage/Events.js
deleted file mode 100644
index 54eb80b..0000000
--- a/src/landingpage/Events.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React, { Component } from "react"
-import dateFormat from "dateformat"
-import SourceLink from './SourceLink'
-
-class Events extends Component {
-  constructor(props) {
-    super(props)
-    this.state = { meetings: [] }
-  }
-
-  render() {
-    const meetings = this.props.data.map((meeting) => {
-      const old = new Date(meeting.start)
-      var meeting_start = dateFormat(
-        new Date(old.getTime() - old.getTimezoneOffset() * 60000),
-        "d mmm yyyy - HH:MM"
-      )
-      if (meeting.fullday) {
-        meeting_start = meeting_start.slice(0, -5) + "All day"
-      }
-      return (
-        <Event
-          key={meeting_start + meeting.summary}
-          start={meeting_start}
-          summary={meeting.summary}
-          link={meeting.link}
-          info={meeting.info}
-        />
-      )
-    })
-    return (
-      <div>
-        <h1 className="padded">
-          Meetings and testdays in the next 7 days{" "}
-          <SourceLink href="https://apps.fedoraproject.org/calendar/QA/" />
-        </h1>
-        <ul className="events">{meetings}</ul>
-      </div>
-    )
-  }
-}
-
-class Event extends Component {
-  render() {
-    return (
-      <li key={this.props.start + this.props.summary}>
-        <b>{this.props.start}</b>
-        <br />
-        <a target="_blank" rel="noopener noreferrer" href={this.props.link}>
-          {this.props.summary}
-        </a>
-        <br />
-      </li>
-    )
-  }
-}
-
-export default Events
diff --git a/src/landingpage/Hideable.js b/src/landingpage/Hideable.js
deleted file mode 100644
index aac075a..0000000
--- a/src/landingpage/Hideable.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React, { Component } from "react"
-import _ from "lodash"
-
-class Hideable extends Component {
-  constructor(props) {
-    super(props)
-    this.id = _.uniqueId("hideable-id-")
-  }
-
-  render() {
-    if (this.props.component_name === undefined) {
-      return <div key={this.id} />
-    }
-    return (
-      <div
-        key={this.id}
-        className={
-          this.props.config_mode
-            ? this.props.is_enabled
-              ? "border border-dark"
-              : "bgcl border border-dark"
-            : ""
-        }>
-        {this.props.children}
-        <a
-          href="#"
-          className={this.props.config_mode ? "d-block text-center badge badge-primary" : "d-none"}
-          onClick={(e) => this.props.toggle_handler(e, this.props.component_name)}
-          role="button">
-          {this.props.is_enabled ? "Disable" : "Enable"}
-        </a>
-      </div>
-    )
-  }
-}
-
-export default Hideable
diff --git a/src/landingpage/LandingPage.js b/src/landingpage/LandingPage.js
deleted file mode 100644
index aec079a..0000000
--- a/src/landingpage/LandingPage.js
+++ /dev/null
@@ -1,141 +0,0 @@
-import React, { Component } from "react"
-import { Container, Row } from "reactstrap"
-import { Link } from "react-router-dom"
-import Layout from "../layout/Layout"
-import Timeline from "./Timeline"
-import Events from "./Events"
-import Blockers from "./Blockers"
-import Minutes from "./Minutes"
-import Hideable from "./Hideable"
-
-import _ from "lodash"
-
-import { connect } from "react-redux"
-import { fetchLandingPageData } from "../actions/reduxActions"
-
-import Cookies from "universal-cookie"
-
-class LandingPage extends Component {
-  constructor(props) {
-    super(props)
-    this.cookies = new Cookies()
-    this.available_components = ["events", "blockers", "minutes"]
-    let enabled_components = this.cookies.get("landingpage_enabled_components")
-    if (enabled_components === undefined) {
-      enabled_components = this.available_components.slice()
-      this.cookies.set("landingpage_enabled_components", enabled_components, { path: "/" })
-    }
-    this.state = {
-      blockerbugs: {},
-      devel: 0,
-      meetings: [],
-      schedule: [],
-      last_qa_meeting: {},
-      stable: 0,
-      config_mode: false,
-      enabled_components: enabled_components,
-    }
-  }
-
-  componentDidMount() {
-    this.props.dispatch(fetchLandingPageData())
-  }
-
-  toggle_config_mode(e) {
-    let config_mode = !this.state.config_mode
-    this.setState({ config_mode: config_mode })
-    e.preventDefault()
-  }
-
-  toggle_component_visibility(e, name) {
-    if (name === undefined) {
-      e.preventDefault()
-      return
-    }
-    let enabled_components = this.state.enabled_components
-    if (enabled_components.includes(name)) {
-      enabled_components.splice(enabled_components.indexOf(name), 1)
-    } else {
-      enabled_components.push(name)
-      enabled_components = this.available_components.filter((c) => enabled_components.includes(c))
-    }
-    this.cookies.set("landingpage_enabled_components", enabled_components, { path: "/" })
-    this.setState({ enabled_components: enabled_components })
-    e.preventDefault()
-  }
-
-  render() {
-    const available_components = {
-      events: <Events data={this.props.meetings} />,
-      blockers: <Blockers data={this.props.blockerbugs} release={this.props.devel} />,
-      minutes: <Minutes data={this.props.last_qa_meeting} />,
-    }
-    let components = _.chunk(
-      this.state.config_mode ? this.available_components : this.state.enabled_components,
-      2
-    )
-    components = components.map((row) => (
-      <Row>
-        {row.map((item) => (
-          <div className="col-md-6">
-            <Hideable
-              config_mode={this.state.config_mode}
-              toggle_handler={this.toggle_component_visibility.bind(this)}
-              component_name={item}
-              is_enabled={this.state.enabled_components.includes(item)}>
-              {available_components[item]}
-            </Hideable>
-          </div>
-        ))}
-      </Row>
-    ))
-    return (
-      <Layout loading={this.props.stable === 0}>
-        <div className="bluebox">
-          <Container>
-            <Row>
-              <div className="col-md-12">
-                <Timeline data={this.props.schedule} />
-              </div>
-            </Row>
-          </Container>
-        </div>
-        <Container>
-          {components}
-          <Row className="padded">
-            <div className="col-md-12 text-right">
-              <a
-                href="#"
-                onClick={(e) => this.toggle_config_mode(e)}
-                className="badge badge-secondary events"
-                role="button">
-                {this.state.config_mode
-                  ? "Save changes"
-                  : "Configure visibility of the info-cards"}
-              </a>
-            </div>
-          </Row>
-          <Row className="padded">
-            <div className="col-md-12 padded">
-              <Link
-                className="btn btn-primary btn-block btn-wrap-text btn-lg active"
-                to="/wizard"
-                role="button">
-                Do you have some spare time? Feeling like helping others? Wanna improve Fedora?
-                Click here!
-              </Link>
-            </div>
-          </Row>
-        </Container>
-      </Layout>
-    )
-  }
-}
-
-const mapStateToProps = (state) => {
-  return {
-    ...state.landing_page,
-  }
-}
-
-export default connect(mapStateToProps)(LandingPage)
diff --git a/src/landingpage/Minutes.js b/src/landingpage/Minutes.js
deleted file mode 100644
index 4f88f2b..0000000
--- a/src/landingpage/Minutes.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React, { Component } from "react"
-
-class Events extends Component {
-  render() {
-    return (
-      <div>
-        <h1 className="padded">Fedora QA Meeting Minutes</h1>
-        <div className="events">
-          <a target="_blank" href={this.props.data.link} rel="noopener noreferrer">
-            Latest minutes from {this.props.data.date}
-          </a>
-          <br />
-          Visit{" "}
-          <a
-            target="_blank"
-            href="https://meetbot.fedoraproject.org/sresults/?group_id=fedora-qa&type=team"
-            rel="noopener noreferrer">
-            meetbot
-          </a>{" "}
-          to see older.
-          <br />
-        </div>
-      </div>
-    )
-  }
-}
-
-export default Events
diff --git a/src/landingpage/SourceLink.js b/src/landingpage/SourceLink.js
deleted file mode 100644
index 76cfa0b..0000000
--- a/src/landingpage/SourceLink.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React, {Component} from 'react'
-
-class SourceLink extends Component {
-    render() {
-        return (
-            <a
-                target="_blank"
-                rel="noopener noreferrer"
-                href={this.props.href}
-                className="smallsuper">
-                <i className="fas fa-external-link-alt"></i>
-            </a>
-        )
-    }
-}
-
-export default SourceLink
diff --git a/src/landingpage/Timeline.js b/src/landingpage/Timeline.js
deleted file mode 100644
index 1de10c5..0000000
--- a/src/landingpage/Timeline.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import React, { Component } from "react"
-import SourceLink from './SourceLink'
-
-class Timeline extends Component {
-  constructor(props) {
-    super(props)
-    this.state = { schedule: [] }
-  }
-
-  get_title(summary) {
-    summary = summary.toLowerCase()
-    if (summary.includes("freeze"))
-      return "At the milestone freeze, pushes from the updates-testing to the stable repository are suspended until the release candidate is accepted."
-    if (summary === "rawhide")
-      return "Next Fedora release hasn't been branched yet from rolling release branch."
-    if (summary.includes("branch"))
-      return "Next version of Fedora that was 'branched' from the rolling Rawhide tree and in the future will become the next stable Fedora release."
-    if (summary.includes("release"))
-      return "Release candidate was accepted (violating no milestone criteria) and was released."
-  }
-
-  render() {
-    const line = this.props.data.map((milestone) => {
-      return (
-        <td key={"line" + milestone.summary}>
-          <Line color={milestone.current ? "#2371ae" : "#dcdcdc"} />
-        </td>
-      )
-    })
-
-    const dates = this.props.data.map((milestone) => {
-      return (
-        <td key={"dates" + milestone.summary} width="150">
-          <b>{milestone.date}</b>
-        </td>
-      )
-    })
-
-    const schedule = this.props.data.map((milestone) => {
-      return (
-        <td
-          key={"schedule" + milestone.summary}
-          title={this.get_title(milestone.summary)}
-          width="150">
-          {milestone.summary} <i className="fas fa-question-circle light"></i>
-        </td>
-      )
-    })
-    return (
-      <div>
-        <h1 className="padded">
-          Current development schedule{" "}
-          <SourceLink href="https://fedorapeople.org/groups/schedule/" />
-        </h1>
-        <div className="table-responsive">
-          <table className="timeline">
-            <tbody>
-              <tr>{line}</tr>
-              <tr>{dates}</tr>
-              <tr>{schedule}</tr>
-            </tbody>
-          </table>
-        </div>
-      </div>
-    )
-  }
-}
-
-class Line extends Component {
-  render() {
-    const lineStyle = {
-      stroke: this.props.color,
-      strokeWidth: "3",
-    }
-    return (
-      <svg width="150" height="20" version="1.1">
-        <line x1="0" y1="50%" x2="100%" y2="50%" style={lineStyle} />
-        <circle cx="50%" cy="50%" r="4" style={lineStyle} fill="#f8f9fa" />
-      </svg>
-    )
-  }
-}
-
-export default Timeline
diff --git a/src/reducers/index.js b/src/reducers/index.js
deleted file mode 100644
index 4dfe6f1..0000000
--- a/src/reducers/index.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import ActionTypes from "../constants"
-
-export const defaultState = {
-  landing_page: {
-    blockerbugs: {},
-    devel: 0,
-    meetings: [],
-    schedule: [],
-    last_qa_meeting: {},
-    stable: 0,
-    config_mode: false,
-    enabled_components: ["events", "blockers", "minutes"],
-  },
-  wizard: {
-    actions: [],
-    providers: [],
-    all_actions: [],
-  },
-}
-
-export default (state = defaultState, action) => {
-  switch (action.type) {
-    case ActionTypes.LOAD_DATA_RESP:
-      return {
-        ...state,
-        landing_page: action.payload,
-      }
-
-    case ActionTypes.LOAD_WIZARD_DATA_RESP:
-      return {
-        ...state,
-        wizard: {
-          ...state.wizard,
-          providers: action.payload.providers,
-          all_actions: action.payload.actions,
-        },
-      }
-
-    default:
-      return {
-        ...state,
-      }
-  }
-}
diff --git a/src/reducers/landingPageSlice.js b/src/reducers/landingPageSlice.js
deleted file mode 100644
index d1e2cbb..0000000
--- a/src/reducers/landingPageSlice.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { createSlice } from "@reduxjs/toolkit";
-
-const landingPageReducer = createSlice({
-  name: "landing_page",
-  initialState: {
-    blockerbugs: {},
-    devel: 0,
-    meetings: [],
-    schedule: [],
-    last_qa_meeting: {},
-    stable: 0,
-    config_mode: false,
-    enabled_components: ["events", "blockers", "minutes"],
-
-    loading: false
-  },
-  reducers: {
-    loadData(state, action) {
-      if (!state.loading) state.loading = true;
-    },
-    loadDataResp(state, action) {
-      state.loading = false;
-      Object.assign(state, { ...action.payload });
-    }
-  }
-});
-export const { loadData, loadDataResp } = landingPageReducer.actions;
-export default landingPageReducer.reducer;

From ed8426bec4a732bb2329a60d98c84a5f0e52ff29 Mon Sep 17 00:00:00 2001
From: Divyanshi Singh <divyanshipilot@gmail.com>
Date: Apr 04 2021 17:14:19 +0000
Subject: [PATCH 4/7] common api function, http error handling


---

diff --git a/src/Containers/LandingPage/actions.js b/src/Containers/LandingPage/actions.js
index 00a0d1c..1f4a0aa 100644
--- a/src/Containers/LandingPage/actions.js
+++ b/src/Containers/LandingPage/actions.js
@@ -1,14 +1,14 @@
 import { loadData, loadDataResp } from "./reducer";
+import { fetchAPI } from "../../api/api.common";
 
-export const fetchLandingPageData = (dispatch) => dispatch => {
+export const fetchLandingPageData = () =>  async dispatch => {
     dispatch(loadData());
-
-    fetch(window.env.ORACULUM_API_URL_v1 + "landing_page")
-    .then(blob => blob.json())
-    .then(data => {
+    try{
+        const url = window.env.ORACULUM_API_URL_v1 + "landing_page";
+        const data = await fetchAPI(url);
         dispatch(loadDataResp(data))
-    })
-    .catch((error) => {
-        console.error('Error:', error);
-    });
+    } catch(err) {
+        console.error(err);
+    }
+    
 }
\ No newline at end of file
diff --git a/src/Errors/HttpApiCallError.js b/src/Errors/HttpApiCallError.js
new file mode 100644
index 0000000..14087fe
--- /dev/null
+++ b/src/Errors/HttpApiCallError.js
@@ -0,0 +1,9 @@
+export default class HttpApiCallError extends Error {
+    constructor(message, statusCode) {
+    super(message);
+    this.message = message;
+    this.statusCode = statusCode;
+    this.stack = new Error(message).stack;
+    this.name = 'HttpApiCallError';
+    }
+}
\ No newline at end of file
diff --git a/src/api/api.common.js b/src/api/api.common.js
new file mode 100644
index 0000000..d40dfa6
--- /dev/null
+++ b/src/api/api.common.js
@@ -0,0 +1,13 @@
+import HttpApiCallError from "../Errors/HttpApiCallError";
+
+export const fetchAPI = async url => {
+    const response = await fetch(url);
+    const responseBody = await response.json();
+    const isSuccess = response.status === 200;
+    if ( isSuccess ) {
+        return responseBody;
+    } 
+    const error = HttpApiCallError(response.statusText, response.status);
+    error.response = response;
+    throw error;
+}
\ No newline at end of file
diff --git a/src/api/api.users.js b/src/api/api.users.js
deleted file mode 100644
index e69de29..0000000
--- a/src/api/api.users.js
+++ /dev/null

From 082ea05fbaf3752d015992a18278af10bb4d0f56 Mon Sep 17 00:00:00 2001
From: Divyanshi Singh <divyanshipilot@gmail.com>
Date: Apr 04 2021 17:35:43 +0000
Subject: [PATCH 5/7] wizard component


---

diff --git a/src/App.js b/src/App.js
index 3f55033..6f9cdb9 100644
--- a/src/App.js
+++ b/src/App.js
@@ -3,7 +3,7 @@ import React, { Component } from 'react';
 import { Route, Switch } from 'react-router';
 import { BrowserRouter } from 'react-router-dom'
 
-import Wizard from './wizard/Wizard';
+import Wizard from './Containers/Wizard';
 import LandingPage from './Containers/LandingPage';
 import NotFound from './NotFound';
 
diff --git a/src/Containers/Wizard/actions.js b/src/Containers/Wizard/actions.js
new file mode 100644
index 0000000..b092d00
--- /dev/null
+++ b/src/Containers/Wizard/actions.js
@@ -0,0 +1,14 @@
+import { loadWizardDataResp, loadWizardData } from './reducer';
+import { fetchAPI } from '../../api/api.common';
+
+export const fetchWizardData = () => async dispatch => {
+    dispatch(loadWizardData())
+    try{
+        const url = window.env.ORACULUM_API_URL_v1 + "actions/all";
+        const data = await fetchAPI(url);
+        dispatch(loadWizardDataResp(data))
+    } catch(err) {
+        console.error(err);
+    }
+}
+
diff --git a/src/Containers/Wizard/index.js b/src/Containers/Wizard/index.js
new file mode 100644
index 0000000..4918d34
--- /dev/null
+++ b/src/Containers/Wizard/index.js
@@ -0,0 +1,71 @@
+import React, { Component } from "react"
+import WizardForm from "../../wizard/WizardForm"
+import Layout from "../../layout/Layout"
+import { oraculumApiUrl_v1 } from "../../config"
+import Actions from "../../wizard/Actions"
+import { Container, Row } from "reactstrap"
+
+import { connect } from "react-redux"
+import { fetchWizardData } from "./actions"
+
+class Wizard extends Component {
+  constructor(props) {
+    super(props)
+    this.state = {
+      actions: [],
+    }
+  }
+
+  componentDidMount() {
+    fetch(oraculumApiUrl_v1 + "actions/all")
+      .then((resp) => resp.json())
+      .then((data) => {
+        this.setState({
+          providers: data.providers,
+          all_actions: data.actions,
+        })
+      })
+
+    this.props.dispatch(fetchWizardData())
+  }
+
+  show_actions(actions) {
+    this.setState({ actions })
+  }
+
+  render() {
+    return (
+      <Layout>
+        <div className="bluebox">
+          <Container>
+            <WizardForm
+              show_actions={this.show_actions.bind(this)}
+              actions={this.props.all_actions}
+              providers={this.props.providers}
+            />
+            <h1>Nothing sparked joy?</h1>
+            <div>
+              None of the above looks interesting to you? We'd be happy if you looked around at{" "}
+              <a href="https://whatcanidoforfedora.org/">https://whatcanidoforfedora.org/</a>!
+            </div>
+          </Container>
+        </div>
+        <Container>
+          <Row>
+            <div className="col-md-12">
+              <Actions data={this.state.actions} />
+            </div>
+          </Row>
+        </Container>
+      </Layout>
+    )
+  }
+}
+
+const mapStateToProps = (state) => {
+  return {
+    ...state.wizard,
+  }
+}
+
+export default connect(mapStateToProps)(Wizard)
diff --git a/src/Containers/Wizard/reducer.js b/src/Containers/Wizard/reducer.js
new file mode 100644
index 0000000..f48032b
--- /dev/null
+++ b/src/Containers/Wizard/reducer.js
@@ -0,0 +1,24 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+const wizardReducer = createSlice({
+  name: "wizard",
+  initialState: {
+    actions: [],
+    providers: [],
+    all_actions: [],
+
+    loading: false
+  },
+  reducers: {
+    loadWizardData(state, action) {
+      if (!state.loading) state.loading = true;
+    },
+    loadWizardDataResp(state, action) {
+      state.loading = false;
+      state.providers = action.payload.providers;
+      state.all_actions = action.payload.actions;
+    }
+  }
+});
+export const { loadWizardData, loadWizardDataResp } = wizardReducer.actions;
+export default wizardReducer.reducer;
diff --git a/src/actions/reduxActions.js b/src/actions/reduxActions.js
deleted file mode 100644
index 084894f..0000000
--- a/src/actions/reduxActions.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { loadWizardDataResp, loadWizardData } from '../reducers/wizardSlice';
-
-export const fetchWizardData = payload => dispatch => {
-    dispatch(loadWizardData())
-    fetch(window.env.ORACULUM_API_URL_v1 + "actions/all")
-    .then(blob => blob.json())
-    .then(data => {
-        dispatch(loadWizardDataResp(data))
-    })
-    .catch((error) => {
-        console.error('Error:', error);
-    });
-}
diff --git a/src/configureStore.js b/src/configureStore.js
index 29d33ad..febe607 100644
--- a/src/configureStore.js
+++ b/src/configureStore.js
@@ -2,7 +2,7 @@ import { configureStore, combineReducers } from "@reduxjs/toolkit";
 import logger from "redux-logger";
 import thunkMiddleware from "redux-thunk";
 import landingPageReducer from "./Containers/LandingPage/reducer";
-import wizardReducer from "./reducers/wizardSlice";
+import wizardReducer from "./Containers/Wizard/reducer";
 
 export const defaultState = {
   landing_page: {
diff --git a/src/reducers/wizardSlice.js b/src/reducers/wizardSlice.js
deleted file mode 100644
index f48032b..0000000
--- a/src/reducers/wizardSlice.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { createSlice } from "@reduxjs/toolkit";
-
-const wizardReducer = createSlice({
-  name: "wizard",
-  initialState: {
-    actions: [],
-    providers: [],
-    all_actions: [],
-
-    loading: false
-  },
-  reducers: {
-    loadWizardData(state, action) {
-      if (!state.loading) state.loading = true;
-    },
-    loadWizardDataResp(state, action) {
-      state.loading = false;
-      state.providers = action.payload.providers;
-      state.all_actions = action.payload.actions;
-    }
-  }
-});
-export const { loadWizardData, loadWizardDataResp } = wizardReducer.actions;
-export default wizardReducer.reducer;
diff --git a/src/wizard/Wizard.js b/src/wizard/Wizard.js
deleted file mode 100644
index 1b136bd..0000000
--- a/src/wizard/Wizard.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import React, { Component } from "react"
-import WizardForm from "./WizardForm"
-import Layout from "../layout/Layout"
-import { oraculumApiUrl_v1 } from "../config"
-import Actions from "./Actions"
-import { Container, Row } from "reactstrap"
-
-import { connect } from "react-redux"
-import { fetchWizardData } from "../actions/reduxActions"
-
-class Wizard extends Component {
-  constructor(props) {
-    super(props)
-    this.state = {
-      actions: [],
-    }
-  }
-
-  componentDidMount() {
-    fetch(oraculumApiUrl_v1 + "actions/all")
-      .then((resp) => resp.json())
-      .then((data) => {
-        this.setState({
-          providers: data.providers,
-          all_actions: data.actions,
-        })
-      })
-
-    this.props.dispatch(fetchWizardData())
-  }
-
-  show_actions(actions) {
-    this.setState({ actions })
-  }
-
-  render() {
-    return (
-      <Layout>
-        <div className="bluebox">
-          <Container>
-            <WizardForm
-              show_actions={this.show_actions.bind(this)}
-              actions={this.props.all_actions}
-              providers={this.props.providers}
-            />
-            <h1>Nothing sparked joy?</h1>
-            <div>
-              None of the above looks interesting to you? We'd be happy if you looked around at{" "}
-              <a href="https://whatcanidoforfedora.org/">https://whatcanidoforfedora.org/</a>!
-            </div>
-          </Container>
-        </div>
-        <Container>
-          <Row>
-            <div className="col-md-12">
-              <Actions data={this.state.actions} />
-            </div>
-          </Row>
-        </Container>
-      </Layout>
-    )
-  }
-}
-
-const mapStateToProps = (state) => {
-  return {
-    ...state.wizard,
-  }
-}
-
-export default connect(mapStateToProps)(Wizard)

From 8388eaf94d23cd21ce9f3f6eeda3c49c2dbfbab9 Mon Sep 17 00:00:00 2001
From: Divyanshi Singh <divyanshipilot@gmail.com>
Date: Apr 07 2021 11:12:40 +0000
Subject: [PATCH 6/7] redux toolkit implemented


---

diff --git a/package.json b/package.json
index 20d0779..fab2975 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
   "private": true,
   "homepage": ".",
   "dependencies": {
+    "@reduxjs/toolkit": "^1.5.1",
     "bootstrap": "^4.4.1",
     "dateformat": "^3.0.3",
     "react": "^16.5.2",
diff --git a/src/actions/reduxActions.js b/src/actions/reduxActions.js
index 80a3461..306bca1 100644
--- a/src/actions/reduxActions.js
+++ b/src/actions/reduxActions.js
@@ -1,15 +1,8 @@
-import ActionTypes from '../constants';
+import { loadData, loadDataResp } from '../reducers/landingPageSlice';
+import { loadWizardDataResp, loadWizardData } from '../reducers/wizardSlice';
 
-export const loadDataResp = payload => ({
-    type: ActionTypes.LOAD_DATA_RESP,
-    payload: payload
-})
-
-export const loadData = payload => dispatch => {
-    dispatch({
-        type: ActionTypes.LOAD_DATA,
-        payload: payload
-    });
+export const fetchLandingPageData = (dispatch) => dispatch => {
+    dispatch(loadData());
 
     fetch(window.env.ORACULUM_API_URL_v1 + "landing_page")
     .then(blob => blob.json())
@@ -21,17 +14,8 @@ export const loadData = payload => dispatch => {
     });
 }
 
-export const loadWizardDataResp = payload => ({
-    type: ActionTypes.LOAD_WIZARD_DATA_RESP,
-    payload: payload
-})
-
-export const loadWizardData = payload => dispatch => {
-    dispatch({
-        type: ActionTypes.LOAD_WIZARD_DATA,
-        payload: payload
-    });
-
+export const fetchWizardData = payload => dispatch => {
+    dispatch(loadWizardData())
     fetch(window.env.ORACULUM_API_URL_v1 + "actions/all")
     .then(blob => blob.json())
     .then(data => {
diff --git a/src/configureStore.js b/src/configureStore.js
new file mode 100644
index 0000000..4ac50f4
--- /dev/null
+++ b/src/configureStore.js
@@ -0,0 +1,19 @@
+import { configureStore, combineReducers } from '@reduxjs/toolkit';
+import logger from 'redux-logger';
+import thunkMiddleware from 'redux-thunk';
+import landingPageReducer from './reducers/landingPageSlice';
+import wizardReducer from './reducers/wizardSlice';
+
+const reducer = combineReducers({
+    landing_page: landingPageReducer,
+    wizard: wizardReducer
+})
+
+export default function configureAppStore() {
+    const store = configureStore({
+        reducer,
+        middleware: [ thunkMiddleware, logger ],
+        devTools: process.env.NODE_ENV !== 'production',
+    })
+    return store;
+}
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 35f417c..5c27953 100644
--- a/src/index.js
+++ b/src/index.js
@@ -9,17 +9,10 @@ import 'typeface-open-sans'
 import App from './App';
 import * as serviceWorker from './serviceWorker';
 
-import { createStore, applyMiddleware } from 'redux'
-import thunkMiddleware from 'redux-thunk'
-import { createLogger } from 'redux-logger'
-import { Provider } from 'react-redux'
-import reducer from './reducers'
+import { Provider } from 'react-redux';
+import configureAppStore from './configureStore';
 
-const loggerMiddleware = createLogger();
-const store = createStore(reducer, applyMiddleware(
-  thunkMiddleware,
-  loggerMiddleware
-));
+const store= configureAppStore();
 
 ReactDOM.render(
     <React.StrictMode>
diff --git a/src/landingpage/LandingPage.js b/src/landingpage/LandingPage.js
index b1bee82..aec079a 100644
--- a/src/landingpage/LandingPage.js
+++ b/src/landingpage/LandingPage.js
@@ -11,7 +11,7 @@ import Hideable from "./Hideable"
 import _ from "lodash"
 
 import { connect } from "react-redux"
-import { loadData } from "../actions/reduxActions"
+import { fetchLandingPageData } from "../actions/reduxActions"
 
 import Cookies from "universal-cookie"
 
@@ -38,7 +38,7 @@ class LandingPage extends Component {
   }
 
   componentDidMount() {
-    this.props.dispatch(loadData())
+    this.props.dispatch(fetchLandingPageData())
   }
 
   toggle_config_mode(e) {
diff --git a/src/reducers/index.js b/src/reducers/index.js
deleted file mode 100644
index 5e628e0..0000000
--- a/src/reducers/index.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import ActionTypes from "../constants"
-
-const defaultState = {
-  landing_page: {
-    blockerbugs: {},
-    devel: 0,
-    meetings: [],
-    schedule: [],
-    last_qa_meeting: {},
-    stable: 0,
-    config_mode: false,
-    enabled_components: ["events", "blockers", "minutes"],
-  },
-  wizard: {
-    actions: [],
-    providers: [],
-    all_actions: [],
-  },
-}
-
-export default (state = defaultState, action) => {
-  switch (action.type) {
-    case ActionTypes.LOAD_DATA_RESP:
-      return {
-        ...state,
-        landing_page: action.payload,
-      }
-
-    case ActionTypes.LOAD_WIZARD_DATA_RESP:
-      return {
-        ...state,
-        wizard: {
-          ...state.wizard,
-          providers: action.payload.providers,
-          all_actions: action.payload.actions,
-        },
-      }
-
-    default:
-      return {
-        ...state,
-      }
-  }
-}
diff --git a/src/reducers/landingPageSlice.js b/src/reducers/landingPageSlice.js
new file mode 100644
index 0000000..d1e2cbb
--- /dev/null
+++ b/src/reducers/landingPageSlice.js
@@ -0,0 +1,28 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+const landingPageReducer = createSlice({
+  name: "landing_page",
+  initialState: {
+    blockerbugs: {},
+    devel: 0,
+    meetings: [],
+    schedule: [],
+    last_qa_meeting: {},
+    stable: 0,
+    config_mode: false,
+    enabled_components: ["events", "blockers", "minutes"],
+
+    loading: false
+  },
+  reducers: {
+    loadData(state, action) {
+      if (!state.loading) state.loading = true;
+    },
+    loadDataResp(state, action) {
+      state.loading = false;
+      Object.assign(state, { ...action.payload });
+    }
+  }
+});
+export const { loadData, loadDataResp } = landingPageReducer.actions;
+export default landingPageReducer.reducer;
diff --git a/src/reducers/wizardSlice.js b/src/reducers/wizardSlice.js
new file mode 100644
index 0000000..f48032b
--- /dev/null
+++ b/src/reducers/wizardSlice.js
@@ -0,0 +1,24 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+const wizardReducer = createSlice({
+  name: "wizard",
+  initialState: {
+    actions: [],
+    providers: [],
+    all_actions: [],
+
+    loading: false
+  },
+  reducers: {
+    loadWizardData(state, action) {
+      if (!state.loading) state.loading = true;
+    },
+    loadWizardDataResp(state, action) {
+      state.loading = false;
+      state.providers = action.payload.providers;
+      state.all_actions = action.payload.actions;
+    }
+  }
+});
+export const { loadWizardData, loadWizardDataResp } = wizardReducer.actions;
+export default wizardReducer.reducer;
diff --git a/src/wizard/Wizard.js b/src/wizard/Wizard.js
index a9ecb3e..1b136bd 100644
--- a/src/wizard/Wizard.js
+++ b/src/wizard/Wizard.js
@@ -6,7 +6,7 @@ import Actions from "./Actions"
 import { Container, Row } from "reactstrap"
 
 import { connect } from "react-redux"
-import { loadWizardData } from "../actions/reduxActions"
+import { fetchWizardData } from "../actions/reduxActions"
 
 class Wizard extends Component {
   constructor(props) {
@@ -26,7 +26,7 @@ class Wizard extends Component {
         })
       })
 
-    this.props.dispatch(loadWizardData())
+    this.props.dispatch(fetchWizardData())
   }
 
   show_actions(actions) {
diff --git a/yarn.lock b/yarn.lock
index 85bfaa4..626a2c7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1359,6 +1359,16 @@
   resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
   integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
 
+"@reduxjs/toolkit@^1.5.1":
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.5.1.tgz#05daa2f6eebc70dc18cd98a90421fab7fa565dc5"
+  integrity sha512-PngZKuwVZsd+mimnmhiOQzoD0FiMjqVks6ituO1//Ft5UEX5Ca9of13NEjo//pU22Jk7z/mdXVsmDfgsig1osA==
+  dependencies:
+    immer "^8.0.1"
+    redux "^4.0.0"
+    redux-thunk "^2.3.0"
+    reselect "^4.0.0"
+
 "@svgr/babel-plugin-add-jsx-attribute@^4.2.0":
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1"
@@ -5236,6 +5246,11 @@ immer@1.10.0:
   resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
   integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
 
+immer@^8.0.1:
+  version "8.0.4"
+  resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.4.tgz#3a21605a4e2dded852fb2afd208ad50969737b7a"
+  integrity sha512-jMfL18P+/6P6epANRvRk6q8t+3gGhqsJ9EuJ25AXE+9bNTYtssvzeYbEd0mXRYWCmmXSIbnlpz6vd6iJlmGGGQ==
+
 import-cwd@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
@@ -8837,7 +8852,7 @@ redux-thunk@^2.3.0:
   resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
   integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
 
-redux@^4.0.5:
+redux@^4.0.0, redux@^4.0.5:
   version "4.0.5"
   resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
   integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
@@ -9017,6 +9032,11 @@ requires-port@^1.0.0:
   resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
   integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
 
+reselect@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
+  integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
+
 resolve-cwd@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"

From aab55ff8c280df6528aafe2f26dc1494ba4c35f1 Mon Sep 17 00:00:00 2001
From: Divyanshi Singh <divyanshipilot@gmail.com>
Date: Apr 08 2021 13:37:50 +0000
Subject: [PATCH 7/7] rebased


---

diff --git a/src/configureStore.js b/src/configureStore.js
index febe607..9d817e1 100644
--- a/src/configureStore.js
+++ b/src/configureStore.js
@@ -1,38 +1,19 @@
-import { configureStore, combineReducers } from "@reduxjs/toolkit";
-import logger from "redux-logger";
-import thunkMiddleware from "redux-thunk";
-import landingPageReducer from "./Containers/LandingPage/reducer";
-import wizardReducer from "./Containers/Wizard/reducer";
-
-export const defaultState = {
-  landing_page: {
-    blockerbugs: {},
-    devel: 0,
-    meetings: [],
-    schedule: [],
-    last_qa_meeting: {},
-    stable: 0,
-    config_mode: false,
-    enabled_components: ["events", "blockers", "minutes"]
-  },
-  wizard: {
-    actions: [],
-    providers: [],
-    all_actions: []
-  }
-};
+import { configureStore, combineReducers } from '@reduxjs/toolkit';
+import logger from 'redux-logger';
+import thunkMiddleware from 'redux-thunk';
+import landingPageReducer from './reducers/landingPageSlice';
+import wizardReducer from './reducers/wizardSlice';
 
 const reducer = combineReducers({
-  landing_page: landingPageReducer,
-  wizard: wizardReducer
-});
+    landing_page: landingPageReducer,
+    wizard: wizardReducer
+})
 
-export default function configureAppStore(initialState) {
-  const store = configureStore({
-    reducer,
-    middleware: [logger, thunkMiddleware],
-    devTools: process.env.NODE_ENV !== "production",
-    initialState
-  });
-  return store;
+export default function configureAppStore() {
+    const store = configureStore({
+        reducer,
+        middleware: [ thunkMiddleware, logger ],
+        devTools: process.env.NODE_ENV !== 'production',
+    })
+    return store;
 }
diff --git a/src/index.js b/src/index.js
index 7bf6062..5c27953 100644
--- a/src/index.js
+++ b/src/index.js
@@ -11,9 +11,8 @@ import * as serviceWorker from './serviceWorker';
 
 import { Provider } from 'react-redux';
 import configureAppStore from './configureStore';
-import { defaultState } from './configureStore';
 
-const store= configureAppStore(defaultState);
+const store= configureAppStore();
 
 ReactDOM.render(
     <React.StrictMode>
diff --git a/src/reducers/landingPageSlice.js b/src/reducers/landingPageSlice.js
new file mode 100644
index 0000000..d1e2cbb
--- /dev/null
+++ b/src/reducers/landingPageSlice.js
@@ -0,0 +1,28 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+const landingPageReducer = createSlice({
+  name: "landing_page",
+  initialState: {
+    blockerbugs: {},
+    devel: 0,
+    meetings: [],
+    schedule: [],
+    last_qa_meeting: {},
+    stable: 0,
+    config_mode: false,
+    enabled_components: ["events", "blockers", "minutes"],
+
+    loading: false
+  },
+  reducers: {
+    loadData(state, action) {
+      if (!state.loading) state.loading = true;
+    },
+    loadDataResp(state, action) {
+      state.loading = false;
+      Object.assign(state, { ...action.payload });
+    }
+  }
+});
+export const { loadData, loadDataResp } = landingPageReducer.actions;
+export default landingPageReducer.reducer;
diff --git a/src/reducers/wizardSlice.js b/src/reducers/wizardSlice.js
new file mode 100644
index 0000000..f48032b
--- /dev/null
+++ b/src/reducers/wizardSlice.js
@@ -0,0 +1,24 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+const wizardReducer = createSlice({
+  name: "wizard",
+  initialState: {
+    actions: [],
+    providers: [],
+    all_actions: [],
+
+    loading: false
+  },
+  reducers: {
+    loadWizardData(state, action) {
+      if (!state.loading) state.loading = true;
+    },
+    loadWizardDataResp(state, action) {
+      state.loading = false;
+      state.providers = action.payload.providers;
+      state.all_actions = action.payload.actions;
+    }
+  }
+});
+export const { loadWizardData, loadWizardDataResp } = wizardReducer.actions;
+export default wizardReducer.reducer;

