diff --git a/frontend/src/components/MiningLiveCounter.tsx b/frontend/src/components/MiningLiveCounter.tsx
new file mode 100644
index 0000000..80e1926
--- /dev/null
+++ b/frontend/src/components/MiningLiveCounter.tsx
@@ -0,0 +1,83 @@
+import React, { useState, useEffect } from 'react';
+import * as icon from '@mdi/js';
+import BaseIcon from './BaseIcon';
+import { useAppSelector } from '../stores/hooks';
+
+interface MiningLiveCounterProps {
+ initialBalance?: number;
+ hashrate?: number;
+ isActive?: boolean;
+}
+
+const MiningLiveCounter = ({ initialBalance = 0, hashrate = 42.5, isActive = true }: MiningLiveCounterProps) => {
+ const [balance, setBalance] = useState(initialBalance);
+ const iconsColor = useAppSelector((state) => state.style.iconsColor);
+
+ useEffect(() => {
+ if (!isActive) return;
+
+ const interval = setInterval(() => {
+ // Simulate mining increment: balance increases slightly every second
+ // 0.00000001 BTC (1 Satoshi) per tick roughly
+ setBalance((prev) => prev + 0.000000012);
+ }, 2000);
+
+ return () => clearInterval(interval);
+ }, [isActive]);
+
+ return (
+
+
+
+
+
+
+
+
+
Available Balance
+
+ {balance.toFixed(8)} BTC
+
+
+
+
+
+ {isActive ? '● LIVE MINING' : 'OFFLINE'}
+
+
+
+
+ Est. Daily: 0.000512 BTC
+ Next Payout: 0.005 BTC
+
+
+
+
+
+
+
+
+
+
+
Network Hashrate
+
+ {hashrate.toFixed(1)} TH/s
+
+
+
+
+ {[40, 70, 45, 90, 65, 80, 50, 85].map((h, i) => (
+
+ ))}
+
+
+
+ Uptime: 99.9%
+ Efficiency: 0.22 J/GH
+
+
+
+ );
+};
+
+export default MiningLiveCounter;
diff --git a/frontend/src/components/NavBarItem.tsx b/frontend/src/components/NavBarItem.tsx
index eb155e3..1986306 100644
--- a/frontend/src/components/NavBarItem.tsx
+++ b/frontend/src/components/NavBarItem.tsx
@@ -1,6 +1,5 @@
-import React, {useEffect, useRef} from 'react'
+import React, {useEffect, useRef, useState} from 'react'
import Link from 'next/link'
-import { useState } from 'react'
import { mdiChevronUp, mdiChevronDown } from '@mdi/js'
import BaseDivider from './BaseDivider'
import BaseIcon from './BaseIcon'
@@ -129,4 +128,4 @@ export default function NavBarItem({ item }: Props) {
}
return {NavBarItemComponentContents}
-}
+}
\ No newline at end of file
diff --git a/frontend/src/layouts/Authenticated.tsx b/frontend/src/layouts/Authenticated.tsx
index 1b9907d..2a694cc 100644
--- a/frontend/src/layouts/Authenticated.tsx
+++ b/frontend/src/layouts/Authenticated.tsx
@@ -1,5 +1,4 @@
-import React, { ReactNode, useEffect } from 'react'
-import { useState } from 'react'
+import React, { ReactNode, useEffect, useState } from 'react'
import jwt from 'jsonwebtoken';
import { mdiForwardburger, mdiBackburger, mdiMenu } from '@mdi/js'
import menuAside from '../menuAside'
@@ -52,7 +51,7 @@ export default function LayoutAuthenticated({
useEffect(() => {
dispatch(findMe());
if (!isTokenValid()) {
- dispatch(logoutUser());
+ dispatch(dispatch(logoutUser()));
router.push('/login');
}
}, [token, localToken]);
@@ -126,4 +125,4 @@ export default function LayoutAuthenticated({
)
-}
+}
\ No newline at end of file
diff --git a/frontend/src/pages/dashboard.tsx b/frontend/src/pages/dashboard.tsx
index c2fe6e9..677f56c 100644
--- a/frontend/src/pages/dashboard.tsx
+++ b/frontend/src/pages/dashboard.tsx
@@ -9,6 +9,7 @@ import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton
import BaseIcon from "../components/BaseIcon";
import { getPageTitle } from '../config'
import Link from "next/link";
+import MiningLiveCounter from '../components/MiningLiveCounter';
import { hasPermission } from "../helpers/userPermissions";
import { fetchWidgets } from '../stores/roles/rolesSlice';
@@ -16,6 +17,7 @@ import { WidgetCreator } from '../components/WidgetCreator/WidgetCreator';
import { SmartWidget } from '../components/SmartWidget/SmartWidget';
import { useAppDispatch, useAppSelector } from '../stores/hooks';
+
const Dashboard = () => {
const dispatch = useAppDispatch();
const iconsColor = useAppSelector((state) => state.style.iconsColor);
@@ -40,7 +42,10 @@ const Dashboard = () => {
const [api_jobs, setApi_jobs] = React.useState(loadingMessage);
const [audit_events, setAudit_events] = React.useState(loadingMessage);
-
+ const [userBalance, setUserBalance] = React.useState(0);
+ const [userHashrate, setUserHashrate] = React.useState(42.5);
+ const [isMining, setIsMining] = React.useState(true);
+
const [widgetsRole, setWidgetsRole] = React.useState({
role: { value: '', label: '' },
});
@@ -74,6 +79,26 @@ const Dashboard = () => {
}
});
});
+
+ if (hasPermission(currentUser, 'READ_BALANCES')) {
+ axios.get('/balances').then(res => {
+ if (res.data.rows?.length > 0) {
+ setUserBalance(parseFloat(res.data.rows[0].available_btc || 0));
+ }
+ });
+ }
+ if (hasPermission(currentUser, 'READ_MINING_SESSIONS')) {
+ axios.get('/mining_sessions').then(res => {
+ const runningSession = res.data.rows?.find((s: any) => s.state === 'running');
+ if (runningSession) {
+ setUserHashrate(parseFloat(runningSession.avg_hashrate_ths || 42.5));
+ setIsMining(true);
+ } else {
+ setUserHashrate(0);
+ setIsMining(false);
+ }
+ });
+ }
}
async function getWidgets(roleId) {
@@ -100,10 +125,12 @@ const Dashboard = () => {
{''}
+
+
{hasPermission(currentUser, 'CREATE_ROLES') && {page}
}
-export default Dashboard
+export default Dashboard
\ No newline at end of file
diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx
index 438b9b2..e71b1f0 100644
--- a/frontend/src/pages/index.tsx
+++ b/frontend/src/pages/index.tsx
@@ -12,150 +12,100 @@ import BaseButtons from '../components/BaseButtons';
import { getPageTitle } from '../config';
import { useAppSelector } from '../stores/hooks';
import CardBoxComponentTitle from "../components/CardBoxComponentTitle";
-import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
+import * as icon from '@mdi/js';
+import BaseIcon from '../components/BaseIcon';
export default function Starter() {
- const [illustrationImage, setIllustrationImage] = useState({
- src: undefined,
- photographer: undefined,
- photographer_url: undefined,
- })
- const [illustrationVideo, setIllustrationVideo] = useState({video_files: []})
- const [contentType, setContentType] = useState('video');
- const [contentPosition, setContentPosition] = useState('right');
const textColor = useAppSelector((state) => state.style.linkColor);
-
- const title = 'Bitcoin Mining Dashboard'
-
- // Fetch Pexels image/video
- useEffect(() => {
- async function fetchData() {
- const image = await getPexelsImage();
- const video = await getPexelsVideo();
- setIllustrationImage(image);
- setIllustrationVideo(video);
- }
- fetchData();
- }, []);
-
- const imageBlock = (image) => (
-
- );
-
- const videoBlock = (video) => {
- if (video?.video_files?.length > 0) {
- return (
-
-
-
-
)
- }
- };
+ const title = 'Bitcine'
return (
-
+
-
{getPageTitle('Starter Page')}
+
{getPageTitle('Bitcine - Auto Mining 24/7')}
-
-
- {contentType === 'image' && contentPosition !== 'background'
- ? imageBlock(illustrationImage)
- : null}
- {contentType === 'video' && contentPosition !== 'background'
- ? videoBlock(illustrationVideo)
- : null}
-
-
-
-
-
-
-
-
+ {/* Hero Section */}
+
+ {/* Animated Background Elements */}
+
+
-
-
+
+
+
+ System Live & Mining
+
+
+
+ Next-Gen Bitcoin Mining
+
Auto-Pilot Efficiency
+
+
+
+ Experience the world's most advanced 24/7 autonomous mining platform.
+ Real-time hashrate monitoring, instant payouts, and zero-config hardware integration.
+
+
+
+
+
+
+
+
+
+
-
-
-
-
© 2026 {title}. All rights reserved
-
- Privacy Policy
-
-
+ {/* Feature Grid */}
+
+
+
+
+
+
24/7 Auto-Mining
+
+ Our autonomous algorithms optimize hashrate allocation 24/7, ensuring you never miss a block.
+
+
+
+
+
+
+
+
Instant Payouts
+
+ Direct wallet integration with zero waiting time. Move your earnings to any Bitcoin wallet instantly.
+
+
+
+
+
+
+
+
Advanced Security
+
+ Military-grade encryption for your private keys and withdrawal requests. Your BTC is safe.
+
+
+
+
+
+ {/* Simple Footer */}
+
);
}