diff --git a/src/App.css b/src/App.css
index 45e4d2f..ae02eda 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,97 +1,75 @@
-/* @import '~antd/dist/antd.css'; */
-
+/* Global styles */
body {
- background-color: #f3f6f8;;
+ background-color: #f3f6f8;
}
-#usercentrics-button {
- display: none;
+/* Ant Design Button Customizations */
+:root {
+ --btn-primary-color: #7BCADE;
+ --btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
+ --btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
}
.App {
text-align: center;
}
-.ant-btn-primary {
- color: #fff;
- background-color: #7BCADE;
- border-color: #7BCADE;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
- box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
+#usercentrics-button {
+ display: none;
}
-.ant-btn:active {
+.ant-btn-primary,
+.ant-btn:active,
+.ant-btn:focus {
color: #fff;
- background-color: #7BCADE;
- border-color: #7BCADE;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
- box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
+ background-color: var(--btn-primary-color);
+ border-color: var(--btn-primary-color);
+ text-shadow: var(--btn-text-shadow);
+ box-shadow: var(--btn-shadow);
}
.ant-btn:hover {
- border: solid 1px #7BCADE;
+ border: solid 1px var(--btn-primary-color);
}
-.ant-btn:focus {
- color: #fff;
- background-color: #7BCADE;
- border-color: #7BCADE;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
- box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
+/* Ant Design Slider Customizations */
+.ant-slider-handle,
+.ant-slider-track,
+.ant-slider-dot-active,
+.ant-slider:hover .ant-slider-track,
+.ant-slider:hover .ant-slider-handle,
+.ant-slider:hover .ant-slider-handle:not(.ant-tooltip-open),
+.ant-slider-handle-click-focused {
+ border-color: var(--btn-primary-color);
}
.ant-slider-handle {
- border: solid 2px #7BCADE;
-}
-
-.ant-slider-track {
- border: solid 2px #7BCADE;
-}
-
-.ant-slider-dot-active {
- border-color: #7BCADE;
+ border: solid 2px var(--btn-primary-color);
}
-.ant-slider:hover .ant-slider-track {
- background-color: #7BCADE;
-}
-
-.ant-slider:hover .ant-slider-handle {
- border-color: #7BCADE;
-}
-
-.ant-slider:hover .ant-slider-handle:not(.ant-tooltip-open) {
- border-color: #7BCADE;
-}
-
-.ant-slider-handle-click-focused {
- border-color: #7BCADE;
-}
+/* Other styles */
.devicon-size {
font-size: 1.5rem;
padding-top: 3px;
}
.b {
- width: 30px
+ width: 30px;
}
-/* width */
+/* Scrollbar Customizations */
::-webkit-scrollbar {
width: 12px;
}
-/* Track */
::-webkit-scrollbar-track {
background: #f3f6f8;
}
-/* Handle */
::-webkit-scrollbar-thumb {
background: #888;
}
-/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #555;
}
diff --git a/src/App.js b/src/App.js
index 4cb4c15..f72a430 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,75 +1,48 @@
-import React, {Component, Suspense} from 'react';
-import Routes from './routes';
-import {ThemeContext} from "./themeContext";
-import style from './Theme.module.scss'
-
-class RoutedApp extends Component {
- render() {
- return <>
-
- >
- }
-}
-
-class Theme extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- theme: localStorage.getItem('theme') ?? this.getSystemPreferredTheme(),
- toggleTheme: this.toggleTheme,
- };
+import React, { useState, useEffect, lazy, Suspense } from 'react';
+import Routes from './routes'; // Ensure you have this component in your project.
+import { ThemeContext } from "./themeContext";
+import style from './Theme.module.scss';
+import classNames from 'classnames';
+const DARK_THEME = 'dark';
+const LIGHT_THEME = 'light';
- }
-
- toggleTheme = () => {
- this.setState(state => {
- const newTheme = state.theme === 'dark' ? 'light' : 'dark'
-
- localStorage.setItem('theme', newTheme);
+const RoutedApp = () => {
+ return ;
+}
- return {
- theme: newTheme
- }
- });
- }
+const Theme = () => {
+ const storedTheme = localStorage.getItem('theme');
+ const [theme, setTheme] = useState(storedTheme || getSystemPreferredTheme());
- getSystemPreferredTheme() {
- const isDarkTheme = window.matchMedia("(prefers-color-scheme: dark)");
+ useEffect(() => {
+ localStorage.setItem('theme', theme);
+ }, [theme]);
- if (isDarkTheme.matches) {
- return 'dark';
- }
+ const toggleTheme = () => {
+ setTheme(currentTheme => currentTheme === DARK_THEME ? LIGHT_THEME : DARK_THEME);
+ };
- return 'light';
+ const getSystemPreferredTheme = () => {
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? DARK_THEME : LIGHT_THEME;
}
- render() {
+ const classes = classNames(style.Theme, {
+ [style.Theme_dark]: theme === DARK_THEME,
+ [style.Theme_light]: theme !== DARK_THEME,
+ });
- const classes = [style.Theme];
-
- if(this.state.theme === 'dark') {
- classes.push(style.Theme_dark);
- } else {
- classes.push(style.Theme_light)
- }
-
- return (
-
-
-
-
-
-
-
- );
- }
+ return (
+
+
+ Loading...}>
+
+
+
+
+ );
}
-
export default function App() {
- return (
-
- );
+ return ;
}
diff --git a/src/Theme.module.scss b/src/Theme.module.scss
index b16d32d..aed0211 100644
--- a/src/Theme.module.scss
+++ b/src/Theme.module.scss
@@ -1,12 +1,22 @@
+// Define theme colors and other constants
+$theme-light-bg: #F3F4F6;
+$theme-dark-bg: #2F3136;
+$box-shadow-dark: 0 4px 8px rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.06), 0px 0px 1px rgba(0, 0, 0, 0.04);
+
.Theme {
+ // Smooth transition for theme changes
transition: background-color .2s ease-in-out;
+ // Light theme styling
&_light {
- background-color: #F3F4F6;
+ background-color: $theme-light-bg;
}
+ // Dark theme styling
&_dark {
- background-color: #2F3136;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.06), 0px 0px 1px rgba(0, 0, 0, 0.04);
+ background-color: $theme-dark-bg;
+
+ // Shadow for added depth in dark theme
+ box-shadow: $box-shadow-dark;
}
-}
\ No newline at end of file
+}
diff --git a/src/routes.js b/src/routes.js
index d07de0c..d07e9bf 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -1,31 +1,34 @@
-import React from "react";
+import React, { lazy, Suspense } from "react";
import { Switch, Route } from "react-router-dom";
-import JobsContainer from "./jobs/JobsContainer/JobsContainer";
-import NotFound from "./pages/NotFound";
-import Imprint from "./pages/Imprint";
-import DataSecurity from "./pages/DataSecurity";
-import Terms from "./pages/Terms";
-import ChoosePlanContainer from "./jobs/ChoosePlanContainer/ChoosePlanContainer";
-import NewJobContainer from "./jobs/NewJobContainer/index";
-import InvoiceDetails from "./jobs/NewJobContainer/InvoiceDetails";
-import Pricing from './static/Pricing';
-import About from './static/About';
-import AboutOld from './pages/About.js';
-import Company from './static/CompanyProfile';
-import BrandsList from "./brands/BrandsList";
-import EduRoom from './EduRoom/EduRoom';
-import Tutorials from './EduRoom/Tutorials/Tutorials';
-import Meetups from './EduRoom/Meetups/Meetups';
-import Meetup from './EduRoom/Meetups/Meetup';
-import StudyMaterial from './EduRoom/StudyMaterial/StudyMaterial';
-import StudyMaterialSingle from './EduRoom/StudyMaterial/StudyMaterialSingle';
-import Blog from './Blog/Blog';
-import BlogSingle from "./Blog/BlogSingle";
-import Token from "./Token/J4IT";
-import Statistics from './statistics/Statistics';
+
+const JobsContainer = lazy(() => import("./jobs/JobsContainer/JobsContainer"));
+const NotFound = lazy(() => import("./pages/NotFound"));
+const Imprint = lazy(() => import("./pages/Imprint"));
+const DataSecurity = lazy(() => import("./pages/DataSecurity"));
+const Terms = lazy(() => import("./pages/Terms"));
+const ChoosePlanContainer = lazy(() => import("./jobs/ChoosePlanContainer/ChoosePlanContainer"));
+const NewJobContainer = lazy(() => import("./jobs/NewJobContainer/index"));
+const InvoiceDetails = lazy(() => import("./jobs/NewJobContainer/InvoiceDetails"));
+const Pricing = lazy(() => import('./static/Pricing'));
+const About = lazy(() => import('./static/About'));
+const AboutOld = lazy(() => import('./pages/About.js'));
+const Company = lazy(() => import('./static/CompanyProfile'));
+const BrandsList = lazy(() => import("./brands/BrandsList"));
+const EduRoom = lazy(() => import('./EduRoom/EduRoom'));
+const Tutorials = lazy(() => import('./EduRoom/Tutorials/Tutorials'));
+const Meetups = lazy(() => import('./EduRoom/Meetups/Meetups'));
+const Meetup = lazy(() => import('./EduRoom/Meetups/Meetup'));
+const StudyMaterial = lazy(() => import('./EduRoom/StudyMaterial/StudyMaterial'));
+const StudyMaterialSingle = lazy(() => import('./EduRoom/StudyMaterial/StudyMaterialSingle'));
+const Blog = lazy(() => import('./Blog/Blog'));
+const BlogSingle = lazy(() => import("./Blog/BlogSingle"));
+const Token = lazy(() => import("./Token/J4IT"));
+const Statistics = lazy(() => import('./statistics/Statistics'));
const Routes = () => (
+ Loading...}>
+
@@ -33,9 +36,7 @@ const Routes = () => (
- {/**/}
-
@@ -51,8 +52,9 @@ const Routes = () => (
-
+
+
);
export default Routes;
diff --git a/src/sitemap.js b/src/sitemap.js
index cef0034..bf8b1e5 100644
--- a/src/sitemap.js
+++ b/src/sitemap.js
@@ -1,189 +1,143 @@
-const { paramsApplier } = require("react-router-sitemap");
+// Dependencies and Libraries
const fs = require("fs");
+const path = require('path');
const contentful = require("contentful");
const moment = require('moment');
const xmlFormatter = require('xml-formatter');
-const path = require('path');
-
-const SPACE_ID = process.env.REACT_APP_SPACE_ID || "f6zwhql64w01";
-const ACCESS_TOKEN =
- process.env.REACT_APP_ACCESS_TOKEN ||
- "00b696c26342aa70ce936b551fe48e6548745fa637b6cd0c62fa72886af5bd78";
-const MANAGER_TOKEN =
- process.env.REACT_APP_MANAGER_TOKEN ||
- "CFPAT-1BFhL_2UiqD7Q2Z-azTipNT5RgZoqjq0U4UpQQuSTi4";
-const ENVIRONMENT = process.env.REACT_APP_ENVIRONMENT || "master";
-
-const client = contentful.createClient({
- space: SPACE_ID,
- accessToken: ACCESS_TOKEN,
- environment: ENVIRONMENT,
-});
-
-const getTechnologies = () =>
- client.getEntries({
- content_type: "technology",
- });
-
-const getCities = () =>
- client.getEntries({
- content_type: "city",
- });
-
-const getAllJobs = () => client.getEntries({
- content_type: 'job',
- limit: 1000,
- skip: 0,
- select: 'fields.position,fields.slug',
- order: '-fields.displayPriority,-fields.dateDisplayed'
-});
-
-const getTechnologyNames = async () => {
- const technologies = await getTechnologies();
-
- if (technologies.items.length < 0) {
- return false;
- }
-
- return technologies.items.map((tech) => tech.fields.name.toLowerCase());
-};
-
-const getCityNames = async () => {
- const cities = await getCities();
-
- if (cities.items.length < 0) {
- return false;
- }
+const { paramsApplier } = require("react-router-sitemap");
- return cities.items.map((city) => city.fields.name.toLowerCase());
+// Configuration Constants
+const CONTENTFUL_CONFIG = {
+ space: process.env.REACT_APP_SPACE_ID,
+ accessToken: process.env.REACT_APP_ACCESS_TOKEN,
+ environment: process.env.REACT_APP_ENVIRONMENT
};
-
-const getJobSlugs = async () => {
- const jobs = await getAllJobs(1000, 0);
-
- if (jobs.items.length < 0) {
- return false;
+const client = contentful.createClient(CONTENTFUL_CONFIG);
+
+// Utility Functions
+async function fetchContentfulEntries(contentType) {
+ try {
+ const entries = await client.getEntries({ content_type: contentType });
+ return entries.items.length > 0 ? entries.items : [];
+ } catch (error) {
+ console.error(`Error fetching ${contentType} entries:`, error);
+ return [];
}
-
- return jobs.items.map((job) => encodeURIComponent(job.fields.slug));
}
+// Sitemap Generation Functions
function generatePathsBasedOnRoute(route) {
- const config = {};
- config[route.path] = [{ ...route.params }];
-
+ const config = { [route.path]: [{ ...route.params }] };
return paramsApplier([route.path], config);
}
function generateSitemap(routes) {
const date = moment().format('YYYY-MM-DD');
const host = 'https://jobsforit.de';
+
const xml = `
- ${routes
- .map((route) => {
- return `${host + route}${date}`;
- })
- .join("")}
-
- `;
+ ${routes.map(route => `${host + route}${date}`).join("")}
+ `;
return xmlFormatter(xml);
}
+// Main Execution
async function sitemapGenerator() {
- console.log('Started generating sitemap');
- const technologies = await getTechnologyNames();
- const cities = await getCityNames();
- const jobs = await getJobSlugs();
-
- const routes = [
- {
- path: "/filters/:tech/:city",
- exact: true,
- params: {
- tech: technologies,
- city: cities,
- },
- },
- {
- path: "/filters/:tech",
- params: {
- tech: technologies,
- },
- },
- {
- path: "/jobs/:id",
- params: {
- id: jobs
- }
- },
- {
- path: "/choose-plan",
- },
- {
- path: "/token",
- },
- {
- path: "/pricing",
- },
- {
- path: "/",
- },
- {
- path: "/about",
- },
- {
- path: "/company",
- },
- {
- path: "/brand-room",
- },
- {
- path: "/imprint",
- },
- {
- path: "/edu-room",
- },
- {
- path: "/tutorials",
- },
- {
- path: "/meetup",
- },
- {
- path: "/meetups",
- },
- {
- path: "/study-material",
- },
- {
- path: "/study-material-single",
- },
- {
- path: "/blog",
- },
- {
- path: "/statistics",
- },
- {
- path: "/terms-and-conditions",
- },
- {
- path: "/privacy-policy",
- },
- ];
+ try {
+ console.log('Starting sitemap generation...');
+
+ const technologies = (await fetchContentfulEntries("technology")).map(tech => tech.fields.name.toLowerCase());
+ const cities = (await fetchContentfulEntries("city")).map(city => city.fields.name.toLowerCase());
+ const jobs = (await fetchContentfulEntries('job')).map(job => encodeURIComponent(job.fields.slug));
+
+ const routes = [
+ {
+ path: "/filters/:tech/:city",
+ exact: true,
+ params: {
+ tech: technologies,
+ city: cities,
+ },
+ },
+ {
+ path: "/filters/:tech",
+ params: {
+ tech: technologies,
+ },
+ },
+ {
+ path: "/jobs/:id",
+ params: {
+ id: jobs
+ }
+ },
+ {
+ path: "/choose-plan",
+ },
+ {
+ path: "/token",
+ },
+ {
+ path: "/pricing",
+ },
+ {
+ path: "/",
+ },
+ {
+ path: "/about",
+ },
+ {
+ path: "/company",
+ },
+ {
+ path: "/brand-room",
+ },
+ {
+ path: "/imprint",
+ },
+ {
+ path: "/edu-room",
+ },
+ {
+ path: "/tutorials",
+ },
+ {
+ path: "/meetup",
+ },
+ {
+ path: "/meetups",
+ },
+ {
+ path: "/study-material",
+ },
+ {
+ path: "/study-material-single",
+ },
+ {
+ path: "/blog",
+ },
+ {
+ path: "/statistics",
+ },
+ {
+ path: "/terms-and-conditions",
+ },
+ {
+ path: "/privacy-policy",
+ },
+ ];
- const newRoutes = [];
+ const newRoutes = routes.flatMap(generatePathsBasedOnRoute);
- routes.forEach((route) => {
- console.log(`Generating paths for: ${route.path}`);
- newRoutes.push(...generatePathsBasedOnRoute(route));
- });
+ console.log('Saving sitemap to public/sitemap.xml');
+ fs.writeFileSync(path.join(process.cwd(), 'public', 'sitemap.xml'), generateSitemap(newRoutes));
+ console.log('Sitemap generation completed.');
- console.log('Saving sitemap to public/sitemap.xml');
- fs.writeFileSync(path.join(process.cwd(), 'public', 'sitemap.xml'), generateSitemap(newRoutes));
- console.log('Sitemap successfully created');
+ } catch (error) {
+ console.error('Error generating sitemap:', error);
+ }
}
sitemapGenerator();
diff --git a/src/themeContext.js b/src/themeContext.js
index 6b57536..9a6eadd 100644
--- a/src/themeContext.js
+++ b/src/themeContext.js
@@ -2,15 +2,19 @@ import React from 'react';
const getSystemPreferredTheme = () => {
const isDarkTheme = window.matchMedia("(prefers-color-scheme: dark)");
+ return isDarkTheme.matches ? 'dark' : 'light';
+}
- if (isDarkTheme.matches) {
- return 'dark';
+const getInitialTheme = () => {
+ try {
+ return localStorage.getItem('theme') ?? getSystemPreferredTheme();
+ } catch (error) {
+ console.error("Failed to get theme from localStorage", error);
+ return getSystemPreferredTheme();
}
-
- return 'light';
}
export const ThemeContext = React.createContext({
- theme: localStorage.getItem('theme') ?? 'dark',
+ theme: getInitialTheme(),
toggleTheme: () => {}
-});
\ No newline at end of file
+});