Error Handling

Made some error handling on some routes to prevent empty strings to be passed to the DB function.
This commit is contained in:
Nixyi 2024-12-13 09:16:04 -03:00
parent 1fc0d20e22
commit eef9803249
7 changed files with 70 additions and 90 deletions

View file

@ -8,7 +8,7 @@ export async function POST(request: Request) {
const supabase = await createClient() const supabase = await createClient()
const domain = process.env.DOMAIN; const domain = process.env.DOMAIN;
console.log(domain)
if (!domain) { if (!domain) {
return NextResponse.json({ return NextResponse.json({
error: "Server is misconfigured, please check env variables and try again." error: "Server is misconfigured, please check env variables and try again."

View file

@ -6,9 +6,20 @@ export async function POST(request: Request) {
const supabase = await createClient() const supabase = await createClient()
try { try {
const domain = process.env.DOMAIN;
if (!domain) {
return NextResponse.json({
error: "Server is misconfigured, please check env variables and try again."
},
{
status: 500
})
}
// First create the auth user // First create the auth user
const {data: {user}, error: authError} = await supabase.auth.signUp({ const {data: {user}, error: authError} = await supabase.auth.signUp({
email: `${username}@${process.env.DOMAIN}`, // Using username as email email: `${username}@${domain}`, // Using username as email
password: password, password: password,
}) })

View file

@ -1,74 +0,0 @@
// app/api/realtime/route.ts
import {createClient} from '@/lib/supabase/server'
export async function GET(request: Request) {
const supabase = await createClient()
console.log("Updated")
// Get the current authenticated user
const {data: {user}, error: userError} = await supabase.auth.getUser()
// If any of these, return a default error.
if (userError || !user) {
return new Response('Unauthorized', {status: 401})
}
// Start the stream of data
const stream = new TransformStream()
const writer = stream.writable.getWriter()
const encoder = new TextEncoder()
// Create the channel
let channel: ReturnType<typeof supabase.channel> | null = null
try {
// RealTime supabase!
channel = supabase
.channel('user-requests')
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'users',
filter: `uuid=eq.${user.id}`,
},
async (payload) => {
if (payload.new.requests !== payload.old.requests) {
try {
const data = encoder.encode(`data: ${JSON.stringify({
type: 'requests_update',
data: payload.new.requests
})}\n\n`)
await writer.write(data)
} catch (error) {
console.error('Error writing to stream:', error)
}
}
}
)
.subscribe()
const initialData = encoder.encode(`data: ${JSON.stringify({
type: 'connected',
message: 'SSE connection established'
})}\n\n`)
await writer.write(initialData)
request.signal.addEventListener('abort', () => {
channel?.unsubscribe()
writer.close()
})
} catch (error) {
console.error('Error in SSE setup:', error)
return new Response('Error setting up SSE', {status: 500})
}
return new Response(stream.readable, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
})
}

View file

@ -45,7 +45,12 @@ export async function POST(request: Request) {
return NextResponse.json({user: null}, {status: 401}); return NextResponse.json({user: null}, {status: 401});
} }
const userSuuid = (await getUserByUUID(supabase, user.id)).suuid; const getUser = await getUserByUUID(supabase, user.id)
const userSuuid = getUser.suuid;
if (userSuuid === searchTerm) {
return NextResponse.json({success: false, hint: "Used self SUUID"}, {status: 409});
}
const result = await updateUserRequests(searchTerm, userSuuid, supabase); const result = await updateUserRequests(searchTerm, userSuuid, supabase);

View file

@ -58,7 +58,6 @@ export default async function RootLayout(
<div className={`max-h-[1080px] p-6 bg-secondary`}> <div className={`max-h-[1080px] p-6 bg-secondary`}>
<div className="flex bg-background"> <div className="flex bg-background">
<Sidebar> <Sidebar>
<RealtimeRequests/>
{children} {children}
</Sidebar> </Sidebar>
</div> </div>

View file

@ -1,12 +1,20 @@
// components/RealtimeRequests.tsx // components/RealtimeRequests.tsx
'use client' 'use client'
import {useEffect} from 'react' import {Dispatch, SetStateAction, useEffect} from 'react'
import {useToast} from "@/hooks/use-toast" import {useToast} from "@/hooks/use-toast"
import {useUser} from "@/contexts/user" import {useUser} from "@/contexts/user"
import {createBrowserClient} from "@/lib/supabase/browser"; import {createBrowserClient} from "@/lib/supabase/browser";
export function RealtimeRequests() { interface RealtimeRequests {
setRequests: Dispatch<SetStateAction<string[]>>
}
export function RealtimeRequests(
{
setRequests,
}: RealtimeRequests
) {
const {toast} = useToast() const {toast} = useToast()
const {user, updateUser} = useUser() const {user, updateUser} = useUser()
@ -19,7 +27,13 @@ export function RealtimeRequests() {
table: 'users', table: 'users',
filter: `uuid=eq.${user.uuid}`, filter: `uuid=eq.${user.uuid}`,
}, async (payload) => { }, async (payload) => {
console.log(payload) if (payload.new.requests !== payload.old.requests) {
try {
setRequests(payload.new.requests)
} catch (error) {
console.error('Error writing to stream:', error)
}
}
}).subscribe() }).subscribe()
}, []) }, [])

View file

@ -3,7 +3,7 @@ import React, {useCallback, useEffect, useState} from "react"
import {usePathname} from "next/navigation" import {usePathname} from "next/navigation"
import Link from "next/link" import Link from "next/link"
import {AnimatePresence, motion} from "framer-motion" import {AnimatePresence, motion} from "framer-motion"
import {LogOut, Mail, MailPlus, X} from "lucide-react" import {Check, LogOut, Mail, MailPlus, X} from "lucide-react"
import {Button} from "@/components/ui/button" import {Button} from "@/components/ui/button"
import {Avatar, AvatarFallback} from "@/components/ui/avatar" import {Avatar, AvatarFallback} from "@/components/ui/avatar"
import {Separator} from "@/components/ui/separator" import {Separator} from "@/components/ui/separator"
@ -17,6 +17,7 @@ import {useToast} from "@/hooks/use-toast";
import {useTheme} from "next-themes"; import {useTheme} from "next-themes";
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip"; import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
import {DropdownMenu, DropdownMenuContent, DropdownMenuTrigger} from "@/components/ui/dropdown-menu"; import {DropdownMenu, DropdownMenuContent, DropdownMenuTrigger} from "@/components/ui/dropdown-menu";
import {RealtimeRequests} from "@/components/main/realtime/request";
type SidebarProps = { type SidebarProps = {
children?: React.ReactNode children?: React.ReactNode
@ -33,24 +34,30 @@ function Sidebar(
const [threads, setThreads] = useState<SiPher.Messages[] | []>([]); const [threads, setThreads] = useState<SiPher.Messages[] | []>([]);
const [threadMenu, setThreadMenu] = useState<SiPher.Messages[] | []>([]); const [threadMenu, setThreadMenu] = useState<SiPher.Messages[] | []>([]);
const [copied, setCopied] = useState<boolean>(false); const [copied, setCopied] = useState<boolean>(false);
const {theme, systemTheme} = useTheme() const {theme, systemTheme} = useTheme();
const {toast} = useToast(); const {toast} = useToast();
const {isDrawerOpen, setIsDrawerOpen} = useUIState() const {isDrawerOpen, setIsDrawerOpen} = useUIState();
const {drawerRef} = useRefs(); const {drawerRef} = useRefs();
const [requests, setRequests] = useState<string[]>([]);
const [pendingRequest, setPendingRequest] = useState<number>(0); const [pendingRequest, setPendingRequest] = useState<number>(0);
const {user, getUser} = useUser() const {user, getUser} = useUser();
const { const {
username, username,
suuid suuid
} = user } = user;
useEffect(() => { useEffect(() => {
setPendingRequest(user.requests?.length || 0); setPendingRequest(requests.length || 0);
}, [user]) }, [requests, setPendingRequest]);
useEffect(() => {
setPendingRequest(user.requests.length);
setRequests(user.requests);
}, []);
useEffect(() => { useEffect(() => {
const getThreads = async () => { const getThreads = async () => {
@ -149,10 +156,27 @@ function Sidebar(
</div> </div>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="px-4 py-1 w-56" side={"right"}> <DropdownMenuContent className="px-4 py-1 w-56" side={"right"}>
<div className={"flex flex-row w-full justify-between items-center select-none"}>
<p>User</p>
<p>Decline | Accept</p>
</div>
{ {
pendingRequest > 0 && user.requests.map((request, item) => { pendingRequest > 0 && requests.map((request, item) => {
return ( return (
<p key={request}>{request}</p> <div key={item} className={"flex flex-col w-full"}>
<Separator className="my-2"/>
<div key={item} className={"flex flex-row space-x-2 w-full items-center"}>
<p className={"text-secondary-foreground"}>{request}</p>
<div className={"flex flex-row justify-end space-x-1 w-full"}>
<Button size={"icon"} className={"bg-red-500"}>
<X className={"w-4 h-4"}/>
</Button>
<Button size={"icon"} className={"bg-green-500"}>
<Check className={"w-4 h-4"}/>
</Button>
</div>
</div>
</div>
) )
}) || ( }) || (
<p>Nothing new here</p> <p>Nothing new here</p>
@ -210,6 +234,7 @@ function Sidebar(
return ( return (
<> <>
<MobileHeader/> <MobileHeader/>
<RealtimeRequests setRequests={setRequests}/>
<aside <aside
className={`hidden lg:flex flex-col items-end h-screen max-h-[900px] sticky top-0 border-r border-border ${ className={`hidden lg:flex flex-col items-end h-screen max-h-[900px] sticky top-0 border-r border-border ${
isDarkMode ? "bg-background" : "white" isDarkMode ? "bg-background" : "white"