diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 7c1c80b..99e31cc 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/packages/nextjs/app/(app)/dashboard/page.tsx b/packages/nextjs/app/(app)/dashboard/page.tsx index c05762d..c0fc95f 100644 --- a/packages/nextjs/app/(app)/dashboard/page.tsx +++ b/packages/nextjs/app/(app)/dashboard/page.tsx @@ -1,5 +1,8 @@ import { Metadata } from "next"; import { ClaimRoleCard } from "~~/components/dashboard/ClaimRoleCard"; +import { DataRegistry } from "~~/components/dashboard/DataRegistry"; +import MineralToken from "~~/components/dashboard/MineralToken"; +import { SupplyChain } from "~~/components/dashboard/SupplyChain"; export const metadata: Metadata = { title: "Dashboard", @@ -7,8 +10,12 @@ export const metadata: Metadata = { export default function DashboardPage() { return ( -
+
+ + +
); } + diff --git a/packages/nextjs/components/dashboard/ClaimRoleCard.tsx b/packages/nextjs/components/dashboard/ClaimRoleCard.tsx index 735d986..56d1652 100644 --- a/packages/nextjs/components/dashboard/ClaimRoleCard.tsx +++ b/packages/nextjs/components/dashboard/ClaimRoleCard.tsx @@ -1,8 +1,23 @@ +/* eslint-disable prettier/prettier */ "use client"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select"; +import { useState } from "react"; +import { ethers } from "ethers"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "../ui/select"; +import ParticipantsABI from "../../contracts/Participants.json"; // Adjust the path as needed -const roles = [ +type Role = { + label: string; + role: string; +}; + +const roles: Role[] = [ { label: "Refiner", role: "REFINER" }, { label: "Miner", role: "MINER" }, { label: "Transporter", role: "TRANSPORTER" }, @@ -11,25 +26,72 @@ const roles = [ ]; export const ClaimRoleCard: React.FC = () => { + const [selectedRole, setSelectedRole] = useState(null); + + const handleRoleChange = (role: string) => { + setSelectedRole(role); + }; + + const handleClaimRole = async (): Promise => { + if (!selectedRole) return; + + try { + if (!window.ethereum) { + alert("Please install MetaMask or any other EVM-wallet"); + return; + } + + const provider = new ethers.providers.Web3Provider(window.ethereum); + const signer = provider.getSigner(); + + const contractAddress = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"; + const contract = new ethers.Contract( + contractAddress, + ParticipantsABI.abi, + signer + ); + + const roleBytes32 = ethers.utils.formatBytes32String(selectedRole); + + const tx = await contract.registerParticipant( + await signer.getAddress(), + "Participant's name", + "Participant's location", + roleBytes32 + ); + + await tx.wait(); + alert("Role claimed successfully!"); + } catch (error: any) { + console.error("Error claiming role:", error); + alert("An error occurred while claiming the role."); + } + }; + return ( -
+

Congratulations!

- Claim a role that will be used to identify you in Stoneproof platform. + Claim a role that will be used to identify you on the Stoneproof platform.

- - {roles.map(role => ( + {roles.map((role) => ( {role.label} ))} - +
); }; diff --git a/packages/nextjs/components/dashboard/DataRegistry.tsx b/packages/nextjs/components/dashboard/DataRegistry.tsx new file mode 100644 index 0000000..4fb8b5c --- /dev/null +++ b/packages/nextjs/components/dashboard/DataRegistry.tsx @@ -0,0 +1,76 @@ +/* eslint-disable prettier/prettier */ +"use client"; + +import { useState, useEffect } from "react"; +import { ethers } from "ethers"; +import DataRegistryABI from "../../contracts/DataRegistry.json"; +type DataRecord = { + id: string; + description: string; + owner: string; +}; + +export const DataRegistry: React.FC = () => { + const [records, setRecords] = useState([]); + const [isLoading, setIsLoading] = useState(true); + + const fetchDataRecords = async () => { + setIsLoading(true); + try { + if (!window.ethereum) { + alert("Please install MetaMask or any other EVM-wallet"); + return; + } + + const provider = new ethers.providers.Web3Provider(window.ethereum); + const signer = provider.getSigner(); + const contractAddress = "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"; + const contract = new ethers.Contract(contractAddress, DataRegistryABI.abi, signer); + + const recordsData = await contract.getAllRecords(); + const formattedRecords = recordsData.map((record: any) => ({ + id: record.id, + description: record.description, + owner: record.owner, + })); + + setRecords(formattedRecords); + } catch (error) { + console.error("Error fetching records:", error); + alert("An error occurred while fetching records."); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + fetchDataRecords(); + }, []); + + return ( +
+

Data Records

+

+ View and manage data entries on the StoneProof platform. +

+ {isLoading ? ( +

Loading records...

+ ) : ( +
    + {records.map((record) => ( +
  • +

    {record.description}

    +

    Owned by: {record.owner}

    +
  • + ))} +
+ )} + +
+ ); +}; diff --git a/packages/nextjs/components/dashboard/MineralToken.tsx b/packages/nextjs/components/dashboard/MineralToken.tsx new file mode 100644 index 0000000..e38de0b --- /dev/null +++ b/packages/nextjs/components/dashboard/MineralToken.tsx @@ -0,0 +1,99 @@ +"use client"; + +import React, { ChangeEvent, useState } from "react"; +// Import ABI correctly +import MineralTokenABI from "../../contracts/MineralToken.json"; +import { ethers, providers } from "ethers"; + +// Props interface for optional address override +interface ClaimRoleCardProps { + contractAddress?: string; +} + +// Default contract address used if not provided via props +const DEFAULT_CONTRACT_ADDRESS = "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"; + +const ClaimRoleCard: React.FC = ({ contractAddress = DEFAULT_CONTRACT_ADDRESS }) => { + // State hooks with proper types + const [role, setRole] = useState(""); + const [account, setAccount] = useState(""); + const [statusMessage, setStatusMessage] = useState(""); + + // Helper function to get the contract instance + const getContract = (): Contract => { + const provider = new providers.Web3Provider(window.ethereum as any); + const signer = provider.getSigner(); + return new ethers.Contract(contractAddress, MineralTokenABI.abi, signer); + }; + + // Grant role function + const handleGrantRole = async () => { + try { + const contract = getContract(); + const tx = await contract.grantRole(ethers.utils.formatBytes32String(role), account); + setStatusMessage(`Transaction submitted: ${tx.hash}`); + await tx.wait(); + setStatusMessage(`Transaction confirmed: ${tx.hash}`); + } catch (error: any) { + setStatusMessage(`Error: ${error.message}`); + } + }; + + // Revoke role function + const handleRevokeRole = async () => { + try { + const contract = getContract(); + const tx = await contract.revokeRole(ethers.utils.formatBytes32String(role), account); + setStatusMessage(`Transaction submitted: ${tx.hash}`); + await tx.wait(); + setStatusMessage(`Transaction confirmed: ${tx.hash}`); + } catch (error: any) { + setStatusMessage(`Error: ${error.message}`); + } + }; + + // Handle input changes with reusable setter function + const handleChange = + (setter: React.Dispatch>) => (event: ChangeEvent) => { + setter(event.target.value); + }; + + return ( +
+

Manage Roles

+
+ + +
+
+ + +
+ {statusMessage &&

{statusMessage}

} +
+ ); +}; + +export default ClaimRoleCard; diff --git a/packages/nextjs/components/dashboard/SupplyChain.tsx b/packages/nextjs/components/dashboard/SupplyChain.tsx new file mode 100644 index 0000000..c054423 --- /dev/null +++ b/packages/nextjs/components/dashboard/SupplyChain.tsx @@ -0,0 +1,152 @@ +/* eslint-disable prettier/prettier */ +"use client"; + +import React, { useState, ChangeEvent } from "react"; +import { ethers, Contract, providers } from "ethers"; +import SupplyChainABI from "../../contracts/SupplyChain.json"; + +const SupplyChainAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3"; + +interface BatchDetails { + id: ethers.BigNumber; + owner: string; + location: string; + status: string; + timestamp: number; +} + +export const SupplyChain: React.FC = () => { + const [location, setLocation] = useState(''); + const [batchId, setBatchId] = useState(''); + const [newOwner, setNewOwner] = useState(''); + const [newStatus, setNewStatus] = useState(''); + const [batchDetails, setBatchDetails] = useState(null); + + const provider = new providers.Web3Provider(window.ethereum as any); + const signer = provider.getSigner(); + const supplyChainContract: Contract = new ethers.Contract( + SupplyChainAddress, + SupplyChainABI.abi, + signer + ); + + const createBatch = async (): Promise => { + try { + const tx = await supplyChainContract.createBatch(location); + await tx.wait(); + alert("Batch created!"); + } catch (error: any) { + console.error(error); + alert("Error creating batch."); + } + }; + + const getBatch = async (): Promise => { + try { + const batch = await supplyChainContract.getBatch(parseInt(batchId, 10)); + setBatchDetails(batch); + } catch (error: any) { + console.error(error); + alert("Error fetching batch details."); + } + }; + + const transferOwnership = async (): Promise => { + try { + const tx = await supplyChainContract.transferOwnership(parseInt(batchId, 10), newOwner); + await tx.wait(); + alert("Ownership transferred!"); + } catch (error: any) { + console.error(error); + alert("Error transferring ownership."); + } + }; + + const updateStatus = async (): Promise => { + try { + const tx = await supplyChainContract.updateStatus(parseInt(batchId, 10), newStatus); + await tx.wait(); + alert("Status updated!"); + } catch (error: any) { + console.error(error); + alert("Error updating status."); + } + }; + + const handleChange = (setter: React.Dispatch>) => + (event: ChangeEvent) => { + setter(event.target.value); + }; + + return ( +
+

