Add error page

This commit is contained in:
Eduard Gert
2026-02-04 15:11:22 +01:00
parent ca33849f31
commit 5da2b0fdcc
12 changed files with 106 additions and 22 deletions

View File

@@ -1,4 +1,4 @@
import { useState, useRef } from "react";
import { useState, useRef, useEffect } from "react";
import {Loader2, Lock, Binary, LogIn} from "lucide-react";
import { getData, type Data } from "@/data";
import Button from "@/components/Button";
@@ -22,6 +22,10 @@ const methods: NonNullable<Data["methods"]> =
: { password:"password", pin: "pin", oidc: "/auth/oidc" };
function App() {
useEffect(() => {
document.title = "Authentication Required - NetBird Service";
}, []);
const [error, setError] = useState<string | null>(null);
const [submitting, setSubmitting] = useState<string | null>(null);
const [pin, setPin] = useState("");

View File

@@ -2,11 +2,16 @@ import { NetBirdLogo } from "./NetBirdLogo";
export function PoweredByNetBird() {
return (
<div className="flex items-center justify-center mt-8 gap-2 group cursor-pointer">
<a
href="https://netbird.io?utm_source=netbird-proxy&utm_medium=web&utm_campaign=powered_by"
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center mt-8 gap-2 group cursor-pointer"
>
<span className="text-sm text-nb-gray-400 font-light text-center group-hover:opacity-80 transition-all">
Powered by
</span>
<NetBirdLogo size="small" mobile={false} />
</div>
</a>
);
}

View File

@@ -1,9 +1,21 @@
// Auth method types matching Go
export type AuthMethod = 'pin' | 'password' | 'oidc' | "link"
// Page types
export type PageType = 'auth' | 'error'
// Error data structure
export interface ErrorData {
code: number
title: string
message: string
}
// Data injected by Go templates
export interface Data {
page?: PageType
methods?: Partial<Record<AuthMethod, string>>
error?: ErrorData
}
declare global {

View File

@@ -2,9 +2,17 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
import { ErrorPage } from './pages/ErrorPage.tsx'
import { getData } from '@/data'
const data = getData()
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
{data.page === 'error' && data.error ? (
<ErrorPage {...data.error} />
) : (
<App />
)}
</StrictMode>,
)

View File

@@ -0,0 +1,42 @@
import { useEffect } from "react";
import { BookText, RotateCw } from "lucide-react";
import { Title } from "@/components/Title";
import { Description } from "@/components/Description";
import { PoweredByNetBird } from "@/components/PoweredByNetBird";
import { Card } from "@/components/Card";
import Button from "@/components/Button";
import type { ErrorData } from "@/data";
export function ErrorPage({ code, title, message }: ErrorData) {
useEffect(() => {
document.title = `${title} - NetBird Service`;
}, [title]);
return (
<main className="flex flex-col items-center mt-40 px-4 max-w-xl mx-auto">
<Card className="text-center">
<div className="text-5xl font-bold text-nb-gray-200 mb-4">{code}</div>
<Title>{title}</Title>
<Description className="mt-2">{message}</Description>
<div className="mt-6 flex gap-3 justify-center">
<Button
variant="primary"
onClick={() => window.location.reload()}
>
<RotateCw size={16} />
Refresh Page
</Button>
<Button
variant="secondary"
onClick={() => window.open("https://docs.netbird.io", "_blank")}
>
<BookText size={16} />
Documentation
</Button>
</div>
</Card>
<PoweredByNetBird />
</main>
);
}