import styled from 'styled-components';
import { motion } from 'framer-motion';
const DashboardContainer = styled.div`
display: flex;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
`;
const Sidebar = styled(motion.aside)`
width: 280px;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-right: 1px solid rgba(255, 255, 255, 0.2);
padding: 32px 0;
display: flex;
flex-direction: column;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
position: relative;
z-index: 10;
h2 {
font-size: 24px;
font-weight: 700;
color: #1a202c;
margin: 0 32px 48px;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
@media (max-width: 768px) {
width: 240px;
}
`;
const SidebarItem = styled(motion.div)`
padding: 16px 32px;
margin: 4px 16px;
border-radius: 12px;
color: #4a5568;
font-weight: 500;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
text-transform: capitalize;
&:hover {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
transform: translateX(8px);
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4);
}
&:active {
transform: translateX(4px) scale(0.98);
}
`;
const LogoutButton = styled(motion.button)`
margin: auto 16px 16px;
padding: 16px 32px;
background: linear-gradient(135deg, #ff6b6b, #ee5a52);
color: white;
border: none;
border-radius: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 4px 16px rgba(238, 90, 82, 0.3);
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(238, 90, 82, 0.4);
background: linear-gradient(135deg, #ff5252, #e53e3e);
}
&:active {
transform: translateY(0);
}
`;
const MainContent = styled.div`
flex: 1;
display: flex;
flex-direction: column;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 24px 0 0 24px;
margin: 16px 16px 16px 0;
overflow: hidden;
`;
const Header = styled(motion.header)`
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
padding: 24px 32px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
`;
const UserInfo = styled(motion.div)`
display: flex;
align-items: center;
gap: 12px;
padding: 12px 20px;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1));
border-radius: 50px;
border: 1px solid rgba(102, 126, 234, 0.2);
svg {
color: #667eea;
font-size: 18px;
}
`;
const UserName = styled.span`
font-weight: 600;
color: #2d3748;
text-transform: capitalize;
`;
const HeaderButton = styled(motion.button)`
background: linear-gradient(135deg, rgba(255, 107, 107, 0.1), rgba(238, 90, 82, 0.1));
border: 1px solid rgba(255, 107, 107, 0.2);
border-radius: 12px;
padding: 12px;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
justify-content: center;
svg {
color: #ff6b6b;
font-size: 18px;
}
&:hover {
background: linear-gradient(135deg, #ff6b6b, #ee5a52);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(255, 107, 107, 0.3);
svg {
color: white;
}
}
&:active {
transform: translateY(0);
}
`;
// Animation variants for framer-motion
const sidebarVariants = {
initial: { x: -280, opacity: 0 },
animate: { x: 0, opacity: 1, transition: { duration: 0.6, ease: "easeOut" } }
};
const headerVariants = {
initial: { y: -60, opacity: 0 },
animate: { y: 0, opacity: 1, transition: { duration: 0.6, delay: 0.2, ease: "easeOut" } }
};
const sidebarItemVariants = {
initial: { x: -20, opacity: 0 },
animate: { x: 0, opacity: 1 },
hover: { x: 8, transition: { duration: 0.2 } }
};
const userInfoVariants = {
initial: { scale: 0.9, opacity: 0 },
animate: { scale: 1, opacity: 1, transition: { duration: 0.4, delay: 0.4 } }
};
// Add these props to your components:
// <Sidebar variants={sidebarVariants} initial="initial" animate="animate">
// <Header variants={headerVariants} initial="initial" animate="animate">
// <SidebarItem variants={sidebarItemVariants} whileHover="hover">
// <UserInfo variants={userInfoVariants} initial="initial" animate="animate">
import { FaSignOutAlt, FaUser } from "react-icons/fa";
import { Outlet } from "react-router-dom";
function Dashboard() {
return (
<DashboardContainer>
<Sidebar>
<h2>Banking App</h2>
<SidebarItem>Profile</SidebarItem>
<SidebarItem>Create account</SidebarItem>
<SidebarItem>view transactions</SidebarItem>
<SidebarItem>deposit</SidebarItem>
<SidebarItem>withdraw</SidebarItem>
<SidebarItem>take loan</SidebarItem>
<SidebarItem>transfer money</SidebarItem>
<SidebarItem>View analytics</SidebarItem>
<LogoutButton>Logout</LogoutButton>
</Sidebar>
<MainContent>
<Header>
<UserInfo>
<FaUser />
<UserName>username</UserName>
</UserInfo>
<HeaderButton>
<FaSignOutAlt />
</HeaderButton>
</Header>
<Outlet />
</MainContent>
</DashboardContainer>
);
}
export default Dashboard;
---------------- PROFILE PAGE ---------------
import styled from 'styled-components';
import { motion } from 'framer-motion';
const ProfileContainer = styled(motion.div)`
padding: 32px;
max-width: 1200px;
margin: 0 auto;
min-height: calc(100vh - 120px);
h3 {
font-size: 24px;
font-weight: 700;
color: #1a202c;
margin: 48px 0 24px;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
@media (max-width: 768px) {
padding: 20px;
}
`;
const ProfileTitle = styled(motion.h2)`
font-size: 32px;
font-weight: 800;
color: #1a202c;
margin-bottom: 32px;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-align: center;
@media (max-width: 768px) {
font-size: 28px;
margin-bottom: 24px;
}
`;
const UserDetails = styled(motion.div)`
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 32px;
margin-bottom: 32px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 24px;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(135deg, #667eea, #764ba2);
}
@media (max-width: 768px) {
padding: 24px;
grid-template-columns: 1fr;
gap: 16px;
}
`;
const UserDetail = styled(motion.div)`
display: flex;
flex-direction: column;
gap: 8px;
padding: 20px;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.05), rgba(118, 75, 162, 0.05));
border-radius: 12px;
border: 1px solid rgba(102, 126, 234, 0.1);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.15);
border-color: rgba(102, 126, 234, 0.3);
}
strong {
font-weight: 600;
color: #4a5568;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
&::after {
content: attr(data-value);
font-size: 18px;
font-weight: 700;
color: #1a202c;
margin-top: 4px;
}
`;
const Table = styled(motion.table)`
width: 100%;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 20px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-collapse: separate;
border-spacing: 0;
@media (max-width: 768px) {
font-size: 14px;
}
`;
const TableHeader = styled.th`
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 20px 16px;
text-align: left;
font-weight: 600;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
border: none;
&:first-child {
border-top-left-radius: 20px;
}
&:last-child {
border-top-right-radius: 20px;
}
@media (max-width: 768px) {
padding: 16px 12px;
font-size: 12px;
}
`;
// Fixed typo - this should match the component name
const TabeHeader = styled(TableHeader)``;
const TableRow = styled(motion.tr)`
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:hover {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.05), rgba(118, 75, 162, 0.05));
transform: scale(1.01);
}
&:nth-child(even) {
background: rgba(248, 250, 252, 0.5);
}
&:last-child td:first-child {
border-bottom-left-radius: 20px;
}
&:last-child td:last-child {
border-bottom-right-radius: 20px;
}
`;
const TableCell = styled.td`
padding: 20px 16px;
border-bottom: 1px solid rgba(226, 232, 240, 0.5);
color: #4a5568;
font-weight: 500;
border: none;
vertical-align: middle;
&:last-child {
border-bottom: none;
}
@media (max-width: 768px) {
padding: 16px 12px;
font-size: 13px;
}
`;
const ActionLink = styled(motion.button)`
display: inline-flex;
align-items: center;
gap: 8px;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1));
color: #667eea;
border: 1px solid rgba(102, 126, 234, 0.2);
padding: 10px 16px;
border-radius: 25px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
text-decoration: none;
margin: 2px;
svg {
font-size: 12px;
}
&:hover {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
border-color: transparent;
}
&:active {
transform: translateY(0);
}
@media (max-width: 768px) {
padding: 8px 12px;
font-size: 12px;
gap: 6px;
}
`;
// Animation variants for framer-motion
const containerVariants = {
initial: { opacity: 0, y: 20 },
animate: {
opacity: 1,
y: 0,
transition: {
duration: 0.6,
ease: "easeOut",
staggerChildren: 0.1
}
}
};
const titleVariants = {
initial: { opacity: 0, y: -20 },
animate: {
opacity: 1,
y: 0,
transition: { duration: 0.6, ease: "easeOut" }
}
};
const userDetailsVariants = {
initial: { opacity: 0, scale: 0.95 },
animate: {
opacity: 1,
scale: 1,
transition: {
duration: 0.5,
ease: "easeOut",
staggerChildren: 0.1
}
}
};
const userDetailVariants = {
initial: { opacity: 0, x: -20 },
animate: { opacity: 1, x: 0 },
hover: {
y: -4,
transition: { duration: 0.2 }
}
};
const tableVariants = {
initial: { opacity: 0, y: 30 },
animate: {
opacity: 1,
y: 0,
transition: {
duration: 0.6,
ease: "easeOut",
staggerChildren: 0.05
}
}
};
const rowVariants = {
initial: { opacity: 0, x: -20 },
animate: { opacity: 1, x: 0 },
hover: {
scale: 1.01,
transition: { duration: 0.2 }
}
};
const actionLinkVariants = {
hover: {
y: -2,
transition: { duration: 0.2 }
},
tap: {
y: 0,
scale: 0.95
}
};
// Add these props to your components:
// <ProfileContainer variants={containerVariants}>
// <ProfileTitle variants={titleVariants}>
// <UserDetails variants={userDetailsVariants}>
// <UserDetail variants={userDetailVariants} whileHover="hover">
// <Table variants={tableVariants}>
// <TableRow variants={rowVariants} whileHover="hover">
// <ActionLink variants={actionLinkVariants} whileHover="hover" whileTap="tap">
import { FaEye } from "react-icons/fa";
function Profile() {
const user = {
name: "John Doe",
email: "john.doe@example.com",
age: 30,
};
const accounts = [
{
srNo: 1,
accountNumber: "1234567890",
holderName: "Kishan",
balance: 1000.0,
creationDate: "2023-01-01",
},
{
srNo: 2,
accountNumber: "0987654321",
holderName: "Kishan",
balance: 2000.0,
creationDate: "2023-02-01",
},
];
return (
<ProfileContainer
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, ease: "easeOut" }}
>
<ProfileTitle>User profile</ProfileTitle>
<UserDetails>
<UserDetail>
<strong>Name:</strong> {user.name}
</UserDetail>
<UserDetail>
<strong>Email:</strong> {user.email}
</UserDetail>
<UserDetail>
<strong>Age:</strong> {user.age}
</UserDetail>
</UserDetails>
<h3>Accounts</h3>
<Table>
<thead>
<tr>
<TabeHeader>Sr. No</TabeHeader>
<TabeHeader>Account Number</TabeHeader>
<TableHeader>ACcount holder name</TableHeader>
<TableHeader>Date of creation</TableHeader>
<TableHeader>Account Balance</TableHeader>
<TableHeader>Actions</TableHeader>
</tr>
</thead>
<tbody>
{accounts.map((account) => (
<TableRow key={account.srNo}>
<TableCell>{account.srNo}</TableCell>
<TableCell>{account.accountNumber}</TableCell>
<TableCell>{account.holderName}</TableCell>
<TableCell>{account.creationDate}</TableCell>
<TableCell>${account.balance.toFixed(2)}</TableCell>
<TableCell>
<ActionLink>
<FaEye />
View Balance
</ActionLink>
</TableCell>
<TableCell>
<ActionLink>
<FaEye />
View TRansactions
</ActionLink>
</TableCell>
</TableRow>
))}
</tbody>
</Table>
</ProfileContainer>
);
}
export default Profile;
--------------- CREATE ACCOUNT STYLES------------
import styled from 'styled-components';
import { motion, AnimatePresence } from 'framer-motion';
// Styled Components
const Container = styled(motion.div)`
padding: 32px;
max-width: 1200px;
margin: 0 auto;
min-height: calc(100vh - 120px);
h2 {
font-size: 32px;
font-weight: 800;
color: #1a202c;
margin-bottom: 32px;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-align: center;
}
@media (max-width: 768px) {
padding: 20px;
h2 {
font-size: 28px;
margin-bottom: 24px;
}
}
`;
const Form = styled(motion.form)`
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 32px;
margin-bottom: 32px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
display: grid;
grid-template-columns: 1fr 1fr auto;
gap: 24px;
align-items: end;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(135deg, #667eea, #764ba2);
}
@media (max-width: 768px) {
grid-template-columns: 1fr;
gap: 20px;
padding: 24px;
}
`;
const InputGroup = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
`;
const Label = styled.label`
font-weight: 600;
color: #4a5568;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
`;
const Input = styled.input`
padding: 16px 20px;
border: 2px solid rgba(102, 126, 234, 0.2);
border-radius: 12px;
font-size: 16px;
font-weight: 500;
color: #2d3748;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
background: rgba(255, 255, 255, 0.95);
}
&::placeholder {
color: #a0aec0;
}
&:invalid {
border-color: #ff6b6b;
}
`;
const Select = styled.select`
padding: 16px 20px;
border: 2px solid rgba(102, 126, 234, 0.2);
border-radius: 12px;
font-size: 16px;
font-weight: 500;
color: #2d3748;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
&:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
background: rgba(255, 255, 255, 0.95);
}
option {
background: white;
color: #2d3748;
padding: 12px;
}
`;
const CreateButton = styled(motion.button)`
display: flex;
align-items: center;
gap: 12px;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 12px;
padding: 16px 24px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.4);
height: fit-content;
&:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.5);
background: linear-gradient(135deg, #5a67d8, #6b46c1);
}
&:active {
transform: translateY(0);
scale: 0.98;
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
svg {
transition: transform 0.2s ease;
}
&:hover svg {
transform: rotate(90deg);
}
`;
const Table = styled.table`
width: 100%;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 20px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-collapse: separate;
border-spacing: 0;
th {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 20px 16px;
text-align: left;
font-weight: 600;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
border: none;
&:first-child {
border-top-left-radius: 20px;
}
&:last-child {
border-top-right-radius: 20px;
}
}
td {
padding: 20px 16px;
color: #4a5568;
font-weight: 500;
border-bottom: 1px solid rgba(226, 232, 240, 0.5);
vertical-align: middle;
}
tr:hover {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.05), rgba(118, 75, 162, 0.05));
}
tr:nth-child(even) {
background: rgba(248, 250, 252, 0.5);
}
tr:last-child td:first-child {
border-bottom-left-radius: 20px;
}
tr:last-child td:last-child {
border-bottom-right-radius: 20px;
}
@media (max-width: 768px) {
font-size: 14px;
th, td {
padding: 16px 12px;
}
}
`;
const StatusBadge = styled.span`
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
${props => props.status === 'ACTIVE' && `
background: linear-gradient(135deg, rgba(72, 187, 120, 0.2), rgba(56, 178, 172, 0.2));
color: #38a169;
border: 1px solid rgba(72, 187, 120, 0.3);
`}
${props => props.status === 'INACTIVE' && `
background: linear-gradient(135deg, rgba(255, 107, 107, 0.2), rgba(238, 90, 82, 0.2));
color: #e53e3e;
border: 1px solid rgba(255, 107, 107, 0.3);
`}
`;
const AccountTypeBadge = styled.span`
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
${props => props.type === 'SAVINGS' && `
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
color: #667eea;
border: 1px solid rgba(102, 126, 234, 0.3);
`}
${props => props.type === 'CURRENT' && `
background: linear-gradient(135deg, rgba(255, 193, 7, 0.2), rgba(255, 152, 0, 0.2));
color: #f6ad55;
border: 1px solid rgba(255, 193, 7, 0.3);
`}
${props => props.type === 'SALARY' && `
background: linear-gradient(135deg, rgba(72, 187, 120, 0.2), rgba(56, 178, 172, 0.2));
color: #38a169;
border: 1px solid rgba(72, 187, 120, 0.3);
`}
`;
// Modal 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: 24px;
padding: 32px;
max-width: 500px;
width: 100%;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.2);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(135deg, #667eea, #764ba2);
}
`;
const ModalHeader = styled.div`
margin-bottom: 24px;
h3 {
font-size: 24px;
font-weight: 700;
color: #1a202c;
margin-bottom: 8px;
}
p {
color: #4a5568;
font-size: 16px;
line-height: 1.5;
}
`;
const ModalActions = styled.div`
display: flex;
gap: 12px;
justify-content: flex-end;
margin-top: 32px;
`;
const ModalButton = styled(motion.button)`
padding: 12px 24px;
border-radius: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 2px solid transparent;
${props => props.variant === 'primary' ? `
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.4);
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.5);
}
` : `
background: transparent;
color: #4a5568;
border-color: #e2e8f0;
&:hover {
background: #f7fafc;
border-color: #cbd5e0;
}
`}
&:active {
transform: translateY(0);
}
`;
// Toast Components
const ToastContainer = styled(motion.div)`
position: fixed;
top: 20px;
right: 20px;
z-index: 1100;
`;
const Toast = styled(motion.div)`
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 12px;
padding: 16px 20px;
margin-bottom: 12px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
border: 1px solid rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
gap: 12px;
min-width: 300px;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 4px;
background: ${props =>
props.type === 'success' ? 'linear-gradient(135deg, #48bb78, #38b2ac)' :
props.type === 'error' ? 'linear-gradient(135deg, #ff6b6b, #ee5a52)' :
'linear-gradient(135deg, #667eea, #764ba2)'
};
}
.toast-content {
flex: 1;
.toast-title {
font-weight: 600;
color: #1a202c;
margin-bottom: 4px;
}
.toast-message {
color: #4a5568;
font-size: 14px;
}
}
`;
// Animation variants
const containerVariants = {
initial: { opacity: 0, y: 20 },
animate: {
opacity: 1,
y: 0,
transition: { duration: 0.6, ease: "easeOut" }
}
};
const formVariants = {
initial: { opacity: 0, scale: 0.95 },
animate: {
opacity: 1,
scale: 1,
transition: { duration: 0.5, ease: "easeOut" }
}
};
const modalVariants = {
overlay: {
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 }
},
content: {
initial: { opacity: 0, scale: 0.95, y: 20 },
animate: {
opacity: 1,
scale: 1,
y: 0,
transition: { duration: 0.3, ease: "easeOut" }
},
exit: {
opacity: 0,
scale: 0.95,
y: 20,
transition: { duration: 0.2 }
}
}
};
const toastVariants = {
initial: { opacity: 0, x: 300, scale: 0.9 },
animate: {
opacity: 1,
x: 0,
scale: 1,
transition: { duration: 0.4, ease: "easeOut" }
},
exit: {
opacity: 0,
x: 300,
scale: 0.9,
transition: { duration: 0.3 }
}
};
// Reusable Modal Component
const Modal = ({ isOpen, onClose, title, message, onConfirm, confirmText = "Confirm", cancelText = "Cancel" }) => (
<AnimatePresence>
{isOpen && (
<ModalOverlay
variants={modalVariants.overlay}
initial="initial"
animate="animate"
exit="exit"
onClick={onClose}
>
<ModalContent
variants={modalVariants.content}
onClick={e => e.stopPropagation()}
>
<ModalHeader>
<h3>{title}</h3>
<p>{message}</p>
</ModalHeader>
<ModalActions>
<ModalButton
variant="secondary"
onClick={onClose}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
{cancelText}
</ModalButton>
<ModalButton
variant="primary"
onClick={onConfirm}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
{confirmText}
</ModalButton>
</ModalActions>
</ModalContent>
</ModalOverlay>
)}
</AnimatePresence>
);
// Reusable Toast Component
const ToastComponent = ({ toasts, removeToast }) => (
<ToastContainer>
<AnimatePresence>
{toasts.map(toast => (
<Toast
key={toast.id}
type={toast.type}
variants={toastVariants}
initial="initial"
animate="animate"
exit="exit"
onClick={() => removeToast(toast.id)}
style={{ cursor: 'pointer' }}
>
<div className="toast-content">
<div className="toast-title">{toast.title}</div>
<div className="toast-message">{toast.message}</div>
</div>
</Toast>
))}
</AnimatePresence>
</ToastContainer>
);
// Export all styled components for use in the main component
export {
Container,
Form,
InputGroup,
Label,
Input,
Select,
CreateButton,
Table,
StatusBadge,
AccountTypeBadge,
Modal,
ToastComponent,
containerVariants,
formVariants
};
--------------- CREATE ACCOUNT PAGE --------------
import { Plus } from "lucide-react";
import { useState, useCallback } from "react";
import {
Container,
Form,
InputGroup,
Label,
Input,
Select,
CreateButton,
Table,
StatusBadge,
AccountTypeBadge,
Modal,
ToastComponent,
containerVariants,
formVariants
} from './CreateAccountStyles'; // Import from the styles file
function CreateAccount() {
const [form, setForm] = useState({
holderName: "",
accountType: "SAVINGS",
});
const [accounts, setAccounts] = useState([
{
name: "Kishan",
accountNumber: "12345678901",
balance: 1000.0,
creationDate: "2023-01-01",
accountType: "SAVINGS",
status: "ACTIVE",
},
{
name: "Tilak",
accountNumber: "09876543210",
balance: 2000.0,
creationDate: "2023-02-01",
accountType: "CURRENT",
status: "ACTIVE",
},
]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [toasts, setToasts] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [errors, setErrors] = useState({});
// Generate random 11-digit account number
const generateAccountNumber = () => {
return Math.floor(10000000000 + Math.random() * 90000000000).toString();
};
// Validate form
const validateForm = () => {
const newErrors = {};
if (!form.holderName.trim()) {
newErrors.holderName = "Account holder name is required";
} else if (form.holderName.trim().length < 2) {
newErrors.holderName = "Name must be at least 2 characters";
} else if (!/^[a-zA-Z\s]+$/.test(form.holderName.trim())) {
newErrors.holderName = "Name can only contain letters and spaces";
}
if (!form.accountType) {
newErrors.accountType = "Account type is required";
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
// Handle input changes
const handleInputChange = (e) => {
const { name, value } = e.target;
setForm(prev => ({
...prev,
[name]: value
}));
// Clear error when user starts typing
if (errors[name]) {
setErrors(prev => ({
...prev,
[name]: ""
}));
}
};
// Add toast notification
const addToast = useCallback((type, title, message) => {
const id = Date.now() + Math.random();
const newToast = { id, type, title, message };
setToasts(prev => [...prev, newToast]);
// Auto remove toast after 5 seconds
setTimeout(() => {
removeToast(id);
}, 5000);
}, []);
// Remove toast
const removeToast = useCallback((id) => {
setToasts(prev => prev.filter(toast => toast.id !== id));
}, []);
// Handle form submission
const handleSubmit = (e) => {
e.preventDefault();
if (!validateForm()) {
addToast('error', 'Validation Error', 'Please fix the errors and try again');
return;
}
setIsModalOpen(true);
};
// Handle account creation confirmation
const handleConfirmCreate = async () => {
setIsModalOpen(false);
setIsLoading(true);
try {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1500));
const newAccount = {
name: form.holderName.trim(),
accountNumber: generateAccountNumber(),
balance: 0.0,
creationDate: new Date().toISOString().split('T')[0],
accountType: form.accountType,
status: "ACTIVE",
};
setAccounts(prev => [...prev, newAccount]);
// Reset form
setForm({
holderName: "",
accountType: "SAVINGS",
});
addToast(
'success',
'Account Created Successfully!',
`Account ${newAccount.accountNumber} has been created for ${newAccount.name}`
);
} catch (error) {
addToast('error', 'Creation Failed', 'Failed to create account. Please try again.');
} finally {
setIsLoading(false);
}
};
// Format currency
const formatCurrency = (amount) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(amount);
};
// Format date
const formatDate = (dateString) => {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
};
return (
<>
<Container
variants={containerVariants}
initial="initial"
animate="animate"
>
<h2>Create New Account</h2>
<Form
variants={formVariants}
onSubmit={handleSubmit}
>
<InputGroup>
<Label htmlFor="holderName">Account Holder Name</Label>
<Input
id="holderName"
name="holderName"
type="text"
placeholder="Enter full name"
value={form.holderName}
onChange={handleInputChange}
required
autoComplete="name"
style={{
borderColor: errors.holderName ? '#ff6b6b' : undefined
}}
/>
{errors.holderName && (
<span style={{ color: '#ff6b6b', fontSize: '14px', marginTop: '4px' }}>
{errors.holderName}
</span>
)}
</InputGroup>
<InputGroup>
<Label htmlFor="accountType">Account Type</Label>
<Select
id="accountType"
name="accountType"
value={form.accountType}
onChange={handleInputChange}
required
>
<option value="SAVINGS">Savings Account</option>
<option value="CURRENT">Current Account</option>
<option value="SALARY">Salary Account</option>
</Select>
</InputGroup>
<CreateButton
type="submit"
disabled={isLoading}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<Plus size={18} />
{isLoading ? 'Creating...' : 'Create Account'}
</CreateButton>
</Form>
<Table>
<thead>
<tr>
<th>Account Holder</th>
<th>Account Number</th>
<th>Account Type</th>
<th>Balance</th>
<th>Creation Date</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{accounts.map((account, index) => (
<tr key={account.accountNumber}>
<td>{account.name}</td>
<td>
<code style={{
background: 'rgba(102, 126, 234, 0.1)',
padding: '4px 8px',
borderRadius: '6px',
fontSize: '14px',
fontWeight: '600'
}}>
{account.accountNumber}
</code>
</td>
<td>
<AccountTypeBadge type={account.accountType}>
{account.accountType}
</AccountTypeBadge>
</td>
<td style={{ fontWeight: '600', color: '#2d3748' }}>
{formatCurrency(account.balance)}
</td>
<td>{formatDate(account.creationDate)}</td>
<td>
<StatusBadge status={account.status}>
{account.status}
</StatusBadge>
</td>
</tr>
))}
</tbody>
</Table>
</Container>
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title="Confirm Account Creation"
message={`Are you sure you want to create a ${form.accountType.toLowerCase()} account for ${form.holderName}? This action cannot be undone.`}
onConfirm={handleConfirmCreate}
confirmText="Create Account"
cancelText="Cancel"
/>
<ToastComponent
toasts={toasts}
removeToast={removeToast}
/>
</>
);
}
export default CreateAccount;
Top comments (0)