Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

add feature user redirection to onboarding app #41

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ module.exports = {
V5: "https://api.topcoder-dev.com/v5",
},
REAUTH_OFFSET: 55, // seconds
PROFILE_CREATION_DATE_THRESHOLD: "2019-01-01", // format: "YYYY-MM-DD"
};
27 changes: 25 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import React, { useState, useCallback, useMemo, useEffect } from "react";
import _ from "lodash";
import MainMenu from "./components/MainMenu";
import NavBar from "./components/NavBar";
import { Router } from "@reach/router";
import { navigate, Router } from "@reach/router";
import { useSelector } from "react-redux";
import useMatchSomeRoute from "./hooks/useMatchSomeRoute";
import NotificationsModal from "./components/NotificationsModal";
import "./styles/main.module.scss";
import { checkOnboarding, checkProfileCreationDate } from "./utils";
import { getOnboardingChecklist } from "./services/auth";

const App = () => {
// all menu options
Expand All @@ -18,10 +20,14 @@ const App = () => {
const apps = useMemo(() => _.flatMap(menu, "apps"), [menu]);
// list of routes where we have to disabled sidebar
const disabledRoutes = useSelector((state) => state.menu.disabledRoutes);
// user profile information
const auth = useSelector((state) => state.auth);
// `true` is sidebar has to be disabled for the current route
const isSideBarDisabled = useMatchSomeRoute(disabledRoutes);
// Left sidebar collapse state
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
// hide switch tools and notification when user is onboarding
const [hideSwitchTools, setHideSwitchTools] = useState(false);
// Toggle left sidebar callback
const toggleSidebar = useCallback(() => {
setSidebarCollapsed(!sidebarCollapsed);
Expand All @@ -43,9 +49,26 @@ const App = () => {
}
}, [isSideBarDisabled]);

useEffect(() => {
(async () => {
if (auth?.profile && checkProfileCreationDate(auth?.profile)) {
const { profile, tokenV3 } = auth;

const response = await getOnboardingChecklist(profile?.handle, tokenV3);
const onboardingPath = checkOnboarding(response);
if (onboardingPath) {
setHideSwitchTools(true);
navigate(onboardingPath);
} else {
setHideSwitchTools(false);
}
}
})();
}, [auth]);

return (
<>
<NavBar />
<NavBar hideSwitchTools={hideSwitchTools} />
{!isSideBarDisabled && (
<div className="main-menu-wrapper">
<Router>
Expand Down
21 changes: 16 additions & 5 deletions src/components/NavBar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import React, {
useMemo,
} from "react";
import _ from "lodash";
import PropTypes from "prop-types";
import UserMenu from "../UserMenu";
import AllAppsMenu from "../AllAppsMenu";
import { useSelector } from "react-redux";
Expand All @@ -21,7 +22,7 @@ import "./styles.css";
import { useMediaQuery } from "react-responsive";
import NotificationsMenu from "../NotificationsMenu";

const NavBar = () => {
const NavBar = ({ hideSwitchTools }) => {
// all menu options
const menu = useSelector((state) => state.menu.categories);
// flat list of all apps
Expand Down Expand Up @@ -54,7 +55,9 @@ const NavBar = () => {
<div className="navbar">
<div className="navbar-left">
{isMobile ? (
<AllAppsMenu />
hideSwitchTools ? null : (
<AllAppsMenu />
)
) : (
<Fragment>
<Link to="/">
Expand Down Expand Up @@ -88,7 +91,7 @@ const NavBar = () => {
(auth.tokenV3 ? (
auth.profile && (
<Fragment>
<NotificationsMenu />
{hideSwitchTools ? null : <NotificationsMenu />}
<UserMenu profile={auth.profile} />
</Fragment>
)
Expand All @@ -100,13 +103,13 @@ const NavBar = () => {
</Fragment>
) : (
<Fragment>
<AllAppsMenu appChange={changeApp} />
{hideSwitchTools ? null : <AllAppsMenu appChange={changeApp} />}
<div className="navbar-divider"></div>
{auth.isInitialized &&
(auth.tokenV3 ? (
auth.profile && (
<Fragment>
<NotificationsMenu />
{hideSwitchTools ? null : <NotificationsMenu />}
<UserMenu profile={auth.profile} />
</Fragment>
)
Expand All @@ -122,4 +125,12 @@ const NavBar = () => {
);
};

NavBar.defaultProps = {
hideSwitchTools: false,
};

NavBar.propTypes = {
hideSwitchTools: PropTypes.boolean,
};

export default NavBar;
12 changes: 12 additions & 0 deletions src/services/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,15 @@ export function authenticate(store) {
}
});
}

/**
* Get the onboarding checklist data to know completed steps
*/
export function getOnboardingChecklist(username, userTokenV3) {
const fetcher = getFetcher(userTokenV3);
return fetcher(
`${config.API.V5}/members/${username}/traits?traitIds=onboarding_checklist`
)
.then((res) => res.json())
.then((res) => ({ data: res || [] }));
}
69 changes: 69 additions & 0 deletions src/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import _ from 'lodash';
import moment from "moment";
import config from "../../config";

/**
Expand Down Expand Up @@ -45,3 +47,70 @@ export const login = () => {
export const businessLogin = () => {
window.location = getBusinessLoginUrl();
};

/**
* TODO: Re-check when onboarding processor is ready
* Check Onboarding API
*
* @param resp {Object} User trait object
*
* @returns {boolean | string}
*/
export function checkOnboarding(resp) {
if (resp?.data.length === 0) {
return false;
}
const data = resp?.data.filter(
(item) => item.traitId === "onboarding_checklist"
)[0].traits.data[0].profile_completed;
if (data.status === "completed") {
return false;
}

// TODO: Re-check when onboarding processor is ready.
// It checks for at least one onboarding checklist was completed, then we don't enter onboarding flow
// This logic will be changed.
for (const item in data.metadata) {
if (data.metadata[item]) {
return false;
}
}

const steps = {
"/onboard/": ["profile_picture", "skills"],
"/onboard/contact-details": ["country"],
"/onboard/payments-setup": [],
"/onboard/build-my-profile": ["bio", "work", "education", "language"],
};
if (data.status === "pending_at_user") {
const flags = Object.keys(data.metadata);
for (const step of Object.keys(steps)) {
for (const flag of steps[step]) {
if (flags.indexOf(flag) >= 0 && !data.metadata[flag]) {
return step;
}
}
}
}
return false;
}

/**
* Checks If current user's profile creation time
*
* @param profile {Object} user profile
*
* @returns {boolean}
*/
export const checkProfileCreationDate = (profile) => {
const thresholdDate = moment(
config.PROFILE_CREATION_DATE_THRESHOLD,
"YYYY-MM-DD"
);

if (profile?.createdAt) {
return thresholdDate.isBefore(moment(profile?.createdAt));
}

return false;
};