DEV Community

Nebula
Nebula

Posted on

profilePage

  1. Additional Imports (at the top with other imports)
import { useState } from 'react';
import { FaTimes } from 'react-icons/fa';
Enter fullscreen mode Exit fullscreen mode
  1. New Styled Components (add after the existing styled components)
const ModalOverlay = styled(motion.div)`
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 20px;
`;

const ModalContent = styled(motion.div)`
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  border-radius: 20px;
  padding: 32px;
  width: 90%;
  max-width: 1000px;
  max-height: 80vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.3);
  position: relative;
`;

const ModalHeader = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
  padding-bottom: 16px;
  border-bottom: 2px solid rgba(102, 126, 234, 0.1);

  h3 {
    font-size: 24px;
    font-weight: 700;
    background: linear-gradient(135deg, #667eea, #764ba2);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    margin: 0;
  }
`;

const CloseButton = styled(motion.button)`
  background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1));
  border: 1px solid rgba(102, 126, 234, 0.2);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #667eea;
  transition: all 0.3s ease;

  &:hover {
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    transform: rotate(90deg);
  }
`;

const TransactionTable = styled(motion.table)`
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
`;

const StatusBadge = styled.span`
  padding: 6px 12px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;

  ${props => {
    switch (props.status) {
      case 'SUCCESS':
        return `
          background: rgba(34, 197, 94, 0.1);
          color: #059669;
          border: 1px solid rgba(34, 197, 94, 0.2);
        `;
      case 'FAILURE':
        return `
          background: rgba(239, 68, 68, 0.1);
          color: #dc2626;
          border: 1px solid rgba(239, 68, 68, 0.2);
        `;
      case 'PENDING':
        return `
          background: rgba(245, 158, 11, 0.1);
          color: #d97706;
          border: 1px solid rgba(245, 158, 11, 0.2);
        `;
      default:
        return `
          background: rgba(156, 163, 175, 0.1);
          color: #6b7280;
          border: 1px solid rgba(156, 163, 175, 0.2);
        `;
    }
  }}
`;

const TypeBadge = styled.span`
  padding: 6px 12px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;

  ${props => {
    switch (props.type) {
      case 'DEPOSIT':
        return `
          background: rgba(34, 197, 94, 0.1);
          color: #059669;
          border: 1px solid rgba(34, 197, 94, 0.2);
        `;
      case 'WITHDRAWAL':
        return `
          background: rgba(239, 68, 68, 0.1);
          color: #dc2626;
          border: 1px solid rgba(239, 68, 68, 0.2);
        `;
      case 'TRANSFER':
        return `
          background: rgba(59, 130, 246, 0.1);
          color: #2563eb;
          border: 1px solid rgba(59, 130, 246, 0.2);
        `;
      case 'LOAN':
        return `
          background: rgba(168, 85, 247, 0.1);
          color: #7c3aed;
          border: 1px solid rgba(168, 85, 247, 0.2);
        `;
      default:
        return `
          background: rgba(156, 163, 175, 0.1);
          color: #6b7280;
          border: 1px solid rgba(156, 163, 175, 0.2);
        `;
    }
  }}
`;

const EmptyState = styled(motion.div)`
  text-align: center;
  padding: 60px 20px;
  color: #6b7280;

  h4 {
    font-size: 20px;
    font-weight: 600;
    margin-bottom: 8px;
    color: #374151;
  }

  p {
    font-size: 16px;
    margin: 0;
  }
