From b7bdb5ef0b41c7faddb4c42d664befc8f88227c6 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Mon, 7 Sep 2020 15:59:22 +0200 Subject: [PATCH 001/175] Add new intel and client Yeet old out of existence, yeet new into existence. --- src/index.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/index.js b/src/index.js index 2be9cd9..68d9f24 100644 --- a/src/index.js +++ b/src/index.js @@ -16,7 +16,12 @@ import { loadingBarMiddleware } from "react-redux-loading-bar"; // Thunk import thunk from "redux-thunk"; //> Intel -import { Intel } from "snek-intel"; +import INTEL_SNEK from "snek-intel/lib/utils/snek"; +import INTEL_INSTAGRAM from "snek-intel/lib/utils/instagram"; +import INTEL_IMGUR from "snek-intel/lib/utils/imgur"; + +//> Client +import { SnekClient } from "snek-client"; //> Font Awesome // Font Awesome is an awesome icon library @@ -40,13 +45,7 @@ import registerServiceWorker from "./registerServiceWorker"; //#endregion //#region > Redux Store Initialization -const INTEL = new Intel(); - -//#TODO -// Must be moved to INTEL in future? -const getIntel = () => { - return INTEL; -}; +const CLIENT_SNEK = new SnekClient("http://localhost:8000/graphql"); const composeEnhancers = typeof window === "object" && @@ -61,8 +60,10 @@ const enhancer = composeEnhancers( applyMiddleware( loadingBarMiddleware(), thunk.withExtraArgument({ - // Intel - getIntel, + INTEL_SNEK, + INTEL_IMGUR, + INTEL_INSTAGRAM, + CLIENT_SNEK, }) ) // other store enhancers if any From 8abce19ebfd5cb743ecb1605ca2bf73d9d406128 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Mon, 7 Sep 2020 16:53:33 +0200 Subject: [PATCH 002/175] Add new register The register component has been reworked. --- .../molecules/UserActionCard/index.jsx | 55 +- .../molecules/forms/LoginForm/index.jsx | 2 +- .../molecules/forms/RegisterForm/index.jsx | 788 +++--------------- 3 files changed, 116 insertions(+), 729 deletions(-) diff --git a/src/components/molecules/UserActionCard/index.jsx b/src/components/molecules/UserActionCard/index.jsx index 999c998..c701e0e 100644 --- a/src/components/molecules/UserActionCard/index.jsx +++ b/src/components/molecules/UserActionCard/index.jsx @@ -44,64 +44,25 @@ class UserActionCard extends React.Component {
{activeItem === 0 && ( <> - this.setActiveItem(1)}> + this.setActiveItem(1)}> + Login to SNEK
-
+
or
-

Choose your snek

-

What is your main profession?

- - -
this.setActiveItem(2)} - > -

Software Engineer

- -
-
- -
this.setActiveItem(3)} - > -

Media Engineer

- -
-
-
+

Sign up

+

+ Join the biggest network for engineers today! +

+ )} {activeItem === 1 && } - {activeItem === 2 && } - {activeItem === 3 && ( - <> -
- this.goTo(0)} - > - - Back - -
- -

- - Media Engineer profiles are not yet supported -

- this.goTo(2)}> - Create Software Engineer profile - -
- - )}
); } diff --git a/src/components/molecules/forms/LoginForm/index.jsx b/src/components/molecules/forms/LoginForm/index.jsx index 07dcfab..23a8239 100644 --- a/src/components/molecules/forms/LoginForm/index.jsx +++ b/src/components/molecules/forms/LoginForm/index.jsx @@ -190,7 +190,7 @@ class LoginForm extends React.Component { } value={this.state.login_password} /> - + Login diff --git a/src/components/molecules/forms/RegisterForm/index.jsx b/src/components/molecules/forms/RegisterForm/index.jsx index 5aa8832..7158a83 100644 --- a/src/components/molecules/forms/RegisterForm/index.jsx +++ b/src/components/molecules/forms/RegisterForm/index.jsx @@ -56,173 +56,7 @@ class RegisterForm extends React.Component { email: "", password1: "", password2: "", - username: "", - gitlab_username: "", - gitlab_servers: undefined, - gitlab_server: "Choose your organisation", - sourceList: [], - usernames: [], promoCode: true, - code: "", - }; - - componentDidMount = () => { - this.getGitLabServers(); - }; - - toggle = () => { - if (!this.state.modalGitLab) { - this.setState({ - modalGitLab: true, - }); - } else { - this.setState({ - modalGitLab: false, - }); - } - }; - - getGitLabServers = async () => { - // Check if GitLab Servers have already been set - if (this.state.gitlab_servers === undefined) { - // Retrieve GitLab servers - this.props.fetchGitLabServers().then(() => { - this.setState({ - gitlab_servers: this.props.gitlabServers, - }); - }); - } - }; - - addGitLab = () => { - const username = this.state.gitlab_username; - const server = this.state.gitlab_server; - - //#TSID7 - //console.log("REGISTER FORM ADD GITLAB", username, server); - - if (username.trim() && server.trim()) { - if (server !== "Choose your organisation") { - this.connectGitLab(username, "https://" + server); - } - } - }; - - connectGitLab = async (username, platformUrl) => { - this.setState( - { - modalGitLab: false, - gitlab_username: "", - gitlab_server: "Choose your organisation", - }, - () => this.pushToSourceList("gitlab", username, platformUrl) - ); - }; - - oauthGitHubSuccess = (response) => { - this.setState( - { - loadingGitHub: true, - }, - async () => { - this.pushToSourceList( - "github", - response.username, - "https://api.github.com/graphql", - response.accessToken - ); - } - ); - }; - - oauthGitHubFailure = (response) => { - //#ERROR - console.error(response); - }; - - pushToSourceList = (platformName, username, platformUrl, token) => { - let sourceList = this.state.sourceList; - - this.addToUsernames(username, platformName); - - sourceList.push({ - id: username.length + platformName.length + username + platformName, - user: username, - authorization: token ? "token " + token : null, - platform: { - name: platformName, - url: platformUrl, - }, - }); - - if (platformName === "github") { - this.setState({ - username, - hasGitHub: true, - sourceList, - loadingGitHub: false, - }); - } else { - // Set the new list of user information - this.setState({ - sourceList, - }); - } - }; - - addToUsernames = (username, source) => { - let usernames = this.state.usernames; - let found = false; - - for (let i = 0; i < usernames.length; i++) { - if ( - usernames[i].username === username && - usernames[i].source === source - ) { - found = true; - break; - } - } - - if (!found) { - // Make sure that only GitHub usernames are available for selection - // This aims to prevent name abuse in the first versions of this application - usernames.push({ - id: username.length + source.length + username + source, - username, - source, - verified: source === "github" ? true : false, - }); - this.setState({ - usernames, - }); - } - }; - - removeSource = (id) => { - let sourceList = this.state.sourceList.filter(function (obj) { - return obj.id !== id; - }); - let usernames = this.state.usernames.filter(function (obj) { - return obj.id !== id; - }); - - this.setState({ - sourceList, - usernames, - }); - }; - - handleUserNamePick = (username) => { - this.setState({ - username, - }); - }; - - handleSelectChange = (e) => { - this.setState({ - gitlab_server: e[0], - }); }; testForError = (id) => { @@ -301,539 +135,131 @@ class RegisterForm extends React.Component { } }; - // Handle sumbit of register form - handleSubmit = async () => { - //#TSID8 - //console.log("REGISTER FORM HANDLE SUBMIT"); - - // CHANGE TO CONST - let { - password1, - password2, - firstname, - lastname, - email, - sourceList, - username, - promoCode, - code, - } = this.state; - - // Error - let errors = []; - - // Check if passwords match - if (password1 !== "" && password2 !== "" && password1 !== password2) { - errors.push({ - code: 1, - msg: "Your passwords do not match.", - weight: 10, - }); - } - - if (sourceList.length === 0) { - errors.push({ - code: 2, - msg: "No platforms are connected.", - weight: 10, - }); - } - - if (firstname === "") { - errors.push({ - code: 3, - msg: "Please enter your first name.", - weight: 8, - }); - } - - if (lastname === "") { - errors.push({ - code: 4, - msg: "Please enter your last name.", - weight: 8, - }); - } - - if (email === "") { - errors.push({ - code: 5, - msg: "Please enter your email.", - weight: 9, - }); - } - - if (username === "") { - errors.push({ - code: 6, - msg: "Please select a username from the list above.", - weight: 10, - }); - } - - if (password1 === "") { - errors.push({ - code: 7, - msg: "Please enter a password.", - weight: 10, - }); - } - - if (password2 === "") { - errors.push({ - code: 8, - msg: "Please repeat your password.", - weight: 10, - }); - } - - if (code === "") { - errors.push({ - code: 9, - msg: "Please enter your promo code or contact us to receive one.", - weight: 5, - }); - } - - if (errors.length === 0) { - this.setState( - { - loading: true, - }, - () => { - //#TSID9 - //console.log("REGISTER FORM REGISTER", this.state); - - let registrationData = { - sources: sourceList, - username, - email, - first_name: firstname, - last_name: lastname, - gift_code: promoCode && code !== "" ? code : null, - password: password1, - }; - - this.props.register(registrationData).then(() => { - const { username, password } = registrationData; - - this.props.login({ - username, - password, - }); - }); - } - ); - } else { - this.setState({ - errors, - }); - } - }; - - handleCodeChange = (e) => { - let code = e.target.value; - - if (code.length <= 14) { - if (code.length === 4 || code.length === 9) { - code = code + "-"; - } - - this.setState( - { - code: code.toUpperCase(), - }, - () => this.removeError(9) - ); - } else { - return false; - } - }; - render() { const { goTo } = this.props; return ( <> - {!this.state.loading ? ( - <> -
- this.setState({ errors: [] }, () => goTo(0))} - > - - Back - -
-

So you're a Software Engineer...

-

- We just need a bit more information to get you started. -

-
- - - this.handleChange(e, 3)} - value={this.state.firstname} - /> - - - this.handleChange(e, 4)} - value={this.state.lastname} - /> - - + + this.handleChange(e, 5)} + value={this.state.username} + /> + + this.handleChange(e, 5)} - value={this.state.email} + placeholder="Firstname" + name="firstname" + onChange={(e) => this.handleChange(e, 3)} + value={this.state.firstname} /> - - - this.handleChange(e, [7, 1])} - value={this.state.password1} - /> - - - this.handleChange(e, [8, 1])} - value={this.state.password2} - /> - - - -
- - this.setState({ promoCode: !this.state.promoCode }) - } - > - {!this.state.promoCode - ? "I have a promo code" - : "I don't have a promo code"} - -
- {this.state.promoCode && ( +
+ this.handleChange(e, 4)} + value={this.state.lastname} /> - )} -

Connect your work

- - You need to connect at least one account to continue. - -
- - - - Why do I need to connect my accounts? - -
- - - Connecting accounts - - - To generate your expressive and meaningful profile, we - require data about your work, which we acquire by fetching - it from platforms like GitHub, GitLab and BitBucket. It also - helps us verify your data. -
- - Learn more - -
-
-
-
-
- this.setState({ modalGitLab: true })} - disabled={ - !this.state.gitlab_servers || - (this.state.gitlab_server && - this.state.gitlab_server.length < 1) + + + this.handleChange(e, 5)} + value={this.state.email} + /> + + + - - - {!process.env.NODE_ENV || - process.env.NODE_ENV === "development" ? ( - - ) : ( - - )} - - - -
-
- - {this.state.loadingGitHub && } - {this.state.usernames.map((source, i) => { - return ( - -
- - {source.username} - {source.verified ? ( - - - - -
- Verified - - - - - - - This source has been{" "} - - verified - {" "} - by logging into it. - - - -
-
- ) : ( - - - - -
- Not verified - - - - - - - We can not verify your identity with GitLab. - Your data is still being included. - - - -
-
- )} -
- this.removeSource(source.id)} - /> -
- ); - })} -
-
- - Join now - -

- - Don't worry, you can easily connect further accounts in the - future. - -

