diff --git a/components.json b/components.json
new file mode 100644
index 0000000..329d3e5
--- /dev/null
+++ b/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.js",
+ "css": "styles/globals.css",
+ "baseColor": "slate",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
\ No newline at end of file
diff --git a/lib/utils.ts b/lib/utils.ts
new file mode 100644
index 0000000..bd0c391
--- /dev/null
+++ b/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/package.json b/package.json
index c58a454..0235806 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,22 @@
"@dagrejs/dagre": "^1.1.4",
"@internationalized/date": "^3.7.0",
"@mistralai/mistralai": "^1.5.0",
+ "@radix-ui/react-alert-dialog": "^1.1.6",
+ "@radix-ui/react-avatar": "^1.1.3",
+ "@radix-ui/react-collapsible": "^1.1.3",
+ "@radix-ui/react-context-menu": "^2.2.6",
+ "@radix-ui/react-dialog": "^1.1.6",
+ "@radix-ui/react-dropdown-menu": "^2.1.6",
"@radix-ui/react-icons": "^1.3.2",
+ "@radix-ui/react-label": "^2.1.2",
+ "@radix-ui/react-popover": "^1.1.6",
+ "@radix-ui/react-scroll-area": "^1.2.3",
+ "@radix-ui/react-select": "^2.1.6",
+ "@radix-ui/react-separator": "^1.1.2",
+ "@radix-ui/react-slot": "^1.1.2",
+ "@radix-ui/react-switch": "^1.1.3",
+ "@radix-ui/react-tabs": "^1.1.3",
+ "@radix-ui/react-tooltip": "^1.1.8",
"@radix-ui/themes": "^3.2.0",
"@react-aria/ssr": "3.9.7",
"@react-aria/visually-hidden": "3.8.18",
@@ -25,16 +40,18 @@
"@tailwindcss/postcss": "^4.0.3",
"@xyflow/react": "^12.4.2",
"ai": "^4.1.34",
- "clsx": "2.1.1",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
"d3-force": "^3.0.0",
"d3-quadtree": "^3.0.1",
"framer-motion": "^12.3.1",
"intl-messageformat": "^10.5.0",
"lodash.debounce": "^4.0.8",
- "lucide-react": "^0.474.0",
+ "lucide-react": "^0.475.0",
"next": "15.1.6",
"next-themes": "^0.4.4",
"nextjs-toploader": "^3.7.15",
+ "popover": "^2.4.1",
"postcss": "^8.5.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
@@ -42,7 +59,9 @@
"react-markdown": "^9.0.3",
"react-resizable-panels": "^2.1.7",
"swr": "^2.3.0",
+ "tailwind-merge": "^3.0.1",
"tailwindcss": "^4.0.3",
+ "tailwindcss-animate": "^1.0.7",
"usehooks-ts": "^3.1.1",
"vaul": "^1.1.2",
"zod": "^3.24.1"
diff --git a/src/app/auth/callback/route.ts b/src/app/auth/callback/route.ts
index 1dea95e..af11e00 100644
--- a/src/app/auth/callback/route.ts
+++ b/src/app/auth/callback/route.ts
@@ -1,6 +1,6 @@
import { NextResponse } from 'next/server'
// The client you created from the Server-Side Auth instructions
-import { createClient } from '@/src/lib/supabase/server'
+import { createClient } from '@/lib/supabase/server'
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
diff --git a/src/app/auth/confirm/route.ts b/src/app/auth/confirm/route.ts
index db1c675..4a46dca 100644
--- a/src/app/auth/confirm/route.ts
+++ b/src/app/auth/confirm/route.ts
@@ -1,7 +1,7 @@
import { type EmailOtpType } from '@supabase/supabase-js'
import { type NextRequest } from 'next/server'
-import { createClient } from '@/src/lib/supabase/server'
+import { createClient } from '@/lib/supabase/server'
import { redirect } from 'next/navigation'
export async function GET(request: NextRequest) {
diff --git a/src/app/dashboard/keys/page.tsx b/src/app/dashboard/keys/page.tsx
index 14d0ce3..fbac352 100644
--- a/src/app/dashboard/keys/page.tsx
+++ b/src/app/dashboard/keys/page.tsx
@@ -1,121 +1,9 @@
-import { Button, Card, IconButton, Separator, Table, Tabs } from "@radix-ui/themes"
-import { Trash2 } from 'lucide-react'
+import React from 'react'
-export default function APIKeys() {
- return (
-
-
-
-
-
-
Vos clés API
-
- Gérez vos clés API personnelles pour votre espace de travail.
-
-
-
-
-
-
- Vous pouvez créer jusqu'à 10 clés API et les supprimer lorsque vous n'en avez plus besoin.
-
-
-
-
-
- Actif
-
-
- Expiré
-
-
-
-
-
-
-
- Nom
- Clé
- Date d'expiration
-
-
-
-
-
- clé d'essai
- ************************pnA5
- 15 février 2025
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Vos clés de services tiers
-
- Gérez vos clés API de services tiers pour votre espace de travail.
-
-
-
-
-
-
-
-
- Actif
-
-
- Expiré
-
-
-
-
-
-
-
- Nom
- Clé
- Date d'expiration
-
-
-
-
-
- clé d'essai
- ************************pnA5
- 15 février 2025
-
-
-
-
-
-
-
-
-
-
-
- )
+const page = () => {
+ return (
+ keys
+ )
}
+
+export default page
\ No newline at end of file
diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx
deleted file mode 100644
index e565855..0000000
--- a/src/app/dashboard/layout.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import type React from "react"
-import { createClient } from "@/src/lib/supabase/server"
-import { redirect } from "next/navigation"
-import Logo from "@/src/components/logo"
-import { Box, Flex, ScrollArea, TextField, Text, IconButton } from "@radix-ui/themes"
-import NewCase from "@/src/components/dashboard/new-case"
-import { MagnifyingGlassIcon } from "@radix-ui/react-icons"
-import User from "@/src/components/user"
-import Link from "next/link"
-import { PlusIcon } from 'lucide-react';
-
-const navigation = [
- {
- name: "Dashboard",
- children: [
- {
- name: "Your investigations",
- href: "/dashboard",
- },
- ],
- },
- {
- name: "Configuration",
- children: [
- {
- name: "Settings",
- href: "/dashboard/settings",
- },
- {
- name: "API keys",
- href: "/dashboard/keys",
- },
- ],
- },
-]
-
-const DashboardLayout = async ({
- children,
-}: {
- children: React.ReactNode
-}) => {
- const supabase = await createClient()
- const { data, error } = await supabase.auth.getUser()
- if (error || !data?.user) {
- redirect("/login")
- }
-
- return (
-
- {/* Left Panel */}
-
- {/* Left Panel Header */}
-
-
-
-
-
-
-
-
-
- {/* Left Panel Content */}
-
-
- {navigation.map((nav, i) => (
-
-
- {nav.name}
-
-
- {nav?.children?.map((child, j) => (
-
-
- {child.name}
-
-
- ))}
-
-
- ))}
-
-
-
-
- {/* Main Content */}
-
- {/* Top Navigation */}
-
-
-
-
-
-
-
-
-
- {/* Main Content Area */}
-
- {children}
-
-
-
- )
-}
-
-export default DashboardLayout
\ No newline at end of file
diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx
index f63a8aa..23034ab 100644
--- a/src/app/dashboard/page.tsx
+++ b/src/app/dashboard/page.tsx
@@ -1,33 +1,52 @@
-import React from 'react'
-import { getInvestigations } from '@/src/lib/actions/investigations'
-import Investigation from '@/src/components/dashboard/investigation'
-import { Button, Flex } from '@radix-ui/themes'
-import { DownloadIcon, FolderIcon, PlusIcon } from 'lucide-react'
-import NewCase from '@/src/components/dashboard/new-case'
+import { AppSidebar } from "@/components/app-sidebar"
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+} from "@/components/ui/breadcrumb"
+import { Separator } from "@/components/ui/separator"
+import {
+ SidebarInset,
+ SidebarProvider,
+ SidebarTrigger,
+} from "@/components/ui/sidebar"
-const DashboardPage = async () => {
- const { investigations, error } = await getInvestigations()
- if (error) return An error occured.
- return (
-
-
-
Vos investigations
-
- La liste de vos investigations. Vous pouvez également en créer d'autres.
-
-
-
-
-
-
-
-
-
-
{investigations.map((investigation) => (
-
- ))}
-
+export default function Page() {
+ return (
+
+
+
+
+
- )
+
+
+ )
}
-export default DashboardPage
\ No newline at end of file
diff --git a/src/app/investigations/[investigation_id]/individuals.tsx b/src/app/investigations/[investigation_id]/individuals.tsx
index 1bc2c70..360ac83 100644
--- a/src/app/investigations/[investigation_id]/individuals.tsx
+++ b/src/app/investigations/[investigation_id]/individuals.tsx
@@ -1,11 +1,14 @@
"use client"
import React from 'react'
-import { Avatar, Box, Card, Flex, IconButton, Skeleton, Text } from '@radix-ui/themes';
-import { useIndividuals } from '@/src/lib/hooks/individuals/use-individuals';
-import { useInvestigationContext } from '@/src/components/contexts/investigation-provider';
-import { cn } from '@/src/lib/utils';
+import { Skeleton } from '@/components/ui/skeleton';
+import { useIndividuals } from '@/lib/hooks/individuals/use-individuals';
+import { useInvestigationContext } from '@/components/contexts/investigation-provider';
+import { cn } from '@/lib/utils';
import { Pencil1Icon } from '@radix-ui/react-icons';
import { RotateCwIcon } from 'lucide-react';
+import { Button } from '@/components/ui/button';
+import { Card } from '@/components/ui/card';
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
const Filters = ({ investigation_id }: { investigation_id: string }) => {
const { individuals, isLoading, refetch } = useIndividuals(investigation_id)
@@ -13,53 +16,49 @@ const Filters = ({ investigation_id }: { investigation_id: string }) => {
return (
-
Profiles
- refetch()} size="1" variant="ghost" color="gray">
+ Profiles
+
+
+
{isLoading && <>
-
-
-
+
+
+
>
}
{individuals?.map((individual: any) => (
-
- setCurrentNode(individual.id)}>
-
-
-
-
+
+
setCurrentNode(individual.id)}>
+
+
+
+ CN
+
+
+
{individual.full_name}
-
-
+
+
{individual.notes}
-
-
-
-
+
+
+
-
+
))}
-
-
+
+
)
}
diff --git a/src/app/investigations/[investigation_id]/layout.tsx b/src/app/investigations/[investigation_id]/layout.tsx
index 7179816..54846cb 100644
--- a/src/app/investigations/[investigation_id]/layout.tsx
+++ b/src/app/investigations/[investigation_id]/layout.tsx
@@ -1,11 +1,11 @@
-import { InvestigationProvider } from '@/src/components/contexts/investigation-provider';
-import InvestigationLayout from '@/src/components/investigations/layout';
+import { InvestigationProvider } from '@/components/contexts/investigation-provider';
+import InvestigationLayout from '@/components/investigations/layout';
import Individuals from './individuals';
-import { SearchProvider } from '@/src/components/contexts/search-context';
-import { createClient } from "@/src/lib/supabase/server";
+import { SearchProvider } from '@/components/contexts/search-context';
+import { createClient } from "@/lib/supabase/server";
import { notFound, redirect } from "next/navigation";
-import { ChatProvider } from '@/src/components/contexts/chatbot-context';
-import { getInvestigation } from '@/src/lib/actions/investigations';
+import { ChatProvider } from '@/components/contexts/chatbot-context';
+import { getInvestigation } from '@/lib/actions/investigations';
const DashboardLayout = async ({
children,
diff --git a/src/app/investigations/[investigation_id]/loading.tsx b/src/app/investigations/[investigation_id]/loading.tsx
index a1452a1..48e8ea0 100644
--- a/src/app/investigations/[investigation_id]/loading.tsx
+++ b/src/app/investigations/[investigation_id]/loading.tsx
@@ -1,9 +1,8 @@
-import { Spinner } from '@radix-ui/themes'
import React from 'react'
const loading = () => {
return (
-
Loading nodes and edges...
+
Loading nodes and edges...
)
}
diff --git a/src/app/investigations/[investigation_id]/page.tsx b/src/app/investigations/[investigation_id]/page.tsx
index 5629a23..45b7a6b 100644
--- a/src/app/investigations/[investigation_id]/page.tsx
+++ b/src/app/investigations/[investigation_id]/page.tsx
@@ -1,6 +1,6 @@
-import { getInvestigationData } from '@/src/lib/actions/investigations'
-import InvestigationGraph from '@/src/components/investigations/graph'
-import IndividualModal from '@/src/components/investigations/individual-modal'
+import { getInvestigationData } from '@/lib/actions/investigations'
+import InvestigationGraph from '@/components/investigations/graph'
+import IndividualModal from '@/components/investigations/individual-modal'
const DashboardPage = async ({
params,
diff --git a/src/app/investigations/loading.tsx b/src/app/investigations/loading.tsx
index 79604ce..7a28b35 100644
--- a/src/app/investigations/loading.tsx
+++ b/src/app/investigations/loading.tsx
@@ -1,9 +1,8 @@
-import { Spinner } from '@radix-ui/themes'
import React from 'react'
const loading = () => {
return (
-
Loading investigation...
+
Loading investigation...
)
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index c4ae0a2..0eab430 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,14 +1,12 @@
-import "@/styles/globals.css";
+import "../../styles/globals.css";
import { Metadata, Viewport } from "next";
import clsx from "clsx";
-import "@/styles/globals.css"
import { Providers } from "./providers";
-import "@radix-ui/themes/styles.css";
import { siteConfig } from "@/config/site";
import { fontSans } from "@/config/fonts";
-import { Theme } from "@radix-ui/themes";
-import { ConfirmContextProvider } from "@/src/components/use-confirm-dialog";
+import { ConfirmContextProvider } from "@/components/use-confirm-dialog";
import NextTopLoader from 'nextjs-toploader';
+import { TooltipProvider } from "@/components/ui/tooltip";
export const metadata: Metadata = {
title: {
@@ -38,19 +36,19 @@ export default function RootLayout({
-
-
-
+
+
+
{children}
-
-
+
+
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index f531122..67dcbde 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -1,5 +1,5 @@
-import { LoginForm } from "@/src/components/login-form"
-import { createClient } from "@/src/lib/supabase/server"
+import { LoginForm } from "@/components/login-form"
+import { createClient } from "@/lib/supabase/server"
import { redirect } from "next/navigation"
export default async function Page() {
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 61de571..9096e66 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,4 +1,4 @@
-import { Button } from "@radix-ui/themes";
+import { Button } from '@/components/ui/button'
import Link from "next/link";
export default function Home() {
diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx
new file mode 100644
index 0000000..94ad3a0
--- /dev/null
+++ b/src/components/app-sidebar.tsx
@@ -0,0 +1,175 @@
+"use client"
+
+import * as React from "react"
+import {
+ AudioWaveform,
+ BookOpen,
+ Bot,
+ Command,
+ Frame,
+ GalleryVerticalEnd,
+ Map,
+ PieChart,
+ Settings2,
+ SquareTerminal,
+} from "lucide-react"
+
+import { NavMain } from "@/components/nav-main"
+import { NavProjects } from "@/components/nav-projects"
+import { NavUser } from "@/components/nav-user"
+import { TeamSwitcher } from "@/components/team-switcher"
+import {
+ Sidebar,
+ SidebarContent,
+ SidebarFooter,
+ SidebarHeader,
+ SidebarRail,
+} from "@/components/ui/sidebar"
+
+// This is sample data.
+const data = {
+ user: {
+ name: "shadcn",
+ email: "m@example.com",
+ avatar: "/avatars/shadcn.jpg",
+ },
+ teams: [
+ {
+ name: "Acme Inc",
+ logo: GalleryVerticalEnd,
+ plan: "Enterprise",
+ },
+ {
+ name: "Acme Corp.",
+ logo: AudioWaveform,
+ plan: "Startup",
+ },
+ {
+ name: "Evil Corp.",
+ logo: Command,
+ plan: "Free",
+ },
+ ],
+ navMain: [
+ {
+ title: "Playground",
+ url: "#",
+ icon: SquareTerminal,
+ isActive: true,
+ items: [
+ {
+ title: "History",
+ url: "#",
+ },
+ {
+ title: "Starred",
+ url: "#",
+ },
+ {
+ title: "Settings",
+ url: "#",
+ },
+ ],
+ },
+ {
+ title: "Models",
+ url: "#",
+ icon: Bot,
+ items: [
+ {
+ title: "Genesis",
+ url: "#",
+ },
+ {
+ title: "Explorer",
+ url: "#",
+ },
+ {
+ title: "Quantum",
+ url: "#",
+ },
+ ],
+ },
+ {
+ title: "Documentation",
+ url: "#",
+ icon: BookOpen,
+ items: [
+ {
+ title: "Introduction",
+ url: "#",
+ },
+ {
+ title: "Get Started",
+ url: "#",
+ },
+ {
+ title: "Tutorials",
+ url: "#",
+ },
+ {
+ title: "Changelog",
+ url: "#",
+ },
+ ],
+ },
+ {
+ title: "Settings",
+ url: "#",
+ icon: Settings2,
+ items: [
+ {
+ title: "General",
+ url: "#",
+ },
+ {
+ title: "Team",
+ url: "#",
+ },
+ {
+ title: "Billing",
+ url: "#",
+ },
+ {
+ title: "Limits",
+ url: "#",
+ },
+ ],
+ },
+ ],
+ projects: [
+ {
+ name: "Design Engineering",
+ url: "#",
+ icon: Frame,
+ },
+ {
+ name: "Sales & Marketing",
+ url: "#",
+ icon: PieChart,
+ },
+ {
+ name: "Travel",
+ url: "#",
+ icon: Map,
+ },
+ ],
+}
+
+export function AppSidebar({ ...props }: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/contexts/chatbot-context.tsx b/src/components/contexts/chatbot-context.tsx
index ccd94be..54adff8 100644
--- a/src/components/contexts/chatbot-context.tsx
+++ b/src/components/contexts/chatbot-context.tsx
@@ -1,142 +1,152 @@
-'use client';
-
-import { createContext, ReactNode, useContext, useEffect, useState } from 'react';
-import { Avatar, Box, Card, Dialog, Flex, Spinner, Text, TextArea, TextField } from '@radix-ui/themes';
-import { useChat } from '@ai-sdk/react';
-import { BotIcon } from 'lucide-react';
-import { cn } from '@/src/lib/utils';
-import ReactMarkdown from 'react-markdown'
+"use client"
+import type React from "react"
+import { createContext, type ReactNode, useContext, useEffect, useState } from "react"
+import { useChat } from "@ai-sdk/react"
+import { Bot, User } from "lucide-react"
+import { cn } from "@/lib/utils"
+import ReactMarkdown from "react-markdown"
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Avatar, AvatarFallback } from "@/components/ui/avatar"
+import { Card, CardContent } from "@/components/ui/card"
+import { Input } from "@/components/ui/input"
+import { Button } from "@/components/ui/button"
interface ChatContextType {
- open: boolean,
- handleOpenChat: any
+ open: boolean
+ handleOpenChat: (content: any) => void
}
-const ChatContext = createContext(undefined);
+const ChatContext = createContext(undefined)
interface ChatProviderProps {
- children: ReactNode;
+ children: ReactNode
}
export const ChatProvider: React.FC = ({ children }) => {
- const [open, setOpen] = useState(false);
- // content is the object passed to the chat, as a secondary object
- const [context, setContext] = useState(false);
- const { messages, input, handleInputChange, setInput, handleSubmit, error, isLoading } = useChat();
+ const [open, setOpen] = useState(false)
+ const [context, setContext] = useState(null)
+ const { messages, input, handleInputChange, setInput, handleSubmit, error, isLoading } = useChat()
- const handleOpenChat = (content: any) => {
- setContext(content)
- setInput(`What pattern can you extract from this person ?\n ${JSON.stringify(content)}`)
- setOpen(true)
- }
+ const handleOpenChat = (content: any) => {
+ setContext(content)
+ setInput(`What pattern can you extract from this person ?\n ${JSON.stringify(content)}`)
+ setOpen(true)
+ }
- return (
-
- {children}
-
- 0 ? "730px" : '480px'} className="w-full p-4">
- Ask AI
-
- Ask AI chat bot to help you understant patterns.
- {/*
- context: {content?.title || content?.full_name}
-
*/}
-
- {messages.map(m => (
-
-
- : }
- />
-
-
- {isLoading && m.role !== 'user' ? : m.role === 'user' ? 'User' : 'Chatbot'}
-
-
-
-
- {m.content}
-
-
-
-
-
-
- ))}
- {error &&
-
- }
- />
-
-
- {'Error'}
-
-
-
-
- {"Oops, an error occured. Make sure you provided a valid Mistral API key."}
-
-
-
-
-
- }
-
-
-
-
-
- );
+ return (
+
+ {children}
+
+
+ )
}
export const useChatContext = (): ChatContextType => {
- const context = useContext(ChatContext);
- if (!context) {
- throw new Error("useChatContext must be used within a ChatProvider");
- }
- return context;
-};
+ const context = useContext(ChatContext)
+ if (!context) {
+ throw new Error("useChatContext must be used within a ChatProvider")
+ }
+ return context
+}
interface LoadingDotsProps {
- speed?: number
- text?: string
+ speed?: number
+ text?: string
}
const LoadingDots: React.FC = ({ speed = 200, text = "Thinking" }) => {
- const [dots, setDots] = useState("")
+ const [dots, setDots] = useState("")
- useEffect(() => {
- const interval = setInterval(() => {
- setDots((prevDots) => {
- if (prevDots.length >= 3) {
- return ""
- }
- return prevDots + "."
- })
- }, speed)
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setDots((prevDots) => {
+ if (prevDots.length >= 3) {
+ return ""
+ }
+ return prevDots + "."
+ })
+ }, speed)
- return () => clearInterval(interval)
- }, [speed])
+ return () => clearInterval(interval)
+ }, [speed])
+
+ return (
+
+ {text}
+ {dots}
+
+ )
+}
- return (
-
- {text}
- {dots}
-
- )
-}
\ No newline at end of file
diff --git a/src/components/contexts/investigation-provider.tsx b/src/components/contexts/investigation-provider.tsx
index 479885d..61f95dc 100644
--- a/src/components/contexts/investigation-provider.tsx
+++ b/src/components/contexts/investigation-provider.tsx
@@ -1,15 +1,23 @@
"use client"
-import useLocalStorage from "@/src/lib/hooks/use-local-storage";
+import useLocalStorage from "@/lib/hooks/use-local-storage";
import React, { createContext, useContext, ReactNode, useState, useCallback } from "react";
-import { Button, Dialog, Flex, Switch } from "@radix-ui/themes";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogClose,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button";
+import { Switch } from "@/components/ui/switch";
import { useParams, useRouter, usePathname, useSearchParams } from "next/navigation";
-import { Investigation } from "@/src/types/investigation";
-import { useInvestigation } from "@/src/lib/hooks/investigation/investigation";
-import { ThemeSwitch } from "../theme-switch";
-import { useConfirm } from "../use-confirm-dialog";
-import { supabase } from "@/src/lib/supabase/client";
-import FloatingEdge from "../investigations/floating-edge";
-import { cn } from "@/src/lib/utils";
+import { Investigation } from "@/types/investigation";
+import { useInvestigation } from "@/lib/hooks/investigation/investigation";
+import { ThemeSwitch } from "@/components/theme-switch";
+import { useConfirm } from "@/components/use-confirm-dialog";
+import { supabase } from "@/lib/supabase/client";
+// import FloatingEdge from "../investigations/floating-edge";
+import { cn } from "@/lib/utils";
interface InvestigationContextType {
filters: any,
@@ -87,13 +95,13 @@ export const InvestigationProvider: React.FC = ({ ch
return (
{children}
-
-
- Settings
-
+
-
+
+
@@ -109,16 +117,16 @@ export const InvestigationProvider: React.FC = ({ ch
-
-
- setOpenSettingsModal(false)}>
-
);
};
diff --git a/src/components/contexts/node-context.tsx b/src/components/contexts/node-context.tsx
index 0a353b9..94860bf 100644
--- a/src/components/contexts/node-context.tsx
+++ b/src/components/contexts/node-context.tsx
@@ -1,11 +1,20 @@
"use client"
import React, { createContext, useContext, ReactNode, useState, useCallback } from "react";
-import { Button, Callout, Dialog, Flex, Text, TextField } from "@radix-ui/themes";
+import {
+ Dialog,
+ DialogClose,
+ DialogContent,
+ DialogDescription,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Input } from "@/components/ui/input"
+import { Button } from "@/components/ui/button";
import { useParams } from "next/navigation";
-import { supabase } from "@/src/lib/supabase/client";
+import { supabase } from "@/lib/supabase/client";
import { useNodeId, useReactFlow } from "@xyflow/react";
-import { InfoCircledIcon } from "@radix-ui/react-icons";
-import { useConfirm } from "../use-confirm-dialog";
+import { useConfirm } from "@/components/use-confirm-dialog";
+import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
+import { AlertCircle } from "lucide-react";
interface NodeContextType {
setOpenAddNodeModal: any,
@@ -145,22 +154,22 @@ export const NodeProvider: React.FC = (props: any) => {
return (
{props.children}
-
-
- New {nodeType?.type}
-
+
+
-
-
+
+
);
};
diff --git a/src/components/contexts/search-context.tsx b/src/components/contexts/search-context.tsx
index b1cf285..7caada5 100644
--- a/src/components/contexts/search-context.tsx
+++ b/src/components/contexts/search-context.tsx
@@ -1,23 +1,34 @@
"use client"
-import React, { createContext, useContext, ReactNode, useState } from "react";
-import { Button, Callout, Card, Dialog, Flex, Text, TextField } from "@radix-ui/themes";
-import { InfoCircledIcon } from "@radix-ui/react-icons";
-import { investigateValue } from "@/src/lib/actions/search";
-import { useParams } from "next/navigation";
-import Breaches from "../breach";
+import type React from "react"
+import { createContext, useContext, type ReactNode, useState } from "react"
+import { Button } from "@/components/ui/button"
+import { Card } from "@/components/ui/card"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Alert, AlertDescription } from "@/components/ui/alert"
+import { InfoIcon } from "lucide-react"
+import { investigateValue } from "@/lib/actions/search"
+import { useParams } from "next/navigation"
+import Breaches from "../breach"
interface SearchContextType {
- openSearchModal: boolean,
- handleOpenSearchModal: any
+ openSearchModal: boolean
+ handleOpenSearchModal: (val: string) => void
}
-const SearchContext = createContext(undefined);
+const SearchContext = createContext(undefined)
interface SearchProviderProps {
- children: ReactNode;
+ children: ReactNode
}
-export const SearchProvider: React.FC = (props: any) => {
+export const SearchProvider: React.FC = ({ children }) => {
const [openSearchModal, setOpenSearchModal] = useState(false)
const { investigation_id } = useParams()
const [value, setValue] = useState(null)
@@ -31,10 +42,10 @@ export const SearchProvider: React.FC = (props: any) => {
setIsLoading(true)
setError("")
try {
- const data = await investigateValue(investigation_id, value)
+ const data = await investigateValue(investigation_id as string, value)
setResults(data)
} catch (err) {
- setError(err instanceof Error ? err.message : "An error occured.")
+ setError(err instanceof Error ? err.message : "An error occurred.")
} finally {
setIsLoading(false)
}
@@ -53,76 +64,68 @@ export const SearchProvider: React.FC = (props: any) => {
}
return (
-
- {props.children}
-
-
- New search
-
- Make a new keyword associated research.
-
+
+ {children}
+
-
+
+
- );
-};
+ )
+}
export const useSearchContext = (): SearchContextType => {
- const context = useContext(SearchContext);
+ const context = useContext(SearchContext)
if (!context) {
- throw new Error("useSearchContext must be used within a SearchProvider");
+ throw new Error("useSearchContext must be used within a SearchProvider")
}
- return context;
-};
\ No newline at end of file
+ return context
+}
+
diff --git a/src/components/copy.tsx b/src/components/copy.tsx
index 56228e7..818e5f1 100644
--- a/src/components/copy.tsx
+++ b/src/components/copy.tsx
@@ -1,16 +1,18 @@
"use client"
import { useState, useCallback } from "react"
-import { IconButton, Tooltip } from "@radix-ui/themes"
import { Copy } from "lucide-react"
import { useTimeout } from "usehooks-ts"
+import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"
+import { Button } from "./ui/button"
interface CopyButtonProps {
content: string
delay?: number
+ className?: string
}
-export function CopyButton({ content, delay = 2000 }: CopyButtonProps) {
+export function CopyButton({ content, className, delay = 2000 }: CopyButtonProps) {
const [isCopied, setIsCopied] = useState(false)
const handleCopy = useCallback((e: { stopPropagation: () => void }) => {
@@ -30,10 +32,15 @@ export function CopyButton({ content, delay = 2000 }: CopyButtonProps) {
)
return (
-
-
-
-
+
+
+
+
+
+
+
+ Copied !
+
)
}
diff --git a/src/components/dashboard/investigation.tsx b/src/components/dashboard/investigation.tsx
index 7e8d644..e526fc4 100644
--- a/src/components/dashboard/investigation.tsx
+++ b/src/components/dashboard/investigation.tsx
@@ -1,37 +1,35 @@
"use client"
import React from 'react'
-import { Investigation } from '@/src/types/investigation';
+import { Investigation } from '@/types/investigation';
import Link from 'next/link';
-import { Box, Card, Inset, Text } from '@radix-ui/themes';
import Image from 'next/image';
+import { Card } from '../ui/card';
const investigation = ({ investigation }: { investigation: Investigation }) => {
return (
-
+
-
-
-
-
+
+
+
+
+
+
+ {investigation.title}
-
-
- {investigation.title}
-
-
- {investigation.description || No description provided.}
-
+
+ {investigation.description || No description provided.}
-
+
-
+
)
}
diff --git a/src/components/dashboard/new-case.tsx b/src/components/dashboard/new-case.tsx
index 53b6011..6ee621b 100644
--- a/src/components/dashboard/new-case.tsx
+++ b/src/components/dashboard/new-case.tsx
@@ -1,79 +1,91 @@
"use client"
-import { DropdownMenu, Button, Dialog, Flex, TextField, Text, Badge, Box } from "@radix-ui/themes";
-import { useState } from "react";
-import { supabase } from '@/src/lib/supabase/client';
-import { useRouter } from "next/navigation";
+import { useState } from "react"
+import { useRouter } from "next/navigation"
+import { supabase } from "@/lib/supabase/client"
+import { Button } from "@/components/ui/button"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Badge } from "@/components/ui/badge"
export default function NewCase({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(false)
const router = useRouter()
- async function handleNewCase(e: { preventDefault: () => void; currentTarget: HTMLFormElement | undefined; }) {
- e.preventDefault();
- const data = Object.fromEntries(new FormData(e.currentTarget))
- const investigation = await supabase.from("investigations").insert(data).select("id")
- .single()
- .then(({ data, error }) => {
- if (error)
- throw error
- return data
- })
- if (investigation)
- router.push(`/investigations/${investigation.id}`)
- setOpen(false)
+ async function handleNewCase(e: React.FormEvent
) {
+ e.preventDefault()
+ const formData = new FormData(e.currentTarget)
+ const data = Object.fromEntries(formData)
+
+ try {
+ const { data: investigation, error } = await supabase.from("investigations").insert(data).select("id").single()
+
+ if (error) throw error
+ if (investigation) router.push(`/investigations/${investigation.id}`)
+ setOpen(false)
+ } catch (error) {
+ console.error("Error creating new case:", error)
+ // Handle error (e.g., show error message to user)
+ }
}
+
return (
<>
-
-
- {children}
-
-
- setOpen(true)} shortcut="⌘ E">New case
- New organization Soon
-
-
-
-
+
+ {children}
+
+ setOpen(true)}>
+ New case
+ ⌘ E
+
+
+ New organization
+
+ Soon
+
+ ⌘ D
+
+
+
+
-
+
+
>
- );
+ )
}
+
diff --git a/src/components/dashboard/search-palette.tsx b/src/components/dashboard/search-palette.tsx
index 458d289..1edace3 100644
--- a/src/components/dashboard/search-palette.tsx
+++ b/src/components/dashboard/search-palette.tsx
@@ -1,15 +1,18 @@
"use client"
+
import { useState, useCallback, useEffect, SetStateAction } from 'react'
// @ts-ignore
-import debounce from "lodash.debounce";
-import { SearchIcon } from "lucide-react"
+import debounce from "lodash.debounce"
+import { Search } from 'lucide-react'
// @ts-ignore
-import Highlighter from "react-highlight-words";
-import Link from 'next/link';
-import { useSearchResults } from '../../lib/hooks/investigation/use-search-results';
-import { Card, Dialog, Flex, IconButton, ScrollArea, Spinner, TextField } from '@radix-ui/themes';
-import { MagnifyingGlassIcon } from '@radix-ui/react-icons';
-import { useInvestigationContext } from '../contexts/investigation-provider';
+import Highlighter from "react-highlight-words"
+import { useSearchResults } from '../../lib/hooks/investigation/use-search-results'
+import { useInvestigationContext } from '../contexts/investigation-provider'
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Input } from "@/components/ui/input"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent } from "@/components/ui/card"
+import { ScrollArea } from "@/components/ui/scroll-area"
const SearchModal = ({ investigation_id }: { investigation_id: string }) => {
const [search, setSearch] = useState("")
@@ -20,113 +23,95 @@ const SearchModal = ({ investigation_id }: { investigation_id: string }) => {
error,
isLoading,
refetch,
- } = useSearchResults(search, investigation_id);
+ } = useSearchResults(search, investigation_id)
- const changeHandler = (event: { target: { value: SetStateAction; }; }) => {
- setSearch(event.target.value);
- refetch && refetch();
- };
- const debouncedChangeHandler = useCallback(debounce(changeHandler, 300), []);
+ const changeHandler = (event: { target: { value: SetStateAction } }) => {
+ setSearch(event.target.value)
+ refetch && refetch()
+ }
+ const debouncedChangeHandler = useCallback(debounce(changeHandler, 300), [])
const handleClose = () => {
- () => setSearch('')
+ setSearch('')
setOpen(false)
}
useEffect(() => {
- const handleKeyPress = (event: { ctrlKey: any; key: string; }) => {
+ const handleKeyPress = (event: KeyboardEvent) => {
if (event.ctrlKey && event.key === 'k') {
setOpen(true)
}
- };
- window.addEventListener('keydown', handleKeyPress);
+ }
+ window.addEventListener('keydown', handleKeyPress)
return () => {
- window.removeEventListener('keydown', handleKeyPress);
- };
- }, []);
+ window.removeEventListener('keydown', handleKeyPress)
+ }
+ }, [])
- const SearchItem = ({ item }: any) =>
- ( setOpen(false)}>
- setCurrentNode(item.id)}>
-
- Individual
-
-
-
-
-
-
-
-
- {/*
-
- */}
-
-
-
+ const SearchItem = ({ item }: any) => (
+ setOpen(false)}>
+ setCurrentNode(item.id)}>
+
+
+
Individual
+
+
+
+
+
+
+
+
+
+
+
+
)
+
return (
<>
-
-
- setOpen(true)} color="gray" size="2" variant="soft">
-
-
-
- Search
-
- Find the profile you're looking for.
-
-
-
-
-
-
-
-
- {error && "An error occured."}
- {isLoading &&
}
- {results?.length === 0 && `No results found for "${search}".`}
-
-
-
+
);
};
@@ -370,7 +383,7 @@ export default function (props: any) {
}, [])
if (!mounted) {
- return
+ return
Loading...
}
return (
diff --git a/src/components/investigations/individual-modal.tsx b/src/components/investigations/individual-modal.tsx
index 9ab8a0d..3ec77eb 100644
--- a/src/components/investigations/individual-modal.tsx
+++ b/src/components/investigations/individual-modal.tsx
@@ -1,32 +1,23 @@
"use client"
import type React from "react"
import { useEffect, useState } from "react"
-import {
- Flex,
- Dialog,
- TextField,
- Button,
- Box,
- Skeleton,
- Avatar,
- Tabs,
- IconButton,
- Text,
- Spinner,
- Badge,
- Grid,
- Link,
- Callout,
-} from "@radix-ui/themes"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
-import { useIndividual } from "@/src/lib/hooks/individuals/use-individual"
-import { useEmailsAndBreaches } from "@/src/lib/hooks/individuals/use-emails-breaches"
-import { Pencil1Icon, Cross2Icon, PlusIcon, TrashIcon } from "@radix-ui/react-icons"
-import { useRelations } from "@/src/lib/hooks/individuals/use-relations"
+import { useIndividual } from "@/lib/hooks/individuals/use-individual"
+import { useEmailsAndBreaches } from "@/lib/hooks/individuals/use-emails-breaches"
+import { useRelations } from "@/lib/hooks/individuals/use-relations"
import { useInvestigationContext } from "../contexts/investigation-provider"
-import { usePlatformIcons } from "@/src/lib/hooks/use-platform-icons"
+import { usePlatformIcons } from "@/lib/hooks/use-platform-icons"
+import { supabase } from "@/lib/supabase/client"
+import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogTitle } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Badge } from "@/components/ui/badge"
+import { Alert, AlertDescription } from "@/components/ui/alert"
+import { Card, CardContent } from "@/components/ui/card"
+import { Pencil, X, Plus, Trash2 } from "lucide-react"
import Breaches from "../breach"
-import { supabase } from "@/src/lib/supabase/client"
const IndividualModal = () => {
const router = useRouter()
@@ -39,7 +30,7 @@ const IndividualModal = () => {
const platformsIcons = usePlatformIcons("medium")
const { relations, isLoading: isLoadingRelations } = useRelations(individual_id)
const [editMode, setEditMode] = useState(false)
- const [image, setImage] = useState
('')
+ const [image, setImage] = useState("")
const [phones, setPhones] = useState([""])
const [accounts, setAccounts] = useState([""])
const [ips, setIps] = useState([""])
@@ -60,7 +51,12 @@ const IndividualModal = () => {
event.preventDefault()
const formData = new FormData(event.currentTarget)
const formContent = Object.fromEntries(formData.entries())
- const { data } = await supabase.from("individuals").update({ ...formContent, birth_date: null }).eq("id", individual_id).select("image_url").single()
+ const { data } = await supabase
+ .from("individuals")
+ .update({ ...formContent, birth_date: null })
+ .eq("id", individual_id)
+ .select("image_url")
+ .single()
setImage(data?.image_url)
setEditMode(false)
}
@@ -80,229 +76,292 @@ const IndividualModal = () => {
if (!isLoading && !individual) {
return (
-
-
- No data
-
- No data found for this individual.
-
-
-
+
-
-
+
+
+
)
}
return (
-
-
-
-