Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Mobile App navigation #369

Merged
merged 9 commits into from
Mar 28, 2024
Merged
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
80 changes: 48 additions & 32 deletions packages/frontend/src/MobileApp.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Suspense, memo } from "react";
import { memo } from "react";
import {
IonApp,
IonRouterOutlet,
@@ -15,10 +15,13 @@ import { useAuth } from "./api/hooks";
import { useGetFeaturesQuery } from "./api/services";
import CONFIG from "./config";
import ToastContainer from "./containers/toasts/ToastContainer";
import PreloaderPage from "./pages/preloader";
import "@alphaday/ui-kit/global.scss";
import "./customIonicStyles.scss";
import { EMobileRoutePaths, mobileRoutes } from "./routes";
import {
EMobileRoutePaths,
EMobileTabRoutePaths,
mobileRoutes,
} from "./routes";

const { IS_DEV } = CONFIG;

@@ -51,49 +54,62 @@ const MobileApp: React.FC = () => {
<IonReactRouter>
<IonTabs>
<IonRouterOutlet ionPage>
<Suspense fallback={<PreloaderPage />}>
{mobileRoutes.map((route) => {
if (route.type === "redirect") {
return (
<Redirect
key={route.path}
path={route.path}
to={route.redirectTo}
exact={route.exact ?? false}
/>
);
}
// if the route is authwalled, let's just redirect to superfeed page.
if (route.authWalled && !isAuthenticated) {
return (
<Redirect
key={route.path}
path={route.path}
to={EMobileRoutePaths.Superfeed}
exact={route.exact ?? false}
/>
);
}
{mobileRoutes.map((route) => {
if (route.type === "redirect") {
return (
<Redirect
key={route.path}
path={route.path}
to={route.redirectTo}
exact={route.exact ?? false}
/>
);
}
if (route.type === "fallback") {
return (
<Route
render={() => (
<Redirect to={route.redirectTo} />
)}
/>
);
}
// if the route is authwalled, let's just redirect to superfeed page.
if (route.authWalled && !isAuthenticated) {
return (
<Redirect
key={route.path}
path={route.path}
to={EMobileRoutePaths.Superfeed}
exact={route.exact ?? false}
render={() => <route.component />}
/>
);
})}
</Suspense>
}
return (
<Route
key={route.path}
path={route.path}
exact={route.exact ?? false}
render={() => <route.component />}
/>
);
})}
</IonRouterOutlet>
<IonTabBar slot="bottom">
<IonTabButton tab="superfeed" href="/superfeed">
<IonTabButton
tab="superfeed"
href={EMobileTabRoutePaths.Superfeed}
>
<CustomNavTab
label="Superfeed"
Icon={SuperfeedSVG}
/>
</IonTabButton>
{IS_DEV && (
<IonTabButton tab="market" href="/market">
<IonTabButton
tab="market"
href={EMobileTabRoutePaths.Market}
>
<CustomNavTab
label="Market"
Icon={MarketsSVG}
@@ -102,7 +118,7 @@ const MobileApp: React.FC = () => {
)}
<IonTabButton
tab="portfolio"
href="/portfolio"
href={EMobileTabRoutePaths.Portfolio}
disabled={!IS_DEV}
>
<CustomNavTab
1 change: 1 addition & 0 deletions packages/frontend/src/api/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -32,3 +32,4 @@ export * from "./useQuery";
export * from "./useValueWatcher";
export * from "./useOnScreen";
export * from "./usePullToRefresh";
export * from "./useHistory";
26 changes: 26 additions & 0 deletions packages/frontend/src/api/hooks/useHistory.ts
elcharitas marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useCallback } from "react";
import { useHistory as useRRDHistory } from "react-router-dom";
import { EMobileTabRoutePaths } from "src/routes";

export const useHistory = () => {
const history = useRRDHistory();

/**
* we shouldn't need this ideally, but adding a listener
* ensures route navigation to tabs route paths which is great
*/
history.listen(() => {});

const backNavigation = useCallback(() => {
if (history.length > 0) {
history.goBack();
} else {
history.push(EMobileTabRoutePaths.Superfeed);
}
}, [history]);

return {
...history,
backNavigation,
};
};
7 changes: 6 additions & 1 deletion packages/frontend/src/layout/PagedMobileLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FC, ReactNode } from "react";
import { Pager, ScrollBar } from "@alphaday/ui-kit";
import { useHistory } from "src/api/hooks";

const PagedMobileLayout: FC<{
title: string;
@@ -8,11 +9,15 @@ const PagedMobileLayout: FC<{
handleClose?: () => void;
handleBack?: () => void;
}> = ({ children, title, onScroll, handleBack, handleClose }) => {
const { backNavigation } = useHistory();
return (
<ScrollBar className="h-screen flex flex-col" onScroll={onScroll}>
<Pager
title={title}
handleBack={handleBack}
handleBack={() => {
handleBack?.();
backNavigation();
}}
handleClose={handleClose}
/>
<div className="w-full flex flex-grow flex-col">{children}</div>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC } from "react";
import { FormInput, Pager, ScrollBar } from "@alphaday/ui-kit";
import moment from "moment";
import { useHistory } from "react-router";
import { useHistory } from "src/api/hooks";
import { TCoin, THolding } from "src/api/types";

interface IAddHolding {
@@ -54,9 +54,7 @@ const AddHolding: FC<IAddHolding> = ({
{selectedCoin.name}
</span>
}
handleClose={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
handleClose={history.backNavigation}
handleBack={() => setSelectedCoin(undefined)}
/>
<div className="flex flex-col items-center mt-4 mx-4">
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC, FormEvent } from "react";
import { Input, Pager, ScrollBar, Spinner } from "@alphaday/ui-kit";
import { useHistory } from "react-router";
import { useHistory } from "src/api/hooks";
import { TCoin } from "src/api/types";
import { ReactComponent as ChevronSVG } from "src/assets/icons/chevron-right.svg";
import { ReactComponent as SearchSVG } from "src/assets/svg/search.svg";
@@ -26,12 +26,7 @@ const SelectHoldingCoin: FC<ISelectHoldingCoin> = ({

return (
<ScrollBar onScroll={onScroll}>
<Pager
title="Add Manually"
handleClose={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
/>
<Pager title="Add Manually" handleClose={history.backNavigation} />
<p className="mx-4 fontGroup-highlight">
Search or select the desired crypto coin that you have in your
portfolio.
7 changes: 2 additions & 5 deletions packages/frontend/src/mobile-pages/add-wallet.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState } from "react";
import { FormInput, MiniDialog, Pager } from "@alphaday/ui-kit";
import { useHistory } from "react-router";
import { usePortfolioAccount } from "src/api/hooks";
import { usePortfolioAccount, useHistory } from "src/api/hooks";
import { validateEthAddr } from "src/api/utils/accountUtils";
import { ReactComponent as GreenCheckSVG } from "src/assets/icons/green-check.svg";
import { EMobileRoutePaths } from "src/routes";
@@ -37,9 +36,7 @@ const AddWalletPage = () => {
<>
<Pager
title="Add wallet address"
handleClose={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
handleClose={history.backNavigation}
/>
<div className="flex flex-col items-center mt-4 mx-4">
<FormInput
60 changes: 26 additions & 34 deletions packages/frontend/src/mobile-pages/auth.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useState, useRef, useCallback } from "react";
import { MiniDialog } from "@alphaday/ui-kit";
import { IonPage } from "@ionic/react";
import { useHistory } from "react-router-dom";
import { useAuth } from "src/api/hooks";
import { EAuthMethod } from "src/api/types";
@@ -10,6 +9,7 @@ import { toast } from "src/api/utils/toastUtils";
import { ReactComponent as GreenCheckSVG } from "src/assets/icons/green-check.svg";
import { Auth } from "src/components/auth/Auth";
import PagedMobileLayout from "src/layout/PagedMobileLayout";
import { EMobileRoutePaths } from "src/routes";

const AuthPage: React.FC = () => {
const [email, setEmail] = useState("");
@@ -66,44 +66,36 @@ const AuthPage: React.FC = () => {
* If user is already authenticated, redirect to home page
*/
if (isInitiallyAuthenticated) {
history.push("/");
history.push(EMobileRoutePaths.Superfeed);
return null;
}

const handleBack = () => {
resetAuthState();
if (history.length > 1) history.goBack();
else history.push("/");
};

return (
<IonPage>
<PagedMobileLayout
title="Continue with Email"
handleBack={handleBack}
<PagedMobileLayout
title="Continue with Email"
handleBack={resetAuthState}
>
<Auth
email={email}
authState={authState}
handleOtpSubmit={handleOtpSubmit}
handleSSOCallback={handleSSOCallback}
handleEmailSubmit={handleEmailSubmit}
handleEmailChange={handleEmailChange}
/>
<MiniDialog
show={isAuthenticated}
icon={<GreenCheckSVG />}
title="CONGRATS"
onActionClick={() => {
history.push(EMobileRoutePaths.Superfeed);
}}
>
<Auth
email={email}
authState={authState}
handleOtpSubmit={handleOtpSubmit}
handleSSOCallback={handleSSOCallback}
handleEmailSubmit={handleEmailSubmit}
handleEmailChange={handleEmailChange}
/>
<MiniDialog
show={isAuthenticated}
icon={<GreenCheckSVG />}
title="CONGRATS"
onActionClick={() => {
history.push("/");
}}
>
<div className="text-center text-sm font-normal leading-tight tracking-tight text-slate-300">
Your account has been created!
</div>
</MiniDialog>
</PagedMobileLayout>
</IonPage>
<div className="text-center text-sm font-normal leading-tight tracking-tight text-slate-300">
Your account has been created!
</div>
</MiniDialog>
</PagedMobileLayout>
);
};

9 changes: 2 additions & 7 deletions packages/frontend/src/mobile-pages/connect-wallet.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import { OutlineButton, Pager } from "@alphaday/ui-kit";
import { useHistory } from "react-router";
import { useHistory } from "src/api/hooks";
import { ReactComponent as MetamaskSVG } from "src/assets/icons/metamask.svg";
import { ReactComponent as WalletConnectSVG } from "src/assets/icons/wallet-connect.svg";

const ConnectWalletPage = () => {
const history = useHistory();
return (
<>
<Pager
title="Connect wallet"
handleBack={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
/>
<Pager title="Connect wallet" handleBack={history.backNavigation} />
<div className="w-full flex px-5 mt-4 fontGroup-highlight !font-bold">
Select your preferred wallet provider to conect to your
portfolio
26 changes: 8 additions & 18 deletions packages/frontend/src/mobile-pages/notifications.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useState } from "react";
import { IonPage } from "@ionic/react";
import { useHistory } from "react-router";
import { useAuth } from "src/api/hooks";
import { EFeedItemType } from "src/api/types";
import PagedMobileLayout from "src/layout/PagedMobileLayout";
@@ -82,7 +80,6 @@ const mockNotifications = [
];

const NotificationsPage = () => {
const history = useHistory();
const { isAuthenticated } = useAuth();

const [notifications, setNotifications] = useState(mockNotifications);
@@ -96,21 +93,14 @@ const NotificationsPage = () => {
setNotifications((prev) => prev.filter((n) => n.id !== id));
};
return (
<IonPage>
<PagedMobileLayout
title="Notifications"
handleBack={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
>
<Notifications
isAuthenticated={isAuthenticated}
notifications={notifications}
markAsRead={markAsRead}
removeNotification={removeNotification}
/>
</PagedMobileLayout>
</IonPage>
<PagedMobileLayout title="Notifications">
<Notifications
isAuthenticated={isAuthenticated}
notifications={notifications}
markAsRead={markAsRead}
removeNotification={removeNotification}
/>
</PagedMobileLayout>
);
};

9 changes: 3 additions & 6 deletions packages/frontend/src/mobile-pages/placeholder.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { IonPage } from "@ionic/react";
import MobileLayout from "src/layout/MobileLayout";

const PlaceholderPage: React.FC = () => {
return (
<IonPage>
<MobileLayout>
<h1 className="mx-6 my-10 fontGroup-major">Placeholder</h1>
</MobileLayout>
</IonPage>
<MobileLayout>
<h1 className="mx-6 my-10 fontGroup-major">Placeholder</h1>
</MobileLayout>
);
};

10 changes: 2 additions & 8 deletions packages/frontend/src/mobile-pages/portfolio.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { FC } from "react";
import { Pager } from "@alphaday/ui-kit";
import { useHistory } from "react-router";
import { useAuth } from "src/api/hooks";
import { useAuth, useHistory } from "src/api/hooks";
import { ReactComponent as CloseSVG } from "src/assets/icons/close.svg";
import { ReactComponent as InfoSVG } from "src/assets/icons/Info2.svg";
import WalletConnectionOptions from "src/mobile-components/portfolio/WalletConnectionOptions";
@@ -37,12 +36,7 @@ const PortfolioPage = () => {
// TODO if user has holdings route to holdings
return (
<>
<Pager
title="Portfolio"
handleBack={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
/>
<Pager title="Portfolio" />
<TopSection isAuthenticated={isAuthenticated} />
<WalletConnectionOptions
isAuthenticated={isAuthenticated}
37 changes: 17 additions & 20 deletions packages/frontend/src/mobile-pages/superfeed.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useState } from "react";
import { IonPage } from "@ionic/react";
import md5 from "md5";
import { useParams, useHistory } from "react-router-dom";
import { useAccount } from "src/api/hooks";
@@ -17,25 +16,23 @@ const SuperfeedPage: React.FC = () => {
const toggleFeedFilters = () => history.push(EMobileRoutePaths.UserFilters);

return (
<IonPage>
<MobileLayout
avatar={
userProfile?.user.email
? `https://www.gravatar.com/avatar/${md5(
userProfile.user.email
).toString()}?d=retro`
: undefined
}
onSearchHandleClick={() => setShowSearchBar((show) => !show)}
>
<AuthPromptContainer />
<SuperfeedContainer
tags={tags}
showSearchBar={showSearchBar}
onToggleFeedFilters={toggleFeedFilters}
/>
</MobileLayout>
</IonPage>
<MobileLayout
avatar={
userProfile?.user.email
? `https://www.gravatar.com/avatar/${md5(
userProfile.user.email
).toString()}?d=retro`
: undefined
}
onSearchHandleClick={() => setShowSearchBar((show) => !show)}
>
<AuthPromptContainer />
<SuperfeedContainer
tags={tags}
showSearchBar={showSearchBar}
onToggleFeedFilters={toggleFeedFilters}
/>
</MobileLayout>
);
};

17 changes: 3 additions & 14 deletions packages/frontend/src/mobile-pages/user-filters.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
import { IonPage } from "@ionic/react";
import { useHistory } from "react-router-dom";
import PagedMobileLayout from "src/layout/PagedMobileLayout";
import UserFiltersContainer from "src/mobile-containers/UserFiltersContainer";

const UserSettings: React.FC = () => {
const history = useHistory();

return (
<IonPage>
<PagedMobileLayout
title="Superfeed filters"
handleBack={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
>
<UserFiltersContainer />
</PagedMobileLayout>
</IonPage>
<PagedMobileLayout title="Superfeed filters">
<UserFiltersContainer />
</PagedMobileLayout>
);
};

17 changes: 3 additions & 14 deletions packages/frontend/src/mobile-pages/user-settings.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
import { IonPage } from "@ionic/react";
import { useHistory } from "react-router-dom";
import PagedMobileLayout from "src/layout/PagedMobileLayout";
import UserSettingsContainer from "src/mobile-containers/UserSettingsContainer";

const UserSettings: React.FC = () => {
const history = useHistory();

return (
<IonPage>
<PagedMobileLayout
title=""
handleBack={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
>
<UserSettingsContainer />
</PagedMobileLayout>
</IonPage>
<PagedMobileLayout title="">
<UserSettingsContainer />
</PagedMobileLayout>
);
};

41 changes: 17 additions & 24 deletions packages/frontend/src/routes.ts
Original file line number Diff line number Diff line change
@@ -101,6 +101,13 @@ export const errorRoutes: IRoute[] = [
*/

const BASE_TABS_ROUTE = "/";

export enum EMobileTabRoutePaths {
Superfeed = `${BASE_TABS_ROUTE}superfeed`,
Portfolio = `${BASE_TABS_ROUTE}portfolio`,
Market = `${BASE_TABS_ROUTE}market`,
}

export enum EMobileRoutePaths {
Base = BASE_TABS_ROUTE,
Superfeed = `${BASE_TABS_ROUTE}superfeed`,
@@ -132,13 +139,17 @@ type TMobileRoute =
redirectTo: string;
exact?: boolean;
type: "redirect";
}
| {
redirectTo: string;
type: "fallback";
};
export const mobileRoutes: TMobileRoute[] = [
{
path: EMobileRoutePaths.Base,
component: SuperfeedPage,
redirectTo: EMobileRoutePaths.Superfeed,
exact: true,
type: "regular",
type: "redirect",
},
{
path: EMobileRoutePaths.Superfeed,
@@ -220,30 +231,12 @@ export const mobileRoutes: TMobileRoute[] = [
type: "regular",
},
/**
* The following are desktop routes.
* Ideally we would just use a wildcard `*` to handle all routes that doesn't
* match those listed above. However, that approach is not working correctly for some
* reason.
* Fallback route.
*
* This redirects all non-existing routes to the superfeed tab.
*/
{
path: EDesktopRoutePaths.Boards,
redirectTo: EMobileRoutePaths.Superfeed,
type: "redirect",
},
{
path: EDesktopRoutePaths.Calendar,
redirectTo: EMobileRoutePaths.Superfeed,
type: "redirect",
},
{
path: EDesktopRoutePaths.CalendarEvent,
redirectTo: EMobileRoutePaths.Superfeed,
type: "redirect",
type: "fallback",
},
// this doesn't work with IonTabs
// {
// path: "*",
// redirectTo: EMobileRoutePaths.Superfeed,
// type: "redirect",
// },
];