- - ) : ( -
-

- Hey, {this.state.firstname}! -

-

Your profile is being generated.

-
-
-
- -
- )} - {this.state.modalGitLab && ( - - - - Add GitLab profile - - + placeholder="Password" + name="password1" + onChange={(e) => this.handleChange(e, [7, 1])} + value={this.state.password1} + /> +
+ - this.setState({ [e.target.name]: e.target.value }) + type="password" + className={ + this.testForError([8, 1]) + ? "form-control error" + : "form-control" } - value={this.state.gitlab_username} + placeholder="Confirm password" + name="password2" + onChange={(e) => this.handleChange(e, [8, 1])} + value={this.state.password2} /> - - - - - Choose your organisation - - {this.state.gitlab_servers && - this.state.gitlab_servers.map((source, i) => { - return ( - - {source.organisation} - - ); - })} - - - - - - - Add - - - Cancel - - - + +
+ +
+ this.setState({ promoCode: !this.state.promoCode })} + > + {!this.state.promoCode + ? "I have a promo code" + : "I don't have a promo code"} + +
+ {this.state.promoCode && ( + )} + + + Join now + ); } From c8ac1220c547e0ac37d62d5bcd4173ae62f08a46 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Mon, 7 Sep 2020 17:19:39 +0200 Subject: [PATCH 003/175] Improve register The labels have been improved. --- .../molecules/forms/RegisterForm/index.jsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/molecules/forms/RegisterForm/index.jsx b/src/components/molecules/forms/RegisterForm/index.jsx index 7158a83..de06ae2 100644 --- a/src/components/molecules/forms/RegisterForm/index.jsx +++ b/src/components/molecules/forms/RegisterForm/index.jsx @@ -140,7 +140,8 @@ class RegisterForm extends React.Component { return ( <> -
+ + Username this.handleChange(e, 5)} value={this.state.username} /> - + + Firstname this.handleChange(e, 3)} value={this.state.firstname} /> + Lastname this.handleChange(e, 4)} value={this.state.lastname} /> + E-Mail this.handleChange(e, 5)} value={this.state.email} /> + Password this.handleChange(e, [7, 1])} value={this.state.password1} /> + Confirm password this.handleChange(e, [8, 1])} value={this.state.password2} @@ -246,7 +246,7 @@ class RegisterForm extends React.Component { type="text" id="materialFormRegisterConfirmEx40" name="code" - placeholder="Promo code" + placeholder="XXXX-XXXX-XXXX" label="Promotional code" /> )} From 57b35dcf0ac8828455ecee3f9686be3eedbe951a Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 18:23:28 +0200 Subject: [PATCH 004/175] Remove all actions and implement user actions All actions have been removed. User actions like login, logout, and getPerson have been implemented. --- src/store/actions/authActions.js | 102 ----- src/store/actions/generalActions.js | 152 ------- src/store/actions/personActions.js | 0 src/store/actions/userActions.js | 580 +++----------------------- src/store/reducers/authReducers.js | 66 --- src/store/reducers/generalReducers.js | 89 ---- src/store/reducers/index.js | 8 - src/store/reducers/userReducers.js | 175 ++------ src/store/types.js | 11 + 9 files changed, 105 insertions(+), 1078 deletions(-) delete mode 100644 src/store/actions/authActions.js delete mode 100644 src/store/actions/generalActions.js create mode 100644 src/store/actions/personActions.js delete mode 100644 src/store/reducers/authReducers.js delete mode 100644 src/store/reducers/generalReducers.js create mode 100644 src/store/types.js diff --git a/src/store/actions/authActions.js b/src/store/actions/authActions.js deleted file mode 100644 index 3ebd7cd..0000000 --- a/src/store/actions/authActions.js +++ /dev/null @@ -1,102 +0,0 @@ -//#region > Authentication Actions -/** - * Handle login. - * - * @param user A user to login with - * @description Handles states for login - */ -const loginAction = (user) => { - return (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - const session = intel.snekclient.session; - - return session - .begin(user) - .then((whoami) => { - if (!whoami?.anonymous && whoami?.__typename === "SNEKUser") { - dispatch({ - type: "LOGIN_SUCCESS", - payload: { - username: whoami.username, - avatarUrl: - "https://www.clipartmax.com/png/full/166-1669056_the-20-cooler-octocat-github-octocat.png", - }, - }); - } else if (whoami.anonymous) { - dispatch({ - type: "LOGIN_ANON_SUCCESS", - payload: {}, - }); - } else { - throw Error("Login failed") - } - }) - .catch((ex) => - dispatch({ - type: "LOGIN_FAILED", - payload: { - errorCode: 619, - message: "Incorrect username or password", - error: ex, - }, - }) - ); - } catch (ex) { - dispatch({ - type: "LOGIN_ERROR", - payload: { errorCode: 600, message: "Login failed", error: ex }, - }); - } - }; -}; - -/** - * Logout user. - * - * @description Handles the logging out of active users - */ -const logoutAction = () => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - const session = intel.snekclient.session; - - await session - .end() - .then(() => { - dispatch({ - type: "LOGOUT_SUCCESS", - payload: {}, - }); - - dispatch({ - type: "REMOVE_LOGGED_USER", - }); - }) - .catch((ex) => - dispatch({ type: "LOGOUT_ERROR", payload: { error: ex } }) - ); - } catch (ex) { - dispatch({ - type: "LOGOUT_FAILED", - payload: { - errorCode: 601, - message: "Logout failed", - error: ex, - }, - }); - } - }; -}; -//#endregion - -//#region > Exports -//> Default Component -export { loginAction, logoutAction }; -//#endregion - -/** - * SPDX-License-Identifier: (EUPL-1.2) - * Copyright © 2019-2020 Simon Prast - */ diff --git a/src/store/actions/generalActions.js b/src/store/actions/generalActions.js deleted file mode 100644 index 3f03e96..0000000 --- a/src/store/actions/generalActions.js +++ /dev/null @@ -1,152 +0,0 @@ -//#region > Registration Actions -/** - * Append Source Objects - * - * @param sourceList A source object - * @description Hands source list over to intel - */ -const appendSourceObjectsAction = (sourceList) => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - - intel.appendList(sourceList); - - dispatch({ - type: "APPEND_SOURCE_OBJECTS_SUCCESS", - payload: {}, - }); - } catch (ex) { - dispatch({ - type: "APPEND_SOURCE_OBJECTS_ERROR", - payload: { - errorCode: 602, - message: "Appending source objects failed", - error: ex, - }, - }); - } - }; -}; - -/** - * Fetch GitLab Servers - * - * @description Retrieves a list of available GitLab servers - */ -const fetchGitLabServersAction = () => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - const session = intel.snekclient.session; - - return session.tasks.general - .gitlabServer() - .then(({ data }) => { - const gitLabServers = data?.page?.supportedGitlabs; - - dispatch({ - type: "FETCH_GITLAB_SERVER_SUCCESS", - payload: { gitLabServers }, - }); - }) - .catch((ex) => - dispatch({ - type: "FETCH_GITLAB_SERVER_ERROR", - payload: { error: ex }, - }) - ); - } catch (ex) { - dispatch({ - type: "FETCH_GITLAB_SERVER_ERROR", - payload: { - errorCode: 605, - message: "Fetching GitLab server failed", - error: ex, - }, - }); - } - }; -}; -//#endregion - -//#region > Data Handling Actions -/** - * Get intel data - * - * @description Retrieves data from current applied source list - */ -const getDataAction = () => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - - intel - .get() - .then((res) => dispatch({ type: "GET_DATA_SUCCESS", payload: res })) - .catch((ex) => - dispatch({ type: "GET_DATA_ERROR", payload: { error: ex } }) - ); - } catch (ex) { - dispatch({ - type: "GET_DATA_ERROR", - payload: { - errorCode: 603, - message: "Getting intel data failed", - error: ex, - }, - }); - } - }; -}; - -/** - * Get all users - * - * @description Retrieves a list of all users - */ -const getUserSearchItems = () => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - const session = intel.snekclient.session; - - return await session.tasks.general - .allUserPageUrls() - .then((res) => { - dispatch({ - type: "GET_APP_PAGE_URLS_SUCCESS", - payload: { items: res.data.page.children }, - }); - }) - .catch((ex) => - dispatch({ type: "GET_APP_PAGE_URLS_ERROR", payload: { error: ex } }) - ); - } catch (ex) { - dispatch({ - type: "GET_APP_PAGE_URLS_ERROR", - payload: { - errorCode: 616, - message: "Getting all page urls failed", - error: ex, - }, - }); - } - }; -}; -//#endregion - -//#region > Exports -//> Default Component -export { - appendSourceObjectsAction, - getDataAction, - getUserSearchItems, - fetchGitLabServersAction, -}; -//#endregion - -/** - * SPDX-License-Identifier: (EUPL-1.2) - * Copyright © 2019-2020 Simon Prast - */ diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js new file mode 100644 index 0000000..e69de29 diff --git a/src/store/actions/userActions.js b/src/store/actions/userActions.js index 8513232..f1a5e9e 100644 --- a/src/store/actions/userActions.js +++ b/src/store/actions/userActions.js @@ -1,483 +1,76 @@ //#region > Imports -//> Redux -// Allows to manually display a LoadingBar -import { showLoading, hideLoading } from "react-redux-loading-bar"; -//> Additional -// SHA Hashing algorithm -import sha256 from "js-sha256"; +//> Action Types +import * as Action from "../types"; +//> Intel +import INTEL_SNEK from "snek-intel/lib/utils/snek"; //#endregion -//#region > Register Actions +//#region > User Actions /** - * Register user. + * Handle login. * - * @param registrationData Data to register a user - * @description Handles the registration of users + * @param user A user to login with + * @description Handles states for login */ -const registerAction = (registrationData) => { - return async (dispatch, getState, { getIntel }) => { +const loginAction = (user) => { + return async (dispatch, getState, { CLIENT_SNEK }) => { try { - const intel = getIntel(); - const session = intel.snekclient.session; - const clearPassword = registrationData.password; + dispatch({ type: Action.USER_LOGIN_REQUEST }); - // Hash password - registrationData.password = sha256(registrationData.password); + const whoami = await CLIENT_SNEK.session.begin(user); - // Append Source objects - await intel.appendList(registrationData.sources); - // Generate talks based on the previous appended list - await intel.generateTalks(registrationData.sources); - - // Get fresh platform data - const intelData = { - ...(await intel.get()), - talks: await intel.getTalks(), - }; - - // Save Object to platformData as JSON - registrationData.platform_data = JSON.stringify(intelData); - // Create JSON string out of sources for backend use - registrationData.sources = JSON.stringify(registrationData.sources); - - return session.tasks.user - .registration(registrationData) - .then((res) => { - if (res.result === "FAIL") { - dispatch({ - type: "SIGNUP_FAILED", - payload: { - errorCode: 606, - message: "Registration failed due to false registration result", - error: undefined, - }, - }); - } else { - dispatch({ - type: "SIGNUP_SUCCESS", - payload: { - registrationData, - username: registrationData.username, - password: clearPassword, - }, - }); - } - }) - .catch((ex) => - dispatch({ type: "SIGNUP_ERROR", payload: { error: ex } }) - ); - } catch (ex) { - dispatch({ - type: "SIGNUP_ERROR", - payload: { - errorCode: 617, - message: "Registration failed", - error: ex, - }, - }); - } - }; -}; -//#endregion - -//#region > Caching Actions -/** - * Write cache. - * - * @param platformData A data object to store in cache - * @description Handles the calls for writing to cache - */ -const writeCacheAction = (platformData) => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - const session = intel.snekclient.session; - - return session.tasks.user - .cache(JSON.stringify(platformData)) - .then(() => - dispatch({ - type: "WRITE_CACHE_SUCCESS", - payload: {}, - }) - ) - .catch((ex) => - dispatch({ type: "WRITE_CACHE_ERROR", payload: { error: ex } }) - ); - } catch (ex) { - dispatch({ - type: "WRITE_CACHE_ERROR", - payload: { - errorCode: 607, - message: "Writing to cache failed", - error: ex, - }, - }); - } - }; -}; - -/** - * Read cache. - * - * @param username A username to read the cache from - * @description Handles the calls for reading the cache - */ -const readCacheAction = (username) => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - const session = intel.snekclient.session; - - return session.tasks.user - .profile(username) - .then(async ({ data }) => { - if (!data.page) { - dispatch({ - type: "READ_CACHE_FAILED", - payload: { - errorCode: 608, - message: "Cache not loaded", - error: undefined, - }, - }); - } else { - // Split profile to chunks - const profile = data.page; - const sources = profile.sources - ? JSON.parse(profile.sources) - : null; - - let platformData = profile.person.cache - ? JSON.parse(profile.person.cache) - : {}; - - let user = platformData.user ? platformData.user : {}; - - // Check if data is valid - if (!sources) { - dispatch({ - type: "READ_CACHE_FAILED", - payload: { - errorCode: 609, - message: "Sources are empty", - error: undefined, - }, - }); - } else { - // Set settings for first time fetching - if ( - ![ - "firstName", - "lastName", - "email", - "avatarUrl", - "websiteUrl", - "websiteUrl", - "location", - "company", - ].every((item) => user.hasOwnProperty(item)) - ) { - user.firstName = platformData.profile.firstName; - user.lastName = platformData.profile.lastName; - user.email = platformData.profile.email; - user.avatarUrl = platformData.profile.avatarUrl; - user.websiteUrl = platformData.profile.websiteUrl; - user.location = platformData.profile.location; - user.company = platformData.profile.company; - } - - if (!user.settings) { - user.settings = { - show3DDiagram: true, - show2DDiagram: true, - showCompanyPublic: true, - showEmailPublic: true, - showLocalRanking: true, - activeTheme: null, - }; - } - - // Build fetchedUser object - let fetchedUser = { - username: profile.personName, - platformData: { - ...platformData, - user, - }, - sources, - verified: data.page.verified ? data.page.verified : true, - accessories: { - badges: { - bids: [data.page.bids] - }, - themes: { - tids: [data.page.tids] - } - }, - }; - - dispatch({ - type: "READ_CACHE_SUCCESS", - payload: { fetchedUser }, - }); - - const state = getState(); - - if (fetchedUser.username === state.auth.loggedUser?.username) { - dispatch({ - type: "SET_LOGGED_USER", - payload: { fetchedUser }, - }); - } - } - } - }) - .catch((ex) => { - dispatch({ type: "READ_CACHE_ERROR", payload: { error: ex } }) + if (!whoami?.anonymous && whoami?.__typename === "SNEKUser") { + dispatch({ + type: Action.USER_LOGIN_SUCCESS, + payload: { + username: whoami.username, + anonymous: false, + }, }); - } catch (ex) { - dispatch({ - type: "READ_CACHE_ERROR", - payload: { - errorCode: 610, - message: "Reading from cache failed", - error: ex, - }, - }); - } - }; -}; - -/** - * Update cache. - * - * @param fetchedUser A fetched user object - * @description Handles the calls for updating the cache - */ -const updateCacheAction = (fetchedUser) => { - return async (dispatch, getState, { getIntel }) => { - try { - dispatch(showLoading()); - - const intel = getIntel(); - const session = intel.snekclient.session; - - // Appned Source objects - await intel.appendList(fetchedUser.sources); - // Generate talks based on the previous appended list - await intel.generateTalks(fetchedUser.sources); - - // Get fresh platform data - const intelData = { - ...(await intel.get()), - talks: await intel.getTalks(), - }; - - // Fix duplicates - for (const i in intelData.talks) { - let state = true; - - for (const i2 in fetchedUser.platformData.talks) { - if ( - intelData.talks[i].url === fetchedUser.platformData.talks[i2].url - ) { - state = false; - } - } - - if (state) { - fetchedUser.platformData.talks.push(intelData.talks[i]); - } - } - - fetchedUser.platformData = { - ...intelData, - user: fetchedUser.platformData.user, - talks: fetchedUser.platformData.talks, - }; - - intel.resetReducer(); - - dispatch(hideLoading()); - - return session.tasks.user - .cache(JSON.stringify(fetchedUser.platformData)) - .then( - dispatch({ - type: "UPDATE_CACHE_SUCCESS", - payload: { fetchedUser }, - }) - ) - .catch((ex) => - dispatch({ type: "UPDATE_CACHE_ERROR", payload: { error: ex } }) - ); - } catch (ex) { - dispatch({ - type: "UPDATE_CACHE_ERROR", - payload: { - errorCode: 618, - message: "Updating cache failed", - error: ex, - }, - }); - } - }; -}; - -/** - * Save settings - * - * @param nextSettings The settings that should be applied - * @description Saves the user settings - */ -const saveSettingsActions = (nextSettings) => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - const state = getState(); - - const fetchedUser = state.user.fetchedUser; - const session = intel.snekclient.session; - - if (fetchedUser.platformData) { - // Check for mandatory fields - if (nextSettings.email) { - fetchedUser.platformData.user.avatarUrl = nextSettings.avatar_url - ? nextSettings.avatar_url - : ""; - fetchedUser.platformData.user.firstName = nextSettings.first_name - ? nextSettings.first_name - : ""; - fetchedUser.platformData.user.lastName = nextSettings.last_name - ? nextSettings.last_name - : ""; - fetchedUser.platformData.user.email = nextSettings.email - ? nextSettings.email - : fetchedUser.platformData.user.email; - fetchedUser.platformData.user.websiteUrl = nextSettings.website - ? nextSettings.website - : ""; - fetchedUser.platformData.user.location = nextSettings.location - ? nextSettings.location - : ""; - fetchedUser.platformData.user.company = nextSettings.company - ? nextSettings.company - : ""; - fetchedUser.platformData.user.settings = { - showTopLanguages: nextSettings.showTopLanguages, - showLocalRanking: nextSettings.showLocalRanking, - show3DDiagram: nextSettings.show3DDiagram, - show2DDiagram: nextSettings.show2DDiagram, - showEmailPublic: nextSettings.showEmailPublic, - showCompanyPublic: nextSettings.showCompanyPublic, - activeTheme: nextSettings.activeTheme, - }; - } - - session.tasks.user.cache(fetchedUser.username, JSON.stringify(fetchedUser.platformData)); + dispatch(getPerson(whoami.username)); + } else if (whoami.anonymous) { dispatch({ - type: "SAVE_SETTING_SUCCESS", + type: Action.USER_LOGIN_SUCCESS, payload: { - fetchedUser, + anonymous: true, }, }); + } else { + throw Error("Login failed"); } } catch (ex) { dispatch({ - type: "SAVE_SETTING_ERROR", + type: Action.USER_LOGIN_FAILURE, payload: { - errorCode: 604, - message: "Saving settings failed", + errorCode: 619, + message: "Login failed", error: ex, }, }); } }; }; -//#endregion - -//#region > Talks Actions -//> Is currently not needed but has been left for later implementations! -// /** -// * Get all talks. -// * -// * @description Handles the call for getting all talks. -// */ -// const getAllTalksAction = () => { -// return async (dispatch, getState, { getIntel }) => { -// try { -// const intel = getIntel(); - -// return intel -// .getTalks() -// .then((talks) => -// dispatch({ type: "GET_TALKS_SUCCESS", payload: { talks } }) -// ) -// .catch((ex) => -// dispatch({ type: "GET_TALKS_ERROR", payload: { error: ex } }) -// ); -// } catch (ex) { -// dispatch({ -// type: "GET_TALKS_ERROR", -// payload: { -// errorCode: 611, -// message: "Getting intel talks failed", -// error: ex, -// }, -// }); -// } -// }; -// }; /** - * Get a talk. + * Logout user. * - * @param uid A unique id to find a talk - * @param username A username associated with the talk - * @description Handles the call for getting one specific talk + * @description Handles the logging out of active users */ -const getTalkAction = (uid, username) => { - return async (dispatch, getState, { getIntel }) => { +const logoutAction = () => { + return async (dispatch, getState, { CLIENT_SNEK }) => { try { - const intel = getIntel(); - const session = intel.snekclient.session; + dispatch({ type: Action.USER_LOGOUT_REQUEST }); - return session.tasks.user - .profile(username) - .then(async ({ data }) => { - if (data.page) { - let talks = JSON.parse(data.page.platformData).talks; + await CLIENT_SNEK.session.end(); - talks = talks.filter((talk) => { - return talk.uid === uid; - }); - - dispatch({ - type: "GET_TALK_SUCCESS", - payload: { talk: talks[0] }, - }); - } else { - dispatch({ - type: "GET_TALK_FAILED", - payload: { - errorCode: 613, - message: "Cannot get specific talk " + uid, - error: undefined, - }, - }); - } - }) - .catch((ex) => - dispatch({ type: "GET_TALK_ERROR", payload: { error: ex } }) - ); + dispatch({ type: Action.USER_LOGOUT_SUCCESS }); } catch (ex) { dispatch({ - type: "GET_TALK_ERROR", + type: Action.USER_LOGOUT_FAILURE, payload: { - errorCode: 614, - message: "Getting talks failed", + errorCode: 601, + message: "Logout failed", error: ex, }, }); @@ -486,109 +79,32 @@ const getTalkAction = (uid, username) => { }; /** - * Upload talk. - * - * @param file A file to be uploaded - * @param talkInfo Additional information to add to the talk - * @description Handles the call for uploading a talk + * Get person page for a logged user */ -const uploadTalkAction = (file, talkInfo) => { - return async (dispatch, getState, { getIntel }) => { +const getPerson = (personName) => { + return async (dispatch, getState, {}) => { try { - const intel = getIntel(); - const state = getState(); - - const fetchedUser = state.user.fetchedUser; - const session = intel.snekclient.session; - - return intel.appendTalk(file).then(() => { - return intel.getTalks().then((talks) => { - talks[talks.length - 1].repository = talkInfo; + dispatch({ type: Action.USER_PERSON_GET_REQUEST }); - fetchedUser.platformData.talks.push(talks[talks.length - 1]); + const person = await INTEL_SNEK.person.get({ personName }); - session.tasks.user - .cache(JSON.stringify(fetchedUser.platformData)) - .then(() => - dispatch({ - type: "UPLOAD_TALK_SUCCESS", - payload: { - fetchedUser, - }, - }) - ); - }); - }); + dispatch({ type: Action.USER_PERSON_GET_SUCCESS, payload: person }); } catch (ex) { dispatch({ - type: "UPLOAD_TALK_ERROR", + type: Action.USER_PERSON_GET_FAILURE, payload: { - errorCode: 612, - message: "Uploading talk failed", + errorCode: 601, + message: `Getting person (${personName}) failed`, error: ex, }, }); } }; }; - -/** - * @todo currentCache over getState - * Delete talk. - * - * @param talk A talk that should be deleted - * @description Handles the call for deleting a talk. - */ -const deleteTalkAction = (talk) => { - return async (dispatch, getState, { getIntel }) => { - try { - const intel = getIntel(); - const state = getState(); - - const fetchedUser = state.user.fetchedUser; - const session = intel.snekclient.session; - - for (const index in fetchedUser.platformData.talks) { - if (talk.uid === fetchedUser.platformData.talks[index].uid) { - fetchedUser.platformData.talks.splice(index, 1); - } - } - - session.tasks.user.cache(JSON.stringify(fetchedUser.platformData)); - - dispatch({ - type: "DELETING_TALK_SUCCESS", - payload: { - fetchedUser, - }, - }); - } catch (ex) { - dispatch({ - type: "DELETING_TALK_ERROR", - payload: { - errorCode: 615, - message: "Deleting talk failed", - raw: ex, - }, - }); - } - }; -}; //#endregion //#region > Exports -//> Default Component -export { - registerAction, - writeCacheAction, - readCacheAction, - updateCacheAction, - saveSettingsActions, - //getAllTalksAction, - getTalkAction, - uploadTalkAction, - deleteTalkAction, -}; +export { loginAction, logoutAction, getPerson }; //#endregion /** diff --git a/src/store/reducers/authReducers.js b/src/store/reducers/authReducers.js deleted file mode 100644 index 769bf07..0000000 --- a/src/store/reducers/authReducers.js +++ /dev/null @@ -1,66 +0,0 @@ -//#region > Imports -//> Error Serialization -// Serialize/deserialize an error into a plain object -import { serializeError } from "serialize-error"; -//#endregion - -//#region > Constant Variables -const INIT_STATE = { - loggedUser: { anonymous: true }, - authError: null, - authErrorDetails: null, -}; -//#endregion - -//#region > Reducers -const authReducer = (state = INIT_STATE, action) => { - switch (action.type) { - //> LOGIN - case "LOGIN_SUCCESS": - return { - ...state, - loggedUser: { ...action.payload, anonymous: false }, - authErrorDetails: null, - }; - - case "LOGIN_ANON_SUCCESS": - return { - ...state, - loggedUser: undefined, - loggedUser: { anonymous: true }, - authErrorDetails: null, - }; - - case "LOGIN_FAILED" || "LOGIN_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> LOGOUT - case "LOGOUT_SUCCESS": - return INIT_STATE; - - case "LOGOUT_FAILED" || "LOGIN_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - default: - return state; - } -}; -//#endregion - -//#region > Exports -//> Default Component -export default authReducer; -//#endregion - -/** - * SPDX-License-Identifier: (EUPL-1.2) - * Copyright © 2019-2020 Simon Prast - */ diff --git a/src/store/reducers/generalReducers.js b/src/store/reducers/generalReducers.js deleted file mode 100644 index 081e33d..0000000 --- a/src/store/reducers/generalReducers.js +++ /dev/null @@ -1,89 +0,0 @@ -//#region > Imports -//> Error Serialization -// Serialize/deserialize an error into a plain object -import { serializeError } from "serialize-error"; -//#endregion - -//#region > Constant Variables -const INIT_STATE = { - allUserSearchItems: null, - allGitlabServers: [], - generatedIntelData: null, - generalError: null, - generalErrorDetails: null, -}; -//#endregion - -//#region > Reducers -const generalReducer = (state = INIT_STATE, action) => { - switch (action.type) { - //> appendSourceObjectsAction - case "APPEND_SOURCE_OBJECTS_SUCCESS": - return { - ...state, - }; - - case "APPEND_SOURCE_OBJECTS_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> fetchGitLabServersAction - case "FETCH_GITLAB_SERVER_SUCCESS": - return { - ...state, - allGitlabServers: action.payload.gitLabServers, - }; - - case "FETCH_GITLAB_SERVER_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> getDataAction - case "GET_DATA_SUCCESS": - return { - ...state, - generatedIntelData: action.payload, - }; - - case "GET_DATA_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> getUserSearchItems - case "GET_APP_PAGE_URLS_SUCCESS": - return { - ...state, - allUserSearchItems: action.payload.items, - }; - - case "GET_APP_PAGE_URLS_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - default: - return state; - } -}; -//#endregion - -//#region > Exports -//> Default Component -export default generalReducer; -//#endregion - -/** - * SPDX-License-Identifier: (EUPL-1.2) - * Copyright © 2019-2020 Simon Prast - */ diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js index d2dd520..91c0430 100644 --- a/src/store/reducers/index.js +++ b/src/store/reducers/index.js @@ -7,10 +7,6 @@ import { combineReducers } from "redux"; import { loadingBarReducer } from "react-redux-loading-bar"; //> Reducers -// Authentication -import authReducer from "./authReducers"; -// General -import generalReducer from "./generalReducers"; // User import userReducer from "./userReducers"; //#endregion @@ -19,10 +15,6 @@ import userReducer from "./userReducers"; const rootReducer = combineReducers({ // Loading bar loadingBar: loadingBarReducer, - // User authentication - auth: authReducer, - // General data - general: generalReducer, // User data user: userReducer, }); diff --git a/src/store/reducers/userReducers.js b/src/store/reducers/userReducers.js index e1c164a..ddaf49b 100644 --- a/src/store/reducers/userReducers.js +++ b/src/store/reducers/userReducers.js @@ -2,151 +2,74 @@ //> Error Serialization // Serialize/deserialize an error into a plain object import { serializeError } from "serialize-error"; +//> Action Types +import * as Action from "../types"; //#endregion //#region > Constant Variables const INIT_STATE = { - fetchedUser: null, - loggedUser: null, - registrationHistory: null, - selectedTalk: null, - newCachedUser: null, - cachingDone: false, - userError: null, - userErrorDetails: null, + user: { anonymous: undefined, username: undefined, person: undefined }, + error: undefined, + errorDetails: undefined, }; //#endregion -//#region > User Reducers +//#region > Reducers const userReducer = (state = INIT_STATE, action) => { switch (action.type) { - //> registerAction - case "SIGNUP_SUCCESS": - return { - ...state, - registrationHistory: { ...action.payload }, - }; - - case "SIGNUP_FAILED" || "SIGNUP_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> writeCacheAction - case "WRITE_CACHE_SUCCESS": - return { - ...state, - }; - - case "WRITE_CACHE_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> readCacheAction - case "READ_CACHE_SUCCESS": - return { - ...state, - fetchedUser: { ...action.payload.fetchedUser }, - }; - - case "READ_CACHE_FAILED" || "READ_CACHE_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> updateCacheAction - case "UPDATE_CACHE_SUCCESS": - return { - ...state, - newCachedUser: { ...action.payload.fetchedUser }, - cachingDone: true, - }; - - case "UPDATE_CACHE_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> saveSettingsActions - case "SAVE_SETTING_SUCCESS": - return { - ...state, - fetchedUser: { ...action.payload.fetchedUser }, - }; - - case "SAVE_SETTING_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> getTalkAction - case "GET_TALK_SUCCESS": - return { - ...state, - selectedTalk: { ...action.payload.talk }, - }; - - case "GET_TALK_FAILED" || "GET_TALK_ERROR": - return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), - }; - - //> uploadTalkAction - case "UPLOAD_TALK_SUCCESS": - return { - ...state, - fetchedUser: { ...action.payload.fetchedUser }, - }; - - case "UPLOAD_TALK_ERROR": + //> Login + case Action.USER_LOGIN_REQUEST: + return state; + case Action.USER_LOGIN_SUCCESS: return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), + user: { + ...action.payload, + person: null, + }, }; - - //> deleteTalkAction - case "DELETING_TALK_SUCCESS": + case Action.USER_LOGIN_FAILURE: return { - ...state, - fetchedUser: { ...action.payload.fetchedUser }, + user: INIT_STATE.user, + error: action.payload, + errorDetails: serializeError(action.payload.error), }; - - case "DELETING_TALK_ERROR": + //> Logout + case Action.USER_LOGOUT_REQUEST: + return state; + case Action.USER_LOGIN_SUCCESS: + return INIT_STATE; + case Action.USER_LOGOUT_FAILURE: return { - ...state, - authError: action.payload, - authErrorDetails: serializeError(action.payload.error), + user: INIT_STATE.user, + error: action.payload, + errorDetails: serializeError(action.payload.error), }; - - /** Temporary implementation */ - //> loggedUser - case "SET_LOGGED_USER": + //> Person + case Action.USER_PERSON_GET_REQUEST: + return state; + case Action.USER_PERSON_GET_SUCCESS: return { ...state, - loggedUser: action.payload.fetchedUser, + user: { + ...state.user, + person: { + ...action.payload, + }, + }, }; - - case "REMOVE_LOGGED_USER": + case Action.USER_PERSON_GET_FAILURE: return { ...state, - loggedUser: null, + user: { + ...state.user, + person: { + ...INIT_STATE.user.person, + }, + }, + error: action.payload, + errorDetails: serializeError(action.payload.error), }; - //> Default default: return state; } @@ -154,11 +77,5 @@ const userReducer = (state = INIT_STATE, action) => { //#endregion //#region > Exports -//> Default Component export default userReducer; //#endregion - -/** - * SPDX-License-Identifier: (EUPL-1.2) - * Copyright © 2019-2020 Simon Prast - */ diff --git a/src/store/types.js b/src/store/types.js new file mode 100644 index 0000000..5841504 --- /dev/null +++ b/src/store/types.js @@ -0,0 +1,11 @@ +export const USER_LOGIN_REQUEST = "USER_LOGIN_REQUEST"; +export const USER_LOGIN_FAILURE = "USER_LOGIN_FAILURE"; +export const USER_LOGIN_SUCCESS = "USER_LOGIN_SUCCESS"; + +export const USER_LOGOUT_REQUEST = "USER_LOGOUT_REQUEST"; +export const USER_LOGOUT_FAILURE = "USER_LOGOUT_FAILURE"; +export const USER_LOGOUT_SUCCESS = "USER_LOGOUT_SUCCESS"; + +export const USER_PERSON_GET_REQUEST = "USER_GET_PERSONS_REQUEST"; +export const USER_PERSON_GET_FAILURE = "USER_PERSON_GET_FAILURE"; +export const USER_PERSON_GET_SUCCESS = "USER_PERSON_GET_SUCCESS"; From 152b01c25588b1fdeefe90dbd1e8edbe309da4dd Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 18:24:51 +0200 Subject: [PATCH 005/175] Adjust components to work with new user actions LoginForm and HomePage have been adjusted to work with the new user actions and state definition. --- src/components/molecules/forms/LoginForm/index.jsx | 2 +- src/components/pages/HomePage/index.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/molecules/forms/LoginForm/index.jsx b/src/components/molecules/forms/LoginForm/index.jsx index 07dcfab..4587077 100644 --- a/src/components/molecules/forms/LoginForm/index.jsx +++ b/src/components/molecules/forms/LoginForm/index.jsx @@ -17,7 +17,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { loginAction } from "../../../../store/actions/authActions"; +import { loginAction } from "../../../../store/actions/userActions"; //#endregion //#region > Components diff --git a/src/components/pages/HomePage/index.jsx b/src/components/pages/HomePage/index.jsx index 4c68119..4263505 100644 --- a/src/components/pages/HomePage/index.jsx +++ b/src/components/pages/HomePage/index.jsx @@ -106,7 +106,7 @@ class HomePage extends React.Component { const { loggedUser } = this.props; const activeActionCard = this.props.location?.state?.actionCard; - if (!loggedUser.anonymous) { + if (loggedUser.anonymous == false) { return ; } else { return ( @@ -308,7 +308,7 @@ class HomePage extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + loggedUser: state.user.user, }); const mapDispatchToProps = (dispatch) => { From 6056351601e2f15e1d9345a561973bd5fafa4803 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 20:03:15 +0200 Subject: [PATCH 006/175] Comment out a bit Code was commented out to avoid errors caused by deleting the actions. --- src/App.js | 4 ++-- src/Routes.js | 14 +++++++------- src/components/molecules/Navbar/index.jsx | 2 +- .../molecules/forms/RegisterForm/index.jsx | 12 ++++++------ .../molecules/modals/TalkUploadModal/index.jsx | 4 ++-- .../organisms/tabs/OverviewTab/index.jsx | 4 ++-- src/components/organisms/tabs/TalksTab/index.jsx | 4 ++-- src/components/pages/ProfilePage/index.jsx | 16 ++++++++-------- src/components/pages/SettingsPage/index.jsx | 12 ++++++------ src/components/pages/TalkPage/index.jsx | 4 ++-- 10 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/App.js b/src/App.js index bb0f031..56879af 100644 --- a/src/App.js +++ b/src/App.js @@ -13,7 +13,7 @@ import LoadingBarContainer from "react-redux-loading-bar"; //> Actions // Functions to send data from the application to the store -import { loginAction } from "./store/actions/authActions"; +import { loginAction } from "./store/actions/userActions"; //> Components import { Footer, Navbar } from "./components/molecules"; // Starts the page on top when reloaded or redirected @@ -40,7 +40,7 @@ function App() {
- + {/* */}
diff --git a/src/Routes.js b/src/Routes.js index d981784..4762d9e 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -8,11 +8,11 @@ import { Route, Switch } from "react-router-dom"; //> Components import { HomePage, - ProfilePage, - CompanyPage, - TalkPage, - SettingsPage, - TempPage, + // ProfilePage, + // CompanyPage, + // TalkPage, + // SettingsPage, + // TempPage, } from "./components/pages"; //#endregion @@ -23,7 +23,7 @@ class Routes extends React.Component { return ( } /> - } @@ -57,7 +57,7 @@ class Routes extends React.Component { exact path="/settings" component={(props) => } - /> + /> */} Not Found; diff --git a/src/components/molecules/Navbar/index.jsx b/src/components/molecules/Navbar/index.jsx index 9fd2ef1..0492413 100644 --- a/src/components/molecules/Navbar/index.jsx +++ b/src/components/molecules/Navbar/index.jsx @@ -186,7 +186,7 @@ Navbar.propTypes = { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: { ...state.auth.loggedUser, ...state.user.loggedUser }, + loggedUser: { ...state.user.user }, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/components/molecules/forms/RegisterForm/index.jsx b/src/components/molecules/forms/RegisterForm/index.jsx index de06ae2..caebd6e 100644 --- a/src/components/molecules/forms/RegisterForm/index.jsx +++ b/src/components/molecules/forms/RegisterForm/index.jsx @@ -38,9 +38,9 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { registerAction } from "../../../../store/actions/userActions"; -import { fetchGitLabServersAction } from "../../../../store/actions/generalActions"; -import { loginAction } from "../../../../store/actions/authActions"; +// import { registerAction } from "../../../../store/actions/userActions"; +// import { fetchGitLabServersAction } from "../../../../store/actions/generalActions"; +// import { loginAction } from "../../../../store/actions/authActions"; //#endregion //#region > Components @@ -280,9 +280,9 @@ const mapStateToProps = (state) => ({ const mapDispatchToProps = (dispatch) => { return { - register: (registrationData) => dispatch(registerAction(registrationData)), - login: (user) => dispatch(loginAction(user)), - fetchGitLabServers: () => dispatch(fetchGitLabServersAction()), + register: (registrationData) => dispatch((registrationData)), + login: (user) => dispatch((user)), + fetchGitLabServers: () => dispatch(), }; }; //#endregion diff --git a/src/components/molecules/modals/TalkUploadModal/index.jsx b/src/components/molecules/modals/TalkUploadModal/index.jsx index 59b3638..6b5a238 100644 --- a/src/components/molecules/modals/TalkUploadModal/index.jsx +++ b/src/components/molecules/modals/TalkUploadModal/index.jsx @@ -20,7 +20,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { uploadTalkAction } from "../../../../store/actions/userActions"; +// import { uploadTalkAction } from "../../../../store/actions/userActions"; //#endregion //#region > Components @@ -160,7 +160,7 @@ const mapStateToProps = (state) => ({ }); const mapDispatchToProps = (dispatch) => { - return { uploadTalk: (file) => dispatch(uploadTalkAction(file)) }; + return { uploadTalk: (file) => dispatch(file) }; }; //#endregion diff --git a/src/components/organisms/tabs/OverviewTab/index.jsx b/src/components/organisms/tabs/OverviewTab/index.jsx index 4fa4188..c4ce56d 100644 --- a/src/components/organisms/tabs/OverviewTab/index.jsx +++ b/src/components/organisms/tabs/OverviewTab/index.jsx @@ -14,7 +14,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { writeCacheAction } from "../../../../store/actions/userActions"; +// import { writeCacheAction } from "../../../../store/actions/userActions"; //> Style sheet import "./overviewtab.scss"; //> Components @@ -281,7 +281,7 @@ const mapStateToProps = (state) => ({ const mapDispatchToProps = (dispatch) => { return { - writeCache: (platformData) => dispatch(writeCacheAction(platformData)), + writeCache: (platformData) => dispatch(platformData), }; }; //#endregion diff --git a/src/components/organisms/tabs/TalksTab/index.jsx b/src/components/organisms/tabs/TalksTab/index.jsx index 597b599..7098cfa 100644 --- a/src/components/organisms/tabs/TalksTab/index.jsx +++ b/src/components/organisms/tabs/TalksTab/index.jsx @@ -23,7 +23,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { deleteTalkAction } from "../../../../store/actions/userActions"; +// import { deleteTalkAction } from "../../../../store/actions/userActions"; //> Style sheet import "./talkstab.scss"; //> Modules @@ -220,7 +220,7 @@ const mapStateToProps = (state) => ({ }); const mapDispatchToProps = (dispatch) => { - return { deleteTalk: (talk) => dispatch(deleteTalkAction(talk)) }; + return { deleteTalk: (talk) => dispatch(talk) }; }; //#endregion diff --git a/src/components/pages/ProfilePage/index.jsx b/src/components/pages/ProfilePage/index.jsx index ccacb82..ebfc5da 100644 --- a/src/components/pages/ProfilePage/index.jsx +++ b/src/components/pages/ProfilePage/index.jsx @@ -11,11 +11,11 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { - readCacheAction, - updateCacheAction, - saveSettingsActions, -} from "../../../store/actions/userActions"; +// import { +// readCacheAction, +// updateCacheAction, +// saveSettingsActions, +// } from "../../../store/actions/userActions"; //> Components import { SoftwareEngineer } from "../../organisms/profiles"; //> Style sheet @@ -138,9 +138,9 @@ const mapStateToProps = (state) => ({ const mapDispatchToProps = (dispatch) => { return { - saveSettings: (nextSettings) => dispatch(saveSettingsActions(nextSettings)), - readCache: (username) => dispatch(readCacheAction(username)), - updateCache: (fetchedUser) => dispatch(updateCacheAction(fetchedUser)), + saveSettings: (nextSettings) => dispatch(nextSettings), + readCache: (username) => dispatch(username), + updateCache: (fetchedUser) => dispatch(fetchedUser), }; }; //#endregion diff --git a/src/components/pages/SettingsPage/index.jsx b/src/components/pages/SettingsPage/index.jsx index 8569662..e830a27 100644 --- a/src/components/pages/SettingsPage/index.jsx +++ b/src/components/pages/SettingsPage/index.jsx @@ -35,10 +35,10 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { - readCacheAction, - saveSettingsActions, -} from "../../../store/actions/userActions"; +// import { +// readCacheAction, +// saveSettingsActions, +// } from "../../../store/actions/userActions"; //> Components // Profile Picture Editor import { ProfilePictureModal } from "../../../components/molecules/modals"; @@ -574,8 +574,8 @@ const mapStateToProps = (state) => ({ const mapDispatchToProps = (dispatch) => { return { - saveSettings: (nextSettings) => dispatch(saveSettingsActions(nextSettings)), - readCache: (username) => dispatch(readCacheAction(username)), + saveSettings: (nextSettings) => dispatch(nextSettings), + readCache: (username) => dispatch(username), }; }; //#endregion diff --git a/src/components/pages/TalkPage/index.jsx b/src/components/pages/TalkPage/index.jsx index dc4bb90..62392fb 100644 --- a/src/components/pages/TalkPage/index.jsx +++ b/src/components/pages/TalkPage/index.jsx @@ -27,7 +27,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { getTalkAction } from "../../../store/actions/userActions"; +// import { getTalkAction } from "../../../store/actions/userActions"; //> Style sheet import "./talk.scss"; //#endregion @@ -383,7 +383,7 @@ const mapStateToProps = (state) => ({ }); const mapDispatchToProps = (dispatch) => { - return { getTalk: (uid, username) => dispatch(getTalkAction(uid, username)) }; + return { getTalk: (uid, username) => dispatch((uid, username)) }; }; //#endregion From d6f8612e13f54a6739188020495679e904586042 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 20:17:19 +0200 Subject: [PATCH 007/175] Add person get action Now it is possible to fetch persons which get stored in the store as fetchedPerson. --- src/store/actions/personActions.js | 34 ++++++++++++++++++++++ src/store/reducers/index.js | 4 +++ src/store/reducers/personReducer.js | 44 +++++++++++++++++++++++++++++ src/store/types.js | 4 +++ 4 files changed, 86 insertions(+) create mode 100644 src/store/reducers/personReducer.js diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index e69de29..51742be 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -0,0 +1,34 @@ +//#region > Imports +//> Action Types +import * as Action from "../types"; +//> Intel +import INTEL_SNEK from "snek-intel/lib/utils/snek"; +//#endregion + +//#region > Person Actions +/** + * Get person page for a logged user + */ +const getPerson = (personName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.USER_PERSON_GET_REQUEST }); + + const person = await INTEL_SNEK.person.get({ personName }); + + dispatch({ type: Action.USER_PERSON_GET_SUCCESS, payload: person }); + } catch (ex) { + dispatch({ + type: Action.USER_PERSON_GET_FAILURE, + payload: { + errorCode: 601, + message: `Getting person (${personName}) failed`, + error: ex, + }, + }); + } + }; +}; +//#endregion + +export { getPerson }; diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js index 91c0430..9a0aa63 100644 --- a/src/store/reducers/index.js +++ b/src/store/reducers/index.js @@ -9,6 +9,8 @@ import { loadingBarReducer } from "react-redux-loading-bar"; //> Reducers // User import userReducer from "./userReducers"; +// Person +import personReducer from "./personReducer"; //#endregion //#region > Config @@ -17,6 +19,8 @@ const rootReducer = combineReducers({ loadingBar: loadingBarReducer, // User data user: userReducer, + // Person data + person: personReducer, }); //#endregion diff --git a/src/store/reducers/personReducer.js b/src/store/reducers/personReducer.js new file mode 100644 index 0000000..5648989 --- /dev/null +++ b/src/store/reducers/personReducer.js @@ -0,0 +1,44 @@ +//#region > Imports +//> Error Serialization +// Serialize/deserialize an error into a plain object +import { serializeError } from "serialize-error"; +//> Action Types +import * as Action from "../types"; +//#endregion + +//#region > Constant Variables +const INIT_STATE = { + fetchedPerson: undefined, + error: undefined, + errorDetails: undefined, +}; +//#endregion + +//#region > Reducers +const userReducer = (state = INIT_STATE, action) => { + switch (action.type) { + //> Get + case Action.PERSON_GET_REQUEST: + return state; + case Action.PERSON_GET_SUCCESS: + return { + fetchedPerson: { + ...action.payload, + }, + }; + case Action.PERSON_GET_FAILURE: + return { + fetchedPerson: undefined, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + + default: + return state; + } +}; +//#endregion + +//#region > Exports +export default userReducer; +//#endregion diff --git a/src/store/types.js b/src/store/types.js index 5841504..20188b7 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -9,3 +9,7 @@ export const USER_LOGOUT_SUCCESS = "USER_LOGOUT_SUCCESS"; export const USER_PERSON_GET_REQUEST = "USER_GET_PERSONS_REQUEST"; export const USER_PERSON_GET_FAILURE = "USER_PERSON_GET_FAILURE"; export const USER_PERSON_GET_SUCCESS = "USER_PERSON_GET_SUCCESS"; + +export const PERSON_GET_REQUEST = "PERSON_GET_REQUEST"; +export const PERSON_GET_FAILURE = "PERSON_GET_FAILURE"; +export const PERSON_GET_SUCCESS = "PERSON_GET_SUCCESS"; From 794b9f02dabd15976fd25e20bf7fb3db45861e73 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 20:37:51 +0200 Subject: [PATCH 008/175] Rename import path for logout action The logout action has been imported from another location. --- src/components/molecules/Navbar/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/molecules/Navbar/index.jsx b/src/components/molecules/Navbar/index.jsx index 0492413..98588b0 100644 --- a/src/components/molecules/Navbar/index.jsx +++ b/src/components/molecules/Navbar/index.jsx @@ -30,7 +30,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { logoutAction } from "../../../store/actions/authActions"; +import { logoutAction } from "../../../store/actions/userActions"; //> SearchBar import { SearchBar } from "../../atoms"; //> Images From 31a08a6ab8ed14c2327587c61e9cdb1b34cdaa64 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 20:44:11 +0200 Subject: [PATCH 009/175] Update profile page Cleanup and person action integration --- src/components/pages/ProfilePage/index.jsx | 67 +++------------------- 1 file changed, 7 insertions(+), 60 deletions(-) diff --git a/src/components/pages/ProfilePage/index.jsx b/src/components/pages/ProfilePage/index.jsx index ebfc5da..2c7a1a8 100644 --- a/src/components/pages/ProfilePage/index.jsx +++ b/src/components/pages/ProfilePage/index.jsx @@ -11,11 +11,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -// import { -// readCacheAction, -// updateCacheAction, -// saveSettingsActions, -// } from "../../../store/actions/userActions"; +import { getPerson } from "../../../store/actions/personActions"; //> Components import { SoftwareEngineer } from "../../organisms/profiles"; //> Style sheet @@ -35,63 +31,17 @@ class ProfilePage extends React.Component { this.props.saveSettings(state); }; - /** - * Check for refetch for a specific username. - * - * @param {string} username The username associated with a profile page - * @returns {boolean} True if a refetch is required otherwise False - */ - refetchRequired = (username) => { - const fetchedUser = this.props.fetchedUser; - - if (!fetchedUser) { - return true; - } else if (fetchedUser && !this.usernameMatchesFetchedUsername(username)) { - return true; - } - - return false; - }; - - /** - * Check if the provided username matches with the current fetched user. - * - * @param {string} username The username associated with a profile page - * @returns {boolean} True if the usernames matches otherwise False - */ - usernameMatchesFetchedUsername = (username) => { - return username === this.props.fetchedUser?.username; - }; - componentDidMount = () => { this._isMounted = true; - - const { match, loggedUser, fetchedUser } = this.props; + const { match } = this.props; const username = match?.params?.username; if (username) { - if (this.refetchRequired(username)) { - this.props.readCache(username); - } + this.props.getPerson(username); } }; - componentDidUpdate() { - const { loggedUser, fetchedUser } = this.props; - - if (!this.props.cachingDone) { - if ( - !loggedUser.anonymous && - loggedUser.username === fetchedUser?.username - ) { - this.props.updateCache(fetchedUser).then(() => { - if (this._isMounted) { - this.props.readCache(loggedUser.username); - } - }); - } - } - } + componentDidUpdate() {} componentWillUnmount() { this._isMounted = false; @@ -131,16 +81,13 @@ class ProfilePage extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, - fetchedUser: state.user.fetchedUser, - cachingDone: state.user.cachingDone, + loggedUser: state.user.user, + fetchedPerson: state.person.fetchedPerson, }); const mapDispatchToProps = (dispatch) => { return { - saveSettings: (nextSettings) => dispatch(nextSettings), - readCache: (username) => dispatch(username), - updateCache: (fetchedUser) => dispatch(fetchedUser), + getPerson: (personName) => dispatch(getPerson(personName)), }; }; //#endregion From f49cfa4237e83504c866e7303968f2a62146350c Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 20:44:49 +0200 Subject: [PATCH 010/175] Fix wrong dispatches in person action Incorrect dispatches in the person action have been fixed. --- src/store/actions/personActions.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index 51742be..5faa49b 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -12,14 +12,14 @@ import INTEL_SNEK from "snek-intel/lib/utils/snek"; const getPerson = (personName) => { return async (dispatch, getState, {}) => { try { - dispatch({ type: Action.USER_PERSON_GET_REQUEST }); + dispatch({ type: Action.PERSON_GET_REQUEST }); const person = await INTEL_SNEK.person.get({ personName }); - dispatch({ type: Action.USER_PERSON_GET_SUCCESS, payload: person }); + dispatch({ type: Action.PERSON_GET_SUCCESS, payload: person }); } catch (ex) { dispatch({ - type: Action.USER_PERSON_GET_FAILURE, + type: Action.PERSON_GET_FAILURE, payload: { errorCode: 601, message: `Getting person (${personName}) failed`, From 6b6eb5c3c98bf422520938983d6ab5838dba9548 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Mon, 7 Sep 2020 20:52:44 +0200 Subject: [PATCH 011/175] Fix modals Some non existent action has been removed. --- src/components/molecules/modals/AddSongModal/index.jsx | 2 +- src/components/molecules/modals/AddVideoModal/index.jsx | 2 +- src/components/molecules/modals/ImageModal/index.jsx | 4 ++-- .../molecules/modals/InstagramSelectorModal/index.jsx | 2 +- src/components/molecules/modals/VideoModal/index.jsx | 4 ++-- src/components/organisms/sections/media/AIGallery/index.jsx | 2 +- .../organisms/sections/media/AISongGallery/index.jsx | 2 +- .../organisms/sections/media/AIVideoGallery/index.jsx | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/molecules/modals/AddSongModal/index.jsx b/src/components/molecules/modals/AddSongModal/index.jsx index 8e4a33d..28adf45 100644 --- a/src/components/molecules/modals/AddSongModal/index.jsx +++ b/src/components/molecules/modals/AddSongModal/index.jsx @@ -120,7 +120,7 @@ class AddSongModal extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + //loggedUser: state.auth.loggedUser, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/components/molecules/modals/AddVideoModal/index.jsx b/src/components/molecules/modals/AddVideoModal/index.jsx index 125b24b..9f1cd3e 100644 --- a/src/components/molecules/modals/AddVideoModal/index.jsx +++ b/src/components/molecules/modals/AddVideoModal/index.jsx @@ -134,7 +134,7 @@ class AddVideoModal extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + //loggedUser: state.auth.loggedUser, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/components/molecules/modals/ImageModal/index.jsx b/src/components/molecules/modals/ImageModal/index.jsx index 4a84be0..8de2c59 100644 --- a/src/components/molecules/modals/ImageModal/index.jsx +++ b/src/components/molecules/modals/ImageModal/index.jsx @@ -83,11 +83,11 @@ class ImageModal extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + //loggedUser: state.auth.loggedUser, }); const mapDispatchToProps = (dispatch) => { - return null; + return {}; }; //#endregion diff --git a/src/components/molecules/modals/InstagramSelectorModal/index.jsx b/src/components/molecules/modals/InstagramSelectorModal/index.jsx index b014e8f..3e6c096 100644 --- a/src/components/molecules/modals/InstagramSelectorModal/index.jsx +++ b/src/components/molecules/modals/InstagramSelectorModal/index.jsx @@ -115,7 +115,7 @@ class InstagramSelectorModal extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + //loggedUser: state.auth.loggedUser, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/components/molecules/modals/VideoModal/index.jsx b/src/components/molecules/modals/VideoModal/index.jsx index c3a649c..752a62d 100644 --- a/src/components/molecules/modals/VideoModal/index.jsx +++ b/src/components/molecules/modals/VideoModal/index.jsx @@ -59,11 +59,11 @@ class VideoModal extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + //loggedUser: state.auth.loggedUser, }); const mapDispatchToProps = (dispatch) => { - return null; + return {}; }; //#endregion diff --git a/src/components/organisms/sections/media/AIGallery/index.jsx b/src/components/organisms/sections/media/AIGallery/index.jsx index 50c287d..82aca79 100644 --- a/src/components/organisms/sections/media/AIGallery/index.jsx +++ b/src/components/organisms/sections/media/AIGallery/index.jsx @@ -158,7 +158,7 @@ class AIGallery extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + //loggedUser: state.auth.loggedUser, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/components/organisms/sections/media/AISongGallery/index.jsx b/src/components/organisms/sections/media/AISongGallery/index.jsx index be77665..24b5779 100644 --- a/src/components/organisms/sections/media/AISongGallery/index.jsx +++ b/src/components/organisms/sections/media/AISongGallery/index.jsx @@ -120,7 +120,7 @@ class AISongGallery extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + //loggedUser: state.auth.loggedUser, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/components/organisms/sections/media/AIVideoGallery/index.jsx b/src/components/organisms/sections/media/AIVideoGallery/index.jsx index dd24ea7..7733519 100644 --- a/src/components/organisms/sections/media/AIVideoGallery/index.jsx +++ b/src/components/organisms/sections/media/AIVideoGallery/index.jsx @@ -168,7 +168,7 @@ class AIVideoGallery extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, + //loggedUser: state.auth.loggedUser, }); const mapDispatchToProps = (dispatch) => { From 953de6a1248792e3fac69720a5f031fe4e3b43b4 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Mon, 7 Sep 2020 21:12:57 +0200 Subject: [PATCH 012/175] Add ConnectModal The modal to connect other accounts has been added. --- src/Routes.js | 18 +- .../molecules/modals/ConnectModal/index.jsx | 192 ++++++++++++++++++ src/components/molecules/modals/index.js | 2 + src/components/pages/TempPage/index.jsx | 29 ++- 4 files changed, 215 insertions(+), 26 deletions(-) create mode 100644 src/components/molecules/modals/ConnectModal/index.jsx diff --git a/src/Routes.js b/src/Routes.js index 4762d9e..fbea44b 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -8,11 +8,11 @@ import { Route, Switch } from "react-router-dom"; //> Components import { HomePage, - // ProfilePage, - // CompanyPage, + ProfilePage, + CompanyPage, // TalkPage, // SettingsPage, - // TempPage, + TempPage, } from "./components/pages"; //#endregion @@ -23,7 +23,7 @@ class Routes extends React.Component { return ( } /> - {/* } @@ -33,16 +33,16 @@ class Routes extends React.Component { path="/c/:name" component={(props) => } /> - } - /> } /> + {/* } + /> Imports +//> React +// Contains all the functionality necessary to define React components +import React from "react"; +//> Time management +import moment from "moment"; +//> Redux +// Allows React components to read data, update data and dispatch actions +// from/to a Redux store. +import { connect } from "react-redux"; +//> MDB +// "Material Design for Bootstrap" is a great UI design framework +import { + MDBBtn, + MDBModal, + MDBModalBody, + MDBIcon, + MDBFormInline, + MDBRow, + MDBCol, + MDBModalFooter, + MDBModalHeader, + MDBSelect, + MDBSelectInput, + MDBSelectOption, + MDBSelectOptions, +} from "mdbreact"; +//#endregion + +//#region > Components +class ConnectModal extends React.Component { + state = { youtubeLink: "", modalGitLab: false }; + + toggle = () => { + this.setState({ modalGitLab: !this.state.modalGitLab }); + }; + + render() { + const { selectedVideoId } = this.props; + + return ( + <> + + +
+

