From 92a1744030847a86437b1c4c326cba0f3f6ba916 Mon Sep 17 00:00:00 2001 From: TheMaddax Date: Tue, 25 Mar 2025 11:13:52 -0500 Subject: [PATCH] Admin dashboard updates. --- TECH_STACK | 8 +- backend/package.json | 2 +- cline_docs/activeContext.md | 85 +-- cline_docs/productContext.md | 270 ++++---- cline_docs/progress.md | 183 ++++-- cline_docs/systemPatterns.md | 341 ++++++---- cline_docs/techContext.md | 229 ++++--- frontend/src/app/admin/content/page.tsx | 459 +++++++++++++ frontend/src/app/admin/dashboard/layout.tsx | 55 ++ frontend/src/app/admin/dashboard/page.tsx | 266 ++++++++ frontend/src/app/admin/documents/page.tsx | 491 ++++++++++++++ frontend/src/app/admin/events/page.tsx | 336 ++++++++++ frontend/src/app/admin/layout.tsx | 19 + frontend/src/app/admin/login/page.tsx | 152 +++++ frontend/src/app/admin/members/page.tsx | 456 +++++++++++++ frontend/src/app/admin/page.tsx | 9 + frontend/src/app/admin/settings/page.tsx | 621 ++++++++++++++++++ frontend/src/app/admin/videos/page.tsx | 326 +++++++++ frontend/src/app/api/auth/login/route.ts | 74 +++ .../src/components/admin/AdminSidebar.tsx | 131 ++++ planned_implementation.txt | 6 +- 21 files changed, 4059 insertions(+), 460 deletions(-) create mode 100644 frontend/src/app/admin/content/page.tsx create mode 100644 frontend/src/app/admin/dashboard/layout.tsx create mode 100644 frontend/src/app/admin/dashboard/page.tsx create mode 100644 frontend/src/app/admin/documents/page.tsx create mode 100644 frontend/src/app/admin/events/page.tsx create mode 100644 frontend/src/app/admin/layout.tsx create mode 100644 frontend/src/app/admin/login/page.tsx create mode 100644 frontend/src/app/admin/members/page.tsx create mode 100644 frontend/src/app/admin/page.tsx create mode 100644 frontend/src/app/admin/settings/page.tsx create mode 100644 frontend/src/app/admin/videos/page.tsx create mode 100644 frontend/src/app/api/auth/login/route.ts create mode 100644 frontend/src/components/admin/AdminSidebar.tsx diff --git a/TECH_STACK b/TECH_STACK index 24a8be9..524334a 100644 --- a/TECH_STACK +++ b/TECH_STACK @@ -6,13 +6,13 @@ - React Router DOM 7 - Tailwind CSS 4.0 (CSS-first configuration with @theme directives, 182x faster builds) - Framer Motion 11 -- React Icons 5.4 -- React Simple Maps 4.0 (beta) -- React Intersection Observer 9.13 +- React Icons 5.5.0 +- React Simple Maps 3.0.0 +- React Intersection Observer 9.16.0 - Next.js 15.2.3 (includes security patches for CVE-2025-29927) ### Backend -- Node.js with Express 4.21 +- Node.js with Express 4.18.2 - TypeScript 5.8 - Nodemailer 6.9 for email handling - CORS for cross-origin resource sharing diff --git a/backend/package.json b/backend/package.json index af34e08..b3e18e4 100644 --- a/backend/package.json +++ b/backend/package.json @@ -13,7 +13,7 @@ "bcrypt": "^5.1.1", "cors": "^2.8.5", "dotenv": "^16.4.0", - "express": "^4.21.0", + "express": "^4.18.2", "express-rate-limit": "^7.1.5", "helmet": "^7.1.0", "jsonwebtoken": "^9.0.2", diff --git a/cline_docs/activeContext.md b/cline_docs/activeContext.md index 17cf9e4..0882df6 100644 --- a/cline_docs/activeContext.md +++ b/cline_docs/activeContext.md @@ -1,50 +1,51 @@ -# Active Context: OCD Website Implementation Phase 1 +# Active Context: OCD Website Implementation Phase 3-4 Transition ## What I'm Working On Now -- Implemented Phase 1 of the OCD website based on the planned implementation -- Created key public-facing pages (Home, About, Contact) with full accessibility -- Set up core components like Navigation, Footer, Hero, and ContactForm with WCAG 2.2 AA compliance -- Established MongoDB schema validation and database models -- Implemented JWT-based authentication middleware with RBAC -- Created Docker configuration with security best practices +- Completing Phase 3 of the OCD website development plan +- Finalizing admin interface implementation +- Setting up connections between frontend UI and backend APIs +- Preparing for Phase 4 (accessibility features and refinement) +- Adding API integration for CRUD operations ## Recent Changes -- Created the complete directory structure following atomic design principles -- Set up core configuration files: - - Docker Compose with multi-stage builds, resource limits, and security - - Frontend/backend Dockerfiles with non-root users - - MongoDB initialization scripts with schema validation - - Next.js configuration with security headers - - Tailwind CSS with CSS-first @theme configuration - - Nginx configuration with security headers -- Installed dependencies for both frontend and backend -- Implemented responsive Navigation component with keyboard accessibility -- Added Footer component with site map and accessibility options -- Created Hero component with animations and responsive design -- Built Contact form with validation and ARIA attributes -- Implemented Home, About, and Contact pages with accessibility features -- Created Video Player component with transcript display options -- Set up JWT authentication middleware for admin dashboard +- Implemented comprehensive admin dashboard system: + - Created central dashboard with statistics and quick actions + - Built out events management with filtering and CRUD UI + - Implemented members management with bulk actions and status tracking + - Developed video management with accessibility indicators + - Added document repository with visibility controls + - Created content management with WYSIWYG editor preview + - Added settings interface with site, email, and membership options + +- Major improvements to frontend architecture: + - Implemented responsive layouts for all admin interfaces + - Used TypeScript for strongly-typed components + - Created reusable filter, table, and card components + - Maintained consistent UI patterns across admin sections + - Ensured all interfaces follow accessibility guidelines ## Next Steps -1. Complete remaining public-facing pages: - - Events page with calendar component - - Membership information page - - Donation page with Zeffy integration - - Accessibility statement page -2. Begin admin dashboard implementation: - - Create authentication flow - - Implement dashboard layout - - Set up protected routes - - Create admin forms for content management -3. Implement event management system -4. Set up video upload and management functionality -5. Create membership tracking system with expiration notifications +1. Complete backend API integrations: + - Connect admin UI components to backend endpoints + - Add real data loading with loading states + - Implement error handling for API requests + - Set up client-side data validation +2. Implement remaining admin features: + - Add form handlers for CRUD operations + - Implement event recurrence functionality + - Create media upload components + - Add user notification system +3. Deploy staging environment: + - Set up Docker containers for testing + - Configure environment variables + - Enable SSL certificates + - Test on multiple devices and browsers ## Special Considerations -- Maintain WCAG 2.2 AA compliance throughout all components and pages -- Focus on creating components that support deaf and DeafBlind users -- All videos must have thumbnails, captions, and full transcripts -- Ensure keyboard navigation works properly throughout the site -- Follow database schema validation using $jsonSchema for data integrity -- Apply security best practices in all aspects of the implementation +- Ensure strict authentication for all admin routes +- Keep all forms accessible and keyboard navigable +- Ensure admin interfaces work well on mobile devices +- All uploaded content must support WCAG 2.2 AA compliance +- Maintain clear separation between public and admin areas +- Add proper validation for all form inputs +- Implement comprehensive error handling diff --git a/cline_docs/productContext.md b/cline_docs/productContext.md index 60b65b3..5628b3b 100644 --- a/cline_docs/productContext.md +++ b/cline_docs/productContext.md @@ -1,159 +1,167 @@ -# Product Context: Olathe Club of the Deaf (OCD) Website +# Product Context: Olathe Club of the Deaf Website -## Why This Project Exists +## Purpose -The Olathe Club of the Deaf (OCD) website serves as a digital hub for the deaf community in Olathe, Kansas. The project exists to: +The Olathe Club of the Deaf (OCD) website serves as the official digital presence for the Olathe Club of the Deaf, a community organization serving deaf and hard-of-hearing individuals in Olathe, Kansas. The website aims to: -1. **Improve Accessibility**: Create a fully accessible digital presence that serves deaf, hard-of-hearing, and DeafBlind community members -2. **Streamline Operations**: Automate administrative tasks like membership tracking and event management -3. **Increase Visibility**: Raise awareness of OCD's activities, events, and services in the broader community -4. **Preserve History**: Document and showcase the organization's rich history since 1975 -5. **Facilitate Communication**: Provide an accessible platform for members to stay informed about club activities -6. **Support Governance**: Make organizational bylaws, minutes, and board information readily available +1. **Provide Accessible Information**: Deliver critical information about the club's activities, mission, and resources in a fully accessible format. -The website addresses the lack of a modern, accessible, and functional digital presence for this important community organization. +2. **Facilitate Community Engagement**: Enable members and potential members to discover and participate in club events, meetings, and initiatives. + +3. **Streamline Club Administration**: Provide club leadership with tools to manage membership, events, and content without technical expertise. + +4. **Promote Deaf Culture**: Showcase the richness of deaf culture and the club's contributions to the local deaf community. + +5. **Support Organizational Growth**: Attract new members, volunteers, and donors while retaining existing community connections. ## Problems Solved +The OCD website addresses several key challenges: + ### For Community Members -- **Information Gap**: Previously, community members had difficulty accessing up-to-date information about events, meetings, and organizational news -- **Membership Barriers**: The old paper-based membership process was cumbersome and inaccessible -- **Resource Access**: Community resources, historical documents, and educational materials were not easily available -- **Event Awareness**: Many community members missed events due to inconsistent communication -### For Organization Leaders -- **Administrative Burden**: Manual membership tracking and event management consumed valuable volunteer time -- **Communication Challenges**: Reaching all members efficiently was difficult and inconsistent -- **Donation Limitations**: No streamlined way to accept donations and support -- **Membership Tracking**: Difficulty managing membership statuses, expirations, and renewals -- **Content Management**: No easy way to update website content without technical expertise +- **Information Access Barriers**: Many deaf individuals face barriers to information that is primarily delivered through audio channels. The website provides visual and text-based information delivery. -### For Website Visitors -- **Accessibility Issues**: Previous digital presence was not fully accessible to deaf, hard-of-hearing, and DeafBlind users -- **Content Freshness**: Information was often outdated or incomplete -- **Usability Problems**: Navigation and information architecture were confusing -- **Mobile Experience**: Previous site was not responsive or mobile-friendly -- **Visual Communication**: Lack of ASL videos and visual elements essential for deaf users +- **Community Discovery**: Finding local deaf community events and resources can be challenging. The website centralizes information about club activities and resources. -## How It Should Work +- **ASL-First Communication**: Many deaf individuals prefer ASL as their primary language. The website incorporates ASL videos alongside text content. -### Core User Journeys +- **Digital Participation Gap**: The website bridges the gap between online and in-person participation for the deaf community. -#### Community Member Journey -1. Discovers the OCD website through search or referral -2. Browses upcoming events and community information -3. Learns about membership benefits and application process -4. Completes membership application and submits payment -5. Receives membership confirmation and welcome materials -6. Regularly checks website for events and organizational updates -7. Participates in events and community activities -8. Renews membership when notified of expiration +### For Club Administrators -#### Organization Administrator Journey -1. Logs in to secure admin dashboard -2. Manages membership data and tracks renewals -3. Creates and updates event information -4. Publishes content updates to public pages -5. Uploads meeting minutes and organizational documents -6. Reviews and responds to contact form submissions -7. Generates membership and activity reports -8. Manages ASL videos and accessibility features +- **Administrative Burden**: Tracking memberships, organizing events, and distributing information manually is time-consuming. The admin system automates these tasks. -#### Website Visitor Journey -1. Visits website to learn about OCD organization -2. Explores information about deaf community in Olathe -3. Views upcoming events calendar -4. Watches accessible ASL videos with captions/transcripts -5. Contacts the organization through accessible form -6. Makes donations to support the organization -7. Shares content with others via social media +- **Technological Barriers**: Club leaders may not have technical expertise. The admin interface provides accessible tools for non-technical users. -### Key Features +- **Content Updates**: Maintaining current information was historically difficult. The CMS allows for easy content updates. -#### Public-Facing Features -- **Home Page**: Showcases organization mission, featured events, and announcements -- **About Section**: History, mission statement, board members with photos and bios -- **Events Calendar**: Interactive calendar with filtering capabilities and event details -- **Membership Information**: Benefits, types, pricing, and application process -- **Contact Form**: Accessible contact methods with form validation -- **Donation Integration**: Zeffy widget for secure online donations -- **Document Repository**: Accessible bylaws, minutes, and organizational documents -- **ASL Video Library**: Captioned and transcribed ASL videos about the organization +- **Resource Distribution**: Sharing meeting minutes, bylaws, and other documents was inefficient. The document repository centralizes these resources. -#### Administration Features -- **Member Management**: Database of members with search, filtering, and export -- **Event Management**: Create, edit, and publish events with recurrence options -- **Content Management**: WYSIWYG editor for page content updates -- **Document Management**: Upload and organize meeting minutes and documents -- **Video Management**: Upload ASL videos with caption and transcript support -- **Contact Management**: Review and respond to contact form submissions -- **Membership Notifications**: Automated email system for membership expirations -- **User Management**: Admin account control with secure authentication +### For Public Awareness -### User Types & Needs +- **Deaf Awareness**: Many hearing people lack understanding of deaf culture. The website educates the broader community. -#### Deaf Community Members -- ASL videos with captions and transcripts -- Visual design that minimizes text-heavy content -- Clear, simple navigation -- High contrast visual elements -- Mobile accessibility for on-the-go access -- Event information in visual formats +- **Resource Visibility**: Community resources for deaf individuals were not widely known. The website increases visibility of these resources. -#### DeafBlind Users -- Screen reader compatibility -- High contrast mode -- Simplified content structure -- Keyboard navigation support -- Text descriptions of all visual elements -- Reduced motion option +## Target Users -#### Organization Board Members -- Secure access to administrative features -- Easy content management without technical skills -- Membership data visualization -- Export capabilities for reports -- Notification management +### Primary Users -#### Potential Members & Community Supporters -- Clear information about the organization -- Simple donation process -- Easy-to-understand membership benefits -- Mobile-friendly experience -- Social sharing capabilities +1. **Current OCD Members** + - Age range: 18-80+ + - Technical proficiency: Varies widely + - Need: Access event information, membership details, club updates -## Special Considerations +2. **Club Leadership & Board Members** + - Role: Volunteer administrators + - Technical proficiency: Basic to intermediate + - Need: Manage content, track memberships, coordinate events -### Accessibility Requirements -- WCAG 2.2 AA compliance as minimum standard -- ASL videos must have captions and transcripts -- All functionality must be keyboard accessible -- Screen reader testing and optimization -- Color contrast ratios ≥ 4.5:1 for normal text -- Support for text resizing up to 200% without loss of content -- Reduced motion preferences respected -- Focus indicators clear and visible +3. **Prospective Members** + - Deaf or hard-of-hearing individuals in Olathe area + - May be new to the area or community + - Need: Learn about the club, membership benefits, upcoming events -### Content Management -- Non-technical administrators must be able to update content -- ASL video uploads must be simple with caption/transcript support -- Automated backups of all content -- Version history for content changes -- Role-based permissions for different admin functions +### Secondary Users -### Technical Requirements -- Fast loading times (especially on mobile) -- Secure authentication for admin features -- HTTPS encryption for all traffic -- Regular security updates -- Daily database backups -- Responsive design for all device sizes -- Cross-browser compatibility -- Email notification system for expirations +4. **Deaf Community Supporters** + - Family members, interpreters, educators + - Connection: Support deaf individuals or the community + - Need: Event information, volunteer opportunities, donation options -### Legal & Privacy -- Clear privacy policy -- Secure handling of member data -- GDPR-compliant data practices -- Terms of service for website use -- Accessibility statement with contact information +5. **Community Partners** + - Local businesses, schools, government agencies + - Relationship: Collaborate with OCD on initiatives + - Need: Contact information, organizational details + +6. **Researchers & Media** + - Studying deaf community or seeking information + - Need: Historical information, contact details, mission information + +## User Journeys + +### Member Journey: Event Participation + +1. **Discovery**: Member visits website to learn about upcoming events +2. **Information Gathering**: Views event details including date, time, location +3. **Decision**: Decides to attend based on accessible information +4. **Preparation**: Uses location map to plan transportation +5. **Follow-up**: Returns to website after event to view photos or minutes + +### Administrator Journey: Event Management + +1. **Creation**: Logs into admin dashboard to create new event +2. **Setup**: Enters event details, uploads images, sets category +3. **Publication**: Publishes event to website and highlights on homepage +4. **Management**: Monitors registrations if applicable +5. **Post-Event**: Uploads photos or minutes after event concludes + +### New Member Journey: Joining the Club + +1. **Introduction**: Discovers website through search or referral +2. **Exploration**: Browses about section, history, and mission +3. **Consideration**: Reviews membership benefits and requirements +4. **Application**: Completes online membership application form +5. **Integration**: Receives welcome email with next steps +6. **Engagement**: Begins participating in club events + +### Public Journey: Learning About Deaf Culture + +1. **Discovery**: Visits website seeking information about deaf community +2. **Education**: Explores pages about deaf culture and ASL +3. **Awareness**: Views ASL videos with accompanying transcripts +4. **Connection**: Uses contact form to request more information +5. **Engagement**: Signs up for newsletter or follows on social media + +## Key Features & Priorities + +### Critical Features (Must-Have) + +- **Accessible Design**: WCAG 2.2 AA compliance with deaf-specific considerations +- **Event Calendar**: Browsable calendar with detailed event information +- **Membership Management**: Member tracking and status management +- **Content Management**: Easy updates for non-technical administrators +- **Document Repository**: Storage for minutes, bylaws, and forms + +### Important Features (Should-Have) + +- **ASL Video Support**: Video content with transcripts and subtitles +- **Contact Functionality**: Forms for inquiries and feedback +- **Responsive Design**: Mobile-friendly experience across devices +- **Board Member Information**: Leadership profiles and roles +- **Email Integration**: Notification system for members + +### Enhancement Features (Nice-to-Have) + +- **Member Portal**: Personal dashboard for individual members +- **Donation Integration**: Online donation capabilities +- **Social Media Integration**: Sharing and cross-posting capabilities +- **Event Registration**: RSVP functionality for events +- **Photo Gallery**: Event photo albums + +## Accessibility Requirements + +As an organization serving the deaf community, accessibility is paramount. The website must include: + +- **Visual Communication Priority**: Information presented visually first +- **ASL Video Content**: Key information presented in ASL +- **Text Alternatives**: Captions and transcripts for all video content +- **High Contrast Design**: Clear visual distinction for all users +- **Screen Reader Support**: For DeafBlind community members +- **Keyboard Navigation**: Full functionality without mouse use +- **Simple Language**: Clear, concise content for varied reading levels +- **Reduced Motion Options**: For users with vestibular disorders +- **Responsive Text Sizing**: Adjustable text without breaking layouts + +## Success Metrics + +The OCD website's success will be measured by: + +1. **Member Engagement**: Increase in event attendance and participation +2. **Administrative Efficiency**: Reduction in manual administrative tasks +3. **Membership Growth**: New member applications through the website +4. **Content Freshness**: Frequency of content updates +5. **Accessibility Compliance**: WCAG 2.2 AA audit score +6. **User Satisfaction**: Feedback from community members +7. **Resource Utilization**: Downloads of documents and forms diff --git a/cline_docs/progress.md b/cline_docs/progress.md index 4bbfd44..24acb0d 100644 --- a/cline_docs/progress.md +++ b/cline_docs/progress.md @@ -1,68 +1,129 @@ # Project Progress: OCD Website -## What Works -- Complete project structure created according to the system patterns -- Essential configuration files for development environment setup: - - Docker Compose with multi-stage builds and security - - Frontend and backend Dockerfiles with security best practices - - Package.json files with dependencies - - Next.js configuration with security headers - - Tailwind CSS configuration with CSS-first approach - - Nginx configuration with security headers -- Core implementations: - - Navigation component with responsive design and accessibility features - - Footer component with site map and accessibility options - - Hero component with animation and adaptability - - Contact form with validation and ARIA attributes - - Public-facing pages including Home, About, and Contact - - Custom Video Player component with accessibility features and transcript display - - MongoDB initialization scripts with schema validation - - Database models with validation for Videos and Members - - Authentication middleware with JWT and RBAC - - Directory structure for both frontend and backend +## Completed Features -## What's Left to Build -The implementation has a solid foundation, but these key features still need to be built: +### Phase 1: Project Setup & Infrastructure +- [x] Initialize Next.js project with TypeScript +- [x] Configure project structure (app directory, API routes) +- [x] Set up ESLint with accessibility rules +- [x] Create basic layout components (Header, Footer, Navigation) +- [x] Implement responsive design breakpoints +- [x] Configure MongoDB connection +- [x] Set up Redis for caching +- [x] Implement Docker development environment +- [x] Create authentication middleware +- [x] Configure admin login system +- [x] Set up email service connection -1. Events and Calendar pages and functionality -2. Membership information and application pages -3. Admin dashboard and authentication flow -4. Full event management system -5. Membership tracking and notification system -6. Document repository with meeting minutes and bylaws -7. Full implementation of video management with upload functionality -8. Integration with Zeffy for donations -9. Email notification system implementation -10. Final deployment and testing +### Phase 2: Core Public Pages +- [x] Implement home page with featured events section +- [x] Create About OCD section pages + - [x] History page + - [x] Mission statement page + - [x] Board members page with photo grid +- [x] Implement bylaws page with document viewer +- [x] Create minutes archive with filtering and search +- [x] Develop responsive navigation system +- [x] Implement SEO optimization + - [x] Dynamic meta tags + - [x] Structured data for events + - [x] Sitemap generation +- [x] Create contact form with validation and email notifications +- [x] Implement breadcrumb navigation -For a detailed breakdown of specific tasks, refer to TO_DO.txt. +### Phase 3: Admin Dashboard +- [x] Create dashboard layout and navigation +- [x] Implement admin authentication and authorization +- [x] Develop dashboard overview with statistics +- [x] Create event management interface + - [x] Event listing with filtering + - [x] Event creation/editing form + - [x] Category management +- [x] Build member management interface + - [x] Member directory with filtering + - [x] Member profile editing + - [x] Membership status tracking +- [x] Implement document repository + - [x] Document upload and categorization + - [x] Permission controls (public/private) + - [x] Document search and filtering +- [x] Create content management system + - [x] Page listing and organization + - [x] WYSIWYG editor interface + - [x] Publish/unpublish functionality +- [x] Implement settings interface + - [x] General site settings + - [x] Email configuration + - [x] Membership settings + - [x] Accessibility options +- [x] Develop video management system + - [x] Video listing and organization + - [x] Accessibility indicators for subtitles + - [x] Publishing controls -## Progress Status -- **Current Phase**: Phase 1 - Core setup and public-facing pages -- **Tasks Completed**: - - Updated technology stack to latest versions (Next.js 15.2.3, TypeScript 5.8, Tailwind CSS 4.0) - - Created complete directory structure according to system patterns - - Implemented core configuration files (Docker, Nginx, Tailwind, Next.js) - - Created MongoDB initialization scripts with schema validation - - Implemented Video Player component with transcript display - - Set up authentication middleware with JWT - - Created model files with validation for Videos and Members - - Created basic API routes structure - - Enhanced database schemas with validation and indexing - - Upgraded accessibility to WCAG 2.2 AA compliance requirements - - Added required video transcript and thumbnail specifications - - Implemented Docker setup with security best practices - - Created responsive Navigation and Footer components - - Implemented Home, About, and Contact pages with accessibility features - - Created Contact form with validation and ARIA attributes -- **Tasks In Progress**: - - Events and Calendar functionality - - Membership section development -- **Next Tasks**: - - Complete remaining public-facing pages (Events, Membership) - - Begin admin dashboard implementation - - Implement event management system - - Set up video upload and management functionality +## In Progress Features -## Current Task -Implementing additional public-facing pages to complete Phase 2, with focus on the event calendar and membership information sections. Once those are complete, we'll move on to the admin functionality in Phase 3. +### Phase 4: API Integration & Backend Functionality +- [ ] Connect admin interfaces to backend API endpoints +- [ ] Implement real data loading with state management +- [ ] Create API error handling and recovery +- [ ] Develop form submissions with validation +- [ ] Build media upload functionality +- [ ] Implement user notification system +- [ ] Create advanced filtering for data tables +- [ ] Develop data export functionality +- [ ] Build search functionality across system + +### Phase 5: Accessibility & Refinement +- [ ] Conduct comprehensive accessibility audit +- [ ] Implement screen reader optimizations +- [ ] Refine keyboard navigation +- [ ] Add focus management system +- [ ] Implement reduced motion alternatives +- [ ] Create high contrast mode +- [ ] Optimize for text resizing +- [ ] Test with assistive technologies +- [ ] Add accessibility documentation + +## Upcoming Features + +### Phase 6: Testing & Optimization +- [ ] Conduct user testing with club members +- [ ] Perform performance optimization + - [ ] Image optimization + - [ ] Code splitting + - [ ] Bundle size reduction +- [ ] Implement caching strategies +- [ ] Conduct security audit +- [ ] Fix identified bugs +- [ ] Refine UI/UX based on feedback +- [ ] Optimize database queries +- [ ] Create automated testing suite + +### Phase 7: Deployment & Documentation +- [ ] Set up production Docker environment +- [ ] Configure Nginx and SSL +- [ ] Implement automated backups +- [ ] Create deployment documentation +- [ ] Develop admin user guide +- [ ] Create technical documentation +- [ ] Implement monitoring and alerting +- [ ] Conduct training session for administrators + +## Technical Debt & Improvements +- [ ] Refine type definitions for stronger typing +- [ ] Improve error boundary implementation +- [ ] Enhance logging and monitoring +- [ ] Create more comprehensive unit tests +- [ ] Optimize database indexing +- [ ] Refine component reusability +- [ ] Consolidate duplicate styling +- [ ] Add comprehensive JSDoc comments + +## Project Stats +- **Completed Tasks:** 36 +- **In Progress Tasks:** 9 +- **Upcoming Tasks:** 23 +- **Completion Rate:** ~53% +- **Current Phase:** Transitioning from Phase 3 to Phase 4 +- **Next Major Milestone:** Full API integration diff --git a/cline_docs/systemPatterns.md b/cline_docs/systemPatterns.md index 20c6ab7..9bc7427 100644 --- a/cline_docs/systemPatterns.md +++ b/cline_docs/systemPatterns.md @@ -2,164 +2,221 @@ ## Architecture Patterns -### Frontend Architecture -- **Component Structure**: Atomic Design methodology - - **Atoms**: Buttons, inputs, icons, typography elements - - **Molecules**: Forms, cards, navigation items, video player - - **Organisms**: Navigation bar, page sections, footer - - **Templates**: Page layouts with content placeholders - - **Pages**: Complete views with actual content -- **Data Flow**: Unidirectional data flow (React standard) -- **State Management**: React Context API for global state -- **Rendering Strategy**: - - Server-side rendering for initial page load and SEO - - Client-side rendering for interactive components - - Static generation for stable content -- **Styling Approach**: - - Utility-first with Tailwind CSS - - Component-specific styles via custom CSS - - CSS variables for theming and consistency -- **Responsive Design**: - - Mobile-first breakpoints (sm, md, lg, xl) - - Container-based fluid layouts - - Flexbox and CSS Grid for complex layouts +### Component Architecture +- **Atomic Design Methodology** + - **Atoms**: Basic building blocks (buttons, inputs, icons) + - **Molecules**: Simple groups of UI elements (form fields, cards) + - **Organisms**: Complex UI components (navigation, forms) + - **Templates**: Page layouts without specific content + - **Pages**: Templates with real content -### Backend Architecture -- **API Design**: RESTful with resource-based endpoints -- **Controller Pattern**: Route handlers separated from business logic -- **Repository Pattern**: Data access abstracted from controllers -- **Middleware Stack**: - - Authentication/Authorization - - Request validation - - Error handling - - Logging - - CORS handling -- **Data Models**: MongoDB schemas with validation -- **Service Layer**: Business logic encapsulated in service modules +- **File Organization** + - Components grouped by type (atoms, molecules, organisms) + - Pages in Next.js app directory structure + - Shared utilities in separate folders + - Clear separation between frontend and backend -## Key Technical Decisions +### State Management +- **React Context API** for global state + - Authentication context for user sessions + - UI context for theme and preferences + - Toast notification context for system messages +- **Local component state** for UI-specific state +- **Form state** handled with controlled components +- **API state** managed with custom hooks -### Next.js App Router -- File-based routing with nested layouts -- Server components for performance -- Client components marked with 'use client' for interactivity -- Metadata API for SEO optimization +### Data Flow Patterns +- **Unidirectional data flow** + - Props down, events up + - Context providers at appropriate levels +- **Container/Presenter pattern** + - Container components handle data fetching and state + - Presenter components are pure rendering functions +- **Custom hooks** for reusable logic + - useAuth for authentication + - useFetch for data fetching + - useForm for form handling -### Tailwind CSS 4.0 -- JIT (Just-In-Time) compilation for optimal CSS bundle size -- Extended theme for custom design tokens -- CSS variables for runtime theming -- Utility-first approach for rapid development +## Frontend Patterns -### Accessibility First -- WCAG 2.2 AA compliance as baseline requirement -- Semantic HTML structure -- ARIA attributes used appropriately -- Keyboard navigation focus management -- Screen reader announcements for dynamic content -- High contrast mode support -- Reduced motion option +### Styling Approach +- **Utility-first CSS with Tailwind** + - Consistent design tokens through Tailwind config + - Custom utilities for project-specific needs + - Component classes for common patterns +- **CSS variables for theming** + - Core colors defined as CSS variables + - Dark mode implementation using CSS variables + - Responsive design using Tailwind breakpoints +- **Component-specific styles when needed** + - Modules used for complex styling needs + - Animation styles with Framer Motion -### Docker Containerization -- Multi-stage builds for production optimization -- Development environment consistency -- Separate containers for frontend, backend, and database -- Volume mounting for source code in development -- Environment variable management +### Responsive Design +- **Mobile-first approach** + - Default styles for mobile + - Progressive enhancement for larger screens +- **Breakpoint system** + - sm: 640px and up + - md: 768px and up + - lg: 1024px and up + - xl: 1280px and up + - 2xl: 1536px and up +- **Flexible layouts** + - CSS Grid for page layouts + - Flexbox for component layouts -### JWT Authentication -- HTTP-only cookies for security -- Role-based access control -- Token refresh strategy -- Secure routes with middleware +### Form Handling +- **Controlled components** for form inputs +- **Field validation** with client-side validation +- **Error handling** with inline error messages +- **Form submission** with loading states +- **Accessibility considerations** + - Proper labeling + - Error association + - Keyboard navigation -## Code Organization +### Routing +- **Next.js App Router** + - File-based routing for pages + - Dynamic routes for entity details + - Route groups for organization + - Layouts for shared UI elements +- **Protected routes** for admin sections + - Auth middleware + - Redirect to login if unauthorized -### Frontend Structure -``` -frontend/ -├── public/ # Static assets -├── src/ -│ ├── app/ # Next.js routes and pages -│ ├── components/ # React components -│ │ ├── atoms/ # Basic UI elements -│ │ ├── molecules/ # Compound components -│ │ ├── organisms/ # Complex components -│ │ └── video/ # Video-related components -│ ├── hooks/ # Custom React hooks -│ ├── lib/ # Utility functions and helpers -│ ├── styles/ # Global styles and Tailwind config -│ └── types/ # TypeScript type definitions -└── tests/ # Test suites -``` +## Backend Patterns -### Backend Structure -``` -backend/ -├── src/ -│ ├── config/ # Configuration settings -│ ├── controllers/ # Request handlers -│ ├── middleware/ # Express middleware -│ ├── models/ # Data models and schemas -│ ├── routes/ # API route definitions -│ ├── services/ # Business logic -│ └── utils/ # Helper functions -└── tests/ # Test suites -``` +### API Design +- **RESTful endpoints** + - Resource-based URLs + - Appropriate HTTP methods + - Consistent response format + - Status codes for error handling +- **Controller pattern** + - Route handlers for request parsing + - Controllers for business logic + - Services for reusable operations + - Models for data access -## Design Patterns - -### Component Composition -- Prefer composition over inheritance -- Small, focused components with single responsibilities -- Higher-order components for shared functionality -- Render props for flexible component APIs - -### Custom Hooks -- Extract reusable stateful logic into custom hooks -- Naming convention: use[HookName] -- Keep hooks focused on specific concerns +### Authentication +- **JWT-based authentication** + - JWTs stored in HTTP-only cookies + - Short expiration with refresh tokens + - CSRF protection with tokens +- **Permission-based authorization** + - Role-based access control + - Resource ownership checks + - Fine-grained permissions ### Error Handling -- Try/catch blocks in async functions -- Error boundaries for UI component failures -- Consistent error response format in API -- Detailed logging for debugging +- **Centralized error handling middleware** + - Consistent error format + - Appropriate status codes + - Detailed error messages in development + - Sanitized messages in production +- **Try/catch blocks** for async operations +- **Validation errors** for input validation -### Dependency Injection -- Service dependencies provided via parameters -- Loose coupling between modules -- Facilitates testing with mocks +## Database Patterns -## Naming Conventions +### Schema Design +- **Document-based design** for MongoDB + - Embedded documents for related data + - References for shared entities + - Denormalization for performance +- **Validation schemas** with Mongoose + - Required fields + - Field types and constraints + - Custom validators +- **Indexes** for frequently queried fields -### Frontend -- **Component Files**: PascalCase.tsx -- **Hook Files**: camelCase.ts -- **Utility Files**: camelCase.ts -- **CSS Modules**: camelCase.module.css -- **Component Props**: interface ComponentNameProps +### Query Patterns +- **Repository pattern** for data access + - Encapsulated database operations + - Reusable query methods + - Consistent error handling +- **Pagination** for large collections + - Limit/skip approach + - Cursor-based pagination for efficiency +- **Filtering** with query parameters + - Dynamic filter building + - Validation of filter parameters -### Backend -- **Controllers**: camelCase.controller.ts -- **Models**: PascalCase.model.ts -- **Routes**: camelCase.routes.ts -- **Services**: camelCase.service.ts -- **Middleware**: camelCase.middleware.ts +## Testing Patterns -## Testing Strategy -- **Frontend**: - - Component tests with React Testing Library - - E2E tests with Playwright - - Visual regression tests -- **Backend**: - - Unit tests for business logic - - Integration tests for API endpoints - - Mock database for testing +### Unit Testing +- **Component testing** with React Testing Library + - Component rendering + - User interactions + - State changes +- **Hook testing** with custom test utilities +- **Service testing** for business logic -## CI/CD Pipeline (Planned) -- GitHub Actions for automated builds -- Linting and type checking -- Automated testing -- Docker image building -- Deployment to production server +### Integration Testing +- **API endpoint testing** + - Request validation + - Response structure + - Error handling +- **Database interaction testing** + - Create, read, update, delete operations + - Schema validation + - Indexing performance + +### End-to-End Testing +- **User flow testing** + - Critical user journeys + - Form submissions + - Authentication flows +- **Accessibility testing** + - Automated a11y checks + - Manual screen reader testing + - Keyboard navigation testing + +## Deployment Patterns + +### Docker Containerization +- **Multi-stage builds** for production + - Build stage for dependencies and compilation + - Production stage for runtime + - Minimal production image +- **Docker Compose** for local development + - Service definitions + - Volume mappings + - Network configuration + +### Environment Configuration +- **Environment-specific variables** + - Development settings + - Production settings + - Testing settings +- **Secret management** + - Environment variables for sensitive data + - Docker secrets for production + +## Accessibility Patterns + +### WCAG 2.2 Compliance +- **Semantic HTML** + - Proper heading hierarchy + - Meaningful element choices + - Landmark regions +- **ARIA attributes** when needed + - Role definitions + - State indications + - Relationship attributes +- **Keyboard navigation** + - Focus management + - Logical tab order + - Skip links +- **Screen reader support** + - Alt text for images + - Descriptive link text + - Status announcements +- **Color contrast** + - Meeting WCAG AA contrast ratios + - Not relying on color alone +- **Motion sensitivity** + - Respecting reduced motion preferences + - Careful use of animations diff --git a/cline_docs/techContext.md b/cline_docs/techContext.md index 0e56568..7ef25e8 100644 --- a/cline_docs/techContext.md +++ b/cline_docs/techContext.md @@ -1,98 +1,175 @@ # Technical Context: OCD Website -## Technologies Used +## Technology Stack ### Frontend -- **Framework**: Next.js 15.2.3 - Server-side rendering with React -- **Language**: TypeScript 5.8 - Type-safe development -- **UI Components**: React 19.0.0 - Component-based architecture +- **Framework**: Next.js 15.2.3 with React 19 +- **Language**: TypeScript 5.8 - **Styling**: - - Tailwind CSS 4.0.15 - Utility-first CSS framework - - CSS Variables - Custom theming system - - PostCSS 8.4 - CSS processing - - Autoprefixer 10.4 - CSS vendor prefixing -- **Animation**: Framer Motion 12.6.0 - Interactive animations -- **Routing**: Next.js App Router - File-based routing with layouts -- **Icons**: Custom SVG icons - Accessibility-focused -- **Forms**: Custom form components with validation + - Tailwind CSS 4.0 + - PostCSS 8.4 with Autoprefixer 10.4 + - CSS variables for theming +- **State Management**: React Context API +- **Routing**: Next.js App Router +- **Animations**: Framer Motion 11 +- **Icons**: React Icons 5.5.0 +- **Maps**: React Simple Maps 3.0.0 +- **Utility Libraries**: + - React Intersection Observer 9.16.0 + - Axios 1.6 for API requests + - date-fns for date manipulation ### Backend -- **Framework**: Node.js with Express 4.21 -- **Language**: TypeScript - Type-safe API development -- **Database**: MongoDB - Document-based storage -- **API**: RESTful endpoints -- **Email**: Nodemailer 6.9 - Email notifications +- **Framework**: Node.js with Express 4.18.2 +- **Language**: TypeScript 5.8 +- **API Design**: RESTful endpoints +- **Email Handling**: Nodemailer 6.9 - **Authentication**: JWT-based with HTTP-only cookies -- **Data Validation**: Server-side schema validation +- **Cross-Origin**: CORS middleware +- **Environment Variables**: dotenv 16.4 +- **Caching & Rate Limiting**: Upstash Redis 1.28 -### Development Tools +### Database +- **Primary Database**: MongoDB with Mongoose ODM +- **Caching Layer**: Redis +- **Schema Validation**: Mongoose schemas with validation +- **Data Models**: + - Admin User + - Member + - Event + - Page Content + - Document + - Video + - Contact Submission + +### Development & Build Tools - **Package Manager**: pnpm 9.14 +- **Containerization**: Docker & Docker Compose +- **Build Tool**: Vite 6.0 - **Linting**: ESLint 9 -- **Build System**: Next.js built-in bundler -- **Version Control**: Git -- **Container**: Docker & Docker Compose -- **Configuration**: Environment variables with dotenv -- **Caching**: Redis (planned) +- **Process Management**: Concurrently for multiple processes +- **TypeScript Execution**: tsx/ts-node +- **Hot Module Replacement**: Enabled -### Deployment -- **Production Server**: Nginx reverse proxy -- **Containers**: Docker multi-stage builds -- **Database**: MongoDB Atlas (planned) -- **Cache**: Redis (planned) -- **CI/CD**: GitHub Actions (planned) +### Production Environment +- **Web Server**: Nginx for static assets and reverse proxy +- **API Server**: Node.js +- **Containerization**: Docker with multi-stage builds +- **SSL**: Let's Encrypt certificates +- **Monitoring**: Basic health checks +- **Logging**: Winston logger with structured format -## Development Environment +## Architecture Overview -### Local Setup -- Next.js development server (localhost:3000) -- Express API server (localhost:4000) -- MongoDB container -- Tailwind CSS JIT compilation -- Hot module reloading +### Frontend Architecture +- **Server Components**: Used for static pages (About, Bylaws) +- **Client Components**: Used for interactive elements +- **Rendering Strategy**: + - SSR for critical pages (Home, Events) + - Static Generation for stable content + - Client-side rendering for interactive components +- **Component Structure**: + - Atomic design principles (atoms, molecules, organisms) + - Layout components for consistent page structure + - Page-specific components +- **Data Flow**: + - React Context for application state + - API hooks for data fetching + - Form state handled locally -### Key Configuration Files -- **docker-compose.yml**: Container orchestration -- **frontend/next.config.js**: Next.js configuration -- **frontend/tailwind.config.js**: Tailwind customization -- **frontend/postcss.config.js**: CSS processing -- **backend/.env**: API environment variables -- **nginx/conf/default.conf**: Production web server +### Backend Architecture +- **API Layer**: RESTful endpoints organized by resource +- **Authentication Layer**: JWT middleware for protected routes +- **Controller Layer**: Handles business logic +- **Model Layer**: Mongoose models with validation +- **Email Service**: Nodemailer for transactional emails +- **File Handling**: Multer for uploads -## Technical Constraints +### Database Design +- Document-oriented schema with Mongoose +- Relationships handled through references +- Indexing for frequently queried fields +- Validation at the schema level -### Accessibility Requirements -- WCAG 2.2 AA compliance -- Screen reader compatibility +## Development Setup + +### Local Development +- Docker Compose for local environment +- Frontend on port 3000 +- Backend API on port 4000 +- MongoDB on port 27017 +- Redis on port 6379 +- Hot reloading enabled for development + +### Environment Configuration +- Frontend environment variables in .env.local +- Backend environment variables in .env +- Production variables set through Docker + +### CI/CD Flow +- Manual deployment to production +- Build process in Docker +- Multi-stage builds for smaller images + +## API Structure + +### Authentication Endpoints +- POST /api/auth/login +- POST /api/auth/logout +- POST /api/auth/reset-password +- POST /api/auth/set-password + +### Content Management Endpoints +- GET/POST/PUT/DELETE /api/pages +- GET/PUT /api/pages/:slug +- PUT /api/pages/:id/publish + +### Event Endpoints +- GET/POST/PUT/DELETE /api/events +- GET /api/events/:id +- GET /api/events/calendar/:year/:month + +### Member Endpoints +- GET/POST/PUT/DELETE /api/members +- GET /api/members/expiring +- POST /api/members/notify + +### Document Endpoints +- GET/POST/PUT/DELETE /api/documents +- GET /api/documents/:id + +### Video Endpoints +- GET/POST/PUT/DELETE /api/videos +- GET /api/videos/:id +- POST /api/videos/:id/subtitles + +### Contact Endpoints +- POST /api/contact +- GET /api/contact +- PUT /api/contact/:id +- POST /api/contact/:id/respond + +## Accessibility Implementation + +- WCAG 2.2 AA compliance target +- Semantic HTML structure +- ARIA attributes for interactive components - Keyboard navigation support +- Screen reader considerations - Color contrast compliance -- Reduced motion support -- DeafBlind/Blind user accessibility -- ASL video content with captions and transcripts +- Focus management +- Reduced motion option +- Video subtitle support +- Text resizing support -### Browser Support -- Modern browsers (Chrome, Firefox, Safari, Edge) -- IE not supported -- Mobile browsers (iOS Safari, Chrome Android) +## Security Measures -### Performance Targets -- First contentful paint < 1.5s -- Time to interactive < 3.5s -- Core Web Vitals compliance -- Optimized image delivery -- Minimal JavaScript overhead - -### Security Considerations -- HTTPS-only in production -- Content Security Policy headers -- JWT authentication with secure cookies -- Input sanitization and validation +- Authentication with JWTs and HTTP-only cookies +- Role-based access control +- Input validation - CSRF protection -- Rate limiting (planned) - -## Additional Notes -- Custom CSS variables for theming -- Dark mode support via media query -- Mobile-first responsive design -- Component-based architecture -- Accessibility-first approach -- Server-side rendering for SEO +- Content Security Policy +- Secure HTTP headers +- Rate limiting +- Data sanitization +- Secure password handling diff --git a/frontend/src/app/admin/content/page.tsx b/frontend/src/app/admin/content/page.tsx new file mode 100644 index 0000000..a565253 --- /dev/null +++ b/frontend/src/app/admin/content/page.tsx @@ -0,0 +1,459 @@ +'use client'; + +import React, { useState } from 'react'; +import Link from 'next/link'; + +// Page Filter Component +const PageFilter = ({ + onFilterChange +}: { + onFilterChange: (filter: { status: string; search: string }) => void +}) => { + const [status, setStatus] = useState('all'); + const [search, setSearch] = useState(''); + + const handleFilterChange = () => { + onFilterChange({ status, search }); + }; + + const handleReset = () => { + setStatus('all'); + setSearch(''); + onFilterChange({ status: 'all', search: '' }); + }; + + return ( +
+

