From 3d49aaad16891624571c67b3c400063ba4d91a9b Mon Sep 17 00:00:00 2001 From: Aidan Date: Tue, 22 Apr 2025 09:50:43 -0400 Subject: [PATCH] design: better mobile footer display, clean up welcome card + add link, add grading to security checks, clean up services display --- components/cards/dashboard/git/LinkGitea.tsx | 4 +- .../cards/dashboard/overview/WelcomeCard.tsx | 33 ++++----- components/pages/dashboard/Footer.tsx | 4 +- components/pages/dashboard/SecurityTab.tsx | 72 +++++++++++++++++-- components/pages/dashboard/ServicesTab.tsx | 20 +++--- 5 files changed, 99 insertions(+), 34 deletions(-) diff --git a/components/cards/dashboard/git/LinkGitea.tsx b/components/cards/dashboard/git/LinkGitea.tsx index 0305015..f9c69d8 100644 --- a/components/cards/dashboard/git/LinkGitea.tsx +++ b/components/cards/dashboard/git/LinkGitea.tsx @@ -190,12 +190,12 @@ export function LinkGitea({ linked }: { linked: boolean }) { >here.

{unlinkLoading ? ( - ) : ( - diff --git a/components/cards/dashboard/overview/WelcomeCard.tsx b/components/cards/dashboard/overview/WelcomeCard.tsx index a747539..f678b17 100644 --- a/components/cards/dashboard/overview/WelcomeCard.tsx +++ b/components/cards/dashboard/overview/WelcomeCard.tsx @@ -1,25 +1,26 @@ -import React, { useState, useEffect } from "react"; -import Cookies from "js-cookie"; -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Check } from "lucide-react"; +import React, { useState, useEffect } from "react" +import Cookies from "js-cookie" +import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { Check } from "lucide-react" +import Link from "next/link" export const WelcomeCard = () => { - const [visible, setVisible] = useState(true); + const [visible, setVisible] = useState(true) useEffect(() => { - const isRead = Cookies.get("welcome-read"); + const isRead = Cookies.get("welcome-read") if (isRead === "true") { - setVisible(false); + setVisible(false) } - }, []); + }, []) const handleMarkAsRead = () => { - Cookies.set("welcome-read", "true"); - setVisible(false); - }; + Cookies.set("welcome-read", "true") + setVisible(false) + } - if (!visible) return null; + if (!visible) return null return ( @@ -31,7 +32,7 @@ export const WelcomeCard = () => { Thanks for logging in! Here you can manage your account and the services available to you.

- We’re thrilled to have you on board, and if you need anything, don’t hesitate to contact support (see the sidebar). + We’re thrilled to have you on board, and if you need anything, don’t hesitate to contact our support team!

That’s all, have a great day!

@@ -41,5 +42,5 @@ export const WelcomeCard = () => {
- ); -}; \ No newline at end of file + ) +} diff --git a/components/pages/dashboard/Footer.tsx b/components/pages/dashboard/Footer.tsx index 201cb31..082fe22 100644 --- a/components/pages/dashboard/Footer.tsx +++ b/components/pages/dashboard/Footer.tsx @@ -27,11 +27,11 @@ export function Footer() {

{renderTime !== null ? ( -

+

Page rendered in {renderTime.toFixed(2)} ms

) : ( -

+

Calculating render time...

)} diff --git a/components/pages/dashboard/SecurityTab.tsx b/components/pages/dashboard/SecurityTab.tsx index f26bc91..e5103fb 100644 --- a/components/pages/dashboard/SecurityTab.tsx +++ b/components/pages/dashboard/SecurityTab.tsx @@ -1,14 +1,22 @@ import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { AlertCircle, CheckCircleIcon, XCircleIcon, Loader2, ShieldCheck, Search, Lightbulb } from "lucide-react" -import { useState } from "react" +import { useState, useEffect } from "react" import { SiAuthentik } from "react-icons/si" import { type SecurityResults } from "@/app/api/users/security/route" +interface CategoryChecks { + passed: number + failed: number + total: number +} + export const SecurityTab = () => { const [scanning, setScanning] = useState(false) const [scanResults, setScanResults] = useState(null) const [error, setError] = useState(null) + const [authentikChecks, setAuthentikChecks] = useState({ passed: 0, failed: 0, total: 0 }) + const [overallChecks, setOverallChecks] = useState({ passed: 0, failed: 0, total: 0 }) const scanAcc = async () => { setScanning(true) @@ -30,6 +38,41 @@ export const SecurityTab = () => { // If user has no 2FA methods setup, this will be true const insufficient2FA = scanResults?.authentik?.authenticators.length === 0 + useEffect(() => { + if (scanResults) { + const authentik: CategoryChecks = { + passed: 0, + failed: 0, + total: 0 + } + + // Password age + authentik.total++ + if (!shouldResetPass) { + authentik.passed++ + } else { + authentik.failed++ + } + + // 2FA + authentik.total++ + if (!insufficient2FA) { + authentik.passed++ + } else { + authentik.failed++ + } + + setAuthentikChecks(authentik) + + setOverallChecks(authentik) + } + }, [scanResults, shouldResetPass, insufficient2FA]) + + const calculatePercentage = (passed: number, total: number) => { + if (total === 0) return 0 + return Math.round((passed / total) * 100) + } + return (
@@ -51,9 +94,16 @@ export const SecurityTab = () => {
) : scanResults ? ( <> -
- -

Authentik

+
+
+ +

Authentik

+
+
+ + {authentikChecks.passed}/{authentikChecks.total} checks passed + +
{shouldResetPass ? ( @@ -79,6 +129,20 @@ export const SecurityTab = () => {

{scanResults?.authentik?.authenticators.length} two-factor authentication methods setup

)} + +
+
+ Results +
+ + {calculatePercentage(overallChecks.passed, overallChecks.total)}% + + + {overallChecks.passed}/{overallChecks.total} checks passed + +
+
+
) : ( <> diff --git a/components/pages/dashboard/ServicesTab.tsx b/components/pages/dashboard/ServicesTab.tsx index 461cafe..25e577f 100644 --- a/components/pages/dashboard/ServicesTab.tsx +++ b/components/pages/dashboard/ServicesTab.tsx @@ -15,9 +15,9 @@ export const ServicesTab = () => ( Send, read, and manage your email account from a web browser! Powered by Roundcube and LibreCloud Mail. - @@ -33,9 +33,9 @@ export const ServicesTab = () => ( Host unlimited repositories and run Actions on our Git server, powered by Gitea. - @@ -51,9 +51,9 @@ export const ServicesTab = () => ( Securely store your passwords, notes, and 2FA codes with Vaultwarden. Data is encrypted at rest. - @@ -69,9 +69,9 @@ export const ServicesTab = () => ( Manage your single-sign-on account for all LibreCloud services. - @@ -87,9 +87,9 @@ export const ServicesTab = () => ( Store, share, edit, and synchronize files with Nextcloud. -