Skip to content

Commit

Permalink
feat: add seller landing page (#683)
Browse files Browse the repository at this point in the history
* feat: custom store changes

* fix: additional footer links

* wip

* feat: token gating screen

* feat: add sales channels page in seller center

* feat: improve sales channels cards

* feat: congratulations page

* fix: footer styles

* feat: build more pages

* feat: products

* wip

* wip

* fix: bug crash

* wip

* wip

* wip

* wip

* help section

* fix sales channels column and fetching

* copies and images

* font changes create product

* support for non-meta tx

* fix layout

* fix spinner sales channels

* attempt to fix owner query for nonexisten token

* sales channels with products

* lastupdated divided by 1000

* wip

* wip

* wip

* works

* wip

* fix

* fix

* spinner

* reload button in products page

* stop propagation

* some fixes

* token gating

* token gating

* carousel loading

* carousel swipeable

* images

* no tags

* styles

* create product click

* wip

* redesign token gating form

* wip

* wip

* wip

* wip

* typeforms

* wip

* wip

* wip

* wup

* fix: merge

* fix: merge

* chore: remove comment
  • Loading branch information
albertfolch-redeemeum committed Jun 19, 2023
1 parent 8f60660 commit dd552f9
Show file tree
Hide file tree
Showing 57 changed files with 1,833 additions and 191 deletions.
20 changes: 13 additions & 7 deletions src/components/customNavigation/LinkWithQuery.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import { ReactNode } from "react";
import { Link, useLocation } from "react-router-dom";

import { getKeepStoreFieldsQueryParams } from "../../lib/utils/hooks/useKeepQueryParamsNavigate";

type Props = {
children: string | JSX.Element;
export type LinkWithQueryProps = {
children: ReactNode;
to: string;
state?: Record<string, unknown>;
[x: string]: unknown;
search?: Parameters<typeof getKeepStoreFieldsQueryParams>[1];
} & Parameters<typeof Link>[0];
export const LinkWithQuery = ({ children, to, state, ...props }: Props) => {
export const LinkWithQuery = ({
children,
to,
state,
search,
...props
}: LinkWithQueryProps) => {
const location = useLocation();
// TODO: doesnt currently support passing query params in the 'to' parameter
const search = getKeepStoreFieldsQueryParams(location, null);
const searchWithStoreFields = getKeepStoreFieldsQueryParams(location, search);
return (
<Link
to={{
pathname: to,
search
search: searchWithStoreFields
}}
state={{ ...state, prevPath: location.pathname }}
{...props}
Expand Down
14 changes: 7 additions & 7 deletions src/components/customNavigation/Navigate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ import {

import { getKeepStoreFieldsQueryParams } from "../../lib/utils/hooks/useKeepQueryParamsNavigate";

type NavigateProps = Parameters<typeof ReactRouterDomNavigate>[0];
type NavigateProps = Omit<Parameters<typeof ReactRouterDomNavigate>[0], "to"> &
Required<{ to: Partial<Path> }> & {
search?: Parameters<typeof getKeepStoreFieldsQueryParams>[1];
};

export default function Navigate(
props: Omit<NavigateProps, "to"> & Required<{ to: Partial<Path> }>
) {
export default function Navigate({ search, ...props }: NavigateProps) {
const location = useLocation();
// TODO: doesnt currently support passing query params in the 'to' parameter
const search = getKeepStoreFieldsQueryParams(location, null);
const searchWithStoreFields = getKeepStoreFieldsQueryParams(location, search);
return (
<ReactRouterDomNavigate
{...props}
to={{
...props.to,
search
search: searchWithStoreFields
}}
state={{ ...props.state, prevPath: location.pathname }}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/detail/DetailWidget/DetailWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ const DetailWidget: React.FC<IDetailWidget> = ({
isPauseCommitting={!address}
buttonRef={commitButtonRef}
onGetSignerAddress={handleOnGetSignerAddress}
disabled={isCommitDisabled}
disabled={!!isCommitDisabled}
offerId={offer.id}
exchangeToken={offer.exchangeToken.address}
price={offer.price}
Expand Down
5 changes: 4 additions & 1 deletion src/components/footer/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ export const getSellRoutes = ({
}) => {
const isAccountSeller = roles.some((role) => role === UserRoles.Seller);
const productRoutes: { name: string; url: string }[] = [];

productRoutes.push({
name: "Sell",
url: BosonRoutes.Sell
});
productRoutes.push({
name: "Create Products",
url: SellerCenterRoutes.CreateProduct
Expand Down
3 changes: 2 additions & 1 deletion src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ export const layoutPadding = css`
`;

export const LayoutRoot = styled.div<{ fullWidth?: boolean }>`
position: relative;
${({ fullWidth }) => {
if (fullWidth) {
return "";
return css``;
}
return css`
margin: 0 auto;
Expand Down
10 changes: 8 additions & 2 deletions src/components/modal/ModalComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import EscalateModal from "./components/Chat/components/EscalateModal/EscalateMo
import MakeProposalModal from "./components/Chat/MakeProposal/MakeProposalModal";
import ResolveDisputeModal from "./components/Chat/ResolveDisputeModal";
import CompleteExchange from "./components/CompleteExchange";
import { AccountCreationModal } from "./components/createProduct/AccountCreationModal";
import VariableStepsExplainerModal from "./components/createProduct/VariableStepsExplainerModal";
import CreateProductDraft from "./components/CreateProductDraft";
import CustomStore from "./components/CustomStore";
import DetailWidget from "./components/DetailWidget";
Expand Down Expand Up @@ -76,7 +78,9 @@ export const MODAL_TYPES = {
PROFILE_DETAILS: "PROFILE_DETAILS",
IMAGE_EDITOR: "IMAGE_EDITOR",
IFRAME_MODAL: "IFRAME_MODAL",
SALES_CHANNELS: "SALES_CHANNELS"
SALES_CHANNELS: "SALES_CHANNELS",
ACCOUNT_CREATION: "ACCOUNT_CREATION",
VARIABLE_STEPS_EXPLAINER: "VARIABLE_STEPS_EXPLAINER"
} as const;

export const MODAL_COMPONENTS = {
Expand Down Expand Up @@ -118,5 +122,7 @@ export const MODAL_COMPONENTS = {
[MODAL_TYPES.PROFILE_DETAILS]: ProfileDetailsModal,
[MODAL_TYPES.IMAGE_EDITOR]: ImageEditorModal,
[MODAL_TYPES.IFRAME_MODAL]: IframeModal,
[MODAL_TYPES.SALES_CHANNELS]: SalesChannelsModal
[MODAL_TYPES.SALES_CHANNELS]: SalesChannelsModal,
[MODAL_TYPES.ACCOUNT_CREATION]: AccountCreationModal,
[MODAL_TYPES.VARIABLE_STEPS_EXPLAINER]: VariableStepsExplainerModal
} as const;
14 changes: 11 additions & 3 deletions src/components/modal/components/CreateProductDraft.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@ export default function CreateProductDraft({ chooseNew, chooseDraft }: Props) {
Do you wish to continue editing this product or start fresh?
</Typography>
</Grid>
<Grid flexDirection="row" justifyContent="space-between">
<BosonButton variant="primaryFill" onClick={chooseDraft}>
<Grid flexDirection="row" justifyContent="space-between" flexWrap="wrap">
<BosonButton
variant="primaryFill"
onClick={chooseDraft}
style={{ whiteSpace: "pre-line" }}
>
Edit draft
</BosonButton>
<BosonButton variant="accentInverted" onClick={chooseNew}>
<BosonButton
variant="accentInverted"
onClick={chooseNew}
style={{ whiteSpace: "pre-line" }}
>
Start Fresh
</BosonButton>
</Grid>
Expand Down
54 changes: 46 additions & 8 deletions src/components/modal/components/CustomStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,29 @@ import { Copy, CopySimple, Info } from "phosphor-react";
import * as pretty from "pretty";
import { useState } from "react";
import toast from "react-hot-toast";
import { useSearchParams } from "react-router-dom";
import styled from "styled-components";

import Collapse from "../../../components/collapse/Collapse";
import { SellerLandingPageParameters } from "../../../lib/routing/parameters";
import { colors } from "../../../lib/styles/colors";
import copyToClipboard from "../../../lib/utils/copyToClipboard";
import { Notify } from "../../detail/Detail.style";
import { CopyButton } from "../../form/Field.styles";
import BosonButton from "../../ui/BosonButton";
import Grid from "../../ui/Grid";
import Typography from "../../ui/Typography";
import { ModalProps } from "../ModalContext";
import { useModal } from "../useModal";
import {
getNextButtonText,
getNextStepFromQueryParams,
getNextTo,
getSlTitle,
getVariableStepsFromQueryParams,
QueryParamStep,
useRemoveLandingQueryParams,
VariableStep
} from "./createProduct/const";

const CopyIcon = styled(CopySimple)`
cursor: pointer;
Expand Down Expand Up @@ -60,13 +72,11 @@ const StyledCopyButton = styled(CopyButton)`
interface Props {
ipfsUrl: string;
htmlString: string;
hideModal: NonNullable<ModalProps["hideModal"]>;
}
export default function CustomStore({
ipfsUrl = "",
htmlString = "",
hideModal
}: Props) {
export default function CustomStore({ ipfsUrl = "", htmlString = "" }: Props) {
const { showModal, hideModal } = useModal();
const removeLandingQueryParams = useRemoveLandingQueryParams();
const [searchParams] = useSearchParams();
const [show, setShow] = useState<boolean>(false);

const iframeString = htmlString.substring(
Expand Down Expand Up @@ -222,7 +232,35 @@ export default function CustomStore({
<BosonButton
variant="primaryFill"
type="button"
onClick={() => hideModal()}
onClick={() => {
if (searchParams.has(SellerLandingPageParameters.slsteps)) {
const nextStepResult = getNextStepFromQueryParams(
searchParams,
QueryParamStep.store
);
hideModal(!nextStepResult);
if (nextStepResult) {
const title = getSlTitle(searchParams);
showModal("VARIABLE_STEPS_EXPLAINER", {
title,
doSetQueryParams: false,
order: getVariableStepsFromQueryParams(searchParams) as [
VariableStep,
VariableStep,
VariableStep
],
text: "Your storefront is now successfully created!",
buttonText: getNextButtonText(nextStepResult.nextStep),
to: getNextTo(nextStepResult.nextStep),
firstActiveStep: nextStepResult.nextStepInNumber
});
} else {
removeLandingQueryParams();
}
} else {
hideModal(true);
}
}}
>
Done
</BosonButton>
Expand Down
46 changes: 39 additions & 7 deletions src/components/modal/components/Profile/CreateProfileModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { subgraph } from "@bosonprotocol/react-kit";
import { ConnectButton } from "@rainbow-me/rainbowkit";
import { useCallback, useEffect, useState } from "react";
import toast from "react-hot-toast";
import { useAccount } from "wagmi";
Expand All @@ -9,8 +8,10 @@ import { colors } from "../../../../lib/styles/colors";
import { Profile } from "../../../../lib/utils/hooks/lens/graphql/generated";
import useGetLensProfiles from "../../../../lib/utils/hooks/lens/profile/useGetLensProfiles";
import useUpdateSellerMetadata from "../../../../lib/utils/hooks/seller/useUpdateSellerMetadata";
import { useCurrentSellers } from "../../../../lib/utils/hooks/useCurrentSellers";
import { useKeepQueryParamsNavigate } from "../../../../lib/utils/hooks/useKeepQueryParamsNavigate";
import { Switch } from "../../../form/Switch";
import ConnectButton from "../../../header/ConnectButton";
import { CreateProfile } from "../../../product/utils";
import SuccessTransactionToast from "../../../toasts/SuccessTransactionToast";
import BosonButton from "../../../ui/BosonButton";
Expand All @@ -23,18 +24,42 @@ import { ProfileType } from "./const";
import LensProfileFlow from "./Lens/LensProfileFlow";
import { CreateRegularProfileFlow } from "./Regular/CreateRegularProfileFlow";

const waitForIndexedSeller = async (
refetch: ReturnType<typeof useCurrentSellers>["refetch"]
) => {
let i = 0;
while (i < 100) {
const r = await refetch();
const [resultByAddress] = r;
if (resultByAddress.status === "fulfilled") {
const val = resultByAddress.value;
if (val) {
const hasSellers = val.data?.sellers?.length;
if (hasSellers) {
break;
}
}
}
await new Promise<void>((resolve) => setTimeout(() => resolve(), 300));

i++;
}
};

interface Props {
initialRegularCreateProfile: CreateProfile;
initialRegularCreateProfile?: CreateProfile;
onRegularProfileCreated?: (createValues: CreateProfile) => void;
seller?: subgraph.SellerFieldsFragment;
lensProfile?: Profile;
waitUntilIndexed?: boolean;
}

export default function CreateProfileModal({
initialRegularCreateProfile,
onRegularProfileCreated,
seller,
lensProfile: selectedProfile
lensProfile: selectedProfile,
waitUntilIndexed
}: Props) {
const navigate = useKeepQueryParamsNavigate();
const { mutateAsync: updateSellerMetadata } = useUpdateSellerMetadata();
Expand Down Expand Up @@ -67,6 +92,7 @@ export default function CreateProfileModal({
const [switchChecked, setSwitchChecked] = useState<boolean>(
profileType === ProfileType.LENS
);
const { refetch } = useCurrentSellers();
const setSwitchAndProfileType = useCallback((switchToLens: boolean) => {
setSwitchChecked(switchToLens);
setProfileType(switchToLens ? ProfileType.LENS : ProfileType.REGULAR);
Expand Down Expand Up @@ -122,11 +148,13 @@ export default function CreateProfileModal({
if (profileType === undefined && hasLensProfile) {
return <ChooseProfileType setProfileType={setProfileType} />;
}

return profileType === ProfileType.LENS ? (
<LensProfileFlow
onSubmit={async (id, overrides) => {
hideModal(selectedProfile);
if (waitUntilIndexed) {
await waitForIndexedSeller(refetch);
}
hideModal(true);
if (selectedProfile) {
onRegularProfileCreated?.(overrides);
}
Expand All @@ -141,12 +169,16 @@ export default function CreateProfileModal({
) : (
<CreateRegularProfileFlow
initialData={initialRegularCreateProfile}
onSubmit={(regularProfile) => {
onSubmit={async (regularProfile) => {
if (waitUntilIndexed) {
await waitForIndexedSeller(refetch);
}

toast((t) => (
<SuccessTransactionToast t={t} action="Create Seller Account" />
));
onRegularProfileCreated?.(regularProfile);
hideModal();
hideModal(true);
}}
switchButton={SwitchButton}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AuthTokenType } from "@bosonprotocol/react-kit";
import { ConnectButton } from "@rainbow-me/rainbowkit";
import { useCallback, useState } from "react";
import { useAccount } from "wagmi";

Expand All @@ -9,6 +8,7 @@ import useUpdateSellerMetadata from "../../../../lib/utils/hooks/seller/useUpdat
import { useCurrentSellers } from "../../../../lib/utils/hooks/useCurrentSellers";
import { useKeepQueryParamsNavigate } from "../../../../lib/utils/hooks/useKeepQueryParamsNavigate";
import { Switch } from "../../../form/Switch";
import ConnectButton from "../../../header/ConnectButton";
import { CreateProfile } from "../../../product/utils";
import BosonButton from "../../../ui/BosonButton";
import Grid from "../../../ui/Grid";
Expand Down
Loading

0 comments on commit dd552f9

Please sign in to comment.