diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index d30ebad..0ce0498 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -317,11 +317,13 @@ const App: React.FC = () => {
-
- setDrawerOpen(false)}>
-
-
-
+ {user && (
+
+ setDrawerOpen(false)}>
+
+
+
+ )}
setCatOpen(!catOpen)}>
@@ -444,14 +446,16 @@ const App: React.FC = () => {
-
+ {user && (
+
+ )}
}
diff --git a/frontend/src/components/RatingBadge.tsx b/frontend/src/components/RatingBadge.tsx
new file mode 100644
index 0000000..30cf83b
--- /dev/null
+++ b/frontend/src/components/RatingBadge.tsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import { Box, Typography, alpha, useTheme } from '@mui/material';
+
+interface RatingBadgeProps {
+ score: number;
+ size?: 'small' | 'medium' | 'large';
+ sx?: any;
+}
+
+const RatingBadge: React.FC = ({ score, size = 'medium', sx }) => {
+ const theme = useTheme();
+ const isLarge = size === 'large';
+ const isSmall = size === 'small';
+
+ return (
+
+
+ {typeof score === 'number' ? score.toFixed(isLarge ? 1 : 0) : score}
+
+
+ / 10
+
+
+ );
+};
+
+export default RatingBadge;
diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts
index 74ce1f8..3394794 100644
--- a/frontend/src/i18n.ts
+++ b/frontend/src/i18n.ts
@@ -88,9 +88,10 @@ const resources = {
},
"common": {
"search": "Search...",
+ "back": "Back",
+ "backTo": "Back to {{page}}",
"backToArchive": "Back to Archive",
"backToHome": "Back to Home",
- "backTo": "Back to",
"buyNow": "Buy Now",
"reviews": "reviews",
"rank": "Rank",
@@ -218,9 +219,10 @@ const resources = {
},
"common": {
"search": "Suchen...",
+ "back": "Zurück",
+ "backTo": "Zurück zu {{page}}",
"backToArchive": "Zurück zum Archiv",
"backToHome": "Zurück zur Startseite",
- "backTo": "Zurück zu",
"buyNow": "Jetzt kaufen",
"reviews": "Bewertungen",
"rank": "Rang",
diff --git a/frontend/src/pages/CommunityFeed.tsx b/frontend/src/pages/CommunityFeed.tsx
index b31fa93..5452d5a 100644
--- a/frontend/src/pages/CommunityFeed.tsx
+++ b/frontend/src/pages/CommunityFeed.tsx
@@ -27,6 +27,7 @@ import SendIcon from '@mui/icons-material/Send';
import WhatshotIcon from '@mui/icons-material/Whatshot';
import NotificationsIcon from '@mui/icons-material/Notifications';
import PeopleIcon from '@mui/icons-material/People';
+import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { Link, useNavigate } from 'react-router-dom';
import api from '../api';
import { useTitle } from '../hooks/useTitle';
@@ -34,6 +35,7 @@ import RichText from '../components/RichText';
import { formatDate } from '../utils/date';
import { useTranslation } from 'react-i18next';
import MentionTextField from '../components/MentionTextField';
+import RatingBadge from '../components/RatingBadge';
interface Reply {
id: number;
@@ -100,6 +102,14 @@ const CommunityFeed: React.FC = () => {
user.username.toLowerCase().includes(followingSearch.toLowerCase())
);
+ const handleGoBack = () => {
+ if (window.history.length > 1) {
+ navigate(-1);
+ } else {
+ navigate('/');
+ }
+ };
+
const fetchFeedData = async (pageNum: number) => {
setLoading(true);
try {
@@ -177,6 +187,28 @@ const CommunityFeed: React.FC = () => {
return (
+
+ }
+ sx={{
+ borderRadius: 2,
+ textTransform: 'none',
+ fontWeight: 'bold',
+ color: 'text.secondary',
+ borderColor: 'divider',
+ '&:hover': {
+ borderColor: 'primary.main',
+ color: 'primary.main',
+ bgcolor: 'transparent'
+ }
+ }}
+ >
+ {window.history.length > 1 ? t('common.back') : t('common.backToHome')}
+
+
+
{t('community.title')}
@@ -239,18 +271,7 @@ const CommunityFeed: React.FC = () => {
- alpha(theme.palette.primary.main, 0.1),
- color: 'primary.main',
- px: 2, py: 0.5,
- borderRadius: 2
- }}>
- {rating.score}
- / 10
-
+
{/* Flavor and Comment */}
@@ -397,10 +418,9 @@ const CommunityFeed: React.FC = () => {
+
))}
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx
index 7005f13..86476a4 100644
--- a/frontend/src/pages/Dashboard.tsx
+++ b/frontend/src/pages/Dashboard.tsx
@@ -107,7 +107,7 @@ const Dashboard: React.FC = () => {
}
}}
>
- {t('common.backToHome').replace('Home', 'Back')}
+ {window.history.length > 1 ? t('common.back') : t('common.backToHome')}
diff --git a/frontend/src/pages/FlavorList.tsx b/frontend/src/pages/FlavorList.tsx
index 640dbbc..7ba5b0a 100644
--- a/frontend/src/pages/FlavorList.tsx
+++ b/frontend/src/pages/FlavorList.tsx
@@ -4,15 +4,16 @@ import {
Card,
CardContent,
Box,
- Rating as MuiRating,
TextField,
Button,
Accordion,
AccordionSummary,
- AccordionDetails
+ AccordionDetails,
+ Rating as MuiRating
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import api from '../api';
+import RatingBadge from '../components/RatingBadge';
interface Rating {
id: number;
@@ -143,8 +144,7 @@ const FlavorList: React.FC = () => {
)}
Avg:
-
- ({(flavor.average_rating || 0).toFixed(1)})
+
{flavor.ratings && flavor.ratings.length > 0 && (
@@ -175,7 +175,7 @@ const FlavorList: React.FC = () => {
setRatingInput({...ratingInput, [flavor.id]: {...(ratingInput[flavor.id] || {comment: ''}), score: val || 0}})}
+ onChange={(_: any, val: number | null) => setRatingInput({...ratingInput, [flavor.id]: {...(ratingInput[flavor.id] || {comment: ''}), score: val || 0}})}
/>
{
const { t } = useTranslation();
- const isMobileSize = useMediaQuery('(max-width:600px)');
const [topFlavors, setTopFlavors] = useState([]);
const [newestFlavors, setNewestFlavors] = useState([]);
const [recentReviews, setRecentReviews] = useState([]);
@@ -202,8 +200,7 @@ const MainPage: React.FC = () => {
{flavor.name}
{flavor.category_name}
-
- ({(flavor.average_rating || 0).toFixed(1)})
+
@@ -362,7 +359,7 @@ const MainPage: React.FC = () => {
-
+
{t('home.hallOfFame')}
@@ -409,10 +406,10 @@ const MainPage: React.FC = () => {
{currentTop.name}
-
-
-
- {(currentTop.average_rating || 0).toFixed(1)} / 10
+
+
+
+ {currentTop.ratings.length} {t('common.reviews')}
@@ -497,14 +494,7 @@ const MainPage: React.FC = () => {
{review.user}
- {/* Compact rating for sidebar and tablets */}
-
-
- {review.score}/10
-
-
-
-
+
{formatDate(review.created_at)} • on {review.flavor_name}
diff --git a/frontend/src/pages/PublicProfile.tsx b/frontend/src/pages/PublicProfile.tsx
index ff327cb..873f48b 100644
--- a/frontend/src/pages/PublicProfile.tsx
+++ b/frontend/src/pages/PublicProfile.tsx
@@ -19,6 +19,7 @@ import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { Link } from 'react-router-dom';
import api from '../api';
import { useTitle } from '../hooks/useTitle';
+import { useTranslation } from 'react-i18next';
interface Rating {
id: number;
@@ -43,6 +44,7 @@ interface ProfileData {
}
const PublicProfile: React.FC = () => {
+ const { t } = useTranslation();
const { username } = useParams<{ username: string }>();
const navigate = useNavigate();
const [data, setData] = useState(null);
@@ -144,7 +146,7 @@ const PublicProfile: React.FC = () => {
}
}}
>
- Back
+ {window.history.length > 1 ? t('common.back') : t('common.backToHome')}
{/* Profile Header */}
diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx
index e389712..c5fe497 100644
--- a/frontend/src/pages/Settings.tsx
+++ b/frontend/src/pages/Settings.tsx
@@ -17,7 +17,7 @@ import {
Grid
} from '@mui/material';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
-import { Link } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom';
import api from '../api';
import { useTranslation } from 'react-i18next';
import { useTitle } from '../hooks/useTitle';
@@ -30,6 +30,7 @@ interface SettingsProps {
const Settings: React.FC = ({ themeName, onThemeChange }) => {
const { t, i18n } = useTranslation();
+ const navigate = useNavigate();
useTitle(t('nav.settings'));
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
@@ -44,6 +45,14 @@ const Settings: React.FC = ({ themeName, onThemeChange }) => {
const [isDeleting, setIsDeleting] = useState(false);
const [message, setMessage] = useState<{ type: 'success' | 'error', text: string } | null>(null);
+ const handleGoBack = () => {
+ if (window.history.length > 1) {
+ navigate(-1);
+ } else {
+ navigate('/');
+ }
+ };
+
useEffect(() => {
const fetchUser = async () => {
try {
@@ -162,12 +171,23 @@ const Settings: React.FC = ({ themeName, onThemeChange }) => {
}
- sx={{ mb: 4, textTransform: 'none', borderRadius: 2 }}
+ sx={{
+ mb: 4,
+ borderRadius: 2,
+ textTransform: 'none',
+ fontWeight: 'bold',
+ color: 'text.secondary',
+ borderColor: 'divider',
+ '&:hover': {
+ borderColor: 'primary.main',
+ color: 'primary.main',
+ bgcolor: 'transparent'
+ }
+ }}
>
- {t('common.backToHome')}
+ {window.history.length > 1 ? t('common.back') : t('common.backToHome')}
diff --git a/frontend/src/pages/categories/CategoryFlavors.tsx b/frontend/src/pages/categories/CategoryFlavors.tsx
index 628dd53..46b3218 100644
--- a/frontend/src/pages/categories/CategoryFlavors.tsx
+++ b/frontend/src/pages/categories/CategoryFlavors.tsx
@@ -5,7 +5,6 @@ import {
Box,
Card,
CardContent,
- Rating as MuiRating,
CircularProgress,
Container,
Button
@@ -13,6 +12,8 @@ import {
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import api from '../../api';
import { useTitle } from '../../hooks/useTitle';
+import RatingBadge from '../../components/RatingBadge';
+import { useTranslation } from 'react-i18next';
interface Rating {
id: number;
@@ -37,6 +38,7 @@ interface Flavor {
}
const CategoryFlavors: React.FC = () => {
+ const { t } = useTranslation();
const { slug } = useParams<{ slug: string }>();
const navigate = useNavigate();
const [flavors, setFlavors] = useState([]);
@@ -95,7 +97,7 @@ const CategoryFlavors: React.FC = () => {
}
}}
>
- Back
+ {window.history.length > 1 ? t('common.back') : t('common.backToHome')}
@@ -152,8 +154,7 @@ const CategoryFlavors: React.FC = () => {
{flavor.name}
-
- ({(flavor.average_rating || 0).toFixed(1)})
+
{flavor.ratings.length} reviews
diff --git a/frontend/src/pages/flavors/FlavorDetail.tsx b/frontend/src/pages/flavors/FlavorDetail.tsx
index 6377831..03042a5 100644
--- a/frontend/src/pages/flavors/FlavorDetail.tsx
+++ b/frontend/src/pages/flavors/FlavorDetail.tsx
@@ -27,6 +27,7 @@ import CommentIcon from '@mui/icons-material/Comment';
import { formatDate } from '../../utils/date';
import MentionTextField from '../../components/MentionTextField';
import RichText from '../../components/RichText';
+import RatingBadge from '../../components/RatingBadge';
interface Reply {
id: number;
@@ -193,34 +194,6 @@ const FlavorDetail: React.FC = () => {
}
};
- const RatingBadge = ({ score, size = 'medium' }: { score: number, size?: 'small' | 'medium' | 'large' }) => {
- const isLarge = size === 'large';
- const isSmall = size === 'small';
-
- return (
- alpha(theme.palette.primary.main, 0.1),
- color: 'primary.main',
- px: isLarge ? 3 : (isSmall ? 1 : 2),
- py: isLarge ? 1 : 0.5,
- borderRadius: isLarge ? 3 : 2,
- minWidth: isLarge ? 80 : 50,
- border: '1px solid',
- borderColor: (theme) => alpha(theme.palette.primary.main, 0.2)
- }}>
-
- {score}
-
-
- / 10
-
-
- );
- };
-
if (loading) return ;
if (!flavor) return Flavor not found;
@@ -245,7 +218,7 @@ const FlavorDetail: React.FC = () => {
}
}}
>
- {t('common.backToHome').replace('Home', 'Back')}
+ {window.history.length > 1 ? t('common.back') : t('common.backToHome')}
@@ -311,13 +284,10 @@ const FlavorDetail: React.FC = () => {
-
-
-
-
- {flavor.ratings.length} {t('common.reviews')}
-
-
+
+
+ {flavor.ratings.length} {t('common.reviews')}
+