Mobile improvements
This commit is contained in:
@@ -79,7 +79,7 @@ body {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 14px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group input:focus,
|
.form-group input:focus,
|
||||||
@@ -185,6 +185,70 @@ body {
|
|||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile responsive adjustments */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.dashboard-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar h1 {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make tables responsive */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 600px; /* Ensure minimum width for readability */
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auth pages mobile adjustments */
|
||||||
|
.auth-container {
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 20px;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card {
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Welcome section mobile adjustments */
|
||||||
|
.welcome-section {
|
||||||
|
max-width: 100% !important;
|
||||||
|
padding: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-section h1 {
|
||||||
|
font-size: 1.8rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form grid mobile adjustments */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
form[style*="grid-template-columns"] {
|
||||||
|
grid-template-columns: 1fr !important;
|
||||||
|
gap: 16px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.status-badge {
|
.status-badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
@@ -255,7 +319,7 @@ body {
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 14px;
|
font-size: 16px;
|
||||||
color: #333;
|
color: #333;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,30 +301,32 @@ const Dashboard: React.FC = () => {
|
|||||||
<div className="card" style={{ marginTop: '20px' }}>
|
<div className="card" style={{ marginTop: '20px' }}>
|
||||||
<h3 style={{ marginBottom: '16px' }}>Payment History</h3>
|
<h3 style={{ marginBottom: '16px' }}>Payment History</h3>
|
||||||
{payments.length > 0 ? (
|
{payments.length > 0 ? (
|
||||||
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
<div className="table-container">
|
||||||
<thead>
|
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
||||||
<tr style={{ borderBottom: '2px solid #ddd' }}>
|
<thead>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Date</th>
|
<tr style={{ borderBottom: '2px solid #ddd' }}>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Amount</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Date</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Method</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Amount</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Status</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Method</th>
|
||||||
</tr>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Status</th>
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{payments.map(payment => (
|
|
||||||
<tr key={payment.id} style={{ borderBottom: '1px solid #eee' }}>
|
|
||||||
<td style={{ padding: '12px' }}>{payment.payment_date ? formatDate(payment.payment_date) : 'Pending'}</td>
|
|
||||||
<td style={{ padding: '12px' }}>£{payment.amount.toFixed(2)}</td>
|
|
||||||
<td style={{ padding: '12px' }}>{payment.payment_method}</td>
|
|
||||||
<td style={{ padding: '12px' }}>
|
|
||||||
<span className={`status-badge ${getStatusClass(payment.status)}`}>
|
|
||||||
{payment.status.toUpperCase()}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{payments.map(payment => (
|
||||||
|
<tr key={payment.id} style={{ borderBottom: '1px solid #eee' }}>
|
||||||
|
<td style={{ padding: '12px' }}>{payment.payment_date ? formatDate(payment.payment_date) : 'Pending'}</td>
|
||||||
|
<td style={{ padding: '12px' }}>£{payment.amount.toFixed(2)}</td>
|
||||||
|
<td style={{ padding: '12px' }}>{payment.payment_method}</td>
|
||||||
|
<td style={{ padding: '12px' }}>
|
||||||
|
<span className={`status-badge ${getStatusClass(payment.status)}`}>
|
||||||
|
{payment.status.toUpperCase()}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p style={{ color: '#666' }}>No payment history available.</p>
|
<p style={{ color: '#666' }}>No payment history available.</p>
|
||||||
)}
|
)}
|
||||||
@@ -339,41 +341,43 @@ const Dashboard: React.FC = () => {
|
|||||||
{allPayments.filter(p => p.status === 'pending').length > 0 && (
|
{allPayments.filter(p => p.status === 'pending').length > 0 && (
|
||||||
<div style={{ marginBottom: '20px' }}>
|
<div style={{ marginBottom: '20px' }}>
|
||||||
<h4 style={{ marginBottom: '12px' }}>Pending Payments</h4>
|
<h4 style={{ marginBottom: '12px' }}>Pending Payments</h4>
|
||||||
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
<div className="table-container">
|
||||||
<thead>
|
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
||||||
<tr style={{ borderBottom: '2px solid #ddd' }}>
|
<thead>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>User</th>
|
<tr style={{ borderBottom: '2px solid #ddd' }}>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Amount</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>User</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Method</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Amount</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Membership</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Method</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Actions</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Membership</th>
|
||||||
</tr>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Actions</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
{allPayments.filter(p => p.status === 'pending').map(payment => {
|
<tbody>
|
||||||
const membership = allMemberships.find(m => m.id === payment.membership_id);
|
{allPayments.filter(p => p.status === 'pending').map(payment => {
|
||||||
return (
|
const membership = allMemberships.find(m => m.id === payment.membership_id);
|
||||||
<tr key={payment.id} style={{ borderBottom: '1px solid #eee' }}>
|
return (
|
||||||
<td style={{ padding: '12px' }}>{getUserName(payment.user_id)}</td>
|
<tr key={payment.id} style={{ borderBottom: '1px solid #eee' }}>
|
||||||
<td style={{ padding: '12px' }}>£{payment.amount.toFixed(2)}</td>
|
<td style={{ padding: '12px' }}>{getUserName(payment.user_id)}</td>
|
||||||
<td style={{ padding: '12px' }}>{payment.payment_method}</td>
|
<td style={{ padding: '12px' }}>£{payment.amount.toFixed(2)}</td>
|
||||||
<td style={{ padding: '12px' }}>
|
<td style={{ padding: '12px' }}>{payment.payment_method}</td>
|
||||||
{membership ? `${membership.tier.name} (${membership.status})` : 'N/A'}
|
<td style={{ padding: '12px' }}>
|
||||||
</td>
|
{membership ? `${membership.tier.name} (${membership.status})` : 'N/A'}
|
||||||
<td style={{ padding: '12px' }}>
|
</td>
|
||||||
<button
|
<td style={{ padding: '12px' }}>
|
||||||
className="btn btn-primary"
|
<button
|
||||||
onClick={() => handleApprovePayment(payment.id, payment.membership_id || undefined)}
|
className="btn btn-primary"
|
||||||
style={{ fontSize: '12px', padding: '6px 12px' }}
|
onClick={() => handleApprovePayment(payment.id, payment.membership_id || undefined)}
|
||||||
>
|
style={{ fontSize: '12px', padding: '6px 12px' }}
|
||||||
Approve
|
>
|
||||||
</button>
|
Approve
|
||||||
</td>
|
</button>
|
||||||
</tr>
|
</td>
|
||||||
);
|
</tr>
|
||||||
})}
|
);
|
||||||
</tbody>
|
})}
|
||||||
</table>
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -381,30 +385,32 @@ const Dashboard: React.FC = () => {
|
|||||||
{allMemberships.filter(m => m.status === 'pending').length > 0 && (
|
{allMemberships.filter(m => m.status === 'pending').length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<h4 style={{ marginBottom: '12px' }}>Pending Memberships</h4>
|
<h4 style={{ marginBottom: '12px' }}>Pending Memberships</h4>
|
||||||
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
<div className="table-container">
|
||||||
<thead>
|
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
||||||
<tr style={{ borderBottom: '2px solid #ddd' }}>
|
<thead>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>User</th>
|
<tr style={{ borderBottom: '2px solid #ddd' }}>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Tier</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>User</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Start Date</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Tier</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Status</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Start Date</th>
|
||||||
</tr>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Status</th>
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{allMemberships.filter(m => m.status === 'pending').map(membership => (
|
|
||||||
<tr key={membership.id} style={{ borderBottom: '1px solid #eee' }}>
|
|
||||||
<td style={{ padding: '12px' }}>{getUserName(membership.user_id)}</td>
|
|
||||||
<td style={{ padding: '12px' }}>{membership.tier.name}</td>
|
|
||||||
<td style={{ padding: '12px' }}>{formatDate(membership.start_date)}</td>
|
|
||||||
<td style={{ padding: '12px' }}>
|
|
||||||
<span className={`status-badge ${getStatusClass(membership.status)}`}>
|
|
||||||
{membership.status.toUpperCase()}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{allMemberships.filter(m => m.status === 'pending').map(membership => (
|
||||||
|
<tr key={membership.id} style={{ borderBottom: '1px solid #eee' }}>
|
||||||
|
<td style={{ padding: '12px' }}>{getUserName(membership.user_id)}</td>
|
||||||
|
<td style={{ padding: '12px' }}>{membership.tier.name}</td>
|
||||||
|
<td style={{ padding: '12px' }}>{formatDate(membership.start_date)}</td>
|
||||||
|
<td style={{ padding: '12px' }}>
|
||||||
|
<span className={`status-badge ${getStatusClass(membership.status)}`}>
|
||||||
|
{membership.status.toUpperCase()}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -437,78 +443,80 @@ const Dashboard: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
<div className="table-container">
|
||||||
<thead>
|
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
||||||
<tr style={{ borderBottom: '2px solid #ddd' }}>
|
<thead>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Name</th>
|
<tr style={{ borderBottom: '2px solid #ddd' }}>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Email</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Name</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Role</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Email</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Status</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Role</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Joined</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Status</th>
|
||||||
<th style={{ padding: '12px', textAlign: 'left' }}>Actions</th>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Joined</th>
|
||||||
</tr>
|
<th style={{ padding: '12px', textAlign: 'left' }}>Actions</th>
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{filteredUsers.map(u => (
|
|
||||||
<tr
|
|
||||||
key={u.id}
|
|
||||||
style={{ borderBottom: '1px solid #eee', cursor: 'pointer' }}
|
|
||||||
onClick={() => handleUserClick(u)}
|
|
||||||
>
|
|
||||||
<td style={{ padding: '12px' }}>{u.first_name} {u.last_name}</td>
|
|
||||||
<td style={{ padding: '12px' }}>{u.email}</td>
|
|
||||||
<td style={{ padding: '12px' }}>
|
|
||||||
<span style={{
|
|
||||||
backgroundColor: u.role === 'super_admin' ? '#dc3545' :
|
|
||||||
u.role === 'admin' ? '#ffc107' : '#28a745',
|
|
||||||
color: u.role === 'member' ? 'white' : 'black',
|
|
||||||
padding: '4px 8px',
|
|
||||||
borderRadius: '4px',
|
|
||||||
fontSize: '12px',
|
|
||||||
fontWeight: 'bold'
|
|
||||||
}}>
|
|
||||||
{u.role.toUpperCase()}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td style={{ padding: '12px' }}>
|
|
||||||
<span className={`status-badge ${u.is_active ? 'status-active' : 'status-expired'}`}>
|
|
||||||
{u.is_active ? 'ACTIVE' : 'INACTIVE'}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td style={{ padding: '12px' }}>{formatDate(u.created_at)}</td>
|
|
||||||
<td style={{ padding: '12px' }}>
|
|
||||||
{u.role === 'member' && (
|
|
||||||
<button
|
|
||||||
className="btn btn-primary"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation(); // Prevent row click
|
|
||||||
handleUpdateUserRole(u.id, 'admin');
|
|
||||||
}}
|
|
||||||
style={{ fontSize: '12px', padding: '4px 8px', marginRight: '4px' }}
|
|
||||||
>
|
|
||||||
Make Admin
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{u.role === 'admin' && u.id !== user?.id && (
|
|
||||||
<button
|
|
||||||
className="btn btn-secondary"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation(); // Prevent row click
|
|
||||||
handleUpdateUserRole(u.id, 'member');
|
|
||||||
}}
|
|
||||||
style={{ fontSize: '12px', padding: '4px 8px' }}
|
|
||||||
>
|
|
||||||
Remove Admin
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{u.role === 'super_admin' && (
|
|
||||||
<span style={{ fontSize: '12px', color: '#666' }}>Super Admin</span>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{filteredUsers.map(u => (
|
||||||
|
<tr
|
||||||
|
key={u.id}
|
||||||
|
style={{ borderBottom: '1px solid #eee', cursor: 'pointer' }}
|
||||||
|
onClick={() => handleUserClick(u)}
|
||||||
|
>
|
||||||
|
<td style={{ padding: '12px' }}>{u.first_name} {u.last_name}</td>
|
||||||
|
<td style={{ padding: '12px' }}>{u.email}</td>
|
||||||
|
<td style={{ padding: '12px' }}>
|
||||||
|
<span style={{
|
||||||
|
backgroundColor: u.role === 'super_admin' ? '#dc3545' :
|
||||||
|
u.role === 'admin' ? '#ffc107' : '#28a745',
|
||||||
|
color: u.role === 'member' ? 'white' : 'black',
|
||||||
|
padding: '4px 8px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
fontSize: '12px',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}}>
|
||||||
|
{u.role.toUpperCase()}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td style={{ padding: '12px' }}>
|
||||||
|
<span className={`status-badge ${u.is_active ? 'status-active' : 'status-expired'}`}>
|
||||||
|
{u.is_active ? 'ACTIVE' : 'INACTIVE'}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td style={{ padding: '12px' }}>{formatDate(u.created_at)}</td>
|
||||||
|
<td style={{ padding: '12px' }}>
|
||||||
|
{u.role === 'member' && (
|
||||||
|
<button
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation(); // Prevent row click
|
||||||
|
handleUpdateUserRole(u.id, 'admin');
|
||||||
|
}}
|
||||||
|
style={{ fontSize: '12px', padding: '4px 8px', marginRight: '4px' }}
|
||||||
|
>
|
||||||
|
Make Admin
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{u.role === 'admin' && u.id !== user?.id && (
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation(); // Prevent row click
|
||||||
|
handleUpdateUserRole(u.id, 'member');
|
||||||
|
}}
|
||||||
|
style={{ fontSize: '12px', padding: '4px 8px' }}
|
||||||
|
>
|
||||||
|
Remove Admin
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{u.role === 'super_admin' && (
|
||||||
|
<span style={{ fontSize: '12px', color: '#666' }}>Super Admin</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const Login: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="auth-container" style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: '40px', padding: '20px' }}>
|
<div className="auth-container" style={{ gap: '40px', padding: '20px' }}>
|
||||||
<div className="welcome-section" style={{
|
<div className="welcome-section" style={{
|
||||||
flex: '1',
|
flex: '1',
|
||||||
maxWidth: '400px',
|
maxWidth: '400px',
|
||||||
|
|||||||
Reference in New Issue
Block a user