Untitled
'use client'; import React, { useState, useEffect, useCallback } from 'react'; import { Button, Box, Dialog, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, CircularProgress, Snackbar, Chip, IconButton } from '@mui/material'; import MainCard from 'ui-component/cards/MainCard'; import AddAccountsForm from './AddAccountsForm'; import axiosInstance from '../../utils/axios'; import MuiAlert from '@mui/material/Alert'; import { useDispatch } from 'react-redux'; import { openSnackbar } from 'store/slices/snackbar'; import { useAccounts } from 'contexts/AccountsContext'; import DeleteIcon from '@mui/icons-material/Delete'; import ConfirmDeleteDialog from '../../components/ConfirmDeleteDialog'; import { useRouter } from 'next/navigation'; import { useSearchParams } from 'next/navigation'; import { FormattedMessage } from 'react-intl'; import Joyride, { Step } from 'react-joyride'; import HelpOutlineIcon from '@mui/icons-material/HelpOutline'; import { useDashboard } from 'contexts/DashboardContext'; // Subscription interface SubscriptionAccount { allowedAccounts: number; usedAccounts: number; } // Data type export type AccountData = { id: number; number: string; name: string; account_type: 'Live' | 'Demo'; platform_name: string; connection: boolean; status: string; balance: number | string; last_sync: string; // Add this line }; const getStatusColor = (status: string) => { switch (status) { case 'Connected': return 'success'; case 'Disconnected': return 'error'; case 'Connecting': return 'default'; // Grey color default: return 'default'; } }; interface AccountsProps { isNewUser?: boolean; } const AccountsTable: React.FC<AccountsProps> = ({ isNewUser }) => { const [open, setOpen] = useState(false); const { accountsData, setAccountsData } = useAccounts(); const { setAccountId } = useDashboard(); const searchParams = useSearchParams(); const dispatch = useDispatch(); const router = useRouter(); // Initialize useRouter const [subscriptionAccount, setSubscriptionAccount] = useState<SubscriptionAccount>({ allowedAccounts: 5, usedAccounts: 0 }); // ToDo: Set allowed accounts limit based on plan const [runTour, setRunTour] = useState(false); const steps: Step[] = [ { target: 'body', content: "Welcome to TraderWaves! 🎉 Let's get started by adding your first trading account", placement: 'center' }, { target: '.add-account-button', content: 'Click here to add an account', placement: 'bottom' }, // ToDo: Add the folllowing steps to the tour { target: '.name-field', content: 'Give your account a memorable name', placement: 'bottom', disableBeacon: true }, { target: '.broker-server-fields', content: 'We support all MT5 brokers', placement: 'bottom', disableBeacon: true }, { target: '.login-fields', content: 'Type your account login details, usually sent to you in an email by your broker', placement: 'bottom', disableBeacon: true } ]; const handleOpenTour = () => { setRunTour(true); }; // Add this useEffect to start the tour when isNewUser is true useEffect(() => { if (isNewUser) { setRunTour(true); } }, [isNewUser]); useEffect(() => { // Check if the query parameter openDialog is true if (searchParams.get('openDialog') === 'true') { setOpen(true); } }, [searchParams]); const handleOpen = useCallback(() => { if (subscriptionAccount.usedAccounts >= subscriptionAccount.allowedAccounts) { dispatch( openSnackbar({ open: true, message: <FormattedMessage id="upgrade-your-plan-add-more" />, variant: 'alert', alert: { color: 'error' }, close: false }) ); } else { setOpen(true); } }, [subscriptionAccount, dispatch]); const handleClose = () => { setOpen(false); router.push('/accounts'); // Update URL to remove openAddForm parameter }; const handleCloseError = () => setError(null); useEffect(() => { if (searchParams.get('openAddForm') === 'true') { handleOpen(); } }, [searchParams, handleOpen]); const handleCloseDelete = () => { setOpenDelete(false); }; const [openDelete, setOpenDelete] = useState(false); const [selectedId, setSelectedId] = useState<number | null>(null); const [loadingDelete, setLoadingDelete] = useState(false); const handleClickOpen = (id: number) => { setSelectedId(id); setOpenDelete(true); }; const handleDelete = async () => { if (!selectedId) { return; } try { setLoadingDelete(true); // Fetch the signal copy relationships for the account const response = await axiosInstance.post('/get-slaves-signal-copy'); const data = response.data; if (data.status === 'success') { const signalCopies = data.SlavesSignalCopyAccounts.filter((account: any) => account.slave_id === selectedId); // Delete each signal copy relationship for (const signalCopy of signalCopies) { try { const deleteResponse = await axiosInstance.post('/delete-slave', { id_copy: signalCopy.id }); const deleteData = deleteResponse.data; if (deleteData.status !== 'success') { console.error(`Error deleting signal copy with id ${signalCopy.id}:`, deleteData.message); } else { console.log(`Signal copy with id ${signalCopy.id} deleted successfully`); } } catch (error) { console.error(`Error deleting signal copy with id ${signalCopy.id}:`, error); } } } else { console.error('Error fetching signal copy relationships:', data.message); } // Proceed to delete the account const accountDeleteResponse = await axiosInstance.post('/delete-account', { id: selectedId }); const accountDeleteData = accountDeleteResponse.data; if (accountDeleteData.status !== 'success') { console.log('Error deleting account:', accountDeleteData.message); } else { setAccountsData((prevData) => prevData.filter((account) => account.id !== selectedId)); updateSubscriptionAccount(subscriptionAccount.usedAccounts - 1); // Update the used accounts console.log('Account deleted successfully'); } } catch (error) { setError('Error deleting account'); console.error('Error:', error); } finally { setLoadingDelete(false); handleCloseDelete(); } }; //For every add and delete account update the combo box in dashboard useEffect(() => { if (accountsData.length > 0) { setAccountId(accountsData[0].id); } }, [accountsData, setAccountId]); const [loading, setLoading] = useState(true); const [error, setError] = useState<string | null>(null); useEffect(() => { const fetchSubscriptionData = async () => { try { const response = await axiosInstance.post('/get-accounts'); const data = response.data; if (response.status !== 200 || data.status !== 'success') { console.error('Error fetching account data:', response.data); setError('Error fetching account data: ' + data.status); return; } const usedAccounts = data.accounts ? data.accounts.length : 0; setSubscriptionAccount({ allowedAccounts: 5, usedAccounts: usedAccounts }); } catch (error) { console.error('Error fetching subscription data:', error); setError('Error fetching subscription data'); } }; const fetchAccountDetails = async (accountId: number) => { try { const response = await axiosInstance.post('/get-account-details', { id: accountId }); const data = response.data; if (response.status !== 200 || data.status !== 'success') { console.error('Error fetching account details:', data); return null; } return { balance: data.balance, account_type: data.account_type, connection_status: data.connection_status }; } catch (error) { console.error('Error fetching account details:', error); return null; } }; const fetchAccountData = async () => { if (open) { return; } try { setLoading(true); const response = await axiosInstance.post('/get-accounts'); const data = response.data; if (response.status !== 200 || data.status !== 'success') { console.error('Error fetching account data:', response.data); setError('Error fetching account data: ' + data.status); return; } if (data.accounts) { const accounts = data.accounts; const accountsData: AccountData[] = accounts.map((account: Partial<AccountData>) => ({ id: account.id!, number: account.number!, name: account.name!, account_type: account.account_type!, platform_name: account.platform_name!, connection: false, status: 'Connecting', balance: '-', last_sync: account.last_sync || '' // Add this line })); setAccountsData(accountsData); // Fetch account details asynchronously accountsData.forEach(async (account) => { const details = await fetchAccountDetails(account.id); if (details) { setAccountsData((prevData) => prevData.map((acc) => acc.id === account.id ? { ...acc, balance: details.balance, account_type: details.account_type, connection: true, status: details.connection_status } : acc ) ); } }); } } catch (error) { console.error('Error fetching account data:', error); setError('Error fetching account data'); } finally { setLoading(false); } }; fetchSubscriptionData(); fetchAccountData(); }, [setAccountsData, open]); const updateSubscriptionAccount = (usedAccounts: number) => { setSubscriptionAccount((prev) => ({ ...prev, usedAccounts: usedAccounts })); }; const progress = (subscriptionAccount.usedAccounts / subscriptionAccount.allowedAccounts) * 100; return ( <MainCard title={ <Box display="flex" justifyContent="space-between" alignItems="center"> <Typography variant="h5"> <FormattedMessage id="my-accounts" /> </Typography> <Box display="flex" alignItems="center"> <Box position="relative" display="inline-flex" mr={2}> <CircularProgress variant="determinate" value={progress >= 100 ? 100 : progress} size={40} thickness={4} color={progress >= 100 ? 'error' : 'primary'} /> <Box top={0} left={0} bottom={0} right={0} position="absolute" display="flex" alignItems="center" justifyContent="center"> <Typography variant="caption" component="div" color="textSecondary"> {`${subscriptionAccount.usedAccounts}/${subscriptionAccount.allowedAccounts}`} </Typography> </Box> </Box> <Button variant="contained" color="primary" size="small" onClick={handleOpen} className="add-account-button"> <FormattedMessage id="add-account" /> </Button> </Box> </Box> } > <Joyride steps={steps} run={runTour} continuous showSkipButton styles={{ options: { zIndex: 10000 } }} callback={(data) => { const { status } = data; if (status === 'finished' || status === 'skipped') { setRunTour(false); } }} /> {loading ? ( <Box display="flex" justifyContent="center" alignItems="center" minHeight="200px"> <CircularProgress /> </Box> ) : error ? ( <Snackbar open={Boolean(error)} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} autoHideDuration={2000} onClose={handleCloseError} > <MuiAlert onClose={handleCloseError} severity="error" elevation={2} variant="filled"> {error} </MuiAlert> </Snackbar> ) : accountsData.length === 0 ? ( <Box display="flex" flexDirection="column" alignItems="center" justifyContent="center" minHeight="200px"> <Typography variant="body1" gutterBottom> <FormattedMessage id="no-accounts-connected" /> </Typography> <Box mt={2} display="flex" gap={2}> <Button variant="contained" color="primary" onClick={handleOpen} className="add-account-button"> <FormattedMessage id="add-account" /> </Button> <Button variant="outlined" color="primary" startIcon={<HelpOutlineIcon />} onClick={handleOpenTour}> <FormattedMessage id="help-guide" /> </Button> </Box> </Box> ) : ( <TableContainer> <Table sx={{ minWidth: 650 }} aria-label="accounts table"> <TableHead> <TableRow> <TableCell> <FormattedMessage id="Status" /> </TableCell> <TableCell> <FormattedMessage id="number" /> </TableCell> <TableCell> <FormattedMessage id="name" /> </TableCell> <TableCell> <FormattedMessage id="type" /> </TableCell> <TableCell> <FormattedMessage id="platform" /> </TableCell> <TableCell> <FormattedMessage id="balance" /> </TableCell> <TableCell> <FormattedMessage id="delete" /> </TableCell> </TableRow> </TableHead> <TableBody> {accountsData.map((row) => ( <TableRow key={row.id} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}> <TableCell> <Chip label={row.status} color={getStatusColor(row.status)} sx={{ opacity: 0.7 }} /> </TableCell> <TableCell component="th" scope="row"> {row.number} </TableCell> <TableCell>{row.name}</TableCell> <TableCell>{row.account_type}</TableCell> <TableCell>{row.platform_name}</TableCell> <TableCell>{isNaN(Number(row.balance)) ? '-' : Number(row.balance).toFixed(2)}</TableCell> <TableCell> <IconButton aria-label="delete" color="error" onClick={() => handleClickOpen(row.id)}> <DeleteIcon /> </IconButton> </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> )} <Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title"> <AddAccountsForm handleClose={handleClose} updateSubscriptionAccount={updateSubscriptionAccount} existingAccounts={accountsData} /> </Dialog> <ConfirmDeleteDialog open={openDelete} loadingDelete={loadingDelete} handleClose={handleCloseDelete} handleDelete={handleDelete} /> </MainCard> ); }; export default AccountsTable;
Leave a Comment