Skip to content

Commit

Permalink
🌺 Lens and Hey v3: v28 (#lens-v3)
Browse files Browse the repository at this point in the history
Summary: Migrated to Lens v3, updating contract references and adding new Apollo cache policies.

Highlights:

• Replaced `LensHub` with `Graph` in `Follow.tsx` and updated related constants.
• Added new `App.ts`, `Feed.ts`, `Graph.ts`, and `Username.ts` files in `abis`.
• Implemented cursor-based pagination in Apollo cache with `createPostsFieldPolicy`.

Read more: https://pierre.co/hey/hey/lens-v3
  • Loading branch information
Yoginth authored and Pierre committed Dec 5, 2024
1 parent 9b05221 commit 9ae4554
Show file tree
Hide file tree
Showing 24 changed files with 5,469 additions and 211 deletions.
2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"ua-parser-js": "2.0.0",
"urlcat": "^3.1.0",
"uuid": "^11.0.2",
"viem": "^2.21.51",
"viem": "^2.21.53",
"zod": "^3.23.8"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"urlcat": "^3.1.0",
"use-resize-observer": "^9.1.0",
"uuid": "^11.0.2",
"viem": "^2.21.51",
"viem": "^2.21.53",
"wagmi": "^2.13.0",
"zod": "^3.23.8",
"zustand": "5.0.1"
Expand Down
47 changes: 7 additions & 40 deletions apps/web/src/components/Composer/NewPublication.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import { POST } from "@hey/data/tracking";
import collectModuleParams from "@hey/helpers/collectModuleParams";
import getAccount from "@hey/helpers/getAccount";
import getMentions from "@hey/helpers/getMentions";
import removeQuoteOn from "@hey/helpers/removeQuoteOn";
import type { CreatePostRequest, Post } from "@hey/indexer";
import type { CreatePostRequest, Post, PostResponse } from "@hey/indexer";
import type { IGif } from "@hey/types/giphy";
import type { NewAttachment } from "@hey/types/misc";
import { Button, Card, ErrorMessage, H6 } from "@hey/ui";
import { Button, Card, H6 } from "@hey/ui";
import { MetadataAttributeType } from "@lens-protocol/metadata";
import dynamic from "next/dynamic";
import type { FC } from "react";
Expand Down Expand Up @@ -165,45 +164,20 @@ const NewPublication: FC<NewPublicationProps> = ({ className, post }) => {
errorToast(error);
};

const onCompleted = (
__typename?:
| "CreateMomokaPublicationResult"
| "LensProfileManagerRelayError"
| "RelayError"
| "RelaySuccess"
) => {
if (
__typename === "RelayError" ||
__typename === "LensProfileManagerRelayError"
) {
const onCompleted = (post?: PostResponse) => {
if (post?.__typename !== "PostResponse") {
return onError();
}

// Reset states
reset();

// Track in leafwatch
const eventProperties = {
comment_on: isComment ? post?.id : null,
post_collect_module: collectModule.type,
post_has_attachments: attachments.length > 0,
post_has_poll: showPollEditor,
post_is_live: showLiveVideoEditor,
post_reference_module: selectedReferenceModule,
post_reference_module_degrees_of_separation:
selectedReferenceModule ===
ReferenceModuleType.DegreesOfSeparationReferenceModule
? degreesOfSeparation
: null,
quote_on: isQuote ? quotedPost?.id : null
};
Leafwatch.track(
isComment ? POST.NEW_COMMENT : isQuote ? POST.NEW_QUOTE : POST.NEW_POST,
eventProperties
isComment ? POST.NEW_COMMENT : isQuote ? POST.NEW_QUOTE : POST.NEW_POST
);
};

const { createPost, error } = useCreatePost({
const { createPost } = useCreatePost({
commentOn: post,
onCompleted,
onError,
Expand Down Expand Up @@ -368,13 +342,6 @@ const NewPublication: FC<NewPublicationProps> = ({ className, post }) => {

return (
<Card className={className} onClick={() => setShowEmojiPicker(false)}>
{error ? (
<ErrorMessage
className="!rounded-none"
error={error}
title="Transaction failed!"
/>
) : null}
<Editor />
{postContentError ? (
<H6 className="mt-1 px-5 pb-3 text-red-500">{postContentError}</H6>
Expand All @@ -385,7 +352,7 @@ const NewPublication: FC<NewPublicationProps> = ({ className, post }) => {
<NewAttachments attachments={attachments} />
{quotedPost ? (
<Wrapper className="m-5" zeroPadding>
<QuotedPost isNew post={removeQuoteOn(quotedPost as Quote)} />
<QuotedPost isNew post={quotedPost as Post} />
</Wrapper>
) : null}
<div className="divider mx-5" />
Expand Down
84 changes: 43 additions & 41 deletions apps/web/src/components/Shared/Account/Follow.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useApolloClient } from "@apollo/client";
import errorToast from "@helpers/errorToast";
import { Leafwatch } from "@helpers/leafwatch";
import { LensHub } from "@hey/abis";
import { LENS_HUB } from "@hey/data/constants";
import { Errors } from "@hey/data/errors";
import { ACCOUNT } from "@hey/data/tracking";
import { type Account, useFollowMutation } from "@hey/indexer";
import selfFundedTransactionData from "@hey/helpers/selfFundedTransactionData";
import sponsoredTransactionData from "@hey/helpers/sponsoredTransactionData";
import {
type Account,
type FollowResponse,
useFollowMutation
} from "@hey/indexer";
import { OptmisticPostType } from "@hey/types/enums";
import type { OptimisticTransaction } from "@hey/types/misc";
import { Button } from "@hey/ui";
Expand All @@ -17,7 +21,8 @@ import { useAccountStatus } from "src/store/non-persisted/useAccountStatus";
import { useGlobalModalStateStore } from "src/store/non-persisted/useGlobalModalStateStore";
import { useAccountStore } from "src/store/persisted/useAccountStore";
import { useTransactionStore } from "src/store/persisted/useTransactionStore";
import { useWriteContract } from "wagmi";
import { sendEip712Transaction, sendTransaction } from "viem/zksync";
import { useWalletClient } from "wagmi";

interface FollowProps {
buttonClassName: string;
Expand All @@ -40,6 +45,7 @@ const Follow: FC<FollowProps> = ({

const [isLoading, setIsLoading] = useState(false);
const { cache } = useApolloClient();
const { data: walletClient } = useWalletClient();

const generateOptimisticFollow = ({
txHash
Expand All @@ -55,62 +61,59 @@ const Follow: FC<FollowProps> = ({

const updateCache = () => {
cache.modify({
fields: {
isFollowedByMe: (existingValue) => {
return { ...existingValue, value: true };
}
},
fields: { isFollowedByMe: () => true },
id: cache.identify(account.operations)
});
};

const onCompleted = (
__typename?: "LensProfileManagerRelayError" | "RelayError" | "RelaySuccess"
) => {
if (
__typename === "RelayError" ||
__typename === "LensProfileManagerRelayError"
) {
const onCompleted = (hash: string, follow?: FollowResponse) => {
if (follow?.__typename !== "FollowResponse") {
return;
}

updateCache();
addTransaction(generateOptimisticFollow({ txHash: hash }));
setIsLoading(false);
toast.success("Followed");
Leafwatch.track(ACCOUNT.FOLLOW, { path: pathname, target: account?.id });
Leafwatch.track(ACCOUNT.FOLLOW, {
path: pathname,
target: account?.address
});
};

const onError = (error: any) => {
setIsLoading(false);
errorToast(error);
};

const { writeContractAsync } = useWriteContract({
mutation: {
onError,
onSuccess: (hash: string) => {
addTransaction(generateOptimisticFollow({ txHash: hash }));
onCompleted();
}
}
});

const write = async ({ args }: { args: any[] }) => {
return await writeContractAsync({
abi: LensHub,
address: LENS_HUB,
args,
functionName: "follow"
});
};

const [follow] = useFollowMutation({
onCompleted: async ({ follow }) => {
if (follow.__typename === "FollowResponse") {
addTransaction(generateOptimisticFollow({ txHash: follow.hash }));
onCompleted(follow.__typename);
} else {
await write({ args: [account.address] });
return onCompleted(follow.hash, follow);
}

if (walletClient) {
if (follow.__typename === "SponsoredTransactionRequest") {
const hash = await sendEip712Transaction(walletClient, {
account: walletClient.account,
...sponsoredTransactionData(follow.raw)
});

return onCompleted(hash);
}

if (follow.__typename === "SelfFundedTransactionRequest") {
const hash = await sendTransaction(walletClient, {
account: walletClient.account,
...selfFundedTransactionData(follow.raw)
});

return onCompleted(hash);
}
}

if (follow.__typename === "TransactionWillFail") {
return toast.error(follow.reason);
}
},
onError
Expand All @@ -128,7 +131,6 @@ const Follow: FC<FollowProps> = ({

try {
setIsLoading(true);

return await follow({
variables: { request: { account: account.address } }
});
Expand Down
76 changes: 48 additions & 28 deletions apps/web/src/components/Shared/Account/Unfollow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import errorToast from "@helpers/errorToast";
import { Leafwatch } from "@helpers/leafwatch";
import { Errors } from "@hey/data/errors";
import { ACCOUNT } from "@hey/data/tracking";
import { type Account, useUnfollowMutation } from "@hey/indexer";
import selfFundedTransactionData from "@hey/helpers/selfFundedTransactionData";
import sponsoredTransactionData from "@hey/helpers/sponsoredTransactionData";
import {
type Account,
type UnfollowResponse,
useUnfollowMutation
} from "@hey/indexer";
import { OptmisticPostType } from "@hey/types/enums";
import type { OptimisticTransaction } from "@hey/types/misc";
import { Button } from "@hey/ui";
Expand All @@ -15,6 +21,8 @@ import { useAccountStatus } from "src/store/non-persisted/useAccountStatus";
import { useGlobalModalStateStore } from "src/store/non-persisted/useGlobalModalStateStore";
import { useAccountStore } from "src/store/persisted/useAccountStore";
import { useTransactionStore } from "src/store/persisted/useTransactionStore";
import { sendEip712Transaction, sendTransaction } from "viem/zksync";
import { useWalletClient } from "wagmi";

interface UnfollowProps {
buttonClassName: string;
Expand All @@ -37,6 +45,7 @@ const Unfollow: FC<UnfollowProps> = ({

const [isLoading, setIsLoading] = useState(false);
const { cache } = useApolloClient();
const { data: walletClient } = useWalletClient();

const generateOptimisticUnfollow = ({
txHash
Expand All @@ -52,29 +61,24 @@ const Unfollow: FC<UnfollowProps> = ({

const updateCache = () => {
cache.modify({
fields: {
isFollowedByMe: (existingValue) => {
return { ...existingValue, value: false };
}
},
fields: { isFollowedByMe: () => false },
id: cache.identify(account.operations)
});
};

const onCompleted = (
__typename?: "LensProfileManagerRelayError" | "RelayError" | "RelaySuccess"
) => {
if (
__typename === "RelayError" ||
__typename === "LensProfileManagerRelayError"
) {
const onCompleted = (hash: string, unfollow?: UnfollowResponse) => {
if (unfollow?.__typename !== "UnfollowResponse") {
return;
}

updateCache();
addTransaction(generateOptimisticUnfollow({ txHash: hash }));
setIsLoading(false);
toast.success("Unfollowed");
Leafwatch.track(ACCOUNT.UNFOLLOW, { path: pathname, target: account?.id });
Leafwatch.track(ACCOUNT.UNFOLLOW, {
path: pathname,
target: account.address
});
};

const onError = (error: any) => {
Expand All @@ -83,22 +87,38 @@ const Unfollow: FC<UnfollowProps> = ({
};

const [unfollow] = useUnfollowMutation({
onCompleted: ({ unfollow }) => {
if (unfollow.__typename === "RelaySuccess") {
addTransaction(generateOptimisticUnfollow({ txHash: unfollow.txHash }));
onCompleted: async ({ unfollow }) => {
if (unfollow.__typename === "UnfollowResponse") {
return onCompleted(unfollow.hash, unfollow);
}

if (walletClient) {
if (unfollow.__typename === "SponsoredTransactionRequest") {
const hash = await sendEip712Transaction(walletClient, {
account: walletClient.account,
...sponsoredTransactionData(unfollow.raw)
});

return onCompleted(hash);
}

if (unfollow.__typename === "SelfFundedTransactionRequest") {
const hash = await sendTransaction(walletClient, {
account: walletClient.account,
...selfFundedTransactionData(unfollow.raw)
});

return onCompleted(hash);
}
}

if (unfollow.__typename === "TransactionWillFail") {
return toast.error(unfollow.reason);
}
onCompleted(unfollow.__typename);
},
onError
});

const unfollowViaLensManager = async (request: UnfollowRequest) => {
const { data } = await unfollow({ variables: { request } });
if (data?.unfollow?.__typename === "LensProfileManagerRelayError") {
return await createUnfollowTypedData({ variables: { request } });
}
};

const handleCreateUnfollow = async () => {
if (!currentAccount) {
setShowAuthModal(true);
Expand All @@ -111,9 +131,9 @@ const Unfollow: FC<UnfollowProps> = ({

try {
setIsLoading(true);
const request: UnfollowRequest = { unfollow: [account?.id] };

return await createUnfollowTypedData({ variables: { request } });
return await unfollow({
variables: { request: { account: account.address } }
});
} catch (error) {
onError(error);
}
Expand Down
Loading

0 comments on commit 9ae4554

Please sign in to comment.