From 422503df1a22b02bffd0b916a2378f248cd4d4b9 Mon Sep 17 00:00:00 2001 From: Rushikesh Nimkar Date: Fri, 30 Aug 2024 14:01:13 +0530 Subject: [PATCH 01/12] fix : dvpn title --- utils/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/data.js b/utils/data.js index aaf41b3..0e6966c 100644 --- a/utils/data.js +++ b/utils/data.js @@ -1,7 +1,7 @@ export const cardDetails2 = [ { image: "win1", - title: " ÐVPN for Unparalleled Privacys", + title: " ÐVPN for Unparalleled Privacy", desc1: "No data is ever tracked or logged without your explicit consent.", desc2: "Open-source code ensures complete transparency and reinforces our commitment to safety and user privacy.", From 82f1d2be8f4d18f852cc77fe459ff9563e1f89de Mon Sep 17 00:00:00 2001 From: Ashwini-Paw Date: Fri, 30 Aug 2024 16:21:32 +0530 Subject: [PATCH 02/12] Fix: Profile.js ,id.tsx mobile UI --- pages/nodeinfo/[id].tsx | 256 +++++++++++++++++++++++----------------- pages/profile.js | 230 +++++++++++++++++------------------- 2 files changed, 260 insertions(+), 226 deletions(-) diff --git a/pages/nodeinfo/[id].tsx b/pages/nodeinfo/[id].tsx index 7cf74e6..f87a717 100644 --- a/pages/nodeinfo/[id].tsx +++ b/pages/nodeinfo/[id].tsx @@ -24,6 +24,7 @@ interface Node { domain: string; ipinfoip: string; chainName: string; + price: number; // or string } interface Client { @@ -95,88 +96,111 @@ const NodeDetail: React.FC = () => { // const data = [{ country: node.region, value: 0 }]; return ( -
-
{node.name}
- -
-
+
+
{node.name}
+ +
+
IP City: {node.ipinfocity}, {node.ipinfocountry}
IP TimeZone: {node.ipinfotimezone}
IP Org: {node.ipinfoorg}
- -
+ +
-
-
- Node Name -
-
- Status -
-
- Start Time -
-
- Last Pinged -
-
+
+
+
+ {/* Header Section */} +
+
Node Name
+
Status
+
Start Time
+
Last Pinged
+
-
-
{node.nodename}
-
- {node.status} -
-
{new Date(node.startTimeStamp * 1000).toLocaleString()}
-
{new Date(node.lastPingedTimeStamp * 1000).toLocaleString()}
-
-
+ {/* Data Section for Desktop */} +
+
{node.nodename}
+
+ {node.status} +
+
{new Date(node.startTimeStamp * 1000).toLocaleString()}
+
{new Date(node.lastPingedTimeStamp * 1000).toLocaleString()}
+
+ + {/* Data Section for Mobile */} +
+
+
Node Name:
+
{node.nodename}
+
+
+
Status:
+
{node.status}
+
+
+
Start Time:
+
{new Date(node.startTimeStamp * 1000).toLocaleString()}
+
+
+
Last Pinged:
+
{new Date(node.lastPingedTimeStamp * 1000).toLocaleString()}
+
+
+
+
+
+
+
-
- Bandwidth trans. data -
-
-
-
-
- -
- {node.uploadSpeed} -
Kbps Speed
-
-
-
Upload
-
-
-
- -
- {node.downloadSpeed} -
Kbps Speed
-
-
-
Download
-
-
-
+
+ Bandwidth trans. data +
+
+
+
+
+ +
+
{node.uploadSpeed}
+
Kbps Speed
+
+
+
Upload
+
+ +
+
+ +
+
{node.downloadSpeed}
+
Kbps Speed
+
+
Download
+
+
+
+
-
-
+ +
+
{ data={data} />
-
+
-
+
Domain
-
{node.domain}
+
{node.domain}
- +
-
+
IP Address
-
{node.ipinfoip}
+
{node.ipinfoip}
- +
-
+
Chain
-
{node.chainName}
+
{node.chainName}
- -
+ +
-
-
- Client Name -
-
- User ID -
-
- Region -
-
- Created At -
-
+
+ {/* Header Section for Desktop */} +
+
Client Name
+
User ID
+
Region
+
Created At
+
- {clients.map((client) => ( -
-
{client.name}
-
{client.userId}
-
{client.region}
-
{new Date(client.created_at).toLocaleString()}
-
- ))} -
+ {/* Data Section for Desktop */} + {clients.map((client) => ( +
+
{client.name}
+
{client.userId}
+
{client.region}
+
{new Date(client.created_at).toLocaleString()}
+
+ ))} + {/* Data Section for Mobile */} + {clients.map((client) => ( +
+
+
Client Name:
+
{client.name}
+
+
+
User ID:
+
{client.userId}
+
+
+
Region:
+
{client.region}
+
+
+
Created At:
+
{new Date(client.created_at).toLocaleString()}
+
+
+ ))} +
+
-
- Total Clients +
+ Price
-
{clients?.length ? clients?.length : 0}
+
{node.price}
); -}; +} -export default NodeDetail; +export default NodeDetail; \ No newline at end of file diff --git a/pages/profile.js b/pages/profile.js index 71d21a7..848c8da 100644 --- a/pages/profile.js +++ b/pages/profile.js @@ -551,135 +551,127 @@ const chainDetails = chainInfo[chainsym?.toLowerCase()] || { name: 'Unknown Chai {profileset && ( <> -
-

-
Profile information
-
-
- {chainDetails.icon && {`${chainDetails.name}} - {chainDetails.name} -
-
{walletaddr?.slice(0, 4)}...{walletaddr?.slice(-4)}
+
+
+
+

+ Profile information +

+
+
+ {chainDetails.icon && ( + {`${chainDetails.name} + )} + {chainDetails.name} +
+
+ {walletaddr?.slice(0, 4)}...{walletaddr?.slice(-4)} +
+
+
+ +
+
+
+
+
+ {profileData?.profilePictureUrl ? ( +
+ Profile
-

-
-
- -
-
-
- {profileData?.profilePictureUrl ? ( -
- alt -
- ) : ( -
- {/* */} - alt -
- )} -
-
+ ) : ( +
+ Default Profile +
+ )} +
+
-
-
-
- {profileData?.name - ? profileData?.name - : "Name"} -
+
+
+
+ {profileData?.name || "Name"} +
-
- {profileData?.country - ? profileData?.country - : "Country"} -
-
+
+ {profileData?.country || "Country"} +
-
-
- {profileData?.discord - ? profileData?.discord - : "Discord"} -
+
+ {profileData?.discord || "Discord"} +
-
- {profileData?.twitter - ? profileData?.twitter - : "Twitter"} -
-
-
-
+
+ {profileData?.twitter || "Twitter"} +
+
-
-
- -
-
- +
+ +
+
+
+ - {loading && ( -
-
-
-
- Loading icon - - Loading... + {loading && ( +
+
+
+
+ Loading icon + Loading... +
+
+
-
+ )}
- )} - -
-
- - + )} From 571301970716f5a0fc1d4a0ae2e79b87b7a11df7 Mon Sep 17 00:00:00 2001 From: Ashwini-Paw Date: Sun, 1 Sep 2024 12:23:52 +0530 Subject: [PATCH 03/12] UI changes on the NodeDataDvpnUser, NodeDataDwifiUser --- components/NodesDataDvpnUser.jsx | 28 +++++++++++++++++----------- components/nodedataDwifiUser.js | 26 ++++++++++++-------------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/components/NodesDataDvpnUser.jsx b/components/NodesDataDvpnUser.jsx index 354dbd8..9734d30 100644 --- a/components/NodesDataDvpnUser.jsx +++ b/components/NodesDataDvpnUser.jsx @@ -15,7 +15,7 @@ const NodesData = () => { const fetchNodesData = async () => { try { - const response = await axios.get(`${EREBRUS_GATEWAY_URL}api/v1.0/nodes/all`); + const response = await axios.get(`${EREBRUS_GATEWAY_URL}/api/v1.0/nodes/all`); console.log("API Response:", response.data); @@ -73,15 +73,21 @@ const NodesData = () => { {nodesdata.length > 0 ? (
- - - {["Node Name", "Chain", "Wallet Address", "Region", "Network Speed", "Status", "Uptime", "Last Ping"].map((header) => ( - - ))} - - + + + {["Node Name", "Chain", "Wallet Address", "Region", "Network Speed", "Status", "Uptime", "Last Ping"].map((header) => ( + + ))} + + + + {nodesdata.map((node) => ( { ); }; -export default NodesData; +export default NodesData; \ No newline at end of file diff --git a/components/nodedataDwifiUser.js b/components/nodedataDwifiUser.js index 96bea2e..3a0fb4f 100644 --- a/components/nodedataDwifiUser.js +++ b/components/nodedataDwifiUser.js @@ -95,7 +95,6 @@ const NodeDwifiStreamUser = () => { ); } - return (

DWifi Nodes Dashboard

@@ -103,9 +102,9 @@ const NodeDwifiStreamUser = () => {
- {header} -
+ {header} +
- + {["Host SSID", "Gateway", "Chain", "Interface", "Connected Devices", "Status", "Location", "Connected At", "Last Pinged"].map((header) => ( - ))} @@ -115,25 +114,25 @@ const NodeDwifiStreamUser = () => { {Object.values(uniqueNodesData).map((item) => ( - - - - - - + + + + + - - - + + + ))} @@ -142,5 +141,4 @@ const NodeDwifiStreamUser = () => { ); }; - export default NodeDwifiStreamUser; \ No newline at end of file From a7e0dfd8287988044b68553174d44b50e2f8341e Mon Sep 17 00:00:00 2001 From: vaibhavvvvv Date: Tue, 3 Sep 2024 12:32:51 +0530 Subject: [PATCH 04/12] Scan: Add Map page to scan nearby dwifi nodes using user's current location --- components/DwifiMap.js | 162 +++++++++++++++++--------------- components/nodedataDwifiUser.js | 22 ++++- pages/scan.js | 12 +++ 3 files changed, 116 insertions(+), 80 deletions(-) create mode 100644 pages/scan.js diff --git a/components/DwifiMap.js b/components/DwifiMap.js index ce4bfdd..1977198 100644 --- a/components/DwifiMap.js +++ b/components/DwifiMap.js @@ -1,9 +1,8 @@ import { useState, useEffect, useRef } from 'react'; -import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'; +import { MapContainer, TileLayer, Marker, Popup, useMap } from 'react-leaflet'; import 'leaflet/dist/leaflet.css'; import L from 'leaflet'; -// Custom icon const customIcon = new L.DivIcon({ html: `
@@ -13,119 +12,125 @@ const customIcon = new L.DivIcon({
`, className: 'ant-icon', - iconSize: [25, 41], // Twice the original size - iconAnchor: [12, 25], // Adjust anchor to be at the bottom center of the icon - popupAnchor: [1, -34], // Adjust popup position + iconSize: [25, 41], + iconAnchor: [12, 25], + popupAnchor: [1, -34], shadowUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png', shadowSize: [41, 41], }); +// Create a custom icon for the current location +const currentLocationIcon = new L.DivIcon({ + html: `
`, + className: '', + iconSize: [20, 20], + iconAnchor: [10, 10], + popupAnchor: [0, -10], +}); -// Add this CSS to handle the animation const style = document.createElement('style'); style.innerHTML = ` .custom-marker { animation: pulse 2s infinite; - color: #1E3A8A; /* Dark blue */ + color: #1E3A8A; } @keyframes pulse { 0%, 100% { transform: scale(0.9); - color: #1E3A8A; /* Dark blue */ + color: #1E3A8A; filter: drop-shadow(0 0 10px rgba(0, 0, 0, 0.5)); } 50% { transform: scale(1.1); - color: #3B82F6; /* Normal blue */ + color: #3B82F6; filter: drop-shadow(0 0 0px rgba(0, 0, 0, 0)); } } + + .current-location-marker { + background-color: blue; + border-radius: 50%; + width: 20px; + height: 20px; + position: relative; + animation: pulseLocation 2s infinite; + } + + @keyframes pulseLocation { + 0%, 100% { + box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.5); + } + 50% { + box-shadow: 0 0 20px 30px rgba(59, 130, 246, 0); + } + } `; document.head.appendChild(style); -export default function DwifiMap() { - const [nodes, setNodes] = useState([]); - const socketRef = useRef(null); // Use ref to maintain WebSocket across renders +// Component to handle current location marker +function CurrentLocationMarker() { + const map = useMap(); + const [position, setPosition] = useState(null); useEffect(() => { - const socket = new WebSocket('wss://dev.gateway.erebrus.io/api/v1.0/nodedwifi/stream'); + if (!navigator.geolocation) { + console.log('Geolocation is not supported by your browser'); + return; + } - socket.onopen = function () { - console.log('WebSocket is open now.'); - }; + navigator.geolocation.getCurrentPosition( + (position) => { + const { latitude, longitude } = position.coords; + setPosition([latitude, longitude]); + map.flyTo([latitude, longitude], 13); // Adjust the map's view to the user's location + }, + (error) => { + console.error('Error fetching geolocation:', error); + } + ); + }, [map]); - socket.onmessage = function (event) { - console.log('Received:'); - }; + return position === null ? null : ( + +
You are here
+
+ ); +} - socket.onerror = function (event) { - console.error('WebSocket error:', event); - }; +export default function WorldMap({ showCurrentLocation }) { + const [nodes, setNodes] = useState([]); + const socketRef = useRef(null); - socket.onclose = function (event) { - console.log('WebSocket is closed now.', event); - }; + useEffect(() => { + const socket = new WebSocket('wss://dev.gateway.erebrus.io/api/v1.0/nodedwifi/stream'); - return () => { - socket.close(); + socket.onopen = () => console.log('WebSocket is open now.'); + socket.onmessage = (event) => { + const newNode = JSON.parse(event.data); + setNodes((prevNodes) => { + const existingIndex = prevNodes.findIndex((node) => node.id === newNode.id); + if (existingIndex !== -1) { + return prevNodes.map((node) => (node.id === newNode.id ? newNode : node)); + } else { + return [...prevNodes, newNode]; + } + }); }; - }, []); - - useEffect(() => { - function connectWebSocket() { - // Initialize the WebSocket connection - socketRef.current = new WebSocket('wss://dev.gateway.erebrus.io/api/v1.0/nodedwifi/stream'); - - // Handle the WebSocket connection opening - socketRef.current.onopen = function () { - console.log('WebSocket is open now.'); - }; - - // Handle incoming WebSocket messages - socketRef.current.onmessage = function (event) { - const newNode = JSON.parse(event.data); - setNodes((prevNodes) => { - const existingIndex = prevNodes.findIndex((node) => node.id === newNode.id); - if (existingIndex !== -1) { - return prevNodes.map((node) => (node.id === newNode.id ? newNode : node)); - } else { - return [...prevNodes, newNode]; - } - }); - }; - - // Handle WebSocket errors - socketRef.current.onerror = function (event) { - console.error('WebSocket error:', event); - }; - - // Handle WebSocket closure - socketRef.current.onclose = function () { - console.log('WebSocket is closed. Attempting to reconnect...'); - setTimeout(connectWebSocket, 5000); // Attempt to reconnect after 5 seconds - }; - } - // Establish WebSocket connection - connectWebSocket(); + socket.onerror = (event) => console.error('WebSocket error:', event); + socket.onclose = () => console.log('WebSocket is closed.'); - // Cleanup function - return () => { - console.log('Cleaning up WebSocket connection...'); - if (socketRef.current) { - socketRef.current.close(); - } - }; - }, []); // Empty dependency array ensures this runs once + return () => socket.close(); + }, []); return (
-
Address: {node.location}
+
Address: {node.location}

Gateway: {node.gateway}

Price per Minute: {node.price_per_min}

Wallet Address: {node.wallet_address}

@@ -148,6 +153,7 @@ export default function DwifiMap() { ); })} + {showCurrentLocation && }
); diff --git a/components/nodedataDwifiUser.js b/components/nodedataDwifiUser.js index 3a0fb4f..8a858fb 100644 --- a/components/nodedataDwifiUser.js +++ b/components/nodedataDwifiUser.js @@ -1,8 +1,8 @@ "use client" import React, { useState, useEffect } from 'react'; import Cookies from 'js-cookie'; -import Link from "next/link"; import { motion } from "framer-motion"; +import Link from "next/link"; const NodeDwifiStreamUser = () => { const [data, setData] = useState([]); @@ -72,6 +72,15 @@ const NodeDwifiStreamUser = () => { return ( /* eslint-disable */
+
+

+ Scan To Explore The ÐWi-Fi Nodes Around You +

+ +

DWifi Nodes Dashboard

+
+

+ Scan To Explore The ÐWi-Fi Nodes Around You +

+ +

DWifi Nodes Dashboard

-
+ {header}
{item.status[0].hostSSID}{item.gateway}{item.chain_name}{item.status[0].interfaceName}{item.status.length} + {item.status[0].hostSSID}{item.gateway}{item.chain_name}{item.status[0].interfaceName}{item.status.length} {item.connected === "true" ? "Offline" : "Online"} {item.location}{new Date(item.status[0].connectedAt).toLocaleString()}{new Date(item.status[0].lastChecked).toLocaleString()}{item.location}{new Date(item.status[0].connectedAt).toLocaleString()}{new Date(item.status[0].lastChecked).toLocaleString()}
diff --git a/pages/scan.js b/pages/scan.js new file mode 100644 index 0000000..dad2c23 --- /dev/null +++ b/pages/scan.js @@ -0,0 +1,12 @@ +import React from "react"; +import DwifiMap from "../components/DwifiMap"; + +const Scan = () => { + return ( +
+ +
+ ); +}; + +export default Scan; From 8d6ce53cf0d509e0d8357e1a76b2d01176da83b9 Mon Sep 17 00:00:00 2001 From: vaibhavvvvv Date: Tue, 3 Sep 2024 14:04:52 +0530 Subject: [PATCH 05/12] Scan: Fix build errors; Add .env to .gitignore --- .gitignore | 1 + pages/dwifi.tsx | 2 +- pages/scan.js | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 55175ef..56f72c6 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ yarn-error.log* # local env files .env*.local +.env # vercel .vercel diff --git a/pages/dwifi.tsx b/pages/dwifi.tsx index df3678b..5234db5 100644 --- a/pages/dwifi.tsx +++ b/pages/dwifi.tsx @@ -74,7 +74,7 @@ const Dwifi = () => {
- +
diff --git a/pages/scan.js b/pages/scan.js index dad2c23..3b78828 100644 --- a/pages/scan.js +++ b/pages/scan.js @@ -1,5 +1,7 @@ import React from "react"; -import DwifiMap from "../components/DwifiMap"; +import dynamic from 'next/dynamic'; + +const DwifiMap = dynamic(() => import('../components/DwifiMap'), { ssr: false }); const Scan = () => { return ( From 58c1c92bcfd98f6d3aa18874b44a0483c150e9d8 Mon Sep 17 00:00:00 2001 From: Rushikesh Nimkar Date: Wed, 4 Sep 2024 15:53:20 +0530 Subject: [PATCH 06/12] fix : dvpnnft url --- pages/dvpnnft.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/dvpnnft.tsx b/pages/dvpnnft.tsx index 1ea3238..7444984 100644 --- a/pages/dvpnnft.tsx +++ b/pages/dvpnnft.tsx @@ -21,7 +21,7 @@ const BaliDVPNNFTPage = () => { setTimeout(async () => { try { - const result = await axios.post(`${REACT_APP_GATEWAY_URL}api/v1.0/dvpnnft`, { + const result = await axios.post(`${REACT_APP_GATEWAY_URL}api/v1.0/dvpnnft/chain=evm`, { wallet_address: walletAddress }); setResponse(result.data); From d0dd1c6b08e90844364d5498fcba43698d05a474 Mon Sep 17 00:00:00 2001 From: Rushikesh Nimkar Date: Wed, 11 Sep 2024 17:38:12 +0530 Subject: [PATCH 07/12] update : usernode page --- components/nodedataDwifiUser.js | 366 ++++++++---- components/peaqabi/contractABI.json | 894 ++++++++++++++++++++++++++++ package.json | 1 + pnpm-lock.yaml | 102 +++- 4 files changed, 1243 insertions(+), 120 deletions(-) create mode 100644 components/peaqabi/contractABI.json diff --git a/components/nodedataDwifiUser.js b/components/nodedataDwifiUser.js index 8a858fb..9569eac 100644 --- a/components/nodedataDwifiUser.js +++ b/components/nodedataDwifiUser.js @@ -3,91 +3,211 @@ import React, { useState, useEffect } from 'react'; import Cookies from 'js-cookie'; import { motion } from "framer-motion"; import Link from "next/link"; +import { ethers } from 'ethers'; +import contractABI from '../components/peaqabi/contractABI.json'; + +const contractAddress = '0x5940445e1e8A419ebea10B45c5d1C0F603926F41'; const NodeDwifiStreamUser = () => { const [data, setData] = useState([]); const [noData, setNoData] = useState(false); - + const [isConnected, setIsConnected] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [editingNode, setEditingNode] = useState(null); + const [isSaving, setIsSaving] = useState(false); useEffect(() => { - const socket = new WebSocket('wss://dev.gateway.erebrus.io/api/v1.0/nodedwifi/stream'); - const wallet = Cookies.get("erebrus_wallet"); - - socket.onopen = function (event) { - console.log('WebSocket is open now.'); - }; + checkConnection(); + }, []); - socket.onmessage = function (event) { - const newData = JSON.parse(event.data); + async function checkConnection() { + if (typeof window.ethereum !== 'undefined') { + try { + await window.ethereum.request({ method: 'eth_requestAccounts' }); + setIsConnected(true); + fetchOperators(); + } catch (error) { + console.error('Failed to connect:', error); + setIsConnected(false); + setError('Failed to connect to MetaMask. Please try again.'); + } + } else { + setError('Please install MetaMask to use this feature.'); + } + } - if (newData.wallet_address === wallet) { - setData((prevData) => { - const updatedData = prevData.map((item) => { - if (item.id === newData.id) { - return newData; - } - return item; - }); + async function fetchOperators() { + setError(null); + setData([]); + setIsLoading(true); + setNoData(false); - const existingIndex = prevData.findIndex((item) => item.id === newData.id); - if (existingIndex === -1) { - updatedData.push(newData); - } + const walletAddress = Cookies.get('erebrus_wallet'); + if (!walletAddress) { + setError('Wallet address not found in cookies.'); + setIsLoading(false); + setNoData(true); + return; + } - return updatedData; - }); - setNoData(false); - } - }; + try { + const provider = new ethers.providers.Web3Provider(window.ethereum); + const signer = provider.getSigner(); - socket.onerror = function (event) { - console.error('WebSocket error:', event); - }; + const contract = new ethers.Contract(contractAddress, contractABI, signer); - socket.onclose = function (event) { - console.log('WebSocket is closed now.'); - }; + const operators = []; + for (let i = 0; i <= 50; i++) { + try { + const result = await contract.wifiNodeOperators(i); + if (result.user.toLowerCase() === walletAddress.toLowerCase()) { + operators.push({ + id: i, + user: result.user, + ssid: result.ssid, + location: result.location, + isActive: result.isActive, + pricePerMinute: ethers.utils.formatUnits(result.pricePerMinute, 'ether'), + connectedAt: new Date().toISOString(), + lastChecked: new Date().toISOString() + }); + } + } catch (error) { + console.error(`Error querying index ${i}:`, error); + } + } - // Set a timeout to check if any data has been received - const timeoutId = setTimeout(() => { - if (data.length === 0) { + if (operators.length > 0) { + setData(operators); + } else { setNoData(true); } - }, 2); // Wait for 5 seconds - - return () => { - socket.close(); - clearTimeout(timeoutId); - }; - }, []); + } catch (error) { + console.error('Error fetching operators:', error); + setError('An error occurred while fetching operators. Please try again later.'); + setNoData(true); + } finally { + setIsLoading(false); + } + } + const handleEdit = (node) => { + setEditingNode(node); + }; - const uniqueNodesData = data.reduce((acc, item) => { - if (!acc[item.id]) { - acc[item.id] = {...item, status: [item.status[0]]}; + const handleSave = async (updatedNode) => { + setError(null); + setIsSaving(true); + try { + const provider = new ethers.providers.Web3Provider(window.ethereum); + const signer = provider.getSigner(); + const contract = new ethers.Contract(contractAddress, contractABI, signer); + + // Convert price to wei + const priceInWei = ethers.utils.parseEther(updatedNode.pricePerMinute); + + // Call the smart contract function to update the node + const tx = await contract.updateWiFiNode( + updatedNode.id, + updatedNode.ssid, + updatedNode.location, + priceInWei + ); + + // Wait for the transaction to be mined + await tx.wait(); + + // Update the local state immediately + setData(prevData => prevData.map(node => + node.id === updatedNode.id ? {...node, ...updatedNode} : node + )); + + // Update the editing node state + setEditingNode({...updatedNode}); + + // Re-fetch the operators data to get the updated information + await fetchOperators(); + + // Close the popup after successful update + setEditingNode(null); + } catch (error) { + console.error('Error updating node:', error); + if (error.data && error.data.message && error.data.message.includes("Erebrus: Unauthorized")) { + setError('You are not authorized to update this node. Only the node owner can make changes.'); + } else { + setError('Failed to update node. Please try again.'); + } + } finally { + setIsSaving(false); } - return acc; - }, {}); + }; + {isSaving && ( +
+
+
+)} + + const EditPopup = ({ node, onSave, onCancel }) => { + const [editedNode, setEditedNode] = useState(node); + + const handleChange = (e) => { + setEditedNode({ ...editedNode, [e.target.name]: e.target.value }); + }; + return ( +
+
+

Edit Node (ID: {node.id})

+ + + +
+ + +
+
+
+ ); + }; if (noData) { return ( - /* eslint-disable */
-
-

- Scan To Explore The ÐWi-Fi Nodes Around You -

- -

DWifi Nodes Dashboard

-

No dVPN Nodes

-

You don't have any dVPN nodes running at the moment.

{ className="mt-6" > - - Run Your Node - + Run Your Node
); } + return (
-
-

- Scan To Explore The ÐWi-Fi Nodes Around You -

- -

DWifi Nodes Dashboard

-
-
- - - {["Host SSID", "Gateway", "Chain", "Interface", "Connected Devices", "Status", "Location", "Connected At", "Last Pinged"].map((header) => ( - - ))} - - - - {Object.values(uniqueNodesData).map((item) => ( - - - - - - - - - - + {!isConnected && ( + + )} + {isLoading &&

Loading...

} + {error &&

{error}

} + {!noData && ( +
+
- {header} -
{item.status[0].hostSSID}{item.gateway}{item.chain_name}{item.status[0].interfaceName}{item.status.length} - - {item.connected === "true" ? "Offline" : "Online"} - - {item.location}{new Date(item.status[0].connectedAt).toLocaleString()}{new Date(item.status[0].lastChecked).toLocaleString()}
+ + + {["Node ID", "SSID", "User", "Chain", "Status", "Location", "Price Per Minute", "Connected At", "Last Pinged", "Actions"].map((header) => ( + + ))} - ))} - -
+ {header} +
-
+ + + {data.map((item) => ( + + {item.id} + {item.ssid} + + {item.user.slice(0, 3)}...{item.user.slice(-3)} + + peaq + + + {item.isActive ? "Online" : "Offline"} + + + {item.location} + {item.pricePerMinute} ETH + {new Date(item.connectedAt).toLocaleString()} + {new Date(item.lastChecked).toLocaleString()} + + + + + ))} + + +
+ )} + {editingNode && ( + setEditingNode(null)} + /> + )} + {(isLoading || isSaving) && ( +
+
+
+

+ {isLoading ? "Loading..." : "Saving changes..."} +

+
+
+ )}
); -}; +} export default NodeDwifiStreamUser; \ No newline at end of file diff --git a/components/peaqabi/contractABI.json b/components/peaqabi/contractABI.json new file mode 100644 index 0000000..34e26ae --- /dev/null +++ b/components/peaqabi/contractABI.json @@ -0,0 +1,894 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "erebrusmanagerAddr", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "name": "AddAttribute", + "type": "event", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "did_account", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "name", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "value", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "validity", + "type": "uint32", + "indexed": false, + "internalType": "uint32" + } + ], + "anonymous": false, + "constant": false, + "payable": false, + "signature": "0x13aef52bc4a99da04591533072e304017e3fb76f43e7fadd25eb7f514c5ef6e5" + }, + { + "name": "NodeDeactivated", + "type": "event", + "inputs": [ + { + "name": "operatorAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false, + "constant": false, + "payable": false, + "signature": "0xd9957750e6343405c319eb99a4ec67fa11cfd66969318cbc71aa2d45fa53a349" + }, + { + "name": "NodeOperatorUpdated", + "type": "event", + "inputs": [ + { + "name": "operatorAddress", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "ssid", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "location", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false, + "constant": false, + "payable": false, + "signature": "0xf512e0b8ea262571de058d8b17a3c2d29913f35abcd4c173935ba6fa58b3833b" + }, + { + "name": "RemoveAttribte", + "type": "event", + "inputs": [ + { + "name": "did_account", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "name", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false, + "constant": false, + "payable": false, + "signature": "0x647d95b9099b095e5957558106bc51df77720f963539a0ca62ee9948e6554da1" + }, + { + "name": "UpdateAttribute", + "type": "event", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "did_account", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "name", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "value", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "validity", + "type": "uint32", + "indexed": false, + "internalType": "uint32" + } + ], + "anonymous": false, + "constant": false, + "payable": false, + "signature": "0x018be4d5e2634aefdb51c4ddd186f33072cfb5f6baf685579c2e214995dc9e4f" + }, + { + "name": "VPNUpdated", + "type": "event", + "inputs": [ + { + "name": "nodeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "updatedStatus", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + }, + { + "name": "updatedRegion", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false, + "constant": false, + "payable": false, + "signature": "0x34349e39780aaa7fc3b8b465ca9a2ada7a8a0a941e269b03102ad3867ff34b66" + }, + { + "name": "VpnNodeRegistered", + "type": "event", + "inputs": [ + { + "name": "nodeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "nodename", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "ipaddress", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "ispinfo", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "region", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "location", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false, + "constant": false, + "payable": false, + "signature": "0x9e6fb352d55d4e4414d6ec189c261105e99d8baba96bd55c43a2013e2ee9453b" + }, + { + "name": "WifiNodeOperatorRegistered", + "type": "event", + "inputs": [ + { + "name": "nodeID", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "deviceId", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "ssid", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "location", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "pricePerMinute", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false, + "constant": false, + "payable": false, + "signature": "0x72ab8f8888d362028a5ec40836cefca72088b92b1ef7afc7fb795556b02d6658" + }, + { + "name": "VpnDeviceCheckpoints", + "type": "function", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0xee5458b3" + }, + { + "name": "addAttribute", + "type": "function", + "inputs": [ + { + "name": "did_account", + "type": "address", + "internalType": "address" + }, + { + "name": "name", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "value", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "validity_for", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0xcc4a70ca" + }, + { + "name": "deactivateNode", + "type": "function", + "inputs": [ + { + "name": "nodeID", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0xe9d63830" + }, + { + "name": "didToUser", + "type": "function", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0xe4f4ff00" + }, + { + "name": "getWifiDetails", + "type": "function", + "inputs": [ + { + "name": "nodeID", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "price", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0x387f68e1" + }, + { + "name": "readAttribute", + "type": "function", + "inputs": [ + { + "name": "did_account", + "type": "address", + "internalType": "address" + }, + { + "name": "name", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "components": [ + { + "name": "name", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "value", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "validity", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "created", + "type": "uint256", + "internalType": "uint256" + } + ], + "internalType": "struct DID.Attribute" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0xb2028b7d" + }, + { + "name": "registerVpnNode", + "type": "function", + "inputs": [ + { + "name": "node", + "type": "tuple", + "components": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "peaqDid", + "type": "string", + "internalType": "string" + }, + { + "name": "nodename", + "type": "string", + "internalType": "string" + }, + { + "name": "ipaddress", + "type": "string", + "internalType": "string" + }, + { + "name": "ispinfo", + "type": "string", + "internalType": "string" + }, + { + "name": "region", + "type": "string", + "internalType": "string" + }, + { + "name": "location", + "type": "string", + "internalType": "string" + }, + { + "name": "status", + "type": "uint8", + "internalType": "uint8" + } + ], + "internalType": "struct ErebrusRegistry.VPNNode" + } + ], + "outputs": [], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0xd04b7ae4" + }, + { + "name": "registerWifiNode", + "type": "function", + "inputs": [ + { + "name": "_deviceId", + "type": "string", + "internalType": "string" + }, + { + "name": "_peaqDid", + "type": "string", + "internalType": "string" + }, + { + "name": "_ssid", + "type": "string", + "internalType": "string" + }, + { + "name": "_location", + "type": "string", + "internalType": "string" + }, + { + "name": "_pricePermin", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0x04795f58" + }, + { + "name": "removeAttribute", + "type": "function", + "inputs": [ + { + "name": "did_account", + "type": "address", + "internalType": "address" + }, + { + "name": "name", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0xe8a81690" + }, + { + "name": "updateAttribute", + "type": "function", + "inputs": [ + { + "name": "did_account", + "type": "address", + "internalType": "address" + }, + { + "name": "name", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "value", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "validity_for", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0x68b4b2c1" + }, + { + "name": "updateVPNNode", + "type": "function", + "inputs": [ + { + "name": "nodeID", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_status", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "_region", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0xe48da8a4" + }, + { + "name": "updateWiFiNode", + "type": "function", + "inputs": [ + { + "name": "nodeID", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ssid", + "type": "string", + "internalType": "string" + }, + { + "name": "location", + "type": "string", + "internalType": "string" + }, + { + "name": "pricePerMin", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0x8a7692dc" + }, + { + "name": "vpnDeviceCheckpoint", + "type": "function", + "inputs": [ + { + "name": "nodeID", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "dataHash", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0x1b9f0c95" + }, + { + "name": "vpnNodeOperators", + "type": "function", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "peaqDid", + "type": "string", + "internalType": "string" + }, + { + "name": "nodename", + "type": "string", + "internalType": "string" + }, + { + "name": "ipaddress", + "type": "string", + "internalType": "string" + }, + { + "name": "ispinfo", + "type": "string", + "internalType": "string" + }, + { + "name": "region", + "type": "string", + "internalType": "string" + }, + { + "name": "location", + "type": "string", + "internalType": "string" + }, + { + "name": "status", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0xd5399313" + }, + { + "name": "vpnTotalCheckpoints", + "type": "function", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0xef5050fb" + }, + { + "name": "wifiDeviceCheckpoint", + "type": "function", + "inputs": [ + { + "name": "nodeID", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "dataHash", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable", + "constant": false, + "payable": false, + "signature": "0x63c3a7e7" + }, + { + "name": "wifiDeviceCheckpoints", + "type": "function", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0x4f663d31" + }, + { + "name": "wifiNodeOperators", + "type": "function", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "deviceId", + "type": "string", + "internalType": "string" + }, + { + "name": "peaqDid", + "type": "string", + "internalType": "string" + }, + { + "name": "ssid", + "type": "string", + "internalType": "string" + }, + { + "name": "location", + "type": "string", + "internalType": "string" + }, + { + "name": "pricePerMinute", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "isActive", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0x8f9c8ee2" + }, + { + "name": "wifiTotalCheckpoints", + "type": "function", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view", + "constant": true, + "payable": false, + "signature": "0x0608a6b6" + } + ] \ No newline at end of file diff --git a/package.json b/package.json index 4460e56..1cb6b22 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "fewcha-plugin-wallet-adapter": "^0.1.3", "file-saver": "^2.0.5", "framer-motion": "^8.0.2", + "http-proxy-middleware": "^3.0.2", "js-cookie": "^3.0.5", "leaflet": "^1.9.4", "mapbox-gl": "^3.5.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7822849..d65fbe0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,6 +149,9 @@ importers: framer-motion: specifier: ^8.0.2 version: 8.5.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + http-proxy-middleware: + specifier: ^3.0.2 + version: 3.0.2 js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -3828,6 +3831,9 @@ packages: '@types/http-cache-semantics@4.0.4': resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@types/http-proxy@1.17.15': + resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -4896,6 +4902,10 @@ packages: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + broadcast-channel@3.7.0: resolution: {integrity: sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==} @@ -5491,6 +5501,15 @@ packages: supports-color: optional: true + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} @@ -6263,6 +6282,10 @@ packages: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + filter-obj@1.1.0: resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} engines: {node: '>=0.10.0'} @@ -6699,6 +6722,14 @@ packages: http-https@1.0.0: resolution: {integrity: sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==} + http-proxy-middleware@3.0.2: + resolution: {integrity: sha512-fBLFpmvDzlxdckwZRjM0wWtwDZ4KBtQ8NFqhrFKoEtK4myzuiumBuNTxD+F4cVbXfOZljIbrynmvByofDzT7Ag==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + http-proxy@1.18.1: + resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} + engines: {node: '>=8.0.0'} + http-shutdown@1.2.2: resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} @@ -7036,6 +7067,10 @@ packages: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + is-reference@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} @@ -7819,6 +7854,10 @@ packages: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + microseconds@0.2.0: resolution: {integrity: sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==} @@ -9412,6 +9451,9 @@ packages: resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} engines: {node: '>= 4.0.0'} + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + requizzle@0.2.4: resolution: {integrity: sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==} @@ -16950,6 +16992,10 @@ snapshots: '@types/http-cache-semantics@4.0.4': {} + '@types/http-proxy@1.17.15': + dependencies: + '@types/node': 20.14.2 + '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -18702,32 +18748,32 @@ snapshots: axios@0.21.4: dependencies: - follow-redirects: 1.15.5 + follow-redirects: 1.15.5(debug@4.3.7) transitivePeerDependencies: - debug axios@0.24.0: dependencies: - follow-redirects: 1.15.5 + follow-redirects: 1.15.5(debug@4.3.7) transitivePeerDependencies: - debug axios@0.26.1: dependencies: - follow-redirects: 1.15.5 + follow-redirects: 1.15.5(debug@4.3.7) transitivePeerDependencies: - debug axios@0.27.2: dependencies: - follow-redirects: 1.15.5 + follow-redirects: 1.15.5(debug@4.3.7) form-data: 4.0.0 transitivePeerDependencies: - debug axios@1.6.2: dependencies: - follow-redirects: 1.15.5 + follow-redirects: 1.15.5(debug@4.3.7) form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -18735,7 +18781,7 @@ snapshots: axios@1.6.5: dependencies: - follow-redirects: 1.15.5 + follow-redirects: 1.15.5(debug@4.3.7) form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -18961,6 +19007,10 @@ snapshots: dependencies: fill-range: 7.0.1 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + broadcast-channel@3.7.0: dependencies: '@babel/runtime': 7.24.5 @@ -19658,6 +19708,10 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.3.7: + dependencies: + ms: 2.1.3 + decamelize-keys@1.1.1: dependencies: decamelize: 1.2.0 @@ -20885,6 +20939,10 @@ snapshots: dependencies: to-regex-range: 5.0.1 + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + filter-obj@1.1.0: {} finalhandler@1.1.2: @@ -20949,7 +21007,9 @@ snapshots: flow-parser@0.235.1: {} - follow-redirects@1.15.5: {} + follow-redirects@1.15.5(debug@4.3.7): + optionalDependencies: + debug: 4.3.7 fontfaceobserver@2.3.0: {} @@ -21407,6 +21467,25 @@ snapshots: http-https@1.0.0: {} + http-proxy-middleware@3.0.2: + dependencies: + '@types/http-proxy': 1.17.15 + debug: 4.3.7 + http-proxy: 1.18.1(debug@4.3.7) + is-glob: 4.0.3 + is-plain-object: 5.0.0 + micromatch: 4.0.8 + transitivePeerDependencies: + - supports-color + + http-proxy@1.18.1(debug@4.3.7): + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.15.5(debug@4.3.7) + requires-port: 1.0.0 + transitivePeerDependencies: + - debug + http-shutdown@1.2.2: {} http2-wrapper@1.0.3: @@ -21807,6 +21886,8 @@ snapshots: dependencies: isobject: 3.0.1 + is-plain-object@5.0.0: {} + is-reference@3.0.2: dependencies: '@types/estree': 1.0.5 @@ -22821,6 +22902,11 @@ snapshots: braces: 3.0.2 picomatch: 2.3.1 + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + microseconds@0.2.0: {} miller-rabin@4.0.1: @@ -24653,6 +24739,8 @@ snapshots: rc: 1.2.8 resolve: 1.7.1 + requires-port@1.0.0: {} + requizzle@0.2.4: dependencies: lodash: 4.17.21 From cafc83b194840e0c08d1643d8205bfd968acc3da Mon Sep 17 00:00:00 2001 From: Rushikesh Nimkar Date: Wed, 11 Sep 2024 18:08:06 +0530 Subject: [PATCH 08/12] build fix --- components/nodedataDwifiUser.js | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nodedataDwifiUser.js b/components/nodedataDwifiUser.js index 9569eac..035d221 100644 --- a/components/nodedataDwifiUser.js +++ b/components/nodedataDwifiUser.js @@ -208,6 +208,7 @@ const NodeDwifiStreamUser = () => {

DWifi Nodes Dashboard

No dVPN Nodes

+ {/* eslint-disable-next-line */}

You don't have any dVPN nodes running at the moment.

Date: Thu, 12 Sep 2024 02:11:58 +0530 Subject: [PATCH 09/12] fix : ui usernode page --- components/nodedataDwifiUser.js | 31 +++++++++++++++++++++++++++++-- pnpm-lock.yaml | 22 +++++++++++----------- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/components/nodedataDwifiUser.js b/components/nodedataDwifiUser.js index 035d221..a481d82 100644 --- a/components/nodedataDwifiUser.js +++ b/components/nodedataDwifiUser.js @@ -6,6 +6,7 @@ import Link from "next/link"; import { ethers } from 'ethers'; import contractABI from '../components/peaqabi/contractABI.json'; + const contractAddress = '0x5940445e1e8A419ebea10B45c5d1C0F603926F41'; const NodeDwifiStreamUser = () => { @@ -16,6 +17,7 @@ const NodeDwifiStreamUser = () => { const [error, setError] = useState(null); const [editingNode, setEditingNode] = useState(null); const [isSaving, setIsSaving] = useState(false); + const [expandedLocations, setExpandedLocations] = useState({}); useEffect(() => { checkConnection(); @@ -94,6 +96,13 @@ const NodeDwifiStreamUser = () => { const handleEdit = (node) => { setEditingNode(node); }; + const toggleLocation = (id) => { + setExpandedLocations(prev => ({ + ...prev, + [id]: !prev[id] + })); + }; + const handleSave = async (updatedNode) => { setError(null); @@ -262,8 +271,26 @@ const NodeDwifiStreamUser = () => { {item.isActive ? "Online" : "Offline"} - {item.location} - {item.pricePerMinute} ETH + + {expandedLocations[item.id] ? ( + {item.location} + ) : ( + + {item.location.length > 20 + ? `${item.location.slice(0, 20)}...` + : item.location} + + )} + {item.location.length > 20 && ( + + )} + + {item.pricePerMinute} AGNG {new Date(item.connectedAt).toLocaleString()} {new Date(item.lastChecked).toLocaleString()} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d65fbe0..e3d45a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13171,7 +13171,7 @@ snapshots: chalk: 4.1.2 ci-info: 3.9.0 connect: 3.7.0 - debug: 4.3.4 + debug: 4.3.7 env-editor: 0.4.2 fast-glob: 3.3.2 find-yarn-workspace-root: 2.0.0 @@ -13262,7 +13262,7 @@ snapshots: '@expo/plist': 0.1.3 '@expo/sdk-runtime-versions': 1.0.0 chalk: 4.1.2 - debug: 4.3.4 + debug: 4.3.7 find-up: 5.0.0 getenv: 1.0.0 glob: 7.1.6 @@ -13332,7 +13332,7 @@ snapshots: '@expo/env@0.3.0': dependencies: chalk: 4.1.2 - debug: 4.3.4 + debug: 4.3.7 dotenv: 16.4.5 dotenv-expand: 11.0.6 getenv: 1.0.0 @@ -13383,7 +13383,7 @@ snapshots: '@expo/json-file': 8.3.3 '@expo/spawn-async': 1.7.2 chalk: 4.1.2 - debug: 4.3.4 + debug: 4.3.7 find-yarn-workspace-root: 2.0.0 fs-extra: 9.1.0 getenv: 1.0.0 @@ -13409,7 +13409,7 @@ snapshots: find-up: 5.0.0 find-yarn-workspace-root: 2.0.0 js-yaml: 3.14.1 - micromatch: 4.0.5 + micromatch: 4.0.8 npm-package-arg: 7.0.0 ora: 3.4.0 split: 1.0.1 @@ -13429,7 +13429,7 @@ snapshots: '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 '@react-native/normalize-colors': 0.74.83 - debug: 4.3.4 + debug: 4.3.7 expo-modules-autolinking: 1.11.1 fs-extra: 9.1.0 resolve-from: 5.0.0 @@ -20993,7 +20993,7 @@ snapshots: find-yarn-workspace-root@2.0.0: dependencies: - micromatch: 4.0.5 + micromatch: 4.0.8 flat-cache@3.2.0: dependencies: @@ -22103,7 +22103,7 @@ snapshots: '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 @@ -22200,7 +22200,7 @@ snapshots: chalk: 4.1.2 flow-parser: 0.235.1 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.8 neo-async: 2.6.2 node-dir: 0.1.17 recast: 0.21.5 @@ -22771,7 +22771,7 @@ snapshots: graceful-fs: 4.2.11 invariant: 2.2.4 jest-worker: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 node-abort-controller: 3.1.1 nullthrows: 1.1.1 walker: 1.0.8 @@ -24797,7 +24797,7 @@ snapshots: retry-request@5.0.2: dependencies: - debug: 4.3.4 + debug: 4.3.7 extend: 3.0.2 transitivePeerDependencies: - supports-color From d021706d0c7388faa1c9f038512be9da326809ec Mon Sep 17 00:00:00 2001 From: Rushikesh Nimkar Date: Fri, 13 Sep 2024 02:43:36 +0530 Subject: [PATCH 10/12] add : save to walrus and download button --- components/Myvpncard.tsx | 174 +++++++++++++----- .../walrus/DownloadFromWalrusButton.tsx | 45 +++++ components/walrus/SaveToWalrusButton.tsx | 145 +++++++++++++++ package.json | 1 + pages/subscription.tsx | 11 +- pnpm-lock.yaml | 16 ++ 6 files changed, 340 insertions(+), 52 deletions(-) create mode 100644 components/walrus/DownloadFromWalrusButton.tsx create mode 100644 components/walrus/SaveToWalrusButton.tsx diff --git a/components/Myvpncard.tsx b/components/Myvpncard.tsx index da89acc..48a205b 100644 --- a/components/Myvpncard.tsx +++ b/components/Myvpncard.tsx @@ -8,6 +8,9 @@ import QrCode from "./qrCode"; import dlt from "../public/dlt.png"; import Image from "next/image"; import Link from "next/link"; +import CryptoJS from 'crypto-js'; + +import DownloadFromWalrusButton from "./walrus/DownloadFromWalrusButton"; const REACT_APP_GATEWAY_URL = process.env.NEXT_PUBLIC_GATEWAY_URL; const EREBRUS_GATEWAY_URL = process.env.NEXT_PUBLIC_EREBRUS_BASE_URL; @@ -82,6 +85,8 @@ const MyVpnCard: React.FC = ({ const [delvpn, setdelvpn] = useState(false); const [qr, setqr] = useState(false); const [formattedDate, setFormattedDate] = useState(''); + const [showDownloadModal, setShowDownloadModal] = useState(false); + const [downloadPin, setDownloadPin] = useState(''); useEffect(() => { if (metaData) { @@ -117,6 +122,60 @@ const MyVpnCard: React.FC = ({ onReviewDeleted(); // Call the callback function when a review is deleted } }; + const handleDownloadClick = () => { + setShowDownloadModal(true); + }; + + const downloadConfig = async () => { + if (downloadPin.length !== 6) { + alert('Please enter a valid 6-digit PIN'); + return; + } + + try { + const auth = Cookies.get("erebrus_token"); + const walletAddress = Cookies.get('erebrus_wallet') || ''; + + if (!walletAddress) { + throw new Error('Wallet address not found'); + } + + // Fetch the encrypted blobId from Erebrus + const response = await axios.get( + `${EREBRUS_GATEWAY_URL}api/v1.0/erebrus/client/${metaData.UUID}/blobId`, + { + headers: { + Authorization: `Bearer ${auth}`, + }, + } + ); + + const encryptedBlobId = response.data.payload.blobId; + const decryptedBlobId = decryptBlobId(encryptedBlobId, walletAddress, downloadPin); + + // Fetch the config from Walrus + const walrusResponse = await axios.get( + `https://aggregator-devnet.walrus.space/v1/${decryptedBlobId}`, + { responseType: 'blob' } + ); + + // Download the config file + const blob = new Blob([walrusResponse.data], { type: 'text/plain' }); + saveAs(blob, `${metaData.name}.conf`); + + setShowDownloadModal(false); + setDownloadPin(''); + } catch (error) { + console.error('Error downloading config:', error); + alert('Failed to download config. Please check your PIN and try again.'); + } + }; + + const decryptBlobId = (encryptedBlobId: string, walletAddress: string, pin: string) => { + const key = `${walletAddress}-${pin}`; // Reconstruct the key + const bytes = CryptoJS.AES.decrypt(encryptedBlobId, key); + return bytes.toString(CryptoJS.enc.Utf8); + }; const deletevpn = async (id: string, region: string) => { setLoading(true); @@ -188,60 +247,24 @@ const MyVpnCard: React.FC = ({
- {/*
- -
*/} +
- {/* - */} - -
- - {/*
-
- -
{ - - }}> - -
-
- -
- -
-
- -
-
*/} + + +
+
{qr && ( @@ -343,6 +366,55 @@ const MyVpnCard: React.FC = ({ > Delete + + + + + + )} + {showDownloadModal && ( +
+
+
+
+

+ Enter PIN to Download +

+
+
+ setDownloadPin(e.target.value)} + maxLength={6} + placeholder="Enter 6-digit PIN" + className="w-full p-2 rounded-md text-black" + /> +
+
+ +
diff --git a/components/walrus/DownloadFromWalrusButton.tsx b/components/walrus/DownloadFromWalrusButton.tsx new file mode 100644 index 0000000..2a1ceee --- /dev/null +++ b/components/walrus/DownloadFromWalrusButton.tsx @@ -0,0 +1,45 @@ +import React, { useState } from 'react'; +import axios from 'axios'; + +interface DownloadFromWalrusButtonProps { + blobId: string; + clientName: string; +} + +const DownloadFromWalrusButton: React.FC = ({ blobId, clientName }) => { + const [isDownloading, setIsDownloading] = useState(false); + + const downloadFromWalrus = async () => { + setIsDownloading(true); + try { + const response = await axios.get(`https://aggregator-devnet.walrus.space/v1/${blobId}`, { + responseType: 'blob' + }); + + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', `${clientName}.conf`); + document.body.appendChild(link); + link.click(); + link.remove(); + } catch (error) { + console.error('Error downloading from Walrus:', error); + alert('Failed to download the configuration file.'); + } finally { + setIsDownloading(false); + } + }; + + return ( + + ); +}; + +export default DownloadFromWalrusButton; \ No newline at end of file diff --git a/components/walrus/SaveToWalrusButton.tsx b/components/walrus/SaveToWalrusButton.tsx new file mode 100644 index 0000000..90cb4ce --- /dev/null +++ b/components/walrus/SaveToWalrusButton.tsx @@ -0,0 +1,145 @@ +import React, { useState } from 'react'; +import axios from 'axios'; +import Cookies from 'js-cookie'; +import CryptoJS from 'crypto-js'; // For encryption + +interface SaveToWalrusButtonProps { + configFile: string; + vpnName: string; + clientUUID: string; +} + +const SaveToWalrusButton: React.FC = ({ configFile, vpnName, clientUUID }) => { + const [isSaving, setIsSaving] = useState(false); + const [saveStatus, setSaveStatus] = useState<'idle' | 'success' | 'error'>('idle'); + const [isPinModalOpen, setIsPinModalOpen] = useState(false); + const [pin, setPin] = useState(''); + const [confirmPin, setConfirmPin] = useState(''); + + // Encryption function using wallet address and PIN + const encryptBlobId = (blobId: string, walletAddress: string, pin: string) => { + const key = `${walletAddress}-${pin}`; // Combine wallet address and PIN for encryption key + return CryptoJS.AES.encrypt(blobId, key).toString(); // Encrypt the blobId + }; + + // Open modal to enter the PIN + const handleSave = async () => { + setIsPinModalOpen(true); // Open the modal + }; + + // Function to save to Walrus and update Erebrus with encrypted blobId + const saveToWalrus = async () => { + if (pin.length !== 6) { + alert('Please enter a valid 6-digit PIN'); + return; + } + + if (pin !== confirmPin) { + alert('PIN and confirmation PIN do not match'); + return; + } + + setIsSaving(true); + setSaveStatus('idle'); + + try { + // Save to Walrus + const walrusResponse = await axios.put( + 'https://publisher-devnet.walrus.space/v1/store', + configFile, + { + params: { epochs: 5 }, + headers: { 'Content-Type': 'text/plain' }, + } + ); + + const blobId = walrusResponse.data.newlyCreated.blobObject.blobId; + + // Retrieve user's wallet address from cookies + const walletAddress = Cookies.get('erebrus_wallet') || ''; + if (!walletAddress) { + throw new Error('Wallet address not found'); + } + + // Encrypt blobId with wallet address and PIN + const encryptedBlobId = encryptBlobId(blobId, walletAddress, pin); + + // Update encrypted blobId in Erebrus Gateway + const erebrusGatewayUrl = process.env.NEXT_PUBLIC_EREBRUS_BASE_URL || ''; + await axios.put(`${erebrusGatewayUrl}api/v1.0/erebrus/client/${clientUUID}/blobId`, + { blobId: encryptedBlobId }, + { + headers: { + 'Authorization': `Bearer ${Cookies.get('erebrus_token')}`, + 'Content-Type': 'application/json', + }, + } + ); + + setSaveStatus('success'); + } catch (error) { + console.error('Error saving to Walrus or updating blobId:', error); + setSaveStatus('error'); + } finally { + setIsSaving(false); + setIsPinModalOpen(false); // Close the modal after saving + } + }; + + return ( + <> + + + {/* Modal for PIN and Confirm PIN entry */} + {isPinModalOpen && ( +
+
+

Enter PIN and Confirm PIN

+ setPin(e.target.value)} + maxLength={6} + placeholder="Enter 6-digit PIN" + className="border border-gray-300 p-2 rounded-md w-full mb-4" + /> + setConfirmPin(e.target.value)} + maxLength={6} + placeholder="Confirm PIN" + className="border border-gray-300 p-2 rounded-md w-full" + /> +
+ + +
+
+
+ )} + + ); +}; + +export default SaveToWalrusButton; diff --git a/package.json b/package.json index 1cb6b22..bdd0beb 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "react-intersection-observer": "^9.13.0", "react-leaflet": "^4.2.1", "react-mapbox-gl": "^5.1.1", + "react-pin-input": "^1.3.1", "react-responsive-carousel": "^3.2.23", "react-toastify": "^9.1.1", "react-world-countries-map": "^1.1.0", diff --git a/pages/subscription.tsx b/pages/subscription.tsx index ad6d94a..f056539 100644 --- a/pages/subscription.tsx +++ b/pages/subscription.tsx @@ -14,6 +14,8 @@ import Button from "../components/Button"; import { useRouter } from "next/router"; import Image from "next/image"; import SingleSignerTransaction from "../components/transactionFlow/SingleSigner"; +import SaveToWalrusButton from "../components/walrus/SaveToWalrusButton"; +import DownloadFromWalrusButton from "../components/walrus/DownloadFromWalrusButton"; const REACT_APP_GATEWAY_URL = process.env.NEXT_PUBLIC_GATEWAY_URL; const EREBRUS_GATEWAY_URL = process.env.NEXT_PUBLIC_EREBRUS_BASE_URL; const mynetwork = process.env.NEXT_PUBLIC_NETWORK; @@ -73,6 +75,7 @@ const Subscription = () => { const [selectedIndex, setSelectedIndex] = useState(null); const { account, connected, network, signMessage } = useWallet(); const router = useRouter(); + const [clientUUID, setClientUUID] = useState(''); let sendable = isSendableNetwork(connected, network?.name); const bg = { @@ -199,6 +202,7 @@ const Subscription = () => { if (response.status === 200) { const responseData = await response.json(); setVpnName(responseData.payload.client.Name); + setClientUUID(responseData.payload.client.UUID); setFormData(initialFormData); console.log("vpn data", responseData); @@ -1251,6 +1255,11 @@ const Subscription = () => {
+
@@ -1273,7 +1282,7 @@ const Subscription = () => {
)} - + {loading && (
Date: Sat, 14 Sep 2024 02:47:05 +0530 Subject: [PATCH 11/12] update : ui --- components/walrus/SaveToWalrusButton.tsx | 182 +++++++++++++++++------ pages/subscription.tsx | 99 +++++++----- 2 files changed, 203 insertions(+), 78 deletions(-) diff --git a/components/walrus/SaveToWalrusButton.tsx b/components/walrus/SaveToWalrusButton.tsx index 90cb4ce..eb8a458 100644 --- a/components/walrus/SaveToWalrusButton.tsx +++ b/components/walrus/SaveToWalrusButton.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import axios from 'axios'; import Cookies from 'js-cookie'; import CryptoJS from 'crypto-js'; // For encryption @@ -15,6 +15,10 @@ const SaveToWalrusButton: React.FC = ({ configFile, vpn const [isPinModalOpen, setIsPinModalOpen] = useState(false); const [pin, setPin] = useState(''); const [confirmPin, setConfirmPin] = useState(''); + const [showPopup, setShowPopup] = useState(false); + const [popupMessage, setPopupMessage] = useState(''); + const [isLoading, setIsLoading] = useState(false); + // Encryption function using wallet address and PIN const encryptBlobId = (blobId: string, walletAddress: string, pin: string) => { @@ -39,6 +43,7 @@ const SaveToWalrusButton: React.FC = ({ configFile, vpn return; } + setIsLoading(true); setIsSaving(true); setSaveStatus('idle'); @@ -52,6 +57,12 @@ const SaveToWalrusButton: React.FC = ({ configFile, vpn headers: { 'Content-Type': 'text/plain' }, } ); + if (walrusResponse.data.alreadyCertified) { + setSaveStatus('success'); + setPopupMessage('Configuration is already saved.'); + setShowPopup(true); + return; + } const blobId = walrusResponse.data.newlyCreated.blobObject.blobId; @@ -77,69 +88,156 @@ const SaveToWalrusButton: React.FC = ({ configFile, vpn ); setSaveStatus('success'); + setPopupMessage('Configuration saved successfully!'); + setShowPopup(true); } catch (error) { console.error('Error saving to Walrus or updating blobId:', error); setSaveStatus('error'); + setPopupMessage('Failed to save configuration.'); + setShowPopup(true); } finally { setIsSaving(false); - setIsPinModalOpen(false); // Close the modal after saving + setIsPinModalOpen(false); + setIsLoading(false); } }; + + useEffect(() => { + if (showPopup) { + const timer = setTimeout(() => { + setShowPopup(false); + setSaveStatus('idle'); + }, 5000); + + return () => clearTimeout(timer); + } + }, [showPopup]); return ( <> - - {/* Modal for PIN and Confirm PIN entry */} - {isPinModalOpen && ( -
-
-

Enter PIN and Confirm PIN

- setPin(e.target.value)} - maxLength={6} - placeholder="Enter 6-digit PIN" - className="border border-gray-300 p-2 rounded-md w-full mb-4" - /> - setConfirmPin(e.target.value)} - maxLength={6} - placeholder="Confirm PIN" - className="border border-gray-300 p-2 rounded-md w-full" - /> -
- - + {/* Status Popup */} + {showPopup && ( +
+
+
+ {saveStatus === 'success' ? ( + + + + ) : ( + + + + )} +
+

+ {popupMessage} +

+
+
+ )} + {isLoading && ( +
+
+ {/* Blockchain representation */} +
+ {[0, 1, 2, 3].map((i) => ( +
+
+
+
+
+ ))} +
+ {/* Connecting lines */} +
+ {[0, 1, 2].map((i) => ( +
+ ))}
+ + {/* Loading text */} +
+ Saving to Walrus... +
)} + {/* Modal for PIN and Confirm PIN entry */} + {isPinModalOpen && ( +
+
+

Secure Your Configuration

+

+ Important: This PIN is your key to accessing your saved configuration. + Please store it securely. If forgotten, you will need to create a new configuration. +

+
+ +
+ setPin(e.target.value)} + maxLength={6} + placeholder="••••••" + className="border border-gray-300 p-2 pl-10 pr-10 rounded-md w-full focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all" + /> + + + +
+
+
+ +
+ setConfirmPin(e.target.value)} + maxLength={6} + placeholder="••••••" + className="border border-gray-300 p-2 pl-10 pr-10 rounded-md w-full focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all" + /> + + + +
+
+
+ + +
+
+
+)} ); }; -export default SaveToWalrusButton; +export default SaveToWalrusButton; \ No newline at end of file diff --git a/pages/subscription.tsx b/pages/subscription.tsx index f056539..5596ff3 100644 --- a/pages/subscription.tsx +++ b/pages/subscription.tsx @@ -75,7 +75,7 @@ const Subscription = () => { const [selectedIndex, setSelectedIndex] = useState(null); const { account, connected, network, signMessage } = useWallet(); const router = useRouter(); - const [clientUUID, setClientUUID] = useState(''); + const [clientUUID, setClientUUID] = useState(""); let sendable = isSendableNetwork(connected, network?.name); const bg = { @@ -223,6 +223,11 @@ const Subscription = () => { setValueFromChild2("refreshafterclientcreate"); // } else if(response.status === 400){ // setMsg("Cant create more than 3 clients"); + + // Reset the form after successful creation + resetForm(); + // Close the form modal + setbuttonset(false); } else { setMsg("Failed to create VPN. Try with unique name."); } @@ -240,7 +245,13 @@ const Subscription = () => { const wallet = Cookies.get("erebrus_wallet"); useEffect(() => { - if (loggedin &&!loading && isDataChecked && !nftdata && !trialsubscriptiondata) { + if ( + loggedin && + !loading && + isDataChecked && + !nftdata && + !trialsubscriptiondata + ) { const redirectTimer = setTimeout(() => { router.push("/plans"); }, 1000); // 1 second delay @@ -300,7 +311,6 @@ const Subscription = () => { setLoading(false); } }; - const vpnnft = async () => { setLoading(true); @@ -410,8 +420,6 @@ const Subscription = () => { // setregion(e.target.value); // }; - - const getAptosWallet = () => { if ("aptos" in window) { return (window as any).aptos; @@ -695,16 +703,23 @@ const Subscription = () => { const time = dateObj.toLocaleTimeString(); return `${day} ${month} ${year} ${time}`; }; + const resetForm = () => { + setFormData(initialFormData); + setSelectedOption(null); + setSelectedIndex(null); + setregionname(''); + }; + const regiondata = [ - { id: "SG", region: "SG" }, - { id: "IN", region: "IN" }, - { id: "US", region: "US" }, - { id: "JP", region: "JP" }, - { id: "CA", region: "CA" }, - { id: "FI", region: "FI" }, - { id: "GB", region: "GB" }, - { id: "AU", region: "AU" }, + { id: "SG", region: "Singapore" }, + { id: "IN", region: "India" }, + { id: "US", region: "United States" }, + { id: "JP", region: "Japan" }, + { id: "CA", region: "Canada" }, + { id: "FI", region: "Finland" }, + { id: "GB", region: "United Kingdom" }, + { id: "AU", region: "Australia" }, // Add more nodes as needed ]; //form @@ -1209,6 +1224,31 @@ const Subscription = () => { }} >
+ {/* Add cross icon */} + +

Successfully created!

@@ -1255,34 +1295,24 @@ const Subscription = () => {
- +
-
- + +
+
)} - + {loading && (
{
{ loading ? ( -
) : projectsData && projectsData?.length !== 0 ? ( -
+ +
+
+ ))} +
+ )} +
+ + {error &&

{error}

} + + ); +}; + +export default FileStorage; \ No newline at end of file diff --git a/pages/subscription.tsx b/pages/subscription.tsx index 5596ff3..33f0f54 100644 --- a/pages/subscription.tsx +++ b/pages/subscription.tsx @@ -16,6 +16,7 @@ import Image from "next/image"; import SingleSignerTransaction from "../components/transactionFlow/SingleSigner"; import SaveToWalrusButton from "../components/walrus/SaveToWalrusButton"; import DownloadFromWalrusButton from "../components/walrus/DownloadFromWalrusButton"; +import FileStorage from "../components/walrus/FileStorage"; const REACT_APP_GATEWAY_URL = process.env.NEXT_PUBLIC_GATEWAY_URL; const EREBRUS_GATEWAY_URL = process.env.NEXT_PUBLIC_EREBRUS_BASE_URL; const mynetwork = process.env.NEXT_PUBLIC_NETWORK; @@ -843,7 +844,8 @@ const Subscription = () => { )} -
+
+
{nftdata && (
{
)} +
+ +
+ +
)}