diff --git a/src/deda_frontend/components.json b/src/deda_frontend/components.json new file mode 100644 index 0000000..fb5b4e6 --- /dev/null +++ b/src/deda_frontend/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.scss", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} \ No newline at end of file diff --git a/src/deda_frontend/package.json b/src/deda_frontend/package.json index d17f182..e978069 100644 --- a/src/deda_frontend/package.json +++ b/src/deda_frontend/package.json @@ -14,11 +14,22 @@ "@dfinity/agent": "^1.4.0", "@dfinity/candid": "^1.4.0", "@dfinity/principal": "^1.4.0", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-scroll-area": "^1.2.0", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.1", + "@radix-ui/react-tabs": "^1.1.1", "axios": "^1.7.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", "ic-auth": "^0.9.1", + "lucide-react": "^0.453.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "recoil": "^0.7.7" + "recoil": "^0.7.7", + "tailwind-merge": "^2.5.4", + "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "@dfinity/auth-client": "^1.4.0", @@ -27,11 +38,11 @@ "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "@vitejs/plugin-react": "^4.0.1", - "autoprefixer": "^10.4.19", + "autoprefixer": "^10.4.20", "dotenv": "^16.4.5", - "postcss": "^8.4.38", + "postcss": "^8.4.47", "sass": "^1.63.6", - "tailwindcss": "^3.4.4", + "tailwindcss": "^3.4.14", "typescript": "^5.1.3", "vite": "^4.3.9", "vite-plugin-environment": "^1.1.3" diff --git a/src/deda_frontend/src/App.tsx b/src/deda_frontend/src/App.tsx index fec003e..cea524a 100644 --- a/src/deda_frontend/src/App.tsx +++ b/src/deda_frontend/src/App.tsx @@ -1,26 +1,29 @@ -import React from 'react'; -import { RecoilRoot, useRecoilValue } from 'recoil'; -import Login from './components/Login'; -import DataRequestList from './components/DataRequestList'; -import SubmitData from './components/SubmitData'; -import VerifyData from './components/VerifyData'; -import StoreCleanedData from './components/StoreCleanedData'; -import AddDataRequest from './components/AddDataRequest'; -import PayContributors from './components/PayContributors'; -//import './App.css'; -import { userState } from './state/userState'; +import React from "react"; +import { RecoilRoot, useRecoilValue } from "recoil"; +import MainPage from "./Pages/Main/MainPage"; +import Login from "./components/Login"; +import DataRequestList from "./components/DataRequestList"; +import SubmitData from "./components/SubmitData"; +import VerifyData from "./components/VerifyData"; +import StoreCleanedData from "./components/StoreCleanedData"; +import AddDataRequest from "./components/AddDataRequest"; +import PayContributors from "./components/PayContributors"; +import "./App.css"; +import { userState } from "./state/userState"; const AppContent: React.FC = () => { const user = useRecoilValue(userState); return (
-

DeDa - Decentralized Data Marketplace

+

+ DeDa - Decentralized Data Marketplace +

