Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
177 changes: 177 additions & 0 deletions __tests__/components/drop-forge/drop-forge-status.helpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
jest.mock("@/components/drop-forge/launch/launchClaimHelpers", () => ({
isMissingRequiredLaunchInfo: jest.fn(),
}));

import { getClaimPrimaryStatus } from "@/components/drop-forge/drop-forge-status.helpers";
import { isMissingRequiredLaunchInfo } from "@/components/drop-forge/launch/launchClaimHelpers";
import type { MintingClaim } from "@/generated/models/MintingClaim";

const mockedIsMissingRequiredLaunchInfo = jest.mocked(
isMissingRequiredLaunchInfo
);

describe("getClaimPrimaryStatus", () => {
const baseClaim = {
claim_id: 123,
metadata_location: "ar://example",
media_uploading: false,
} as MintingClaim;

beforeEach(() => {
mockedIsMissingRequiredLaunchInfo.mockReturnValue(false);
});

it("returns a loading status while launch onchain state is still fetching", () => {
expect(
getClaimPrimaryStatus({
claim: baseClaim,
manifoldClaim: null,
isCraftContext: false,
isManifoldClaimFetching: true,
})
).toMatchObject({
key: "checking_onchain",
label: "Checking Onchain",
tone: "pending",
});
});

it("returns pending initialization after launch onchain state has finished loading", () => {
expect(
getClaimPrimaryStatus({
claim: baseClaim,
manifoldClaim: null,
isCraftContext: false,
isManifoldClaimFetching: false,
})
).toMatchObject({
key: "pending_initialization",
label: "Pending Initialization",
tone: "pending",
});
});

it("returns draft when there is no metadata and nothing is initialized", () => {
expect(
getClaimPrimaryStatus({
claim: {
...baseClaim,
metadata_location: null,
},
manifoldClaim: null,
isCraftContext: false,
})
).toMatchObject({
key: "draft",
label: "Draft",
tone: "neutral",
});
});

it("returns pending initialization missing info when launch fields are incomplete", () => {
mockedIsMissingRequiredLaunchInfo.mockReturnValue(true);

expect(
getClaimPrimaryStatus({
claim: baseClaim,
manifoldClaim: null,
isCraftContext: false,
isManifoldClaimFetching: false,
})
).toMatchObject({
key: "pending_initialization_missing_info",
label: "Pending Initialization — Missing Info",
tone: "pending",
});
});

it("keeps craft claims in the published state", () => {
expect(
getClaimPrimaryStatus({ claim: baseClaim, isCraftContext: true })
).toMatchObject({
key: "published",
label: "Published",
tone: "success",
});
});

it("keeps craft claims published even when launch info is missing", () => {
mockedIsMissingRequiredLaunchInfo.mockReturnValue(true);

expect(
getClaimPrimaryStatus({ claim: baseClaim, isCraftContext: true })
).toMatchObject({
key: "published",
label: "Published",
tone: "success",
});
});

it("treats instanceId 0 as initialized onchain", () => {
expect(
getClaimPrimaryStatus({
claim: baseClaim,
manifoldClaim: {
instanceId: 0,
location: "ar://example",
},
isCraftContext: false,
})
).toMatchObject({
key: "live",
label: "Live",
tone: "success",
});
});

it("returns live when onchain and local metadata match", () => {
expect(
getClaimPrimaryStatus({
claim: baseClaim,
manifoldClaim: {
instanceId: 123,
location: "ar://example",
},
})
).toMatchObject({
key: "live",
label: "Live",
tone: "success",
});
});

it("returns live needs update when onchain metadata differs", () => {
expect(
getClaimPrimaryStatus({
claim: baseClaim,
manifoldClaim: {
instanceId: 123,
location: "ar://older",
},
})
).toMatchObject({
key: "live_needs_update",
label: "Live — Needs Update",
tone: "update",
});
});

it("returns diverged when initialized onchain without local metadata", () => {
expect(
getClaimPrimaryStatus({
claim: {
...baseClaim,
metadata_location: null,
},
manifoldClaim: {
instanceId: 123,
location: "ar://example",
},
})
).toMatchObject({
key: "diverged",
label: "Diverged",
tone: "destructive",
});
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { getAutoSelectedLaunchPhase } from "@/components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers";
import {
clampResearchTargetEditionSize,
getAutoSelectedLaunchPhase,
getDefaultResearchTargetEditionSize,
getResearchTargetEditionSizeLimit,
} from "@/components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers";

describe("getAutoSelectedLaunchPhase", () => {
const phases = [
Expand Down Expand Up @@ -140,3 +145,39 @@ describe("getAutoSelectedLaunchPhase", () => {
).toBe("phase1");
});
});

describe("research target edition size helpers", () => {
it("uses the live onchain total max when it is available", () => {
expect(getResearchTargetEditionSizeLimit(400, 250)).toBe(250);
expect(getResearchTargetEditionSizeLimit(250, 400)).toBe(400);
});

it("defaults to the lower of the claim edition size and 310", () => {
expect(getDefaultResearchTargetEditionSize(305)).toBe(305);
expect(getDefaultResearchTargetEditionSize(500)).toBe(310);
});

it("defaults to the onchain cap whenever it is available", () => {
expect(getDefaultResearchTargetEditionSize(500, 275)).toBe(275);
expect(getDefaultResearchTargetEditionSize(250, 400)).toBe(310);
});

it("falls back to 310 when the claim edition size is missing", () => {
expect(getDefaultResearchTargetEditionSize(null)).toBe(310);
expect(getDefaultResearchTargetEditionSize(0)).toBe(310);
});

it("caps the research target at the claim edition size", () => {
expect(clampResearchTargetEditionSize(310, 305)).toBe(305);
expect(clampResearchTargetEditionSize(304.8, 305)).toBe(304);
});

it("caps the research target at the live onchain total max", () => {
expect(clampResearchTargetEditionSize(310, 500, 275)).toBe(275);
expect(clampResearchTargetEditionSize(450, 250, 400)).toBe(400);
});

it("keeps the research target uncapped when there is no edition size limit", () => {
expect(clampResearchTargetEditionSize(310, null)).toBe(310);
});
});
12 changes: 9 additions & 3 deletions components/drop-forge/DropForgeClaimsListPageClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ function ClaimCardContent({
}

function CraftClaimCard({ claim }: Readonly<{ claim: MintingClaim }>) {
const primaryStatus = getClaimPrimaryStatus({ claim });
const primaryStatus = getClaimPrimaryStatus({ claim, isCraftContext: true });

return (
<Link
Expand All @@ -366,10 +366,13 @@ function CraftClaimCard({ claim }: Readonly<{ claim: MintingClaim }>) {
}

function LaunchClaimCard({ claim }: Readonly<{ claim: MintingClaim }>) {
const { claim: manifoldClaim } = useDropForgeManifoldClaim(claim.claim_id);
const { claim: manifoldClaim, isFetching: isManifoldClaimFetching } =
useDropForgeManifoldClaim(claim.claim_id);
const primaryStatus = getClaimPrimaryStatus({
claim,
manifoldClaim: manifoldClaim ?? null,
isCraftContext: false,
isManifoldClaimFetching,
});

return (
Expand All @@ -381,7 +384,10 @@ function LaunchClaimCard({ claim }: Readonly<{ claim: MintingClaim }>) {
<DropForgeStatusPill
className={getPrimaryStatusPillClassName(primaryStatus.tone)}
label={primaryStatus.label}
showLoader={primaryStatus.key === "publishing"}
showLoader={
primaryStatus.key === "publishing" ||
primaryStatus.key === "checking_onchain"
}
tooltipText={primaryStatus.reason ?? ""}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1665,7 +1665,7 @@ function ArweaveSection({
const { setToast } = useAuth();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const primaryStatus = getClaimPrimaryStatus({ claim });
const primaryStatus = getClaimPrimaryStatus({ claim, isCraftContext: true });
const isPublishing = primaryStatus.key === "publishing";
const isDraft = primaryStatus.key === "draft";
const canPublish = isDraft && !hasPendingChanges && !loading && !isPublishing;
Expand Down
Loading
Loading