Connect your profiles

+ + Done + +
+
+ + + + + Connect GitHub + + + + Connect GitLab + + + + Connect Instagram + + + +
+ {this.state.youtubeId && ( +
+ +
+ )} +
+
+ {this.state.modalGitLab && ( + + + + Add GitLab profile + + + + this.setState({ [e.target.name]: e.target.value }) + } + value={this.state.gitlab_username} + /> + + + + + Choose your organisation + + {this.state.gitlab_servers && + this.state.gitlab_servers.map((source, i) => { + return ( + + {source.organisation} + + ); + })} + + + + + + + Add + + + Cancel + + + + )} + + ); + } +} +//#endregion + +//#region > Redux Mapping +const mapStateToProps = (state) => ({ + //loggedUser: state.auth.loggedUser, +}); + +const mapDispatchToProps = (dispatch) => { + return {}; +}; +//#endregion + +//#region > Exports +/** + * Provides its connected component with the pieces of the data it needs from + * the store, and the functions it can use to dispatch actions to the store. + * + * Got access to the history object’s properties and the closest + * 's match. + */ +export default connect(mapStateToProps, mapDispatchToProps)(ConnectModal); +//#endregion + +/** + * SPDX-License-Identifier: (EUPL-1.2) + * Copyright © 2019-2020 Simon Prast + */ diff --git a/src/components/molecules/modals/index.js b/src/components/molecules/modals/index.js index 5de1d91..5305d5d 100644 --- a/src/components/molecules/modals/index.js +++ b/src/components/molecules/modals/index.js @@ -8,6 +8,7 @@ import VideoModal from "./VideoModal"; import AddVideoModal from "./AddVideoModal"; import InstagramSelectorModal from "./InstagramSelectorModal"; import AddSongModal from "./AddSongModal"; +import ConnectModal from "./ConnectModal"; //#endregion //#region > Exports @@ -21,6 +22,7 @@ export { AddVideoModal, InstagramSelectorModal, AddSongModal, + ConnectModal, }; //#endregion diff --git a/src/components/pages/TempPage/index.jsx b/src/components/pages/TempPage/index.jsx index c9872fc..052e28d 100644 --- a/src/components/pages/TempPage/index.jsx +++ b/src/components/pages/TempPage/index.jsx @@ -10,7 +10,7 @@ import { withRouter } from "react-router-dom"; import { connect } from "react-redux"; //> MDB // "Material Design for Bootstrap" is a great UI design framework -import { MDBContainer } from "mdbreact"; +import { MDBContainer, MDBBtn } from "mdbreact"; //> Components import { @@ -18,19 +18,26 @@ import { AIVideoGallery, AISongGallery, } from "../../organisms/sections/media"; +import { ConnectModal } from "../../molecules/modals"; //#endregion //#region > Components class TempPage extends React.Component { - state = {}; + state = { connect: true }; componentDidMount = () => {}; - render() { - const { loggedUser } = this.props; + toggleConnect = () => { + this.setState({ + connect: !this.state.connect, + }); + }; + render() { return ( + {this.state.connect && } + @@ -40,16 +47,6 @@ class TempPage extends React.Component { } //#endregion -//#region > Redux Mapping -const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, -}); - -const mapDispatchToProps = (dispatch) => { - return {}; -}; -//#endregion - //#region > Exports /** * Provides its connected component with the pieces of the data it needs from @@ -58,9 +55,7 @@ const mapDispatchToProps = (dispatch) => { * Got access to the history object’s properties and the closest * 's match. */ -export default withRouter( - connect(mapStateToProps, mapDispatchToProps)(TempPage) -); +export default TempPage; //#endregion /** From 24118e2c069103508e676a0b5fafb1a5767d50f6 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Mon, 7 Sep 2020 21:32:25 +0200 Subject: [PATCH 013/175] Improve ConnectModal Some functions have been introduced. --- .../molecules/modals/ConnectModal/index.jsx | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/modals/ConnectModal/index.jsx b/src/components/molecules/modals/ConnectModal/index.jsx index 1cf83cd..d8877f7 100644 --- a/src/components/molecules/modals/ConnectModal/index.jsx +++ b/src/components/molecules/modals/ConnectModal/index.jsx @@ -25,16 +25,49 @@ import { MDBSelectOption, MDBSelectOptions, } from "mdbreact"; + +//> Actions +// Functions to send data from the application to the store +//import { fetchGitLabServersAction } from "../../../../store/actions/generalActions"; //#endregion //#region > Components class ConnectModal extends React.Component { state = { youtubeLink: "", modalGitLab: false }; + componentDidMount = () => { + this.getGitLabServers(); + }; + + getGitLabServers = async () => { + // Check if GitLab Servers have already been set + if (this.state.gitlab_servers === undefined) { + // Retrieve GitLab servers + /*this.props.fetchGitLabServers().then(() => { + this.setState({ + gitlab_servers: this.props.gitlabServers, + }); + });*/ + } + }; + + // Activate or deactivate GitLab modal toggle = () => { this.setState({ modalGitLab: !this.state.modalGitLab }); }; + addGitLab = () => { + // Do stuff + }; + + addGitHub = () => { + // Do stuff + }; + + addInstagram = () => { + // Do stuff + }; + render() { const { selectedVideoId } = this.props; @@ -61,6 +94,7 @@ class ConnectModal extends React.Component { social="git" size="lg" className="d-block mx-auto w-100" + onClick={() => this.addGitHub()} > Connect GitHub @@ -78,6 +112,7 @@ class ConnectModal extends React.Component { social="ins" size="lg" className="d-block mx-auto w-100" + onClick={() => this.addInstagram()} > Connect Instagram @@ -167,11 +202,13 @@ class ConnectModal extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - //loggedUser: state.auth.loggedUser, + //gitlabServers: state.general.allGitlabServers, }); const mapDispatchToProps = (dispatch) => { - return {}; + return { + //fetchGitLabServers: () => dispatch(fetchGitLabServersAction()) + }; }; //#endregion From 5e21ca15869f84211aee5eacdefc969a39515f45 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 21:34:18 +0200 Subject: [PATCH 014/175] Update search functionallity Now it is possible again to search users. --- src/App.js | 2 +- src/components/atoms/SearchBar/index.jsx | 24 ++++++++++---------- src/store/actions/personActions.js | 28 +++++++++++++++++++++++- src/store/reducers/personReducer.js | 18 +++++++++++++++ src/store/types.js | 4 ++++ 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/App.js b/src/App.js index 56879af..3bb75b2 100644 --- a/src/App.js +++ b/src/App.js @@ -40,7 +40,7 @@ function App() {
- {/* */} +
diff --git a/src/components/atoms/SearchBar/index.jsx b/src/components/atoms/SearchBar/index.jsx index 32204fc..bf2f23d 100644 --- a/src/components/atoms/SearchBar/index.jsx +++ b/src/components/atoms/SearchBar/index.jsx @@ -22,7 +22,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { getUserSearchItems } from "../../../store/actions/generalActions"; +import { getPersonsBrief } from "../../../store/actions/personActions"; //> Style sheet import "./search.scss"; //#endregion @@ -52,8 +52,6 @@ class SearchBar extends React.Component { handleSelection = (event, value) => { if (event === "user") { this.props.history.push("/u/" + value); - } else if (event === "search_page") { - this.props.history.push("/search?q=" + value); } }; @@ -84,24 +82,28 @@ class SearchBar extends React.Component { {!this.state.loading && this.state.searchItems ? ( - this.state.searchItems.length > 0 && this.state.filter.length > 0 ? ( - + this.state.searchItems.length > 0 && + this.state.filter.length > 0 ? ( fuzzysort .go(this.state.filter, this.state.searchItems, { key: "title" }) .map((element, i) => { return ( - {element.target} + {element.obj.slug.split("-")[1]} ); }) ) : null ) : ( - Loading - )} + Loading + )} ); @@ -111,12 +113,12 @@ class SearchBar extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - allUserSearchItems: state.general.allUserSearchItems, + allUserSearchItems: state.person.allPersonBrief, }); const mapDispatchToProps = (dispatch) => { return { - allsearchItems: () => dispatch(getUserSearchItems()), + allsearchItems: () => dispatch(getPersonsBrief()), }; }; //#endregion diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index 5faa49b..4ed260d 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -29,6 +29,32 @@ const getPerson = (personName) => { } }; }; + +/** + * Get all person in a brief form + */ +const getPersonsBrief = () => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSONS_BRIEF_GET_REQUEST }); + + const persons = await INTEL_SNEK.person.allBrief(); + + console.log(persons); + + dispatch({ type: Action.PERSONS_BRIEF_GET_SUCCESS, payload: persons }); + } catch (ex) { + dispatch({ + type: Action.PERSONS_BRIEF_GET_FAILURE, + payload: { + errorCode: 601, + message: "Getting all person in a brief form failed", + error: ex, + }, + }); + } + }; +}; //#endregion -export { getPerson }; +export { getPerson, getPersonsBrief }; diff --git a/src/store/reducers/personReducer.js b/src/store/reducers/personReducer.js index 5648989..b3e930c 100644 --- a/src/store/reducers/personReducer.js +++ b/src/store/reducers/personReducer.js @@ -9,6 +9,7 @@ import * as Action from "../types"; //#region > Constant Variables const INIT_STATE = { fetchedPerson: undefined, + allPersonBrief: undefined, error: undefined, errorDetails: undefined, }; @@ -22,16 +23,33 @@ const userReducer = (state = INIT_STATE, action) => { return state; case Action.PERSON_GET_SUCCESS: return { + ...state, fetchedPerson: { ...action.payload, }, }; case Action.PERSON_GET_FAILURE: return { + ...state, fetchedPerson: undefined, error: action.payload, errorDetails: serializeError(action.payload.error), }; + //> Get all brief + case Action.PERSONS_BRIEF_GET_REQUEST: + return state; + case Action.PERSONS_BRIEF_GET_SUCCESS: + return { + ...state, + allPersonBrief: action.payload, + }; + case Action.PERSONS_BRIEF_GET_FAILURE: + return { + ...state, + allPersonBrief: undefined, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; default: return state; diff --git a/src/store/types.js b/src/store/types.js index 20188b7..b84ad4a 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -13,3 +13,7 @@ export const USER_PERSON_GET_SUCCESS = "USER_PERSON_GET_SUCCESS"; export const PERSON_GET_REQUEST = "PERSON_GET_REQUEST"; export const PERSON_GET_FAILURE = "PERSON_GET_FAILURE"; export const PERSON_GET_SUCCESS = "PERSON_GET_SUCCESS"; + +export const PERSONS_BRIEF_GET_REQUEST = "PERSONS_BRIEF_GET_REQUEST"; +export const PERSONS_BRIEF_GET_FAILURE = "PERSON_BRIEF_GET_FAILURE"; +export const PERSONS_BRIEF_GET_SUCCESS = "PERSON_BRIEF_GET_SUCCESS"; From 76976c1ac95c2f387095f924a32c812b83d0489b Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 21:50:44 +0200 Subject: [PATCH 015/175] Add general reducers A action for getting all gitlab servers for registration has been added. --- src/store/actions/generalActions.js | 38 +++++++++++++++++++++++ src/store/reducers/generalReducers.js | 44 +++++++++++++++++++++++++++ src/store/reducers/index.js | 5 +++ src/store/types.js | 6 ++++ 4 files changed, 93 insertions(+) create mode 100644 src/store/actions/generalActions.js create mode 100644 src/store/reducers/generalReducers.js diff --git a/src/store/actions/generalActions.js b/src/store/actions/generalActions.js new file mode 100644 index 0000000..c8159a8 --- /dev/null +++ b/src/store/actions/generalActions.js @@ -0,0 +1,38 @@ +//#region > Imports +//> Action Types +import * as Action from "../types"; +//> Intel +import INTEL_SNEK from "snek-intel/lib/utils/snek"; +//#endregion + +//#region > Person Actions +/** + * Get all gitlab servers for registration + */ +const getGitlabServers = () => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.GENERAL_GITLAB_SERVER_GET_REQUEST }); + + const servers = await INTEL_SNEK.general.getGitlabServer(); + + dispatch({ + type: Action.GENERAL_GITLAB_SERVER_GET_SUCCESS, + payload: servers, + }); + } catch (ex) { + dispatch({ + type: Action.GENERAL_GITLAB_SERVER_GET_FAILURE, + payload: { + errorCode: 601, + message: `Getting person (${personName}) failed`, + error: ex, + }, + }); + } + }; +}; + +//#endregion + +export { getPerson, getPersonsBrief }; diff --git a/src/store/reducers/generalReducers.js b/src/store/reducers/generalReducers.js new file mode 100644 index 0000000..ecc2333 --- /dev/null +++ b/src/store/reducers/generalReducers.js @@ -0,0 +1,44 @@ +//#region > Imports +//> Error Serialization +// Serialize/deserialize an error into a plain object +import { serializeError } from "serialize-error"; +//> Action Types +import * as Action from "../types"; +//#endregion + +//#region > Constant Variables +const INIT_STATE = { + gitlabServer: undefined, + error: undefined, + errorDetails: undefined, +}; +//#endregion + +//#region > Reducers +const generalReducer = (state = INIT_STATE, action) => { + switch (action.type) { + //> Get all gitlab server + case Action.GENERAL_GITLAB_SERVER_GET_REQUEST: + return state; + case Action.GENERAL_GITLAB_SERVER_GET_FAILURE: + return { + ...state, + gitlabServer: action.payload, + }; + case Action.GENERAL_GITLAB_SERVER_GET_SUCCESS: + return { + ...state, + gitlabServer: undefined, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + + default: + return state; + } +}; +//#endregion + +//#region > Exports +export default generalReducer; +//#endregion diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js index 9a0aa63..c77f7a2 100644 --- a/src/store/reducers/index.js +++ b/src/store/reducers/index.js @@ -11,6 +11,9 @@ import { loadingBarReducer } from "react-redux-loading-bar"; import userReducer from "./userReducers"; // Person import personReducer from "./personReducer"; +// General +import generalReducers from "./generalReducers"; + //#endregion //#region > Config @@ -21,6 +24,8 @@ const rootReducer = combineReducers({ user: userReducer, // Person data person: personReducer, + // General data + general: generalReducers, }); //#endregion diff --git a/src/store/types.js b/src/store/types.js index b84ad4a..e0d3fcc 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -17,3 +17,9 @@ export const PERSON_GET_SUCCESS = "PERSON_GET_SUCCESS"; export const PERSONS_BRIEF_GET_REQUEST = "PERSONS_BRIEF_GET_REQUEST"; export const PERSONS_BRIEF_GET_FAILURE = "PERSON_BRIEF_GET_FAILURE"; export const PERSONS_BRIEF_GET_SUCCESS = "PERSON_BRIEF_GET_SUCCESS"; +export const GENERAL_GITLAB_SERVER_GET_REQUEST = + "GENERAL_GITLAB_SERVER_GET_REQUEST"; +export const GENERAL_GITLAB_SERVER_GET_FAILURE = + "GENERAL_GITLAB_SERVER_GET_FAILURE"; +export const GENERAL_GITLAB_SERVER_GET_SUCCESS = + "GENERAL_GITLAB_SERVER_GET_SUCCESS"; From cc25e35a9d92df6fa354fd49f4b5f907b867e399 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Mon, 7 Sep 2020 21:52:08 +0200 Subject: [PATCH 016/175] Improve ConnectModal Some more functionality has been added. --- src/components/molecules/modals/ConnectModal/index.jsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/modals/ConnectModal/index.jsx b/src/components/molecules/modals/ConnectModal/index.jsx index d8877f7..2634af8 100644 --- a/src/components/molecules/modals/ConnectModal/index.jsx +++ b/src/components/molecules/modals/ConnectModal/index.jsx @@ -57,7 +57,15 @@ class ConnectModal extends React.Component { }; addGitLab = () => { - // Do stuff + // Deactivate GitLab modal + this.setState( + { + modalGitLab: false, + }, + () => { + // Do stuff + } + ); }; addGitHub = () => { From 7abb34e95855a20e7196586fd631fad7774bab87 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 21:52:34 +0200 Subject: [PATCH 017/175] Improve store Types have been improved. Naming has been improved. --- src/store/actions/generalActions.js | 6 ++-- src/store/actions/personActions.js | 15 ++++---- src/store/actions/userActions.js | 6 ++-- src/store/reducers/generalReducers.js | 6 ++-- .../{personReducer.js => personReducers.js} | 12 +++---- src/store/reducers/userReducers.js | 6 ++-- src/store/types.js | 34 +++++++++++-------- 7 files changed, 46 insertions(+), 39 deletions(-) rename src/store/reducers/{personReducer.js => personReducers.js} (81%) diff --git a/src/store/actions/generalActions.js b/src/store/actions/generalActions.js index c8159a8..f1ebb4f 100644 --- a/src/store/actions/generalActions.js +++ b/src/store/actions/generalActions.js @@ -12,17 +12,17 @@ import INTEL_SNEK from "snek-intel/lib/utils/snek"; const getGitlabServers = () => { return async (dispatch, getState, {}) => { try { - dispatch({ type: Action.GENERAL_GITLAB_SERVER_GET_REQUEST }); + dispatch({ type: Action.GENERAL_GITLAB_SERVER_FETCH_REQUEST }); const servers = await INTEL_SNEK.general.getGitlabServer(); dispatch({ - type: Action.GENERAL_GITLAB_SERVER_GET_SUCCESS, + type: Action.GENERAL_GITLAB_SERVER_FETCH_SUCCESS, payload: servers, }); } catch (ex) { dispatch({ - type: Action.GENERAL_GITLAB_SERVER_GET_FAILURE, + type: Action.GENERAL_GITLAB_SERVER_FETCH_FAILURE, payload: { errorCode: 601, message: `Getting person (${personName}) failed`, diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index 4ed260d..08778c9 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -12,14 +12,14 @@ import INTEL_SNEK from "snek-intel/lib/utils/snek"; const getPerson = (personName) => { return async (dispatch, getState, {}) => { try { - dispatch({ type: Action.PERSON_GET_REQUEST }); + dispatch({ type: Action.PERSON_FETCH_REQUEST }); const person = await INTEL_SNEK.person.get({ personName }); - dispatch({ type: Action.PERSON_GET_SUCCESS, payload: person }); + dispatch({ type: Action.PERSON_FETCH_SUCCESS, payload: person }); } catch (ex) { dispatch({ - type: Action.PERSON_GET_FAILURE, + type: Action.PERSON_FETCH_FAILURE, payload: { errorCode: 601, message: `Getting person (${personName}) failed`, @@ -36,16 +36,19 @@ const getPerson = (personName) => { const getPersonsBrief = () => { return async (dispatch, getState, {}) => { try { - dispatch({ type: Action.PERSONS_BRIEF_GET_REQUEST }); + dispatch({ type: Action.PERSON_PERSONS_BRIEF_FETCH_REQUEST }); const persons = await INTEL_SNEK.person.allBrief(); console.log(persons); - dispatch({ type: Action.PERSONS_BRIEF_GET_SUCCESS, payload: persons }); + dispatch({ + type: Action.PERSON_PERSONS_BRIEF_FETCH_SUCCESS, + payload: persons, + }); } catch (ex) { dispatch({ - type: Action.PERSONS_BRIEF_GET_FAILURE, + type: Action.PERSON_PERSONS_BRIEF_FETCH_FAILURE, payload: { errorCode: 601, message: "Getting all person in a brief form failed", diff --git a/src/store/actions/userActions.js b/src/store/actions/userActions.js index f1a5e9e..1403df3 100644 --- a/src/store/actions/userActions.js +++ b/src/store/actions/userActions.js @@ -84,14 +84,14 @@ const logoutAction = () => { const getPerson = (personName) => { return async (dispatch, getState, {}) => { try { - dispatch({ type: Action.USER_PERSON_GET_REQUEST }); + dispatch({ type: Action.USER_PERSON_FETCH_REQUEST }); const person = await INTEL_SNEK.person.get({ personName }); - dispatch({ type: Action.USER_PERSON_GET_SUCCESS, payload: person }); + dispatch({ type: Action.USER_PERSON_FETCH_SUCCESS, payload: person }); } catch (ex) { dispatch({ - type: Action.USER_PERSON_GET_FAILURE, + type: Action.USER_PERSON_FETCH_FAILURE, payload: { errorCode: 601, message: `Getting person (${personName}) failed`, diff --git a/src/store/reducers/generalReducers.js b/src/store/reducers/generalReducers.js index ecc2333..b501976 100644 --- a/src/store/reducers/generalReducers.js +++ b/src/store/reducers/generalReducers.js @@ -18,14 +18,14 @@ const INIT_STATE = { const generalReducer = (state = INIT_STATE, action) => { switch (action.type) { //> Get all gitlab server - case Action.GENERAL_GITLAB_SERVER_GET_REQUEST: + case Action.GENERAL_GITLAB_SERVER_FETCH_REQUEST: return state; - case Action.GENERAL_GITLAB_SERVER_GET_FAILURE: + case Action.GENERAL_GITLAB_SERVER_FETCH_FAILURE: return { ...state, gitlabServer: action.payload, }; - case Action.GENERAL_GITLAB_SERVER_GET_SUCCESS: + case Action.GENERAL_GITLAB_SERVER_FETCH_SUCCESS: return { ...state, gitlabServer: undefined, diff --git a/src/store/reducers/personReducer.js b/src/store/reducers/personReducers.js similarity index 81% rename from src/store/reducers/personReducer.js rename to src/store/reducers/personReducers.js index b3e930c..c3d02bc 100644 --- a/src/store/reducers/personReducer.js +++ b/src/store/reducers/personReducers.js @@ -19,16 +19,16 @@ const INIT_STATE = { const userReducer = (state = INIT_STATE, action) => { switch (action.type) { //> Get - case Action.PERSON_GET_REQUEST: + case Action.PERSON_FETCH_REQUEST: return state; - case Action.PERSON_GET_SUCCESS: + case Action.PERSON_FETCH_SUCCESS: return { ...state, fetchedPerson: { ...action.payload, }, }; - case Action.PERSON_GET_FAILURE: + case Action.PERSON_FETCH_FAILURE: return { ...state, fetchedPerson: undefined, @@ -36,14 +36,14 @@ const userReducer = (state = INIT_STATE, action) => { errorDetails: serializeError(action.payload.error), }; //> Get all brief - case Action.PERSONS_BRIEF_GET_REQUEST: + case Action.PERSON_PERSONS_BRIEF_FETCH_REQUEST: return state; - case Action.PERSONS_BRIEF_GET_SUCCESS: + case Action.PERSON_PERSONS_BRIEF_FETCH_SUCCESS: return { ...state, allPersonBrief: action.payload, }; - case Action.PERSONS_BRIEF_GET_FAILURE: + case Action.PERSON_PERSONS_BRIEF_FETCH_FAILURE: return { ...state, allPersonBrief: undefined, diff --git a/src/store/reducers/userReducers.js b/src/store/reducers/userReducers.js index ddaf49b..0a89afd 100644 --- a/src/store/reducers/userReducers.js +++ b/src/store/reducers/userReducers.js @@ -45,9 +45,9 @@ const userReducer = (state = INIT_STATE, action) => { errorDetails: serializeError(action.payload.error), }; //> Person - case Action.USER_PERSON_GET_REQUEST: + case Action.USER_PERSON_FETCH_REQUEST: return state; - case Action.USER_PERSON_GET_SUCCESS: + case Action.USER_PERSON_FETCH_SUCCESS: return { ...state, user: { @@ -57,7 +57,7 @@ const userReducer = (state = INIT_STATE, action) => { }, }, }; - case Action.USER_PERSON_GET_FAILURE: + case Action.USER_PERSON_FETCH_FAILURE: return { ...state, user: { diff --git a/src/store/types.js b/src/store/types.js index e0d3fcc..a966177 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -6,20 +6,24 @@ export const USER_LOGOUT_REQUEST = "USER_LOGOUT_REQUEST"; export const USER_LOGOUT_FAILURE = "USER_LOGOUT_FAILURE"; export const USER_LOGOUT_SUCCESS = "USER_LOGOUT_SUCCESS"; -export const USER_PERSON_GET_REQUEST = "USER_GET_PERSONS_REQUEST"; -export const USER_PERSON_GET_FAILURE = "USER_PERSON_GET_FAILURE"; -export const USER_PERSON_GET_SUCCESS = "USER_PERSON_GET_SUCCESS"; +export const USER_PERSON_FETCH_REQUEST = "USER_FETCH_PERSONS_REQUEST"; +export const USER_PERSON_FETCH_FAILURE = "USER_PERSON_FETCH_FAILURE"; +export const USER_PERSON_FETCH_SUCCESS = "USER_PERSON_FETCH_SUCCESS"; -export const PERSON_GET_REQUEST = "PERSON_GET_REQUEST"; -export const PERSON_GET_FAILURE = "PERSON_GET_FAILURE"; -export const PERSON_GET_SUCCESS = "PERSON_GET_SUCCESS"; +export const PERSON_FETCH_REQUEST = "PERSON_FETCH_REQUEST"; +export const PERSON_FETCH_FAILURE = "PERSON_FETCH_FAILURE"; +export const PERSON_FETCH_SUCCESS = "PERSON_FETCH_SUCCESS"; -export const PERSONS_BRIEF_GET_REQUEST = "PERSONS_BRIEF_GET_REQUEST"; -export const PERSONS_BRIEF_GET_FAILURE = "PERSON_BRIEF_GET_FAILURE"; -export const PERSONS_BRIEF_GET_SUCCESS = "PERSON_BRIEF_GET_SUCCESS"; -export const GENERAL_GITLAB_SERVER_GET_REQUEST = - "GENERAL_GITLAB_SERVER_GET_REQUEST"; -export const GENERAL_GITLAB_SERVER_GET_FAILURE = - "GENERAL_GITLAB_SERVER_GET_FAILURE"; -export const GENERAL_GITLAB_SERVER_GET_SUCCESS = - "GENERAL_GITLAB_SERVER_GET_SUCCESS"; +export const PERSON_PERSONS_BRIEF_FETCH_REQUEST = + "PERSON_PERSONS_BRIEF_FETCH_REQUEST"; +export const PERSON_PERSONS_BRIEF_FETCH_FAILURE = + "PERSON_PERSONS_BRIEF_FETCH_FAILURE"; +export const PERSON_PERSONS_BRIEF_FETCH_SUCCESS = + "PERSON_PERSONS_BRIEF_FETCH_SUCCESS"; + +export const GENERAL_GITLAB_SERVER_FETCH_REQUEST = + "GENERAL_GITLAB_SERVER_FETCH_REQUEST"; +export const GENERAL_GITLAB_SERVER_FETCH_FAILURE = + "GENERAL_GITLAB_SERVER_FETCH_FAILURE"; +export const GENERAL_GITLAB_SERVER_FETCH_SUCCESS = + "GENERAL_GITLAB_SERVER_FETCH_SUCCESS"; From 35b034a8ad1aaf4aa5ab200b129e55a34eb9b2cc Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 21:54:34 +0200 Subject: [PATCH 018/175] Improve general actions The get gitlab servers action is now exported correctly. Also undefined variables have been removed. --- src/store/actions/generalActions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/actions/generalActions.js b/src/store/actions/generalActions.js index f1ebb4f..c8e4863 100644 --- a/src/store/actions/generalActions.js +++ b/src/store/actions/generalActions.js @@ -25,7 +25,7 @@ const getGitlabServers = () => { type: Action.GENERAL_GITLAB_SERVER_FETCH_FAILURE, payload: { errorCode: 601, - message: `Getting person (${personName}) failed`, + message: `Getting gitlab server failed`, error: ex, }, }); @@ -35,4 +35,4 @@ const getGitlabServers = () => { //#endregion -export { getPerson, getPersonsBrief }; +export { getGitlabServers }; From 015de2d97c28853ab59a7129d5ba050c32d66c24 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 21:56:05 +0200 Subject: [PATCH 019/175] Fix naming issue The reducers are now correctly added to the root reducer. --- src/store/reducers/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js index c77f7a2..d2c15c7 100644 --- a/src/store/reducers/index.js +++ b/src/store/reducers/index.js @@ -8,9 +8,9 @@ import { loadingBarReducer } from "react-redux-loading-bar"; //> Reducers // User -import userReducer from "./userReducers"; +import userReducers from "./userReducers"; // Person -import personReducer from "./personReducer"; +import personReducers from "./personReducers"; // General import generalReducers from "./generalReducers"; @@ -21,9 +21,9 @@ const rootReducer = combineReducers({ // Loading bar loadingBar: loadingBarReducer, // User data - user: userReducer, + user: userReducers, // Person data - person: personReducer, + person: personReducers, // General data general: generalReducers, }); From 9884a7f6b23cf53dcf4fe61529589343d1947ec0 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Mon, 7 Sep 2020 22:01:44 +0200 Subject: [PATCH 020/175] Unyeet registration The registration has been unyeeted. --- .../molecules/forms/RegisterForm/index2.jsx | 876 ++++++++++++++++++ 1 file changed, 876 insertions(+) create mode 100644 src/components/molecules/forms/RegisterForm/index2.jsx diff --git a/src/components/molecules/forms/RegisterForm/index2.jsx b/src/components/molecules/forms/RegisterForm/index2.jsx new file mode 100644 index 0000000..8842913 --- /dev/null +++ b/src/components/molecules/forms/RegisterForm/index2.jsx @@ -0,0 +1,876 @@ +//#region > Imports +//> React +// Contains all the functionality necessary to define React components +import React from "react"; +// Runtime type checking for React props and similar objects +import PropTypes from "prop-types"; +//> Additional +// Text animations +import TextLoop from "react-text-loop"; +//> MDB +// "Material Design for Bootstrap" is a great UI design framework +import { + MDBRow, + MDBCol, + MDBBtn, + MDBPopover, + MDBPopoverBody, + MDBPopoverHeader, + MDBIcon, + MDBModal, + MDBModalBody, + MDBModalHeader, + MDBModalFooter, + MDBSelect, + MDBProgress, + MDBSelectInput, + MDBSelectOptions, + MDBSelectOption, + MDBListGroup, + MDBListGroupItem, +} from "mdbreact"; +//> OAuth +import GitHubOAuth from "reactjs-oauth"; +//> Redux +// Allows to React components read data from a Redux store, and dispatch actions +// to the store to update data. +import { connect } from "react-redux"; + +//> Actions +// Functions to send data from the application to the store +import { registerAction } from "../../../../store/actions/userActions"; +//import { fetchGitLabServersAction } from "../../../../store/actions/generalActions"; +import { loginAction } from "../../../../store/actions/authActions"; +//#endregion + +//#region > Components +/** + * @class A registration form component. Contains all fields required for + * registration including OAuth and a selectable list of GitLab servers. + */ +class RegisterForm extends React.Component { + state = { + loading: false, + firstname: "", + lastname: "", + email: "", + password1: "", + password2: "", + username: "", + gitlab_username: "", + gitlab_servers: undefined, + gitlab_server: "Choose your organisation", + sourceList: [], + usernames: [], + promoCode: true, + code: "", + }; + + componentDidMount = () => { + this.getGitLabServers(); + }; + + toggle = () => { + if (!this.state.modalGitLab) { + this.setState({ + modalGitLab: true, + }); + } else { + this.setState({ + modalGitLab: false, + }); + } + }; + + getGitLabServers = async () => { + // Check if GitLab Servers have already been set + if (this.state.gitlab_servers === undefined) { + // Retrieve GitLab servers + this.props.fetchGitLabServers().then(() => { + this.setState({ + gitlab_servers: this.props.gitlabServers, + }); + }); + } + }; + + addGitLab = () => { + const username = this.state.gitlab_username; + const server = this.state.gitlab_server; + + //#TSID7 + //console.log("REGISTER FORM ADD GITLAB", username, server); + + if (username.trim() && server.trim()) { + if (server !== "Choose your organisation") { + this.connectGitLab(username, "https://" + server); + } + } + }; + + connectGitLab = async (username, platformUrl) => { + this.setState( + { + modalGitLab: false, + gitlab_username: "", + gitlab_server: "Choose your organisation", + }, + () => this.pushToSourceList("gitlab", username, platformUrl) + ); + }; + + oauthGitHubSuccess = (response) => { + this.setState( + { + loadingGitHub: true, + }, + async () => { + this.pushToSourceList( + "github", + response.username, + "https://api.github.com/graphql", + response.accessToken + ); + } + ); + }; + + oauthGitHubFailure = (response) => { + //#ERROR + console.error(response); + }; + + pushToSourceList = (platformName, username, platformUrl, token) => { + let sourceList = this.state.sourceList; + + this.addToUsernames(username, platformName); + + sourceList.push({ + id: username.length + platformName.length + username + platformName, + user: username, + authorization: token ? "token " + token : null, + platform: { + name: platformName, + url: platformUrl, + }, + }); + + if (platformName === "github") { + this.setState({ + username, + hasGitHub: true, + sourceList, + loadingGitHub: false, + }); + } else { + // Set the new list of user information + this.setState({ + sourceList, + }); + } + }; + + addToUsernames = (username, source) => { + let usernames = this.state.usernames; + let found = false; + + for (let i = 0; i < usernames.length; i++) { + if ( + usernames[i].username === username && + usernames[i].source === source + ) { + found = true; + break; + } + } + + if (!found) { + // Make sure that only GitHub usernames are available for selection + // This aims to prevent name abuse in the first versions of this application + usernames.push({ + id: username.length + source.length + username + source, + username, + source, + verified: source === "github" ? true : false, + }); + this.setState({ + usernames, + }); + } + }; + + removeSource = (id) => { + let sourceList = this.state.sourceList.filter(function (obj) { + return obj.id !== id; + }); + let usernames = this.state.usernames.filter(function (obj) { + return obj.id !== id; + }); + + this.setState({ + sourceList, + usernames, + }); + }; + + handleUserNamePick = (username) => { + this.setState({ + username, + }); + }; + + handleSelectChange = (e) => { + this.setState({ + gitlab_server: e[0], + }); + }; + + testForError = (id) => { + if (this.state.errors) { + let rtn = this.state.errors.map((error, i) => { + if (!Array.isArray(id)) { + if (error.code === id) { + return true; + } else { + return false; + } + } else { + let innerRtn = id.map((item, ikey) => { + if (error.code === item) { + return true; + } else { + return false; + } + }); + if (innerRtn.includes(true)) { + return true; + } else { + return false; + } + } + }); + + if (rtn.includes(true)) { + return true; + } else { + return false; + } + } else { + return false; + } + }; + + handleChange = (e, id) => { + this.setState( + { + [e.target.name]: e.target.value, + }, + () => this.removeError(id) + ); + }; + + handleChangeManual = (name, value, id) => { + this.setState( + { + [name]: value, + }, + () => this.removeError(id) + ); + }; + + removeError = (id) => { + // Preset errors to local variable + let errors = this.state.errors; + + if (errors) { + if (!Array.isArray(id)) { + errors = errors.filter(function (obj) { + return obj.code !== id; + }); + } else { + id.map((item) => { + errors = errors.filter(function (obj) { + return obj.code !== item; + }); + }); + } + + this.setState({ + errors, + }); + } + }; + + // Handle sumbit of register form + handleSubmit = async () => { + //#TSID8 + //console.log("REGISTER FORM HANDLE SUBMIT"); + + // CHANGE TO CONST + let { + password1, + password2, + firstname, + lastname, + email, + sourceList, + username, + promoCode, + code, + } = this.state; + + // Error + let errors = []; + + // Check if passwords match + if (password1 !== "" && password2 !== "" && password1 !== password2) { + errors.push({ + code: 1, + msg: "Your passwords do not match.", + weight: 10, + }); + } + + if (sourceList.length === 0) { + errors.push({ + code: 2, + msg: "No platforms are connected.", + weight: 10, + }); + } + + if (firstname === "") { + errors.push({ + code: 3, + msg: "Please enter your first name.", + weight: 8, + }); + } + + if (lastname === "") { + errors.push({ + code: 4, + msg: "Please enter your last name.", + weight: 8, + }); + } + + if (email === "") { + errors.push({ + code: 5, + msg: "Please enter your email.", + weight: 9, + }); + } + + if (username === "") { + errors.push({ + code: 6, + msg: "Please select a username from the list above.", + weight: 10, + }); + } + + if (password1 === "") { + errors.push({ + code: 7, + msg: "Please enter a password.", + weight: 10, + }); + } + + if (password2 === "") { + errors.push({ + code: 8, + msg: "Please repeat your password.", + weight: 10, + }); + } + + if (code === "") { + errors.push({ + code: 9, + msg: "Please enter your promo code or contact us to receive one.", + weight: 5, + }); + } + + if (errors.length === 0) { + this.setState( + { + loading: true, + }, + () => { + //#TSID9 + //console.log("REGISTER FORM REGISTER", this.state); + + let registrationData = { + sources: sourceList, + username, + email, + first_name: firstname, + last_name: lastname, + gift_code: promoCode && code !== "" ? code : null, + password: password1, + }; + + this.props.register(registrationData).then(() => { + const { username, password } = registrationData; + + this.props.login({ + username, + password, + }); + }); + } + ); + } else { + this.setState({ + errors, + }); + } + }; + + handleCodeChange = (e) => { + let code = e.target.value; + + if (code.length <= 14) { + if (code.length === 4 || code.length === 9) { + code = code + "-"; + } + + this.setState( + { + code: code.toUpperCase(), + }, + () => this.removeError(9) + ); + } else { + return false; + } + }; + + render() { + const { goTo } = this.props; + + return ( + <> + {!this.state.loading ? ( + <> +
+ this.setState({ errors: [] }, () => goTo(0))} + > + + Back + +
+

