Skip to content
Merged
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
111 changes: 111 additions & 0 deletions src/app/dashboard/pool-market/[id]/components/manuallyUpdateModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import useManuallyUpdatePoolState, {
PoolStatus,
} from "@/app/hooks/useManuallyUpdatePoolStatus";
import { useEffect, useState } from "react";

interface ModalProps {
isOpen: boolean;
onClose: () => void;
currentStatus: PoolStatus;
id: string;
}

export const ManuallyUpdateModal = ({
isOpen,
onClose,
currentStatus,
id,
}: ModalProps) => {
const [selectedStatus, setSelectedStatus] = useState<PoolStatus>(
currentStatus || "Active"
);
const statusOptions = [
{ value: "Active", label: "Active" },
{
value: "Locked",
label: "Locked",
},
{ value: "Settled", label: "Settled" },
{ value: "Closed", label: "Closed" },
{
value: "Suspended",
label: "Suspended",
},
];

const { updatePoolState, isLoading: isUpdating } =
useManuallyUpdatePoolState();

useEffect(() => {
if (!isUpdating) {
setSelectedStatus(currentStatus);
onClose();
}
}, [isUpdating]);

if (!isOpen) return null;

return (
<div className="fixed inset-0 bg-gradient-to-b backdrop-blur-md from-rgba(14, 14, 16, 0.6) to-rgba(14, 14, 16, 0.6) bg-opacity-0 flex items-center justify-center z-50">
<div className="bg-gray-900 w-full max-w-lg rounded-lg shadow-lg overflow-hidden">
<div className="bg-[#0E0E10] shadow-lg shadow-[#25273599] p-6">
<h2 className="text-[#E9E9EF] text-center font-bold text-xl mb-6">
Manually Update Pool Status
</h2>
<div className="">
<h3 className="text-[#E9E9EF] text-center text-sm mb-4">
Select the new status for pool {id}
</h3>
</div>
<div className="p-4">
<label
htmlFor="status"
className="block text-sm font-medium text-gray-700 mb-2"
>
Contract Status
</label>
<select
id="status"
value={selectedStatus}
onChange={(e) => setSelectedStatus(e.target.value as PoolStatus)}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
{statusOptions.map((status) => (
<option
key={status.value}
value={status.value}
className="text-gray-900"
>
{status.label}
</option>
))}
</select>
</div>

<div className="flex gap-4 px-4 mt-5">
<button
onClick={() => {
setSelectedStatus(currentStatus);
onClose();
}}
className="flex-1 py-2 px-4 border border-[#CCCCCC] hover:bg-gray-700 text-[#E9E9EF] rounded"
>
Cancel
</button>
<button
onClick={() => updatePoolState(id, selectedStatus)}
disabled={selectedStatus === currentStatus || isUpdating}
className={`flex-1 py-2 px-4 ${
selectedStatus === currentStatus
? "bg-teal-500/50 cursor-not-allowed"
: "bg-teal-500 hover:bg-teal-600"
} text-white rounded disabled:opacity-50`}
>
{isUpdating ? "Updating..." : "Update"}
</button>
</div>
</div>
</div>
</div>
);
};
39 changes: 30 additions & 9 deletions src/app/dashboard/pool-market/[id]/components/poolDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"use client;"
import useManuallyUpdatePoolState, { PoolStatus } from "@/app/hooks/useManuallyUpdatePoolStatus";
import useValidatorCheck from "@/app/hooks/useValidatorCheck";
import { PREDIFI_ABI } from "@/app/abi/predifi_abi";
import { PREDIFI_CONTRACT_ADDRESS } from "@/static";
import {
Expand All @@ -6,6 +9,7 @@ import {
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Button } from "@/components/ui/button";
import {
formatTimeDiffFromNow,
formatToGMTPlusOne,
Expand All @@ -14,10 +18,10 @@ import {
import { Users, Banknote } from "lucide-react";
import Image from "next/image";
import { useParams } from "next/navigation";
import { ManuallyUpdateModal } from "./manuallyUpdateModal";
import { useContract, useAccount, } from "@starknet-react/core";
import { useCallback, useMemo, useState } from "react";
import toast from "react-hot-toast";
import { Button } from "@/components/ui/button";

interface PoolCardDetailsProps {
title: string;
Expand All @@ -37,7 +41,11 @@ export function PoolCardDetails({
category,
poolImage,
}: PoolCardDetailsProps) {
const [isOpen, setIsOpen] = useState(false);

const creatorAddress = creator as `0x${string}`;
const { isLoading, isValidator } = useValidatorCheck();

const { id: poolId } = useParams() as { id: string };

const poolIdUint256 = useMemo(() => {
Expand Down Expand Up @@ -126,15 +134,28 @@ const { id: poolId } = useParams() as { id: string };
</div>
</div>
</div>
<div className="text-sm lg:md:-right lg:md:text-md">
<small>
Begins in{" "}
<span className="text-teal-500">
{formatTimeDiffFromNow(Number(startTime))}{" "}
</span>
</small>
<p>{formatToGMTPlusOne(Number(startTime))}</p>
<div className="lg:md:-right text-sm lg:md:text-md">
<div className="">
<small>
Begins in{" "}
<span className="text-teal-500">
{formatTimeDiffFromNow(Number(startTime))}{" "}
</span>
</small>
<p>{formatToGMTPlusOne(Number(startTime))}</p>
</div>
{!isLoading && isValidator && (
<Button onClick={()=>{setIsOpen(true)}} className="mt-4 bg-teal-500 hover:bg-teal-600">
Update pool status
</Button>
)}
</div>
<ManuallyUpdateModal
isOpen={isOpen}
id={poolId}
onClose={() => setIsOpen(false)}
currentStatus={status as PoolStatus}
/>
</div>
);
}
Expand Down
84 changes: 84 additions & 0 deletions src/app/hooks/useManuallyUpdatePoolStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { useContract, useAccount } from "@starknet-react/core";
import { PREDIFI_ABI } from "../abi/predifi_abi";
import { PREDIFI_CONTRACT_ADDRESS } from "@/static";
import { useState } from "react";
import { cairo, CallData } from "starknet";
import { createCairoEnum, myProvider } from "@/lib/utils";
import toast from "react-hot-toast";

export type PoolStatus = "Active" | "Locked" | "Settled" | "Closed" | "Suspended";

interface UseManuallyUpdatePoolStateOptions {
onSuccess?: (data: any) => void;
onError?: (error: any) => void;
}

const useManuallyUpdatePoolState = ({
onSuccess,
onError,
}: UseManuallyUpdatePoolStateOptions = {}) => {
const { account } = useAccount();
const { contract } = useContract({
abi: PREDIFI_ABI,
address: PREDIFI_CONTRACT_ADDRESS,
});

const [isLoading, setIsLoading] = useState(false);

const updatePoolState = async (
poolId: string | number,
newStatus: PoolStatus
) => {
if (!account) {
const errorMsg = "Wallet not connected";
onError?.(errorMsg);
}

if (!contract) {
const errorMsg = "Contract not available";
onError?.(errorMsg);
}

setIsLoading(true);

try {
const poolIdU256 = cairo.uint256(poolId.toString());
const callData = CallData.compile({
pool_id: poolIdU256,
new_status: createCairoEnum(newStatus),
});

const result = await account?.execute({
contractAddress: PREDIFI_CONTRACT_ADDRESS,
entrypoint: "manually_update_pool_state",
calldata: callData,
});

// await account.waitForTransaction(result.transaction_hash);
const status = await myProvider.waitForTransaction(
result?.transaction_hash as string
);

onSuccess?.(result);
setIsLoading(false);

if (status.isSuccess()) {
toast.success("Success! 🎉 Pool status has been updated.");
setIsLoading(false);
}
} catch (err: any) {
const errorMessage =
err?.message || "Failed to update pool state. Try again.";
toast.error(errorMessage);
setIsLoading(false);
onError?.(err);
}
};

return {
updatePoolState,
isLoading,
};
};

export default useManuallyUpdatePoolState;
29 changes: 29 additions & 0 deletions src/app/hooks/useValidatorCheck.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useReadContract, useAccount } from "@starknet-react/core";
import { PREDIFI_ABI } from "../abi/predifi_abi";
import { PREDIFI_CONTRACT_ADDRESS } from "@/static";

interface UseAdminCheckOptions {
enabled?: boolean;
}

const useValidatorCheck = ({ enabled = true }: UseAdminCheckOptions = {}) => {
const { address } = useAccount();

const { data: isValidator, isLoading: isValidatorLoading } = useReadContract({
abi: PREDIFI_ABI,
functionName: "is_validator",
address: PREDIFI_CONTRACT_ADDRESS,
args: [address],
enabled: enabled && !!address,
});

const isLoading = isValidatorLoading;

return {
isValidator: Boolean(isValidator),
isLoading,
address,
};
};

export default useValidatorCheck;
1 change: 1 addition & 0 deletions src/constants/functionNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export const GET_SETTLED_POOLS = "get_settled_pools"
export const GET_LOCKED_POOLS = "get_locked_pools";
export const GET_ACTIVE_POOLS = "get_active_pools";
export const GET_CLOSED_POOLS = "get_closed_pools"
export const MANUALLY_UPDATE_POOL_STATE = "manually_update_pool_state"