File size: 3,294 Bytes
6678fa1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { useState, useEffect, ReactNode } from "react";
import { trpc } from "@/lib/trpc";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Lock, Loader2 } from "lucide-react";

const ACCESS_KEY_STORAGE = "access_key_verified";

export function AccessGate({ children }: { children: ReactNode }) {
  const [key, setKey] = useState("");
  const [error, setError] = useState("");
  const [verified, setVerified] = useState<boolean | null>(null);

  const accessKeyEnabled = trpc.auth.accessKeyEnabled.useQuery();
  const verifyMutation = trpc.auth.verifyAccessKey.useMutation();

  // Check if already verified in session
  useEffect(() => {
    if (accessKeyEnabled.data?.enabled === false) {
      setVerified(true);
      return;
    }
    const stored = sessionStorage.getItem(ACCESS_KEY_STORAGE);
    if (stored === "true") {
      setVerified(true);
    } else if (accessKeyEnabled.data?.enabled) {
      setVerified(false);
    }
  }, [accessKeyEnabled.data]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError("");

    try {
      const result = await verifyMutation.mutateAsync({ key });
      if (result.valid) {
        sessionStorage.setItem(ACCESS_KEY_STORAGE, "true");
        setVerified(true);
      } else {
        setError("Invalid access key");
      }
    } catch {
      setError("Failed to verify key");
    }
  };

  // Still loading
  if (accessKeyEnabled.isLoading || verified === null) {
    return (
      <div className="min-h-screen flex items-center justify-center">
        <Loader2 className="w-8 h-8 animate-spin text-primary" />
      </div>
    );
  }

  // Already verified or access key disabled
  if (verified) {
    return <>{children}</>;
  }

  // Show access key prompt
  return (
    <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-purple-50 via-white to-blue-50">
      <Card className="w-full max-w-md mx-4">
        <CardHeader className="text-center">
          <div className="inline-flex items-center justify-center w-12 h-12 bg-primary/10 rounded-xl mx-auto mb-4">
            <Lock className="w-6 h-6 text-primary" />
          </div>
          <CardTitle>Access Required</CardTitle>
          <CardDescription>
            Enter the access key to continue
          </CardDescription>
        </CardHeader>
        <CardContent>
          <form onSubmit={handleSubmit} className="space-y-4">
            <Input
              type="password"
              placeholder="Access key"
              value={key}
              onChange={(e) => setKey(e.target.value)}
              autoFocus
            />
            {error && (
              <p className="text-sm text-red-500">{error}</p>
            )}
            <Button 
              type="submit" 
              className="w-full"
              disabled={verifyMutation.isPending || !key}
            >
              {verifyMutation.isPending ? (
                <Loader2 className="w-4 h-4 animate-spin mr-2" />
              ) : null}
              Continue
            </Button>
          </form>
        </CardContent>
      </Card>
    </div>
  );
}