Skip to content

Commit

Permalink
feat: disable reward button when already claimed (#499)
Browse files Browse the repository at this point in the history
* feat: disable reward button when already claimed

* using unclaimed rewards

* fix

* fix: showing claimed when not claimable
  • Loading branch information
Marchand-Nicolas authored Feb 5, 2024
1 parent 1dbe7b9 commit dd401d3
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 33 deletions.
34 changes: 3 additions & 31 deletions components/lands/land.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { AchievementsDocument } from "types/backTypes";
import Link from "next/link";
import { getCurrentNetwork } from "@utils/network";
import { getNfts } from "@utils/assets";

type LandProps = {
address: string;
Expand All @@ -37,41 +38,12 @@ export const Land = ({
if (address) {
setSoloBuildings([]);
setIsReady(true);
retrieveAssets(
`https://${
network === "TESTNET" ? "api-testnet" : "api"
}.starkscan.co/api/v0/nfts?owner_address=${address}`
).then((data) => {
filterAssets(data.data);
getNfts(address, network).then((nfts) => {
filterAssets(nfts);
});
}
}, [address]);

// Retrieve assets from Starkscan API
const retrieveAssets = async (
url: string,
accumulatedAssets: StarkscanNftProps[] = []
): Promise<StarkscanApiResult> => {
return fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
"x-api-key": `${process.env.NEXT_PUBLIC_STARKSCAN}`,
},
})
.then((res) => res.json())
.then((data) => {
const assets = [...accumulatedAssets, ...data.data];
if (data.next_url) {
return retrieveAssets(data.next_url, assets);
} else {
return {
data: assets,
};
}
});
};

// Fetch achievements from database and add building id from highest achievement level
const getBuildingsFromAchievements = async (filteredAssets: number[]) => {
try {
Expand Down
2 changes: 2 additions & 0 deletions components/quests/questDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const QuestDetails: FunctionComponent<QuestDetailsProps> = ({
const [taskError, setTaskError] = useState<TaskError>();
const [showQuiz, setShowQuiz] = useState<ReactNode>();
const [customError, setCustomError] = useState<string>("");
const [claimed, setClaimed] = useState<boolean>(false);

const questId = quest.id.toString();
const [participants, setParticipants] = useState({
Expand Down Expand Up @@ -416,6 +417,7 @@ const QuestDetails: FunctionComponent<QuestDetailsProps> = ({
}}
disabled={!rewardsEnabled}
mintCalldata={mintCalldata}
claimed={rewardsEnabled && unclaimedRewards?.length === 0}
questName={quest.name}
/>
</>
Expand Down
6 changes: 4 additions & 2 deletions components/quests/reward.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type RewardProps = {
mintCalldata: Call[] | undefined;
questName: string;
hasNftReward?: boolean;
claimed?: boolean;
quest: QuestDocument;
};

Expand All @@ -34,6 +35,7 @@ const Reward: FunctionComponent<RewardProps> = ({
mintCalldata,
questName,
hasNftReward,
claimed,
quest,
}) => {
const [modalTxOpen, setModalTxOpen] = useState(false);
Expand Down Expand Up @@ -78,8 +80,8 @@ const Reward: FunctionComponent<RewardProps> = ({
</div>
<div className="max-w-lg">
{/* getReward */}
<Button onClick={submitTx} disabled={disabled}>
Get Reward
<Button onClick={submitTx} disabled={disabled || claimed}>
{claimed ? "Claimed" : "Get Reward"}
</Button>
</div>

Expand Down
112 changes: 112 additions & 0 deletions tests/utils/assets.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { retrieveAssets, getNfts } from "../../utils/assets";

global.fetch = jest.fn();

describe("retrieveAssets", () => {
beforeEach(() => {
fetch.mockClear();
});
it("successfully retrieves assets without pagination", async () => {
const mockAssets = {
data: [
{ id: "1", name: "Asset 1" },
{ id: "2", name: "Asset 2" },
],
};
fetch.mockResolvedValueOnce({
json: () => Promise.resolve(mockAssets),
});

const url = "https://api.example.com/assets";
const result = await retrieveAssets(url);

expect(result.data).toEqual(mockAssets.data);
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
"x-api-key": expect.any(String),
},
});
});

it("handles pagination correctly", async () => {
const firstPageAssets = {
data: [
{ id: "1", name: "Asset 1" },
{ id: "2", name: "Asset 2" },
],
next_url: "https://api.example.com/assets?page=2",
};
const secondPageAssets = {
data: [
{ id: "3", name: "Asset 3" },
{ id: "4", name: "Asset 4" },
],
};
fetch.mockResolvedValueOnce({
json: () => Promise.resolve(firstPageAssets),
});
fetch.mockResolvedValueOnce({
json: () => Promise.resolve(secondPageAssets),
});
const url = "https://api.example.com/assets";
const result = await retrieveAssets(url);

expect(result.data).toEqual([
...firstPageAssets.data,
...secondPageAssets.data,
]);
expect(fetch).toHaveBeenCalledTimes(2);
});
});

describe("getNfts", () => {
beforeEach(() => {
fetch.mockClear();
});
it("retrieves NFTs for a given address on the mainnet", async () => {
const mockNfts = {
data: [
{ id: "1", name: "NFT 1" },
{ id: "2", name: "NFT 2" },
],
};
fetch.mockResolvedValueOnce({
json: () => Promise.resolve(mockNfts),
});

const address = "0x123";
const network = "MAINNET";
const nfts = await getNfts(address, network);

expect(nfts).toEqual(mockNfts.data);
expect(fetch).toHaveBeenCalledWith(
expect.stringContaining("api.starkscan.co"),
expect.any(Object)
);
});

it("retrieves NFTs for a given address on the testnet", async () => {
const mockNfts = {
data: [
{ id: "1", name: "NFT 1" },
{ id: "2", name: "NFT 2" },
],
};
fetch.mockResolvedValueOnce({
json: () => Promise.resolve(mockNfts),
});

const address = "0x456";
const network = "TESTNET";
const nfts = await getNfts(address, network);

expect(nfts).toEqual(mockNfts.data);
expect(fetch).toHaveBeenCalledWith(
expect.stringContaining("api-testnet.starkscan.co"),
expect.any(Object)
);
});
});
34 changes: 34 additions & 0 deletions utils/assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export const retrieveAssets = async (
url: string,
accumulatedAssets: StarkscanNftProps[] = []
): Promise<StarkscanApiResult> => {
return fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
"x-api-key": `${process.env.NEXT_PUBLIC_STARKSCAN}`,
},
})
.then((res) => res.json())
.then((data) => {
const assets = [...accumulatedAssets, ...data.data];
if (data.next_url) {
return retrieveAssets(data.next_url, assets);
} else {
return {
data: assets,
};
}
});
};

export const getNfts = async (
address: string,
network: string
): Promise<StarkscanNftProps[]> => {
const url = `https://${
network === "TESTNET" ? "api-testnet" : "api"
}.starkscan.co/api/v0/nfts?owner_address=${address}`;
const assets = await retrieveAssets(url);
return assets.data;
};

0 comments on commit dd401d3

Please sign in to comment.