So you're a Software Engineer...

+

+ We just need a bit more information to get you started. +

+ + + + this.handleChange(e, 3)} + value={this.state.firstname} + /> + + + this.handleChange(e, 4)} + value={this.state.lastname} + /> + + + this.handleChange(e, 5)} + value={this.state.email} + /> + + + this.handleChange(e, [7, 1])} + value={this.state.password1} + /> + + + this.handleChange(e, [8, 1])} + value={this.state.password2} + /> + + + +
+ + this.setState({ promoCode: !this.state.promoCode }) + } + > + {!this.state.promoCode + ? "I have a promo code" + : "I don't have a promo code"} + +
+ {this.state.promoCode && ( + + )} +

Connect your work

+ + You need to connect at least one account to continue. + +
+ + + + Why do I need to connect my accounts? + +
+ + + Connecting accounts + + + To generate your expressive and meaningful profile, we + require data about your work, which we acquire by fetching + it from platforms like GitHub, GitLab and BitBucket. It also + helps us verify your data. +
+ + Learn more + +
+
+
+
+
+ this.setState({ modalGitLab: true })} + disabled={ + !this.state.gitlab_servers || + (this.state.gitlab_server && + this.state.gitlab_server.length < 1) + } + > + + + {!process.env.NODE_ENV || + process.env.NODE_ENV === "development" ? ( + + ) : ( + + )} + + + +
+
+ + {this.state.loadingGitHub && } + {this.state.usernames.map((source, i) => { + return ( + +
+ + {source.username} + {source.verified ? ( + + + + +
+ Verified + + + + + + + This source has been{" "} + + verified + {" "} + by logging into it. + + + +
+
+ ) : ( + + + + +
+ Not verified + + + + + + + We can not verify your identity with GitLab. + Your data is still being included. + + + +
+
+ )} +
+ this.removeSource(source.id)} + /> +
+ ); + })} +
+
+ + Join now + +

