whoami7 - Manager
:
/
home
/
dataiclx
/
vielorbe.com
/
wp-content
/
plugins
/
suremails
/
src
/
screens
/
connections
/
Upload File:
files >> //home/dataiclx/vielorbe.com/wp-content/plugins/suremails/src/screens/connections/connections.js
import { useState, useEffect, useCallback } from '@wordpress/element'; import { useLocation, useNavigate } from 'react-router-dom'; import { __ } from '@wordpress/i18n'; import { Button, toast, Table } from '@bsf/force-ui'; import { Trash, PenLine, Plus, ChevronsUpDown } from 'lucide-react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import ConnectionsSkeleton from './connections-skeleton'; import ProvidersDrawer from '@screens/connections/providers-drawer'; import TestEmailDrawer from '@screens/connections/test-email-drawer'; import NoConnection from '@screens/connections/no-connections'; import ConfirmationDialog from '@components/confirmation-dialog/confirmation-dialog'; import { fetchSettings, deleteConnection as apiDeleteConnection, } from '@api/connections'; import { formatDate, sortData } from '@utils/utils'; import Tooltip from '@components/tooltip/tooltip'; import TruncatedTooltipText from '@components/truncated-tooltip-text'; import Title from '@components/title/title'; import useProviders from './use-dynamic-providers'; const Connections = () => { const [ isDrawerOpen, setIsDrawerOpen ] = useState( false ); const [ isTestEmailDrawerOpen, setIsTestEmailDrawerOpen ] = useState( false ); const [ currentConnection, setCurrentConnection ] = useState( null ); const [ sortDirection, setSortDirection ] = useState( 'asc' ); const [ isDialogOpen, setIsDialogOpen ] = useState( false ); const [ dialogConfig, setDialogConfig ] = useState( { title: '', description: '', onConfirm: null, } ); const queryClient = useQueryClient(); const location = useLocation(); const navigate = useNavigate(); useEffect( () => { if ( location.state?.openDrawer ) { setIsDrawerOpen( true ); const storedFormState = JSON.parse( localStorage.getItem( 'formStateValues' ) ) || {}; const expirationTime = Date.now(); const stored = localStorage.getItem( 'formStateValuesTimestamp' ); const storedTime = parseInt( stored, 10 ); if ( storedTime && storedTime < expirationTime ) { localStorage.removeItem( 'formStateValues' ); localStorage.removeItem( 'formStateValuesTimestamp' ); } else { setCurrentConnection( storedFormState ); localStorage.removeItem( 'formStateValues' ); localStorage.removeItem( 'formStateValuesTimestamp' ); } navigate( location.pathname, { replace: true, state: {} } ); } }, [ location.state, navigate ] ); // Query for fetching connections const { data: settings, isLoading, error, } = useQuery( { queryKey: [ 'settings' ], queryFn: fetchSettings, select: ( data ) => data?.data || {}, refetchInterval: 100000, // Refetch every 10 minutes refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: true, } ); const { providers: providersList, isLoading: isProvidersLoading } = useProviders(); const getNewConnectionSequenceId = useCallback( () => { const connectionCount = Math.max( Object.values( settings?.connections ).length, 0 ); return ( connectionCount + 1 ) * 10; }, [ settings?.connections ] ); const getNewConnectionCount = useCallback( () => { const count = {}; Object.values( settings?.connections ).forEach( ( connectionItem ) => { count[ connectionItem.type ] = ( count[ connectionItem.type ] || 0 ) + 1; } ); return count; }, [ settings?.connections ] ); // Mutation for deleting connections const deleteMutation = useMutation( { mutationFn: apiDeleteConnection, onSuccess: ( response, connection ) => { if ( response.success ) { toast.success( __( 'Deleted!', 'suremails' ), { description: __( 'Connection deleted successfully.', 'suremails' ), } ); // Update cache by removing the deleted connection queryClient.setQueryData( [ 'settings' ], ( oldData ) => ( { ...oldData, data: { ...oldData.data, connections: Object.fromEntries( Object.entries( oldData.data.connections ).filter( ( [ key ] ) => key !== connection.id ) ), }, } ) ); // Refetch logs and dashboard data queryClient.refetchQueries( { queryKey: [ 'logs' ], } ); // Refetch dashboard data queryClient.refetchQueries( { queryKey: [ 'dashboard-data' ], exact: true, } ); // Refetch settings queryClient.invalidateQueries( { queryKey: [ 'settings' ], } ); } }, onError: ( delError ) => { toast.error( __( 'Error deleting connection', 'suremails' ), { description: delError.message || __( 'There was an issue deleting the connection.', 'suremails' ), } ); }, onSettled: () => { setIsDialogOpen( false ); }, } ); // Update connections cache when a connection is added or edited const updateConnections = () => { // Invalidate the settings query to trigger a refetch queryClient.invalidateQueries( { queryKey: [ 'settings' ], } ); // Refetch dashboard data queryClient.refetchQueries( { queryKey: [ 'dashboard-data' ], } ); }; // Sort functionality const sortTableData = () => { const newDirection = sortDirection === 'asc' ? 'desc' : 'asc'; setSortDirection( newDirection ); }; const renderSortedConnections = () => { const sortedConnections = sortData( Object.entries( settings?.connections || {} ).map( ( [ key, value ] ) => ( { id: key, ...value } ) ), 'created_at', sortDirection ); return sortedConnections; }; const handleDeleteConnection = ( connection ) => { setDialogConfig( { title: __( 'Confirm Deletion', 'suremails' ), description: __( 'Are you sure you want to delete this connection? This action cannot be undone.', 'suremails' ), requireConfirmation: true, onConfirm: () => confirmDelete( connection ), } ); setIsDialogOpen( true ); }; const confirmDelete = async ( connection ) => { await deleteMutation.mutateAsync( connection ); }; const handleTestEmail = ( connection ) => { setCurrentConnection( connection ); setIsTestEmailDrawerOpen( true ); }; const handleEditConnection = ( connection ) => { setCurrentConnection( connection ); setIsDrawerOpen( true ); }; // Show loading state if ( isLoading ) { return <ConnectionsSkeleton />; } // Show error state if ( error ) { toast.error( __( 'Error loading connections', 'suremails' ), { description: error.message || __( 'There was an issue fetching connections.', 'suremails' ), } ); } // Define table headers with sorting capability const headers = [ { label: __( 'Connection', 'suremails' ), }, { label: __( 'Connection Title', 'suremails' ), }, { label: __( 'Email', 'suremails' ), }, { label: __( 'Created On', 'suremails' ), sortable: true, }, { label: __( 'Test Email', 'suremails' ), }, { label: __( 'Action', 'suremails' ), srOnly: true, }, ]; return ( <div className="flex items-start justify-center h-full px-8 py-8 bg-background-secondary"> <div className="w-full h-auto px-4 py-4 space-y-2 border-0.5 border-solid shadow-sm opacity-100 rounded-xl border-border-subtle bg-background-primary"> { /* Header */ } { renderSortedConnections().length > 0 && ( <div className="flex items-center justify-between w-full gap-2 px-2 py-2.25 opacity-100"> <Title title={ __( 'Email Connections', 'suremails' ) } tag="h1" /> <Button variant="primary" size="sm" icon={ <Plus /> } iconPosition="left" onClick={ () => setIsDrawerOpen( true ) } className="font-medium" > { __( 'Add Connection', 'suremails' ) } </Button> </div> ) } { /* Content Area */ } { renderSortedConnections().length > 0 ? ( <Table> <Table.Head className="bg-background-secondary"> { headers.map( ( header, index ) => ( <Table.HeadCell key={ index } className="whitespace-nowrap" > { header?.sortable ? ( <div key="created-at" className="flex items-center cursor-pointer" onClick={ sortTableData } > { header.label } <ChevronsUpDown className="ml-1 size-4" /> </div> ) : ( <span className={ header?.srOnly ? 'sr-only' : '' } > { header.label } </span> ) } </Table.HeadCell> ) ) } </Table.Head> <Table.Body> { renderSortedConnections().map( ( row ) => ( <Table.Row key={ row.id } // Use unique identifier for key > <Table.Cell className="w-32"> <div className="flex items-center"> { providersList.find( ( provider ) => provider.value === row?.type )?.icon } </div> </Table.Cell> <Table.Cell> <TruncatedTooltipText className="max-w-64" text={ `${ row.connection_title } - ${ row.type }` } /> </Table.Cell> <Table.Cell> <TruncatedTooltipText className="max-w-60" text={ row.from_email } /> </Table.Cell> <Table.Cell className="text-nowrap"> { formatDate( row.created_at, { day: true, month: true, year: true, hour: true, minute: true, hour12: true, } ) } </Table.Cell> <Table.Cell> { /* Send Test Email Button */ } <Button variant="outline" size="xs" className="shadow-sm whitespace-nowrap" onClick={ () => handleTestEmail( row ) } > { __( 'Send Test Email', 'suremails' ) } </Button> <div className="inline-flex items-center justify-between gap-2"> { /* Action Buttons with Tooltips */ } </div> </Table.Cell> <Table.Cell> <div className="inline-flex justify-end w-full gap-2"> { /* Edit Button with Tooltip */ } <Tooltip content={ __( 'Edit', 'suremails' ) } position="top" arrow > <Button variant="ghost" size="xs" icon={ <PenLine /> } iconPosition="left" onClick={ () => handleEditConnection( row ) } /> </Tooltip> <Tooltip content={ <span> { __( 'Delete', 'suremails' ) } </span> } position="top" variant="dark" arrow > <Button variant="ghost" size="xs" icon={ <Trash /> } iconPosition="left" onClick={ () => handleDeleteConnection( row ) } /> </Tooltip> </div> </Table.Cell> </Table.Row> ) ) } </Table.Body> </Table> ) : ( <NoConnection onClickAddConnection={ () => setIsDrawerOpen( true ) } /> ) } { /* Providers Drawer */ } <ProvidersDrawer isOpen={ isDrawerOpen } setIsOpen={ setIsDrawerOpen } currentConnection={ currentConnection } // Preselect provider with form data onSave={ updateConnections } providers={ providersList } isProvidersLoading={ isProvidersLoading } sequenceId={ getNewConnectionSequenceId() } connectionCount={ getNewConnectionCount() } /> { /* Test Email Drawer */ } <TestEmailDrawer isOpen={ isTestEmailDrawerOpen } onClose={ ( value ) => { setIsTestEmailDrawerOpen( false ); if ( ! value ) { setCurrentConnection( null ); } } } connections={ settings.connections } currentConnection={ currentConnection } /> { /* Confirmation Dialog */ } <ConfirmationDialog isOpen={ isDialogOpen } title={ dialogConfig.title } description={ dialogConfig.description } onConfirm={ dialogConfig.onConfirm } onCancel={ () => setIsDialogOpen( false ) } confirmButtonText={ __( 'Delete', 'suremails' ) } // Customize button text if needed cancelButtonText={ __( 'Cancel', 'suremails' ) } requireConfirmation={ dialogConfig.requireConfirmation } /> </div> </div> ); }; export default Connections;
Copyright ©2021 || Defacer Indonesia