Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0535ece
docs: add comprehensive documentation to main.jsx
fraidakis Dec 25, 2025
0c6e8de
docs: add comprehensive documentation to LanguageSwitcher.jsx
fraidakis Dec 25, 2025
43ee5f5
docs: add comprehensive documentation to context/index.jsx
fraidakis Dec 25, 2025
183434a
docs: add comprehensive documentation to hooks/index.js
fraidakis Dec 25, 2025
d5a9c20
docs: add comprehensive documentation to i18n/index.js
fraidakis Dec 25, 2025
f48981f
docs: add comprehensive documentation to FavouritesPage.jsx
fraidakis Dec 25, 2025
cd93a35
docs: add comprehensive documentation to NavigationPage.jsx
fraidakis Dec 25, 2025
98adab6
docs: add comprehensive documentation to PlaceDetailsPage.jsx
fraidakis Dec 25, 2025
9da72f2
docs: add comprehensive documentation to PreferencesPage.jsx
fraidakis Dec 25, 2025
f8f71d9
docs: add comprehensive documentation to UserProfilePage.jsx
fraidakis Dec 25, 2025
e85a532
docs: add comprehensive documentation to LoadingSpinner3D.jsx
fraidakis Dec 25, 2025
800ce14
docs: add comprehensive documentation to HomePage.jsx
fraidakis Dec 25, 2025
4f09486
docs: add comprehensive documentation to RecommendationsPage.jsx and …
fraidakis Dec 25, 2025
3e0a2e4
docs: add documentation to el/common.js, el/features.js, useCardTilt.…
fraidakis Dec 25, 2025
4efc916
docs: add documentation to i18n locale files and SignupPage
fraidakis Dec 25, 2025
d59e5f6
docs: add file headers to RouteForm, ProfileInfoCard, ReviewsSection
fraidakis Dec 25, 2025
1a31496
docs: add file headers to usePlaceActions, PreferenceForm, router
fraidakis Dec 25, 2025
dd07792
docs: add file headers to RecommendationFilters, SettingsCard, Profil…
fraidakis Dec 25, 2025
638a62c
docs: add file headers to FavouriteListItem, FeaturesSection, CTASect…
fraidakis Dec 25, 2025
dafad46
docs: add file headers to usePlaceDetails, useAutocomplete, Toast
fraidakis Dec 25, 2025
20a33a4
docs: add file headers to PlaceActionsBar, RouteResults, TravelGlobe,…
fraidakis Dec 25, 2025
c3aac1a
docs: add file header to BottomNavigation
fraidakis Dec 25, 2025
b3fed56
docs: add file header to ReportModal
fraidakis Dec 25, 2025
87b2c7d
docs: add file headers to vite.config, Carousel3D, Footer, Header, Us…
fraidakis Dec 25, 2025
2aa0fd2
docs: add comprehensive inline comments to improve comment density
fraidakis Dec 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion cypress/e2e/auth_login_logout.cy.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
/**
* E2E Tests for Login & Logout Flows
* @fileoverview E2E Tests for Login & Logout Flows
* Tests authentication workflow, session persistence, and protected routes.
* Split from auth_happy_unhappy.cy.js for file size optimization
* @module cypress/e2e/auth_login_logout
*/

import { visitLogin, expectUrlToEqual, expectUrlToContain, fillLoginForm, submitForm, logMessage } from '../support/helpers';

