@@ -5,17 +5,23 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogD
55import Input from "@/components/ui/forms/input" ;
66import toast from "react-hot-toast" ;
77import { createClientClientComponent } from "@/utils/supabase/client" ;
8- import { SimpleMemberData } from "@/app/home/projects/actions" ;
8+ import { SimpleMemberData , getMembers , getTeamLead } from "@/app/home/projects/actions" ;
99
1010/**
11- * ChecklistManageModal - TRIPLE-FIXED VERSION
11+ * ChecklistManageModal - ENHANCED SELF-FETCHING VERSION
1212 *
1313 * FIXES APPLIED:
14- * 1. ✅ Enhanced delete confirmation dialog (no double quotes around item name)
15- * 2. ✅ Removed ALL emoji from toasts (library provides icons automatically)
16- * 3. ✅ Removed ALL double quotes around item names in toasts
17- * 4. ✅ Clean, professional toast messages
18- * 5. ✅ Improved dialog styling and UX
14+ * 1. ✅ Fetches fresh member data internally (no stale props)
15+ * 2. ✅ Always shows current database state
16+ * 3. ✅ Automatic refresh when modal opens
17+ * 4. ✅ No dependency on parent component state
18+ * 5. ✅ Enhanced delete confirmation dialog
19+ * 6. ✅ Clean toast messages (no emoji, no double quotes)
20+ *
21+ * KEY CHANGE:
22+ * - Does NOT rely on teamMembers prop from parent
23+ * - Fetches fresh data from getMembers() when modal opens
24+ * - Guarantees accurate member count for checklists
1925 *
2026 * AUTHENTICATION:
2127 * - Self-contained (no currentUserId prop needed)
@@ -31,17 +37,15 @@ interface ChecklistManageModalProps {
3137 isOpen : boolean ;
3238 projectId : string ;
3339 projectName : string ;
34- teamMembers : SimpleMemberData [ ] ;
35- teamLeadId : string ;
40+ teamMembers ? : SimpleMemberData [ ] ; // Optional, for backward compatibility
41+ teamLeadId ? : string ; // Optional, will fetch if not provided
3642 onClose : ( ) => void ;
3743}
3844
3945const ChecklistManageModal = ( {
4046 isOpen,
4147 projectId,
4248 projectName,
43- teamMembers,
44- teamLeadId,
4549 onClose
4650} : ChecklistManageModalProps ) => {
4751 // State
@@ -53,6 +57,11 @@ const ChecklistManageModal = ({
5357 const [ isFetching , setIsFetching ] = useState ( false ) ;
5458 const [ supabase , setSupabase ] = useState < any > ( null ) ;
5559
60+ // Fresh member data (fetched internally)
61+ const [ freshTeamMembers , setFreshTeamMembers ] = useState < SimpleMemberData [ ] > ( [ ] ) ;
62+ const [ freshTeamLeadId , setFreshTeamLeadId ] = useState < string > ( "" ) ;
63+ const [ isFetchingMembers , setIsFetchingMembers ] = useState ( false ) ;
64+
5665 // Self-contained auth
5766 const [ currentCodevId , setCurrentCodevId ] = useState < string | null > ( null ) ;
5867 const [ isTeamLead , setIsTeamLead ] = useState ( false ) ;
@@ -62,52 +71,95 @@ const ChecklistManageModal = ({
6271 const [ deleteDialogOpen , setDeleteDialogOpen ] = useState ( false ) ;
6372 const [ itemToDelete , setItemToDelete ] = useState < string | null > ( null ) ;
6473
65- // Initialize Supabase and get current user
74+ // Initialize Supabase
6675 useEffect ( ( ) => {
6776 const client = createClientClientComponent ( ) ;
6877 setSupabase ( client ) ;
78+ } , [ ] ) ;
79+
80+ // ✅ CRITICAL FIX: Fetch fresh member data when modal opens
81+ useEffect ( ( ) => {
82+ if ( isOpen && projectId ) {
83+ fetchFreshMemberData ( ) ;
84+ }
85+ } , [ isOpen , projectId ] ) ;
86+
87+ // Fetch fresh member data from database
88+ const fetchFreshMemberData = async ( ) => {
89+ console . log ( "🔄 ChecklistManageModal: Fetching fresh member data..." ) ;
90+ setIsFetchingMembers ( true ) ;
6991
70- if ( client ) {
71- client . auth . getSession ( ) . then ( async ( { data : { session } } ) => {
72- if ( session ?. user ?. email ) {
73- // Map auth user email to codev_id
74- const { data : codevData } = await client
75- . from ( "codev" )
76- . select ( "id" )
77- . eq ( "email_address" , session . user . email )
78- . single ( ) ;
79-
80- if ( codevData ) {
81- setCurrentCodevId ( codevData . id ) ;
82- // Check if this user is the team lead
83- setIsTeamLead ( codevData . id === teamLeadId ) ;
84- }
85- }
86- setAuthChecked ( true ) ;
87- } ) ;
92+ try {
93+ // Fetch team lead
94+ const teamLeadResult = await getTeamLead ( projectId ) ;
95+ if ( teamLeadResult . data ?. id ) {
96+ setFreshTeamLeadId ( teamLeadResult . data . id ) ;
97+ console . log ( "👑 Team Lead ID:" , teamLeadResult . data . id ) ;
98+ }
99+
100+ // Fetch members
101+ const membersResult = await getMembers ( projectId ) ;
102+ if ( membersResult . data ) {
103+ setFreshTeamMembers ( membersResult . data ) ;
104+ console . log ( "👥 Fresh members fetched:" , membersResult . data . length ) ;
105+ console . log ( "📝 Member names:" , membersResult . data . map ( m => `${ m . first_name } ${ m . last_name } ` ) ) ;
106+ }
107+ } catch ( error ) {
108+ console . error ( "❌ Error fetching fresh member data:" , error ) ;
109+ toast . error ( "Failed to load team members" ) ;
110+ } finally {
111+ setIsFetchingMembers ( false ) ;
88112 }
89- } , [ teamLeadId ] ) ;
113+ } ;
114+
115+ // Get current user and check auth
116+ useEffect ( ( ) => {
117+ if ( ! supabase || ! freshTeamLeadId ) return ;
118+
119+ supabase . auth . getSession ( ) . then ( async ( { data : { session } } : any ) => {
120+ if ( session ?. user ?. email ) {
121+ // Map auth user email to codev_id
122+ const { data : codevData } = await supabase
123+ . from ( "codev" )
124+ . select ( "id" )
125+ . eq ( "email_address" , session . user . email )
126+ . single ( ) ;
127+
128+ if ( codevData ) {
129+ setCurrentCodevId ( codevData . id ) ;
130+ // Check if this user is the team lead
131+ setIsTeamLead ( codevData . id === freshTeamLeadId ) ;
132+ console . log ( "🔐 Current user is team lead:" , codevData . id === freshTeamLeadId ) ;
133+ }
134+ }
135+ setAuthChecked ( true ) ;
136+ } ) ;
137+ } , [ supabase , freshTeamLeadId ] ) ;
90138
91139 // Get all member IDs (team lead + members)
92140 const allMemberIds = useMemo ( ( ) => {
93- if ( ! teamLeadId ) {
141+ if ( ! freshTeamLeadId ) {
94142 return [ ] ;
95143 }
96144
97- if ( ! teamMembers || ! Array . isArray ( teamMembers ) ) {
98- return [ teamLeadId ] ;
145+ if ( ! freshTeamMembers || ! Array . isArray ( freshTeamMembers ) ) {
146+ return [ freshTeamLeadId ] ;
99147 }
100148
101- const memberIds = teamMembers . map ( m => m . id ) . filter ( Boolean ) ;
102- return [ teamLeadId , ...memberIds ] ;
103- } , [ teamLeadId , teamMembers ] ) ;
149+ const memberIds = freshTeamMembers . map ( m => m . id ) . filter ( Boolean ) ;
150+ const allIds = [ freshTeamLeadId , ...memberIds ] ;
151+
152+ console . log ( `📊 Total team members for checklist: ${ allIds . length } (1 lead + ${ memberIds . length } members)` ) ;
153+
154+ return allIds ;
155+ } , [ freshTeamLeadId , freshTeamMembers ] ) ;
104156
105157 // Load checklist items when modal opens
106158 useEffect ( ( ) => {
107- if ( isOpen && supabase && projectId ) {
159+ if ( isOpen && supabase && projectId && allMemberIds . length > 0 ) {
108160 loadChecklistItems ( ) ;
109161 }
110- } , [ isOpen , supabase , projectId ] ) ;
162+ } , [ isOpen , supabase , projectId , allMemberIds . length ] ) ;
111163
112164 // Load checklist items from database
113165 const loadChecklistItems = async ( ) => {
@@ -177,7 +229,7 @@ const ChecklistManageModal = ({
177229 description : null ,
178230 priority : "medium" ,
179231 completed : false ,
180- created_by : teamLeadId ,
232+ created_by : freshTeamLeadId ,
181233 due_date : null ,
182234 created_at : new Date ( ) . toISOString ( ) ,
183235 updated_at : new Date ( ) . toISOString ( )
@@ -191,7 +243,6 @@ const ChecklistManageModal = ({
191243 if ( error ) {
192244 toast . error ( `Failed: ${ error . message } ` ) ;
193245 } else {
194- // FIXED: No emoji, no double quotes, clean message
195246 toast . success ( `${ newItemTitle . trim ( ) } added to checklist` ) ;
196247 setItems ( prev => [ ...prev , newItemTitle . trim ( ) ] ) ;
197248 setNewItemTitle ( "" ) ;
@@ -252,7 +303,6 @@ const ChecklistManageModal = ({
252303 if ( error ) {
253304 toast . error ( "Failed to update item" ) ;
254305 } else {
255- // FIXED: No emoji, no double quotes
256306 toast . success ( `${ oldTitle } updated to ${ editingNewTitle . trim ( ) } ` ) ;
257307 setItems ( prev => prev . map ( item => item === oldTitle ? editingNewTitle . trim ( ) : item ) ) ;
258308 handleCancelEdit ( ) ;
@@ -300,7 +350,6 @@ const ChecklistManageModal = ({
300350 if ( error ) {
301351 toast . error ( "Failed to delete item" ) ;
302352 } else {
303- // FIXED: No emoji, no double quotes
304353 toast . success ( `${ itemToDelete } removed from checklist` ) ;
305354 setItems ( prev => prev . filter ( item => item !== itemToDelete ) ) ;
306355 handleCancelDelete ( ) ;
@@ -322,15 +371,17 @@ const ChecklistManageModal = ({
322371 }
323372 } ;
324373
325- // Show loading state while checking auth
326- if ( ! authChecked ) {
374+ // Show loading state while fetching members or checking auth
375+ if ( isFetchingMembers || ! authChecked ) {
327376 return (
328377 < Dialog open = { isOpen } onOpenChange = { handleClose } >
329378 < DialogContent className = "max-w-md bg-white dark:bg-gray-900" >
330379 < div className = "flex items-center justify-center py-8" >
331380 < div className = "text-center" >
332381 < div className = "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500 mx-auto mb-4" > </ div >
333- < p className = "text-sm text-gray-600 dark:text-gray-400" > Loading...</ p >
382+ < p className = "text-sm text-gray-600 dark:text-gray-400" >
383+ { isFetchingMembers ? "Loading team members..." : "Loading..." }
384+ </ p >
334385 </ div >
335386 </ div >
336387 </ DialogContent >
@@ -514,7 +565,7 @@ const ChecklistManageModal = ({
514565 </ DialogContent >
515566 </ Dialog >
516567
517- { /* ENHANCED Delete Confirmation Dialog - NO DOUBLE QUOTES */ }
568+ { /* Delete Confirmation Dialog */ }
518569 < Dialog open = { deleteDialogOpen } onOpenChange = { setDeleteDialogOpen } >
519570 < DialogContent className = "max-w-md bg-white dark:bg-gray-900" >
520571 < DialogHeader >
0 commit comments