+ + Don't worry, you can easily connect further accounts in the + future. + +

+ + ) : ( +
+

+ Hey, {this.state.firstname}! +

+

Your profile is being generated.

+
+
+
+ +
+ )} + {this.state.modalGitLab && ( + + + + Add GitLab profile + + + + this.setState({ [e.target.name]: e.target.value }) + } + value={this.state.gitlab_username} + /> + + + + + Choose your organisation + + {this.state.gitlab_servers && + this.state.gitlab_servers.map((source, i) => { + return ( + + {source.organisation} + + ); + })} + + + + + + + Add + + + Cancel + + + + )} + + ); + } +} +//#endregion + +//#region > PropTypes +RegisterForm.propTypes = { + goto: PropTypes.func, +}; +//#endregion + +//#region > Redux Mapping +const mapStateToProps = (state) => ({ + registrationHistory: state.user.registrationHistory, + //gitlabServers: state.general.allGitlabServers, +}); + +const mapDispatchToProps = (dispatch) => { + return { + register: (registrationData) => dispatch(registerAction(registrationData)), + login: (user) => dispatch(loginAction(user)), + fetchGitLabServers: () => dispatch(fetchGitLabServersAction()), + }; +}; +//#endregion + +//#region > Exports +//> Default Component +/** + * Provides its connected component with the pieces of the data it needs from + * the store, and the functions it can use to dispatch actions to the store. + */ +export default connect(mapStateToProps, mapDispatchToProps)(RegisterForm); +//#endregion + +/** + * SPDX-License-Identifier: (EUPL-1.2) + * Copyright © 2019-2020 Simon Prast + */ From f90b97ce463e79758c92b8d987f6287024eb9009 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 22:21:34 +0200 Subject: [PATCH 021/175] Add registration action The registration action has been added. It calls the login action after. --- src/store/actions/userActions.js | 52 ++++++++++++++++++++++++++++++ src/store/reducers/userReducers.js | 10 ++++++ src/store/types.js | 4 +++ 3 files changed, 66 insertions(+) diff --git a/src/store/actions/userActions.js b/src/store/actions/userActions.js index 1403df3..45079a6 100644 --- a/src/store/actions/userActions.js +++ b/src/store/actions/userActions.js @@ -101,6 +101,58 @@ const getPerson = (personName) => { } }; }; + +/** + * Register new person/user + */ +const register = ( + username, + firstName, + lastName, + email, + password, + redemptionCode +) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.USER_PERSON_SIGNUP_REQUEST }); + + const registration = await INTEL_SNEK.person.register({ + formValues: { + username, + first_name: firstName, + last_name: lastName, + email, + password, + redemption_code: redemptionCode, + }, + }); + + if (registration.result === "ok") { + dispatch({ type: Action.USER_PERSON_SIGNUP_SUCCESS }); + + dispatch(loginAction({ username, password })); + } else { + dispatch({ + type: Action.USER_PERSON_SIGNUP_FAILURE, + payload: { + errorCode: 601, + message: `Registration failed`, + }, + }); + } + } catch (ex) { + dispatch({ + type: Action.USER_PERSON_SIGNUP_FAILURE, + payload: { + errorCode: 601, + message: `Registration error`, + error: ex, + }, + }); + } + }; +}; //#endregion //#region > Exports diff --git a/src/store/reducers/userReducers.js b/src/store/reducers/userReducers.js index 0a89afd..cf9169d 100644 --- a/src/store/reducers/userReducers.js +++ b/src/store/reducers/userReducers.js @@ -69,6 +69,16 @@ const userReducer = (state = INIT_STATE, action) => { error: action.payload, errorDetails: serializeError(action.payload.error), }; + case Action.USER_PERSON_SIGNUP_REQUEST: + return state; + case Action.USER_PERSON_SIGNUP_SUCCESS: + return { ...state }; + case Action.USER_PERSON_SIGNUP_FAILURE: + return { + ...state, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; default: return state; diff --git a/src/store/types.js b/src/store/types.js index a966177..e56c585 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -10,6 +10,10 @@ export const USER_PERSON_FETCH_REQUEST = "USER_FETCH_PERSONS_REQUEST"; export const USER_PERSON_FETCH_FAILURE = "USER_PERSON_FETCH_FAILURE"; export const USER_PERSON_FETCH_SUCCESS = "USER_PERSON_FETCH_SUCCESS"; +export const USER_PERSON_SIGNUP_REQUEST = "USER_PERSON_SIGNUP_REQUEST"; +export const USER_PERSON_SIGNUP_FAILURE = "USER_PERSON_SIGNUP_FAILURE"; +export const USER_PERSON_SIGNUP_SUCCESS = "USER_PERSON_SIGNUP_SUCCESS"; + export const PERSON_FETCH_REQUEST = "PERSON_FETCH_REQUEST"; export const PERSON_FETCH_FAILURE = "PERSON_FETCH_FAILURE"; export const PERSON_FETCH_SUCCESS = "PERSON_FETCH_SUCCESS"; From 9231eccd6d4d2836a9b0c9d7b75a00ad2ab8c417 Mon Sep 17 00:00:00 2001 From: schettn Date: Mon, 7 Sep 2020 22:48:17 +0200 Subject: [PATCH 022/175] Move person actions to general action Get persons brief and get person have been moved to the general actions. The person actions should only contain actions for the currently logged person. --- src/components/atoms/SearchBar/index.jsx | 4 +- src/components/pages/ProfilePage/index.jsx | 4 +- src/store/actions/generalActions.js | 54 ++++++++++++++++++- src/store/actions/personActions.js | 63 ---------------------- src/store/reducers/generalReducers.js | 34 ++++++++++++ src/store/reducers/personReducers.js | 62 --------------------- src/store/types.js | 18 +++---- 7 files changed, 100 insertions(+), 139 deletions(-) diff --git a/src/components/atoms/SearchBar/index.jsx b/src/components/atoms/SearchBar/index.jsx index bf2f23d..eab315c 100644 --- a/src/components/atoms/SearchBar/index.jsx +++ b/src/components/atoms/SearchBar/index.jsx @@ -22,7 +22,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { getPersonsBrief } from "../../../store/actions/personActions"; +import { getPersonsBrief } from "../../../store/actions/generalActions"; //> Style sheet import "./search.scss"; //#endregion @@ -113,7 +113,7 @@ class SearchBar extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - allUserSearchItems: state.person.allPersonBrief, + allUserSearchItems: state.general.allPersonBrief, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/components/pages/ProfilePage/index.jsx b/src/components/pages/ProfilePage/index.jsx index 2c7a1a8..efa7b7b 100644 --- a/src/components/pages/ProfilePage/index.jsx +++ b/src/components/pages/ProfilePage/index.jsx @@ -11,7 +11,7 @@ import { connect } from "react-redux"; //> Actions // Functions to send data from the application to the store -import { getPerson } from "../../../store/actions/personActions"; +import { getPerson } from "../../../store/actions/generalActions"; //> Components import { SoftwareEngineer } from "../../organisms/profiles"; //> Style sheet @@ -82,7 +82,7 @@ class ProfilePage extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ loggedUser: state.user.user, - fetchedPerson: state.person.fetchedPerson, + fetchedPerson: state.general.fetchedPerson, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/store/actions/generalActions.js b/src/store/actions/generalActions.js index c8e4863..542eb75 100644 --- a/src/store/actions/generalActions.js +++ b/src/store/actions/generalActions.js @@ -33,6 +33,58 @@ const getGitlabServers = () => { }; }; +/** + * Get all person in a brief form + */ +const getPersonsBrief = () => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.GENERAL_PERSONS_BRIEF_FETCH_REQUEST }); + + const persons = await INTEL_SNEK.person.allBrief(); + + console.log(persons); + + dispatch({ + type: Action.GENERAL_PERSONS_BRIEF_FETCH_SUCCESS, + payload: persons, + }); + } catch (ex) { + dispatch({ + type: Action.GENERAL_PERSONS_BRIEF_FETCH_FAILURE, + payload: { + errorCode: 601, + message: "Getting all person in a brief form failed", + error: ex, + }, + }); + } + }; +}; + +/** + * Get person page for a logged user + */ +const getPerson = (personName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.GENERAL_PERSON_FETCH_REQUEST }); + + const person = await INTEL_SNEK.person.get({ personName }); + + dispatch({ type: Action.GENERAL_PERSON_FETCH_SUCCESS, payload: person }); + } catch (ex) { + dispatch({ + type: Action.GENERAL_PERSON_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Getting person (${personName}) failed`, + error: ex, + }, + }); + } + }; +}; //#endregion -export { getGitlabServers }; +export { getGitlabServers, getPersonsBrief, getPerson }; diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index 08778c9..e69de29 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -1,63 +0,0 @@ -//#region > Imports -//> Action Types -import * as Action from "../types"; -//> Intel -import INTEL_SNEK from "snek-intel/lib/utils/snek"; -//#endregion - -//#region > Person Actions -/** - * Get person page for a logged user - */ -const getPerson = (personName) => { - return async (dispatch, getState, {}) => { - try { - dispatch({ type: Action.PERSON_FETCH_REQUEST }); - - const person = await INTEL_SNEK.person.get({ personName }); - - dispatch({ type: Action.PERSON_FETCH_SUCCESS, payload: person }); - } catch (ex) { - dispatch({ - type: Action.PERSON_FETCH_FAILURE, - payload: { - errorCode: 601, - message: `Getting person (${personName}) failed`, - error: ex, - }, - }); - } - }; -}; - -/** - * Get all person in a brief form - */ -const getPersonsBrief = () => { - return async (dispatch, getState, {}) => { - try { - dispatch({ type: Action.PERSON_PERSONS_BRIEF_FETCH_REQUEST }); - - const persons = await INTEL_SNEK.person.allBrief(); - - console.log(persons); - - dispatch({ - type: Action.PERSON_PERSONS_BRIEF_FETCH_SUCCESS, - payload: persons, - }); - } catch (ex) { - dispatch({ - type: Action.PERSON_PERSONS_BRIEF_FETCH_FAILURE, - payload: { - errorCode: 601, - message: "Getting all person in a brief form failed", - error: ex, - }, - }); - } - }; -}; -//#endregion - -export { getPerson, getPersonsBrief }; diff --git a/src/store/reducers/generalReducers.js b/src/store/reducers/generalReducers.js index b501976..34cdb21 100644 --- a/src/store/reducers/generalReducers.js +++ b/src/store/reducers/generalReducers.js @@ -8,6 +8,8 @@ import * as Action from "../types"; //#region > Constant Variables const INIT_STATE = { + fetchedPerson: undefined, + allPersonBrief: undefined, gitlabServer: undefined, error: undefined, errorDetails: undefined, @@ -32,6 +34,38 @@ const generalReducer = (state = INIT_STATE, action) => { error: action.payload, errorDetails: serializeError(action.payload.error), }; + //> Get person + case Action.GENERAL_PERSON_FETCH_REQUEST: + return state; + case Action.GENERAL_PERSON_FETCH_SUCCESS: + return { + ...state, + fetchedPerson: { + ...action.payload, + }, + }; + case Action.GENERAL_PERSON_FETCH_FAILURE: + return { + ...state, + fetchedPerson: undefined, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + //> Get all persons brief + case Action.GENERAL_PERSONS_BRIEF_FETCH_REQUEST: + return state; + case Action.GENERAL_PERSONS_BRIEF_FETCH_SUCCESS: + return { + ...state, + allPersonBrief: action.payload, + }; + case Action.GENERAL_PERSONS_BRIEF_FETCH_FAILURE: + return { + ...state, + allPersonBrief: undefined, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; default: return state; diff --git a/src/store/reducers/personReducers.js b/src/store/reducers/personReducers.js index c3d02bc..e69de29 100644 --- a/src/store/reducers/personReducers.js +++ b/src/store/reducers/personReducers.js @@ -1,62 +0,0 @@ -//#region > Imports -//> Error Serialization -// Serialize/deserialize an error into a plain object -import { serializeError } from "serialize-error"; -//> Action Types -import * as Action from "../types"; -//#endregion - -//#region > Constant Variables -const INIT_STATE = { - fetchedPerson: undefined, - allPersonBrief: undefined, - error: undefined, - errorDetails: undefined, -}; -//#endregion - -//#region > Reducers -const userReducer = (state = INIT_STATE, action) => { - switch (action.type) { - //> Get - case Action.PERSON_FETCH_REQUEST: - return state; - case Action.PERSON_FETCH_SUCCESS: - return { - ...state, - fetchedPerson: { - ...action.payload, - }, - }; - case Action.PERSON_FETCH_FAILURE: - return { - ...state, - fetchedPerson: undefined, - error: action.payload, - errorDetails: serializeError(action.payload.error), - }; - //> Get all brief - case Action.PERSON_PERSONS_BRIEF_FETCH_REQUEST: - return state; - case Action.PERSON_PERSONS_BRIEF_FETCH_SUCCESS: - return { - ...state, - allPersonBrief: action.payload, - }; - case Action.PERSON_PERSONS_BRIEF_FETCH_FAILURE: - return { - ...state, - allPersonBrief: undefined, - error: action.payload, - errorDetails: serializeError(action.payload.error), - }; - - default: - return state; - } -}; -//#endregion - -//#region > Exports -export default userReducer; -//#endregion diff --git a/src/store/types.js b/src/store/types.js index e56c585..e7e6587 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -14,16 +14,16 @@ export const USER_PERSON_SIGNUP_REQUEST = "USER_PERSON_SIGNUP_REQUEST"; export const USER_PERSON_SIGNUP_FAILURE = "USER_PERSON_SIGNUP_FAILURE"; export const USER_PERSON_SIGNUP_SUCCESS = "USER_PERSON_SIGNUP_SUCCESS"; -export const PERSON_FETCH_REQUEST = "PERSON_FETCH_REQUEST"; -export const PERSON_FETCH_FAILURE = "PERSON_FETCH_FAILURE"; -export const PERSON_FETCH_SUCCESS = "PERSON_FETCH_SUCCESS"; +export const GENERAL_PERSON_FETCH_REQUEST = "GENERAL_PERSON_FETCH_REQUEST"; +export const GENERAL_PERSON_FETCH_FAILURE = "GENERAL_PERSON_FETCH_FAILURE"; +export const GENERAL_PERSON_FETCH_SUCCESS = "GENERAL_PERSON_FETCH_SUCCESS"; -export const PERSON_PERSONS_BRIEF_FETCH_REQUEST = - "PERSON_PERSONS_BRIEF_FETCH_REQUEST"; -export const PERSON_PERSONS_BRIEF_FETCH_FAILURE = - "PERSON_PERSONS_BRIEF_FETCH_FAILURE"; -export const PERSON_PERSONS_BRIEF_FETCH_SUCCESS = - "PERSON_PERSONS_BRIEF_FETCH_SUCCESS"; +export const GENERAL_PERSONS_BRIEF_FETCH_REQUEST = + "GENERAL_PERSONS_BRIEF_FETCH_REQUEST"; +export const GENERAL_PERSONS_BRIEF_FETCH_FAILURE = + "GENERAL_PERSONS_BRIEF_FETCH_FAILURE"; +export const GENERAL_PERSONS_BRIEF_FETCH_SUCCESS = + "GENERAL_PERSONS_BRIEF_FETCH_SUCCESS"; export const GENERAL_GITLAB_SERVER_FETCH_REQUEST = "GENERAL_GITLAB_SERVER_FETCH_REQUEST"; From aec4641ba975391cb257ab495922d19b9fed88fb Mon Sep 17 00:00:00 2001 From: schettn Date: Tue, 8 Sep 2020 17:04:26 +0200 Subject: [PATCH 023/175] Add some more actions and reducers Following actions and their reducers have been added: - All Achievements - Person Settings - Person Meta Link - Person Profiles - Person Add Profile - Person Delete Profile - Person Update Profile - Person Instagram Posts - Person Process Profiles - Person Follow - Person Unfollow - Person Like - Person Unlike --- src/store/actions/generalActions.js | 29 +- src/store/actions/personActions.js | 455 ++++++++++++++++++++++++++ src/store/reducers/generalReducers.js | 16 + src/store/reducers/personReducers.js | 78 +++++ src/store/types.js | 68 ++++ 5 files changed, 645 insertions(+), 1 deletion(-) diff --git a/src/store/actions/generalActions.js b/src/store/actions/generalActions.js index 542eb75..3a2c61a 100644 --- a/src/store/actions/generalActions.js +++ b/src/store/actions/generalActions.js @@ -85,6 +85,33 @@ const getPerson = (personName) => { } }; }; + +/** + * Get all achievements with collectors + */ +const getAchievements = () => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.GENERAL_ACHIEVEMENTS_FETCH_REQUEST }); + + const achievements = await INTEL_SNEK.achievements.all(); + + dispatch({ + type: Action.GENERAL_ACHIEVEMENTS_FETCH_SUCCESS, + payload: achievements, + }); + } catch (ex) { + dispatch({ + type: Action.GENERAL_ACHIEVEMENTS_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Getting achievements failed`, + error: ex, + }, + }); + } + }; +}; //#endregion -export { getGitlabServers, getPersonsBrief, getPerson }; +export { getGitlabServers, getPersonsBrief, getPerson, getAchievements }; diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index e69de29..842f1f1 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -0,0 +1,455 @@ +//#region > Imports +//> Action Types +import * as Action from "../types"; +//> Intel +import INTEL_SNEK from "snek-intel/lib/utils/snek"; +//#endregion + +//#region > Utils +const extractNameFromPersonSlug = (personSlug) => personSlug.split("-")[1]; +//#endregion + +//#region > Actions +/** + * Get person page for a logged user + */ +const updateSettings = ( + nextSettings = { + avatarImage, + bio, + display2dCalendar, + display3dCalendar, + displayEmail, + displayProgrammingLanguages, + displayRanking, + displayWorkplace, + email, + firstName, + lastName, + location, + movablePool, + status, + websiteUrl, + workplace, + } +) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_SETTINGS_UPDATE_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const person = await INTEL_SNEK.person.updateSettings({ + personName, + settings: { + ...nextSettings, + }, + }); + + dispatch({ + type: Action.PERSON_SETTINGS_UPDATE_SUCCESS, + payload: person, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_SETTINGS_UPDATE_FAILURE, + payload: { + errorCode: 601, + message: `Updating settings failed`, + error: ex, + }, + }); + } + }; +}; + +const addMetaLink = ( + linkOptions = { + url, + linkType, + location, + imgurDeleteHash, + description, + } +) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_META_LINK_ADD_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const link = await INTEL_SNEK.person.addMetaLink({ + personName, + linkOptions: { + ...linkOptions, + }, + }); + + dispatch({ type: Action.PERSON_META_LINK_ADD_SUCCESS, payload: link }); + } catch (ex) { + dispatch({ + type: Action.PERSON_META_LINK_ADD_FAILURE, + payload: { + errorCode: 601, + message: `Adding link failed`, + error: ex, + }, + }); + } + }; +}; + +const deleteMetaLink = (id) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_META_LINK_DELETE_REQUEST }); + + const link = await INTEL_SNEK.person.deleteMetaLink({ + metaLinkId: id, + }); + + dispatch({ type: Action.PERSON_META_LINK_DELETE_SUCCESS, payload: link }); + } catch (ex) { + dispatch({ + type: Action.PERSON_META_LINK_DELETE_FAILURE, + payload: { + errorCode: 601, + message: `Deleting link failed`, + error: ex, + }, + }); + } + }; +}; + +const getProfiles = () => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_PROFILES_FETCH_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const profiles = await INTEL_SNEK.person.profiles({ + personName, + }); + + dispatch({ + type: Action.PERSON_PROFILES_FETCH_SUCCESS, + payload: profiles, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_PROFILES_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Fetching profiles failed`, + error: ex, + }, + }); + } + }; +}; + +const addProfile = (source = { url, type, authorization, username }) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_PROFILE_ADD_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const profile = await INTEL_SNEK.person.addProfile({ + personName, + source: { + ...source, + }, + }); + + dispatch({ type: Action.PERSON_PROFILE_ADD_SUCCESS, payload: profile }); + } catch (ex) { + dispatch({ + type: Action.PERSON_PROFILE_ADD_FAILURE, + payload: { + errorCode: 601, + message: `Adding profile failed`, + error: ex, + }, + }); + } + }; +}; + +const deleteProfile = (id) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_META_LINK_DELETE_REQUEST }); + + const profiles = await INTEL_SNEK.person.deleteProfile({ + profileId: id, + }); + + dispatch({ + type: Action.PERSON_META_LINK_DELETE_SUCCESS, + payload: profiles, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_META_LINK_DELETE_FAILURE, + payload: { + errorCode: 601, + message: `Deleting link failed`, + error: ex, + }, + }); + } + }; +}; + +const updateProfile = ( + id, + nextProfile = { + avatarImage, + bio, + display2dCalendar, + display3dCalendar, + displayEmail, + displayProgrammingLanguages, + displayRanking, + displayWorkplace, + email, + firstName, + lastName, + location, + movablePool, + status, + websiteUrl, + workplace, + } +) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_PROFILE_UPDATE_REQUEST }); + + const profile = await INTEL_SNEK.person.updateProfile({ + profileId: id, + toUpdate: { + ...nextProfile, + }, + }); + + dispatch({ + type: Action.PERSON_PROFILE_UPDATE_SUCCESS, + payload: profile, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_PROFILE_UPDATE_FAILURE, + payload: { + errorCode: 601, + message: `Updating profile failed`, + error: ex, + }, + }); + } + }; +}; + +const getInstagramPosts = (id) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_INSTAGRAM_POSTS_FETCH_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const posts = await INTEL_SNEK.person.getInstagramPosts({ + personName, + }); + + dispatch({ + type: Action.PERSON_INSTAGRAM_POSTS_FETCH_SUCCESS, + payload: posts, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_INSTAGRAM_POSTS_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Fetching instagram posts failed`, + error: ex, + }, + }); + } + }; +}; + +const processProfiles = () => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_PROFILES_PROCESS_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const posts = await INTEL_SNEK.person.processProfiles({ + personName, + }); + + dispatch({ + type: Action.PERSON_PROFILES_PROCESS_SUCCESS, + payload: posts, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_PROFILES_PROCESS_FAILURE, + payload: { + errorCode: 601, + message: `Processing profiles failed`, + error: ex, + }, + }); + } + }; +}; + +const follow = (receiverPersonName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_FOLLOW_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const res = await INTEL_SNEK.social.follow({ + invoker: personName, + receiver: receiverPersonName, + }); + + dispatch({ + type: Action.PERSON_FOLLOW_SUCCESS, + payload: res, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_FOLLOW_FAILURE, + payload: { + errorCode: 601, + message: `Following ${receiverPersonName} failed`, + error: ex, + }, + }); + } + }; +}; + +const unfollow = (receiverPersonName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_UNFOLLOW_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const res = await INTEL_SNEK.social.unfollow({ + invoker: personName, + receiver: receiverPersonName, + }); + + dispatch({ + type: Action.PERSON_UNFOLLOW_SUCCESS, + payload: res, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_UNFOLLOW_FAILURE, + payload: { + errorCode: 601, + message: `Unfollowing ${receiverPersonName} failed`, + error: ex, + }, + }); + } + }; +}; + +const like = (receiverPersonName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_LIKE_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const res = await INTEL_SNEK.social.follow({ + invoker: personName, + receiver: receiverPersonName, + }); + + dispatch({ + type: Action.PERSON_LIKE_SUCCESS, + payload: res, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_LIKE_FAILURE, + payload: { + errorCode: 601, + message: `Liking ${receiverPersonName} failed`, + error: ex, + }, + }); + } + }; +}; + +const unlike = (receiverPersonName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_UNLIKE_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const res = await INTEL_SNEK.social.unfollow({ + invoker: personName, + receiver: receiverPersonName, + }); + + dispatch({ + type: Action.PERSON_UNLIKE_SUCCESS, + payload: res, + }); + } catch (ex) { + dispatch({ + type: Action.PERSON_UNLIKE_FAILURE, + payload: { + errorCode: 601, + message: `Unliking ${receiverPersonName} failed`, + error: ex, + }, + }); + } + }; +}; + +//#endregion +//#region > Exports +export { + updateSettings, + addMetaLink, + deleteMetaLink, + getProfiles, + addProfile, + deleteProfile, + updateProfile, + getInstagramPosts, + processProfiles, + follow, + unfollow, + like, + unlike, +}; +//#endregion diff --git a/src/store/reducers/generalReducers.js b/src/store/reducers/generalReducers.js index 34cdb21..fa0e221 100644 --- a/src/store/reducers/generalReducers.js +++ b/src/store/reducers/generalReducers.js @@ -11,6 +11,7 @@ const INIT_STATE = { fetchedPerson: undefined, allPersonBrief: undefined, gitlabServer: undefined, + achievements: undefined, error: undefined, errorDetails: undefined, }; @@ -66,6 +67,21 @@ const generalReducer = (state = INIT_STATE, action) => { error: action.payload, errorDetails: serializeError(action.payload.error), }; + //> Achievements + case Action.GENERAL_ACHIEVEMENTS_FETCH_REQUEST: + return state; + case Action.GENERAL_ACHIEVEMENTS_FETCH_SUCCESS: + return { + ...state, + achievements: action.payload, + }; + case Action.GENERAL_ACHIEVEMENTS_FETCH_FAILURE: + return { + ...state, + achievements: undefined, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; default: return state; diff --git a/src/store/reducers/personReducers.js b/src/store/reducers/personReducers.js index e69de29..92607e6 100644 --- a/src/store/reducers/personReducers.js +++ b/src/store/reducers/personReducers.js @@ -0,0 +1,78 @@ +//#region > Imports +//> Error Serialization +// Serialize/deserialize an error into a plain object +import { serializeError } from "serialize-error"; +//> Action Types +import * as Action from "../types"; +//#endregion + +//#region > Constant Variables +const INIT_STATE = { + error: undefined, + errorDetails: undefined, +}; +//#endregion + +//#region > Reducers +const personReducer = (state = INIT_STATE, action) => { + switch (action.type) { + //> All person types + // Currently no splitted cases are used because there is no need for + case Action.PERSON_SETTINGS_UPDATE_REQUEST | + Action.PERSON_META_LINK_ADD_REQUEST | + Action.PERSON_META_LINK_DELETE_REQUEST | + Action.PERSON_PROFILES_FETCH_REQUEST | + Action.PERSON_PROFILE_ADD_REQUEST | + Action.PERSON_PROFILE_DELETE_REQUEST | + Action.PERSON_PROFILE_UPDATE_REQUEST | + Action.PERSON_INSTAGRAM_POSTS_FETCH_REQUEST | + Action.PERSON_PROFILES_PROCESS_REQUEST | + Action.PERSON_FOLLOW_REQUEST | + Action.PERSON_UNFOLLOW_REQUEST | + Action.PERSON_LIKE_REQUEST | + Action.PERSON_UNLIKE_REQUEST: + return state; + case Action.PERSON_SETTINGS_UPDATE_SUCCESS | + Action.PERSON_META_LINK_ADD_SUCCESS | + Action.PERSON_META_LINK_DELETE_SUCCESS | + Action.PERSON_PROFILES_FETCH_SUCCESS | + Action.PERSON_PROFILE_ADD_SUCCESS | + Action.PERSON_PROFILE_DELETE_SUCCESS | + Action.PERSON_PROFILE_UPDATE_SUCCESS | + Action.PERSON_INSTAGRAM_POSTS_FETCH_SUCCESS | + Action.PERSON_PROFILES_PROCESS_SUCCESS | + Action.PERSON_FOLLOW_SUCCESS | + Action.PERSON_UNFOLLOW_SUCCESS | + Action.PERSON_LIKE_SUCCESS | + Action.PERSON_UNLIKE_SUCCESS: + return { + ...state, + }; + case Action.PERSON_SETTINGS_UPDATE_FAILURE | + Action.PERSON_META_LINK_ADD_FAILURE | + Action.PERSON_META_LINK_DELETE_FAILURE | + Action.PERSON_PROFILES_FETCH_FAILURE | + Action.PERSON_PROFILE_ADD_FAILURE | + Action.PERSON_PROFILE_DELETE_FAILURE | + Action.PERSON_PROFILE_UPDATE_FAILURE | + Action.PERSON_INSTAGRAM_POSTS_FETCH_FAILURE | + Action.PERSON_PROFILES_PROCESS_FAILURE | + Action.PERSON_FOLLOW_FAILURE | + Action.PERSON_UNFOLLOW_FAILURE | + Action.PERSON_LIKE_FAILURE | + Action.PERSON_UNLIKE_FAILURE: + return { + ...state, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + + default: + return state; + } +}; +//#endregion + +//#region > Exports +export default personReducer; +//#endregion diff --git a/src/store/types.js b/src/store/types.js index e7e6587..7ecd9b0 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -31,3 +31,71 @@ export const GENERAL_GITLAB_SERVER_FETCH_FAILURE = "GENERAL_GITLAB_SERVER_FETCH_FAILURE"; export const GENERAL_GITLAB_SERVER_FETCH_SUCCESS = "GENERAL_GITLAB_SERVER_FETCH_SUCCESS"; + +export const GENERAL_ACHIEVEMENTS_FETCH_REQUEST = + "GENERAL_ACHIEVEMENTS_FETCH_REQUEST"; +export const GENERAL_ACHIEVEMENTS_FETCH_FAILURE = + "GENERAL_ACHIEVEMENTS_FETCH_FAILURE"; +export const GENERAL_ACHIEVEMENTS_FETCH_SUCCESS = + "GENERAL_ACHIEVEMENTS_FETCH_SUCCESS"; + +export const PERSON_SETTINGS_UPDATE_REQUEST = "PERSON_SETTINGS_UPDATE_REQUEST"; +export const PERSON_SETTINGS_UPDATE_FAILURE = "PERSON_SETTINGS_UPDATE_FAILURE"; +export const PERSON_SETTINGS_UPDATE_SUCCESS = "PERSON_SETTINGS_UPDATE_SUCCESS"; + +export const PERSON_META_LINK_ADD_REQUEST = "PERSON_META_LINK_ADD_REQUEST"; +export const PERSON_META_LINK_ADD_FAILURE = "PERSON_META_LINK_ADD_FAILURE"; +export const PERSON_META_LINK_ADD_SUCCESS = "PERSON_META_LINK_ADD_SUCCESS"; + +export const PERSON_META_LINK_DELETE_REQUEST = + "PERSON_META_LINK_DELETE_REQUEST"; +export const PERSON_META_LINK_DELETE_FAILURE = + "PERSON_META_LINK_DELETE_FAILURE"; +export const PERSON_META_LINK_DELETE_SUCCESS = + "PERSON_META_LINK_DELETE_SUCCESS"; + +export const PERSON_PROFILES_FETCH_REQUEST = "PERSON_PROFILES_FETCH_REQUEST"; +export const PERSON_PROFILES_FETCH_FAILURE = "PERSON_PROFILES_FETCH_FAILURE"; +export const PERSON_PROFILES_FETCH_SUCCESS = "PERSON_PROFILES_FETCH_SUCCESS"; + +export const PERSON_PROFILE_ADD_REQUEST = "PERSON_PROFILE_ADD_REQUEST"; +export const PERSON_PROFILE_ADD_FAILURE = "PERSON_PROFILE_ADD_FAILURE"; +export const PERSON_PROFILE_ADD_SUCCESS = "PERSON_PROFILE_ADD_SUCCESS"; + +export const PERSON_PROFILE_DELETE_REQUEST = "PERSON_PROFILE_DELETE_REQUEST"; +export const PERSON_PROFILE_DELETE_FAILURE = "PERSON_PROFILE_DELETE_FAILURE"; +export const PERSON_PROFILE_DELETE_SUCCESS = "PERSON_PROFILE_DELETE_SUCCESS"; + +export const PERSON_PROFILE_UPDATE_REQUEST = "PERSON_PROFILE_UPDATE_REQUEST"; +export const PERSON_PROFILE_UPDATE_FAILURE = "PERSON_PROFILE_UPDATE_FAILURE"; +export const PERSON_PROFILE_UPDATE_SUCCESS = "PERSON_PROFILE_UPDATE_SUCCESS"; + +export const PERSON_INSTAGRAM_POSTS_FETCH_REQUEST = + "PERSON_INSTAGRAM_POSTS_FETCH_REQUEST"; +export const PERSON_INSTAGRAM_POSTS_FETCH_FAILURE = + "PERSON_INSTAGRAM_POSTS_FETCH_FAILURE"; +export const PERSON_INSTAGRAM_POSTS_FETCH_SUCCESS = + "PERSON_INSTAGRAM_POSTS_FETCH_SUCCESS"; + +export const PERSON_PROFILES_PROCESS_REQUEST = + "PERSON_PROFILES_PROCESS_REQUEST"; +export const PERSON_PROFILES_PROCESS_FAILURE = + "PERSON_PROFILES_PROCESS_FAILURE"; +export const PERSON_PROFILES_PROCESS_SUCCESS = + "PERSON_PROFILES_PROCESS_SUCCESS"; + +export const PERSON_FOLLOW_REQUEST = "PERSON_FOLLOW_REQUEST"; +export const PERSON_FOLLOW_FAILURE = "PERSON_FOLLOW_FAILURE"; +export const PERSON_FOLLOW_SUCCESS = "PERSON_FOLLOW_SUCCESS"; + +export const PERSON_UNFOLLOW_REQUEST = "PERSON_UNFOLLOW_REQUEST"; +export const PERSON_UNFOLLOW_FAILURE = "PERSON_UNFOLLOW_FAILURE"; +export const PERSON_UNFOLLOW_SUCCESS = "PERSON_UNFOLLOW_SUCCESS"; + +export const PERSON_LIKE_REQUEST = "PERSON_LIKE_REQUEST"; +export const PERSON_LIKE_FAILURE = "PERSON_LIKE_FAILURE"; +export const PERSON_LIKE_SUCCESS = "PERSON_LIKE_SUCCESS"; + +export const PERSON_UNLIKE_REQUEST = "PERSON_UNLIKE_REQUEST"; +export const PERSON_UNLIKE_FAILURE = "PERSON_UNLIKE_FAILURE"; +export const PERSON_UNLIKE_SUCCESS = "PERSON_UNLIKE_SUCCESS"; From 1d208208d9f293d057da33f9cad066628d179b8c Mon Sep 17 00:00:00 2001 From: schettn Date: Tue, 8 Sep 2020 18:41:04 +0200 Subject: [PATCH 024/175] Add enterprise actions and reducers Following actions and their reducers have been added: - Enterprise General - Enterprise Projects - Enterprise Users --- src/store/actions/enterpriseActions.js | 97 ++++++++++++++++++++++++ src/store/actions/generalActions.js | 2 +- src/store/reducers/enterpriseReducers.js | 96 +++++++++++++++++++++++ src/store/types.js | 18 +++++ 4 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/store/actions/enterpriseActions.js create mode 100644 src/store/reducers/enterpriseReducers.js diff --git a/src/store/actions/enterpriseActions.js b/src/store/actions/enterpriseActions.js new file mode 100644 index 0000000..4ebeb78 --- /dev/null +++ b/src/store/actions/enterpriseActions.js @@ -0,0 +1,97 @@ +//#region > Imports +//> Action Types +import * as Action from "../types"; +//> Intel +import { Provider as INTEL_SNEK_E } from "snek-intel/lib/utils/enterprise"; +//#endregion + +//#region > Actions +/** + * Get enterprise + */ +const getGeneral = (enterpriseName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.ENTERPRISE_GENERAL_FETCH_REQUEST }); + + const enterprise = await INTEL_SNEK_E.general.getEnterprisePageGeneralContent( + { slug: `e-${enterpriseName}` } + ); + + dispatch({ + type: Action.ENTERPRISE_GENERAL_FETCH_SUCCESS, + payload: enterprise, + }); + } catch (ex) { + dispatch({ + type: Action.ENTERPRISE_GENERAL_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Getting general enterprise failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Get enterprise projects + */ +const getProjects = (enterpriseName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.ENTERPRISE_PROJECTS_FETCH_REQUEST }); + + const projects = await INTEL_SNEK_E.general.getEnterprisePageProjectsContent( + { slug: `e-${enterpriseName}` } + ); + + dispatch({ + type: Action.ENTERPRISE_PROJECTS_FETCH_SUCCESS, + payload: projects, + }); + } catch (ex) { + dispatch({ + type: Action.ENTERPRISE_PROJECTS_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Getting projects of enterprise failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Get enterprise users + */ +const getUsers = (enterpriseName) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.ENTERPRISE_USERS_FETCH_REQUEST }); + + const projects = await INTEL_SNEK_E.general.getEnterprisePageProjectsContent( + { slug: `e-${enterpriseName}` } + ); + + dispatch({ + type: Action.ENTERPRISE_USERS_FETCH_SUCCESS, + payload: projects, + }); + } catch (ex) { + dispatch({ + type: Action.ENTERPRISE_USERS_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Getting users of enterprise failed`, + error: ex, + }, + }); + } + }; +}; +//#endregion + +export { getGeneral, getProjects, getUsers }; diff --git a/src/store/actions/generalActions.js b/src/store/actions/generalActions.js index 3a2c61a..8884d6a 100644 --- a/src/store/actions/generalActions.js +++ b/src/store/actions/generalActions.js @@ -5,7 +5,7 @@ import * as Action from "../types"; import INTEL_SNEK from "snek-intel/lib/utils/snek"; //#endregion -//#region > Person Actions +//#region > Actions /** * Get all gitlab servers for registration */ diff --git a/src/store/reducers/enterpriseReducers.js b/src/store/reducers/enterpriseReducers.js new file mode 100644 index 0000000..f1ec85f --- /dev/null +++ b/src/store/reducers/enterpriseReducers.js @@ -0,0 +1,96 @@ +//#region > Imports +//> Error Serialization +// Serialize/deserialize an error into a plain object +import { serializeError } from "serialize-error"; +//> Action Types +import * as Action from "../types"; +//#endregion + +//#region > Constant Variables +const INIT_STATE = { + enterprise: { + general: undefined, + projects: undefined, + users: undefined, + }, + error: undefined, + errorDetails: undefined, +}; +//#endregion + +//#region > Reducers +const generalReducer = (state = INIT_STATE, action) => { + switch (action.type) { + //> General Enterprise + case Action.ENTERPRISE_GENERAL_FETCH_REQUEST: + return state; + case Action.ENTERPRISE_GENERAL_FETCH_SUCCESS: + return { + ...state, + enterprise: { + ...state.enterprise, + general: action.payload, + }, + }; + case Action.ENTERPRISE_GENERAL_FETCH_FAILURE: + return { + ...state, + enterprise: { + ...state.enterprise, + general: undefined, + }, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + //> Enterprise Projects + case Action.ENTERPRISE_PROJECTS_FETCH_REQUEST: + return state; + case Action.ENTERPRISE_PROJECTS_FETCH_SUCCESS: + return { + ...state, + enterprise: { + ...state.enterprise, + projects: action.payload, + }, + }; + case Action.ENTERPRISE_PROJECTS_FETCH_FAILURE: + return { + ...state, + enterprise: { + ...state.enterprise, + projects: undefined, + }, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + //> Enterprise Users + case Action.ENTERPRISE_USERS_FETCH_REQUEST: + return state; + case Action.ENTERPRISE_USERS_FETCH_SUCCESS: + return { + ...state, + enterprise: { + ...state.enterprise, + users: action.payload, + }, + }; + case Action.ENTERPRISE_USERS_FETCH_FAILURE: + return { + ...state, + enterprise: { + ...state.enterprise, + users: undefined, + }, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + + default: + return state; + } +}; +//#endregion + +//#region > Exports +export default generalReducer; +//#endregion diff --git a/src/store/types.js b/src/store/types.js index 7ecd9b0..ac3e7c7 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -1,3 +1,21 @@ +export const ENTERPRISE_GENERAL_FETCH_REQUEST = + "ENTERPRISE_GENERAL_FETCH_REQUEST"; +export const ENTERPRISE_GENERAL_FETCH_FAILURE = + "ENTERPRISE_GENERAL_FETCH_FAILURE"; +export const ENTERPRISE_GENERAL_FETCH_SUCCESS = + "ENTERPRISE_GENERAL_FETCH_SUCCESS"; + +export const ENTERPRISE_PROJECTS_FETCH_REQUEST = + "ENTERPRISE_PROJECTS_FETCH_REQUEST"; +export const ENTERPRISE_PROJECTS_FETCH_FAILURE = + "ENTERPRISE_PROJECTS_FETCH_FAILURE"; +export const ENTERPRISE_PROJECTS_FETCH_SUCCESS = + "ENTERPRISE_PROJECTS_FETCH_SUCCESS"; + +export const ENTERPRISE_USERS_FETCH_REQUEST = "ENTERPRISE_USERS_FETCH_REQUEST"; +export const ENTERPRISE_USERS_FETCH_FAILURE = "ENTERPRISE_USERS_FETCH_FAILURE"; +export const ENTERPRISE_USERS_FETCH_SUCCESS = "ENTERPRISE_USERS_FETCH_SUCCESS"; + export const USER_LOGIN_REQUEST = "USER_LOGIN_REQUEST"; export const USER_LOGIN_FAILURE = "USER_LOGIN_FAILURE"; export const USER_LOGIN_SUCCESS = "USER_LOGIN_SUCCESS"; From f176062de5f9d59ffc6c7a05e4f2238d313179cf Mon Sep 17 00:00:00 2001 From: schettn Date: Tue, 8 Sep 2020 18:53:37 +0200 Subject: [PATCH 025/175] Add achievement redeem action and reducer Following actions and their reducers have been added: - Redeem Achievement --- src/store/actions/personActions.js | 45 ++++++++++++++++++++++++++++ src/store/reducers/personReducers.js | 9 ++++-- src/store/types.js | 7 +++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index 842f1f1..3cc8607 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -435,6 +435,50 @@ const unlike = (receiverPersonName) => { }; }; +/** + * Redeem a achievement with sequence + */ +const redeemAchievement = (sequence) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.PERSON_ACHIEVEMENT_REDEEM_REQUEST }); + + const state = getState(); + const personName = extractNameFromPersonSlug(state.user.person.slug); + + const res = await INTEL_SNEK.achievements.redeem({ + personName, + sequence, + }); + + if (res.ok) { + dispatch({ + type: Action.PERSON_ACHIEVEMENT_REDEEM_SUCCESS, + payload: achievements, + }); + } else { + dispatch({ + type: Action.PERSON_ACHIEVEMENT_REDEEM_FAILURE, + payload: { + errorCode: 601, + message: `Redeeming achievement failed. Good try but try again`, + error: ex, + }, + }); + } + } catch (ex) { + dispatch({ + type: Action.PERSON_ACHIEVEMENT_REDEEM_FAILURE, + payload: { + errorCode: 601, + message: `Redeeming achievement failed`, + error: ex, + }, + }); + } + }; +}; + //#endregion //#region > Exports export { @@ -451,5 +495,6 @@ export { unfollow, like, unlike, + redeemAchievement, }; //#endregion diff --git a/src/store/reducers/personReducers.js b/src/store/reducers/personReducers.js index 92607e6..371b17b 100644 --- a/src/store/reducers/personReducers.js +++ b/src/store/reducers/personReducers.js @@ -30,7 +30,8 @@ const personReducer = (state = INIT_STATE, action) => { Action.PERSON_FOLLOW_REQUEST | Action.PERSON_UNFOLLOW_REQUEST | Action.PERSON_LIKE_REQUEST | - Action.PERSON_UNLIKE_REQUEST: + Action.PERSON_UNLIKE_REQUEST | + Action.PERSON_ACHIEVEMENT_REDEEM_REQUEST: return state; case Action.PERSON_SETTINGS_UPDATE_SUCCESS | Action.PERSON_META_LINK_ADD_SUCCESS | @@ -44,7 +45,8 @@ const personReducer = (state = INIT_STATE, action) => { Action.PERSON_FOLLOW_SUCCESS | Action.PERSON_UNFOLLOW_SUCCESS | Action.PERSON_LIKE_SUCCESS | - Action.PERSON_UNLIKE_SUCCESS: + Action.PERSON_UNLIKE_SUCCESS | + Action.PERSON_ACHIEVEMENT_REDEEM_SUCCESS: return { ...state, }; @@ -60,7 +62,8 @@ const personReducer = (state = INIT_STATE, action) => { Action.PERSON_FOLLOW_FAILURE | Action.PERSON_UNFOLLOW_FAILURE | Action.PERSON_LIKE_FAILURE | - Action.PERSON_UNLIKE_FAILURE: + Action.PERSON_UNLIKE_FAILURE | + Action.PERSON_ACHIEVEMENT_REDEEM_FAILURE: return { ...state, error: action.payload, diff --git a/src/store/types.js b/src/store/types.js index ac3e7c7..bd2ae37 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -117,3 +117,10 @@ export const PERSON_LIKE_SUCCESS = "PERSON_LIKE_SUCCESS"; export const PERSON_UNLIKE_REQUEST = "PERSON_UNLIKE_REQUEST"; export const PERSON_UNLIKE_FAILURE = "PERSON_UNLIKE_FAILURE"; export const PERSON_UNLIKE_SUCCESS = "PERSON_UNLIKE_SUCCESS"; + +export const PERSON_ACHIEVEMENT_REDEEM_REQUEST = + "PERSON_ACHIEVEMENT_REDEEM_REQUEST"; +export const PERSON_ACHIEVEMENT_REDEEM_FAILURE = + "PERSON_ACHIEVEMENT_REDEEM_FAILURE"; +export const PERSON_CHIEVEMENT_REDEEM_SUCCESS = + "PERSON_CHIEVEMENT_REDEEM_SUCCESS"; From b32b200c9d905d210181916602bfa7d371f5fae9 Mon Sep 17 00:00:00 2001 From: schettn Date: Tue, 8 Sep 2020 19:02:40 +0200 Subject: [PATCH 026/175] Fix typo in store types A type has been fixed. Yey. --- src/store/types.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/types.js b/src/store/types.js index bd2ae37..7514429 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -122,5 +122,5 @@ export const PERSON_ACHIEVEMENT_REDEEM_REQUEST = "PERSON_ACHIEVEMENT_REDEEM_REQUEST"; export const PERSON_ACHIEVEMENT_REDEEM_FAILURE = "PERSON_ACHIEVEMENT_REDEEM_FAILURE"; -export const PERSON_CHIEVEMENT_REDEEM_SUCCESS = - "PERSON_CHIEVEMENT_REDEEM_SUCCESS"; +export const PERSON_ACHIEVEMENT_REDEEM_SUCCESS = + "PERSON_ACHIEVEMENT_REDEEM_SUCCESS"; From b930d1871abea3b003473354a22c8ba319104f8e Mon Sep 17 00:00:00 2001 From: schettn Date: Tue, 8 Sep 2020 22:52:40 +0200 Subject: [PATCH 027/175] Add missing register export The export of register in the user action has been added. --- src/store/actions/userActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/actions/userActions.js b/src/store/actions/userActions.js index 45079a6..cd3bea2 100644 --- a/src/store/actions/userActions.js +++ b/src/store/actions/userActions.js @@ -156,7 +156,7 @@ const register = ( //#endregion //#region > Exports -export { loginAction, logoutAction, getPerson }; +export { loginAction, logoutAction, getPerson, register }; //#endregion /** From 31c0bf1da355d65dab3e3bac7f71686742027568 Mon Sep 17 00:00:00 2001 From: schettn Date: Tue, 8 Sep 2020 23:15:04 +0200 Subject: [PATCH 028/175] Add valid username check Now it is possible to check if a specific username is already taken. --- src/store/actions/userActions.js | 28 +++++++++++++++++++++++++++- src/store/reducers/userReducers.js | 11 +++++++++++ src/store/types.js | 4 ++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/store/actions/userActions.js b/src/store/actions/userActions.js index cd3bea2..d0c87e3 100644 --- a/src/store/actions/userActions.js +++ b/src/store/actions/userActions.js @@ -153,10 +153,36 @@ const register = ( } }; }; + +/** + * Check if there is already a registered user with the provided username + */ +const isValidUsername = async (username) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.USER_EXISTS_CHECK_REQUEST }); + + const exists = await INTEL_SNEK.general.checkUserExists(username); + + dispatch({ type: Action.USER_EXISTS_CHECK_SUCCESS }); + + return exists; + } catch (ex) { + dispatch({ + type: Action.USER_EXISTS_CHECK_FAILURE, + payload: { + errorCode: 601, + message: `Cannot check if there is already a user with '${username}' as name`, + error: ex, + }, + }); + } + }; +}; //#endregion //#region > Exports -export { loginAction, logoutAction, getPerson, register }; +export { loginAction, logoutAction, getPerson, register, isValidUsername }; //#endregion /** diff --git a/src/store/reducers/userReducers.js b/src/store/reducers/userReducers.js index cf9169d..a31e3f1 100644 --- a/src/store/reducers/userReducers.js +++ b/src/store/reducers/userReducers.js @@ -79,6 +79,17 @@ const userReducer = (state = INIT_STATE, action) => { error: action.payload, errorDetails: serializeError(action.payload.error), }; + //> User Exists Check + case Action.USER_EXISTS_CHECK_REQUEST: + return state; + case Action.USER_EXISTS_CHECK_SUCCESS: + return { ...state }; + case Action.USER_EXISTS_CHECK_FAILURE: + return { + ...state, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; default: return state; diff --git a/src/store/types.js b/src/store/types.js index 7514429..313ccab 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -32,6 +32,10 @@ export const USER_PERSON_SIGNUP_REQUEST = "USER_PERSON_SIGNUP_REQUEST"; export const USER_PERSON_SIGNUP_FAILURE = "USER_PERSON_SIGNUP_FAILURE"; export const USER_PERSON_SIGNUP_SUCCESS = "USER_PERSON_SIGNUP_SUCCESS"; +export const USER_EXISTS_CHECK_REQUEST = "USER_EXISTS_CHECK_REQUEST"; +export const USER_EXISTS_CHECK_FAILURE = "USER_EXISTS_CHECK_FAILURE"; +export const USER_EXISTS_CHECK_SUCCESS = "USER_EXISTS_CHECK_SUCCESS"; + export const GENERAL_PERSON_FETCH_REQUEST = "GENERAL_PERSON_FETCH_REQUEST"; export const GENERAL_PERSON_FETCH_FAILURE = "GENERAL_PERSON_FETCH_FAILURE"; export const GENERAL_PERSON_FETCH_SUCCESS = "GENERAL_PERSON_FETCH_SUCCESS"; From 1b42c34c51e5c4aef96a2f9cee77ac4ffb788ec4 Mon Sep 17 00:00:00 2001 From: schettn Date: Tue, 8 Sep 2020 23:56:47 +0200 Subject: [PATCH 029/175] Add talk actions and reducers Following actions and their reducers have been added: - Get Talk - Get Talks - Add Talk - Delete Talk - Update Talk - Add Talk Comment - Delete Talk Comment - Update Talk Comment --- src/store/actions/talkActions.js | 291 +++++++++++++++++++++++++++++ src/store/reducers/index.js | 4 + src/store/reducers/talkReducers.js | 60 ++++++ src/store/types.js | 32 ++++ 4 files changed, 387 insertions(+) create mode 100644 src/store/actions/talkActions.js create mode 100644 src/store/reducers/talkReducers.js diff --git a/src/store/actions/talkActions.js b/src/store/actions/talkActions.js new file mode 100644 index 0000000..b39e888 --- /dev/null +++ b/src/store/actions/talkActions.js @@ -0,0 +1,291 @@ +//#region > Imports +//> Action Types +import * as Action from "../types"; +//> Intel +import INTEL_SNEK from "snek-intel/lib/utils/snek"; +//#endregion + +//#region > Actions +/** + * Get a specific talk + */ +const getTalk = (id) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.TALKS_FETCH_REQUEST }); + + const talk = await INTEL_SNEK.talk.getTalk({ id }); + + dispatch({ + type: Action.TALKS_FETCH_SUCCESS, + payload: talk, + }); + } catch (ex) { + dispatch({ + type: Action.TALK_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Getting talk id: (${id}) failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Get all talks + */ +const getTalks = () => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.TALKS_FETCH_REQUEST }); + + const talks = await INTEL_SNEK.talk.getTalks(); + + dispatch({ + type: Action.TALKS_FETCH_SUCCESS, + payload: talks, + }); + } catch (ex) { + dispatch({ + type: Action.TALKS_FETCH_FAILURE, + payload: { + errorCode: 601, + message: `Getting talks failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Add a talk + */ +const addTalk = ( + talkOptions = { + title, + description, + displayUrl, + downloadUrl, + path, + url, + } +) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.TALK_ADD_REQUEST }); + + let personName; + + try { + personName = extractNameFromPersonSlug(state.user.person.slug); + } catch { + throw new Error("Something went wrong"); + } + + const talk = await INTEL_SNEK.talk.addTalk({ personName, talkOptions }); + + dispatch({ + type: Action.TALK_ADD_SUCCESS, + payload: talk, + }); + + return talk; + } catch (ex) { + dispatch({ + type: Action.TALK_ADD_FAILURE, + payload: { + errorCode: 601, + message: `Adding talk failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Delete a talk + */ +const deleteTalk = (id) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.TALK_DELETE_REQUEST }); + + const remainingTalks = await INTEL_SNEK.talk.deleteTalk({ talkId: id }); + + dispatch({ + type: Action.TALK_DELETE_SUCCESS, + }); + + return remainingTalks; + } catch (ex) { + dispatch({ + type: Action.TALK_DELETE_FAILURE, + payload: { + errorCode: 601, + message: `Deleting talk failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Delete a talk + */ +const updateTalk = ( + id, + nextTalk = { + title, + description, + displayUrl, + downloadUrl, + path, + url, + } +) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.TALK_UPDATE_REQUEST }); + + const updatedTalk = await INTEL_SNEK.talk.updateTalk({ + talkId: id, + toUpdate: { ...nextTalk }, + }); + + dispatch({ + type: Action.TALK_UPDATE_SUCCESS, + }); + + return updatedTalk; + } catch (ex) { + dispatch({ + type: Action.TALK_DELETE_FAILURE, + payload: { + errorCode: 601, + message: `Updating talk failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Add a comment to a talk + */ +const addTalkComment = ( + commentOptions = { + talkId, + text, + replyToId, + } +) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.TALK_COMMENT_ADD_REQUEST }); + + let personName; + + try { + personName = extractNameFromPersonSlug(state.user.person.slug); + } catch { + throw new Error("Something went wrong"); + } + + const talk = await INTEL_SNEK.talk.addTalkComment({ + personName, + commentOptions, + }); + + dispatch({ + type: Action.TALK_COMMENT_ADD_SUCCESS, + payload: talk, + }); + + return talk; + } catch (ex) { + dispatch({ + type: Action.TALK_COMMENT_ADD_FAILURE, + payload: { + errorCode: 601, + message: `Adding talk comment failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Delete a talk comment + */ +const deleteTalkComment = (id) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.TALK_COMMENT_DELETE_REQUEST }); + + const remainingComments = await INTEL_SNEK.talk.deleteTalkComment({ + commentId: id, + }); + + dispatch({ + type: Action.TALK_COMMENT_DELETE_SUCCESS, + }); + + return remainingComments; + } catch (ex) { + dispatch({ + type: Action.TALK_COMMENT_DELETE_FAILURE, + payload: { + errorCode: 601, + message: `Deleting talk comment failed`, + error: ex, + }, + }); + } + }; +}; + +/** + * Delete a talk + */ +const updateTalk = ( + id, + nextComment = { + text, + } +) => { + return async (dispatch, getState, {}) => { + try { + dispatch({ type: Action.TALK_COMMENT_UPDATE_REQUEST }); + + const updatedComment = await INTEL_SNEK.talk.updateTalkComment({ + talkId: id, + toUpdate: nextComment, + }); + + dispatch({ + type: Action.TALK_COMMENT_UPDATE_SUCCESS, + }); + + return updatedComment; + } catch (ex) { + dispatch({ + type: Action.TALK_COMMENT_UPDATE_FAILURE, + payload: { + errorCode: 601, + message: `Updating talk comment failed`, + error: ex, + }, + }); + } + }; +}; +//#endregion + +export { getTalk, getTalks, addTalk, deleteTalk, updateTalk }; diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js index d2c15c7..f933b2f 100644 --- a/src/store/reducers/index.js +++ b/src/store/reducers/index.js @@ -13,6 +13,8 @@ import userReducers from "./userReducers"; import personReducers from "./personReducers"; // General import generalReducers from "./generalReducers"; +// Talk +import talkReducer from "./talkReducers"; //#endregion @@ -26,6 +28,8 @@ const rootReducer = combineReducers({ person: personReducers, // General data general: generalReducers, + // Talk data + talk: talkReducer, }); //#endregion diff --git a/src/store/reducers/talkReducers.js b/src/store/reducers/talkReducers.js new file mode 100644 index 0000000..9e0893c --- /dev/null +++ b/src/store/reducers/talkReducers.js @@ -0,0 +1,60 @@ +//#region > Imports +//> Error Serialization +// Serialize/deserialize an error into a plain object +import { serializeError } from "serialize-error"; +//> Action Types +import * as Action from "../types"; +//#endregion + +//#region > Constant Variables +const INIT_STATE = { + talks: undefined, + fetchedTalk: undefined, + error: undefined, + errorDetails: undefined, +}; +//#endregion + +//#region > Reducers +const talkReducer = (state = INIT_STATE, action) => { + switch (action.type) { + //> Talk + case Action.TALK_FETCH_REQUEST: + return state; + case Action.TALK_FETCH_SUCCESS: + return { + ...state, + fetchedTalk: action.payload, + }; + case Action.TALK_FETCH_FAILURE: + return { + ...state, + fetchedTalk: undefined, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + //> Talks + case Action.TALKS_FETCH_REQUEST: + return state; + case Action.TALKS_FETCH_SUCCESS: + return { + ...state, + talks: action.payload, + }; + case Action.TALKS_FETCH_FAILURE: + return { + ...state, + talks: undefined, + error: action.payload, + errorDetails: serializeError(action.payload.error), + }; + + default: + return state; + } +}; +//#endregion + +//#region > Exports +export default talkReducer; +//#endregion diff --git a/src/store/types.js b/src/store/types.js index 313ccab..463a8e2 100644 --- a/src/store/types.js +++ b/src/store/types.js @@ -128,3 +128,35 @@ export const PERSON_ACHIEVEMENT_REDEEM_FAILURE = "PERSON_ACHIEVEMENT_REDEEM_FAILURE"; export const PERSON_ACHIEVEMENT_REDEEM_SUCCESS = "PERSON_ACHIEVEMENT_REDEEM_SUCCESS"; + +export const TALK_FETCH_REQUEST = "TALK_FETCH_REQUEST"; +export const TALK_FETCH_FAILURE = "TALK_FETCH_FAILURE"; +export const TALK_FETCH_SUCCESS = "TALK_FETCH_SUCCESS"; + +export const TALKS_FETCH_REQUEST = "TALKS_FETCH_REQUEST"; +export const TALKS_FETCH_FAILURE = "TALKS_FETCH_FAILURE"; +export const TALKS_FETCH_SUCCESS = "TALKS_FETCH_SUCCESS"; + +export const TALK_ADD_REQUEST = "TALK_ADD_REQUEST"; +export const TALK_ADD_FAILURE = "TALK_ADD_FAILURE"; +export const TALK_ADD_SUCCESS = "TALK_ADD_SUCCESS"; + +export const TALK_DELETE_REQUEST = "TALK_DELETE_REQUEST"; +export const TALK_DELETE_FAILURE = "TALK_DELETE_FAILURE"; +export const TALK_DELETE_SUCCESS = "TALK_DELETE_SUCCESS"; + +export const TALK_UPDATE_REQUEST = "TALK_UPDATE_REQUEST"; +export const TALK_UPDATE_FAILURE = "TALK_UPDATE_FAILURE"; +export const TALK_UPDATE_SUCCESS = "TALK_UPDATE_SUCCESS"; + +export const TALK_COMMENT_ADD_REQUEST = "TALK_COMMENT_ADD_REQUEST"; +export const TALK_COMMENT_ADD_FAILURE = "TALK_COMMENT_ADD_FAILURE"; +export const TALK_COMMENT_ADD_SUCCESS = "TALK_COMMENT_ADD_SUCCESS"; + +export const TALK_COMMENT_DELETE_REQUEST = "TALK_COMMENT_DELETE_REQUEST"; +export const TALK_COMMENT_DELETE_FAILURE = "TALK_COMMENT_DELETE_FAILURE"; +export const TALK_COMMENT_DELETE_SUCCESS = "TALK_COMMENT_DELETE_SUCCESS"; + +export const TALK_COMMENT_UPDATE_REQUEST = "TALK_COMMENT_UPDATE_REQUEST"; +export const TALK_COMMENT_UPDATE_FAILURE = "TALK_COMMENT_UPDATE_FAILURE"; +export const TALK_COMMENT_UPDATE_SUCCESS = "TALK_COMMENT_UPDATE_SUCCESS"; From c986125d4f1053751c236ea5d99c02329335ce58 Mon Sep 17 00:00:00 2001 From: schettn Date: Wed, 9 Sep 2020 13:43:14 +0200 Subject: [PATCH 030/175] Adjust component name, location and adjust for new data structure Now it is possible to view the person page with the new data structure. --- src/Routes.js | 4 +- .../organisms/ProfileInfo/index.jsx | 380 ------------------ src/components/organisms/index.js | 7 +- .../profiles/SoftwareEngineer/index.jsx | 43 -- src/components/organisms/profiles/index.js | 16 - .../sections/person/InfoCard/index.jsx | 349 ++++++++++++++++ .../person/InfoCard/infocard.scss} | 0 .../person/Tabs}/index.jsx | 41 +- .../person/Tabs/tabs.scss} | 0 .../organisms/tabs/TalksTab/index.jsx | 42 +- .../{ProfilePage => PersonPage}/index.jsx | 33 +- .../profile.scss => PersonPage/person.scss} | 0 src/components/pages/index.js | 4 +- 13 files changed, 426 insertions(+), 493 deletions(-) delete mode 100644 src/components/organisms/ProfileInfo/index.jsx delete mode 100644 src/components/organisms/profiles/SoftwareEngineer/index.jsx delete mode 100644 src/components/organisms/profiles/index.js create mode 100644 src/components/organisms/sections/person/InfoCard/index.jsx rename src/components/organisms/{ProfileInfo/profileinfo.scss => sections/person/InfoCard/infocard.scss} (100%) rename src/components/organisms/{SoftwareTabs => sections/person/Tabs}/index.jsx (76%) rename src/components/organisms/{SoftwareTabs/softwaretabs.scss => sections/person/Tabs/tabs.scss} (100%) rename src/components/pages/{ProfilePage => PersonPage}/index.jsx (75%) rename src/components/pages/{ProfilePage/profile.scss => PersonPage/person.scss} (100%) diff --git a/src/Routes.js b/src/Routes.js index fbea44b..69d96a6 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -8,7 +8,7 @@ import { Route, Switch } from "react-router-dom"; //> Components import { HomePage, - ProfilePage, + PersonPage, CompanyPage, // TalkPage, // SettingsPage, @@ -26,7 +26,7 @@ class Routes extends React.Component { } + component={(props) => } /> Imports -//> React -// Contains all the functionality necessary to define React components -import React from "react"; -//> MDB -// "Material Design for Bootstrap" is a great UI design framework -import { - MDBBtn, - MDBBadge, - MDBView, - MDBMask, - MDBPopover, - MDBPopoverBody, - MDBPopoverHeader, - MDBIcon, - MDBTooltip, -} from "mdbreact"; -//> Redux -// Allows to React components read data from a Redux store, and dispatch actions -// to the store to update data. -import { connect } from "react-redux"; - -//> Components -import { LanguageChart } from "../../atoms"; -//> Style Sheet -import "./profileinfo.scss"; -//#endregion - -//#region > Components -/** @class This component displays personal information and status of a user */ -class ProfileInfo extends React.Component { - state = { limitLanguages: true }; - - componentDidMount = () => { - const { fetchedUser } = this.props; - - if (fetchedUser && !this.state.sources) { - this.displaySources(fetchedUser.platformData.profile.sources); - } - }; - - displaySources = (sources) => { - let res = sources.map((source, i) => { - switch (source.source) { - case "github": - return "github"; - case "gitlab": - return "gitlab"; - case "bitbucket": - return "bitbucket"; - default: - return false; - } - }); - - this.setState({ - sources: res, - }); - }; - - render() { - const { fetchedUser } = this.props; - - return ( -
- - - - -
-