Filter Pages

+
+
+ + +
+ +
+ + setSearch(e.target.value)} + /> +
+
+ +
+ + +
+
+ ); +}; + +export default function ContentPage() { + const [filter, setFilter] = useState({ status: 'all', search: '' }); + + // Mock pages data - would come from API in a real implementation + const allPages = [ + { + id: '1', + title: 'Home Page', + slug: '/', + metaDescription: 'Welcome to the Olathe Club of the Deaf, serving the deaf community in Olathe, Kansas.', + status: 'published', + lastUpdated: '2025-03-15', + createdBy: 'Admin User', + sections: 6 + }, + { + id: '2', + title: 'About Us', + slug: '/about', + metaDescription: 'Learn about the Olathe Club of the Deaf, our mission, history, and board members.', + status: 'published', + lastUpdated: '2025-02-20', + createdBy: 'Admin User', + sections: 4 + }, + { + id: '3', + title: 'Events', + slug: '/events', + metaDescription: 'Check out upcoming events and activities with the Olathe Club of the Deaf.', + status: 'published', + lastUpdated: '2025-03-10', + createdBy: 'Admin User', + sections: 3 + }, + { + id: '4', + title: 'Membership', + slug: '/membership', + metaDescription: 'Join the Olathe Club of the Deaf and become part of our vibrant community.', + status: 'published', + lastUpdated: '2025-02-28', + createdBy: 'Admin User', + sections: 5 + }, + { + id: '5', + title: 'Contact Us', + slug: '/contact', + metaDescription: 'Get in touch with the Olathe Club of the Deaf. We would love to hear from you!', + status: 'published', + lastUpdated: '2025-02-15', + createdBy: 'Admin User', + sections: 2 + }, + { + id: '6', + title: 'Privacy Policy', + slug: '/privacy-policy', + metaDescription: 'Our privacy policy details how we handle and protect your information.', + status: 'published', + lastUpdated: '2025-01-10', + createdBy: 'Admin User', + sections: 8 + }, + { + id: '7', + title: 'Donate', + slug: '/donate', + metaDescription: 'Support the Olathe Club of the Deaf through donations.', + status: 'published', + lastUpdated: '2025-03-05', + createdBy: 'Admin User', + sections: 4 + }, + { + id: '8', + title: 'Summer Programs', + slug: '/summer-programs', + metaDescription: 'Summer programs and activities for deaf youth in Olathe.', + status: 'draft', + lastUpdated: '2025-03-18', + createdBy: 'Admin User', + sections: 3 + }, + ]; + + // Filter pages based on current filter settings + const filteredPages = allPages.filter(page => { + if (filter.status !== 'all' && page.status !== filter.status) return false; + + if (filter.search) { + const searchLower = filter.search.toLowerCase(); + if (!page.title.toLowerCase().includes(searchLower) && + !page.slug.toLowerCase().includes(searchLower)) { + return false; + } + } + + return true; + }); + + // Handle filter changes + const handleFilterChange = (newFilter: { status: string; search: string }) => { + setFilter(newFilter); + }; + + // Format date for display + const formatDate = (dateString: string) => { + const date = new Date(dateString); + return new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric' + }).format(date); + }; + + return ( +
+
+
+

Content Management

+

+ Manage website content, page sections, and metadata. +

+
+
+ + + + + Create New Page + +
+
+ + {/* Filter component */} + + + {/* Pages table */} +
+
+ + + + + + + + + + + + {filteredPages.map((page) => ( + + + + + + + + ))} + +
+ Page + + URL + + Last Updated + + Status + + Actions +
+
+
+
+ {page.title} +
+
+ {page.sections} sections • Created by {page.createdBy} +
+
+
+
+
{page.slug}
+
{page.metaDescription}
+
+
{formatDate(page.lastUpdated)}
+
+ + {page.status.charAt(0).toUpperCase() + page.status.slice(1)} + + +
+ + View + + + Edit + + {page.status === 'published' ? ( + + ) : ( + + )} + {page.id !== '1' && page.id !== '2' && page.id !== '3' && page.id !== '4' && page.id !== '5' && ( + + )} +
+
+
+ + {filteredPages.length === 0 && ( +
+

No pages found matching the current filters.

+
+ )} +
+ + {/* WYSIWYG Editor Preview */} +
+

Page Editor Preview

+
+
+
+ +
+
+ +
+ {/* Mock toolbar */} +
+ + + + + + + + + + + +
+ + {/* Editor content */} +
+

This is a preview of the WYSIWYG editor. In the actual implementation, this would be a fully functional content editor with formatting options, image uploads, and more.

+

The editor would support various formatting options like bold, italic, and underline text, as well as lists, links, and images.

+
+
+ +
+
+ +
+ + / + + +
+
+
+ + +
+
+ +
+ + +

+ Write a compelling description to improve search engine rankings and click-through rates. +

+
+ +
+ + +
+
+
+
+ ); +} diff --git a/frontend/src/app/admin/dashboard/layout.tsx b/frontend/src/app/admin/dashboard/layout.tsx new file mode 100644 index 0000000..9a8f89a --- /dev/null +++ b/frontend/src/app/admin/dashboard/layout.tsx @@ -0,0 +1,55 @@ +'use client'; + +import React from 'react'; +import AdminSidebar from '../../../components/admin/AdminSidebar'; + +export default function AdminDashboardLayout({ + children, +}: { + children: React.ReactNode; +}) { + // For a real app, add auth check here to prevent unauthorized access + // const { data: session, status } = useSession() + // if (status === "loading") return + // if (status === "unauthenticated") redirect('/admin/login') + + return ( +
+ {/* Sidebar */} +
+ +
+ + {/* Mobile sidebar (hidden by default) */} +
+ {/* We'd implement a mobile menu here */} +
+ + {/* Main content */} +
+ {/* Header */} +
+
+
+

+ Dashboard +

+ + {/* User menu or mobile menu button would go here */} +
+
+ Admin User +
+
+
+
+
+ + {/* Page content */} +
+ {children} +
+
+
+ ); +} diff --git a/frontend/src/app/admin/dashboard/page.tsx b/frontend/src/app/admin/dashboard/page.tsx new file mode 100644 index 0000000..9a7eef5 --- /dev/null +++ b/frontend/src/app/admin/dashboard/page.tsx @@ -0,0 +1,266 @@ +import React from 'react'; +import Link from 'next/link'; +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Admin Dashboard | Olathe Club of the Deaf', + description: 'Admin dashboard for the Olathe Club of the Deaf website', +}; + +// Stats Card Component +const StatCard = ({ title, value, icon, href }: { title: string; value: string; icon: React.ReactNode; href: string }) => ( + +
+
+ {icon} +
+
+

