1
- import { useCallback , useState } from 'react' ;
1
+ import { useCallback , useMemo , useState } from 'react' ;
2
2
import { Popover , PopoverContent , PopoverTrigger } from '@/core/components/common/popover' ;
3
3
import Image from 'next/image' ;
4
4
import Link from 'next/link' ;
5
5
import Skeleton from 'react-loading-skeleton' ;
6
6
import { ScrollArea } from '@/core/components/common/scroll-bar' ;
7
- import { useModal } from '@/core/hooks' ;
8
- import { Modal , Divider } from '@/core/components' ;
7
+ import { useModal , useTeamTasks } from '@/core/hooks' ;
8
+ import { Modal , Divider , SpinnerLoader } from '@/core/components' ;
9
9
import { useTranslations } from 'next-intl' ;
10
10
import { TaskAssignButton } from '@/core/components/tasks/task-assign-button' ;
11
11
import { clsxm } from '@/core/lib/utils' ;
@@ -19,6 +19,7 @@ import { ITimerStatus } from '@/core/types/interfaces/timer/timer-status';
19
19
import { TEmployee , TTask } from '@/core/types/schemas/task/task.schema' ;
20
20
import { useAtomValue } from 'jotai' ;
21
21
import { activeTeamState } from '@/core/stores' ;
22
+ import { TOrganizationTeamEmployee } from '@/core/types/schemas' ;
22
23
23
24
export interface ImageOverlapperProps {
24
25
id : string ;
@@ -67,26 +68,29 @@ export default function ImageOverlapper({
67
68
const { isOpen, openModal, closeModal } = useModal ( ) ;
68
69
69
70
const activeTeam = useAtomValue ( activeTeamState ) ;
70
- const allMembers = activeTeam ?. members || [ ] ;
71
+ const allMembers = useMemo ( ( ) => activeTeam ?. members || [ ] , [ activeTeam ] ) ;
71
72
const [ assignedMembers , setAssignedMembers ] = useState < TEmployee [ ] > ( [ ...( item ?. members || [ ] ) ] ) ;
72
73
const [ unassignedMembers , setUnassignedMembers ] = useState < TEmployee [ ] > ( [ ] ) ;
73
- const [ validate , setValidate ] = useState < boolean > ( false ) ;
74
74
const [ showInfo , setShowInfo ] = useState < boolean > ( false ) ;
75
+ const { updateTask, updateLoading } = useTeamTasks ( ) ;
75
76
76
77
const t = useTranslations ( ) ;
77
78
78
- const onCheckMember = ( member : any ) => {
79
- const checkUser = assignedMembers . some ( ( el : TEmployee ) => el . id === member . id ) ;
80
- if ( checkUser ) {
81
- const updatedMembers = assignedMembers . filter ( ( el : TEmployee ) => el . id != member . id ) ;
82
- setAssignedMembers ( updatedMembers ) ;
83
- setUnassignedMembers ( [ ...unassignedMembers , member ] ) ;
84
- } else {
85
- setAssignedMembers ( [ ...assignedMembers , member ] ) ;
86
- const updatedUnassign = unassignedMembers . filter ( ( el : TEmployee ) => el . id != member . id ) ;
87
- setUnassignedMembers ( updatedUnassign ) ;
88
- }
89
- } ;
79
+ const handleMemberClick = useCallback (
80
+ ( member : TEmployee ) => {
81
+ const checkUser = assignedMembers . some ( ( el : TEmployee ) => el . id === member . id ) ;
82
+ if ( checkUser ) {
83
+ const updatedMembers = assignedMembers . filter ( ( el : TEmployee ) => el . id !== member . id ) ;
84
+ setAssignedMembers ( updatedMembers ) ;
85
+ setUnassignedMembers ( [ ...unassignedMembers , member ] ) ;
86
+ } else {
87
+ setAssignedMembers ( [ ...assignedMembers , member ] ) ;
88
+ const updatedUnassign = unassignedMembers . filter ( ( el : TEmployee ) => el . id !== member . id ) ;
89
+ setUnassignedMembers ( updatedUnassign ) ;
90
+ }
91
+ } ,
92
+ [ assignedMembers , unassignedMembers ]
93
+ ) ;
90
94
91
95
const onRedirect = useCallback (
92
96
( image : ImageOverlapperProps ) : Url => {
@@ -109,15 +113,23 @@ export default function ImageOverlapper({
109
113
[ activeTeam ?. members , onAvatarClickRedirectTo ]
110
114
) ;
111
115
112
- const onCLickValidate = ( ) => {
113
- setValidate ( ! validate ) ;
114
- closeModal ( ) ;
115
- } ;
116
+ const onConfirm = useCallback ( async ( ) => {
117
+ if ( updateLoading ) return ;
118
+ try {
119
+ await updateTask ( {
120
+ ...item ,
121
+ members : assignedMembers
122
+ } ) ;
123
+
124
+ closeModal ( ) ;
125
+ } catch ( error ) {
126
+ console . error ( 'Error updating task members:' , error ) ;
127
+ }
128
+ } , [ closeModal , updateTask , item , assignedMembers , updateLoading ] ) ;
116
129
117
130
const hasMembers = item ?. members ?. length > 0 ;
118
- const membersList = { assignedMembers, unassignedMembers } ;
119
131
120
- if ( imageLength == undefined ) {
132
+ if ( imageLength === undefined ) {
121
133
return < Skeleton height = { 40 } width = { 40 } borderRadius = { 100 } className = "rounded-full dark:bg-[#353741]" /> ;
122
134
}
123
135
@@ -185,18 +197,16 @@ export default function ImageOverlapper({
185
197
>
186
198
< Divider className = "mt-4" />
187
199
< ul className = "overflow-auto p-5 py-6" >
188
- { allMembers ?. map ( ( member : any ) => {
200
+ { allMembers ?. map ( ( member : TOrganizationTeamEmployee ) => {
189
201
return (
190
202
< li
191
- key = { member . employee }
203
+ key = { member . id }
192
204
className = "rounded-lg border border-transparent cursor-pointer w-100 hover:border-blue-500 hover:border-opacity-50"
193
205
>
194
206
< TeamMember
195
207
member = { member }
196
- item = { item }
197
- onCheckMember = { onCheckMember }
198
- membersList = { membersList }
199
- validate = { validate }
208
+ onClick = { handleMemberClick }
209
+ assigned = { assignedMembers . some ( ( el ) => el . id === member . employee ?. id ) }
200
210
/>
201
211
</ li >
202
212
) ;
@@ -209,12 +219,13 @@ export default function ImageOverlapper({
209
219
< TaskAvatars task = { { members : assignedMembers } } limit = { 3 } />
210
220
< div className = "flex px-4 h-fit" >
211
221
< button
212
- className = "flex flex-row gap-1 justify-center items-center px-4 py-2 w-28 min-w-0 h-12 text-sm text-white rounded-xl bg-primary dark:bg-primary-light disabled:bg-primary-light disabled:opacity-40"
222
+ className = "flex flex-row gap-3 justify-center items-center px-2 py-2 w-28 min-w-0 h-12 text-sm text-white rounded-xl bg-primary dark:bg-primary-light disabled:bg-primary-light disabled:opacity-40"
223
+ disabled = { updateLoading }
213
224
onClick = { ( ) => {
214
- onCLickValidate ( ) ;
225
+ onConfirm ( ) ;
215
226
} }
216
227
>
217
- < IconsCheck fill = "#ffffff" />
228
+ { updateLoading ? < SpinnerLoader size = { 20 } /> : < IconsCheck fill = "#ffffff" /> }
218
229
{ t ( 'common.CONFIRM' ) }
219
230
</ button >
220
231
</ div >
0 commit comments