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

fix: count nft collections upon saving draft #464

Merged
merged 7 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
NftGalleryDraftStats,
} from "./NftGalleryDraftCard.blocks";
import * as useAuthorizedActionMock from "@/Hooks/useAuthorizedAction";
import { type DraftNft, type GalleryDraft } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import { type DraftNft, type GallerySavedDraft } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
goga-m marked this conversation as resolved.
Show resolved Hide resolved
import UserDataFactory from "@/Tests/Factories/UserDataFactory";
import { mockAuthContext, render, screen } from "@/Tests/testing-library";

Expand Down Expand Up @@ -56,7 +56,7 @@ describe("NftGalleryDraftHeading", () => {
});

describe("NftGalleryDraftStats", () => {
const draft: GalleryDraft = {
const draft: GallerySavedDraft = {
id: 1,
title: "Test draft",
cover: null,
Expand Down
6 changes: 3 additions & 3 deletions resources/js/Components/Drafts/NftGalleryDraftCard.blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Skeleton } from "@/Components/Skeleton";
import { Tooltip } from "@/Components/Tooltip";
import { useAuth } from "@/Contexts/AuthContext";
import { useIsTruncated } from "@/Hooks/useIsTruncated";
import { type DraftNft, type GalleryDraft } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import { type DraftNft, type GallerySavedDraft } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import { formatAddress } from "@/Utils/format-address";
import { isTruthy } from "@/Utils/is-truthy";
import { TruncateMiddle } from "@/Utils/TruncateMiddle";
Expand Down Expand Up @@ -104,7 +104,7 @@ export const NftGalleryDraftStats = ({
draft,
onDelete,
}: {
draft: GalleryDraft;
draft: GallerySavedDraft;
onDelete: () => void;
}): JSX.Element => {
const { user } = useAuth();
Expand Down Expand Up @@ -184,7 +184,7 @@ export const NftGalleryDraftImageGrid = ({
minimumToShow = 6,
skeletonCount,
}: {
nfts: GalleryDraft["nfts"];
nfts: GallerySavedDraft["nfts"];
minimumToShow?: number;
skeletonCount?: number;
}): JSX.Element => {
Expand Down
6 changes: 3 additions & 3 deletions resources/js/Components/Drafts/NftGalleryDraftCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import { type SpyInstance } from "vitest";
import { NftGalleryDraftCard } from "./NftGalleryDraftCard";
import * as useMetaMaskContext from "@/Contexts/MetaMaskContext";
import { type GalleryDraft } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import { type GallerySavedDraft } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import UserDataFactory from "@/Tests/Factories/UserDataFactory";
import { getSampleMetaMaskState } from "@/Tests/SampleData/SampleMetaMaskState";
import { mockAuthContext, render, screen, userEvent } from "@/Tests/testing-library";
Expand All @@ -12,16 +12,16 @@ let resetAuthContextMock: () => void;
let useMetaMaskContextSpy: SpyInstance;

describe("NftGalleryDraftCard", () => {
const draft: GalleryDraft = {
const draft: GallerySavedDraft = {
id: 1,
title: "Test draft",
cover: null,
coverType: null,
coverFileName: null,
walletAddress: "0x22Fd644149ea87ca26237183ad6A66f91dfcFB87",
collectionsCount: 1,
nfts: [],
value: "0",
collectionsCount: 0,
updatedAt: 123,
};

Expand Down
7 changes: 3 additions & 4 deletions resources/js/Components/Drafts/NftGalleryDraftCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { Link } from "@inertiajs/react";
import cn from "classnames";
import { NftGalleryDraftHeading, NftGalleryDraftImageGrid, NftGalleryDraftStats } from "./NftGalleryDraftCard.blocks";
import { GalleryCoverImage } from "@/Components/Galleries/GalleryPage/GalleryCoverImage";
import { type GalleryDraft } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import { type GallerySavedDraft } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import { isTruthy } from "@/Utils/is-truthy";

export const NftGalleryDraftCard = ({
draft,
onDelete,
}: {
draft: GalleryDraft;
draft: GallerySavedDraft;
onDelete: () => void;
}): JSX.Element => {
let coverImage: string | null = null;
Expand All @@ -21,8 +21,7 @@ export const NftGalleryDraftCard = ({
return (
<Link
href={route("my-galleries.create", {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
draftId: draft.id!,
draftId: draft.id,
editDraft: 1,
})}
className="group focus-visible:outline-none focus-visible:ring-0"
Expand Down
4 changes: 2 additions & 2 deletions resources/js/Pages/Galleries/MyGalleries/Index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { DraftGalleryDeleteModal } from "@/Components/Galleries/GalleryPage/Draf
import { Heading } from "@/Components/Heading";
import { Pagination } from "@/Components/Pagination";
import { useAuthorizedAction } from "@/Hooks/useAuthorizedAction";
import { type GalleryDraft, useWalletDraftGalleries } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import { type GallerySavedDraft, useWalletDraftGalleries } from "@/Pages/Galleries/hooks/useWalletDraftGalleries";
import { assertWallet } from "@/Utils/assertions";
import { isTruthy } from "@/Utils/is-truthy";

Expand All @@ -31,7 +31,7 @@ const Drafts = ({
onRemove,
}: {
isLoading: boolean;
drafts: GalleryDraft[];
drafts: GallerySavedDraft[];
onRemove?: (id: number) => void;
}): JSX.Element => {
const { t } = useTranslation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const defaultGalleryDraft = {
nfts: [],
walletAddress: "mockedAddress",
value: "test",
collectionsCount: 1,
updatedAt: new Date().getTime(),
};

Expand All @@ -25,7 +24,6 @@ const expiredGalleryDraft = {
nfts: [],
walletAddress: "mockedAddress",
value: "test",
collectionsCount: 1,
updatedAt: 169901639000,
};

Expand Down Expand Up @@ -98,7 +96,6 @@ describe("useWalletDraftGalleries", () => {
nfts: [],
walletAddress: "mockedAddress",
value: "test",
collectionsCount: 1,
updatedAt: new Date().getTime(),
});
});
Expand Down Expand Up @@ -131,7 +128,6 @@ describe("useWalletDraftGalleries", () => {
nfts: [],
walletAddress: "mockedAddress",
value: "test",
collectionsCount: 1,
updatedAt: new Date().getTime(),
});
});
Expand Down
42 changes: 27 additions & 15 deletions resources/js/Pages/Galleries/hooks/useWalletDraftGalleries.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import uniqBy from "lodash/uniqBy";
import { useCallback, useEffect, useState } from "react";
import { useIndexedDB } from "react-indexed-db-hook";
import { isTruthy } from "@/Utils/is-truthy";
Expand All @@ -24,28 +25,47 @@ export interface GalleryDraft {
walletAddress?: string;
id?: number | null;
value: string | null;
collectionsCount: number;
updatedAt: number | null;
coverFileName: string | null;
}

interface GallerySavedDraft extends GalleryDraft {
export interface GallerySavedDraft extends GalleryDraft {
id: number;
collectionsCount: number;
}

interface WalletDraftGalleriesState {
upsert: (draft: GalleryDraft) => Promise<GallerySavedDraft>;
add: (draft: GalleryDraft) => Promise<GallerySavedDraft>;
remove: (id?: number | null) => Promise<void>;
removeExpired: () => Promise<void>;
drafts: GalleryDraft[];
drafts: GallerySavedDraft[];
findWalletDraftById: (id: number | string) => Promise<GallerySavedDraft | undefined>;
isLoading: boolean;
isSaving: boolean;
hasReachedLimit: boolean;
allDrafts: () => Promise<GallerySavedDraft[]>;
}

/**
* Calculate collections count based on saved nfts.
*
* @param {GalleryDraft} draft
* @returns {number}
*/
const calculateCollectionsCount = (draft: GalleryDraft): number => uniqBy(draft.nfts, "collectionSlug").length;

/**
* Determine if gallery is expired.
*
* @param {GalleryDraft} draft
* @returns {boolean}
*/
const isExpired = (draft: GalleryDraft): boolean => {
const thresholdDaysAgo = new Date().getTime() - DRAFT_TTL_DAYS * 86400 * 1000;
return (draft.updatedAt ?? 0) < thresholdDaysAgo;
};

/**
* Note: The react-indexed-db-hook package that is used under the hood in this hook
* is not reactive. That means that if this hook is used in multiple components,
Expand All @@ -58,7 +78,7 @@ interface WalletDraftGalleriesState {
*/
export const useWalletDraftGalleries = ({ address }: Properties): WalletDraftGalleriesState => {
const database = useIndexedDB("gallery-drafts");
const [drafts, setDrafts] = useState<GalleryDraft[]>([]);
const [drafts, setDrafts] = useState<GallerySavedDraft[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false);
const [hasReachedLimit, setHasReachedLimit] = useState(false);
Expand Down Expand Up @@ -86,6 +106,7 @@ export const useWalletDraftGalleries = ({ address }: Properties): WalletDraftGal
*/
const add = async (draft: GalleryDraft): Promise<GallerySavedDraft> => {
const allDraftsCount = await allDrafts();

if (allDraftsCount.length >= MAX_DRAFT_LIMIT_PER_WALLET) {
throw new Error("[useWalletDraftGalleries:upsert] Reached limit");
}
Expand All @@ -97,6 +118,7 @@ export const useWalletDraftGalleries = ({ address }: Properties): WalletDraftGal
const id = await database.add({
...draftToSave,
updatedAt: new Date().getTime(),
collectionsCount: calculateCollectionsCount(draft),
});

setIsSaving(false);
Expand All @@ -120,6 +142,7 @@ export const useWalletDraftGalleries = ({ address }: Properties): WalletDraftGal
await database.update({
...draft,
updatedAt: new Date().getTime(),
collectionsCount: calculateCollectionsCount(draft),
});

setIsSaving(false);
Expand Down Expand Up @@ -197,17 +220,6 @@ export const useWalletDraftGalleries = ({ address }: Properties): WalletDraftGal
return draft;
};

/**
* Determine if gallery is expired.
*
* @param {GalleryDraft} draft
* @returns {boolean}
*/
const isExpired = (draft: GalleryDraft): boolean => {
const thresholdDaysAgo = new Date().getTime() - DRAFT_TTL_DAYS * 86400 * 1000;
return (draft.updatedAt ?? 0) < thresholdDaysAgo;
};

/**
* Find draft or throw. Used internally for add/remove.
*
Expand Down
Loading