{title}

+

{value}

+
+
+ +); + +// Simple icons +const MembersIcon = () => ( + + + +); + +const EventsIcon = () => ( + + + +); + +const ContactIcon = () => ( + + + +); + +const VideosIcon = () => ( + + + +); + +export default function AdminDashboardPage() { + // In a real app, these would be fetched from the API + const stats = { + members: "47", + activeMembers: "41", + events: "12", + videos: "8", + documents: "15", + unreadContacts: "3" + }; + + // Upcoming events - in a real app, these would be fetched from the API + const upcomingEvents = [ + { + id: '1', + title: 'Monthly Social', + date: 'Apr 15, 2025', + location: 'Olathe Community Center', + status: 'Published' + }, + { + id: '2', + title: 'ASL Workshop', + date: 'Apr 22, 2025', + location: 'OCD Meeting Room', + status: 'Draft' + }, + { + id: '3', + title: 'Board Meeting', + date: 'May 5, 2025', + location: 'Zoom Meeting', + status: 'Published' + } + ]; + + // Membership expirations - in a real app, these would be fetched from the API + const expiringMemberships = [ + { + id: '101', + name: 'John Smith', + expiryDate: 'Apr 30, 2025', + type: 'Regular', + status: 'Expiring Soon' + }, + { + id: '102', + name: 'Sarah Johnson', + expiryDate: 'May 15, 2025', + type: 'Family', + status: 'Expiring Soon' + }, + { + id: '103', + name: 'Robert Lee', + expiryDate: 'Mar 28, 2025', + type: 'Regular', + status: 'Expired' + } + ]; + + return ( +
+
+

