Skip to content

Commit

Permalink
FEATURE: Marketplace Tab V1 Implementation (#675)
Browse files Browse the repository at this point in the history
* STUD-247: Add Marketplace tab to view details song page

* STUD-251: Add wallet connect to marketplace tab (#679)

* STUD-249 UI for active sale (#696)

* STUD-251: Add wallet connect to marketplace tab

* STUD-251: Add the ability to filter wallet by given songs and apply it to the marketplace tab

* STUD-251: Rename component

* STUD-251: Add wallet as a dependency to fetch new song tokens

* STUD-249: Added active sale and create sale UI along with endpoints

* STUD-252: Add ability to create stream token sale

* STUD-252: Add ping functionality for sale end and start

* STUD-252: Add initial logic for sale start and end pending state

* STUD-252: Fix minor details

* STUD-252: Update min sale value

* Stud 275 sale confirmation modal (#697)

* STUD-275: Add start sale summary modal with price breakdown

* STUD-275: Fix Typography component coming from newm vs mui

* STUD-286: Add sale end and sale start ui and modify polling logic (#698)

* STUD-286: Add sale end and sale start ui and modify polling logic

* STUD-293: Add feature flag endpoints for studio and marketplace (#699)

* STUD-293: Add feature flag endpoints for studio and marketplace

* STUD-289: Update change address reference and fix minor refresh bug on ping sale end (#701)
  • Loading branch information
escobarjonatan authored Jul 25, 2024
1 parent ed73384 commit d0a9e3d
Show file tree
Hide file tree
Showing 60 changed files with 1,924 additions and 87 deletions.
1 change: 1 addition & 0 deletions apps/marketplace/src/api/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const recaptchaEndpointActionMap: Record<string, string> = {
generateTransaction: "generate_order_transaction",
getArtist: "get_artist",
getArtists: "get_artists",
getMarketplaceClientConfig: "marketplace_config",
getSale: "get_sale",
getSales: "get_sales",
};
2 changes: 1 addition & 1 deletion apps/marketplace/src/components/ArtistSongs.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Box } from "@mui/material";
import { FunctionComponent } from "react";
import { SaleStatus } from "@newm-web/types";
import Sales from "./Sales";
import { useGetSalesQuery } from "../modules/sale/api";
import { SaleStatus } from "../modules/sale";

interface ArtistSongsProps {
readonly artistId: string;
Expand Down
3 changes: 2 additions & 1 deletion apps/marketplace/src/components/MoreSongs.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { FunctionComponent } from "react";
import { Box, Typography, useTheme } from "@mui/material";
import { SaleStatus } from "@newm-web/types";
import Sales from "./Sales";
import { SaleStatus, useGetSalesQuery } from "../modules/sale";
import { useGetSalesQuery } from "../modules/sale";

interface MoreSongsProps {
readonly artistId?: string;
Expand Down
2 changes: 1 addition & 1 deletion apps/marketplace/src/components/RecentSongs.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Box } from "@mui/material";
import { FunctionComponent } from "react";
import { SaleStatus } from "@newm-web/types";
import Sales from "./Sales";
import { useGetSalesQuery } from "../modules/sale/api";
import { SaleStatus } from "../modules/sale";

const RecentSongs: FunctionComponent = () => {
const { data, isLoading } = useGetSalesQuery({
Expand Down
2 changes: 1 addition & 1 deletion apps/marketplace/src/components/Sale.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { Form, Formik } from "formik";
import { formatNewmAmount } from "@newm-web/utils";
import { useRouter } from "next/navigation";
import { usePlayAudioUrl } from "@newm-web/audio";
import { Sale as SaleItem } from "@newm-web/types";
import { SaleSkeleton } from "../components";
import { Sale as SaleItem } from "../modules/sale";
import { usePurchaseStreamTokensThunk } from "../modules/sale/thunks";

interface FormValues {
Expand Down
2 changes: 1 addition & 1 deletion apps/marketplace/src/components/SaleMetadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FunctionComponent } from "react";
import { Link, Stack, Typography } from "@mui/material";
import theme from "@newm-web/theme";
import moment from "moment";
import { Sale } from "../modules/sale";
import { Sale } from "@newm-web/types";

interface SaleMetaDataProps {
readonly sale?: Sale;
Expand Down
2 changes: 1 addition & 1 deletion apps/marketplace/src/components/Sales.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Box, Grid, Stack, Typography } from "@mui/material";
import { SongCard } from "@newm-web/components";
import { useRouter } from "next/navigation";
import { usePlayAudioUrl } from "@newm-web/audio";
import { Sale } from "@newm-web/types";
import SalesSkeleton from "./skeletons/SalesSkeleton";
import { Sale } from "../modules/sale/types";

interface SalesProps {
readonly hasTitle?: boolean;
Expand Down
3 changes: 2 additions & 1 deletion apps/marketplace/src/components/SearchResults.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { FunctionComponent } from "react";
import { Box, Skeleton, Stack, Typography, useTheme } from "@mui/material";
import { SaleStatus } from "@newm-web/types";
import Sales from "./Sales";
import { SaleStatus, useGetSalesQuery } from "../modules/sale";
import { useGetSalesQuery } from "../modules/sale";

interface SearchResultsProps {
readonly query: string;
Expand Down
3 changes: 2 additions & 1 deletion apps/marketplace/src/components/SimilarSongs.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { FunctionComponent } from "react";
import { Box } from "@mui/material";
import { SaleStatus } from "@newm-web/types";
import Sales from "./Sales";
import { SaleStatus, useGetSalesQuery } from "../modules/sale";
import { useGetSalesQuery } from "../modules/sale";

interface SimilarSongsProps {
readonly currentArtistId?: string;
Expand Down
31 changes: 31 additions & 0 deletions apps/marketplace/src/modules/content/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { GetStudioClientConfigResponse } from "./types";
import { newmApi } from "../../api";
import { setToastMessage } from "../../modules/ui";

export const extendedApi = newmApi.injectEndpoints({
endpoints: (build) => ({
getMarketplaceClientConfig: build.query<
GetStudioClientConfigResponse,
void
>({
async onQueryStarted(body, { dispatch, queryFulfilled }) {
try {
await queryFulfilled;
} catch (error) {
dispatch(
setToastMessage({
message: "An error occurred while fetching app config",
severity: "error",
})
);
}
},

query: () => ({ method: "GET", url: "v1/client-config/marketplace" }),
}),
}),
});

export const { useGetMarketplaceClientConfigQuery } = extendedApi;

export default extendedApi;
2 changes: 2 additions & 0 deletions apps/marketplace/src/modules/content/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./api";
export * from "./types";
9 changes: 9 additions & 0 deletions apps/marketplace/src/modules/content/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// eslint-disable-next-line
interface FeatureFlags {
// When a feature flag is added it will have the following format:
// readonly exampleFlag: boolean;
}

export interface GetStudioClientConfigResponse {
readonly featureFlags: FeatureFlags;
}
4 changes: 2 additions & 2 deletions apps/marketplace/src/modules/sale/api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { transformApiSale } from "@newm-web/utils";
import {
ApiSale,
GenerateOrderRequest,
Expand All @@ -7,8 +8,7 @@ import {
GetSaleResponse,
GetSalesParams,
GetSalesResponse,
} from "./types";
import { transformApiSale } from "./utils";
} from "@newm-web/types";
import { newmApi } from "../../api";
import { setToastMessage } from "../../modules/ui";
import { Tags } from "../../api/newm/types";
Expand Down
2 changes: 0 additions & 2 deletions apps/marketplace/src/modules/sale/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
export * from "./api";
export * from "./types";
export * from "./utils";
2 changes: 1 addition & 1 deletion apps/marketplace/src/modules/sale/thunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
getWalletChangeAddress,
signWalletTransaction,
} from "@newm.io/cardano-dapp-wallet-connector";
import { GenerateOrderRequest } from "./types";
import { GenerateOrderRequest } from "@newm-web/types";
import saleApi from "./api";
import { setToastMessage } from "../ui";

Expand Down
23 changes: 0 additions & 23 deletions apps/marketplace/src/modules/sale/utils.ts

This file was deleted.

2 changes: 1 addition & 1 deletion apps/marketplace/src/temp/data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Sale, SaleStatus } from "../modules/sale/types";
import { Sale, SaleStatus } from "@newm-web/types";

export const mockArtist = {
coverImageUrl:
Expand Down
6 changes: 3 additions & 3 deletions apps/mobile-wallet-connector/src/modules/wallet/thunks.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import {
EnabledWallet,
getWalletChangeAddress,
signWalletTransaction,
} from "@newm.io/cardano-dapp-wallet-connector";
import { asThunkHook } from "@newm-web/utils";
import { asThunkHook, encodeAddress } from "@newm-web/utils";
import { extendedApi as newmApi } from "./api";
import { ChallengeMethod } from "./types";
import { encodeAddress } from "./utils";
import { setConnectionData } from "./slice";
import { setToastMessage } from "../ui";

Expand All @@ -24,7 +24,7 @@ export const connectFromMobile = createAsyncThunk(
let connection;
const adresses = await wallet.getRewardAddresses();
const stakeAddress = encodeAddress(adresses[0]);
const changeAddress = encodeAddress(await wallet.getChangeAddress());
const changeAddress = await getWalletChangeAddress(wallet);
const utxoCborHexList = await wallet.getUtxos("1a001e8480");

if (isHardwareWallet) {
Expand Down
24 changes: 0 additions & 24 deletions apps/mobile-wallet-connector/src/modules/wallet/utils.ts

This file was deleted.

4 changes: 4 additions & 0 deletions apps/studio/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
IdenfyPingUserStatus,
IdenfySuccessSession,
InvitesModal,
PingSaleEnd,
PingSaleStart,
PrivateRoute,
ProgressBarModal,
Toast,
Expand Down Expand Up @@ -51,6 +53,8 @@ const App = () => {
<ProgressBarModal />
<UpdateWalletAddressModal />
<WalletEnvMismatchModal />
<PingSaleStart />
<PingSaleEnd />
<UnsupportedBrowserBanner />
<ScrollToTop />

Expand Down
7 changes: 7 additions & 0 deletions apps/studio/src/api/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@
export const recaptchaEndpointActionMap: Record<string, string> = {
appleLogin: "login_apple",
createAccount: "signup",
endSaleAmount: "generate_sale_end_amount",
endSaleTransaction: "generate_sale_end_transaction",
getSale: "get_sale",
getSales: "get_sales",
getStudioClientConfig: "studio_config",
googleLogin: "login_google",
login: "login",
resetPassword: "password_reset",
sendVerificationEmail: "auth_code",
startSaleAmount: "generate_sale_start_amount",
startSaleTransaction: "generate_sale_start_transaction",
};
1 change: 1 addition & 0 deletions apps/studio/src/api/newm/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const api = createApi({
Tags.Languages,
Tags.Profile,
Tags.Roles,
Tags.Sale,
Tags.Song,
],
});
Expand Down
3 changes: 2 additions & 1 deletion apps/studio/src/api/newm/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export enum Tags {
Languages = "Languages",
Profile = "Profile",
Roles = "Roles",
Song = "Song",
Sale = "Sale",
Song = "Song"
}
18 changes: 6 additions & 12 deletions apps/studio/src/api/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { BaseQueryApi } from "@reduxjs/toolkit/dist/query/baseQueryTypes";
import Cookies from "js-cookie";
import { Mutex } from "async-mutex";
import axios, { AxiosError, AxiosRequestConfig } from "axios";
import { AxiosRequestConfig } from "axios";
import { executeRecaptcha } from "@newm-web/utils";
import { AxiosBaseQueryParams, BaseQuery } from "@newm-web/types";
import { BaseQuery } from "@newm-web/types";
import { logOutExpiredSession, receiveRefreshToken } from "./actions";
import { recaptchaEndpointActionMap } from "./constants";
import { RootState } from "../store";
Expand Down Expand Up @@ -105,18 +105,12 @@ export const getAuthHeaders = (api: BaseQueryApi) => {
*/
export const getRecaptchaHeaders = async (api: BaseQueryApi) => {
const { endpoint } = api;
const state = api.getState() as RootState;
const { isLoggedIn } = state.session;
const action = recaptchaEndpointActionMap[endpoint] || endpoint;

if (!isLoggedIn) {
return {
"g-recaptcha-platform": "Web",
"g-recaptcha-token": await executeRecaptcha(action),
};
}

return {};
return {
"g-recaptcha-platform": "Web",
"g-recaptcha-token": await executeRecaptcha(action),
};
};

/**
Expand Down
26 changes: 26 additions & 0 deletions apps/studio/src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isProd } from "@newm-web/env";

/**
* NEWM External Links and Support
*/
Expand Down Expand Up @@ -35,3 +37,27 @@ export const SKIP_FETCH_INVITE_PATH_LIST = [
"/idenfy-success-session",
"/idenfy-fail-session",
];

export const NEWM_MARKETPLACE_URL = isProd
? "https://marketplace.newm.io"
: "https://fan.square.newm.io";

export const LOCAL_STORAGE_SALE_START_PENDING_KEY = "saleStartSongs";
export const SALE_START_UPDATED_EVENT = "saleStartUpdated";

export const LOCAL_STORAGE_SALE_END_PENDING_KEY = "saleEndSongIds";
export const SALE_END_UPDATED_EVENT = "saleEndUpdated";
/**
* 15 seconds in milliseconds
*/
export const PENDING_SALE_POLLING_INTERVAL = 15000;

/**
* 5 minutes in milliseconds
*/
export const PENDING_SALE_PING_TIMEOUT = 300000;

/**
* Stream token sale default bundle amount
*/
export const SALE_DEFAULT_BUNDLE_AMOUNT = 1;
9 changes: 9 additions & 0 deletions apps/studio/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,12 @@ export interface PlayerState {
readonly loadingSongId?: string;
readonly song?: Song;
}

interface SaleDetails {
tokensToSell: string;
totalSaleValue: string;
}

export interface SaleStartPendingSongs {
[key: string]: SaleDetails;
}
3 changes: 3 additions & 0 deletions apps/studio/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export { default as WalletEnvMismatchModal } from "./WalletEnvMismatchModal";
export { default as AppleLogin } from "./AppleLogin";
export { default as GoogleLogin } from "./GoogleLogin";
export * from "./idenfy";
export { default as PingSaleStart } from "./sales/PingSaleStart";
export { default as PingSaleEnd } from "./sales/PingSaleEnd";
export { default as InvitesModal } from "./invites/InvitesModal";
export { default as NEWMLogo } from "./NEWMLogo";
export { default as SelectWalletItem } from "./uploadSong/SelectWalletItem";
Expand All @@ -24,6 +26,7 @@ export { default as ProgressBar } from "./ProgressBar";
export { default as ProgressBarModal } from "./ProgressBarModal";
export { default as ResponsiveNEWMLogo } from "./ResponsiveNEWMLogo";
export { default as ProfileSkeleton } from "./skeletons/ProfileSkeleton";
export { default as MarketplaceTabSkeleton } from "./skeletons/MarketplaceTabSkeleton";
export { default as LogoutButton } from "./home/LogoutButton";
export { default as SquareGridCard } from "./SquareGridCard";
export { default as Toast } from "./Toast";
Expand Down
Loading

0 comments on commit d0a9e3d

Please sign in to comment.