Skip to main content
Glama

Karakeep MCP server

by karakeep-app
InviteAcceptForm.tsx9.27 kB
"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { ActionButton } from "@/components/ui/action-button"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { api } from "@/lib/trpc"; import { zodResolver } from "@hookform/resolvers/zod"; import { TRPCClientError } from "@trpc/client"; import { AlertCircle, Clock, Loader2, Mail, UserPlus } from "lucide-react"; import { signIn } from "next-auth/react"; import { useForm } from "react-hook-form"; import { z } from "zod"; const inviteAcceptSchema = z .object({ name: z.string().min(1, "Name is required"), password: z.string().min(8, "Password must be at least 8 characters"), confirmPassword: z .string() .min(8, "Password must be at least 8 characters"), }) .refine((data) => data.password === data.confirmPassword, { message: "Passwords don't match", path: ["confirmPassword"], }); interface InviteAcceptFormProps { token: string; } export default function InviteAcceptForm({ token }: InviteAcceptFormProps) { const router = useRouter(); const form = useForm<z.infer<typeof inviteAcceptSchema>>({ resolver: zodResolver(inviteAcceptSchema), }); const [errorMessage, setErrorMessage] = useState<string | null>(null); const { isPending: loading, data: inviteData, error, } = api.invites.get.useQuery({ token }); useEffect(() => { if (error) { setErrorMessage(error.message); } }, [error]); const acceptInviteMutation = api.invites.accept.useMutation(); const handleBackToSignIn = () => { router.push("/signin"); }; if (loading) { return ( <Card className="w-full"> <CardHeader className="text-center"> <CardTitle className="text-2xl font-bold"> Loading Invitation </CardTitle> <CardDescription> Please wait while we verify your invitation... </CardDescription> </CardHeader> <CardContent className="space-y-4"> <div className="flex items-center justify-center"> <Loader2 className="h-8 w-8 animate-spin text-blue-600" /> </div> </CardContent> </Card> ); } if (!inviteData) { return ( <Card className="w-full"> <CardHeader className="text-center"> <CardTitle className="text-2xl font-bold"> Invalid Invitation </CardTitle> <CardDescription> This invitation link is not valid or has been removed. </CardDescription> </CardHeader> <CardContent className="space-y-4"> <div className="flex items-center justify-center"> <AlertCircle className="h-12 w-12 text-red-500" /> </div> {errorMessage && ( <Alert variant="destructive"> <AlertCircle className="h-4 w-4" /> <AlertDescription>{errorMessage}</AlertDescription> </Alert> )} <Button onClick={handleBackToSignIn} className="w-full"> Back to Sign In </Button> </CardContent> </Card> ); } if (inviteData.expired) { return ( <Card className="w-full"> <CardHeader className="text-center"> <CardTitle className="text-2xl font-bold"> Invitation Expired </CardTitle> <CardDescription> This invitation link has expired and is no longer valid. </CardDescription> </CardHeader> <CardContent className="space-y-4"> <div className="flex items-center justify-center"> <Clock className="h-12 w-12 text-orange-500" /> </div> <div className="space-y-2 text-center"> <p className="text-sm text-gray-600"> Please contact an administrator to request a new invitation. </p> </div> <Button onClick={handleBackToSignIn} variant="outline" className="w-full" > Back to Sign In </Button> </CardContent> </Card> ); } return ( <Card className="w-full"> <CardHeader className="text-center"> <CardTitle className="text-2xl font-bold"> Accept Your Invitation </CardTitle> <CardDescription> Complete your account setup to join Karakeep </CardDescription> </CardHeader> <CardContent className="space-y-6"> <div className="flex items-center justify-center"> <UserPlus className="h-12 w-12 text-blue-600" /> </div> <div className="space-y-2 text-center"> <div className="flex items-center justify-center space-x-2"> <Mail className="h-4 w-4 text-gray-500" /> <p className="text-sm text-gray-600">Invited email:</p> </div> <p className="font-medium text-gray-900">{inviteData.email}</p> </div> <Form {...form}> <form onSubmit={form.handleSubmit(async (value) => { try { await acceptInviteMutation.mutateAsync({ token, name: value.name, password: value.password, }); // Sign in the user after successful account creation const resp = await signIn("credentials", { redirect: false, email: inviteData.email, password: value.password, }); if (!resp || !resp.ok || resp.error) { setErrorMessage( resp?.error ?? "Account created but sign in failed. Please try signing in manually.", ); return; } router.replace("/"); } catch (e) { if (e instanceof TRPCClientError) { setErrorMessage(e.message); } else { setErrorMessage("An unexpected error occurred"); } } })} className="space-y-4" > {errorMessage && ( <Alert variant="destructive"> <AlertCircle className="h-4 w-4" /> <AlertDescription>{errorMessage}</AlertDescription> </Alert> )} <FormField control={form.control} name="name" render={({ field }) => ( <FormItem> <FormLabel>Full Name</FormLabel> <FormControl> <Input type="text" placeholder="Enter your full name" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="password" render={({ field }) => ( <FormItem> <FormLabel>Password</FormLabel> <FormControl> <Input type="password" placeholder="Create a password" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="confirmPassword" render={({ field }) => ( <FormItem> <FormLabel>Confirm Password</FormLabel> <FormControl> <Input type="password" placeholder="Confirm your password" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <ActionButton type="submit" loading={ form.formState.isSubmitting || acceptInviteMutation.isPending } className="w-full" > {form.formState.isSubmitting || acceptInviteMutation.isPending ? ( <> <Loader2 className="mr-2 h-4 w-4 animate-spin" /> Creating Account... </> ) : ( "Create Account & Sign In" )} </ActionButton> <Button type="button" variant="ghost" onClick={handleBackToSignIn} className="w-full" > Back to Sign In </Button> </form> </Form> </CardContent> </Card> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/karakeep-app/karakeep'

If you have feedback or need assistance with the MCP directory API, please join our Discord server