Overview

+
+ } + href="/admin/members" + /> + } + href="/admin/members/active" + /> + } + href="/admin/events" + /> + } + href="/admin/contact" + /> +
+
+ +
+ {/* Upcoming Events */} +
+
+

Upcoming Events

+ + View All + +
+ +
+ {upcomingEvents.map((event) => ( +
+
+
+

{event.title}

+

{event.date} • {event.location}

+
+ + {event.status} + +
+
+ ))} +
+ +
+ + + + + Add Event + +
+
+ + {/* Membership Expirations */} +
+
+

Membership Expirations

+ + View All + +
+ +
+ {expiringMemberships.map((member) => ( +
+
+
+

{member.name}

+

{member.expiryDate} • {member.type}

+
+ + {member.status} + +
+
+ ))} +
+ +
+ + + + + Send Renewal Notices + +
+
+
+ + {/* Quick Actions */} +
+

Quick Actions

+
+ +
+ +
+ New Event + + + +
+ +
+ Add Member + + + +
+ +
+ Upload Video + + + +
+ + + +
+ Edit Pages + +
+
+
+ ); +} diff --git a/frontend/src/app/admin/documents/page.tsx b/frontend/src/app/admin/documents/page.tsx new file mode 100644 index 0000000..e1ca50c --- /dev/null +++ b/frontend/src/app/admin/documents/page.tsx @@ -0,0 +1,491 @@ +'use client'; + +import React, { useState } from 'react'; +import Link from 'next/link'; + +// Document Filter Component +const DocumentFilter = ({ + onFilterChange +}: { + onFilterChange: (filter: { category: string; isPublic: string; search: string }) => void +}) => { + const [category, setCategory] = useState('all'); + const [isPublic, setIsPublic] = useState('all'); + const [search, setSearch] = useState(''); + + const handleFilterChange = () => { + onFilterChange({ category, isPublic, search }); + }; + + const handleReset = () => { + setCategory('all'); + setIsPublic('all'); + setSearch(''); + onFilterChange({ category: 'all', isPublic: 'all', search: '' }); + }; + + return ( +
+

