From eca47d028e6dbd9bbc52171c4fb84374418b4600 Mon Sep 17 00:00:00 2001 From: dextmorgn Date: Tue, 4 Feb 2025 13:31:09 +0100 Subject: [PATCH] feat: social accounts --- .../[investigation_id]/page.tsx | 1 - src/components/investigations/custom-edge.tsx | 2 +- src/components/investigations/graph.tsx | 13 ++- src/components/investigations/nodes/email.tsx | 51 +++++++----- .../investigations/nodes/individual.tsx | 41 ++++++---- .../investigations/nodes/ip_address.tsx | 5 +- .../investigations/nodes/node-context.tsx | 78 ++++++++++-------- src/components/investigations/nodes/phone.tsx | 54 ++++++++----- .../investigations/nodes/social.tsx | 80 +++++++++++++++++++ 9 files changed, 233 insertions(+), 92 deletions(-) create mode 100644 src/components/investigations/nodes/social.tsx diff --git a/src/app/investigations/[investigation_id]/page.tsx b/src/app/investigations/[investigation_id]/page.tsx index b116ea0..1d9caf4 100644 --- a/src/app/investigations/[investigation_id]/page.tsx +++ b/src/app/investigations/[investigation_id]/page.tsx @@ -7,7 +7,6 @@ const DashboardPage = async ({ params: Promise<{ investigation_id: string }> }) => { const { investigation_id } = await (params) - console.log(investigation_id) const { nodes, edges } = await getInvestigationData(investigation_id) return (
diff --git a/src/components/investigations/custom-edge.tsx b/src/components/investigations/custom-edge.tsx index 4fe496f..91d2ef9 100644 --- a/src/components/investigations/custom-edge.tsx +++ b/src/components/investigations/custom-edge.tsx @@ -21,7 +21,7 @@ export default function CustomEdge({ id, label, confidence_level, sourceX, sourc {settings.showEdgeLabel && - + + window.location.reload()} variant="soft"> + + + diff --git a/src/components/investigations/nodes/email.tsx b/src/components/investigations/nodes/email.tsx index a005360..dfd4776 100644 --- a/src/components/investigations/nodes/email.tsx +++ b/src/components/investigations/nodes/email.tsx @@ -1,31 +1,47 @@ "use client" import React, { memo } from 'react'; import { Handle, Position } from '@xyflow/react'; -import { Card, Box, Text, ContextMenu, Badge, Flex, Inset } from '@radix-ui/themes'; +import { Card, Box, Text, ContextMenu, Badge, Flex, Inset, Tooltip, Avatar } from '@radix-ui/themes'; import { NodeProvider, useNodeContext } from './node-context'; import { AtSignIcon } from 'lucide-react'; +import { cn } from '@/utils'; +import { useInvestigationContext } from '../investigation-provider'; function EmailNode({ data }: any) { - const { handleDeleteNode } = useNodeContext() + const { handleDeleteNode, loading } = useNodeContext() + const { settings } = useInvestigationContext() return ( - - - - - - - - - - {data.label} - - - - - + + {settings.showNodeLabel ? + + + + + + + + + {data.label} + + + + + + : + + + } - Copy content diff --git a/src/components/investigations/nodes/individual.tsx b/src/components/investigations/nodes/individual.tsx index 3d0de5f..6fefe76 100644 --- a/src/components/investigations/nodes/individual.tsx +++ b/src/components/investigations/nodes/individual.tsx @@ -2,28 +2,28 @@ import React, { memo, useState } from 'react'; import { Handle, Position } from '@xyflow/react'; import { useInvestigationContext } from '../investigation-provider'; -import { Avatar, Card, Box, Flex, Text, ContextMenu, Dialog, TextField, Button } from '@radix-ui/themes'; -import { AtSignIcon, CameraIcon, FacebookIcon, InstagramIcon, LocateIcon, PhoneIcon, UserIcon } from 'lucide-react'; +import { Avatar, Card, Box, Flex, Text, ContextMenu, Dialog, TextField, Button, Spinner, Badge, Tooltip, Inset } from '@radix-ui/themes'; +import { AtSignIcon, CameraIcon, FacebookIcon, InstagramIcon, LocateIcon, MessageCircleDashedIcon, PhoneIcon, SendIcon, UserIcon } from 'lucide-react'; import { NodeProvider, useNodeContext } from './node-context'; +import { cn } from '@/utils'; function Custom({ data }: any) { - console.log(data) const { settings } = useInvestigationContext() - const { setOpenAddNodeModal, handleDuplicateNode, handleDeleteNode } = useNodeContext() + const { setOpenAddNodeModal, handleDuplicateNode, handleDeleteNode, loading } = useNodeContext() const [open, setOpen] = useState(false); - if (!data) return + return ( <> - {settings.showNodeLabel ? + {settings.showNodeLabel ? setOpen(true)}> : data.full_name[0]} /> {settings.showNodeLabel && @@ -35,12 +35,17 @@ function Custom({ data }: any) { } - : } + : + + + } Social account - Facebook - Instagram - Snapchat - Coco + setOpenAddNodeModal("social_accounts_facebook", data.id)}>Facebook + setOpenAddNodeModal("social_accounts_instagram", data.id)}>Instagram + setOpenAddNodeModal("social_accounts_telegram", data.id)}>Telegram + setOpenAddNodeModal("social_accounts_signal", data.id)}>Signal + setOpenAddNodeModal("social_accounts_snapchat", data.id)}>Snapchat + setOpenAddNodeModal("social_accounts_coco", data.id)}>Coco soon diff --git a/src/components/investigations/nodes/ip_address.tsx b/src/components/investigations/nodes/ip_address.tsx index 398c965..a3072f4 100644 --- a/src/components/investigations/nodes/ip_address.tsx +++ b/src/components/investigations/nodes/ip_address.tsx @@ -4,15 +4,16 @@ import { Handle, Position } from '@xyflow/react'; import { Card, Box, Text, ContextMenu, Flex, Inset, Badge } from '@radix-ui/themes'; import { NodeProvider, useNodeContext } from './node-context'; import { LocateIcon } from 'lucide-react'; +import { cn } from '@/utils'; function Custom({ data }: any) { - const { handleDeleteNode } = useNodeContext() + const { handleDeleteNode, loading } = useNodeContext() return ( <> - + diff --git a/src/components/investigations/nodes/node-context.tsx b/src/components/investigations/nodes/node-context.tsx index 78b5bfc..bb23550 100644 --- a/src/components/investigations/nodes/node-context.tsx +++ b/src/components/investigations/nodes/node-context.tsx @@ -8,15 +8,20 @@ import { useNodeId, useReactFlow } from "@xyflow/react"; interface NodeContextType { setOpenAddNodeModal: any, handleDuplicateNode: any, - handleDeleteNode: any + handleDeleteNode: any, + loading: boolean } const nodesTypes = { - "emails": { table: "emails", type: "email", field: "email" }, - "individuals": { table: "individuals", type: "individual", field: "full_name" }, - "phone_numbers": { table: "phone_numbers", type: "phone", field: "phone_number" }, - "ip_addresses": { table: "ip_addresses", type: "ip", field: "ip_address" }, - "social_accounts": { table: "social_accounts", type: "social", field: "username" }, + "emails": { table: "emails", type: "email", fields: ["email"] }, + "individuals": { table: "individuals", type: "individual", fields: ["full_name"] }, + "phone_numbers": { table: "phone_numbers", type: "phone", fields: ["phone_number"] }, + "ip_addresses": { table: "ip_addresses", type: "ip", fields: ["ip_address"] }, + "social_accounts_facebook": { table: "social_accounts", type: "social", fields: ["profile_url", "username", "platform:facebook"] }, + "social_accounts_instagram": { table: "social_accounts", type: "social", fields: ["profile_url", "username", "platform:instagram"] }, + "social_accounts_telegram": { table: "social_accounts", type: "social", fields: ["profile_url", "username", "platform:telegram"] }, + "social_accounts_snapchat": { table: "social_accounts", type: "social", fields: ["profile_url", "username", "platform:snapchat"] }, + "social_accounts_signal": { table: "social_accounts", type: "social", fields: ["profile_url", "username", "platform:signal"] }, } const NodeContext = createContext(undefined); @@ -41,10 +46,25 @@ export const NodeProvider: React.FC = (props: any) => { setOpenNodeModal(true) } - const onSubmitNewNodeModal = (e: { preventDefault: () => void; currentTarget: HTMLFormElement | undefined; }) => { + const onSubmitNewNodeModal = async (e: { preventDefault: () => void; currentTarget: HTMLFormElement | undefined; }) => { e.preventDefault(); const data = Object.fromEntries(new FormData(e.currentTarget)); - handleAddNode(data); + const newNodeId = crypto.randomUUID() + addNodes({ + id: newNodeId, + type: nodeType.type, + data: { ...data, label: data[nodeType.fields[0]] }, + position: { x: -100, y: -100 } + }); + if (nodeId) + addEdges({ + source: nodeId, + target: newNodeId, + type: 'custom', + id: `${nodeId}-${newNodeId}`.toString(), + label: nodeType.type, + }); + await handleAddNode({ ...data, id: newNodeId }); }; const handleAddNode = async (data: any) => { @@ -74,19 +94,6 @@ export const NodeProvider: React.FC = (props: any) => { relation_type: "relation" }).then(({ error }) => console.log(error)) } - addNodes({ - id: node.id, - type: nodeType.type, - data: { ...node, label: node[nodeType.field] }, - position: { x: -100, y: -100 } - }); - addEdges({ - source: nodeId, - target: node.id, - type: 'custom', - id: `${nodeId}-${node.id}`.toString(), - label: nodeType.type, - }); setLoading(false) setOpenNodeModal(false) } @@ -119,7 +126,7 @@ export const NodeProvider: React.FC = (props: any) => { }, [nodeId, setNodes, setEdges]); return ( - + {props.children} @@ -129,16 +136,23 @@ export const NodeProvider: React.FC = (props: any) => {
- + {nodeType?.fields.map((field: any, i: number) => { + const [key, value] = field.split(":") + console.log(Boolean(value)) + return ( + + ) + })} diff --git a/src/components/investigations/nodes/phone.tsx b/src/components/investigations/nodes/phone.tsx index 997bb3f..7308b38 100644 --- a/src/components/investigations/nodes/phone.tsx +++ b/src/components/investigations/nodes/phone.tsx @@ -1,39 +1,55 @@ "use client" import React, { memo } from 'react'; import { Handle, Position } from '@xyflow/react'; -import { Card, Box, Text, ContextMenu, Flex, Inset, Badge } from '@radix-ui/themes'; +import { Card, Box, Text, ContextMenu, Flex, Inset, Badge, Tooltip, Avatar } from '@radix-ui/themes'; import { NodeProvider, useNodeContext } from './node-context'; import { PhoneIcon } from 'lucide-react'; +import { cn } from '@/utils'; +import { useInvestigationContext } from '../investigation-provider'; function Custom({ data }: any) { - const { handleDeleteNode } = useNodeContext() + const { handleDeleteNode, loading } = useNodeContext() + const { settings } = useInvestigationContext() + return ( <> - - - - - - - - - - {data.label} - - - - - + + {settings.showNodeLabel ? + + + + + + + + + {data.label} + + + + + + : + + + } + - - Copy content diff --git a/src/components/investigations/nodes/social.tsx b/src/components/investigations/nodes/social.tsx new file mode 100644 index 0000000..f497552 --- /dev/null +++ b/src/components/investigations/nodes/social.tsx @@ -0,0 +1,80 @@ +"use client" +import React, { memo, useMemo } from 'react'; +import { Handle, Position } from '@xyflow/react'; +import { Card, Box, Text, ContextMenu, Flex, Inset, Badge, Tooltip, Avatar } from '@radix-ui/themes'; +import { NodeProvider, useNodeContext } from './node-context'; +import { CameraIcon, FacebookIcon, InstagramIcon, MessageCircleDashedIcon, SendIcon } from 'lucide-react'; +import { cn } from '@/utils'; +import { useInvestigationContext } from '../investigation-provider'; + +function Custom({ data }: any) { + const { handleDeleteNode, loading } = useNodeContext() + const { settings } = useInvestigationContext() + + const platformsIcons = useMemo(() => ({ + "facebook": , + "instagram": , + "telegram": , + "signal": , + "snapchat": + }), []) + return ( + <> + + + + {settings.showNodeLabel ? + + + + + {/* @ts-ignore */} + {platformsIcons[data.platform]} + + + + {data.username || data.profile_url} + + + + + + : + + + } + + + + + Copy content + Duplicate + + + Delete + + + + + ); +} + +const SocialNode = (props: any) => ( + + + +); + +export default memo(SocialNode); \ No newline at end of file