@@ -8,7 +8,8 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
88import { Button } from '@/components/ui/button' ;
99import { formatCurrency } from '@/lib/utils' ;
1010import { AccountTypeBadge } from '@/components/ui/account-type-badge' ;
11- import { apiClient } from '@/lib/api-client' ;
11+ import { apiClient , ReceivedShareDto } from '@/lib/api-client' ;
12+ import { CheckIcon , XMarkIcon , EnvelopeIcon } from '@heroicons/react/24/outline' ;
1213import Link from 'next/link' ;
1314import { toast } from 'sonner' ;
1415import {
@@ -64,6 +65,8 @@ export default function AccountsPage() {
6465 const [ archiveConfirm , setArchiveConfirm ] = useState < { show : boolean ; account ?: Account } > ( { show : false } ) ;
6566 const [ deleteConfirm , setDeleteConfirm ] = useState < { show : boolean ; account ?: Account } > ( { show : false } ) ;
6667 const [ shareModal , setShareModal ] = useState < { show : boolean ; account ?: Account } > ( { show : false } ) ;
68+ const [ pendingInvitations , setPendingInvitations ] = useState < ReceivedShareDto [ ] > ( [ ] ) ;
69+ const [ processingShareIds , setProcessingShareIds ] = useState < Set < number > > ( new Set ( ) ) ;
6770
6871 useEffect ( ( ) => {
6972 if ( ! isLoading && ! isAuthenticated ) {
@@ -75,6 +78,7 @@ export default function AccountsPage() {
7578 useEffect ( ( ) => {
7679 if ( isAuthenticated && typeof window !== 'undefined' ) {
7780 loadAccounts ( ) ;
81+ loadPendingInvitations ( ) ;
7882 }
7983 } , [ isAuthenticated ] ) ;
8084
@@ -97,6 +101,54 @@ export default function AccountsPage() {
97101 }
98102 } ;
99103
104+ const loadPendingInvitations = async ( ) => {
105+ try {
106+ const shares = await apiClient . getReceivedShares ( ) ;
107+ setPendingInvitations ( ( shares || [ ] ) . filter ( s => s . status === 1 ) ) ;
108+ } catch ( error ) {
109+ console . error ( 'Failed to load pending invitations:' , error ) ;
110+ }
111+ } ;
112+
113+ const handleAcceptInvitation = async ( shareId : number ) => {
114+ if ( processingShareIds . has ( shareId ) ) return ;
115+ setProcessingShareIds ( prev => new Set ( prev ) . add ( shareId ) ) ;
116+ try {
117+ await apiClient . acceptShareById ( shareId ) ;
118+ toast . success ( t ( 'sharing.invitationAccepted' ) ) ;
119+ loadAccounts ( ) ;
120+ loadPendingInvitations ( ) ;
121+ } catch ( error ) {
122+ console . error ( 'Failed to accept invitation:' , error ) ;
123+ toast . error ( t ( 'sharing.acceptFailed' ) ) ;
124+ } finally {
125+ setProcessingShareIds ( prev => {
126+ const next = new Set ( prev ) ;
127+ next . delete ( shareId ) ;
128+ return next ;
129+ } ) ;
130+ }
131+ } ;
132+
133+ const handleDeclineInvitation = async ( shareId : number ) => {
134+ if ( processingShareIds . has ( shareId ) ) return ;
135+ setProcessingShareIds ( prev => new Set ( prev ) . add ( shareId ) ) ;
136+ try {
137+ await apiClient . declineShareById ( shareId ) ;
138+ toast . success ( t ( 'sharing.invitationDeclined' ) ) ;
139+ loadPendingInvitations ( ) ;
140+ } catch ( error ) {
141+ console . error ( 'Failed to decline invitation:' , error ) ;
142+ toast . error ( t ( 'sharing.declineFailed' ) ) ;
143+ } finally {
144+ setProcessingShareIds ( prev => {
145+ const next = new Set ( prev ) ;
146+ next . delete ( shareId ) ;
147+ return next ;
148+ } ) ;
149+ }
150+ } ;
151+
100152 const handleArchiveAccount = async ( account : Account ) => {
101153 try {
102154 // Archive the account
@@ -218,6 +270,69 @@ export default function AccountsPage() {
218270 </ Card >
219271 </ div >
220272
273+ { /* Pending Invitations */ }
274+ { pendingInvitations . length > 0 && (
275+ < Card className = "bg-white/90 backdrop-blur-xs border-0 shadow-lg border-l-4 border-l-amber-400 mb-8" >
276+ < CardHeader className = "pb-3" >
277+ < CardTitle className = "flex items-center gap-2 text-lg" >
278+ < EnvelopeIcon className = "w-5 h-5 text-amber-600" />
279+ { t ( 'sharing.pendingInvitations' ) }
280+ < span className = "inline-flex items-center justify-center w-6 h-6 rounded-full bg-amber-100 text-amber-800 text-xs font-bold" >
281+ { pendingInvitations . length }
282+ </ span >
283+ </ CardTitle >
284+ </ CardHeader >
285+ < CardContent className = "pt-0" >
286+ < div className = "space-y-3" >
287+ { pendingInvitations . map ( ( invitation ) => (
288+ < div
289+ key = { invitation . id }
290+ className = "flex flex-col sm:flex-row sm:items-center gap-3 p-4 rounded-lg bg-gray-50/50 opacity-75 border border-gray-200"
291+ >
292+ < div className = "flex items-center gap-3 min-w-0 flex-1" >
293+ < div className = "w-10 h-10 sm:w-12 sm:h-12 flex-shrink-0 bg-gradient-to-br from-gray-300 to-gray-500 rounded-xl flex items-center justify-center" >
294+ < BuildingOffice2Icon className = "w-5 h-5 sm:w-6 sm:h-6 text-white" />
295+ </ div >
296+ < div className = "min-w-0" >
297+ < h4 className = "text-base font-semibold text-gray-900 truncate" > { invitation . accountName } </ h4 >
298+ < div className = "flex items-center gap-2 mt-0.5 flex-wrap" >
299+ < span className = "inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-800" >
300+ { t ( 'sharing.pendingInvitation' ) }
301+ </ span >
302+ < span className = "text-xs text-gray-500" >
303+ { t ( 'sharing.sharedByName' , { name : invitation . sharedByName } ) }
304+ { ' - ' }
305+ { getShareRoleName ( invitation . role ) }
306+ </ span >
307+ </ div >
308+ </ div >
309+ </ div >
310+ < div className = "flex items-center gap-2 pl-13 sm:pl-0" >
311+ < Button
312+ size = "sm"
313+ onClick = { ( ) => handleAcceptInvitation ( invitation . id ) }
314+ disabled = { processingShareIds . has ( invitation . id ) }
315+ >
316+ < CheckIcon className = "w-4 h-4 mr-1" />
317+ { t ( 'sharing.accept' ) }
318+ </ Button >
319+ < Button
320+ variant = "outline"
321+ size = "sm"
322+ onClick = { ( ) => handleDeclineInvitation ( invitation . id ) }
323+ disabled = { processingShareIds . has ( invitation . id ) }
324+ >
325+ < XMarkIcon className = "w-4 h-4 mr-1" />
326+ { t ( 'sharing.decline' ) }
327+ </ Button >
328+ </ div >
329+ </ div >
330+ ) ) }
331+ </ div >
332+ </ CardContent >
333+ </ Card >
334+ ) }
335+
221336 { /* Accounts List */ }
222337 < Card className = "bg-white/90 backdrop-blur-xs border-0 shadow-lg" >
223338 < CardHeader >
0 commit comments