- {user.role === 'Researcher' && } + {user.role === "Researcher" && } - {user.role === 'User' && } - {user.role === 'Validator' && ( + {user.role === "User" && } + {user.role === "Validator" && ( <> @@ -33,7 +36,8 @@ const AppContent: React.FC = () => { const App: React.FC = () => ( - + {/* */} + ); diff --git a/src/deda_frontend/src/Pages/Main/MainPage.tsx b/src/deda_frontend/src/Pages/Main/MainPage.tsx new file mode 100644 index 0000000..ced5da2 --- /dev/null +++ b/src/deda_frontend/src/Pages/Main/MainPage.tsx @@ -0,0 +1,185 @@ +import React, { useState } from "react"; +import { + Bell, + ChevronDown, + Home, + Search, + Settings, + User, + Database, + FileCheck, + DollarSign, +} from "lucide-react"; +import { Button } from "../../components/ui/button"; +import { ScrollArea } from "../../components/ui/scroll-area"; +import { Separator } from "../../components/ui/separator"; +import { Switch } from "../../components/ui/switch"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "../../components/ui/tabs"; +import CompletedTasks from "../../components/Tasks/CompletedTasks"; +import ResearcherDashboard from "../../components/Dashboards/ResearcherDashBoard"; +import PublisherDashboard from "../../components/Dashboards/PublisherDashBoard"; +import ValidatorDashboard from "../../components/Dashboards/ValidatorDashBoard"; + +export default function MainPage() { + const [activeRole, setActiveRole] = useState("researcher"); + + return ( +
+ {/* Left Sidebar */} +
+
DEDA
+ +
+ + +
+
+ + {/* Main Content */} +
+ {/* Top Bar */} +
+
+ + + + +
+
+ + +
+
+ + {/* Content Area */} + + + + + Active + + + Completed + + + + {activeRole === "researcher" && } + {activeRole === "publisher" && } + {activeRole === "validator" && } + + + + + + +
+ + {/* Right Sidebar */} +
+

Statistics

+
+
+ Total Datasets + 1,234 +
+
+ Active Requests + 56 +
+
+ Pending Validations + 23 +
+
+ +
+
+ Notifications + +
+
+ Auto-match Requests + +
+
+ +

Recent Activity

+
+

New dataset submitted for NLP task

+

Validation completed for Image Classification data

+

Reward distributed for Sentiment Analysis contribution

+
+
+
+ ); +} diff --git a/src/deda_frontend/src/components/AddDataRequest.tsx b/src/deda_frontend/src/components/AddDataRequest.tsx index 86e4870..2c5c19b 100644 --- a/src/deda_frontend/src/components/AddDataRequest.tsx +++ b/src/deda_frontend/src/components/AddDataRequest.tsx @@ -1,27 +1,35 @@ -import React, { useState } from 'react'; -import { Actor, HttpAgent } from '@dfinity/agent'; -import { idlFactory } from '../../../declarations/deda_backend'; +import React, { useState } from "react"; +import { Actor, HttpAgent } from "@dfinity/agent"; +import { idlFactory } from "../../../declarations/deda_backend"; const agent = new HttpAgent(); -agent.fetchRootKey().catch(err => { - console.warn('Unable to fetch root key. Check to ensure that your local replica is running'); +agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); console.error(err); }); -const backend = Actor.createActor(idlFactory as any, { agent, canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string }); +const backend = Actor.createActor(idlFactory as any, { + agent, + canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string, +}); const AddDataRequest: React.FC = () => { - const [description, setDescription] = useState(''); - const [reward, setReward] = useState(''); - const [response, setResponse] = useState(''); + const [description, setDescription] = useState(""); + const [reward, setReward] = useState(""); + const [response, setResponse] = useState(""); const addDataRequest = async () => { try { - const requestId = await backend.add_data_request(description, BigInt(reward)); + const requestId = await backend.add_data_request( + description, + BigInt(reward) + ); console.log(requestId); setResponse(`Data request added successfully with ID: ${requestId}`); } catch (error) { - console.error(error) - setResponse('Error adding data request'); + console.error(error); + setResponse("Error adding data request"); } }; @@ -42,7 +50,10 @@ const AddDataRequest: React.FC = () => { onChange={(e) => setReward(e.target.value)} className="p-2 border rounded mb-2" /> - {response &&
{response}
} diff --git a/src/deda_frontend/src/components/Dashboards/PublisherDashBoard.tsx b/src/deda_frontend/src/components/Dashboards/PublisherDashBoard.tsx new file mode 100644 index 0000000..761691c --- /dev/null +++ b/src/deda_frontend/src/components/Dashboards/PublisherDashBoard.tsx @@ -0,0 +1,55 @@ +import { Button } from "../ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; + +function PublisherDashboard() { + return ( +
+ + + Available Data Requests + + +
    +
  • +
    + Large Language Model Training Data + 50 ICP +
    + +
  • +
  • +
    + Computer Vision Dataset + 30 ICP +
    + +
  • +
+
+
+ + + Your Submitted Datasets + + +
    +
  • Sentiment Analysis Corpus - Under Validation
  • +
  • Time Series Data - Validated, Reward Pending
  • +
+
+
+
+ ); +} + +export default PublisherDashboard; diff --git a/src/deda_frontend/src/components/Dashboards/ResearcherDashBoard.tsx b/src/deda_frontend/src/components/Dashboards/ResearcherDashBoard.tsx new file mode 100644 index 0000000..45252ee --- /dev/null +++ b/src/deda_frontend/src/components/Dashboards/ResearcherDashBoard.tsx @@ -0,0 +1,58 @@ +import { Button } from "../ui/button"; +import { Input } from "../ui/input"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "../ui/card"; + +function ResearcherDashboard() { + return ( +
+ + + Request New Dataset + + Specify your data requirements and set a reward + + + +
+ + + + +
+
+
+ + + Your Active Requests + + +
    +
  • Machine Learning Dataset - Pending Validation
  • +
  • NLP Corpus - Data Submitted
  • +
  • Image Recognition Set - Awaiting Data
  • +
+
+
+
+ ); +} + +export default ResearcherDashboard; diff --git a/src/deda_frontend/src/components/Dashboards/ValidatorDashBoard.tsx b/src/deda_frontend/src/components/Dashboards/ValidatorDashBoard.tsx new file mode 100644 index 0000000..b839e3c --- /dev/null +++ b/src/deda_frontend/src/components/Dashboards/ValidatorDashBoard.tsx @@ -0,0 +1,82 @@ +import { Button } from "../ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; + +function ValidatorDashboard() { + return ( +
+ + + Datasets Pending Validation + + +
    +
  • +
    Machine Learning Dataset
    +
    + + + +
    +
  • +
  • +
    NLP Corpus
    +
    + + + +
    +
  • +
+
+
+ + + Your Validation History + + +
    +
  • Image Recognition Set - Validated
  • +
  • Time Series Data - Validated
  • +
  • Sentiment Analysis Corpus - Rejected (Low Quality)
  • +
+
+
+
+ ); +} + +export default ValidatorDashboard; diff --git a/src/deda_frontend/src/components/DataRequestList.tsx b/src/deda_frontend/src/components/DataRequestList.tsx index f57cb2f..5687cd9 100644 --- a/src/deda_frontend/src/components/DataRequestList.tsx +++ b/src/deda_frontend/src/components/DataRequestList.tsx @@ -1,23 +1,29 @@ -import React, { useEffect, useState } from 'react'; -import { Actor, HttpAgent } from '@dfinity/agent'; -import { idlFactory } from '../../../declarations/deda_backend'; -import { DataRequest } from '../types'; +import React, { useEffect, useState } from "react"; +import { Actor, HttpAgent } from "@dfinity/agent"; +import { idlFactory } from "../../../declarations/deda_backend"; +import { DataRequest } from "../types"; const agent = new HttpAgent(); -agent.fetchRootKey().catch(err => { - console.warn('Unable to fetch root key. Check to ensure that your local replica is running'); +agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); console.error(err); }); -const backend = Actor.createActor(idlFactory as any, { agent, canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string }); -console.log(backend) +const backend = Actor.createActor(idlFactory as any, { + agent, + canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string, +}); +console.log(backend); const DataRequestList: React.FC = () => { const [dataRequests, setDataRequests] = useState([]); useEffect(() => { const fetchDataRequests = async () => { - const requests = await backend.get_data_requests() as unknown as DataRequest[]; - console.log(requests) + const requests = + (await backend.get_data_requests()) as unknown as DataRequest[]; + console.log(requests); setDataRequests(requests); }; @@ -38,9 +44,15 @@ const DataRequestList: React.FC = () => { {dataRequests.map((request) => ( - {request.id.toString()} - {request.description} - {request.reward.toString()} + + {request.id.toString()} + + + {request.description} + + + {request.reward.toString()} + ))} diff --git a/src/deda_frontend/src/components/Login.tsx b/src/deda_frontend/src/components/Login.tsx index 7fc2170..42cac12 100644 --- a/src/deda_frontend/src/components/Login.tsx +++ b/src/deda_frontend/src/components/Login.tsx @@ -1,86 +1,93 @@ -import React, { useState } from 'react'; -import { useRecoilState } from 'recoil'; -import { userState } from '../state/userState'; -import { Actor, HttpAgent } from '@dfinity/agent'; -import { idlFactory as deda_backend_idl } from '../../../declarations/deda_backend'; -import { Principal } from '@dfinity/principal'; -import { AuthClient } from '@dfinity/auth-client'; +import React, { useState } from "react"; +import { useRecoilState } from "recoil"; +import { userState } from "../state/userState"; +import { Actor, HttpAgent } from "@dfinity/agent"; +import { idlFactory as deda_backend_idl } from "../../../declarations/deda_backend"; +import { Principal } from "@dfinity/principal"; +import { AuthClient } from "@dfinity/auth-client"; const canisterId = process.env.CANISTER_ID_DEDA_BACKEND as string; const agent = new HttpAgent(); -agent.fetchRootKey().catch(err => { - console.warn('Unable to fetch root key. Check to ensure that your local replica is running'); +agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); console.error(err); }); -const backend = Actor.createActor(deda_backend_idl as any, { agent, canisterId: canisterId }); +const backend = Actor.createActor(deda_backend_idl as any, { + agent, + canisterId: canisterId, +}); console.log(backend); const Login: React.FC = () => { const [user, setUser] = useRecoilState(userState); const [loading, setLoading] = useState(false); - const [role, setRole] = useState<'User' | 'Validator' | 'Researcher'>('User'); + const [role, setRole] = useState<"User" | "Validator" | "Researcher">("User"); const login = async () => { setLoading(true); try { - console.log('Role: ', role); + console.log("Role: ", role); let authClient = await AuthClient.create({ idleOptions: { - idleTimeout: 1000 * 60 * 60 - } + idleTimeout: 1000 * 60 * 60, + }, }); await authClient.login({ //identityProvider: `http://127.0.0.1:4943/?canisterId=${process.env.CANISTER_ID_INTERNET_IDENTITY}`, identityProvider: `http://${process.env.CANISTER_ID_INTERNET_IDENTITY}.localhost:4943/`, - onSuccess: async() => { + onSuccess: async () => { console.log("Login successful"); - const identity = authClient.getIdentity().getPrincipal().toString(); - console.log(identity) + const identity = authClient.getIdentity().getPrincipal().toString(); + console.log(identity); const principal = Principal.fromText(identity); - console.log(principal) + console.log(principal); try { - const balance = (await backend.get_balance(principal)) as unknown as number; - console.log(balance) + const balance = (await backend.get_balance( + principal + )) as unknown as number; + console.log(balance); const result = await backend.login(principal, role); console.log(result); setUser({ id: principal, balance, role }); } catch (e) { - console.error('Error fetching balance or logging in:', e); + console.error("Error fetching balance or logging in:", e); } - }, }); /*if (await authClient.isAuthenticated()) { - - + }*/ /*if ('Err' in result) { throw new Error(result.Err); }*/ - } catch (err) { - console.error('Error logging in:', err); + console.error("Error logging in:", err); } setLoading(false); }; return (
- + setRole(e.target.value as "User" | "Validator" | "Researcher") + } className="p-2 border rounded mb-2" > - {user.id && (
diff --git a/src/deda_frontend/src/components/PayContributors.tsx b/src/deda_frontend/src/components/PayContributors.tsx index a3ed4eb..3c42c4f 100644 --- a/src/deda_frontend/src/components/PayContributors.tsx +++ b/src/deda_frontend/src/components/PayContributors.tsx @@ -1,26 +1,31 @@ -import React, { useState } from 'react'; -import { Actor, HttpAgent } from '@dfinity/agent'; -import { idlFactory } from '../../../declarations/deda_backend'; -import * as dotenv from 'dotenv'; +import React, { useState } from "react"; +import { Actor, HttpAgent } from "@dfinity/agent"; +import { idlFactory } from "../../../declarations/deda_backend"; +// import * as dotenv from 'dotenv'; //dotenv.config() const agent = new HttpAgent(); -agent.fetchRootKey().catch(err => { - console.warn('Unable to fetch root key. Check to ensure that your local replica is running'); +agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); console.error(err); }); -const backend = Actor.createActor(idlFactory as any, { agent, canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string }); +const backend = Actor.createActor(idlFactory as any, { + agent, + canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string, +}); const PayContributors: React.FC = () => { - const [submissionId, setSubmissionId] = useState(''); - const [response, setResponse] = useState(''); + const [submissionId, setSubmissionId] = useState(""); + const [response, setResponse] = useState(""); const payContributors = async () => { try { await backend.pay_contributors(Number(submissionId)); // pay_contributors function invoked - setResponse('Contributors paid successfully'); + setResponse("Contributors paid successfully"); } catch (error) { - setResponse('Error paying contributors'); + setResponse("Error paying contributors"); } }; @@ -34,7 +39,10 @@ const PayContributors: React.FC = () => { onChange={(e) => setSubmissionId(e.target.value)} className="p-2 border rounded mb-2" /> - {response &&
{response}
} diff --git a/src/deda_frontend/src/components/StoreCleanedData.tsx b/src/deda_frontend/src/components/StoreCleanedData.tsx index 68b91f1..0f94d29 100644 --- a/src/deda_frontend/src/components/StoreCleanedData.tsx +++ b/src/deda_frontend/src/components/StoreCleanedData.tsx @@ -1,27 +1,32 @@ -import React, { useState } from 'react'; -import { Actor, HttpAgent } from '@dfinity/agent'; -import { idlFactory } from '../../../declarations/deda_backend'; -import * as dotenv from 'dotenv'; +import React, { useState } from "react"; +import { Actor, HttpAgent } from "@dfinity/agent"; +import { idlFactory } from "../../../declarations/deda_backend"; +import * as dotenv from "dotenv"; //dotenv.config() const agent = new HttpAgent(); -agent.fetchRootKey().catch(err => { - console.warn('Unable to fetch root key. Check to ensure that your local replica is running'); +agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); console.error(err); }); -const backend = Actor.createActor(idlFactory as any, { agent, canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string }); +const backend = Actor.createActor(idlFactory as any, { + agent, + canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string, +}); const StoreCleanedData: React.FC = () => { - const [requestId, setRequestId] = useState(''); - const [location, setLocation] = useState(''); - const [response, setResponse] = useState(''); + const [requestId, setRequestId] = useState(""); + const [location, setLocation] = useState(""); + const [response, setResponse] = useState(""); const storeCleanedData = async () => { try { await backend.store_cleaned_data(Number(requestId), location); - setResponse('Cleaned data stored successfully'); + setResponse("Cleaned data stored successfully"); } catch (error) { - setResponse('Error storing cleaned data'); + setResponse("Error storing cleaned data"); } }; @@ -42,7 +47,10 @@ const StoreCleanedData: React.FC = () => { onChange={(e) => setLocation(e.target.value)} className="p-2 border rounded mb-2" /> - {response &&
{response}
} diff --git a/src/deda_frontend/src/components/SubmitData.tsx b/src/deda_frontend/src/components/SubmitData.tsx index 257070b..c37c5ab 100644 --- a/src/deda_frontend/src/components/SubmitData.tsx +++ b/src/deda_frontend/src/components/SubmitData.tsx @@ -1,36 +1,45 @@ -import React, { useState } from 'react'; -import { useRecoilValue } from 'recoil'; -import { userState } from '../state/userState'; -import { Actor, HttpAgent } from '@dfinity/agent'; -import { idlFactory } from '../../../declarations/deda_backend'; +import React, { useState } from "react"; +import { useRecoilValue } from "recoil"; +import { userState } from "../state/userState"; +import { Actor, HttpAgent } from "@dfinity/agent"; +import { idlFactory } from "../../../declarations/deda_backend"; const agent = new HttpAgent(); -agent.fetchRootKey().catch(err => { - console.warn('Unable to fetch root key. Check to ensure that your local replica is running'); +agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); console.error(err); }); -const backend = Actor.createActor(idlFactory as any, { agent, canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string }); +const backend = Actor.createActor(idlFactory as any, { + agent, + canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string, +}); const SubmitData: React.FC = () => { const user = useRecoilValue(userState); - const [requestId, setRequestId] = useState(''); - const [location, setLocation] = useState(''); - const [response, setResponse] = useState(''); + const [requestId, setRequestId] = useState(""); + const [location, setLocation] = useState(""); + const [response, setResponse] = useState(""); const submitData = async () => { try { const principal = user.id; - const result: any= await backend.submit_data(principal, Number(requestId), location); - console.log(result) - if ('Ok' in result) { + const result: any = await backend.submit_data( + principal, + Number(requestId), + location + ); + console.log(result); + if ("Ok" in result) { const submissionId = result.Ok; console.log(submissionId); setResponse(`Data submitted successfully with ID: ${submissionId}`); - } else if ('Err' in result) { + } else if ("Err" in result) { setResponse(`Error submitting data: ${result.Err}`); } } catch (error) { - setResponse('Error submitting data'); + setResponse("Error submitting data"); } }; @@ -51,7 +60,10 @@ const SubmitData: React.FC = () => { onChange={(e) => setLocation(e.target.value)} className="p-2 border rounded mb-2" /> - {response &&
{response}
} diff --git a/src/deda_frontend/src/components/Tasks/CompletedTasks.tsx b/src/deda_frontend/src/components/Tasks/CompletedTasks.tsx new file mode 100644 index 0000000..4f251c8 --- /dev/null +++ b/src/deda_frontend/src/components/Tasks/CompletedTasks.tsx @@ -0,0 +1,20 @@ +import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; + +function CompletedTasks() { + return ( + + + Completed Tasks + + +
    +
  • NLP Dataset - Completed on 2023-10-15
  • +
  • Image Classification Data - Completed on 2023-10-10
  • +
  • Time Series Analysis Set - Completed on 2023-10-05
  • +
+
+
+ ); +} + +export default CompletedTasks; diff --git a/src/deda_frontend/src/components/VerifyData.tsx b/src/deda_frontend/src/components/VerifyData.tsx index b77d40f..ee02216 100644 --- a/src/deda_frontend/src/components/VerifyData.tsx +++ b/src/deda_frontend/src/components/VerifyData.tsx @@ -1,34 +1,42 @@ -import React, { useState } from 'react'; -import { useRecoilValue } from 'recoil'; -import { userState } from '../state/userState'; -import { Actor, HttpAgent } from '@dfinity/agent'; -import { idlFactory } from '../../../declarations/deda_backend'; -import * as dotenv from 'dotenv'; +import React, { useState } from "react"; +import { useRecoilValue } from "recoil"; +import { userState } from "../state/userState"; +import { Actor, HttpAgent } from "@dfinity/agent"; +import { idlFactory } from "../../../declarations/deda_backend"; +import * as dotenv from "dotenv"; //dotenv.config() const agent = new HttpAgent(); -agent.fetchRootKey().catch(err => { - console.warn('Unable to fetch root key. Check to ensure that your local replica is running'); +agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); console.error(err); }); -const backend = Actor.createActor(idlFactory as any, { agent, canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string }); +const backend = Actor.createActor(idlFactory as any, { + agent, + canisterId: process.env.CANISTER_ID_DEDA_BACKEND as string, +}); const VerifyData: React.FC = () => { const user = useRecoilValue(userState); - const [submissionId, setSubmissionId] = useState(''); - const [response, setResponse] = useState(''); + const [submissionId, setSubmissionId] = useState(""); + const [response, setResponse] = useState(""); const verifyData = async () => { try { const principal = user.id; - const result: any = await backend.verify_data(principal, Number(submissionId)); - if ('Ok' in result) { - setResponse('Data verified successfully'); + const result: any = await backend.verify_data( + principal, + Number(submissionId) + ); + if ("Ok" in result) { + setResponse("Data verified successfully"); } else { - setResponse('Error verifying data: ' + result.Err); + setResponse("Error verifying data: " + result.Err); } } catch (error) { - setResponse('Error verifying data'); + setResponse("Error verifying data"); } }; @@ -42,7 +50,10 @@ const VerifyData: React.FC = () => { onChange={(e) => setSubmissionId(e.target.value)} className="p-2 border rounded mb-2" /> - {response &&
{response}
} diff --git a/src/deda_frontend/src/components/ui/button.tsx b/src/deda_frontend/src/components/ui/button.tsx new file mode 100644 index 0000000..385418c --- /dev/null +++ b/src/deda_frontend/src/components/ui/button.tsx @@ -0,0 +1,57 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "../../lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + } +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/src/deda_frontend/src/components/ui/card.tsx b/src/deda_frontend/src/components/ui/card.tsx new file mode 100644 index 0000000..54b4985 --- /dev/null +++ b/src/deda_frontend/src/components/ui/card.tsx @@ -0,0 +1,83 @@ +import * as React from "react"; + +import { cn } from "../../lib/utils"; + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardFooter.displayName = "CardFooter"; + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/src/deda_frontend/src/components/ui/input.tsx b/src/deda_frontend/src/components/ui/input.tsx new file mode 100644 index 0000000..bfd682c --- /dev/null +++ b/src/deda_frontend/src/components/ui/input.tsx @@ -0,0 +1,25 @@ +import * as React from "react"; + +import { cn } from "../../lib/utils"; + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ); + } +); +Input.displayName = "Input"; + +export { Input }; diff --git a/src/deda_frontend/src/components/ui/scroll-area.tsx b/src/deda_frontend/src/components/ui/scroll-area.tsx new file mode 100644 index 0000000..847fca2 --- /dev/null +++ b/src/deda_frontend/src/components/ui/scroll-area.tsx @@ -0,0 +1,46 @@ +import * as React from "react"; +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; + +import { cn } from "../../lib/utils"; + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)); +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = "vertical", ...props }, ref) => ( + + + +)); +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; + +export { ScrollArea, ScrollBar }; diff --git a/src/deda_frontend/src/components/ui/separator.tsx b/src/deda_frontend/src/components/ui/separator.tsx new file mode 100644 index 0000000..e3eb575 --- /dev/null +++ b/src/deda_frontend/src/components/ui/separator.tsx @@ -0,0 +1,29 @@ +import * as React from "react"; +import * as SeparatorPrimitive from "@radix-ui/react-separator"; + +import { cn } from "../../lib/utils"; + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref + ) => ( + + ) +); +Separator.displayName = SeparatorPrimitive.Root.displayName; + +export { Separator }; diff --git a/src/deda_frontend/src/components/ui/switch.tsx b/src/deda_frontend/src/components/ui/switch.tsx new file mode 100644 index 0000000..7614f32 --- /dev/null +++ b/src/deda_frontend/src/components/ui/switch.tsx @@ -0,0 +1,27 @@ +import * as React from "react"; +import * as SwitchPrimitives from "@radix-ui/react-switch"; + +import { cn } from "../../lib/utils"; + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +Switch.displayName = SwitchPrimitives.Root.displayName; + +export { Switch }; diff --git a/src/deda_frontend/src/components/ui/tabs.tsx b/src/deda_frontend/src/components/ui/tabs.tsx new file mode 100644 index 0000000..52d563a --- /dev/null +++ b/src/deda_frontend/src/components/ui/tabs.tsx @@ -0,0 +1,53 @@ +import * as React from "react"; +import * as TabsPrimitive from "@radix-ui/react-tabs"; + +import { cn } from "../../lib/utils"; + +const Tabs = TabsPrimitive.Root; + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsList.displayName = TabsPrimitive.List.displayName; + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName; + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsContent.displayName = TabsPrimitive.Content.displayName; + +export { Tabs, TabsList, TabsTrigger, TabsContent }; diff --git a/src/deda_frontend/src/index.scss b/src/deda_frontend/src/index.scss index bd6213e..46947be 100644 --- a/src/deda_frontend/src/index.scss +++ b/src/deda_frontend/src/index.scss @@ -1,3 +1,66 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary: 0 0% 9%; + --primary-foreground: 0 0% 98%; + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem + } + .dark { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55% + } +} +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} \ No newline at end of file diff --git a/src/deda_frontend/src/lib/utils.ts b/src/deda_frontend/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/src/deda_frontend/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/src/deda_frontend/tailwind.config.js b/src/deda_frontend/tailwind.config.js index 2c0dcca..7ff9e42 100644 --- a/src/deda_frontend/tailwind.config.js +++ b/src/deda_frontend/tailwind.config.js @@ -1,7 +1,56 @@ module.exports = { - content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], + darkMode: ['class'], + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { - extend: {}, + extend: { + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + colors: { + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))' + } + } + } }, - plugins: [], + plugins: [require("tailwindcss-animate")], } diff --git a/src/deda_frontend/tsconfig.json b/src/deda_frontend/tsconfig.json index 39a545e..3e3ad29 100644 --- a/src/deda_frontend/tsconfig.json +++ b/src/deda_frontend/tsconfig.json @@ -15,7 +15,11 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", - "types": ["vite/client"] + "types": ["vite/client"], + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } }, "include": ["src"] } diff --git a/src/deda_frontend/vite.config.js b/src/deda_frontend/vite.config.js index 670b034..6d39414 100644 --- a/src/deda_frontend/vite.config.js +++ b/src/deda_frontend/vite.config.js @@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; import environment from 'vite-plugin-environment'; import dotenv from 'dotenv'; +import path from "path" dotenv.config({ path: '../../.env' }); @@ -34,6 +35,7 @@ export default defineConfig({ alias: [ { find: "declarations", + "@": path.resolve(__dirname, "./src"), replacement: fileURLToPath( new URL("../declarations", import.meta.url) ),