- {fetchedUser && fetchedUser.platformData.user.firstName && ( - <>{fetchedUser.platformData.user.firstName} - )}{" "} - {fetchedUser && fetchedUser.platformData.user.lastName && ( - <>{fetchedUser.platformData.user.lastName} - )} -

- {fetchedUser && - fetchedUser.platformData.user.settings && - fetchedUser.platformData.user.settings.showLocalRanking && ( -

- - #3 in your region - -

- )} - {fetchedUser && fetchedUser.platformData.user.company && ( - <> - {fetchedUser && - fetchedUser.platformData.user.settings.showCompanyPublic && ( - - {fetchedUser.platformData.user.company} - - )} - - )} -
- {fetchedUser && fetchedUser.accessories.badges && ( - <> - {fetchedUser.accessories.badges.bids.map((bid, i) => { - switch (bid) { - case "6403bf4d17b8472735a93b71a37e0bd0": - return ( - - Alpha - - ); - } - })} - - )} -
- {fetchedUser && fetchedUser.platformData.profile.statusMessage && ( -
- {fetchedUser.platformData.profile.statusEmojiHTML && ( -
- )} - - {fetchedUser.platformData.profile.statusMessage} - -
- )} -
-
- - - Follow - - - - Upvote - -
-
-

Connected accounts