Supply Chain Management

+ + + + + + + + {batchDetails && ( +
+

Batch ID: {batchDetails.id.toString()}

+

Owner: {batchDetails.owner}

+

Location: {batchDetails.location}

+

Status: {batchDetails.status}

+

Timestamp: {new Date(batchDetails.timestamp * 1000).toLocaleString()}

+
+ )} + + + + + + +
+ ); +}; diff --git a/packages/nextjs/contracts/Partcipants.json b/packages/nextjs/contracts/Participants.json similarity index 100% rename from packages/nextjs/contracts/Partcipants.json rename to packages/nextjs/contracts/Participants.json diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index ed1fae6..bb6d12d 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -24,6 +24,7 @@ "blo": "~1.0.1", "burner-connector": "~0.0.8", "daisyui": "4.12.10", + "dotenv": "^16.4.5", "ethers": "5.7.2", "framer-motion": "^11.11.10", "lucide-react": "^0.453.0", diff --git a/yarn.lock b/yarn.lock index 4e141d5..c39944d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2981,6 +2981,7 @@ __metadata: blo: ~1.0.1 burner-connector: ~0.0.8 daisyui: 4.12.10 + dotenv: ^16.4.5 eslint: ~8.24.0 eslint-config-next: ~14.0.4 eslint-config-prettier: ~8.5.0