/**
* Test suite for authentication flows.
* Covers login, logout, session persistence, and route protection.
*/
describe('Login & Logout Flows', () => {
// Clear state before each test for isolation
beforeEach(() => { cy.clearLocalStorage(); cy.clearCookies(); });

/**
* Login Page Tests
* Verify login form renders and authentication succeeds with valid credentials.
*/
describe('Login Page', () => {
// Test: Page loads correctly
it('should load the login page', () => {
visitLogin();
cy.contains(/login/i).should('be.visible');
});

// Test: Login with custom test user fixture
it('should successfully log in with valid credentials', () => {
cy.loginAsTestUser('validUser');
expectUrlToEqual('/');
cy.shouldBeAuthenticated();
logMessage('✅ Successfully logged in with test user');
});

// Test: Login with hardcoded demo credentials
it('should log in with demo user credentials', () => {
cy.login('user1@example.com', 'password123');
cy.url().should('not.include', '/login');
Expand All @@ -28,7 +43,12 @@ describe('Login & Logout Flows', () => {
});
});

/**
* Logout Tests
* Verify logout clears session and redirects appropriately.
*/
describe('Logout', () => {
// Test: Programmatic logout
it('should successfully log out', () => {
cy.loginAsTestUser('validUser');
cy.url().should('not.include', '/login');
Expand All @@ -37,6 +57,7 @@ describe('Login & Logout Flows', () => {
logMessage('✅ Successfully logged out');
});

// Test: Logout via UI dropdown button
it('should log out via UI logout button', () => {
cy.loginAsTestUser('validUser');
cy.get('[data-cy="user-dropdown-trigger"]').should('be.visible').click();
Expand All @@ -47,7 +68,12 @@ describe('Login & Logout Flows', () => {
});
});

/**
* Session Persistence Tests
* Verify session survives page reloads and data is stored correctly.
*/
describe('Session Persistence', () => {
// Test: Session survives reload
it('should maintain session after page reload', () => {
cy.loginAsTestUser('validUser');
expectUrlToEqual('/');
Expand All @@ -57,6 +83,7 @@ describe('Login & Logout Flows', () => {
logMessage('✅ Session persists after page reload');
});

// Test: User data in localStorage is correct
it('should restore user data from localStorage', () => {
cy.loginAsTestUser('validUser');
cy.window().its('localStorage.user').should('exist');
Expand All @@ -69,7 +96,12 @@ describe('Login & Logout Flows', () => {
});
});

/**
* Protected Route Tests
* Verify authenticated users can access protected routes.
*/
describe('Protected Routes', () => {
// Test: Authenticated access to profile page
it('should allow access to protected route when authenticated', () => {
cy.loginAsTestUser('validUser');
cy.visit('/profile');
Expand Down
28 changes: 27 additions & 1 deletion cypress/e2e/auth_validation.cy.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
/**
* E2E Tests for Authentication Validation Errors
* @fileoverview E2E Tests for Authentication Validation Errors
* Tests form validation, error messages, and protected route access.
* Split from auth_happy_unhappy.cy.js for file size optimization
* @module cypress/e2e/auth_validation
*/

import { visitLogin, visitSignup, expectUrlToContain, fillLoginForm, fillSignupForm, submitForm, getRandomEmail, logMessage } from '../support/helpers';

/**
* Test suite for authentication validation.
* Covers signup validation, login errors, and route protection.
*/
describe('Authentication Validation Errors', () => {
// Clear state before each test for isolation
beforeEach(() => { cy.clearLocalStorage(); cy.clearCookies(); });

/**
* Signup Validation Tests
* Tests email format, password strength, and required fields.
*/
describe('Signup Validation Errors', () => {
// Test: Invalid email format validation
it('should show email validation error for invalid email format', () => {
cy.intercept('POST', '**/auth/signup').as('signupRequest');
visitSignup();
Expand All @@ -18,6 +31,7 @@ describe('Authentication Validation Errors', () => {
cy.window().its('localStorage.token').should('not.exist');
});

// Test: Weak password validation
it('should show password strength error for weak password', () => {
visitSignup();
fillSignupForm({ name: 'Test User', email: getRandomEmail(), password: 'weak', confirmPassword: 'weak' });
Expand All @@ -26,6 +40,7 @@ describe('Authentication Validation Errors', () => {
expectUrlToContain('/signup');
});

// Test: Password confirmation mismatch
it('should show error for mismatched password confirmation', () => {
visitSignup();
cy.get('[data-cy="input-name"]').clear().type('Test User');
Expand All @@ -37,6 +52,7 @@ describe('Authentication Validation Errors', () => {
expectUrlToContain('/signup');
});

// Test: Required fields validation
it('should show required field errors for empty form submission', () => {
visitSignup();
submitForm();
Expand All @@ -61,7 +77,12 @@ describe('Authentication Validation Errors', () => {
});
});

/**
* Login Authentication Error Tests
* Tests wrong credentials, required fields, and invalid email.
*/
describe('Login Authentication Errors', () => {
// Test: Invalid credentials returns auth error
it('should show auth error for incorrect credentials', () => {
cy.intercept('POST', '**/auth/login', { statusCode: 401, body: { success: false, message: 'Invalid credentials' } }).as('login');
visitLogin();
Expand All @@ -88,7 +109,12 @@ describe('Authentication Validation Errors', () => {
});
});

/**
* Protected Route Access Control Tests
* Verifies unauthenticated users are redirected to login.
*/
describe('Protected Route Access Control - Unauthenticated', () => {
// Routes requiring authentication
const protectedRoutes = [
{ path: '/recommendations', name: 'Recommendations' },
{ path: '/profile', name: 'User Profile' },
Expand Down
60 changes: 59 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
/**
* @fileoverview Root Application Component.
*
* This is the main application component that sets up the entire application
* structure including:
* - Context providers (Theme, Language, Toast)
* - React Router configuration
* - Layout structure (Header, Main, Footer, Bottom Navigation)
* - Authentication state management
*
* The component hierarchy ensures all child components have access to:
* - Theme context for light/dark mode
* - Language context for i18n translations
* - Toast context for notifications
* - Router context for navigation
*
* @module App
* @requires react
* @requires react-router-dom
* @requires ./i18n - Language provider
* @requires ./context - Theme provider
*/

import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { LanguageProvider } from './i18n';
Expand All @@ -9,44 +32,78 @@ import ScrollToTop from './components/ScrollToTop.jsx';
import AppRoutes from './router/index.jsx';
import './App.css';

/**
* App Component
*
* The root component that wraps the entire application with necessary
* providers and sets up the main layout structure. Tracks authentication
* state for conditional rendering of navigation elements.
*
* Provider hierarchy (outermost to innermost):
* 1. ThemeProvider - Dark/light mode
* 2. LanguageProvider - Internationalization
* 3. ToastProvider - Notification system
* 4. Router - Navigation
*
* @function App
* @returns {React.ReactElement} The complete application structure
*/
function App() {
// Track user authentication state for conditional UI
const [isAuthenticated, setIsAuthenticated] = useState(false);

/**
* Sets up authentication state tracking on mount.
* Listens for login/logout events and storage changes.
*/
useEffect(() => {
// Check for existing token on mount
const token = localStorage.getItem('token');
setIsAuthenticated(!!token);

// Listen for login/logout events
// Event handlers for auth state changes
const handleLogin = () => setIsAuthenticated(true);
const handleLogout = () => setIsAuthenticated(false);

// Listen for custom login/logout events
window.addEventListener('user:login', handleLogin);
window.addEventListener('user:logout', handleLogout);

// Listen for storage changes (handles logout from other tabs)
window.addEventListener('storage', (e) => {
if (e.key === 'token') {
setIsAuthenticated(!!e.newValue);
}
});

// Cleanup event listeners on unmount
return () => {
window.removeEventListener('user:login', handleLogin);
window.removeEventListener('user:logout', handleLogout);
};
}, []);

return (
// Theme provider for dark/light mode support
<ThemeProvider>
{/* Language provider for internationalization */}
<LanguageProvider>
{/* Toast provider for notification system */}
<ToastProvider>
{/* React Router for client-side navigation */}
<Router>
{/* Scroll restoration on route change */}
<ScrollToTop />
<div className="App">
{/* Site header with navigation */}
<Header />
{/* Main content area with routes */}
<main className="main-content">
<AppRoutes />
</main>
{/* Site footer */}
<Footer />
{/* Mobile bottom navigation bar */}
<BottomNavigation isAuthenticated={isAuthenticated} />
</div>
</Router>
Expand All @@ -57,3 +114,4 @@ function App() {
}

export default App;

6 changes: 6 additions & 0 deletions src/components/3d/TravelGlobe.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* @fileoverview 3D Travel Globe component.
* Interactive globe with orbiting satellites using Three.js.
* @module components/3d/TravelGlobe
*/

import React, { useRef } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { Icosahedron, OrbitControls, Stars } from '@react-three/drei';
Expand Down
6 changes: 6 additions & 0 deletions src/components/Carousel3D.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* @fileoverview 3D Coverflow-style carousel component.
* Features smooth animations, drag support, and keyboard navigation.
* @module components/Carousel3D
*/

import React, { useState, useEffect, useRef, useCallback } from 'react';
import PropTypes from 'prop-types';
import Icon from './ui/Icon';
Expand Down
6 changes: 6 additions & 0 deletions src/components/Footer.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* @fileoverview Site footer component.
* Contains branding, navigation links, and copyright.
* @module components/Footer
*/

import React from 'react';
import { Link } from 'react-router-dom';
import { useTranslation } from '../i18n';
Expand Down
6 changes: 6 additions & 0 deletions src/components/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* @fileoverview Site header component.
* Professional navigation with glassmorphism, user dropdown, and scroll effects.
* @module components/Header
*/

import React, { useState, useEffect } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { useAuth } from '../hooks';
Expand Down
37 changes: 35 additions & 2 deletions src/components/LanguageSwitcher.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@
/**
* @fileoverview Language Switcher Component for internationalization support.
*
* Provides a button that allows users to toggle between English and Greek
* languages in the application. Uses the translation context to manage
* the current language state.
*
* @module components/LanguageSwitcher
* @requires react
* @requires ../i18n - Translation context and hooks
*/

import React from 'react';
import { useTranslation } from '../i18n';
import './LanguageSwitcher.css';

/**
* LanguageSwitcher Component
*
* A button component that toggles the application language between
* English (EN) and Greek (EL). The button displays the opposite language
* code from the currently active language, indicating what language
* the user will switch to upon clicking.
*
* @component
* @example
* // Basic usage in a navigation bar
* <LanguageSwitcher />
*
* @returns {React.ReactElement} A styled button for language toggling
*
* @see {@link module:i18n/LanguageContext} for language context implementation
*/
const LanguageSwitcher = () => {
// Get current language and toggle function from translation context
const { language, toggleLanguage } = useTranslation();

return (
<button
className="language-switcher"
<button
className="language-switcher"
onClick={toggleLanguage}
aria-label="Change language"
>
{/* Globe emoji followed by the target language code */}
{/* Shows 'EL' when current language is English, 'EN' when Greek */}
🌐 {language === 'en' ? 'EL' : 'EN'}
</button>
);
};

export default LanguageSwitcher;

6 changes: 6 additions & 0 deletions src/components/UserDropdown.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* @fileoverview User dropdown menu component.
* Avatar with dropdown for profile, preferences, and logout.
* @module components/UserDropdown
*/

import React, { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import { useAuth } from '../hooks';
Expand Down
Loading
Loading