Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
carina-akaia committed Jan 20, 2025
1 parent 6efcfdc commit 3c35305
Show file tree
Hide file tree
Showing 17 changed files with 160 additions and 117 deletions.
4 changes: 2 additions & 2 deletions src/common/api/near/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ export const naxiosInstance = new naxios({
});

/**
* NEAR Wallet API
* DO NOT USE DIRECTLY!
*/
export const walletApi = naxiosInstance.walletApi();

/**
* NEAR RPC API Provider3
* NEAR JsonRpcProvider
*/
export const nearRpc = naxiosInstance.rpcApi();

Expand Down
4 changes: 2 additions & 2 deletions src/common/viewer/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { WalletProvider } from "./internal/wallet-provider";

export type ViewerSessionProviderProps = {
children: React.ReactNode;
ssrFallback: React.ReactNode;
ssrFallback?: React.ReactNode;
};

/**
Expand All @@ -19,5 +19,5 @@ export const ViewerSessionProvider: React.FC<ViewerSessionProviderProps> = ({
}) => {
const isCsr = useMemo(isClient, []);

return isCsr ? <WalletProvider>{children}</WalletProvider> : ssrFallback;
return isCsr ? <WalletProvider>{children}</WalletProvider> : children;
};
59 changes: 36 additions & 23 deletions src/common/viewer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { prop } from "remeda";
import { PUBLIC_GOODS_REGISTRY_LIST_ID } from "@/common/constants";
import { RegistrationStatus, listsContractHooks } from "@/common/contracts/core/lists";
import { isAccountId } from "@/common/lib";
import { AccountId } from "@/common/types";
import { useGlobalStoreSelector } from "@/store";

import { WalletContext } from "./internal/wallet-context";
Expand All @@ -20,11 +19,11 @@ export const useViewerSession = (): ViewerSession => {
const { actAsDao } = useGlobalStoreSelector(prop("nav"));
const isDaoRepresentative = actAsDao.toggle && Boolean(actAsDao.defaultAddress);

const accountId: AccountId | undefined = useMemo(() => {
if (wallet.isReady) {
const accountId = useMemo(() => {
if (wallet.isSignedIn) {
return isDaoRepresentative ? actAsDao.defaultAddress : wallet.accountId;
} else return undefined;
}, [actAsDao.defaultAddress, isDaoRepresentative, wallet.accountId, wallet.isReady]);
}, [actAsDao.defaultAddress, isDaoRepresentative, wallet.accountId, wallet.isSignedIn]);

/**
* Account for edge cases in which the wallet is connected to a mismatching network
Expand All @@ -39,23 +38,37 @@ export const useViewerSession = (): ViewerSession => {
listId: PUBLIC_GOODS_REGISTRY_LIST_ID,
});

if (wallet.isSignedIn && accountId && isAccountIdValid) {
return {
accountId,
isSignedIn: true,
isMetadataLoading: isRegistrationLoading,
hasRegistrationSubmitted: registration !== undefined,
hasRegistrationApproved: registration?.status === RegistrationStatus.Approved,
registrationStatus: registration?.status,
};
} else {
return {
accountId: undefined,
isSignedIn: false,
isMetadataLoading: false,
hasRegistrationSubmitted: false,
hasRegistrationApproved: false,
registrationStatus: undefined,
};
}
return useMemo(() => {
if (wallet.isReady && wallet.isSignedIn && accountId) {
return {
hasWalletReady: true,
accountId,
isSignedIn: true,
isMetadataLoading: isRegistrationLoading,
hasRegistrationSubmitted: registration !== undefined,
hasRegistrationApproved: registration?.status === RegistrationStatus.Approved,
registrationStatus: registration?.status,
};
} else if (wallet.isReady && !wallet.isSignedIn) {
return {
hasWalletReady: true,
accountId: undefined,
isSignedIn: false,
isMetadataLoading: false,
hasRegistrationSubmitted: false,
hasRegistrationApproved: false,
registrationStatus: undefined,
};
} else {
return {
hasWalletReady: false,
accountId: undefined,
isSignedIn: false,
isMetadataLoading: false,
hasRegistrationSubmitted: false,
hasRegistrationApproved: false,
registrationStatus: undefined,
};
}
}, [accountId, isRegistrationLoading, registration, wallet.isReady, wallet.isSignedIn]);
};
17 changes: 16 additions & 1 deletion src/common/viewer/internal/wallet-context.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
import { createContext } from "react";

import { create } from "zustand";

import type { AccountId } from "@/common/types";

type WalletContextState =
| { isReady: false; isSignedIn: false; accountId: undefined }
| { isReady: true; isSignedIn: boolean; accountId?: AccountId };

export const initialWalletContextState: WalletContextState = {
const initialWalletContextState: WalletContextState = {
isReady: false,
isSignedIn: false,
accountId: undefined,
};

export const WalletContext = createContext<WalletContextState>(initialWalletContextState);

type WalletContextStore = WalletContextState & {
initialize: (isReady: boolean) => void;
setIsSignedIn: (isSignedIn: boolean) => void;
setAccountId: (accountId: AccountId | undefined) => void;
};

export const useWalletContextStore = create<WalletContextStore>((set) => ({
...initialWalletContextState,
initialize: (isReady: boolean) => set(isReady ? { isReady } : initialWalletContextState),
setIsSignedIn: (isSignedIn: boolean) => set({ isSignedIn }),
setAccountId: (accountId: AccountId | undefined) => set({ accountId }),
}));
34 changes: 13 additions & 21 deletions src/common/viewer/internal/wallet-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,38 @@
import { useCallback, useEffect, useState } from "react";

import { nearClient } from "@/common/api/near";
import type { AccountId } from "@/common/types";

import { WalletContext, initialWalletContextState } from "./wallet-context";
import { WalletContext, useWalletContextStore } from "./wallet-context";

export type WalletProviderProps = {
children: React.ReactNode;
};

export const WalletProvider: React.FC<WalletProviderProps> = ({ children }) => {
const [isReady, setIsReady] = useState(false);
const [error, setError] = useState<unknown>(null);
const [isSignedIn, setIsSignedIn] = useState(false);
const [accountId, setAccountId] = useState<AccountId | undefined>(undefined);
const { initialize, setIsSignedIn, setAccountId, ...contextState } = useWalletContextStore();

const syncWalletState = useCallback(() => {
setIsSignedIn(nearClient.walletApi.walletSelector.isSignedIn());
setAccountId(nearClient.walletApi.accountId);
}, []);
}, [setAccountId, setIsSignedIn]);

useEffect(() => {
if (!isReady && error !== null) {
if (!contextState.isReady && error === null) {
nearClient.walletApi
.initNear()
.then(() => setIsReady(true))
.then(() => initialize(true))
.catch((error) => {
console.log(error);
setError(error);
setIsReady(false);
});
}
}, [error, isReady]);
}, [error, initialize, contextState.isReady]);

useEffect(() => {
if (isReady) {
if (contextState.isReady) {
syncWalletState();

nearClient.walletApi.walletSelector.on("signedIn", syncWalletState);
nearClient.walletApi.walletSelector.on("signedOut", syncWalletState);
nearClient.walletApi.walletSelector.on("accountsChanged", syncWalletState);
Expand All @@ -43,21 +41,15 @@ export const WalletProvider: React.FC<WalletProviderProps> = ({ children }) => {
}

return () => {
if (isReady) {
if (contextState.isReady) {
nearClient.walletApi.walletSelector.off("signedIn", syncWalletState);
nearClient.walletApi.walletSelector.off("signedOut", syncWalletState);
nearClient.walletApi.walletSelector.off("accountsChanged", syncWalletState);
nearClient.walletApi.walletSelector.off("networkChanged", syncWalletState);
nearClient.walletApi.walletSelector.off("uriChanged", syncWalletState);
}
};
}, [syncWalletState, isReady]);

return (
<WalletContext.Provider
value={isReady ? { isReady, isSignedIn, accountId } : initialWalletContextState}
>
{children}
</WalletContext.Provider>
);
}, [syncWalletState, contextState.isReady]);

return <WalletContext.Provider value={contextState}>{children}</WalletContext.Provider>;
};
23 changes: 17 additions & 6 deletions src/common/viewer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,29 @@ import { AccountId } from "@/common/types";

export type ViewerSession =
| {
accountId: AccountId;
registrationStatus?: RegistrationStatus;
isSignedIn: true;
isMetadataLoading: boolean;
hasRegistrationSubmitted: boolean;
hasRegistrationApproved: boolean;
hasWalletReady: false;
accountId: undefined;
registrationStatus: undefined;
isSignedIn: false;
isMetadataLoading: false;
hasRegistrationSubmitted: false;
hasRegistrationApproved: false;
}
| {
hasWalletReady: true;
accountId: undefined;
registrationStatus: undefined;
isSignedIn: false;
isMetadataLoading: false;
hasRegistrationSubmitted: false;
hasRegistrationApproved: false;
}
| {
hasWalletReady: true;
accountId: AccountId;
registrationStatus?: RegistrationStatus;
isSignedIn: true;
isMetadataLoading: boolean;
hasRegistrationSubmitted: boolean;
hasRegistrationApproved: boolean;
};
9 changes: 7 additions & 2 deletions src/entities/campaign/components/CampaignSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ import Link from "next/link";
import { walletApi } from "@/common/api/near/client";
import { useRouteQuery, yoctoNearToFloat } from "@/common/lib";
import { NearIcon } from "@/common/ui/svg";
import { useViewerSession } from "@/common/viewer";
import { AccountProfilePicture } from "@/entities/_shared/account";

import { CampaignForm } from "./CampaignForm";
import { useCampaignDeploymentRedirect } from "../hooks/redirects";
import { useCampaign } from "../hooks/useCampaign";

export const CampaignSettings = () => {
// TODO: Move this call to the corresponding page!
useCampaignDeploymentRedirect();
const [openEditCampaign, setOpenEditCampaign] = useState<boolean>(false);

const {
query: { campaignId },
} = useRouteQuery();

const viewer = useViewerSession();
const [openEditCampaign, setOpenEditCampaign] = useState<boolean>(false);
const { campaign } = useCampaign({ campaignId: campaignId as string });

if (!campaign) return <></>;
Expand Down Expand Up @@ -61,7 +64,8 @@ export const CampaignSettings = () => {
</Link>
</div>
</div>
{walletApi.accountId === campaign?.owner && (

{viewer.isSignedIn && viewer.accountId === campaign?.owner && (
<div>
<p
onClick={() => setOpenEditCampaign(!openEditCampaign)}
Expand All @@ -73,6 +77,7 @@ export const CampaignSettings = () => {
</div>
)}
</div>

{!openEditCampaign ? (
<div className="mt-8 w-full rounded-[12px] border border-solid border-[#DBDBDB] p-6">
<div>
Expand Down
17 changes: 10 additions & 7 deletions src/entities/campaign/hooks/forms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ import { FieldErrors, SubmitHandler, useForm, useWatch } from "react-hook-form";
import { Temporal } from "temporal-polyfill";
import { infer as FromSchema, ZodError } from "zod";

import { walletApi } from "@/common/api/near/client";
import { campaignsContractClient } from "@/common/contracts/core";
import { floatToYoctoNear, useRouteQuery } from "@/common/lib";
import { useViewerSession } from "@/common/viewer";
import { dispatch } from "@/store";

import { campaignFormSchema } from "../models/schema";
import { CampaignEnumType } from "../types";

export const useCampaignForm = () => {
const viewer = useViewerSession();

const {
// TODO: Pass this values down from the page level!
query: { campaignId },
} = useRouteQuery();

Expand Down Expand Up @@ -66,7 +69,7 @@ export const useCampaignForm = () => {
...(values.end_ms && {
end_ms: timeToMiliSeconds(values.end_ms.toString()).epochMilliseconds,
}),
...(campaignId ? {} : { owner: walletApi.accountId as string }),
...(campaignId ? {} : { owner: viewer.accountId as string }),
...(campaignId ? {} : { recipient: values.recipient }),
};

Expand All @@ -76,23 +79,23 @@ export const useCampaignForm = () => {
});

dispatch.campaignEditor.updateCampaignModalState({
header: `You’ve successfully created a campaignsContractClient for ${values.name}.`,
header: `You’ve successfully created a campaign for ${values.name}.`,
description:
"If you are not a member of the project, the campaignsContractClient will be considered unofficial until it has been approved by the project.",
"If you are not a member of the project, the campaign will be considered unofficial until it has been approved by the project.",
type: CampaignEnumType.UPDATE_CAMPAIGN,
});
} else {
campaignsContractClient.create_campaign({ args });

dispatch.campaignEditor.updateCampaignModalState({
header: `You’ve successfully created a campaignsContractClient for ${values.name}.`,
header: `You’ve successfully created a campaign for ${values.name}.`,
description:
"If you are not a member of the project, the campaignsContractClient will be considered unofficial until it has been approved by the project.",
"If you are not a member of the project, the campaign will be considered unofficial until it has been approved by the project.",
type: CampaignEnumType.CREATE_CAMPAIGN,
});
}
},
[campaignId],
[campaignId, viewer.accountId],
);

const onChange = async (field: keyof Values, value: string) => {
Expand Down
5 changes: 3 additions & 2 deletions src/entities/list/components/ListCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { useRouter } from "next/router";
import { FaHeart } from "react-icons/fa";
import { LazyLoadImage } from "react-lazy-load-image-component";

import { walletApi } from "@/common/api/near/client";
import { listsContractClient } from "@/common/contracts/core";
import { truncate } from "@/common/lib";
import { LayersIcon } from "@/common/ui/svg";
import { LikeIcon } from "@/common/ui/svg/like";
import { useViewerSession } from "@/common/viewer";
import { AccountProfilePicture } from "@/entities/_shared/account";
import { dispatch } from "@/store";

Expand All @@ -24,11 +24,12 @@ export const ListCard = ({
background?: string;
backdrop: string;
}) => {
const viewer = useViewerSession();
const [isUpvoted, setIsUpvoted] = useState(false);
const { push } = useRouter();

useEffect(() => {
setIsUpvoted(dataForList.upvotes?.some((data: any) => data?.account === walletApi.accountId));
setIsUpvoted(dataForList.upvotes?.some((data: any) => data?.account === viewer.accountId));
}, [dataForList]);

const handleRoute = useCallback(
Expand Down
Loading

0 comments on commit 3c35305

Please sign in to comment.