Skip to content

Commit

Permalink
feat: Create Portfolio (#253)
Browse files Browse the repository at this point in the history
  • Loading branch information
Xavier-Charles authored Mar 1, 2024
1 parent a2b4cf5 commit 36e0aed
Show file tree
Hide file tree
Showing 26 changed files with 678 additions and 105 deletions.
22 changes: 21 additions & 1 deletion packages/frontend/src/MobileApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,19 @@ import "./customIonicStyles.scss";
const SuperfeedPage = lazyRetry(() => import("./mobile-pages/superfeed"));
const Placeholder = lazyRetry(() => import("./mobile-pages/placeholder"));
const AuthPage = lazyRetry(() => import("./mobile-pages/auth"));
const FiltersPage = lazyRetry(() => import("./mobile-pages/filters"));
const PortfolioPage = lazyRetry(() => import("./mobile-pages/portfolio"));
const NotificationsPage = lazyRetry(
() => import("./mobile-pages/notifications")
);
const UserSettingsPage = lazyRetry(
() => import("./mobile-pages/user-settings")
);
const ConnectWalletPage = lazyRetry(
() => import("./mobile-pages/connect-wallet")
);
const AddWalletPage = lazyRetry(() => import("./mobile-pages/add-wallet"));
const AddHoldingPage = lazyRetry(() => import("./mobile-pages/add-holding"));

const CustomNavTab: React.FC<{
label: string;
Expand Down Expand Up @@ -78,8 +85,21 @@ const TabNavigator: React.FC = () => {
<Placeholder />
</Route>
<Route exact path="/portfolio">
<Placeholder />
<PortfolioPage />
</Route>
<Route path="/portfolio/connect-wallet" exact>
<ConnectWalletPage />
</Route>
<Route path="/portfolio/add-wallet" exact>
<AddWalletPage />
</Route>
<Route path="/filters" exact component={FiltersPage} />

<Route
path="/portfolio/add-holding"
exact
component={AddHoldingPage}
/>
<Route exact path="/auth*">
<AuthPage />
</Route>
Expand Down
6 changes: 5 additions & 1 deletion packages/frontend/src/api/services/coins/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export type TRemoteCoin = TBaseCoin & {
*/

// /coins/
export type TGetCoinsRequest = { tags?: string; limit?: number } | void;
export type TGetCoinsRequest = {
tags?: string;
limit?: number;
page?: number;
} | void;
export type TGetCoinsRawResponse = TPagination & {
results: TRemoteCoin[];
};
Expand Down
9 changes: 9 additions & 0 deletions packages/frontend/src/api/types/portfolio.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { TCoin } from "./primitives";

export type TPortfolioToken = {
id: string;
networkId: number;
Expand Down Expand Up @@ -33,3 +35,10 @@ export type TPortfolio = {
updatedAt: string;
token: TPortfolioToken;
};

// TODO: Update this type to match the API response
export type THolding = {
coin: TCoin;
amount: number;
date: Date;
};
2 changes: 2 additions & 0 deletions packages/frontend/src/api/types/primitives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ export type TCryptoAccount = {
// networkId: number | undefined;
address: string | null;
ens?: string | null;
// name given by user
name?: string | null;
};

export enum ECookieChoice {
Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/src/assets/icons/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions packages/frontend/src/assets/icons/copy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions packages/frontend/src/assets/icons/hand.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions packages/frontend/src/assets/icons/wallet.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion packages/frontend/src/containers/base/BaseContainerMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,10 @@ const BaseContainerMenu: FC<IBaseContainerMenu> = ({
"cursor-not-allowed bg-transparent opacity-50"
)}
>
<CloseSVG style={IconStyle} className="icon" />
<CloseSVG
style={IconStyle}
className="icon text-primaryVariant200"
/>

<div className="break-word w-full px-3 py-0 fontGroup-normal">
Remove Widget
Expand Down
74 changes: 0 additions & 74 deletions packages/frontend/src/mobile-components/navigation/NavBottom.tsx

This file was deleted.

98 changes: 98 additions & 0 deletions packages/frontend/src/mobile-components/portfolio/AddHolding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { FC } from "react";
import { FormInput, Pager, ScrollBar } from "@alphaday/ui-kit";
import moment from "moment";
import { useHistory } from "react-router";
import { TCoin, THolding } from "src/api/types";

interface IAddHolding {
selectedCoin: TCoin;
setSelectedCoin: React.Dispatch<React.SetStateAction<TCoin | undefined>>;
holding: THolding | undefined;
setHolding: React.Dispatch<React.SetStateAction<THolding | undefined>>;
}

const AddHolding: FC<IAddHolding> = ({
selectedCoin,
setSelectedCoin,
holding,
setHolding,
}) => {
const history = useHistory();

const defaultHolding: THolding = {
coin: selectedCoin,
amount: 0,
date: new Date(),
};

const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setHolding((prev) => ({
...(prev || defaultHolding),
amount: parseInt(e.target.value, 10),
}));
};
const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setHolding((prev) => ({
...(prev || defaultHolding),
date: new Date(e.target.value),
}));
};

return (
<ScrollBar>
<Pager
title={
<span className="inline-flex items-center">
<img
className="w-6 h-6 rounded-full mr-2"
src={selectedCoin.icon}
alt=""
/>{" "}
<span className="text-primaryVariant100 mr-1 font-semibold">
{selectedCoin.ticker}
</span>{" "}
{selectedCoin.name}
</span>
}
handleClose={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
handleBack={() => setSelectedCoin(undefined)}
/>
<div className="flex flex-col items-center mt-4 mx-4">
<FormInput
type="number"
label="Amount"
placeholder="Enter amount"
value={holding?.amount || 0}
onChange={handleAmountChange}
name="name"
className="outline-none px-4 py-3"
min={0}
/>
<div className="mt-5 w-full">
<FormInput
type="date"
label="Amount"
placeholder="Enter date"
value={moment(holding?.date).format("YYYY-MM-DD")}
onChange={handleDateChange}
name="amount"
className="outline-none px-4 py-3"
/>
</div>
</div>
<div className="flex justify-center mt-5">
<button
type="button"
className="px-4 py-3 w-full mx-4 bg-accentVariant100 hover:bg-accentVariant200 text-primary rounded-md fontGroup-highlightSemi cursor-pointer disabled:bg-gray-600 disabled:opacity-30"
onClick={() => {}}
>
Add Holding
</button>
</div>
</ScrollBar>
);
};

export default AddHolding;
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { FC, FormEvent } from "react";
import { Input, Pager, ScrollBar, Spinner } from "@alphaday/ui-kit";
import { useHistory } from "react-router";
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";

interface ISelectHoldingCoin {
onScroll: ({ currentTarget }: FormEvent<HTMLElement>) => void;
onInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
inputValue: string;
isLoadingCoinsData: boolean;
coins: TCoin[] | undefined;
setSelectedCoin: React.Dispatch<React.SetStateAction<TCoin | undefined>>;
}

const SelectHoldingCoin: FC<ISelectHoldingCoin> = ({
onScroll,
onInputChange,
inputValue,
isLoadingCoinsData,
coins,
setSelectedCoin,
}) => {
const history = useHistory();

return (
<ScrollBar onScroll={onScroll}>
<Pager
title="Add Manually"
handleClose={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
/>
<p className="mx-4 fontGroup-highlight">
Search or select the desired crypto coin that you have in your
portfolio.
</p>
<div className="fontGroup-normal relative w-full">
<Input
onChange={onInputChange}
id="widgetlib-search"
name="widgetlib-search"
placeholder="Search..."
height="44px"
value={inputValue}
className="mx-auto pl-8 text-primary placeholder:text-primaryVariant200 fontGroup-highlight outline-none border-none focus:outline-none focus:border-none bg-backgroundVariant200"
/>
<SearchSVG
className="h-4 w-4 absolute top-3.5 left-5 text-primaryVariant200"
aria-hidden="true"
/>
</div>
<p className="mx-4 mt-7">Or simply select from the list below.</p>

<div className="mx-4">
{isLoadingCoinsData ? (
<div className="w-full flex justify-center mt-20">
<Spinner />
</div>
) : (
coins?.map((coin) => (
<div
onClick={() => {
setSelectedCoin(coin);
}}
role="button"
tabIndex={0}
key={coin.id}
className="flex items-center justify-between py-4 border-t border-borderLine cursor-pointer hover:bg-backgroundVariant100"
>
<div className="flex items-center">
<img
src={coin.icon}
alt={coin.name}
className="w-5 h-5"
/>
<span className="ml-3 fontGroup-highlight font-semibold">
{coin.name}
</span>
</div>
<ChevronSVG className="w-5 h-5" />
</div>
))
)}
</div>
</ScrollBar>
);
};

export default SelectHoldingCoin;
Loading

0 comments on commit 36e0aed

Please sign in to comment.