mirror of
https://github.com/reconurge/flowsint.git
synced 2026-03-12 01:44:42 -05:00
feat: custom node card
This commit is contained in:
@@ -63,7 +63,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className={cn("flex flex-col gap-1 w-full items-start")}>
|
||||
<Card className="bg-transparent border-0">
|
||||
<Card className="bg-transparent shadow-none border-0">
|
||||
<CardContent className="p-0">
|
||||
<ReactMarkdown>{m.content}</ReactMarkdown>
|
||||
</CardContent>
|
||||
@@ -82,7 +82,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
||||
</Avatar>
|
||||
<div className="flex flex-col gap-1 items-start w-full">
|
||||
<span className="text-sm font-bold text-red-500">Error</span>
|
||||
<Card className="max-w-[80%]">
|
||||
<Card className="bg-transparent shadow-none border-0">
|
||||
<CardContent className="p-3 text-red-500">
|
||||
Oops, an error occurred. Make sure you provided a valid Mistral API key.
|
||||
</CardContent>
|
||||
|
||||
89
src/components/investigations/current-node-card.tsx
Normal file
89
src/components/investigations/current-node-card.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card"
|
||||
import { Phone, User2, XIcon } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
import { useInvestigationContext } from "../contexts/investigation-provider"
|
||||
|
||||
interface PhoneNumber {
|
||||
id: string
|
||||
country: string | null
|
||||
phone_number: string
|
||||
individual_id: string
|
||||
investigation_id: string
|
||||
}
|
||||
|
||||
interface Individual {
|
||||
id: string
|
||||
investigation_id: string
|
||||
full_name: string
|
||||
birth_date: string | null
|
||||
gender: string
|
||||
nationality: string
|
||||
notes: string
|
||||
image_url: string
|
||||
ip_addresses: string[]
|
||||
phone_numbers: PhoneNumber[]
|
||||
}
|
||||
|
||||
interface CurrentNodeProps {
|
||||
individual: Partial<Individual>
|
||||
}
|
||||
|
||||
export default function CurrentNode({ individual }: CurrentNodeProps) {
|
||||
const { handleOpenIndividualModal } = useInvestigationContext()
|
||||
const [show, setShow] = useState(true)
|
||||
if (!show) return
|
||||
return (
|
||||
<Card className="w-full max-w-sm overflow-hidden bg-background">
|
||||
<div className="h-24 bg-primary relative">
|
||||
<Button onClick={() => setShow(false)} className="text-white hover:text-white hover:bg-background/5 absolute top-2 right-2" size={"icon"} variant="ghost">
|
||||
<XIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="absolute -top-12 left-1/2 -translate-x-1/2">
|
||||
<Avatar className="h-24 w-24 border-4 border-background">
|
||||
<AvatarImage src={individual.image_url} />
|
||||
<AvatarFallback className="bg-muted">
|
||||
<span className="text-3xl">{individual?.full_name?.[0]}</span>
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
</div>
|
||||
<CardHeader className="mt-8 text-center">
|
||||
<h2 className="text-2xl font-bold">{individual.full_name}</h2>
|
||||
<p className="text-sm text-muted-foreground">{individual.notes || <span className="italic">No notes.</span>}</p>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-4">
|
||||
{individual?.phone_numbers && individual?.phone_numbers?.length > 0 && (
|
||||
<div className="flex items-center gap-2 justify-center text-sm">
|
||||
<Phone className="h-4 w-4 text-muted-foreground" />
|
||||
{individual?.phone_numbers?.map((phone) => (
|
||||
<span key={phone.id}>{phone.phone_number}</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex gap-2 justify-center">
|
||||
<Button onClick={() => handleOpenIndividualModal(individual.id)}
|
||||
variant="outline">View Details</Button>
|
||||
{/* <Button>Contact</Button> */}
|
||||
</div>
|
||||
<div className="flex justify-between gap-8 text-sm text-muted-foreground border-t pt-4">
|
||||
<div className="text-center">
|
||||
<p className="font-medium">Nationality</p>
|
||||
<p>{individual.nationality || "N/A"}</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="font-medium">Gender</p>
|
||||
<p>{individual.gender || "N/A"}</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="font-medium">IPs</p>
|
||||
<p>{individual?.ip_addresses?.length}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import { Card } from '@/components/ui/card';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useInvestigationContext } from '@/components/contexts/investigation-provider';
|
||||
import { useFlowStore } from '../contexts/use-flow-store';
|
||||
import CurrentNode from './current-node-card';
|
||||
|
||||
const edgeTypes = {
|
||||
"custom": FloatingEdge
|
||||
@@ -139,12 +140,15 @@ const LayoutFlow = ({ theme }: { theme: ColorMode }) => {
|
||||
</Button>
|
||||
<NewActions addNodes={addNodes} />
|
||||
</div>
|
||||
{currentNode && (
|
||||
<Card className='p-3'>
|
||||
<>
|
||||
{getNode(currentNode)?.data?.label}
|
||||
</>
|
||||
</Card>
|
||||
{currentNode && getNode(currentNode) && (
|
||||
getNode(currentNode)?.type === "individual" ?
|
||||
// @ts-ignore
|
||||
<CurrentNode individual={getNode(currentNode).data} /> :
|
||||
<Card className='p-3 bg-background'>
|
||||
<>
|
||||
{getNode(currentNode)?.data.label}
|
||||
</>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
@@ -79,7 +79,7 @@ function SocialNode({ data }: any) {
|
||||
</div>
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuItem onClick={() => handleOpenSearchModal(data.email)}>
|
||||
<ContextMenuItem onClick={() => handleOpenSearchModal(data.label)}>
|
||||
Launch search
|
||||
<Zap className="ml-2 h-4 w-4 text-orange-500" />
|
||||
</ContextMenuItem>
|
||||
|
||||
Reference in New Issue
Block a user