`;
Enter fullscreen mode Exit fullscreen mode
  1. State Management (add inside the Profile component, after the existing useQuery)
const [selectedAccount, setSelectedAccount] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false);

const { data: transactions, isLoading: isTransactionsLoading } = useQuery({
  queryKey: ['transactions', selectedAccount],
  queryFn: async () => {
    if (!selectedAccount) return [];
    try {
      const response = await api.get(`/transactions/${selectedAccount}`);
      return response.data.data;
    } catch (error) {
      console.error('Error fetching transactions', error);
      toast.error("Error fetching transactions");
      return [];
    }
  },
  enabled: !!selectedAccount
});
Enter fullscreen mode Exit fullscreen mode
  1. Helper Functions (add inside the Profile component)
const openTransactionModal = (accountNumber) => {
  setSelectedAccount(accountNumber);
  setIsModalOpen(true);
};

const closeTransactionModal = () => {
  setIsModalOpen(false);
  setSelectedAccount(null);
};

const formatTransactionAmount = (amount, type) => {
  const formattedAmount = formatCurrency(amount);
  if (type === 'DEPOSIT') return `+${formattedAmount}`;
  if (type === 'WITHDRAWAL') return `-${formattedAmount}`;
  return formattedAmount;
};
Enter fullscreen mode Exit fullscreen mode
  1. Update the View Transactions Button (replace the existing ActionLink for transactions)
<ActionLink 
  variants={actionLinkVariants} 
  onClick={() => openTransactionModal(account.accountNumber)}
>
  <FaEye /> View Transactions
</ActionLink>
Enter fullscreen mode Exit fullscreen mode
  1. Add the Modal (add this right before the closing tag)
{isModalOpen && (
  <ModalOverlay
    initial={{ opacity: 0 }}
    animate={{ opacity: 1 }}
    exit={{ opacity: 0 }}
    onClick={closeTransactionModal}
  >
    <ModalContent
      initial={{ opacity: 0, scale: 0.8, y: 50 }}
      animate={{ opacity: 1, scale: 1, y: 0 }}
      exit={{ opacity: 0, scale: 0.8, y: 50 }}
      onClick={(e) => e.stopPropagation()}
    >
      <ModalHeader>
        <h3>Transaction History - {selectedAccount}</h3>
        <CloseButton
          whileHover={{ scale: 1.1 }}
          whileTap={{ scale: 0.9 }}
          onClick={closeTransactionModal}
        >
          <FaTimes />
        </CloseButton>
      </ModalHeader>

      {isTransactionsLoading ? (
        <div style={{ textAlign: 'center', padding: '40px' }}>
          Loading transactions...
        </div>
      ) : transactions?.length === 0 ? (
        <EmptyState
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
        >
          <h4>No Transactions Found</h4>
          <p>This account has no transaction history yet.</p>
        </EmptyState>
      ) : (
        <TransactionTable
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
        >
          <thead>
            <tr>
              <TableHeader>Date</TableHeader>
              <TableHeader>Type</TableHeader>
              <TableHeader>From Account</TableHeader>
              <TableHeader>To Account</TableHeader>
              <TableHeader>Amount</TableHeader>
              <TableHeader>Description</TableHeader>
              <TableHeader>Status</TableHeader>
            </tr>
          </thead>
          <tbody>
            {transactions?.map((transaction) => (
              <TableRow key={transaction.id}>
                <TableCell>{formatDate(transaction.timestamp)}</TableCell>
                <TableCell>
                  <TypeBadge type={transaction.type}>
                    {transaction.type}
                  </TypeBadge>
                </TableCell>
                <TableCell>
                  {transaction.fromAccount ? (
                    <code style={{
                      background: 'rgba(102,126,234,0.1)',
                      padding: '4px 8px',
                      borderRadius: '6px',
                      fontSize: '12px'
                    }}>
                      {transaction.fromAccount.accountNumber}
                    </code>
                  ) : (
                    <span style={{ color: '#9ca3af', fontStyle: 'italic' }}>
                      External
                    </span>
                  )}
                </TableCell>
                <TableCell>
                  {transaction.toAccount ? (
                    <code style={{
                      background: 'rgba(102,126,234,0.1)',
                      padding: '4px 8px',
                      borderRadius: '6px',
                      fontSize: '12px'
                    }}>
                      {transaction.toAccount.accountNumber}
                    </code>
                  ) : (
                    <span style={{ color: '#9ca3af', fontStyle: 'italic' }}>
                      External
                    </span>
                  )}
                </TableCell>
                <TableCell>
                  <span style={{ 
                    fontWeight: 'bold',
                    color: transaction.type === 'DEPOSIT' ? '#059669' : 
                           transaction.type === 'WITHDRAWAL' ? '#dc2626' : '#374151'
                  }}>
                    {formatTransactionAmount(transaction.amount, transaction.type)}
                  </span>
                </TableCell>
                <TableCell>{transaction.description || 'No description'}</TableCell>
                <TableCell>
                  <StatusBadge status={transaction.status}>
                    {transaction.status}
                  </StatusBadge>
                </TableCell>
              </TableRow>
            ))}
          </tbody>
        </TransactionTable>
      )}
    </ModalContent>
  </ModalOverlay>
)}
Enter fullscreen mode Exit fullscreen mode

<h3>Accounts</h3>
      {
        isLoading ? ( <div>fetching accounts...</div>) : isError ? (<div>
          Error fetching accounts!
        </div> ) : accounts.length === 0 ? <div>
          <p>You dont have any accounts yet. Create your first account</p>
          <CreateButton onClick={() => {
            navigate("/dashboard/open-account")
          }}>Create Account</CreateButton>
        </div> : 

        <Table initial={{opacity: 0, y:30}}
        animate={{
          opacity: 1,
          y:0,
          transition: {
            duration: 0.6,
            ease: 'easeOut',
            staggerChildren: 0.05
          }   
        }}>
          <thead>
            <tr>
              <TableHeader>Sr. No</TableHeader>
              <TableHeader>Account Number</TableHeader>
              <TableHeader>Account Holder Name</TableHeader>
              <TableHeader>Date of Creation</TableHeader>
              <TableHeader>Account Balance</TableHeader>
              <TableHeader>Actions</TableHeader>
            </tr>
          </thead>
          <tbody>
            {accounts?.map((account,idx) => (
              <TableRow key={idx} whileHover="hover" >
                <TableCell>{idx + 1}</TableCell>
                <TableCell>
                <code style={{
                    background: 'rgba(102,126,234,0.1)',
                    padding: '4px 8px',
                    borderRadius: '6px',
                    fontSize: '14px',
                    fontWeight: '600'
                  }}>{account.accountNumber}</code>
                </TableCell>
                <TableCell>{user?.name}</TableCell>
                <TableCell>{formatDate(account.createdAt)}</TableCell>
                <TableCell>
                  <ActionLink href="#view-balance" onClick={() => {
                    toast(`Balance ${formatCurrency(account.balance)}`)
                  }}>View Balance</ActionLink>
                </TableCell>
                <TableCell>
                  <ActionLink variants={actionLinkVariants} href="#view-transactions"><FaEye /> View Transactions</ActionLink>
                </TableCell>
              </TableRow>
            ))}
          </tbody>
        </Table>
      }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)