-
- - - -
-
-

Organisations

- {fetchedUser && ( -
= 5 - ? "orgs text-center" - : "orgs" - } - > - {fetchedUser.platformData.profile.organizations.length > 0 ? ( - <> - {fetchedUser.platformData.profile.organizations.map( - (org, i) => { - return ( - - -
- {org.avatarUrl ? ( - {org.name} - ) : ( - - )} - {org.members && ( -
{org.members.length}
- )} -
-
-
- -
- {org.platformName}/ - - {org.name} - -
-
-
- - {org.members - ? org.members.length - : "Unknown"}{" "} - members - -
-
-
- {org.members && - org.members.length > 0 && - org.members - .slice(0, 8) - .map((member, m) => { - return ( - - - {member.username} - - {member.username} - - ); - })} -
- {org.members && org.members.length > 9 && ( -
- {org.platformName === "github" && ( - - Show all - - )} -
- )} -
-
-
- -

{org.description}

- - Show more - - -
-
-
- ); - } - )} - - ) : ( - - {fetchedUser.username} hasn't joined an organisation yet. - - )} -
- )} - {fetchedUser.platformData?.statistic?.languages?.length > 0 && ( -
-
-

Top languages

- - {fetchedUser.platformData.statistic.languages - .slice( - 0, - this.state.limitLanguages - ? 3 - : fetchedUser.platformData.statistic.languages.length - 1 - ) - .map((language, i) => { - return ( - -
-
- - {language.name} -
- - {language.share}% - -
-
- ); - })} - {this.state.limitLanguages && - fetchedUser.platformData.statistic.languages.length > 3 ? ( -

this.setState({ limitLanguages: false })} - > - Show more -

- ) : ( -

this.setState({ limitLanguages: true })} - > - Show less -

- )} -
- )} -
-
- ); - } -} -//#endregion - -//#region > Redux Mapping -const mapStateToProps = (state) => ({ - fetchedUser: state.user.fetchedUser, -}); - -const mapDispatchToProps = (dispatch) => { - return {}; -}; -//#endregion - -//#region > Exports -//> Default Component -/** - * Provides its connected component with the pieces of the data it needs from - * the store, and the functions it can use to dispatch actions to the store. - */ -export default connect(mapStateToProps, mapDispatchToProps)(ProfileInfo); -//#endregion - -/** - * SPDX-License-Identifier: (EUPL-1.2) - * Copyright © 2019-2020 Simon Prast - */ diff --git a/src/components/organisms/index.js b/src/components/organisms/index.js index 8f09366..64a46c5 100644 --- a/src/components/organisms/index.js +++ b/src/components/organisms/index.js @@ -1,13 +1,14 @@ //#region > Imports //> Organisms // Import all components to export them for easy access from parent components -import SoftwareTabs from "./SoftwareTabs"; -import ProfileInfo from "./ProfileInfo"; +import SoftwareTabs from "./sections/person/Tabs"; +import PersonInfoCard from "./sections/person/InfoCard"; +import PersonTabs from "./sections/person/Tabs"; //#endregion //#region > Exports //> Organisms -export { SoftwareTabs, ProfileInfo }; +export { SoftwareTabs, PersonInfoCard, PersonTabs }; //#endregion /** diff --git a/src/components/organisms/profiles/SoftwareEngineer/index.jsx b/src/components/organisms/profiles/SoftwareEngineer/index.jsx deleted file mode 100644 index dfbdbfe..0000000 --- a/src/components/organisms/profiles/SoftwareEngineer/index.jsx +++ /dev/null @@ -1,43 +0,0 @@ -//#region > Imports -//> React -// Contains all the functionality necessary to define React components -import React from "react"; -//> MDB -// "Material Design for Bootstrap" is a great UI design framework -import { MDBContainer, MDBRow, MDBCol } from "mdbreact"; - -//> Components -import { SoftwareTabs, ProfileInfo } from "../../index"; -//#endregion - -//#region > Components -/** @class The profile component of a Software Engineer user */ -class SoftwareEngineer extends React.Component { - state = {}; - - render() { - return ( - - - - - - - - - - - ); - } -} -//#endregion - -//#region > Exports -//> Default Component -export default SoftwareEngineer; -//#endregion - -/** - * SPDX-License-Identifier: (EUPL-1.2) - * Copyright © 2019-2020 Simon Prast - */ diff --git a/src/components/organisms/profiles/index.js b/src/components/organisms/profiles/index.js deleted file mode 100644 index e0173b4..0000000 --- a/src/components/organisms/profiles/index.js +++ /dev/null @@ -1,16 +0,0 @@ -//#region > Imports -//> Components -// Import all components to export them for easy access from parent components -import SoftwareEngineer from "./SoftwareEngineer"; -//#endregion - -//#region > Exports -//> Components -// Export the components for easy access from parent components -export { SoftwareEngineer }; -//#endregion - -/** - * SPDX-License-Identifier: (EUPL-1.2) - * Copyright © 2019-2020 Simon Prast - */ diff --git a/src/components/organisms/sections/person/InfoCard/index.jsx b/src/components/organisms/sections/person/InfoCard/index.jsx new file mode 100644 index 0000000..8fd1731 --- /dev/null +++ b/src/components/organisms/sections/person/InfoCard/index.jsx @@ -0,0 +1,349 @@ +//#region > Imports +//> React +// Contains all the functionality necessary to define React components +import React from "react"; +//> MDB +// "Material Design for Bootstrap" is a great UI design framework +import { + MDBBtn, + MDBBadge, + MDBView, + MDBMask, + MDBPopover, + MDBPopoverBody, + MDBPopoverHeader, + MDBIcon, + MDBTooltip, +} from "mdbreact"; +//> Redux +// Allows to React components read data from a Redux store, and dispatch actions +// to the store to update data. +import { connect } from "react-redux"; + +//> Components +import { LanguageChart } from "../../../../atoms"; +//> Style Sheet +import "./infocard.scss"; +//#endregion + +//#region > Components +/** @class This component displays personal information and status of a user */ +class InfoCard extends React.Component { + state = { limitLanguages: true }; + + componentDidMount = () => {}; + + render() { + const { fetchedPerson } = this.props; + + console.log(fetchedPerson); + return ( +
+ + + + +
+

+ {fetchedPerson?.firstName && <>{fetchedPerson.firstName}}{" "} + {fetchedPerson?.lastName && <>{fetchedPerson.lastName}} +

+ {fetchedPerson?.showLocalRanking && ( +

+ + #3 in your region + +

+ )} + {fetchedPerson?.company && ( + <> + {fetchedPerson?.showCompanyPublic && ( + + {fetchedPerson.company} + + )} + + )} +
+ {fetchedPerson?.bids && ( + <> + {fetchedPerson.bids.map((bid, i) => { + switch (bid) { + case "6403bf4d17b8472735a93b71a37e0bd0": + return ( + + Alpha + + ); + } + })} + + )} +
+ {fetchedPerson?.status && ( +
+ {fetchedPerson.status && ( +
+ )} + {fetchedPerson.status} +
+ )} +
+
+ + + Follow + + + + Upvote + +
+
+

Connected accounts

+
+ e.sourceType == "GITHUB" && e.isActive + ) + ? "active" + : "" + } + /> + e.sourceType == "GITLAB" && e.isActive + ) + ? "active" + : "" + } + /> + e.sourceType == "INSTAGRAM" && e.isActive + ) + ? "active" + : "" + } + /> +
+
+

Organisations

