forked from jamesp/sasa-membership
stuff changed:
- ui has been made 'kinda better' (after making it worse for a while lol - ESP rfid readers are now supported [ill upload the code for them in another repo later] - admin system has been secured a bit better and seems to be working well
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authService, User } from '../services/membershipService';
|
||||
import { useToast } from '../contexts/ToastContext';
|
||||
import { formatLondonDate } from '../utils/timezone';
|
||||
|
||||
interface ProfileMenuProps {
|
||||
userName: string;
|
||||
@@ -38,115 +40,55 @@ const ProfileMenu: React.FC<ProfileMenuProps> = ({ userName, user, onEditProfile
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
return new Date(dateString).toLocaleDateString('en-GB', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
});
|
||||
};
|
||||
|
||||
const dropdownStyle: React.CSSProperties = {
|
||||
position: 'absolute',
|
||||
top: '100%',
|
||||
right: 0,
|
||||
background: 'white',
|
||||
border: '1px solid #ddd',
|
||||
borderRadius: '4px',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
||||
minWidth: '280px',
|
||||
maxWidth: '320px',
|
||||
zIndex: 1000,
|
||||
};
|
||||
|
||||
const menuItemStyle: React.CSSProperties = {
|
||||
display: 'block',
|
||||
width: '100%',
|
||||
padding: '12px 16px',
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
textAlign: 'left',
|
||||
cursor: 'pointer',
|
||||
color: '#333',
|
||||
fontSize: '14px',
|
||||
};
|
||||
const formatDate = (dateString: string) => formatLondonDate(dateString);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ position: 'relative' }} ref={menuRef}>
|
||||
<div className="profile-menu" ref={menuRef}>
|
||||
<button
|
||||
className="profile-menu-trigger"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
color: 'white',
|
||||
cursor: 'pointer',
|
||||
fontSize: '16px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px'
|
||||
}}
|
||||
>
|
||||
<span>{userName}</span>
|
||||
<span style={{ fontSize: '12px' }}>▼</span>
|
||||
<span className="profile-menu-chevron">▼</span>
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div style={dropdownStyle}>
|
||||
{/* Profile Details Section */}
|
||||
<div className="profile-menu-dropdown">
|
||||
{user && (
|
||||
<div style={{
|
||||
padding: '16px',
|
||||
borderBottom: '1px solid #eee',
|
||||
backgroundColor: '#f9f9f9',
|
||||
borderRadius: '4px 4px 0 0'
|
||||
}}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
|
||||
<h4 style={{ margin: 0, fontSize: '14px', fontWeight: 'bold', color: '#333' }}>Profile Details</h4>
|
||||
<div className="profile-menu-summary">
|
||||
<div className="profile-menu-summary-head">
|
||||
<h4>Profile Details</h4>
|
||||
{onEditProfile && (
|
||||
<button
|
||||
className="profile-menu-edit"
|
||||
onClick={() => {
|
||||
onEditProfile();
|
||||
setIsOpen(false);
|
||||
}}
|
||||
style={{
|
||||
background: '#0066cc',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
padding: '4px 8px',
|
||||
borderRadius: '3px',
|
||||
cursor: 'pointer',
|
||||
fontSize: '11px',
|
||||
fontWeight: '500'
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ fontSize: '12px', color: '#555', lineHeight: '1.6' }}>
|
||||
<p style={{ margin: '4px 0' }}><strong>Name:</strong> {user.first_name} {user.last_name}</p>
|
||||
<p style={{ margin: '4px 0' }}><strong>Email:</strong> {user.email}</p>
|
||||
{user.phone && <p style={{ margin: '4px 0' }}><strong>Phone:</strong> {user.phone}</p>}
|
||||
{user.address && <p style={{ margin: '4px 0' }}><strong>Address:</strong> {user.address}</p>}
|
||||
<p style={{ margin: '4px 0' }}><strong>Member since:</strong> {formatDate(user.created_at)}</p>
|
||||
<div className="profile-menu-details">
|
||||
<p><strong>Name:</strong> {user.first_name} {user.last_name}</p>
|
||||
<p><strong>Email:</strong> {user.email}</p>
|
||||
{user.phone && <p><strong>Phone:</strong> {user.phone}</p>}
|
||||
{user.address && <p><strong>Address:</strong> {user.address}</p>}
|
||||
<p><strong>Member since:</strong> {formatDate(user.created_at)}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Menu Items */}
|
||||
<button
|
||||
style={{
|
||||
...menuItemStyle,
|
||||
borderRadius: user ? '0' : '4px 4px 0 0',
|
||||
borderTop: user ? '1px solid #eee' : 'none'
|
||||
}}
|
||||
className={`profile-menu-item ${user ? '' : 'first'}`}
|
||||
onClick={handleChangePassword}
|
||||
>
|
||||
Change Password
|
||||
</button>
|
||||
<button
|
||||
style={{ ...menuItemStyle, borderRadius: '0 0 4px 4px', borderTop: '1px solid #eee' }}
|
||||
className="profile-menu-item last"
|
||||
onClick={handleLogout}
|
||||
>
|
||||
Log Out
|
||||
@@ -167,6 +109,7 @@ interface ChangePasswordModalProps {
|
||||
}
|
||||
|
||||
const ChangePasswordModal: React.FC<ChangePasswordModalProps> = ({ onClose }) => {
|
||||
const toast = useToast();
|
||||
const [currentPassword, setCurrentPassword] = useState('');
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
@@ -195,7 +138,7 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = ({ onClose }) =>
|
||||
new_password: newPassword
|
||||
});
|
||||
|
||||
alert('Password changed successfully!');
|
||||
toast.success('Password changed successfully.');
|
||||
onClose();
|
||||
} catch (error: any) {
|
||||
setError(error.response?.data?.detail || 'Failed to change password');
|
||||
@@ -254,33 +197,19 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = ({ onClose }) =>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '10px', marginTop: '16px' }}>
|
||||
<div className="modal-button-row">
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
disabled={loading}
|
||||
style={{
|
||||
padding: '10px 20px',
|
||||
backgroundColor: '#6c757d',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
style={{
|
||||
padding: '10px 20px',
|
||||
backgroundColor: '#28a745',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
{loading ? 'Changing...' : 'Change Password'}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user