Filter Documents

+
+
+ + +
+ +
+ + +
+ +
+ + setSearch(e.target.value)} + /> +
+
+ +
+ + +
+
+ ); +}; + +export default function DocumentsPage() { + const [filter, setFilter] = useState({ category: 'all', isPublic: 'all', search: '' }); + const [selectedDocuments, setSelectedDocuments] = useState([]); + const [selectAll, setSelectAll] = useState(false); + + // Mock documents data - would come from API in a real implementation + const allDocuments = [ + { + id: '1', + title: 'Board Meeting Minutes - March 2025', + description: 'Minutes from the March 10, 2025 board meeting', + category: 'minutes', + fileUrl: '/documents/minutes-march-2025.pdf', + mimeType: 'application/pdf', + fileSize: '284 KB', + uploadDate: '2025-03-15', + lastModified: '2025-03-15', + isPublic: false, + tags: ['board', 'minutes', 'march', '2025'] + }, + { + id: '2', + title: 'OCD Bylaws 2025', + description: 'Updated bylaws for the Olathe Club of the Deaf', + category: 'bylaws', + fileUrl: '/documents/ocd-bylaws-2025.pdf', + mimeType: 'application/pdf', + fileSize: '567 KB', + uploadDate: '2025-01-05', + lastModified: '2025-01-05', + isPublic: true, + tags: ['bylaws', 'rules', 'organization'] + }, + { + id: '3', + title: 'Membership Application Form', + description: 'Form for new membership applications', + category: 'forms', + fileUrl: '/documents/membership-form.pdf', + mimeType: 'application/pdf', + fileSize: '125 KB', + uploadDate: '2024-12-10', + lastModified: '2025-01-15', + isPublic: true, + tags: ['membership', 'application', 'form'] + }, + { + id: '4', + title: 'Annual Financial Report 2024', + description: 'Financial report for the fiscal year 2024', + category: 'reports', + fileUrl: '/documents/financial-report-2024.pdf', + mimeType: 'application/pdf', + fileSize: '1.2 MB', + uploadDate: '2025-02-15', + lastModified: '2025-02-15', + isPublic: false, + tags: ['financial', 'annual', 'report', '2024'] + }, + { + id: '5', + title: 'Winter Newsletter 2025', + description: 'Newsletter for winter 2025 with club updates and events', + category: 'newsletters', + fileUrl: '/documents/newsletter-winter-2025.pdf', + mimeType: 'application/pdf', + fileSize: '3.4 MB', + uploadDate: '2025-01-10', + lastModified: '2025-01-10', + isPublic: true, + tags: ['newsletter', 'winter', '2025', 'events'] + }, + { + id: '6', + title: 'Event Proposal Form', + description: 'Form for members to propose new events', + category: 'forms', + fileUrl: '/documents/event-proposal-form.docx', + mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + fileSize: '68 KB', + uploadDate: '2024-11-20', + lastModified: '2024-11-20', + isPublic: true, + tags: ['events', 'proposal', 'form'] + }, + { + id: '7', + title: 'Board Meeting Minutes - February 2025', + description: 'Minutes from the February 12, 2025 board meeting', + category: 'minutes', + fileUrl: '/documents/minutes-february-2025.pdf', + mimeType: 'application/pdf', + fileSize: '312 KB', + uploadDate: '2025-02-18', + lastModified: '2025-02-18', + isPublic: false, + tags: ['board', 'minutes', 'february', '2025'] + }, + { + id: '8', + title: 'Member Handbook', + description: 'Comprehensive handbook for all OCD members', + category: 'bylaws', + fileUrl: '/documents/member-handbook.pdf', + mimeType: 'application/pdf', + fileSize: '4.2 MB', + uploadDate: '2025-01-05', + lastModified: '2025-01-05', + isPublic: true, + tags: ['handbook', 'members', 'rules', 'guidelines'] + }, + ]; + + // Filter documents based on current filter settings + const filteredDocuments = allDocuments.filter(document => { + if (filter.category !== 'all' && document.category !== filter.category) return false; + + if (filter.isPublic !== 'all') { + const isPublicBool = filter.isPublic === 'public'; + if (document.isPublic !== isPublicBool) return false; + } + + if (filter.search) { + const searchLower = filter.search.toLowerCase(); + if (!document.title.toLowerCase().includes(searchLower) && + !document.description.toLowerCase().includes(searchLower) && + !document.tags.some(tag => tag.toLowerCase().includes(searchLower))) { + return false; + } + } + + return true; + }); + + // Handle filter changes + const handleFilterChange = (newFilter: { category: string; isPublic: string; search: string }) => { + setFilter(newFilter); + }; + + // Handle bulk actions + const handleBulkAction = (action: string) => { + // In a real app, this would call an API + alert(`Perform ${action} on ${selectedDocuments.length} documents`); + }; + + // Handle select all checkbox + const handleSelectAll = (event: React.ChangeEvent) => { + const checked = event.target.checked; + setSelectAll(checked); + + if (checked) { + setSelectedDocuments(filteredDocuments.map(doc => doc.id)); + } else { + setSelectedDocuments([]); + } + }; + + // Handle individual checkbox selection + const handleSelectDocument = (documentId: string, checked: boolean) => { + if (checked) { + setSelectedDocuments(prev => [...prev, documentId]); + } else { + setSelectedDocuments(prev => prev.filter(id => id !== documentId)); + } + }; + + // Format date for display + const formatDate = (dateString: string) => { + const date = new Date(dateString); + return new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric' + }).format(date); + }; + + // Get file icon based on MIME type + const getFileIcon = (mimeType: string) => { + if (mimeType.includes('pdf')) { + return ( + + + + ); + } else if (mimeType.includes('word') || mimeType.includes('document')) { + return ( + + + + ); + } else if (mimeType.includes('excel') || mimeType.includes('spreadsheet')) { + return ( + + + + ); + } else { + return ( + + + + ); + } + }; + + return ( +
+
+
+

Documents

+

+ Manage bylaws, meeting minutes, forms, and other documents. +

+
+
+ + + + + Upload Document + +
+
+ + {/* Filter component */} + + + {/* Bulk actions */} + {selectedDocuments.length > 0 && ( +
+
+ {selectedDocuments.length} document{selectedDocuments.length > 1 ? 's' : ''} selected +
+
+ + +
+
+ )} + + {/* Documents table */} +
+
+ + + + + + + + + + + + + + {filteredDocuments.map((document) => ( + + + + + + + + + + ))} + +
+
+ + +
+
+ Document + + Category + + Size + + Dates + + Visibility + + Actions +
+
+ handleSelectDocument(document.id, e.target.checked)} + /> + +
+
+
+
+ {getFileIcon(document.mimeType)} +
+
+
+ {document.title} +
+
+ {document.description} +
+
+ {document.tags.map((tag) => ( + + {tag} + + ))} +
+
+
+
+
{document.category}
+
+
{document.fileSize}
+
+
+ Uploaded: {formatDate(document.uploadDate)} +
+
+ Modified: {formatDate(document.lastModified)} +
+
+ + {document.isPublic ? 'Public' : 'Private'} + + +
+ + View + + + Edit + + +
+
+
+ + {filteredDocuments.length === 0 && ( +
+

No documents found matching the current filters.

+
+ )} +
+
+ ); +} diff --git a/frontend/src/app/admin/events/page.tsx b/frontend/src/app/admin/events/page.tsx new file mode 100644 index 0000000..1c889fa --- /dev/null +++ b/frontend/src/app/admin/events/page.tsx @@ -0,0 +1,336 @@ +'use client'; + +import React, { useState } from 'react'; +import Link from 'next/link'; + +// Simple Filter Component +const EventFilter = ({ + onFilterChange +}: { + onFilterChange: (filter: { status: string; category: string; search: string }) => void +}) => { + const [status, setStatus] = useState('all'); + const [category, setCategory] = useState('all'); + const [search, setSearch] = useState(''); + + const handleFilterChange = () => { + onFilterChange({ status, category, search }); + }; + + const handleReset = () => { + setStatus('all'); + setCategory('all'); + setSearch(''); + onFilterChange({ status: 'all', category: 'all', search: '' }); + }; + + return ( +
+