+ {fetchedPerson && ( +
= 5 + ? "orgs text-center" + : "orgs" + } + > + {fetchedPerson.person.organisations.length > 0 ? ( + <> + {fetchedPerson.person.organisations.map((org, i) => { + return ( + + +
+ {org.avatarUrl ? ( + {org.name} + ) : ( + + )} + {org.members && ( +
{org.members.length}
+ )} +
+
+
+ +
+ {org.platformName}/ + {org.name} +
+
+
+ + {org.members ? org.members.length : "Unknown"}{" "} + members + +
+
+
+ {org.members && + org.members.length > 0 && + org.members.slice(0, 8).map((member, m) => { + return ( + + + {member.username} + + {member.username} + + ); + })} +
+ {org.members && org.members.length > 9 && ( +
+ {org.platformName === "github" && ( + + Show all + + )} +
+ )} +
+
+
+ +

{org.description}

+ + Show more + + +
+
+
+ ); + })} + + ) : ( + + {fetchedPerson.username} hasn't joined an organisation yet. + + )} +
+ )} + {fetchedPerson.person.statistic?.languages?.length > 0 && ( +
+
+

Top languages

+ + {fetchedPerson.person.statistic.languages + .slice( + 0, + this.state.limitLanguages + ? 3 + : fetchedPerson.person.statistic.languages.length - 1 + ) + .map((language, i) => { + return ( + +
+
+ + {language.name} +
+ + {language.share}% + +
+
+ ); + })} + {this.state.limitLanguages && + fetchedPerson.person.statistic.languages.length > 3 ? ( +

this.setState({ limitLanguages: false })} + > + Show more +

+ ) : ( +

this.setState({ limitLanguages: true })} + > + Show less +

+ )} +
+ )} +
+
+ ); + } +} +//#endregion + +//#region > Redux Mapping +const mapStateToProps = (state) => ({ + fetchedPerson: state.general.fetchedPerson, +}); + +const mapDispatchToProps = (dispatch) => { + return {}; +}; +//#endregion + +//#region > Exports +//> Default Component +/** + * Provides its connected component with the pieces of the data it needs from + * the store, and the functions it can use to dispatch actions to the store. + */ +export default connect(mapStateToProps, mapDispatchToProps)(InfoCard); +//#endregion + +/** + * SPDX-License-Identifier: (EUPL-1.2) + * Copyright © 2019-2020 Simon Prast + */ diff --git a/src/components/organisms/ProfileInfo/profileinfo.scss b/src/components/organisms/sections/person/InfoCard/infocard.scss similarity index 100% rename from src/components/organisms/ProfileInfo/profileinfo.scss rename to src/components/organisms/sections/person/InfoCard/infocard.scss diff --git a/src/components/organisms/SoftwareTabs/index.jsx b/src/components/organisms/sections/person/Tabs/index.jsx similarity index 76% rename from src/components/organisms/SoftwareTabs/index.jsx rename to src/components/organisms/sections/person/Tabs/index.jsx index 3772496..fbb8130 100644 --- a/src/components/organisms/SoftwareTabs/index.jsx +++ b/src/components/organisms/sections/person/Tabs/index.jsx @@ -11,9 +11,9 @@ import { MDBBadge } from "mdbreact"; import { connect } from "react-redux"; //> Components -import { ProjectTab, OverviewTab, TalksTab } from "../tabs"; +import { ProjectTab, OverviewTab, TalksTab } from "../../../tabs"; //> Style sheet -import "./softwaretabs.scss"; +import "./tabs.scss"; //#endregion //#region > Components @@ -30,13 +30,13 @@ class SoftwareTabs extends React.Component { }; isSameOrigin = () => { - const { fetchedUser, loggedUser } = this.props; + const { fetchedPerson, loggedUser } = this.props; - return fetchedUser.username === loggedUser.username; + return fetchedPerson.username === loggedUser.username; }; render() { - const { fetchedUser } = this.props; + const { fetchedPerson } = this.props; const { activeTab } = this.state; const tabItems = [ { @@ -48,8 +48,8 @@ class SoftwareTabs extends React.Component { { title: "Projects", visible: true, - pill: this.props.fetchedUser?.platformData?.profile?.repositories - ? this.props.fetchedUser?.platformData?.profile?.repositories?.length + pill: fetchedPerson?.person?.repositories + ? fetchedPerson?.person?.repositories.length : "0", notification: false, }, @@ -74,9 +74,7 @@ class SoftwareTabs extends React.Component { title: "Talks", visible: true, notification: false, - pill: this.props.fetchedUser?.platformData.talks - ? this.props.fetchedUser?.platformData.talks.length - : "0", + pill: fetchedPerson?.talks ? fetchedPerson?.talks.length : "0", notification: false, }, ]; @@ -100,15 +98,18 @@ class SoftwareTabs extends React.Component {
{activeTab === 0 && ( - + // +

)} {activeTab === 1 && ( )} @@ -117,7 +118,11 @@ class SoftwareTabs extends React.Component { This feature is not available just yet.

)} - {activeTab === 5 && } + {activeTab === 5 && ( + + )}
); @@ -127,8 +132,8 @@ class SoftwareTabs extends React.Component { //#region > Redux Mapping const mapStateToProps = (state) => ({ - loggedUser: state.auth.loggedUser, - fetchedUser: state.user.fetchedUser, + loggedUser: state.user.user, + fetchedPerson: state.general.fetchedPerson, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/components/organisms/SoftwareTabs/softwaretabs.scss b/src/components/organisms/sections/person/Tabs/tabs.scss similarity index 100% rename from src/components/organisms/SoftwareTabs/softwaretabs.scss rename to src/components/organisms/sections/person/Tabs/tabs.scss diff --git a/src/components/organisms/tabs/TalksTab/index.jsx b/src/components/organisms/tabs/TalksTab/index.jsx index 7098cfa..5b0db5b 100644 --- a/src/components/organisms/tabs/TalksTab/index.jsx +++ b/src/components/organisms/tabs/TalksTab/index.jsx @@ -2,6 +2,8 @@ //> React // Contains all the functionality necessary to define React components import React from "react"; +// Runtime type checking for React props and similar objects +import PropTypes from "prop-types"; //> React Router bindings to DOM import { withRouter, Link } from "react-router-dom"; //> MDB @@ -32,7 +34,7 @@ import { TalkUploadModal } from "../../../molecules/modals"; //#region > Components /** @class A component which lists all talks */ -class Talks extends React.Component { +class TalkTab extends React.Component { state = { showUpload: false, loading: true, @@ -50,16 +52,15 @@ class Talks extends React.Component { let iframe; if (talk.interval.loaded === false) { - if (document.getElementById(talk.uid)) { - iframe = document.getElementById(talk.uid); + if (document.getElementById(talk.id)) { + iframe = document.getElementById(talk.id); iframe.src = talk.displayUrl; } } }; render() { - const { loggedUser, fetchedUser } = this.props; - const talkList = fetchedUser?.platformData?.talks; + const { loggedUser, fetchedPerson, talkList } = this.props; if (talkList) { talkList.map((talk) => { @@ -87,7 +88,7 @@ class Talks extends React.Component {

Talks

- {loggedUser.username === fetchedUser.username && ( + {loggedUser.username === fetchedPerson.username && ( - {talk.name.length > 25 - ? talk.name.substring(0, 25) + "..." - : talk.name} + {talk.title.length > 25 + ? talk.title.substring(0, 25) + "..." + : talk.title} - {loggedUser.username === fetchedUser.username && ( + {loggedUser.username === fetchedPerson.username && ( this.props.deleteTalk(talk)}>
-
- )} - - + + )} +
{this.state.modalGitLab && ( Redux Mapping const mapStateToProps = (state) => ({ - //gitlabServers: state.general.allGitlabServers, + gitlabServer: state.general.gitlabServer, }); const mapDispatchToProps = (dispatch) => { return { - //fetchGitLabServers: () => dispatch(fetchGitLabServersAction()) + addProfile: (source) => dispatch(addProfile(source)), + getGitlabServers: () => dispatch(getGitlabServers()), }; }; //#endregion diff --git a/src/components/pages/SettingsPage/index.jsx b/src/components/pages/SettingsPage/index.jsx index 9815a08..8d2a0c3 100644 --- a/src/components/pages/SettingsPage/index.jsx +++ b/src/components/pages/SettingsPage/index.jsx @@ -30,6 +30,8 @@ import { MDBListGroup, MDBListGroupItem, MDBBadge, + MDBAlert, + MDBProgress, } from "mdbreact"; //> Redux // Allows to React components read data from a Redux store, and dispatch actions @@ -44,12 +46,20 @@ import { connect } from "react-redux"; // } from "../../../store/actions/userActions"; //> Components // Profile Picture Editor -import { ProfilePictureModal } from "../../../components/molecules/modals"; +import { + ProfilePictureModal, + ConnectModal, +} from "../../../components/molecules/modals"; //> Style sheet import "./settings.scss"; //> Actions // Functions to send data from the application to the store -import { updateSettings } from "../../../store/actions/personActions"; +import { + updateSettings, + deleteProfile, + updateProfile, +} from "../../../store/actions/personActions"; +import { getPerson as getUserPerson } from "../../../store/actions/userActions"; //#endregion //#region > Components @@ -77,6 +87,8 @@ class SettingsPage extends React.Component { handleLoading = () => { const { loggedUser } = this.props; + console.log("HANDLE LOADING"); + if (loggedUser.anonymous) { this.props.history.push({ pathname: "/", @@ -86,7 +98,7 @@ class SettingsPage extends React.Component { }); } - if (loggedUser?.person && this.state.loading) { + if (loggedUser?.person) { const { avatarImage, bio, @@ -111,32 +123,58 @@ class SettingsPage extends React.Component { profiles, } = loggedUser?.person; - this.setState({ - loading: false, - person: { - avatarImage, - bio, - display2dCalendar, - display3dCalendar, - displayContributionTypes, - displayWeekActivity, - displayImageGallery, - displayVideoGallery, - displayMusicGallery, - displayEmail, - displayProgrammingLanguages, - displayRanking, - displayWorkplace, - email, - firstName, - lastName, - location, - status, - websiteUrl, - workplace, - profiles, - }, - }); + const person = { + avatarImage, + bio, + display2dCalendar, + display3dCalendar, + displayContributionTypes, + displayWeekActivity, + displayImageGallery, + displayVideoGallery, + displayMusicGallery, + displayEmail, + displayProgrammingLanguages, + displayRanking, + displayWorkplace, + email, + firstName, + lastName, + location, + status, + websiteUrl, + workplace, + profiles, + }; + + if (JSON.stringify(this.state.person) !== JSON.stringify(person)) { + this.setState({ + loading: false, + person: { + avatarImage, + bio, + display2dCalendar, + display3dCalendar, + displayContributionTypes, + displayWeekActivity, + displayImageGallery, + displayVideoGallery, + displayMusicGallery, + displayEmail, + displayProgrammingLanguages, + displayRanking, + displayWorkplace, + email, + firstName, + lastName, + location, + status, + websiteUrl, + workplace, + profiles, + }, + }); + } } }; @@ -150,6 +188,28 @@ class SettingsPage extends React.Component { this.handleLoading(); }; + refetch = () => { + const { loggedUser } = this.props; + + if (loggedUser.anonymous) { + this.props.history.push({ + pathname: "/", + state: { + actionCard: 1, + }, + }); + } + + if (loggedUser.person) { + this.setState( + { + loading: true, + }, + () => this.props.getUserPerson(loggedUser.person.slug.split("-")[1]) + ); + } + }; + onDrop = async (files) => { if (files.length > 0) { this.setState({ @@ -213,10 +273,18 @@ class SettingsPage extends React.Component { : false; }; + toggle = (modal) => { + this.setState({ + [modal]: !this.state[modal], + }); + }; + render() { const { loggedUser } = this.props; const { person, activeItem } = this.state; + console.log("STATE", this.state); + if (person) { return ( <> @@ -435,12 +503,22 @@ class SettingsPage extends React.Component {
-
Connections
+
+
Connections
+
+ +
+
+ {this.state.loading && } {person.profiles?.map((profile, p) => { + console.log("PROFILE", profile); return ( -
- - - - - +
+ + + {profile.username ? profile.username : null} + {profile.isAccessTokenExpired && ( + + Expired + + )}
-
+
Type {profile.sourceType}
- Expired + Active
-
- Active - + {profile.isActive ? ( +
+ this.props + .updateProfile(profile.id, { + URL: profile.sourceUrl, + type: profile.sourceType, + authorization: profile.accessToken, + username: profile.username, + isActive: false, + }) + .then(() => this.refetch()) } /> - +
+ ) : ( +
+ + this.props + .updateProfile(profile.id, { + URL: profile.sourceUrl, + type: profile.sourceType, + authorization: profile.accessToken, + username: profile.username, + isActive: true, + }) + .then(() => this.refetch()) + } + /> +
+ )} +
+ + this.props + .deleteProfile(profile.id) + .then(() => this.refetch()) + } + />
); })} -
- Add -
Customization
@@ -582,16 +698,19 @@ class SettingsPage extends React.Component {
- {!this.checkProfileTypeExists("GITHUB") && !this.checkProfileTypeExists("GITLAB") && ( - - Looks like - no profiles are present. You can add one - here! - + + Looks like no + profiles are present. You can add one{" "} + this.setState({ activeItem: 1 })} + > + here! + + )} - Redux Mapping const mapStateToProps = (state) => ({ loggedUser: state.user.user, + person: state.person, }); const mapDispatchToProps = (dispatch) => { return { saveSettings: (nextSettings) => dispatch(updateSettings(nextSettings)), + deleteProfile: (id) => dispatch(deleteProfile(id)), + updateProfile: (id, nextProfile) => + dispatch(updateProfile(id, nextProfile)), + getUserPerson: (user) => dispatch(getUserPerson(user)), }; }; //#endregion diff --git a/src/store/actions/generalActions.js b/src/store/actions/generalActions.js index 52bf782..66b9005 100644 --- a/src/store/actions/generalActions.js +++ b/src/store/actions/generalActions.js @@ -91,3 +91,8 @@ const getAchievements = () => { //#endregion export { getGitlabServers, getPersonsBrief, getAchievements }; + +/** + * SPDX-License-Identifier: (EUPL-1.2) + * Copyright © 2019-2020 Simon Prast + */ diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index edf49be..43b2cb9 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -184,7 +184,7 @@ const getProfiles = (personName) => { const addProfile = ( source = { - url: undefined, + URL: undefined, type: undefined, authorization: undefined, username: undefined, @@ -199,9 +199,7 @@ const addProfile = ( const profile = await INTEL_SNEK.person.addProfile({ personName, - source: { - ...source, - }, + source, }); dispatch({ type: Action.PERSON_PROFILE_ADD_SUCCESS, payload: profile }); @@ -232,6 +230,7 @@ const deleteProfile = (id) => { payload: profiles, }); } catch (ex) { + console.log("FAIL", Action.PERSON_META_LINK_DELETE_FAILURE); dispatch({ type: Action.PERSON_META_LINK_DELETE_FAILURE, payload: { @@ -247,28 +246,19 @@ const deleteProfile = (id) => { const updateProfile = ( id, nextProfile = { - avatarImage: undefined, - bio: undefined, - display2dCalendar: undefined, - display3dCalendar: undefined, - displayEmail: undefined, - displayProgrammingLanguages: undefined, - displayRanking: undefined, - displayWorkplace: undefined, - email: undefined, - firstName: undefined, - lastName: undefined, - location: undefined, - movablePool: undefined, - status: undefined, - websiteUrl: undefined, - workplace: undefined, + URL: undefined, + type: undefined, + authorization: undefined, + username: undefined, + isActive: undefined, } ) => { return async (dispatch, getState, {}) => { try { dispatch({ type: Action.PERSON_PROFILE_UPDATE_REQUEST }); + console.log(nextProfile, id); + const profile = await INTEL_SNEK.person.updateProfile({ profileId: id, toUpdate: { diff --git a/src/store/reducers/generalReducers.js b/src/store/reducers/generalReducers.js index 22c0211..21c9e5e 100644 --- a/src/store/reducers/generalReducers.js +++ b/src/store/reducers/generalReducers.js @@ -22,12 +22,12 @@ const generalReducer = (state = INIT_STATE, action) => { //> Get all gitlab server case Action.GENERAL_GITLAB_SERVER_FETCH_REQUEST: return state; - case Action.GENERAL_GITLAB_SERVER_FETCH_FAILURE: + case Action.GENERAL_GITLAB_SERVER_FETCH_SUCCESS: return { ...state, gitlabServer: action.payload, }; - case Action.GENERAL_GITLAB_SERVER_FETCH_SUCCESS: + case Action.GENERAL_GITLAB_SERVER_FETCH_FAILURE: return { ...state, gitlabServer: undefined, From ef11eb8e3660a39bd18858868128bceae9c001a5 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Sun, 13 Sep 2020 00:50:36 +0200 Subject: [PATCH 111/175] Add connect modal styling Styling has been added to the connect modal. --- .../molecules/modals/ConnectModal/connectmodal.scss | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/components/molecules/modals/ConnectModal/connectmodal.scss diff --git a/src/components/molecules/modals/ConnectModal/connectmodal.scss b/src/components/molecules/modals/ConnectModal/connectmodal.scss new file mode 100644 index 0000000..31d7e7a --- /dev/null +++ b/src/components/molecules/modals/ConnectModal/connectmodal.scss @@ -0,0 +1,12 @@ +#connectmodal { + .btn { + i { + margin: 0; + } + } +} + +/** + * SPDX-License-Identifier: (EUPL-1.2) + * Copyright © 2019-2020 Simon Prast + */ From 91a392a49eae4f62717e929c15549ab3fe47cd4f Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Sun, 13 Sep 2020 00:53:53 +0200 Subject: [PATCH 112/175] Implement gitlab Gitlabs can now be added. --- .../molecules/modals/ConnectModal/index.jsx | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/modals/ConnectModal/index.jsx b/src/components/molecules/modals/ConnectModal/index.jsx index 9661c43..49bae51 100644 --- a/src/components/molecules/modals/ConnectModal/index.jsx +++ b/src/components/molecules/modals/ConnectModal/index.jsx @@ -65,7 +65,19 @@ class ConnectModal extends React.Component { modalGitLab: false, }, () => { - // Do stuff + const gitlab = { + server: this.state.gitlab_server, + username: this.state.gitlab_username, + }; + + this.props + .addProfile({ + URL: gitlab.server, + type: "GITLAB", + authorization: undefined, + username: gitlab.username, + }) + .then(() => this.props.refetch()); } ); }; @@ -118,6 +130,12 @@ class ConnectModal extends React.Component { console.error(response); }; + handleSelectChange = (e) => { + this.setState({ + gitlab_server: e[0], + }); + }; + render() { const { selectedVideoId } = this.props; From c2547a5ba377492729b964e66b8962f18a25feb8 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Sun, 13 Sep 2020 00:55:57 +0200 Subject: [PATCH 113/175] Improve gitlab modal The button is now disabled unless the required info is given. --- src/components/molecules/modals/ConnectModal/index.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/modals/ConnectModal/index.jsx b/src/components/molecules/modals/ConnectModal/index.jsx index 49bae51..54d1e18 100644 --- a/src/components/molecules/modals/ConnectModal/index.jsx +++ b/src/components/molecules/modals/ConnectModal/index.jsx @@ -256,7 +256,13 @@ class ConnectModal extends React.Component { - + Add From f3db888ebf9fe5dbef6fcd876408917191f7bcaa Mon Sep 17 00:00:00 2001 From: schettn Date: Sun, 13 Sep 2020 01:26:24 +0200 Subject: [PATCH 114/175] Improve profile processing A 30 second lock has been implemented which occurs after profile processing is successful. If you are on your own profile at the time the lockdown is released, it will be re-fetched immediately. Otherwise when entering the profile. --- src/components/pages/PersonPage/index.jsx | 6 ++++-- src/store/actions/personActions.js | 9 ++++++++- src/store/reducers/personReducers.js | 8 +++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/components/pages/PersonPage/index.jsx b/src/components/pages/PersonPage/index.jsx index 2d77501..d5acd6d 100644 --- a/src/components/pages/PersonPage/index.jsx +++ b/src/components/pages/PersonPage/index.jsx @@ -50,13 +50,14 @@ class PersonPage extends React.Component { }; componentDidUpdate = async () => { - const { fetchedPerson, loggedUser } = this.props; + const { fetchedPerson, loggedUser, profilesProcessed } = this.props; if ( !this.state.cachingDone && fetchedPerson && loggedUser?.person && - fetchedPerson.slug === loggedUser.person.slug + fetchedPerson.slug === loggedUser.person.slug && + !profilesProcessed ) { await this.props.processProfiles(); @@ -113,6 +114,7 @@ class PersonPage extends React.Component { const mapStateToProps = (state) => ({ loggedUser: state.user.user, fetchedPerson: state.person.fetchedPerson, + profilesProcessed: state.person.profilesProcessed, }); const mapDispatchToProps = (dispatch) => { diff --git a/src/store/actions/personActions.js b/src/store/actions/personActions.js index 43b2cb9..0cb3406 100644 --- a/src/store/actions/personActions.js +++ b/src/store/actions/personActions.js @@ -326,9 +326,16 @@ const processProfiles = () => { personName, }); + await dispatch({ + type: Action.PERSON_PROFILES_PROCESS_SUCCESS, + payload: true, + }); + + await new Promise((resolve) => setTimeout(resolve, 30000)); + dispatch({ type: Action.PERSON_PROFILES_PROCESS_SUCCESS, - payload: posts, + payload: false, }); } catch (ex) { dispatch({ diff --git a/src/store/reducers/personReducers.js b/src/store/reducers/personReducers.js index 8b79908..3ee232f 100644 --- a/src/store/reducers/personReducers.js +++ b/src/store/reducers/personReducers.js @@ -9,6 +9,7 @@ import * as Action from "../types"; //#region > Constant Variables const INIT_STATE = { fetchedPerson: undefined, + profilesProcessed: false, error: undefined, errorDetails: undefined, }; @@ -44,7 +45,6 @@ const personReducer = (state = INIT_STATE, action) => { Action.PERSON_PROFILE_DELETE_SUCCESS | Action.PERSON_PROFILE_UPDATE_SUCCESS | Action.PERSON_INSTAGRAM_POSTS_FETCH_SUCCESS | - Action.PERSON_PROFILES_PROCESS_SUCCESS | Action.PERSON_FOLLOW_SUCCESS | Action.PERSON_UNFOLLOW_SUCCESS | Action.PERSON_LIKE_SUCCESS | @@ -72,6 +72,12 @@ const personReducer = (state = INIT_STATE, action) => { error: action.payload, errorDetails: serializeError(action.payload.error), }; + //> Profile processing + case Action.PERSON_PROFILES_PROCESS_SUCCESS: + return { + ...state, + profilesProcessed: action.payload, + }; //> Get person case Action.PERSON_FETCH_REQUEST: return state; From ffb878fc839a8ca213b1f819f839b23ba7aa8807 Mon Sep 17 00:00:00 2001 From: Christian Aichner Date: Sun, 13 Sep 2020 12:23:42 +0200 Subject: [PATCH 115/175] Implement media sections functionality Some more functionality has been introduced like a young kitten to a new flat. --- .../molecules/modals/AddVideoModal/index.jsx | 2 +- .../modals/InstagramSelectorModal/index.jsx | 57 +++++++++++------- .../sections/media/AIGallery/aigallery.scss | 22 ++++--- .../sections/media/AIGallery/index.jsx | 16 ++++- .../sections/media/AISongGallery/index.jsx | 28 ++++++--- .../media/AIVideoGallery/aivideogallery.scss | 23 ++++---- .../sections/media/AIVideoGallery/index.jsx | 58 +++++++++---------- .../organisms/tabs/OverviewTab/index.jsx | 24 ++++++++ src/store/actions/personActions.js | 8 ++- 9 files changed, 147 insertions(+), 91 deletions(-) diff --git a/src/components/molecules/modals/AddVideoModal/index.jsx b/src/components/molecules/modals/AddVideoModal/index.jsx index 9f1cd3e..cddff16 100644 --- a/src/components/molecules/modals/AddVideoModal/index.jsx +++ b/src/components/molecules/modals/AddVideoModal/index.jsx @@ -94,7 +94,7 @@ class AddVideoModal extends React.Component {

Add YouTube Video

this.props.save(this.state)} > diff --git a/src/components/molecules/modals/InstagramSelectorModal/index.jsx b/src/components/molecules/modals/InstagramSelectorModal/index.jsx index 3e6c096..c81dd62 100644 --- a/src/components/molecules/modals/InstagramSelectorModal/index.jsx +++ b/src/components/molecules/modals/InstagramSelectorModal/index.jsx @@ -24,6 +24,9 @@ import { MDBMask, } from "mdbreact"; +//> Actions +// Functions to send data from the application to the store +import { getInstagramPosts } from "../../../../store/actions/personActions"; //> Style import "./instagramselector.scss"; //#endregion @@ -41,6 +44,12 @@ const DUMMY = [ class InstagramSelectorModal extends React.Component { state = { selection: [] }; + componentDidMount = async () => { + this.setState({ + posts: await this.props.getInstagramPosts(), + }); + }; + updateList = (picture) => { if (this.state.selection.includes(picture)) { const current = this.state.selection; @@ -61,6 +70,7 @@ class InstagramSelectorModal extends React.Component { }; render() { + console.log("REEEEEE", this.state); return ( <>
- {DUMMY.map((picture, i) => { - const selected = this.state.selection.includes(picture); + {this.state.posts && + this.state.posts.map((picture, i) => { + const selected = this.state.selection.includes(picture); - return ( - - - - this.updateList(picture)} - className="text-white d-flex justify-content-center align-items-center" - > - {selected && } - - - - ); - })} + return ( + + + + this.updateList(picture)} + className="text-white d-flex justify-content-center align-items-center" + > + {selected && ( + + )} + + + + ); + })} @@ -119,7 +132,9 @@ const mapStateToProps = (state) => ({ }); const mapDispatchToProps = (dispatch) => { - return {}; + return { + getInstagramPosts: (id) => dispatch(getInstagramPosts(id)), + }; }; //#endregion diff --git a/src/components/organisms/sections/media/AIGallery/aigallery.scss b/src/components/organisms/sections/media/AIGallery/aigallery.scss index ee67a2e..56e4430 100644 --- a/src/components/organisms/sections/media/AIGallery/aigallery.scss +++ b/src/components/organisms/sections/media/AIGallery/aigallery.scss @@ -1,17 +1,15 @@ -#media { - #gallery { - .card { - .card-body { - padding: 0; +#gallery { + .card { + .card-body { + padding: 0; - .mask { - background: transparentize($color: white, $amount: 1); - transition: background 0.1s ease; - cursor: pointer; + .mask { + background: transparentize($color: white, $amount: 1); + transition: background 0.1s ease; + cursor: pointer; - &:hover { - background: transparentize($color: white, $amount: 0.9); - } + &:hover { + background: transparentize($color: white, $amount: 0.9); } } } diff --git a/src/components/organisms/sections/media/AIGallery/index.jsx b/src/components/organisms/sections/media/AIGallery/index.jsx index 82aca79..11b6787 100644 --- a/src/components/organisms/sections/media/AIGallery/index.jsx +++ b/src/components/organisms/sections/media/AIGallery/index.jsx @@ -70,6 +70,10 @@ class AIGallery extends React.Component { }); }; + componentDidUpdate = () => { + console.log("AAAAAAAAAAAAAAA", this.props.loggedUser); + }; + toggle = (modal) => { this.setState({ [modal]: !this.state[modal], @@ -100,7 +104,7 @@ class AIGallery extends React.Component { const { loggedUser } = this.props; return ( -
+