1
1
"use client"
2
2
3
+ import { Badge } from "@/components/ui/badge"
3
4
import { Button } from "@/components/ui/button"
4
5
import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/card"
5
- import { Badge } from "@/components/ui/badge"
6
6
import { Collapsible , CollapsibleContent , CollapsibleTrigger } from "@/components/ui/collapsible"
7
- import { ChevronDown , ChevronRight , User , X } from "lucide-react"
8
- import { cn } from "@/lib/utils"
9
7
import type { Member } from "@/lib/health-profile-store"
8
+ import { cn } from "@/lib/utils"
9
+ import { ChevronDown , ChevronRight , User , X } from "lucide-react"
10
+ import { useCallback } from "react"
10
11
11
12
import { BasicInformation } from "./basic-information"
12
13
import { LifestyleFactors } from "./lifestyle-factors"
13
- import { PregnancyInformation } from "./pregnancy-information"
14
14
import { MedicalInformation } from "./medical-information"
15
15
import { OtherServicesInput } from "./other-services-input"
16
+ import { PregnancyInformation } from "./pregnancy-information"
16
17
17
18
interface MemberCardProps {
18
19
member : Member
19
20
index : number
20
21
isCollapsed : boolean
21
22
canRemove : boolean
22
- onUpdate : ( updates : Partial < Member > ) => void
23
- onRemove : ( ) => void
24
- onToggleCollapse : ( ) => void
23
+ onUpdate : ( memberId : string , updates : Partial < Member > ) => void
24
+ onRemove : ( memberId : string , index : number ) => void
25
+ onToggleCollapse : ( memberId : string ) => void
25
26
}
26
27
27
28
export function MemberCard ( {
@@ -33,9 +34,33 @@ export function MemberCard({
33
34
onRemove,
34
35
onToggleCollapse
35
36
} : MemberCardProps ) {
37
+ // Create stable callbacks for child components
38
+ const handleUpdate = useCallback ( ( updates : Partial < Member > ) => {
39
+ onUpdate ( member . id , updates )
40
+ } , [ member . id , onUpdate ] )
41
+
42
+ const handleRemove = useCallback ( ( ) => {
43
+ onRemove ( member . id , index )
44
+ } , [ member . id , index , onRemove ] )
45
+
46
+ const handleToggleCollapse = useCallback ( ( ) => {
47
+ onToggleCollapse ( member . id )
48
+ } , [ member . id , onToggleCollapse ] )
49
+
50
+ // Prevent onOpenChange from being called during render
51
+ // Only handle user-initiated changes, not prop-driven changes
52
+ const handleCollapsibleChange = useCallback ( ( newOpen : boolean ) => {
53
+ // The Collapsible is controlled by !isCollapsed
54
+ // So when newOpen is true, isCollapsed should be false
55
+ // Only trigger the callback if this represents an actual user interaction
56
+ if ( newOpen !== ! isCollapsed ) {
57
+ handleToggleCollapse ( )
58
+ }
59
+ } , [ isCollapsed , handleToggleCollapse ] )
60
+
36
61
return (
37
62
< Card className = { cn ( "w-full transition-all" , isCollapsed && "bg-gray-50 border-gray-200" ) } >
38
- < Collapsible open = { ! isCollapsed } onOpenChange = { onToggleCollapse } >
63
+ < Collapsible open = { ! isCollapsed } onOpenChange = { handleCollapsibleChange } >
39
64
< CollapsibleTrigger asChild >
40
65
< CardHeader className = "flex flex-row items-center justify-between p-3 cursor-pointer hover:bg-gray-50 transition-colors rounded-t-lg" >
41
66
< div className = "flex items-center gap-2" >
@@ -84,7 +109,7 @@ export function MemberCard({
84
109
size = "sm"
85
110
onClick = { ( e ) => {
86
111
e . stopPropagation ( )
87
- onRemove ( )
112
+ handleRemove ( )
88
113
} }
89
114
aria-label = { `Remove ${ index === 0 ? "Primary Member" : `Member ${ index + 1 } ` } ` }
90
115
>
@@ -95,17 +120,17 @@ export function MemberCard({
95
120
</ CollapsibleTrigger >
96
121
< CollapsibleContent >
97
122
< CardContent className = "space-y-4 pt-0" >
98
- < BasicInformation member = { member } onUpdate = { onUpdate } />
123
+ < BasicInformation member = { member } onUpdate = { handleUpdate } />
99
124
100
- < LifestyleFactors member = { member } onUpdate = { onUpdate } />
125
+ < LifestyleFactors member = { member } onUpdate = { handleUpdate } />
101
126
102
- < PregnancyInformation member = { member } onUpdate = { onUpdate } />
127
+ < PregnancyInformation member = { member } onUpdate = { handleUpdate } />
103
128
104
- < MedicalInformation member = { member } onUpdate = { onUpdate } />
129
+ < MedicalInformation member = { member } onUpdate = { handleUpdate } />
105
130
106
131
< OtherServicesInput
107
132
services = { member . otherServices || [ ] }
108
- onServicesChange = { ( otherServices ) => onUpdate ( { otherServices } ) }
133
+ onServicesChange = { ( otherServices ) => handleUpdate ( { otherServices } ) }
109
134
/>
110
135
</ CardContent >
111
136
</ CollapsibleContent >
0 commit comments