diff --git a/prerender/seo/homepage.cjs b/prerender/seo/homepage.cjs
index 812685d..2a79206 100644
--- a/prerender/seo/homepage.cjs
+++ b/prerender/seo/homepage.cjs
@@ -7,8 +7,6 @@ const generateHomepageMetaTags = (baseUrl, config) => {
const canonicalUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
return `
-
-
@@ -235,4 +233,4 @@ const generateHomepageJsonLd = (baseUrl, config, categories = []) => {
module.exports = {
generateHomepageMetaTags,
generateHomepageJsonLd,
-};
+};
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
index 6856ba9..214816d 100644
--- a/src/App.js
+++ b/src/App.js
@@ -32,10 +32,11 @@ import i18n from './i18n/index.js';
import Header from "./components/Header.js";
import Footer from "./components/Footer.js";
-const IdleMainPagesSlideshow = lazy(() => import(/* webpackChunkName: "idle-slideshow" */ "./components/IdleMainPagesSlideshow.js"));
-const MainPageLayout = lazy(() => import(/* webpackChunkName: "main-page-layout" */ "./components/MainPageLayout.js"));
-const Content = lazy(() => import(/* webpackChunkName: "content" */ "./components/Content.js"));
-const ProductDetail = lazy(() => import(/* webpackChunkName: "product-detail" */ "./components/ProductDetail.js"));
+import MainPageLayout from "./components/MainPageLayout.js";
+import IdleMainPagesSlideshow from "./components/IdleMainPagesSlideshow.js";
+
+import Content from "./components/Content.js";
+import ProductDetail from "./components/ProductDetail.js";
// Lazy load rarely-accessed pages
const ProfilePage = lazy(() => import(/* webpackChunkName: "profile" */ "./pages/ProfilePage.js"));
diff --git a/src/PrerenderHome.js b/src/PrerenderHome.js
index 0d37973..0496e55 100644
--- a/src/PrerenderHome.js
+++ b/src/PrerenderHome.js
@@ -7,8 +7,6 @@ import {
} from '@mui/material';
import Footer from './components/Footer.js';
import { Logo, CategoryList } from './components/header/index.js';
-import MainPageLayout from './components/MainPageLayout.js';
-import { CarouselProvider } from './contexts/CarouselContext.js';
class PrerenderHome extends React.Component {
@@ -124,18 +122,9 @@ class PrerenderHome extends React.Component {
),
React.createElement(CategoryList, { categoryId: 209, activeCategoryId: null })
),
- React.createElement(
- Box,
- { component: 'main', sx: { flexGrow: 1 } },
- React.createElement(
- CarouselProvider,
- null,
- React.createElement(MainPageLayout)
- )
- ),
React.createElement(Footer)
);
}
}
-export default PrerenderHome;
+export default PrerenderHome;
\ No newline at end of file
diff --git a/src/components/ChatAssistant.js b/src/components/ChatAssistant.js
index 3f96556..05da261 100644
--- a/src/components/ChatAssistant.js
+++ b/src/components/ChatAssistant.js
@@ -18,7 +18,7 @@ import { Link } from 'react-router-dom';
import MuiLink from '@mui/material/Link';
import { alpha } from '@mui/material/styles';
import TelegramIcon from '@mui/icons-material/Telegram';
-import { isUserLoggedIn } from '../utils/authSession.js';
+import { isUserLoggedIn } from './LoginComponent.js';
import { withTranslation } from '../i18n/withTranslation.js';
const TELEGRAM_ASSISTANT_URL = 'https://t.me/Growheads_de_Bot';
diff --git a/src/components/LanguageSwitcher.js b/src/components/LanguageSwitcher.js
index 10cff1c..cb2974a 100644
--- a/src/components/LanguageSwitcher.js
+++ b/src/components/LanguageSwitcher.js
@@ -6,37 +6,13 @@ import MenuItem from '@mui/material/MenuItem';
import Typography from '@mui/material/Typography';
import { withI18n } from '../i18n/withTranslation.js';
-const LANGUAGE_FLAG_EMOJIS = {
- ar: '🇪🇬',
- bg: '🇧🇬',
- cs: '🇨🇿',
- de: '🇩🇪',
- el: '🇬🇷',
- en: '🇺🇸',
- es: '🇪🇸',
- fr: '🇫🇷',
- hr: 'ðŸ‡ðŸ‡·',
- hu: 'ðŸ‡ðŸ‡º',
- it: '🇮🇹',
- pl: '🇵🇱',
- ro: '🇷🇴',
- ru: '🇷🇺',
- sk: '🇸🇰',
- sl: '🇸🇮',
- sq: '🇦🇱',
- sr: '🇷🇸',
- sv: '🇸🇪',
- tr: '🇹🇷',
- uk: '🇺🇦',
- zh: '🇨🇳'
-};
-
class LanguageSwitcher extends Component {
constructor(props) {
super(props);
-
+
this.state = {
- anchorEl: null
+ anchorEl: null,
+ loadedFlags: {}
};
}
@@ -60,7 +36,72 @@ class LanguageSwitcher extends Component {
this.handleClose();
};
+ // Lazy load flag components
+ loadFlagComponent = async (lang) => {
+ if (this.state.loadedFlags[lang]) {
+ return this.state.loadedFlags[lang];
+ }
+
+ try {
+ const flagMap = {
+ 'ar': () => import('country-flag-icons/react/3x2').then(m => m.EG),
+ 'bg': () => import('country-flag-icons/react/3x2').then(m => m.BG),
+ 'cs': () => import('country-flag-icons/react/3x2').then(m => m.CZ),
+ 'de': () => import('country-flag-icons/react/3x2').then(m => m.DE),
+ 'el': () => import('country-flag-icons/react/3x2').then(m => m.GR),
+ 'en': () => import('country-flag-icons/react/3x2').then(m => m.US),
+ 'es': () => import('country-flag-icons/react/3x2').then(m => m.ES),
+ 'fr': () => import('country-flag-icons/react/3x2').then(m => m.FR),
+ 'hr': () => import('country-flag-icons/react/3x2').then(m => m.HR),
+ 'hu': () => import('country-flag-icons/react/3x2').then(m => m.HU),
+ 'it': () => import('country-flag-icons/react/3x2').then(m => m.IT),
+ 'pl': () => import('country-flag-icons/react/3x2').then(m => m.PL),
+ 'ro': () => import('country-flag-icons/react/3x2').then(m => m.RO),
+ 'ru': () => import('country-flag-icons/react/3x2').then(m => m.RU),
+ 'sk': () => import('country-flag-icons/react/3x2').then(m => m.SK),
+ 'sl': () => import('country-flag-icons/react/3x2').then(m => m.SI),
+ 'sq': () => import('country-flag-icons/react/3x2').then(m => m.AL),
+ 'sr': () => import('country-flag-icons/react/3x2').then(m => m.RS),
+ 'sv': () => import('country-flag-icons/react/3x2').then(m => m.SE),
+ 'tr': () => import('country-flag-icons/react/3x2').then(m => m.TR),
+ 'uk': () => import('country-flag-icons/react/3x2').then(m => m.UA),
+ 'zh': () => import('country-flag-icons/react/3x2').then(m => m.CN)
+ };
+
+ const flagLoader = flagMap[lang];
+ if (flagLoader) {
+ const FlagComponent = await flagLoader();
+ this.setState(prevState => ({
+ loadedFlags: {
+ ...prevState.loadedFlags,
+ [lang]: FlagComponent
+ }
+ }));
+ return FlagComponent;
+ }
+ } catch (error) {
+ console.warn(`Failed to load flag for language: ${lang}`, error);
+ }
+ return null;
+ };
+
getLanguageFlag = (lang) => {
+ const FlagComponent = this.state.loadedFlags[lang];
+
+ if (FlagComponent) {
+ return (
+
+ );
+ }
+
+ // Loading placeholder or fallback
return (
- {LANGUAGE_FLAG_EMOJIS[lang] || this.getLanguageLabel(lang)}
+ {this.getLanguageLabel(lang)}
);
};
+ // Load flags when menu opens
+ componentDidUpdate(prevProps, prevState) {
+ const { anchorEl } = this.state;
+ const { languageContext } = this.props;
+
+ if (anchorEl && !prevState.anchorEl && languageContext) {
+ // Menu just opened, lazy load flags for all languages (not just available ones)
+ languageContext.allLanguages.forEach(lang => {
+ if (!this.state.loadedFlags[lang]) {
+ this.loadFlagComponent(lang);
+ }
+ });
+ }
+ }
+
getLanguageLabel = (lang) => {
const labels = {
'ar': 'EG',
@@ -216,4 +275,4 @@ class LanguageSwitcher extends Component {
}
}
-export default withI18n()(LanguageSwitcher);
+export default withI18n()(LanguageSwitcher);
\ No newline at end of file
diff --git a/src/components/LoginComponent.js b/src/components/LoginComponent.js
index 18bd712..a2f6656 100644
--- a/src/components/LoginComponent.js
+++ b/src/components/LoginComponent.js
@@ -21,7 +21,6 @@ import { withRouter } from './withRouter.js';
import GoogleLoginButton from './GoogleLoginButton.js';
import CartSyncDialog from './CartSyncDialog.js';
import { localAndArchiveServer, mergeCarts } from '../utils/cartUtils.js';
-import { isUserLoggedIn } from '../utils/authSession.js';
import config from '../config.js';
import { withI18n } from '../i18n/withTranslation.js';
import {
@@ -54,6 +53,24 @@ const persistSessionAuth = (response) => {
}
};
+// Function to check if user is logged in
+export const isUserLoggedIn = () => {
+ const storedUser = sessionStorage.getItem('user');
+ if (storedUser) {
+ try {
+ const parsedUser = JSON.parse(storedUser);
+ console.log('Parsed User:', parsedUser);
+ return { isLoggedIn: true, user: parsedUser, isAdmin: !!parsedUser.admin };
+
+ } catch (error) {
+ console.error('Error parsing user from sessionStorage:', error);
+ sessionStorage.removeItem('user');
+ }
+ }
+ console.log('isUserLoggedIn', false);
+ return { isLoggedIn: false, user: null, isAdmin: false };
+};
+
// Hilfsfunktion zum Vergleich zweier Cart-Arrays
function cartsAreIdentical(cartA, cartB) {
console.log('Vergleiche Carts:', {cartA, cartB});
@@ -792,4 +809,4 @@ export class LoginComponent extends Component {
}
}
-export default withRouter(withI18n()(LoginComponent));
+export default withRouter(withI18n()(LoginComponent));
\ No newline at end of file
diff --git a/src/components/MainPageLayout.js b/src/components/MainPageLayout.js
index 7778a18..33a982b 100644
--- a/src/components/MainPageLayout.js
+++ b/src/components/MainPageLayout.js
@@ -275,15 +275,7 @@ const ContentBox = ({ box, index, pageType, starHovered, setStarHovered, opacity
>
{opacity === 1 && (
-
+
)}
{box.title}
diff --git a/src/components/header/ButtonGroup.js b/src/components/header/ButtonGroup.js
index a7dec0b..3b98517 100644
--- a/src/components/header/ButtonGroup.js
+++ b/src/components/header/ButtonGroup.js
@@ -18,8 +18,8 @@ const LoginComponent = lazy(() => import(/* webpackChunkName: "login" */ "../Log
import CartDropdown from '../CartDropdown.js';
import LanguageSwitcher from '../LanguageSwitcher.js';
+import { isUserLoggedIn } from '../LoginComponent.js';
import { withI18n } from '../../i18n/withTranslation.js';
-import { isUserLoggedIn } from '../../utils/authSession.js';
function getBadgeNumber() {
let count = 0;
@@ -196,4 +196,4 @@ const ButtonGroupWithRouter = (props) => {
return ;
};
-export default ButtonGroupWithRouter;
+export default ButtonGroupWithRouter;
\ No newline at end of file
diff --git a/src/components/profile/OrderProcessingService.js b/src/components/profile/OrderProcessingService.js
index 6e791a3..2723047 100644
--- a/src/components/profile/OrderProcessingService.js
+++ b/src/components/profile/OrderProcessingService.js
@@ -1,4 +1,4 @@
-import { isUserLoggedIn } from "../../utils/authSession.js";
+import { isUserLoggedIn } from "../LoginComponent.js";
class OrderProcessingService {
constructor(getContext, setState) {
@@ -369,4 +369,4 @@ class OrderProcessingService {
}
}
-export default OrderProcessingService;
+export default OrderProcessingService;
\ No newline at end of file
diff --git a/src/utils/authSession.js b/src/utils/authSession.js
deleted file mode 100644
index 9afec43..0000000
--- a/src/utils/authSession.js
+++ /dev/null
@@ -1,16 +0,0 @@
-export const isUserLoggedIn = () => {
- const storedUser = sessionStorage.getItem('user');
- if (storedUser) {
- try {
- const parsedUser = JSON.parse(storedUser);
- console.log('Parsed User:', parsedUser);
- return { isLoggedIn: true, user: parsedUser, isAdmin: !!parsedUser.admin };
- } catch (error) {
- console.error('Error parsing user from sessionStorage:', error);
- sessionStorage.removeItem('user');
- }
- }
-
- console.log('isUserLoggedIn', false);
- return { isLoggedIn: false, user: null, isAdmin: false };
-};
diff --git a/webpack.config.js b/webpack.config.js
index 0418305..4d574ee 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -5,31 +5,17 @@ import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import ESLintPlugin from 'eslint-webpack-plugin';
import { cpSync } from 'fs';
-import { execFileSync } from 'child_process';
+import { execSync } from 'child_process';
import webpack from 'webpack';
import fs from 'fs';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
-// Git hash for meta tag / currentHash.json — avoid execSync (spawns /bin/sh; fails with EPERM in some sandboxes/CI)
+// Get git commit hash
const getGitCommitHash = () => {
- const fromEnv =
- process.env.GIT_COMMIT ||
- process.env.VERCEL_GIT_COMMIT_SHA ||
- process.env.CI_COMMIT_SHA ||
- process.env.GITHUB_SHA ||
- '';
- if (fromEnv) return String(fromEnv).trim();
-
try {
- return execFileSync('git', ['rev-parse', 'HEAD'], {
- encoding: 'utf8',
- maxBuffer: 1024 * 1024,
- }).trim();
+ return execSync('git rev-parse HEAD').toString().trim();
} catch (e) {
- console.warn(
- 'Git commit hash unavailable (set GIT_COMMIT or run build in a git repo):',
- e && e.message ? e.message : e
- );
+ console.error('Failed to get git commit hash:', e);
return 'unknown';
}
};
@@ -315,36 +301,9 @@ export default {
priority: 20,
reuseExistingChunk: true,
},
- // Keep Stripe checkout code out of the initial vendor bundle
- stripe: {
- test: /[\\/]node_modules[\\/]@stripe[\\/]/,
- name: 'stripe',
- priority: 19,
- chunks: 'async',
- reuseExistingChunk: true,
- enforce: true,
- },
- // Lazy HTML parsing/sanitizing should stay async with the product detail/chat flows
- htmlParser: {
- test: /[\\/]node_modules[\\/](html-react-parser|sanitize-html|htmlparser2|domhandler|dom-serializer|entities|react-property|parse-srcset|postcss)[\\/]/,
- name: 'html-parser-vendor',
- priority: 18,
- chunks: 'async',
- reuseExistingChunk: true,
- enforce: true,
- },
- // Girocode/QR code generation is only needed in checkout/profile flows
- payments: {
- test: /[\\/]node_modules[\\/](qrcode|sepa-payment-qr-code|iban)[\\/]/,
- name: 'payments',
- priority: 17,
- chunks: 'async',
- reuseExistingChunk: true,
- enforce: true,
- },
// socket.io-client and its dependencies — always async, never initial
socketio: {
- test: /[\\/]node_modules[\\/](socket\.io-client|engine\.io-client|engine\.io-parser|@socket\.io|socket\.io-parser|socket\.io-msgpack-parser)[\\/]/,
+ test: /[\\/]node_modules[\\/](socket\.io-client|engine\.io-client|@socket\.io|socket\.io-parser|socket\.io-msgpack-parser)[\\/]/,
name: 'socketio',
priority: 15,
chunks: 'async',