diff --git a/src/components/home/FeaturesSection.jsx b/src/components/home/FeaturesSection.jsx
index 37babcfa..cb4cb0e4 100644
--- a/src/components/home/FeaturesSection.jsx
+++ b/src/components/home/FeaturesSection.jsx
@@ -16,7 +16,7 @@ const FeaturesSection = ({ t }) => {
{t('whatWeOffer')}
-
Everything you need for your perfect travel experience
+
{t('whatWeOfferSubtitle')}
diff --git a/src/components/preferences/PreferenceForm.jsx b/src/components/preferences/PreferenceForm.jsx
index 26a7fb66..57f00e49 100644
--- a/src/components/preferences/PreferenceForm.jsx
+++ b/src/components/preferences/PreferenceForm.jsx
@@ -19,7 +19,7 @@ const CATEGORY_ICONS = {
/**
* Preference form for creating/editing preference profiles
*/
-const PreferenceForm = ({ t, formData, setFormData, editingProfile, onSubmit, onClose }) => {
+const PreferenceForm = ({ t, formData, setFormData, editingProfile, onSubmit, onClose, showError }) => {
const toggleCategory = (category) => {
setFormData(prev => {
const categories = prev.categories || [];
@@ -32,6 +32,24 @@ const PreferenceForm = ({ t, formData, setFormData, editingProfile, onSubmit, on
});
};
+ const handleSubmit = (e) => {
+ e.preventDefault();
+
+ // Validate name
+ if (!formData.name || !formData.name.trim()) {
+ showError(t('profileNameRequired'));
+ return;
+ }
+
+ // Validate categories
+ if (!formData.categories || formData.categories.length === 0) {
+ showError(t('categoryMinOne'));
+ return;
+ }
+
+ onSubmit(e);
+ };
+
return (
@@ -41,7 +59,7 @@ const PreferenceForm = ({ t, formData, setFormData, editingProfile, onSubmit, on
-
@@ -88,3 +104,4 @@ const PreferenceForm = ({ t, formData, setFormData, editingProfile, onSubmit, on
export { PreferenceForm, CATEGORY_ICONS };
export default PreferenceForm;
+
diff --git a/src/components/preferences/ProfileCard.jsx b/src/components/preferences/ProfileCard.jsx
index 9c08c6e9..caaee90c 100644
--- a/src/components/preferences/ProfileCard.jsx
+++ b/src/components/preferences/ProfileCard.jsx
@@ -35,11 +35,11 @@ const ProfileCard = ({ t, profile, isActive, index, onActivate, onEdit, onDelete
{(profile.categories || []).map(cat => (
- {CATEGORY_ICONS[cat]} {cat}
+ {CATEGORY_ICONS[cat]} {t(cat)}
))}
{(!profile.categories || profile.categories.length === 0) && (
- No categories selected
+ {t('noCategoriesSelected')}
)}
diff --git a/src/components/recommendations/RecommendationFilters.jsx b/src/components/recommendations/RecommendationFilters.jsx
index 84c2f05b..6c1325c0 100644
--- a/src/components/recommendations/RecommendationFilters.jsx
+++ b/src/components/recommendations/RecommendationFilters.jsx
@@ -58,10 +58,10 @@ const RecommendationFilters = ({
/>
diff --git a/src/i18n/locales/el/common.json b/src/i18n/locales/el/common.json
index 9c405930..fa7d7b91 100644
--- a/src/i18n/locales/el/common.json
+++ b/src/i18n/locales/el/common.json
@@ -41,6 +41,7 @@
"ctaDescription": "Γίνετε μέλος χιλιάδων ταξιδιωτών που ανακαλύπτουν εκπληκτικούς προορισμούς κάθε μέρα.",
"exploreDestinations": "Εξερευνήστε Προορισμούς",
"whatWeOffer": "Τι προσφέρουμε",
+ "whatWeOfferSubtitle": "Ό,τι χρειάζεστε για μια τέλεια ταξιδιωτική εμπειρία",
"personalizedRecommendations": "Εξατομικευμένες Προτάσεις",
"personalizedRecommendationsDesc": "Λάβετε προτάσεις βασισμένες στις προτιμήσεις σας",
"reviews": "Αξιολογήσεις",
@@ -68,7 +69,8 @@
"haveAccount": "Έχετε ήδη λογαριασμό;",
"loginLink": "Συνδεθείτε εδώ",
"signupError": "Σφάλμα εγγραφής. Το email μπορεί να χρησιμοποιείται ήδη",
- "passwordRequirement": "Τουλάχιστον 6 χαρακτήρες (κεφαλαίο, πεζό, αριθμό)"
+ "passwordRequirement": "Τουλάχιστον 6 χαρακτήρες (κεφαλαίο, πεζό, αριθμό)",
+ "namePlaceholder": "Γιάννης Παπαδόπουλος"
},
"validation": {
"invalidEmail": "Μη έγκυρη διεύθυνση email",
diff --git a/src/i18n/locales/el/features.json b/src/i18n/locales/el/features.json
index 22a47b14..d2020a2b 100644
--- a/src/i18n/locales/el/features.json
+++ b/src/i18n/locales/el/features.json
@@ -3,6 +3,7 @@
"from": "Από",
"to": "Προς",
"getRoute": "Εύρεση Διαδρομής",
+ "navigationTitle": "Πλοήγηση Διαδρομής",
"navigationSubtitle": "Βρείτε τη διαδρομή προς τον προορισμό σας",
"calculateRoute": "Υπολογισμός Διαδρομής",
"startPoint": "Σημείο Εκκίνησης",
@@ -22,6 +23,9 @@
"minutes": "λεπτά",
"mapView": "Προβολή χάρτη (θα ενσωματωθεί σε μελλοντική έκδοση)",
"quickRoutes": "Γρήγορες Διαδρομές",
+ "routeAthensToThessaloniki": "Αθήνα → Θεσσαλονίκη",
+ "routeThessalonikiToAthens": "Θεσσαλονίκη → Αθήνα",
+ "routeHeraklionToAthens": "Ηράκλειο → Αθήνα",
"resolvingLocation": "Εύρεση τοποθεσίας...",
"enterLocation": "Τοποθεσία",
"searchLocationPlaceholder": "π.χ., Αθήνα, Ελλάδα",
@@ -31,7 +35,7 @@
"enterLocationsToStart": "Εισάγετε τοποθεσίες ή επιλέξτε μια γρήγορη διαδρομή"
},
"recommendationsPage": {
- "recommendationsTitle": "✨ Προτάσεις για Εσάς",
+ "recommendationsTitle": "Προτάσεις για Εσάς",
"recommendationsSubtitle": "Εξατομικευμένες προτάσεις βασισμένες στις προτιμήσεις σας",
"filtersTitle": "Φίλτρα Αναζήτησης",
"latitude": "Γεωγραφικό Πλάτος",
@@ -42,8 +46,14 @@
"errorLoadingRecommendations": "Σφάλμα κατά τη φόρτωση των προτάσεων",
"noRecommendationsFound": "Δεν βρέθηκαν προτάσεις",
"tryAgain": "Προσπάθεια Ξανά",
+ "createProfileForRecommendations": "Δημιουργήστε ένα προφίλ προτιμήσεων για να δείτε προτάσεις",
"goToPreferences": "Πηγαίνετε στο \"⚙️ Προφίλ Προτιμήσεων\" για να δημιουργήσετε ένα προφίλ",
- "tryDifferentFilters": "Δοκιμάστε να αλλάξετε τα φίλτρα αναζήτησης ή τις κατηγορίες στο προφίλ σας"
+ "tryDifferentFilters": "Δοκιμάστε να αλλάξετε τα φίλτρα αναζήτησης ή τις κατηγορίες στο προφίλ σας",
+ "sortBy": "Ταξινόμηση",
+ "sortByDistance": "Απόσταση",
+ "sortByRating": "Αξιολόγηση",
+ "recommendationSingular": "Πρόταση",
+ "recommendationPlural": "Προτάσεις"
},
"placeDetails": {
"location": "Τοποθεσία",
@@ -105,6 +115,8 @@
"HOTEL": "Ξενοδοχείο",
"CAFE": "Καφετέρια",
"BAR": "Μπαρ",
+ "NIGHTLIFE": "Νυχτερινή Ζωή",
+ "SPORTS": "Αθλητισμός",
"cheap": "Οικονομικό",
"moderate": "Μέτριο",
"expensive": "Ακριβό"
diff --git a/src/i18n/locales/el/pages.json b/src/i18n/locales/el/pages.json
index 5930a20c..d072fca6 100644
--- a/src/i18n/locales/el/pages.json
+++ b/src/i18n/locales/el/pages.json
@@ -51,7 +51,10 @@
"errorUpdatingProfile": "Σφάλμα κατά την ενημέρωση του προφίλ",
"confirmDeleteProfile": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το προφίλ;",
"errorDeletingProfile": "Σφάλμα κατά τη διαγραφή του προφίλ",
- "errorActivatingProfile": "Σφάλμα κατά την ενεργοποίηση του προφίλ"
+ "errorActivatingProfile": "Σφάλμα κατά την ενεργοποίηση του προφίλ",
+ "noCategoriesSelected": "Δεν έχουν επιλεγεί κατηγορίες",
+ "profileNamePlaceholder": "π.χ., Σαββατοκύριακο",
+ "profileNameRequired": "Το όνομα προφίλ δεν μπορεί να είναι κενό ή να περιέχει μόνο κενά"
},
"favouritesPage": {
"favouritesTitle": "Τα Αγαπημένα σας Μέρη",
diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json
index 3d308a95..680ae611 100644
--- a/src/i18n/locales/en/common.json
+++ b/src/i18n/locales/en/common.json
@@ -41,6 +41,7 @@
"ctaDescription": "Join thousands of travelers discovering amazing destinations every day.",
"exploreDestinations": "Explore Destinations",
"whatWeOffer": "What We Offer",
+ "whatWeOfferSubtitle": "Everything you need for your perfect travel experience",
"personalizedRecommendations": "Personalized Recommendations",
"personalizedRecommendationsDesc": "Get recommendations based on your preferences",
"reviews": "Reviews",
@@ -68,7 +69,8 @@
"haveAccount": "Already have an account?",
"loginLink": "Login here",
"signupError": "Signup error. Email may already be in use",
- "passwordRequirement": "At least 6 characters (uppercase, lowercase, number)"
+ "passwordRequirement": "At least 6 characters (uppercase, lowercase, number)",
+ "namePlaceholder": "John Doe"
},
"validation": {
"invalidEmail": "Invalid email address",
diff --git a/src/i18n/locales/en/features.json b/src/i18n/locales/en/features.json
index 6ad1ba4d..feeec099 100644
--- a/src/i18n/locales/en/features.json
+++ b/src/i18n/locales/en/features.json
@@ -3,6 +3,7 @@
"from": "From",
"to": "To",
"getRoute": "Get Route",
+ "navigationTitle": "Route Navigation",
"navigationSubtitle": "Find the route to your destination",
"calculateRoute": "Calculate Route",
"startPoint": "Starting Point",
@@ -22,6 +23,9 @@
"minutes": "minutes",
"mapView": "Map view (will be integrated in future version)",
"quickRoutes": "Quick Routes",
+ "routeAthensToThessaloniki": "Athens → Thessaloniki",
+ "routeThessalonikiToAthens": "Thessaloniki → Athens",
+ "routeHeraklionToAthens": "Heraklion → Athens",
"resolvingLocation": "Resolving location...",
"enterLocation": "Location",
"searchLocationPlaceholder": "e.g., Athens, Greece",
@@ -31,7 +35,7 @@
"enterLocationsToStart": "Enter locations or select a quick route to get started"
},
"recommendationsPage": {
- "recommendationsTitle": "✨ Recommendations for You",
+ "recommendationsTitle": "Recommendations for You",
"recommendationsSubtitle": "Personalized recommendations based on your preferences",
"filtersTitle": "Search Filters",
"latitude": "Latitude",
@@ -42,8 +46,14 @@
"errorLoadingRecommendations": "Error loading recommendations",
"noRecommendationsFound": "No recommendations found",
"tryAgain": "Try Again",
+ "createProfileForRecommendations": "Create a preference profile to see recommendations",
"goToPreferences": "Go to \"⚙️ Preference Profile\" to create a profile",
- "tryDifferentFilters": "Try changing the search filters or categories in your profile"
+ "tryDifferentFilters": "Try changing the search filters or categories in your profile",
+ "sortBy": "Sort By",
+ "sortByDistance": "Distance",
+ "sortByRating": "Rating",
+ "recommendationSingular": "Recommendation",
+ "recommendationPlural": "Recommendations"
},
"placeDetails": {
"location": "Location",
@@ -105,6 +115,8 @@
"HOTEL": "Hotel",
"CAFE": "Cafe",
"BAR": "Bar",
+ "NIGHTLIFE": "Nightlife",
+ "SPORTS": "Sports",
"cheap": "Cheap",
"moderate": "Moderate",
"expensive": "Expensive"
diff --git a/src/i18n/locales/en/pages.json b/src/i18n/locales/en/pages.json
index 8db8f443..0bbe9a83 100644
--- a/src/i18n/locales/en/pages.json
+++ b/src/i18n/locales/en/pages.json
@@ -51,7 +51,10 @@
"errorUpdatingProfile": "Error updating profile",
"confirmDeleteProfile": "Are you sure you want to delete this profile?",
"errorDeletingProfile": "Error deleting profile",
- "errorActivatingProfile": "Error activating profile"
+ "errorActivatingProfile": "Error activating profile",
+ "noCategoriesSelected": "No categories selected",
+ "profileNamePlaceholder": "e.g., Weekend Getaway",
+ "profileNameRequired": "Profile name cannot be empty or contain only whitespace"
},
"favouritesPage": {
"favouritesTitle": "Your Favourite Places",
diff --git a/src/pages/LoginPage.jsx b/src/pages/LoginPage.jsx
index 185ca714..950e1c20 100644
--- a/src/pages/LoginPage.jsx
+++ b/src/pages/LoginPage.jsx
@@ -112,7 +112,7 @@ const LoginPage = () => {
)}
{error && (
-
+
{error}
)}
diff --git a/src/pages/NavigationPage.jsx b/src/pages/NavigationPage.jsx
index f926aa92..8da9e9e7 100644
--- a/src/pages/NavigationPage.jsx
+++ b/src/pages/NavigationPage.jsx
@@ -34,9 +34,9 @@ import './NavigationPage.css';
/** Predefined quick routes for popular destinations */
const QUICK_ROUTES = [
- { name: 'Athens → Thessaloniki', icon: '🏛️', from: 'Athens, Greece', to: 'Thessaloniki, Greece' },
- { name: 'Thessaloniki → Athens', icon: '🏛️', from: 'Thessaloniki, Greece', to: 'Athens, Greece' },
- { name: 'Heraklion → Athens', icon: '🏖️', from: 'Heraklion, Crete, Greece', to: 'Athens, Greece' },
+ { nameKey: 'routeAthensToThessaloniki', icon: '🏛️', from: 'Athens, Greece', to: 'Thessaloniki, Greece' },
+ { nameKey: 'routeThessalonikiToAthens', icon: '🏛️', from: 'Thessaloniki, Greece', to: 'Athens, Greece' },
+ { nameKey: 'routeHeraklionToAthens', icon: '🏖️', from: 'Heraklion, Crete, Greece', to: 'Athens, Greece' },
];
/**
@@ -95,7 +95,7 @@ const NavigationPage = () => {
return (
{/* Hero section with page title */}
-
+
{/* Main navigation layout with form and results columns */}
@@ -120,7 +120,7 @@ const NavigationPage = () => {
))}
diff --git a/src/pages/PreferencesPage.jsx b/src/pages/PreferencesPage.jsx
index 23b92d23..d7238218 100644
--- a/src/pages/PreferencesPage.jsx
+++ b/src/pages/PreferencesPage.jsx
@@ -73,8 +73,8 @@ const PreferencesPage = () => {
if (loading) {
return (
-
+
@@ -89,8 +89,8 @@ const PreferencesPage = () => {
if (error) {
return (
-
+
@@ -103,8 +103,8 @@ const PreferencesPage = () => {
return (
-
+
{/* Create new profile button */}
@@ -124,6 +124,7 @@ const PreferencesPage = () => {
editingProfile={editingProfile}
onSubmit={editingProfile ? handleUpdate : handleCreate}
onClose={closeForm}
+ showError={showError}
/>
)}
diff --git a/src/pages/RecommendationsPage.jsx b/src/pages/RecommendationsPage.jsx
index 3a16dc4a..bd8f456c 100644
--- a/src/pages/RecommendationsPage.jsx
+++ b/src/pages/RecommendationsPage.jsx
@@ -99,7 +99,7 @@ const RecommendationsPage = () => {
// Info state: API message (e.g., no active profile)
ℹ️
-
{message}
+
{t('createProfileForRecommendations')}
{t('goToPreferences')}
@@ -107,7 +107,7 @@ const RecommendationsPage = () => {
// Success state: show recommendations grid
<>
-
{recommendations.length} {recommendations.length === 1 ? 'Recommendation' : 'Recommendations'}
+ {recommendations.length} {recommendations.length === 1 ? t('recommendationSingular') : t('recommendationPlural')}
{recommendations.map((rec, index) => (
diff --git a/src/pages/SignupPage.jsx b/src/pages/SignupPage.jsx
index 1a1f2fe3..3312cf9a 100644
--- a/src/pages/SignupPage.jsx
+++ b/src/pages/SignupPage.jsx
@@ -63,7 +63,7 @@ const SignupPage = () => {
});
storeUserSession(response);
- navigate('/');
+ navigate('/preferences');
} catch (err) {
console.error('Signup error:', err);
setError(extractErrorMessage(err, t('signupError')));
@@ -89,7 +89,7 @@ const SignupPage = () => {
{({ isSubmitting, errors, touched }) => (