Filter Events

+
+
+ + +
+ +
+ + +
+ +
+ + setSearch(e.target.value)} + /> +
+
+ +
+ + +
+
+ ); +}; + +export default function EventsPage() { + const [filter, setFilter] = useState({ status: 'all', category: 'all', search: '' }); + + // Mock events data - would come from API in a real implementation + const allEvents = [ + { + id: '1', + title: 'Monthly Social', + date: 'Apr 15, 2025', + time: '6:00 PM - 9:00 PM', + location: 'Olathe Community Center', + category: 'social', + status: 'published', + registrationRequired: true, + registeredCount: 24 + }, + { + id: '2', + title: 'ASL Workshop', + date: 'Apr 22, 2025', + time: '10:00 AM - 12:00 PM', + location: 'OCD Meeting Room', + category: 'educational', + status: 'draft', + registrationRequired: true, + registeredCount: 12 + }, + { + id: '3', + title: 'Board Meeting', + date: 'May 5, 2025', + time: '7:00 PM - 8:30 PM', + location: 'Zoom Meeting', + category: 'board', + status: 'published', + registrationRequired: false, + registeredCount: 0 + }, + { + id: '4', + title: 'Summer Picnic', + date: 'Jun 12, 2025', + time: '12:00 PM - 4:00 PM', + location: 'Olathe Park', + category: 'social', + status: 'draft', + registrationRequired: true, + registeredCount: 0 + }, + { + id: '5', + title: 'Deaf Awareness Week Workshop', + date: 'Sep 23, 2025', + time: '6:30 PM - 8:30 PM', + location: 'Olathe Public Library', + category: 'educational', + status: 'published', + registrationRequired: true, + registeredCount: 8 + }, + { + id: '6', + title: 'Holiday Party', + date: 'Dec 18, 2025', + time: '7:00 PM - 10:00 PM', + location: 'Olathe Community Center', + category: 'social', + status: 'draft', + registrationRequired: true, + registeredCount: 0 + }, + ]; + + // Filter events based on current filter settings + const filteredEvents = allEvents.filter(event => { + if (filter.status !== 'all' && event.status !== filter.status) return false; + if (filter.category !== 'all' && event.category !== filter.category) return false; + if (filter.search && !event.title.toLowerCase().includes(filter.search.toLowerCase()) && + !event.location.toLowerCase().includes(filter.search.toLowerCase())) return false; + return true; + }); + + // Handle filter changes + const handleFilterChange = (newFilter: { status: string; category: string; search: string }) => { + setFilter(newFilter); + }; + + // Function to get status badge styles + const getStatusBadgeClasses = (status: string) => { + switch (status) { + case 'published': + return 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200'; + case 'draft': + return 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300'; + case 'archived': + return 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-200'; + default: + return 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300'; + } + }; + + // Function to get category badge styles + const getCategoryBadgeClasses = (category: string) => { + switch (category) { + case 'social': + return 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-200'; + case 'educational': + return 'bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-200'; + case 'board': + return 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-200'; + case 'athletic': + return 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900 dark:text-indigo-200'; + default: + return 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300'; + } + }; + + return ( +
+
+
+

Events

+

+ Manage club events, registrations, and schedules. +

+
+
+ + + + + Create Event + +
+
+ + {/* Filter component */} + + + {/* Events table */} +
+
+ + + + + + + + + + + + + {filteredEvents.map((event) => ( + + + + + + + + + ))} + +
+ Event + + Date & Time + + Location + + Status + + Registrations + + Actions +
+
+
+
{event.title}
+
+ + {event.category.charAt(0).toUpperCase() + event.category.slice(1)} + +
+
+
+
+
{event.date}
+
{event.time}
+
+
{event.location}
+
+ + {event.status.charAt(0).toUpperCase() + event.status.slice(1)} + + + {event.registrationRequired ? ( + {event.registeredCount} registered + ) : ( + Not required + )} + +
+ + View + + + Edit + + +
+
+
+ + {filteredEvents.length === 0 && ( +
+

No events found matching the current filters.

+
+ )} +
+
+ ); +} diff --git a/frontend/src/app/admin/layout.tsx b/frontend/src/app/admin/layout.tsx new file mode 100644 index 0000000..4721cc0 --- /dev/null +++ b/frontend/src/app/admin/layout.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Admin Portal | Olathe Club of the Deaf', + description: 'Secure administration portal for the Olathe Club of the Deaf website', +}; + +export default function AdminLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+ {children} +
+ ); +} diff --git a/frontend/src/app/admin/login/page.tsx b/frontend/src/app/admin/login/page.tsx new file mode 100644 index 0000000..22a75f9 --- /dev/null +++ b/frontend/src/app/admin/login/page.tsx @@ -0,0 +1,152 @@ +'use client'; + +import React, { useState } from 'react'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; +import type { Metadata } from 'next'; + +// Note: This can't be exported from a client component +// The metadata would need to be in a separate layout.tsx file +const metadata = { + title: 'Admin Login | Olathe Club of the Deaf', + description: 'Secure login for Olathe Club of the Deaf administrators', +}; + +const LoginPage = () => { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(''); + const [loading, setLoading] = useState(false); + const router = useRouter(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(''); + setLoading(true); + + try { + // This will be replaced with actual API call in the future + // For now, it's just a mock implementation + const response = await fetch('/api/auth/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ username, password }), + }); + + if (!response.ok) { + const data = await response.json(); + throw new Error(data.message || 'Login failed'); + } + + // Login successful, redirect to admin dashboard + router.push('/admin/dashboard'); + } catch (err) { + console.error('Login error:', err); + setError(err instanceof Error ? err.message : 'An unknown error occurred'); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+

