Skip to content

Commit

Permalink
Merge branch 'dev' into test-swc-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
LoV432 committed Mar 7, 2024
2 parents d9e23a1 + f645ba8 commit 98e32e7
Show file tree
Hide file tree
Showing 11 changed files with 343 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client';
import { useSetAtom, atom } from 'jotai';
import { useEffect, useMemo } from 'react';
import { getConnectedDevices } from '@/lib/get-connected-devices';
export const allConnectedDevices = atom<Array<string>>([]);

export default function ConnectedDevicesWrapper({
children,
connectedDevices: connectedDevices
}: {
children: React.ReactNode;
connectedDevices: string[];
}) {
const setConnectedDevices = useSetAtom(allConnectedDevices);
useMemo(() => {
setConnectedDevices(connectedDevices);
}, []);
useEffect(() => {
setInterval(() => {
getConnectedDevices().then((connectedDevices) => {
if ('error' in connectedDevices) return;
setConnectedDevices(connectedDevices);
});
}, 5000);
});
return <>{children}</>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getConnectedDevices } from '@/lib/get-connected-devices';
import ConnectedDevicesWrapper from './ConnectedDevicesBoundarie.client';

export default async function ConnectedDevicesBoundarie({
children
}: {
children: React.ReactNode;
}) {
const connectedDevices = await getConnectedDevices();
if ('error' in connectedDevices)
return (
<ConnectedDevicesWrapper connectedDevices={[]}>
{children}
</ConnectedDevicesWrapper>
);
return (
<ConnectedDevicesWrapper connectedDevices={connectedDevices}>
{children}
</ConnectedDevicesWrapper>
);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import SpeedMeter from './SpeedMeter.client';
import { getUptime } from '@/lib/get-uptime';
import DashboardUptime from './DashboardUptime.client';
import { db } from '@/lib/db';
import PerUserSpeedDetails from './PerUserSpeedDetails.client';

type ipToName = {
index_number: number;
ip: string;
name: string;
display_name: string;
}[];

export default async function DashboardCardNetWork() {
let uptime = await getUptime();
let allUsers = db
.prepare('SELECT index_number, ip, name, display_name FROM users')
.all() as ipToName;
return (
<>
<div className="card w-full border border-white border-opacity-40 bg-zinc-900 sm:w-96">
<div className="card-body justify-center">
<div className="card-body justify-center pb-3">
<div className="border-b-2 border-white border-opacity-20 px-2 pb-3">
<DashboardUptime uptime={uptime} />
</div>
Expand All @@ -24,6 +36,7 @@ export default async function DashboardCardNetWork() {
maxSpeed={parseInt(process.env.MAX_UPLOAD_SPEED || '15')}
/>
</div>
<PerUserSpeedDetails allUsers={allUsers} />
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
'use client';
import { useAtomValue } from 'jotai';
import { allSpeedStates } from '../../boundaries/SpeedBoundarie.client';
import { useRef } from 'react';

export default function PerUserSpeedDetails({
allUsers
}: {
allUsers: {
index_number: number;
ip: string;
name: string;
display_name: string;
}[];
}) {
const perUserSpeedModal = useRef(
null
) as unknown as React.MutableRefObject<HTMLDialogElement>;
return (
<>
<div className="text-right text-sm font-semibold text-gray-400 opacity-80 hover:cursor-pointer">
<div
onClick={() => perUserSpeedModal.current?.showModal()}
className="mt-2 w-5/6"
>
Show Details
</div>
</div>
<PerUserSpeedDetailsPopUp
allUsers={allUsers}
perUserSpeedModal={perUserSpeedModal}
/>
</>
);
}

function PerUserSpeedDetailsPopUp({
allUsers,
perUserSpeedModal
}: {
allUsers: {
index_number: number;
ip: string;
name: string;
display_name: string;
}[];
perUserSpeedModal: React.MutableRefObject<HTMLDialogElement>;
}) {
function closePopUp() {
perUserSpeedModal.current?.close();
}
const allSpeeds = useAtomValue(allSpeedStates);
if (!allSpeeds[0].length)
return (
<>
<dialog ref={perUserSpeedModal} className="modal">
<div className="modal-box !min-h-[400px] w-11/12 min-w-[auto] bg-zinc-900 sm:w-3/4 md:w-1/2 lg:w-1/2">
<h3 className="pb-5 text-lg font-bold">Per User Speed</h3>

<div className="overflow-x-auto">
<table className="table table-fixed">
<thead>
<tr className="border-zinc-700">
<th>Name</th>
<th>Download</th>
<th>Upload</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>

<button
onClick={closePopUp}
className="btn btn-circle btn-ghost btn-sm absolute right-2 top-2"
>
</button>
</div>
<div className="modal-backdrop bg-zinc-700 opacity-30">
<button onClick={closePopUp}>close</button>
</div>
</dialog>
</>
);
const ipToName = allSpeeds[0].map((user) => {
const userDetails = allUsers.filter((u) => u.ip === user.ip)[0];
if (!userDetails) return;
if (Number(user.in) <= 0 && Number(user.out) <= 0) return;
let userName =
userDetails.display_name ||
(userDetails.name != 'Unknown' ? userDetails.name : user.ip);
return {
index_number: userDetails.index_number,
name: userName,
in: user.in,
out: user.out
};
});
const ipToNameFiltered = ipToName.filter((u) => u !== undefined) as {
index_number: number;
name: string;
in: string;
out: string;
}[];
ipToNameFiltered.sort((a, b) => a.index_number - b.index_number);
return (
<>
<dialog ref={perUserSpeedModal} className="modal">
<div className="modal-box !min-h-[400px] w-11/12 min-w-[auto] bg-zinc-900 sm:w-3/4 md:w-1/2 lg:w-1/2">
<h3 className="pb-5 text-lg font-bold">Per User Speed</h3>

<div className="overflow-x-auto">
<table className="table table-fixed">
<thead>
<tr className="border-zinc-700">
<th>Name</th>
<th>Download</th>
<th>Upload</th>
</tr>
</thead>
<tbody>
{ipToNameFiltered.map((user) => (
<tr className="border-zinc-700" key={user.name}>
<td>{user.name}</td>
<td>{user.in} Mbps</td>
<td>{user.out} Mbps</td>
</tr>
))}
</tbody>
</table>
</div>

<button
onClick={closePopUp}
className="btn btn-circle btn-ghost btn-sm absolute right-2 top-2"
>
</button>
</div>
<div className="modal-backdrop bg-zinc-700 opacity-30">
<button onClick={closePopUp}>close</button>
</div>
</dialog>
</>
);
}
72 changes: 51 additions & 21 deletions app/components/user-cards/UserCard.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import {
getAllBlockedDevices,
unblockDevice as unblockUser
} from '@/lib/block-user-script.server';
import { allBlockedDevices as allBlockedDevicesState } from '../boundaries/BlockedDevicesBoundarie.client';
import { allBlockedDevices as allBlockedDevicesState } from '../boundaries/BlockedDevices/BlockedDevicesBoundarie.client';
import { allConnectedDevices as allConnectedDevicesState } from '../boundaries/ConnectedDevices/ConnectedDevicesBoundarie.client';
export default function UserCard({ user }: { user: userReturnType }) {
const [localUpdateTime, setLocalUpdateTime] = useState('');
const [showDetails, setShowDetails] = useState(false);
const [showToast, setShowToast] = useState(false);
const allBlockedDevices = useAtomValue(allBlockedDevicesState);
const isBlocked = allBlockedDevices.includes(user.mac_address);
const allConnectedDevices = useAtomValue(allConnectedDevicesState);
const isConnected = allConnectedDevices.includes(user.mac_address);

function copyText(text: string) {
// TODO: This whole copy/toast logic is duplicate of DashboardCardCurrentStatus.client.tsx. Find a way to merge?
Expand All @@ -45,6 +48,11 @@ export default function UserCard({ user }: { user: userReturnType }) {
<div
className={`card card-side m-5 h-fit w-full bg-zinc-900 p-2 shadow-xl last:mb-[7rem] sm:w-[300px] ${isBlocked ? 'text-error' : ''}`}
>
<div className="absolute right-0 top-0">
{isConnected && (
<span className="badge indicator-item badge-success badge-sm absolute -right-1 -top-1"></span>
)}
</div>
<UserSpeed ip={user.ip} />
<figure className="relative flex w-1/4 items-center justify-center overflow-visible px-1 py-4">
<DropDown
Expand Down Expand Up @@ -487,20 +495,28 @@ function BlockDevicePopUp({
macAddress: string;
setBlockDeviceModalIsOpen: (value: boolean) => void;
}) {
let router = useRouter();
let blockDeviceModal = useRef<HTMLDialogElement>(null);
const router = useRouter();
const blockDeviceModal = useRef<HTMLDialogElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
const isRunning = useRef(false);
const setBlockedDevices = useSetAtom(allBlockedDevicesState);
async function blockDevice() {
(async () => {
blockUser(macAddress);
setBlockedDevices((prev) => [...prev, macAddress]);
const allBlockedDevices = await getAllBlockedDevices();
if (!('error' in allBlockedDevices)) setBlockedDevices(allBlockedDevices);
})();
isRunning.current = true;
if (!buttonRef.current) return;
buttonRef.current.setAttribute('disabled', 'true');
buttonRef.current.classList.add('after:loading');
buttonRef.current.innerText = '';
await blockUser(macAddress);
const allBlockedDevices = await getAllBlockedDevices();
if (!('error' in allBlockedDevices)) setBlockedDevices(allBlockedDevices);
buttonRef.current.classList.remove('after:loading');
buttonRef.current.removeAttribute('disabled');
isRunning.current = false;
closePopUp();
router.refresh();
}
async function closePopUp() {
if (isRunning.current) return;
blockDeviceModal.current?.close();
await new Promise((resolve) => setTimeout(resolve, 100));
setBlockDeviceModalIsOpen(false);
Expand All @@ -517,7 +533,11 @@ function BlockDevicePopUp({
<div className="modal-box bg-zinc-900">
<h3 className="pb-5 text-lg font-bold">Block Device</h3>
<p>Are you sure you want to block this device internet access?</p>
<button onClick={blockDevice} className="btn btn-error mt-5 w-full">
<button
ref={buttonRef}
onClick={blockDevice}
className="btn btn-error mt-5 w-full"
>
Block
</button>
<button onClick={closePopUp} className="btn btn-ghost mt-5 w-full">
Expand All @@ -544,22 +564,28 @@ function UnblockDevicePopUp({
macAddress: string;
setUnblockDeviceModalIsOpen: (value: boolean) => void;
}) {
let router = useRouter();
let unblockDeviceModal = useRef<HTMLDialogElement>(null);
const router = useRouter();
const unblockDeviceModal = useRef<HTMLDialogElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
const isRunning = useRef(false);
const setBlockedDevices = useSetAtom(allBlockedDevicesState);
async function unblockDevice() {
(async () => {
unblockUser(macAddress);
setBlockedDevices((prev) =>
prev.filter((device) => device !== macAddress)
);
const allBlockedDevices = await getAllBlockedDevices();
if (!('error' in allBlockedDevices)) setBlockedDevices(allBlockedDevices);
})();
isRunning.current = true;
if (!buttonRef.current) return;
buttonRef.current.setAttribute('disabled', 'true');
buttonRef.current.classList.add('after:loading');
buttonRef.current.innerText = '';
await unblockUser(macAddress);
const allBlockedDevices = await getAllBlockedDevices();
if (!('error' in allBlockedDevices)) setBlockedDevices(allBlockedDevices);
buttonRef.current.classList.remove('after:loading');
buttonRef.current.removeAttribute('disabled');
isRunning.current = false;
closePopUp();
router.refresh();
}
async function closePopUp() {
if (isRunning.current) return;
unblockDeviceModal.current?.close();
await new Promise((resolve) => setTimeout(resolve, 100));
setUnblockDeviceModalIsOpen(false);
Expand All @@ -576,7 +602,11 @@ function UnblockDevicePopUp({
<div className="modal-box bg-zinc-900">
<h3 className="pb-5 text-lg font-bold">Unblock Device</h3>
<p>Are you sure you want to Unblock this device internet access?</p>
<button onClick={unblockDevice} className="btn btn-error mt-5 w-full">
<button
ref={buttonRef}
onClick={unblockDevice}
className="btn btn-error mt-5 w-full"
>
Unblock
</button>
<button onClick={closePopUp} className="btn btn-ghost mt-5 w-full">
Expand Down
11 changes: 7 additions & 4 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Dashboard from './components/dashboard/Dashboard.server';
import UserCards from './components/user-cards/UserCards.server';
import SpeedBoundarie from './components/boundaries/SpeedBoundarie.client';
import BlockedDevicesBoundarie from './components/boundaries/BlockedDevicesBoundarie.server';
import BlockedDevicesBoundarie from './components/boundaries/BlockedDevices/BlockedDevicesBoundarie.server';
import ConnectedDevicesBoundarie from './components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.server';
import { Provider } from 'jotai';
export const dynamic = 'force-dynamic';
export default function Home() {
Expand All @@ -14,9 +15,11 @@ export default function Home() {
<Dashboard />
</div>
<div className="flex flex-row flex-wrap justify-evenly">
<BlockedDevicesBoundarie>
<UserCards />
</BlockedDevicesBoundarie>
<ConnectedDevicesBoundarie>
<BlockedDevicesBoundarie>
<UserCards />
</BlockedDevicesBoundarie>
</ConnectedDevicesBoundarie>
</div>
</SpeedBoundarie>
</Provider>
Expand Down
Loading

0 comments on commit 98e32e7

Please sign in to comment.