draupnir4all-web

git clone git://archive.git.mtrnord.blog/MTRNord/draupnir4all-web.git
Log | Files | Refs | README | LICENSE

page.tsx (9717B)


      1 "use client"
      2 
      3 import { useCallback, useEffect, useState } from "react"
      4 import Link from "next/link"
      5 import { Shield, ArrowRight, Loader2, X } from "lucide-react"
      6 
      7 import { Button } from "@/components/ui/button"
      8 import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
      9 import { Input } from "@/components/ui/input"
     10 import { Label } from "@/components/ui/label"
     11 import { useSession } from "@/contexts/session-context"
     12 import RedirectionPageClient from "@/components/redirect-workaround"
     13 
     14 export default function LoginPage() {
     15   const [matrixId, setMatrixId] = useState("")
     16   const [step, setStep] = useState<"initial" | "login" | "error">("initial")
     17   const [password, setPassword] = useState("")
     18   const { isLoading, login, discoveryStatus, homeserverUrl, discoverHomeserver, user } = useSession();
     19   const [loginLoading, setLoginLoading] = useState(isLoading)
     20   const [errorMessage, setErrorMessage] = useState("")
     21 
     22   useEffect(() => {
     23     console.log("Discovery status changed:", discoveryStatus)
     24     if (discoveryStatus === "loading") {
     25       setLoginLoading(true)
     26     } else if (discoveryStatus === "error") {
     27       setErrorMessage("Failed to discover homeserver. Please check your Matrix ID format.")
     28       setLoginLoading(false)
     29     } else if (discoveryStatus === "success") {
     30       setErrorMessage("")
     31       setLoginLoading(false)
     32     }
     33   }, [discoveryStatus])
     34 
     35   const startMatrixAuth = useCallback(() => {
     36     if (!matrixId) return
     37     setLoginLoading(true)
     38     discoverHomeserver(matrixId).then(() => {
     39       setStep("login")
     40     }).catch((err) => {
     41       console.error("Error discovering homeserver:", err)
     42       setErrorMessage("Please check your Matrix ID format. It should be like @username:matrix.org")
     43       setStep("error")
     44       setLoginLoading(false)
     45     });
     46   }, [matrixId, discoverHomeserver]);
     47 
     48   const handleSubmit = useCallback(async (e: React.FormEvent) => {
     49     e.preventDefault()
     50     setErrorMessage("")
     51 
     52     try {
     53       await login(matrixId, password)
     54     } catch (err) {
     55       console.error("Login failed:", err)
     56       setErrorMessage("Login failed. Please check your credentials.")
     57       setStep("error")
     58     }
     59   }, [login, matrixId, password])
     60 
     61   if (user) {
     62     return <RedirectionPageClient redirectUrl="/dashboard" replace />
     63   }
     64 
     65   return (
     66     <div className="flex min-h-screen flex-col bg-black text-white">
     67       <header className="border-b border-gray-800 bg-black py-4">
     68         <div className="container flex items-center justify-between px-4 md:px-6">
     69           <Link href="/" className="flex items-center gap-2">
     70             <Shield className="h-6 w-6 text-purple-400" />
     71             <span className="text-xl font-bold tracking-tighter">Draupnir4All</span>
     72           </Link>
     73         </div>
     74       </header>
     75       <main className="flex-1 flex items-center justify-center p-4">
     76         <Card className="w-full max-w-md border-gray-800 bg-gray-950">
     77           <CardHeader>
     78             <CardTitle className="text-2xl">Log in with Matrix</CardTitle>
     79             <CardDescription className="text-gray-400">Access your Draupnir moderation dashboard</CardDescription>
     80           </CardHeader>
     81           <CardContent className="space-y-4">
     82             {step === "initial" && (
     83               <div className="space-y-4">
     84                 <div className="space-y-2">
     85                   <Label htmlFor="matrix-id">Matrix ID</Label>
     86                   <Input
     87                     id="matrix-id"
     88                     placeholder="@username:matrix.org"
     89                     className="bg-gray-900 border-gray-800"
     90                     value={matrixId}
     91                     onChange={(e) => setMatrixId(e.target.value)}
     92                   />
     93                   <p className="text-xs text-gray-400">Enter your Matrix ID to begin the authentication process</p>
     94                 </div>
     95               </div>
     96             )}
     97 
     98             {step === "login" && (
     99               <form onSubmit={handleSubmit} className="space-y-4">
    100                 <div className="space-y-2">
    101                   <div className="flex items-center justify-between">
    102                     <Label htmlFor="matrix-username">Matrix ID</Label>
    103                     <Button type="button" variant="ghost" size="sm" className="h-6 px-2 text-gray-400" onClick={() => setStep("initial")}>
    104                       <X className="h-4 w-4" />
    105                     </Button>
    106                   </div>
    107                   <div className="flex items-center gap-2 rounded-md bg-gray-900 px-3 py-2 text-sm">
    108                     <span>{matrixId}</span>
    109                   </div>
    110 
    111                   {discoveryStatus === "loading" && (
    112                     <div className="flex items-center gap-2 text-xs text-gray-400">
    113                       <Loader2 className="h-3 w-3 animate-spin" />
    114                       Discovering homeserver...
    115                     </div>
    116                   )}
    117 
    118                   {discoveryStatus === "success" && homeserverUrl && (
    119                     <p className="text-xs text-gray-400">Authenticating with {homeserverUrl.replace(/^https?:\/\//, "")}</p>
    120                   )}
    121 
    122                   {discoveryStatus === "error" && (
    123                     <p className="text-xs text-red-400">Failed to discover homeserver. Please check your Matrix ID and ensure it&apos;s format is &quot;@localpart:example.com&quot;.</p>
    124                   )}
    125                 </div>
    126 
    127                 {discoveryStatus === "success" && (
    128                   <div className="space-y-2">
    129                     <Label htmlFor="matrix-password">Password</Label>
    130                     <Input
    131                       id="matrix-password"
    132                       type="password"
    133                       placeholder="Enter your Matrix password"
    134                       className="bg-gray-900 border-gray-800"
    135                       value={password}
    136                       onChange={(e) => setPassword(e.target.value)}
    137                       required
    138                     />
    139                   </div>
    140                 )}
    141 
    142                 <div className="flex gap-2">
    143                   <Button
    144                     type="submit"
    145                     className="flex-1 bg-purple-600 text-white hover:bg-purple-700"
    146                     disabled={isLoading || !password || discoveryStatus !== "success"}
    147                   >
    148                     {isLoading ? (
    149                       <>
    150                         <Loader2 className="mr-2 h-4 w-4 animate-spin" />
    151                         Authenticating...
    152                       </>
    153                     ) : (
    154                       "Log in"
    155                     )}
    156                   </Button>
    157                   <Button
    158                     type="button"
    159                     variant="outline"
    160                     className="border-gray-700 text-gray-400 hover:bg-gray-900 hover:text-gray-300"
    161                     onClick={() => {
    162                       setStep("initial")
    163                       setMatrixId("")
    164                       setPassword("")
    165                     }}
    166                     disabled={isLoading || loginLoading}
    167                   >
    168                     Cancel
    169                   </Button>
    170                 </div>
    171 
    172                 <p className="text-xs text-gray-400 text-center">
    173                   Your credentials are sent directly to your Matrix homeserver. Draupnir4All only receives a verification token.
    174                 </p>
    175               </form>
    176             )}
    177 
    178             {((isLoading || loginLoading) && discoveryStatus !== "loading") && (
    179               <div className="flex flex-col items-center justify-center py-6 space-y-4">
    180                 <Loader2 className="h-8 w-8 animate-spin text-purple-400" />
    181                 <p className="text-gray-300">Logging in...</p>
    182                 <p className="text-xs text-gray-400">Accessing your Draupnir4All account</p>
    183               </div>
    184             )}
    185 
    186             {((isLoading || loginLoading) && discoveryStatus === "loading") && (
    187               <div className="flex flex-col items-center justify-center py-6 space-y-4">
    188                 <Loader2 className="h-8 w-8 animate-spin text-purple-400" />
    189                 <p className="text-gray-300">Discovering the Homeserver URL...</p>
    190               </div>
    191             )}
    192             {step === "error" && (
    193               <div className="rounded-md bg-red-900/20 border border-red-800 p-4 text-center">
    194                 <p className="text-red-300 font-medium">Login Failed</p>
    195                 <p className="text-sm text-red-200 mt-1">{errorMessage}</p>
    196                 <Button
    197                   variant="outline"
    198                   className="mt-4 border-red-500 text-red-400 hover:bg-red-950 hover:text-red-300"
    199                   onClick={() => { setStep("initial"); setMatrixId(""); setPassword(""); }}
    200                 >
    201                   Try Again
    202                 </Button>
    203               </div>
    204             )}
    205           </CardContent>
    206           <CardFooter className="flex flex-col space-y-4">
    207             {step === "initial" && (
    208               <>
    209                 <Button
    210                   className="w-full bg-purple-600 text-white hover:bg-purple-700"
    211                   onClick={startMatrixAuth}
    212                   disabled={!matrixId || isLoading || loginLoading}
    213                 >
    214                   Continue
    215                   <ArrowRight className="ml-2 h-4 w-4" />
    216                 </Button>
    217                 <p className="text-center text-sm text-gray-400">
    218                   Don&apos;t have a Draupnir bot yet?{" "}
    219                   <Link href="/register" className="text-purple-400 hover:text-purple-300">
    220                     Register here
    221                   </Link>
    222                 </p>
    223               </>
    224             )}
    225           </CardFooter>
    226         </Card>
    227       </main>
    228     </div >
    229   )
    230 }