+ OCD Admin Portal +

+

+ Secure login for authorized administrators +

+
+ +
+ {error && ( +
+ {error} +
+ )} + +
+
+
+ + setUsername(e.target.value)} + aria-required="true" + /> +
+
+ + setPassword(e.target.value)} + aria-required="true" + /> +
+
+ +
+
+ + +
+ +
+ + Forgot your password? + +
+
+ +
+ +
+
+
+ +
+ + Return to public site + +
+
+
+ ); +}; + +export default LoginPage; diff --git a/frontend/src/app/admin/members/page.tsx b/frontend/src/app/admin/members/page.tsx new file mode 100644 index 0000000..a591747 --- /dev/null +++ b/frontend/src/app/admin/members/page.tsx @@ -0,0 +1,456 @@ +'use client'; + +import React, { useState } from 'react'; +import Link from 'next/link'; + +// Member Filter Component +const MemberFilter = ({ + onFilterChange +}: { + onFilterChange: (filter: { status: string; type: string; search: string }) => void +}) => { + const [status, setStatus] = useState('all'); + const [type, setType] = useState('all'); + const [search, setSearch] = useState(''); + + const handleFilterChange = () => { + onFilterChange({ status, type, search }); + }; + + const handleReset = () => { + setStatus('all'); + setType('all'); + setSearch(''); + onFilterChange({ status: 'all', type: 'all', search: '' }); + }; + + return ( +
+

Filter Members

