11import { RiCornerDownLeftLine } from "@remixicon/react" ;
22import { useMutation , useQuery , useQueryClient } from "@tanstack/react-query" ;
33import { Building2 , CircleMinus , FileText , Pencil , Plus , SearchIcon , TrashIcon , User } from "lucide-react" ;
4- import { useEffect , useRef , useState } from "react" ;
4+ import React , { useEffect , useRef , useState } from "react" ;
55
66import { commands as dbCommands } from "@hypr/plugin-db" ;
77import { type Human , type Organization } from "@hypr/plugin-db" ;
@@ -20,25 +20,35 @@ interface ContactViewProps {
2020}
2121
2222export function ContactView ( { userId, initialPersonId, initialOrgId } : ContactViewProps ) {
23+ // Simple state initialization - handles both normal and deep-link cases
2324 const [ selectedOrganization , setSelectedOrganization ] = useState < string | null > ( initialOrgId || null ) ;
2425 const [ selectedPerson , setSelectedPerson ] = useState < string | null > ( initialPersonId || null ) ;
26+
2527 const [ editingPerson , setEditingPerson ] = useState < string | null > ( null ) ;
2628 const [ editingOrg , setEditingOrg ] = useState < string | null > ( null ) ;
2729 const [ showNewOrg , setShowNewOrg ] = useState ( false ) ;
2830 const queryClient = useQueryClient ( ) ;
2931
32+ // Load organizations once and keep cached (global data)
3033 const { data : organizations = [ ] } = useQuery ( {
31- queryKey : [ "organizations" , userId ] ,
34+ queryKey : [ "organizations" ] ,
3235 queryFn : ( ) => dbCommands . listOrganizations ( null ) ,
3336 } ) ;
3437
35- const { data : people = [ ] } = useQuery ( {
36- queryKey : [ "organization-members" , selectedOrganization ] ,
37- queryFn : ( ) =>
38- selectedOrganization ? dbCommands . listOrganizationMembers ( selectedOrganization ) : Promise . resolve ( [ ] ) ,
39- enabled : ! ! selectedOrganization ,
38+ // Load user's own profile
39+ const { data : userProfile } = useQuery ( {
40+ queryKey : [ "user-profile" , userId ] ,
41+ queryFn : async ( ) => {
42+ try {
43+ return await dbCommands . getHuman ( userId ) ;
44+ } catch ( error ) {
45+ console . error ( "Error fetching user profile:" , error ) ;
46+ return null ;
47+ }
48+ } ,
4049 } ) ;
4150
51+ // Load all people once and keep cached (user-specific data)
4252 const { data : allPeople = [ ] } = useQuery ( {
4353 queryKey : [ "all-people" , userId ] ,
4454 queryFn : async ( ) => {
@@ -50,14 +60,32 @@ export function ContactView({ userId, initialPersonId, initialOrgId }: ContactVi
5060 return [ ] ;
5161 }
5262 } ,
53- enabled : ! selectedOrganization ,
5463 } ) ;
5564
65+ // Merge user profile with all people, ensuring user's own profile is included
66+ const allPeopleWithUser = React . useMemo ( ( ) => {
67+ if ( ! userProfile ) {
68+ return allPeople ;
69+ }
70+
71+ // Check if user is already in the list
72+ const userInList = allPeople . some ( person => person . id === userId ) ;
73+
74+ if ( userInList ) {
75+ return allPeople ;
76+ } else {
77+ // Add user profile to the beginning of the list
78+ return [ userProfile , ...allPeople ] ;
79+ }
80+ } , [ allPeople , userProfile , userId ] ) ;
81+
82+ // Person sessions - only runs when person is selected
5683 const { data : personSessions = [ ] } = useQuery ( {
57- queryKey : [ "person-sessions" , selectedPerson , userId ] ,
84+ queryKey : [ "person-sessions" , selectedPerson || "none" ] ,
5885 queryFn : async ( ) => {
86+ // Safety check - this should never run when selectedPerson is null
5987 if ( ! selectedPerson ) {
60- return [ ] ;
88+ throw new Error ( "Query should not run when selectedPerson is null" ) ;
6189 }
6290
6391 const sessions = await dbCommands . listSessions ( {
@@ -81,35 +109,20 @@ export function ContactView({ userId, initialPersonId, initialOrgId }: ContactVi
81109
82110 return sessionsWithPerson ;
83111 } ,
84- enabled : ! ! selectedPerson ,
112+ enabled : selectedPerson !== null && selectedPerson !== undefined && selectedPerson !== "" ,
113+ gcTime : 5 * 60 * 1000 ,
114+ staleTime : 30 * 1000 ,
85115 } ) ;
86116
87- const displayPeople = selectedOrganization ? people : allPeople ;
117+ // Client-side filtering: filter allPeopleWithUser by organization when one is selected
118+ const displayPeople = selectedOrganization
119+ ? allPeopleWithUser . filter ( person => person . organization_id === selectedOrganization )
120+ : allPeopleWithUser ;
88121
89122 const selectedPersonData = displayPeople . find ( p => p . id === selectedPerson ) ;
90123
91- // Handle initial person selection
92- useEffect ( ( ) => {
93- if ( initialPersonId && allPeople . length > 0 ) {
94- const person = allPeople . find ( p => p . id === initialPersonId ) ;
95- if ( person ) {
96- setSelectedPerson ( initialPersonId ) ;
97- if ( person . organization_id ) {
98- setSelectedOrganization ( person . organization_id ) ;
99- }
100- }
101- }
102- } , [ initialPersonId , allPeople ] ) ;
103-
104- // Handle initial organization selection
105- useEffect ( ( ) => {
106- if ( initialOrgId && organizations . length > 0 ) {
107- const org = organizations . find ( o => o . id === initialOrgId ) ;
108- if ( org ) {
109- setSelectedOrganization ( initialOrgId ) ;
110- }
111- }
112- } , [ initialOrgId , organizations ] ) ;
124+ // Simple initialization - no complex useEffects needed
125+ // Initial state is set directly in useState above
113126
114127 const handleSessionClick = ( sessionId : string ) => {
115128 const path = { to : "/app/note/$id" , params : { id : sessionId } } as const satisfies LinkProps ;
@@ -134,7 +147,7 @@ export function ContactView({ userId, initialPersonId, initialOrgId }: ContactVi
134147 mutationFn : ( personId : string ) => dbCommands . deleteHuman ( personId ) ,
135148 onSuccess : ( ) => {
136149 queryClient . invalidateQueries ( { queryKey : [ "all-people" ] } ) ;
137- queryClient . invalidateQueries ( { queryKey : [ "organization-members " ] } ) ;
150+ queryClient . invalidateQueries ( { queryKey : [ "user-profile " ] } ) ;
138151
139152 if ( selectedPerson === selectedPersonData ?. id ) {
140153 setSelectedPerson ( null ) ;
@@ -241,7 +254,7 @@ export function ContactView({ userId, initialPersonId, initialOrgId }: ContactVi
241254 linkedin_username : null ,
242255 } ) . then ( ( ) => {
243256 queryClient . invalidateQueries ( { queryKey : [ "all-people" ] } ) ;
244- queryClient . invalidateQueries ( { queryKey : [ "organization-members " ] } ) ;
257+ queryClient . invalidateQueries ( { queryKey : [ "user-profile " ] } ) ;
245258 setSelectedPerson ( newPersonId ) ;
246259 setEditingPerson ( newPersonId ) ;
247260 } ) ;
@@ -268,7 +281,12 @@ export function ContactView({ userId, initialPersonId, initialOrgId }: ContactVi
268281 </ span >
269282 </ div >
270283 < div className = "flex-1 min-w-0" >
271- < div className = "font-medium truncate" > { person . full_name || person . email || "Unnamed" } </ div >
284+ < div className = "font-medium truncate flex items-center gap-1" >
285+ { person . full_name || person . email || "Unnamed" }
286+ { person . id === userId && (
287+ < span className = "text-xs bg-blue-100 text-blue-700 px-1.5 py-0.5 rounded-full" > You</ span >
288+ ) }
289+ </ div >
272290 { person . email && person . full_name && (
273291 < div className = "text-xs text-neutral-500 truncate" > { person . email } </ div >
274292 ) }
@@ -303,8 +321,11 @@ export function ContactView({ userId, initialPersonId, initialOrgId }: ContactVi
303321 < div className = "flex-1" >
304322 < div className = "flex items-start justify-between" >
305323 < div >
306- < h2 className = "text-lg font-semibold" >
324+ < h2 className = "text-lg font-semibold flex items-center gap-2 " >
307325 { selectedPersonData . full_name || "Unnamed Contact" }
326+ { selectedPersonData . id === userId && (
327+ < span className = "text-sm bg-blue-100 text-blue-700 px-2 py-1 rounded-full" > You</ span >
328+ ) }
308329 </ h2 >
309330 { selectedPersonData . job_title && (
310331 < p className = "text-sm text-neutral-600" > { selectedPersonData . job_title } </ p >
@@ -433,7 +454,7 @@ function EditPersonForm({
433454 } ) ,
434455 onSuccess : ( ) => {
435456 queryClient . invalidateQueries ( { queryKey : [ "all-people" ] } ) ;
436- queryClient . invalidateQueries ( { queryKey : [ "organization-members " ] } ) ;
457+ queryClient . invalidateQueries ( { queryKey : [ "user-profile " ] } ) ;
437458 onSave ( ) ;
438459 } ,
439460 onError : ( ) => {
0 commit comments