diff --git a/frontend/src/App.css b/frontend/src/App.css index c5baccf..7840182 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -180,11 +180,23 @@ body { .dashboard-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + grid-template-columns: 1fr; gap: 20px; margin-top: 20px; } +/* Desktop view: side-by-side layout */ +@media (min-width: 769px) { + .dashboard-grid { + grid-template-columns: 1fr 1fr; + align-items: start; + } + + .dashboard-grid > .card { + margin-bottom: 0; + } +} + /* Mobile responsive adjustments */ @media (max-width: 768px) { .dashboard-grid { @@ -449,3 +461,167 @@ body { border-color: #c82333; color: white !important; } + +/* Events Container Styles */ +.events-container { + display: flex; + flex-direction: column; + gap: 16px; +} + +.event-card { + border: 1px solid #ddd; + border-radius: 8px; + padding: 16px; + background-color: #f9f9f9; +} + +.event-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 16px; + margin-bottom: 12px; +} + +.event-info { + flex: 1; + min-width: 0; +} + +.event-title { + margin: 0 0 4px 0; + color: #0066cc; + font-size: 18px; + word-wrap: break-word; +} + +.event-datetime { + margin: 0; + font-size: 14px; + color: #666; +} + +.event-location { + margin: 4px 0 0 0; + font-size: 14px; + color: #666; +} + +.event-rsvp-buttons { + display: flex; + gap: 8px; + flex-shrink: 0; +} + +.rsvp-btn { + font-size: 12px; + padding: 8px 16px; + border: 2px solid #adb5bd; + border-radius: 4px; + background-color: transparent; + color: #6c757d; + cursor: pointer; + font-weight: normal; + transition: all 0.3s ease; + white-space: nowrap; +} + +.rsvp-btn:hover:not(:disabled) { + opacity: 0.8; +} + +.rsvp-btn:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.rsvp-btn.active { + font-weight: bold; + transform: scale(1.05); +} + +.rsvp-btn:not(.active) { + opacity: 0.5; + filter: grayscale(50%); +} + +.rsvp-btn-attending.active { + border: 3px solid #28a745; + background-color: #28a745; + color: white; + box-shadow: 0 4px 8px rgba(40, 167, 69, 0.3); +} + +.rsvp-btn-maybe.active { + border: 3px solid #ffc107; + background-color: #ffc107; + color: #212529; + box-shadow: 0 4px 8px rgba(255, 193, 7, 0.3); +} + +.rsvp-btn-not-attending.active { + border: 3px solid #dc3545; + background-color: #dc3545; + color: white; + box-shadow: 0 4px 8px rgba(220, 53, 69, 0.3); +} + +.event-description { + margin: 0; + font-size: 14px; + line-height: 1.4; +} + +.event-rsvp-status { + margin-top: 12px; + padding: 8px 12px; + border-radius: 4px; + font-size: 12px; +} + +.event-rsvp-status.attending { + background-color: #d4edda; + border: 1px solid #c3e6cb; + color: #155724; +} + +.event-rsvp-status.maybe { + background-color: #fff3cd; + border: 1px solid #ffeaa7; + color: #856404; +} + +.event-rsvp-status.not_attending { + background-color: #f8d7da; + border: 1px solid #f5c6cb; + color: #721c24; +} + +/* Mobile responsive adjustments for events */ +@media (max-width: 768px) { + .event-header { + flex-direction: column; + align-items: stretch; + } + + .event-rsvp-buttons { + flex-direction: column; + width: 100%; + gap: 8px; + } + + .rsvp-btn { + width: 100%; + padding: 12px 16px; + font-size: 14px; + } + + .event-title { + font-size: 16px; + } + + .event-card { + padding: 12px; + } +} diff --git a/frontend/src/components/ProfileMenu.tsx b/frontend/src/components/ProfileMenu.tsx index 81736eb..708e64b 100644 --- a/frontend/src/components/ProfileMenu.tsx +++ b/frontend/src/components/ProfileMenu.tsx @@ -1,13 +1,15 @@ import React, { useState, useRef, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { authService } from '../services/membershipService'; +import { authService, User } from '../services/membershipService'; interface ProfileMenuProps { userName: string; userRole: string; + user?: User | null; + onEditProfile?: () => void; } -const ProfileMenu: React.FC = ({ userName, userRole }) => { +const ProfileMenu: React.FC = ({ userName, userRole, user, onEditProfile }) => { const [isOpen, setIsOpen] = useState(false); const [showChangePassword, setShowChangePassword] = useState(false); const menuRef = useRef(null); @@ -36,6 +38,14 @@ const ProfileMenu: React.FC = ({ userName, userRole }) => { 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%', @@ -44,7 +54,8 @@ const ProfileMenu: React.FC = ({ userName, userRole }) => { border: '1px solid #ddd', borderRadius: '4px', boxShadow: '0 2px 8px rgba(0,0,0,0.1)', - minWidth: '160px', + minWidth: '280px', + maxWidth: '320px', zIndex: 1000, }; @@ -82,10 +93,52 @@ const ProfileMenu: React.FC = ({ userName, userRole }) => { {isOpen && (
+ {/* Profile Details Section */} + {user && ( +
+
+

Profile Details

+ {onEditProfile && ( + + )} +
+
+

Name: {user.first_name} {user.last_name}

+

Email: {user.email}

+ {user.phone &&

Phone: {user.phone}

} + {user.address &&

Address: {user.address}

} +

Member since: {formatDate(user.created_at)}

+
+
+ )} + + {/* Menu Items */} {userRole === 'super_admin' && ( <> -
-

Name: {user?.first_name} {user?.last_name}

-

Email: {user?.email}

- {user?.phone &&

Phone: {user.phone}

} - {user?.address &&

Address: {user.address}

} -

Registered since: {user && formatDate(user.created_at)}

- - {/* Membership Card */} {activeMembership ? (
@@ -408,6 +401,67 @@ const Dashboard: React.FC = () => {
)} + + {/* Upcoming Events */} +
+

Upcoming Events

+ {upcomingEvents.length > 0 ? ( +
+ {upcomingEvents.map(event => ( +
+
+
+

{event.title}

+

+ {formatDate(event.event_date)} at {event.event_time} +

+ {event.location && ( +

+ 📍 {event.location} +

+ )} +
+
+ + + +
+
+ {event.description && ( +

+ {event.description} +

+ )} + {event.rsvp_status && ( +
+ Your RSVP: {event.rsvp_status.replace('_', ' ')} +
+ )} +
+ ))} +
+ ) : ( +

No upcoming events at this time.

+ )} +
{/* Payment History */} @@ -445,125 +499,6 @@ const Dashboard: React.FC = () => { )} - {/* Upcoming Events */} -
-

Upcoming Events

- {upcomingEvents.length > 0 ? ( -
- {upcomingEvents.map(event => ( -
-
-
-

{event.title}

-

- {formatDate(event.event_date)} at {event.event_time} -

- {event.location && ( -

- 📍 {event.location} -

- )} -
-
- - - -
-
- {event.description && ( -

- {event.description} -

- )} - {event.rsvp_status && ( -
- Your RSVP: {event.rsvp_status.replace('_', ' ')} -
- )} -
- ))} -
- ) : ( -

No upcoming events at this time.

- )} -
- {/* Admin Section */} {(user?.role === 'admin' || user?.role === 'super_admin') && (