"use client" import { useState, useEffect } from "react" import { useTranslations } from "next-intl" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Key, Plus, Loader2, Copy, Trash2, ChevronDown, ChevronUp } from "lucide-react" import { useToast } from "@/components/ui/use-toast" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter, DialogDescription, DialogClose, } from "@/components/ui/dialog" import { Switch } from "@/components/ui/switch" import { Label } from "@/components/ui/label" import { useCopy } from "@/hooks/use-copy" import { useRolePermission } from "@/hooks/use-role-permission" import { PERMISSIONS } from "@/lib/permissions" import { useConfig } from "@/hooks/use-config" type ApiKey = { id: string name: string key: string createdAt: string expiresAt: string | null enabled: boolean } export function ApiKeyPanel() { const t = useTranslations("profile.apiKey") const tCommon = useTranslations("common.actions") const tNoPermission = useTranslations("emails.noPermission") const tMessages = useTranslations("emails.messages") const [apiKeys, setApiKeys] = useState([]) const [loading, setLoading] = useState(false) const [createDialogOpen, setCreateDialogOpen] = useState(false) const [newKeyName, setNewKeyName] = useState("") const [newKey, setNewKey] = useState(null) const { toast } = useToast() const { copyToClipboard } = useCopy() const [showExamples, setShowExamples] = useState(false) const [isLoading, setIsLoading] = useState(true) const { checkPermission } = useRolePermission() const canManageApiKey = checkPermission(PERMISSIONS.MANAGE_API_KEY) const fetchApiKeys = async () => { try { const res = await fetch("/api/api-keys") if (!res.ok) throw new Error(t("createFailed")) const data = await res.json() as { apiKeys: ApiKey[] } setApiKeys(data.apiKeys) } catch (error) { console.error(error) toast({ title: t("createFailed"), description: t("createFailed"), variant: "destructive" }) } finally { setIsLoading(false) } } useEffect(() => { if (canManageApiKey) { fetchApiKeys() } }, [canManageApiKey]) const { config } = useConfig() const createApiKey = async () => { if (!newKeyName.trim()) return setLoading(true) try { const res = await fetch("/api/api-keys", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: newKeyName }) }) if (!res.ok) throw new Error(t("createFailed")) const data = await res.json() as { key: string } setNewKey(data.key) fetchApiKeys() } catch (error) { toast({ title: t("createFailed"), description: error instanceof Error ? error.message : t("createFailed"), variant: "destructive" }) setCreateDialogOpen(false) } finally { setLoading(false) } } const handleDialogClose = () => { setCreateDialogOpen(false) setNewKeyName("") setNewKey(null) } const toggleApiKey = async (id: string, enabled: boolean) => { try { const res = await fetch(`/api/api-keys/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ enabled }) }) if (!res.ok) throw new Error(t("createFailed")) setApiKeys(keys => keys.map(key => key.id === id ? { ...key, enabled } : key ) ) } catch (error) { console.error(error) toast({ title: t("createFailed"), description: t("createFailed"), variant: "destructive" }) } } const deleteApiKey = async (id: string) => { try { const res = await fetch(`/api/api-keys/${id}`, { method: "DELETE" }) if (!res.ok) throw new Error(t("deleteFailed")) setApiKeys(keys => keys.filter(key => key.id !== id)) toast({ title: t("deleteSuccess"), description: t("deleteSuccess") }) } catch (error) { console.error(error) toast({ title: t("deleteFailed"), description: t("deleteFailed"), variant: "destructive" }) } } return (

{t("title")}

{ canManageApiKey && ( {newKey ? t("createSuccess") : t("create")} {newKey && ( {t("description")} )} {!newKey ? (
setNewKeyName(e.target.value)} placeholder={t("namePlaceholder")} />
) : (
)} {!newKey && ( )}
) }
{ !canManageApiKey ? (

{tNoPermission("needPermission")}

{tNoPermission("contactAdmin")}

{ config?.adminContact && (

{tNoPermission("adminContact")}: {config.adminContact}

) }
) : (
{isLoading ? (

{tMessages("loading")}

) : apiKeys.length === 0 ? (

{t("noKeys")}

{t("description")}

) : ( <> {apiKeys.map((key) => (
{key.name}
{t("createdAt")}: {new Date(key.createdAt).toLocaleString()}
toggleApiKey(key.id, checked)} />
))}
{showExamples && (
{t("docs.getConfig")}
                          {`curl ${window.location.protocol}//${window.location.host}/api/config \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
{t("docs.generateEmail")}
                          {`curl -X POST ${window.location.protocol}//${window.location.host}/api/emails/generate \\
  -H "X-API-Key: YOUR_API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{
    "name": "test",
    "expiryTime": 3600000,
    "domain": "moemail.app"
  }'`}
                        
{t("docs.getEmails")}
                          {`curl ${window.location.protocol}//${window.location.host}/api/emails?cursor=CURSOR \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
{t("docs.getMessages")}
                          {`curl ${window.location.protocol}//${window.location.host}/api/emails/{emailId}?cursor=CURSOR \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
{t("docs.getMessage")}
                          {`curl ${window.location.protocol}//${window.location.host}/api/emails/{emailId}/{messageId} \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
{t("docs.createEmailShare")}
                          {`curl -X POST ${window.location.protocol}//${window.location.host}/api/emails/{emailId}/share \\
  -H "X-API-Key: YOUR_API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"expiresIn": 86400000}'`}
                        
{t("docs.getEmailShares")}
                          {`curl ${window.location.protocol}//${window.location.host}/api/emails/{emailId}/share \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
{t("docs.deleteEmailShare")}
                          {`curl -X DELETE ${window.location.protocol}//${window.location.host}/api/emails/{emailId}/share/{shareId} \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
{t("docs.createMessageShare")}
                          {`curl -X POST ${window.location.protocol}//${window.location.host}/api/emails/{emailId}/messages/{messageId}/share \\
  -H "X-API-Key: YOUR_API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"expiresIn": 0}'`}
                        
{t("docs.getMessageShares")}
                          {`curl ${window.location.protocol}//${window.location.host}/api/emails/{emailId}/messages/{messageId}/share \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
{t("docs.deleteMessageShare")}
                          {`curl -X DELETE ${window.location.protocol}//${window.location.host}/api/emails/{emailId}/messages/{messageId}/share/{shareId} \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        

{t("docs.notes")}

  • {t("docs.note1")}
  • {t("docs.note2")}
  • {t("docs.note3")}
  • {t("docs.note4")}
  • {t("docs.note5")}
  • {t("docs.note6")}
  • {t("docs.note7")}
  • {t("docs.note8")}
  • {t("docs.note9")}
  • {t("docs.note10")}
)}
)}
) }
) }