Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor-cart #265

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"react-dom": "^18.2.0",
"react-i18next": "^14.1.2",
"react-icons": "^5.3.0",
"react-virtualized": "^9.22.5",
"server-only": "^0.0.1",
"sonner": "^1.3.1",
"tailwind-merge": "^2.2.1",
Expand All @@ -59,6 +60,7 @@
"@types/node": "^20.11.6",
"@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18",
"@types/react-virtualized": "^9.21.30",
"@vercel/analytics": "^1.1.2",
"@vercel/blob": "^0.19.0",
"@vercel/speed-insights": "^1.0.7",
Expand Down
11 changes: 6 additions & 5 deletions src/app/cart/hooks/use-checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const useCheckout = () => {
const initialCurrentChainId = useChainId()
const { address: userAddress } = useAccount()
const { data: walletClient } = useWalletClient()
const { cartItems, resetCart, setCartItems } = useCart()
const { cartItems, resetCart, removeCartItem } = useCart()
const { mint, nonce: mintNonce, listHasBeenMinted } = useMintEFP()

const [currentChainId, setCurrentChainId] = useState(initialCurrentChainId)
Expand Down Expand Up @@ -155,7 +155,7 @@ const useCheckout = () => {
setListOpsFinished(true)

if (hash) {
setCartItems(cartItems.filter(item => !items.includes(item)))
items.forEach(item => removeCartItem(item.listOp))
queryClient.invalidateQueries({ queryKey: ['following'] })
queryClient.invalidateQueries({ queryKey: ['profile'] })
}
Expand Down Expand Up @@ -183,7 +183,7 @@ const useCheckout = () => {
const splitSize = LIST_OP_LIMITS[chainId || DEFAULT_CHAIN.id] || 1000

for (let i = 0; i < cartItems.length; i += splitSize) {
splitListOps.push(cartItems.slice(i, i + splitSize))
splitListOps.push(Array.from(cartItems.values()).slice(i, i + splitSize))
}

const cartItemActions: Action[] = splitListOps.map((listOps, i) => ({
Expand Down Expand Up @@ -282,8 +282,9 @@ const useCheckout = () => {
}, [moveToNextAction, executeActionByIndex, getRequiredChain, currentChainId, currentActionIndex])

const onFinish = useCallback(() => {
const regex = /Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
if (regex.test(navigator.userAgent)) track(`${listHasBeenMinted ? 'Mint' : 'Checkout'} - Mobile`)
const regex = /Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
if (regex.test(navigator.userAgent))
track(`${listHasBeenMinted ? 'Mint' : 'Checkout'} - Mobile`)
else track(`${listHasBeenMinted ? 'Mint' : 'Checkout'} - Desktop`)

if (fetchFreshStats) refetchStats()
Expand Down
18 changes: 11 additions & 7 deletions src/app/cart/hooks/useImportModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import type { Address } from 'viem'
import { useEffect, useMemo, useState } from 'react'
import { init, useQuery, useQueryWithPagination } from '@airstack/airstack-react'

import { useCart } from '#/contexts/cart-context'
import { listOpAddListRecord } from '#/utils/list-ops'
import type { ImportPlatformType } from '#/types/common'
import { useEFPProfile } from '#/contexts/efp-profile-context'
import { useCart, type CartItem } from '#/contexts/cart-context'

init('0366bbe276e04996af5f92ebb7899f19', { env: 'dev', cache: true })

Expand All @@ -28,7 +28,7 @@ const useImportModal = (platform: ImportPlatformType) => {
const [onlyImportWithEns, setOnlyImportWithEns] = useState(true)
const [isFollowingsLoading, setIsFollowingsLoading] = useState(false)

const { cartItems, setCartItems, getAddressesFromCart } = useCart()
const { cartItems, getAddressesFromCart, setCartItems } = useCart()
const { allFollowingAddresses } = useEFPProfile()

useEffect(() => {
Expand Down Expand Up @@ -144,12 +144,16 @@ const useImportModal = (platform: ImportPlatformType) => {
getAddressesFromCart().includes(addr.toLowerCase())
)
)
.map(followingAddress => ({
listOp: listOpAddListRecord(followingAddress.address as Address),
import: platform
}))
.map(
followingAddress =>
({
listOp: listOpAddListRecord(followingAddress.address as Address),
import: platform
}) as CartItem
)
.concat(Array.from(cartItems.values()))

setCartItems([...cartItems, ...newCartItems])
setCartItems(newCartItems)
}

const alreadyFollow = followings.filter(({ address: addr }) =>
Expand Down
1 change: 1 addition & 0 deletions src/app/swipe/components/loading-recommended-cards.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useTranslation } from "react-i18next";

import UserProfileCard from "#/components/user-profile-card";
import type { ProfileDetailsResponse } from "#/types/requests";

Expand Down
4 changes: 2 additions & 2 deletions src/components/follow-button/hooks/use-follow-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,13 @@ export const useFollowButton = ({

// remove address and tags for this address from cart if it's a pending follow
if (buttonState === 'Pending Following') {
const addressTags = cartItems.filter(item =>
const addressTags = Array.from(cartItems.values()).filter(item =>
item.listOp.opcode > 2 && isTagListOp(item.listOp)
? extractAddressAndTag(item.listOp).address === address
: false
)
removeCartItem(listOpAddListRecord(address))
addressTags.flatMap(item => removeCartItem(item.listOp))
addressTags.forEach(item => removeCartItem(item.listOp))
return
}
// remove from cart if it's a pending unfollow
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from "react";
import type { Address } from "viem";
import { useQuery } from "@tanstack/react-query";

Expand All @@ -24,52 +25,54 @@ export interface FollowListItemProps {
isBlockedBy?: boolean;
}

const FollowListItem: React.FC<FollowListItemProps> = ({
className = "",
address,
ensProfile,
showFollowsYouBadges,
showTags,
tags,
counts,
isFollowers,
canEditTags,
isBlockedList,
isBlockedBy,
}) => {
const { data: fetchedEnsProfile, isLoading: isEnsProfileLoading } = useQuery({
queryKey: ["ens metadata", address],
queryFn: async () => (ensProfile ? ensProfile : await resolveEnsProfile(address)),
});
const FollowListItem: React.FC<FollowListItemProps> = React.memo(
({
className = "",
address,
ensProfile,
showFollowsYouBadges,
showTags,
tags,
counts,
isFollowers,
canEditTags,
isBlockedList,
isBlockedBy,
}) => {
const { data: fetchedEnsProfile, isLoading: isEnsProfileLoading } = useQuery({
queryKey: ["ens metadata", address],
queryFn: async () => (ensProfile ? ensProfile : await resolveEnsProfile(address)),
});

const profileName = fetchedEnsProfile?.name;
const profileAvatar = fetchedEnsProfile?.avatar;
const profileName = fetchedEnsProfile?.name;
const profileAvatar = fetchedEnsProfile?.avatar;

return (
<div
className={cn(
"flex items-center justify-between hover:bg-text/5 transition-all p-1.5 2xl:p-2 rounded-xl",
className
)}
>
{/* Left section: Avatar, Name, and Tags */}
<FollowListItemName
address={address}
avatarUrl={profileAvatar}
name={profileName}
counts={counts}
showFollowsYouBadges={showFollowsYouBadges}
showTags={showTags}
tags={tags}
isFollowers={isFollowers}
canEditTags={canEditTags}
isEnsProfileLoading={isEnsProfileLoading}
isBlockedList={isBlockedList}
/>
{/* Right section: Follow Button with consistent width */}
<FollowButton isBlockedBy={isBlockedBy} address={address} />
</div>
);
};
return (
<div
className={cn(
"flex items-center justify-between hover:bg-text/5 transition-all p-1.5 2xl:p-2 rounded-xl",
className
)}
>
{/* Left section: Avatar, Name, and Tags */}
<FollowListItemName
address={address}
avatarUrl={profileAvatar}
name={profileName}
counts={counts}
showFollowsYouBadges={showFollowsYouBadges}
showTags={showTags}
tags={tags}
isFollowers={isFollowers}
canEditTags={canEditTags}
isEnsProfileLoading={isEnsProfileLoading}
isBlockedList={isBlockedList}
/>
{/* Right section: Follow Button with consistent width */}
<FollowButton isBlockedBy={isBlockedBy} address={address} />
</div>
);
}
);

export default FollowListItem;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface SocialFollowButtonProps {

const SocialFollowButton: React.FC<SocialFollowButtonProps> = ({ profiles }) => {
const { t } = useTranslation();
const { cartItems, setCartItems } = useCart();
const { cartItems, removeCartItem } = useCart();

const removeCarItems = async () => {
const address = profiles?.[0]?.address;
Expand All @@ -26,7 +26,7 @@ const SocialFollowButton: React.FC<SocialFollowButtonProps> = ({ profiles }) =>
: !addresses.includes(`0x${item.listOp.data.toString("hex")}`.toLowerCase())
);

setCartItems(filteredCartItems);
filteredCartItems.forEach((item) => removeCartItem(item.listOp));
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,14 @@ const SocialTagDropdown: React.FC<SocialTagDropdownProps> = ({ profiles, platfor
setTagDropdownOpen(false);
});

const { cartItems, setCartItems, hasListOpAddTag, hasListOpRemoveTag, getTagsFromCartByAddress } =
useCart();
const {
cartItems,
addCartItem,
removeCartItem,
hasListOpAddTag,
hasListOpRemoveTag,
getTagsFromCartByAddress,
} = useCart();
const { t } = useTranslation();
const { recentTags, addRecentTag } = useEFPProfile();

Expand All @@ -51,7 +57,7 @@ const SocialTagDropdown: React.FC<SocialTagDropdownProps> = ({ profiles, platfor
import: platform,
}));

setCartItems([...cartItems, ...newCartItems]);
newCartItems.forEach((item) => addCartItem(item));
}
};

Expand All @@ -64,15 +70,15 @@ const SocialTagDropdown: React.FC<SocialTagDropdownProps> = ({ profiles, platfor
setDisplayedTags((prevTags) => prevTags.filter((prevTag) => prevTag !== tag));
await yieldToMain();

const filteredCartItems = cartItems.filter(
const filteredCartItems = Array.from(cartItems.values()).filter(
(item) =>
!(isTagListOp(item.listOp)
? addresses.includes(extractAddressAndTag(item.listOp).address.toLowerCase()) &&
extractAddressAndTag(item.listOp).tag === tag
: false)
);

setCartItems(filteredCartItems);
filteredCartItems.forEach((item) => removeCartItem(item.listOp));
};

const addCustomTag = () => {
Expand Down
35 changes: 33 additions & 2 deletions src/components/follow-list/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Address } from "viem";
import { List } from "react-virtualized";
import { useTranslation } from "react-i18next";
import Image, { type StaticImageData } from "next/image";

Expand Down Expand Up @@ -126,7 +127,7 @@ export function FollowList({
</div>
)
)}
{profiles?.map(({ address, tags, ens, counts }) => (
{/* {profiles?.map(({ address, tags, ens, counts }) => (
<FollowListItem
className={listItemClassName}
key={address}
Expand All @@ -141,7 +142,37 @@ export function FollowList({
isBlockedBy={isBlockedBy}
isFollowers={isFollowers}
/>
))}
))} */}
<List
autoHeight={true}
autoWidth={true}
height={100000}
width={2000}
rowCount={profiles?.length || 0}
rowHeight={64}
className="gap-1"
rowRenderer={({ key, index }) => {
const profile = profiles?.[index];
if (!profile) return null;

return (
<FollowListItem
className={listItemClassName}
key={profile.address}
address={profile.address}
ensProfile={profile.ens}
showFollowsYouBadges={showFollowsYouBadges}
showTags={showTags}
tags={profile.tags}
counts={profile.counts}
canEditTags={canEditTags}
isBlockedList={isBlockedList}
isBlockedBy={isBlockedBy}
isFollowers={isFollowers}
/>
);
}}
/>
{isLoadingMore &&
new Array(loadingRows)
.fill(1)
Expand Down
24 changes: 2 additions & 22 deletions src/components/top-eight/hooks/use-edit-top-eight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const useEditTopEight = (profiles: TopEightProfileType[]) => {
const { cartItems, addCartItem, setLoadingCartItems } = useCart()
const topEightInCart = useMemo(
() =>
cartItems
Array.from(cartItems.values())
.filter(
({ listOp }) =>
listOp.opcode === 3 &&
Expand All @@ -41,7 +41,7 @@ export const useEditTopEight = (profiles: TopEightProfileType[]) => {
const [editedProfiles, setEditedProfiles] = useState([...profiles, ...topEightInCart])

const validTopEightsLength = useMemo(() => {
const topEightRemoved = cartItems.filter(
const topEightRemoved = Array.from(cartItems.values()).filter(
({ listOp }) =>
listOp.opcode === 4 && isTagListOp(listOp) && extractAddressAndTag(listOp).tag === 'top8'
)
Expand Down Expand Up @@ -102,26 +102,6 @@ export const useEditTopEight = (profiles: TopEightProfileType[]) => {
if (!roles?.isManager) return toast.error(t('not manager'))

setAddProfileSearch('')

// const hasMultipleNames =
// addProfileSearch.includes(',') ||
// addProfileSearch.includes(' ') ||
// addProfileSearch.includes('\n')

// if (hasMultipleNames) {
// const namesToAdd = addProfileSearch
// .replaceAll(',', ' ')
// .replaceAll('\n', ' ')
// .split(' ')
// .map(name => name.trim())
// .filter(name => !!name)

// const addedToCart = await Promise.all(namesToAdd.map(async name => await addToCart(name)))

// const erroredNames = addedToCart.filter(item => item?.user).map(item => item?.user)
// if (erroredNames.length > 0) toast.error(`${t('unresolved')} ${formatError(erroredNames)}`)
// }

const addedToCart = await addToCart(addProfileSearch)
if (addedToCart?.user) toast.error(`${t('unresolved')} ${addProfileSearch}`)
}
Expand Down
Loading