+
+
+ + +
+ +
+ + +
+ +
+ + setSearch(e.target.value)} + /> +
+
+ +
+ + +
+
+ ); +}; + +// Bulk actions component +const BulkActions = ({ selectedMembers, onAction }: { selectedMembers: string[], onAction: (action: string) => void }) => { + if (selectedMembers.length === 0) return null; + + return ( +
+
+ {selectedMembers.length} member{selectedMembers.length > 1 ? 's' : ''} selected +
+
+ + +
+
+ ); +}; + +export default function MembersPage() { + const [filter, setFilter] = useState({ status: 'all', type: 'all', search: '' }); + const [selectedMembers, setSelectedMembers] = useState([]); + const [selectAll, setSelectAll] = useState(false); + + // Mock members data - would come from API in a real implementation + const allMembers = [ + { + id: '1', + firstName: 'John', + lastName: 'Smith', + email: 'john.smith@example.com', + phone: '(913) 555-1234', + membershipType: 'regular', + joinDate: '2019-06-15', + expirationDate: '2025-06-15', + status: 'active', + lastRenewalDate: '2024-06-10', + }, + { + id: '2', + firstName: 'Sarah', + lastName: 'Johnson', + email: 'sarah.j@example.com', + phone: '(913) 555-5678', + membershipType: 'family', + joinDate: '2021-03-22', + expirationDate: '2025-03-22', + status: 'active', + lastRenewalDate: '2024-03-15', + }, + { + id: '3', + firstName: 'Robert', + lastName: 'Lee', + email: 'robert.lee@example.com', + phone: '(913) 555-9012', + membershipType: 'regular', + joinDate: '2020-11-05', + expirationDate: '2025-03-28', + status: 'expired', + lastRenewalDate: '2023-03-25', + }, + { + id: '4', + firstName: 'Emily', + lastName: 'Davis', + email: 'emily.d@example.com', + phone: '(913) 555-3456', + membershipType: 'lifetime', + joinDate: '2018-09-30', + expirationDate: null, + status: 'active', + lastRenewalDate: null, + }, + { + id: '5', + firstName: 'Michael', + lastName: 'Wilson', + email: 'michael.w@example.com', + phone: '(913) 555-7890', + membershipType: 'regular', + joinDate: '2022-01-15', + expirationDate: '2025-01-15', + status: 'active', + lastRenewalDate: '2024-01-10', + }, + { + id: '6', + firstName: 'Jennifer', + lastName: 'Brown', + email: 'jennifer.b@example.com', + phone: '(913) 555-2345', + membershipType: 'family', + joinDate: '2021-07-20', + expirationDate: '2023-07-20', + status: 'expired', + lastRenewalDate: '2022-07-15', + }, + { + id: '7', + firstName: 'William', + lastName: 'Taylor', + email: 'will.t@example.com', + phone: '(913) 555-6789', + membershipType: 'honorary', + joinDate: '2020-05-10', + expirationDate: null, + status: 'active', + lastRenewalDate: null, + }, + { + id: '8', + firstName: 'Lisa', + lastName: 'Anderson', + email: 'lisa.a@example.com', + phone: '(913) 555-0123', + membershipType: 'regular', + joinDate: '2023-02-28', + expirationDate: '2024-02-28', + status: 'pending', + lastRenewalDate: null, + }, + ]; + + // Filter members based on current filter settings + const filteredMembers = allMembers.filter(member => { + if (filter.status !== 'all' && member.status !== filter.status) return false; + if (filter.type !== 'all' && member.membershipType !== filter.type) return false; + if (filter.search) { + const searchLower = filter.search.toLowerCase(); + const fullName = `${member.firstName} ${member.lastName}`.toLowerCase(); + + if (!fullName.includes(searchLower) && + !member.email.toLowerCase().includes(searchLower) && + !member.phone.includes(filter.search)) { + return false; + } + } + return true; + }); + + // Handle filter changes + const handleFilterChange = (newFilter: { status: string; type: string; search: string }) => { + setFilter(newFilter); + }; + + // Handle bulk actions + const handleBulkAction = (action: string) => { + // In a real app, this would call an API + alert(`Perform ${action} on ${selectedMembers.length} members`); + }; + + // Handle select all checkbox + const handleSelectAll = (event: React.ChangeEvent) => { + const checked = event.target.checked; + setSelectAll(checked); + + if (checked) { + setSelectedMembers(filteredMembers.map(member => member.id)); + } else { + setSelectedMembers([]); + } + }; + + // Handle individual checkbox selection + const handleSelectMember = (memberId: string, checked: boolean) => { + if (checked) { + setSelectedMembers(prev => [...prev, memberId]); + } else { + setSelectedMembers(prev => prev.filter(id => id !== memberId)); + } + }; + + // Function to get status badge styles + const getStatusBadgeClasses = (status: string) => { + switch (status) { + case 'active': + return 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200'; + case 'expired': + return 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-200'; + case 'pending': + return 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-200'; + default: + return 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300'; + } + }; + + // Format date for display + const formatDate = (dateString: string | null) => { + if (!dateString) return 'N/A'; + + const date = new Date(dateString); + return new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric' + }).format(date); + }; + + return ( +
+
+
+

Members

+

+ Manage memberships, track expirations, and communicate with members. +

+
+
+ + + + + Add Member + +
+
+ + {/* Filter component */} + + + {/* Bulk actions */} + + + {/* Members table */} +
+
+ + + + + + + + + + + + + + {filteredMembers.map((member) => ( + + + + + + + + + + ))} + +
+
+ + +
+
+ Member + + Contact + + Membership + + Dates + + Status + + Actions +
+
+ handleSelectMember(member.id, e.target.checked)} + /> + +
+
+
+
+
+ {member.firstName} {member.lastName} +
+
+
+
+
{member.email}
+
{member.phone}
+
+
{member.membershipType}
+
+
+ Joined: {formatDate(member.joinDate)} +
+
+ Expires: {formatDate(member.expirationDate)} +
+
+ + {member.status.charAt(0).toUpperCase() + member.status.slice(1)} + + +
+ + View + + + Edit + + +
+
+
+ + {filteredMembers.length === 0 && ( +
+

No members found matching the current filters.

+
+ )} +
+
+ ); +} diff --git a/frontend/src/app/admin/page.tsx b/frontend/src/app/admin/page.tsx new file mode 100644 index 0000000..3aaa198 --- /dev/null +++ b/frontend/src/app/admin/page.tsx @@ -0,0 +1,9 @@ +import { redirect } from 'next/navigation'; + +export default function AdminPage() { + // Redirect to login page + redirect('/admin/login'); + + // This won't be rendered, but is needed for TypeScript + return null; +} diff --git a/frontend/src/app/admin/settings/page.tsx b/frontend/src/app/admin/settings/page.tsx new file mode 100644 index 0000000..57c929a --- /dev/null +++ b/frontend/src/app/admin/settings/page.tsx @@ -0,0 +1,621 @@ +'use client'; + +import React, { useState } from 'react'; + +export default function SettingsPage() { + // Mock settings data - would be loaded from API in real implementation + const [generalSettings, setGeneralSettings] = useState({ + siteName: 'Olathe Club of the Deaf', + siteDescription: 'The official website for the Olathe Club of the Deaf, serving the deaf community in Olathe, Kansas.', + contactEmail: 'info@olathedeafclub.com', + notificationEmail: 'notifications@olathedeafclub.com', + facebookUrl: 'https://facebook.com/olathedeafclub', + instagramUrl: 'https://instagram.com/olathedeafclub', + address: '123 Main Street, Olathe, KS 66061', + googleMapsUrl: 'https://goo.gl/maps/exampleMapLink' + }); + + const [emailSettings, setEmailSettings] = useState({ + smtpHost: 'smtp.gmail.com', + smtpPort: '587', + smtpUsername: 'system@olathedeafclub.com', + smtpPassword: '••••••••••••', + fromName: 'Olathe Club of the Deaf', + fromEmail: 'system@olathedeafclub.com', + replyToEmail: 'info@olathedeafclub.com' + }); + + const [membershipSettings, setMembershipSettings] = useState({ + regularMembershipFee: '30', + familyMembershipFee: '45', + lifetimeMembershipFee: '500', + expirationReminderDays: '30', + automaticRenewalEnabled: false, + sendWelcomeEmail: true, + sendExpirationReminders: true, + sendExpiredNotifications: true, + notifyBoardOnExpirations: true + }); + + const [accessibilitySettings, setAccessibilitySettings] = useState({ + highContrastModeEnabled: true, + reducedMotionEnabled: true, + defaultVideoSubtitles: true, + defaultFontSize: 'medium', + defaultASLVideoDuration: '3', // in minutes + transcriptRequiredForVideos: true, + autoTranslateEnabled: false + }); + + // Handle form submit + const handleSubmit = (e: React.FormEvent, section: string) => { + e.preventDefault(); + // In a real app, this would save settings to the API + alert(`Saved ${section} settings`); + }; + + // Handle changes for each settings section + const handleGeneralChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setGeneralSettings(prev => ({ ...prev, [name]: value })); + }; + + const handleEmailChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setEmailSettings(prev => ({ ...prev, [name]: value })); + }; + + const handleMembershipChange = ( + e: React.ChangeEvent + ) => { + const { name, value, type } = e.target as HTMLInputElement; + const newValue = type === 'checkbox' ? (e.target as HTMLInputElement).checked : value; + setMembershipSettings(prev => ({ ...prev, [name]: newValue })); + }; + + const handleAccessibilityChange = ( + e: React.ChangeEvent + ) => { + const { name, value, type } = e.target as HTMLInputElement; + const newValue = type === 'checkbox' ? (e.target as HTMLInputElement).checked : value; + setAccessibilitySettings(prev => ({ ...prev, [name]: newValue })); + }; + + // Test email connection + const testEmailConnection = async () => { + // In a real app, this would send a test email via API + alert('Test email sent successfully!'); + }; + + return ( +
+
+

Settings

+

+ Configure website settings, email notifications, and accessibility options. +

+
+ + {/* Tabs */} + + + {/* Settings Sections */} +
+ {/* General Settings */} +
+

General Settings

+
handleSubmit(e, 'general')}> +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+