From 92095892b29d88d99d8ca85ca1b340ec4d61914b Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Fri, 15 Aug 2025 18:20:45 +0200 Subject: [PATCH] Implementierung - SEO - 15.08.2025 --- dev-dist/sw.js | 2 +- dev-dist/sw.js.map | 2 +- index.html | 13 +-- src/components/CookieBanner.tsx | 38 ++++-- src/components/Footer.tsx | 6 + src/i18n/locales/de/footer.ts | 3 +- src/i18n/locales/en/footer.ts | 3 +- src/i18n/locales/sr/footer.ts | 3 +- src/pages/ImprintPage.tsx | 93 +++++++++++++++ src/pages/PrivacyPolicyPage.tsx | 200 +++++++++++++++++++++++--------- src/routes.tsx | 12 ++ src/services/gtm.ts | 46 +++++++- 12 files changed, 338 insertions(+), 83 deletions(-) create mode 100644 src/pages/ImprintPage.tsx diff --git a/dev-dist/sw.js b/dev-dist/sw.js index a1c3f9b..8141867 100644 --- a/dev-dist/sw.js +++ b/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-be0f3d84'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.gdtj7rsm15" + "revision": "0.hcrclnqqiv" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/dev-dist/sw.js.map b/dev-dist/sw.js.map index 67dca56..d2b2f15 100644 --- a/dev-dist/sw.js.map +++ b/dev-dist/sw.js.map @@ -1 +1 @@ -{"version":3,"file":"sw.js","sources":["../../AppData/Local/Temp/d1829056ac529945a5ede5fd99558e3d/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-routing@7.3.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheableResponsePlugin as workbox_cacheable_response_CacheableResponsePlugin} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-cacheable-response@7.3.0/node_modules/workbox-cacheable-response/CacheableResponsePlugin.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-strategies@7.3.0/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-strategies@7.3.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-core@7.3.0/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-routing@7.3.0/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"registerSW.js\",\n \"revision\": \"3ca0b8505b4bec776b69afdba2768812\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"0.gdtj7rsm15\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\"), {\n allowlist: [/^\\/$/],\n \n}));\n\n\nworkbox_routing_registerRoute(/^https:\\/\\/fonts\\.googleapis\\.com\\/.*/i, new workbox_strategies_CacheFirst({ \"cacheName\":\"google-fonts-cache\", plugins: [new workbox_cacheable_response_CacheableResponsePlugin({ statuses: [ 0, 200 ] })] }), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/fonts\\.gstatic\\.com\\/.*/i, new workbox_strategies_CacheFirst({ \"cacheName\":\"gstatic-fonts-cache\", plugins: [new workbox_cacheable_response_CacheableResponsePlugin({ statuses: [ 0, 200 ] })] }), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/www\\.googletagmanager\\.com\\/.*/i, new workbox_strategies_NetworkOnly(), 'GET');\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","workbox_precaching_cleanupOutdatedCaches","workbox_routing_registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL","allowlist","workbox_strategies_CacheFirst","plugins","workbox_cacheable_response_CacheableResponsePlugin","statuses","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sw.js","sources":["../../AppData/Local/Temp/d7e8f17f8d09a5c209106c351ec15e68/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-routing@7.3.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheableResponsePlugin as workbox_cacheable_response_CacheableResponsePlugin} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-cacheable-response@7.3.0/node_modules/workbox-cacheable-response/CacheableResponsePlugin.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-strategies@7.3.0/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-strategies@7.3.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-core@7.3.0/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-routing@7.3.0/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"registerSW.js\",\n \"revision\": \"3ca0b8505b4bec776b69afdba2768812\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"0.hcrclnqqiv\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\"), {\n allowlist: [/^\\/$/],\n \n}));\n\n\nworkbox_routing_registerRoute(/^https:\\/\\/fonts\\.googleapis\\.com\\/.*/i, new workbox_strategies_CacheFirst({ \"cacheName\":\"google-fonts-cache\", plugins: [new workbox_cacheable_response_CacheableResponsePlugin({ statuses: [ 0, 200 ] })] }), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/fonts\\.gstatic\\.com\\/.*/i, new workbox_strategies_CacheFirst({ \"cacheName\":\"gstatic-fonts-cache\", plugins: [new workbox_cacheable_response_CacheableResponsePlugin({ statuses: [ 0, 200 ] })] }), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/www\\.googletagmanager\\.com\\/.*/i, new workbox_strategies_NetworkOnly(), 'GET');\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","workbox_precaching_cleanupOutdatedCaches","workbox_routing_registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL","allowlist","workbox_strategies_CacheFirst","plugins","workbox_cacheable_response_CacheableResponsePlugin","statuses","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file diff --git a/index.html b/index.html index a289807..5b90349 100644 --- a/index.html +++ b/index.html @@ -4,13 +4,7 @@ - - - + @@ -135,10 +129,7 @@ - - - +
diff --git a/src/components/CookieBanner.tsx b/src/components/CookieBanner.tsx index ed80907..5fb328a 100644 --- a/src/components/CookieBanner.tsx +++ b/src/components/CookieBanner.tsx @@ -1,6 +1,7 @@ import { useEffect, useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { initGA, logPageView, initFBPixel, initFunctionalCookies } from '../utils/analytics'; +import { loadGoogleTagManager } from '../services/gtm'; // Feste Übersetzungen direkt in der Komponente const translations = { @@ -146,6 +147,7 @@ const blockGoogleAnalytics = () => { const CookieBanner = () => { const { i18n } = useTranslation(); const [currentLang, setCurrentLang] = useState<'de' | 'en' | 'sr'>('de'); + const [showBanner, setShowBanner] = useState(false); const [showSettings, setShowSettings] = useState(false); const [cookieSettings, setCookieSettings] = useState({ necessary: true, // Always true and disabled @@ -172,6 +174,7 @@ const CookieBanner = () => { // Marketing-Dienste nur mit Zustimmung if (settings.marketing) { initFBPixel(); + loadGoogleTagManager(); } // Funktionale Dienste nur mit Zustimmung @@ -206,26 +209,35 @@ const CookieBanner = () => { useEffect(() => { try { const storedSettings = localStorage.getItem('cookieSettings'); - if (storedSettings) { + const hasConsent = localStorage.getItem('cookieConsent'); + + if (storedSettings && hasConsent) { const parsedSettings = JSON.parse(storedSettings) as CookieSettings; setCookieSettings(parsedSettings); // Lade die entsprechenden Dienste basierend auf den Einstellungen initializeServices(parsedSettings); + setShowBanner(false); + } else { + // Zeige Banner wenn keine Zustimmung vorhanden ist + setShowBanner(true); } } catch (error) { console.error('Error loading cookie settings:', error); + setShowBanner(true); } }, [initializeServices]); const handleSaveSettings = () => { localStorage.setItem('cookieSettings', JSON.stringify(cookieSettings)); - localStorage.setItem('cookieConsent', cookieSettings.analytics || cookieSettings.marketing || cookieSettings.functional ? 'true' : 'false'); + localStorage.setItem('cookieConsent', 'true'); + localStorage.setItem('cookieConsentDate', new Date().toISOString()); // Initialisiere Dienste basierend auf den ausgewählten Einstellungen initializeServices(cookieSettings); setShowSettings(false); + setShowBanner(false); }; const handleAcceptAll = () => { @@ -238,12 +250,14 @@ const CookieBanner = () => { localStorage.setItem('cookieSettings', JSON.stringify(allSettings)); localStorage.setItem('cookieConsent', 'true'); + localStorage.setItem('cookieConsentDate', new Date().toISOString()); setCookieSettings(allSettings); // Initialisiere alle Dienste initializeServices(allSettings); setShowSettings(false); + setShowBanner(false); }; const handleDeclineAll = () => { @@ -255,13 +269,15 @@ const CookieBanner = () => { }; localStorage.setItem('cookieSettings', JSON.stringify(minimalSettings)); - localStorage.setItem('cookieConsent', 'false'); + localStorage.setItem('cookieConsent', 'true'); + localStorage.setItem('cookieConsentDate', new Date().toISOString()); setCookieSettings(minimalSettings); // Block all non-essential services initializeServices(minimalSettings); setShowSettings(false); + setShowBanner(false); }; const toggleSetting = (setting: keyof Omit) => { @@ -271,8 +287,8 @@ const CookieBanner = () => { }); }; - // If consent already given, don't show banner - if (localStorage.getItem('cookieConsent')) { + // If banner should not be shown, return null + if (!showBanner) { return null; } @@ -449,12 +465,18 @@ const CookieBanner = () => { -
+
- {getText('learnMore')} + Datenschutzerklärung + + + Impressum
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 80e6494..3eefb5b 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -105,6 +105,12 @@ const Footer = () => { > {t('footer.legal.links.privacy')} + + {t('footer.legal.links.imprint')} + { + const { t } = useTranslation(); + + const schema = { + '@context': 'https://schema.org', + '@type': 'WebPage', + name: 'Impressum', + description: 'Impressum für die Portfolio-Website von Damjan Savić' + }; + + return ( + + +
+
+ + +

Impressum

+ +
+
+

Kontakt

+
+

Damjan Savić

+

Fullstack Developer & Digital Solutions Consultant

+ +

E-Mail:

+

info@damjan-savic.com

+

Website: https://damjan-savic.com

+
+
+ +
+

Haftungsausschluss

+ +

Haftung für Inhalte

+

Die Inhalte meiner Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte kann ich jedoch keine Gewähr übernehmen.

+ +

Haftung für Links

+

Meine Website enthält Links zu externen Websites Dritter, auf deren Inhalte ich keinen Einfluss habe. Deshalb kann ich für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich.

+
+ +
+

Urheberrecht

+

Die durch den Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers.

+

Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitte ich um einen entsprechenden Hinweis.

+
+ +
+

Bildnachweise

+

Die auf dieser Website verwendeten Bilder und Grafiken stammen aus folgenden Quellen:

+
    +
  • Eigene Aufnahmen und Erstellungen
  • +
  • Icons: Heroicons, Tabler Icons (MIT Lizenz)
  • +
  • Weitere Bildquellen sind direkt bei den jeweiligen Bildern angegeben
  • +
+
+ +
+

Datenschutz

+

Die Nutzung unserer Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder E-Mail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Ihre ausdrückliche Zustimmung nicht an Dritte weitergegeben.

+

Weitere Informationen zum Datenschutz finden Sie in unserer Datenschutzerklärung.

+
+ +
+

Technische Umsetzung

+
+

Design & Entwicklung: Damjan Savić

+

Technologien: React, TypeScript, Tailwind CSS

+
+
+ +
+

Copyright

+

© {new Date().getFullYear()} Damjan Savić. Alle Rechte vorbehalten.

+
+
+
+
+
+ ); +}; + +export default ImprintPage; \ No newline at end of file diff --git a/src/pages/PrivacyPolicyPage.tsx b/src/pages/PrivacyPolicyPage.tsx index 6ce4965..1f87b10 100644 --- a/src/pages/PrivacyPolicyPage.tsx +++ b/src/pages/PrivacyPolicyPage.tsx @@ -9,101 +9,185 @@ const PrivacyPolicyPage = () => { const schema = { '@context': 'https://schema.org', '@type': 'WebPage', - name: 'Privacy Policy', - description: 'Privacy Policy for Damjan Savić\'s portfolio website' + name: 'Datenschutzerklärung', + description: 'Datenschutzerklärung für die Portfolio-Website von Damjan Savić' }; return (
- + -

Privacy Policy

+

Datenschutzerklärung

-

Last updated: March 10, 2024

+

Stand: {new Date().toLocaleDateString('de-DE', { year: 'numeric', month: 'long', day: 'numeric' })}

-

1. Introduction

-

This Privacy Policy explains how we collect, use, and protect your personal information when you use our website.

+

1. Verantwortlicher

+

Verantwortlich für die Datenverarbeitung auf dieser Website im Sinne der Datenschutz-Grundverordnung (DSGVO) ist:

+
+

Damjan Savić

+

Köln, Deutschland

+

E-Mail: contact@damjan-savic.com

+

Telefon: +49 151 74477788

+
-

2. Information We Collect

-

2.1 Information You Provide

-

When using our contact form, we collect:

+

2. Allgemeine Hinweise

+

Der Schutz Ihrer persönlichen Daten ist mir ein besonderes Anliegen. Ich verarbeite Ihre Daten daher ausschließlich auf Grundlage der gesetzlichen Bestimmungen (DSGVO, TKG 2003). In dieser Datenschutzerklärung informiere ich Sie über die wichtigsten Aspekte der Datenverarbeitung im Rahmen meiner Website.

+ +

2.1 Datenminimierung

+

Ich erhebe nur solche personenbezogenen Daten, die für die Erfüllung der jeweiligen Zwecke erforderlich sind. Eine darüber hinausgehende Datenerhebung findet nicht statt.

+ +

2.2 Rechtsgrundlagen

+

Die Verarbeitung Ihrer Daten erfolgt auf Basis folgender Rechtsgrundlagen:

+
    +
  • Art. 6 Abs. 1 lit. a DSGVO (Einwilligung)
  • +
  • Art. 6 Abs. 1 lit. b DSGVO (Vertragserfüllung)
  • +
  • Art. 6 Abs. 1 lit. f DSGVO (berechtigte Interessen)
  • +
+
+ +
+

3. Datenerfassung auf dieser Website

+ +

3.1 Cookies

+

Diese Website verwendet Cookies. Dabei handelt es sich um kleine Textdateien, die Ihr Webbrowser auf Ihrem Endgerät speichert. Cookies helfen dabei, unser Angebot nutzerfreundlicher, effektiver und sicherer zu machen.

+ +

Folgende Arten von Cookies werden verwendet:

+
    +
  • Notwendige Cookies: Diese Cookies sind für den Betrieb der Website unerlässlich (z.B. Session-Cookies)
  • +
  • Funktionale Cookies: Diese Cookies ermöglichen erweiterte Funktionen (z.B. Spracheinstellungen)
  • +
  • Analyse-Cookies: Diese Cookies helfen uns, die Nutzung unserer Website zu verstehen (nur mit Ihrer Zustimmung)
  • +
  • Marketing-Cookies: Diese Cookies werden für personalisierte Werbung verwendet (nur mit Ihrer Zustimmung)
  • +
+ +

Sie können Ihre Cookie-Einstellungen jederzeit über den Cookie-Banner auf unserer Website anpassen.

+ +

3.2 Server-Log-Dateien

+

Der Provider der Seiten erhebt und speichert automatisch Informationen in so genannten Server-Log-Dateien, die Ihr Browser automatisch übermittelt. Dies sind:

+
    +
  • Browsertyp und Browserversion
  • +
  • Verwendetes Betriebssystem
  • +
  • Referrer URL
  • +
  • Hostname des zugreifenden Rechners
  • +
  • Uhrzeit der Serveranfrage
  • +
  • IP-Adresse (anonymisiert)
  • +
+

Diese Daten sind nicht bestimmten Personen zuordenbar. Eine Zusammenführung dieser Daten mit anderen Datenquellen wird nicht vorgenommen. Die Daten werden nach 7 Tagen automatisch gelöscht.

+ +

3.3 Kontaktformular

+

Wenn Sie uns per Kontaktformular Anfragen zukommen lassen, werden Ihre Angaben aus dem Anfrageformular inklusive der von Ihnen dort angegebenen Kontaktdaten zwecks Bearbeitung der Anfrage und für den Fall von Anschlussfragen bei uns gespeichert.

+

Verarbeitete Daten:

  • Name
  • -
  • Email address
  • -
  • Message content
  • -
- -

2.2 Automatically Collected Information

-

We automatically collect:

-
    -
  • IP address
  • -
  • Browser type
  • -
  • Device information
  • -
  • Pages visited
  • -
  • Time spent on site
  • +
  • E-Mail-Adresse
  • +
  • Betreff
  • +
  • Nachrichteninhalt
  • +
  • Datum und Uhrzeit der Anfrage
+

Rechtsgrundlage: Die Verarbeitung erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO (Vertragsanbahnung) oder Art. 6 Abs. 1 lit. f DSGVO (berechtigtes Interesse an der Beantwortung Ihrer Anfrage).

+

Speicherdauer: Die Daten werden gelöscht, sobald sie für die Erreichung des Zweckes ihrer Erhebung nicht mehr erforderlich sind, spätestens jedoch nach 6 Monaten.

-

3. How We Use Your Information

-

We use your information to:

+

4. Externe Dienste und Inhalte

+ +

4.1 Google Analytics

+

Diese Website benutzt Google Analytics, einen Webanalysedienst der Google LLC ("Google"). Google Analytics wird nur aktiviert, wenn Sie der Verwendung von Analyse-Cookies ausdrücklich zugestimmt haben.

+

Verarbeitete Daten:

    -
  • Respond to your inquiries
  • -
  • Improve our website
  • -
  • Analyze usage patterns
  • -
  • Prevent fraud
  • +
  • Anonymisierte IP-Adresse
  • +
  • Geräteinformationen
  • +
  • Browserinformationen
  • +
  • Nutzungsverhalten (besuchte Seiten, Verweildauer, etc.)
+

Zweck: Analyse der Websitenutzung zur Verbesserung unseres Angebots

+

Rechtsgrundlage: Art. 6 Abs. 1 lit. a DSGVO (Einwilligung)

+

Speicherdauer: 14 Monate

+

Sie können die Speicherung der Cookies durch eine entsprechende Einstellung Ihrer Browser-Software verhindern oder Ihre Einwilligung jederzeit über unseren Cookie-Banner widerrufen.

+ +

4.2 Google Fonts

+

Diese Website nutzt zur einheitlichen Darstellung von Schriftarten so genannte Google Fonts. Google Fonts werden nur geladen, wenn Sie der Verwendung funktionaler Cookies zugestimmt haben.

+

Verarbeitete Daten: IP-Adresse

+

Zweck: Einheitliche Darstellung von Schriftarten

+

Rechtsgrundlage: Art. 6 Abs. 1 lit. a DSGVO (Einwilligung)

+ +

4.3 Facebook Pixel

+

Diese Website nutzt das Facebook-Pixel von Meta Platforms Inc. Das Facebook-Pixel wird nur aktiviert, wenn Sie der Verwendung von Marketing-Cookies ausdrücklich zugestimmt haben.

+

Verarbeitete Daten:

+
    +
  • Cookie-ID
  • +
  • Geräteinformationen
  • +
  • Nutzungsverhalten
  • +
+

Zweck: Remarketing und Conversion-Tracking

+

Rechtsgrundlage: Art. 6 Abs. 1 lit. a DSGVO (Einwilligung)

-

4. Cookies

-

We use cookies to:

-
    -
  • Remember your preferences
  • -
  • Analyze site traffic
  • -
  • Understand user behavior
  • -
+

5. Ihre Rechte

+

Nach der Datenschutz-Grundverordnung stehen Ihnen folgende Rechte zu:

+ +

5.1 Auskunftsrecht (Art. 15 DSGVO)

+

Sie haben das Recht, Auskunft über Ihre bei uns gespeicherten personenbezogenen Daten zu erhalten.

+ +

5.2 Recht auf Berichtigung (Art. 16 DSGVO)

+

Sie haben das Recht, unrichtige oder unvollständige personenbezogene Daten berichtigen zu lassen.

+ +

5.3 Recht auf Löschung (Art. 17 DSGVO)

+

Sie haben das Recht, die Löschung Ihrer personenbezogenen Daten zu verlangen, sofern die gesetzlichen Voraussetzungen vorliegen.

+ +

5.4 Recht auf Einschränkung der Verarbeitung (Art. 18 DSGVO)

+

Sie haben das Recht, die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.

+ +

5.5 Recht auf Datenübertragbarkeit (Art. 20 DSGVO)

+

Sie haben das Recht, Ihre personenbezogenen Daten in einem strukturierten, gängigen und maschinenlesbaren Format zu erhalten.

+ +

5.6 Widerspruchsrecht (Art. 21 DSGVO)

+

Sie haben das Recht, aus Gründen, die sich aus Ihrer besonderen Situation ergeben, jederzeit gegen die Verarbeitung Sie betreffender personenbezogener Daten Widerspruch einzulegen.

+ +

5.7 Recht auf Widerruf der Einwilligung

+

Sie haben das Recht, Ihre einmal erteilte Einwilligung jederzeit zu widerrufen. Die Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten Verarbeitung wird dadurch nicht berührt.

+ +

5.8 Beschwerderecht bei der Aufsichtsbehörde

+

Sie haben das Recht, sich bei einer Datenschutz-Aufsichtsbehörde zu beschweren. Die für uns zuständige Aufsichtsbehörde ist:

+
+

Landesbeauftragte für Datenschutz und Informationsfreiheit Nordrhein-Westfalen

+

Postfach 20 04 44

+

40102 Düsseldorf

+

Telefon: 0211/38424-0

+

E-Mail: poststelle@ldi.nrw.de

+
-

5. Data Security

-

We implement appropriate security measures to protect your personal information, including:

-
    -
  • Encryption of data in transit
  • -
  • Regular security assessments
  • -
  • Access controls
  • -
  • Secure data storage
  • -
+

6. Datensicherheit

+

Ich verwende innerhalb des Website-Besuchs das verbreitete SSL-Verfahren (Secure Socket Layer) in Verbindung mit der jeweils höchsten Verschlüsselungsstufe, die von Ihrem Browser unterstützt wird. Ob eine einzelne Seite unseres Internetauftrittes verschlüsselt übertragen wird, erkennen Sie an der geschlossenen Darstellung des Schüssel- beziehungsweise Schloss-Symbols in der unteren Statusleiste Ihres Browsers.

+

Darüber hinaus bediene ich mich geeigneter technischer und organisatorischer Sicherheitsmaßnahmen, um Ihre Daten gegen zufällige oder vorsätzliche Manipulationen, teilweisen oder vollständigen Verlust, Zerstörung oder gegen den unbefugten Zugriff Dritter zu schützen.

-

6. Your Rights

-

You have the right to:

-
    -
  • Access your personal data
  • -
  • Request data correction
  • -
  • Request data deletion
  • -
  • Object to data processing
  • -
  • Data portability
  • -
+

7. Aktualität und Änderung dieser Datenschutzerklärung

+

Diese Datenschutzerklärung ist aktuell gültig und hat den Stand {new Date().toLocaleDateString('de-DE', { year: 'numeric', month: 'long', day: 'numeric' })}.

+

Durch die Weiterentwicklung unserer Website und Angebote darüber oder aufgrund geänderter gesetzlicher beziehungsweise behördlicher Vorgaben kann es notwendig werden, diese Datenschutzerklärung zu ändern. Die jeweils aktuelle Datenschutzerklärung kann jederzeit auf der Website unter /privacy von Ihnen abgerufen und ausgedruckt werden.

-

7. Contact Information

-

For privacy-related inquiries, contact us at:

-

Email: privacy@damjan-savic.com

-

Address: {t('contact.address')}

+

8. Kontakt

+

Für Fragen zum Datenschutz können Sie sich jederzeit an mich wenden:

+
+

E-Mail: privacy@damjan-savic.com

+

Telefon: +49 151 74477788

+
diff --git a/src/routes.tsx b/src/routes.tsx index 7e136f8..79214b4 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -16,6 +16,7 @@ const LoginPage = React.lazy(() => import('./pages/LoginPage')); const DashboardPage = React.lazy(() => import('./pages/DashboardPage')); const PrivacyPolicyPage = React.lazy(() => import('./pages/PrivacyPolicyPage')); const TermsPage = React.lazy(() => import('./pages/TermsPage')); +const ImprintPage = React.lazy(() => import('./pages/ImprintPage')); const AppRoutes = () => { return ( @@ -142,6 +143,17 @@ const AppRoutes = () => { } errorElement={} /> + + + + + + } + errorElement={} + /> ); }; diff --git a/src/services/gtm.ts b/src/services/gtm.ts index 52ed310..9ca2f56 100644 --- a/src/services/gtm.ts +++ b/src/services/gtm.ts @@ -6,19 +6,63 @@ declare global { interface Window { dataLayer: any[]; + gtmLoaded?: boolean; } } +// GTM ID +const GTM_ID = 'GTM-NQK6ZV7N'; + // Initialisiere dataLayer falls nicht vorhanden if (typeof window !== 'undefined' && !window.dataLayer) { window.dataLayer = []; } +// Prüft, ob Marketing-Cookies aktiviert sind +const isMarketingEnabled = (): boolean => { + try { + const cookieSettings = localStorage.getItem('cookieSettings'); + if (!cookieSettings) return false; + + const settings = JSON.parse(cookieSettings); + return settings.marketing === true || settings.analytics === true; + } catch (error) { + console.error('Error checking cookie settings:', error); + return false; + } +}; + +// Lädt Google Tag Manager nur nach Zustimmung +export const loadGoogleTagManager = (): void => { + if (!isMarketingEnabled() || window.gtmLoaded) { + return; + } + + // GTM Script laden + const script = document.createElement('script'); + script.innerHTML = ` + (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': + new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], + j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= + 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); + })(window,document,'script','dataLayer','${GTM_ID}'); + `; + document.head.appendChild(script); + + // GTM noscript iframe + const noscript = document.createElement('noscript'); + noscript.innerHTML = ``; + document.body.insertBefore(noscript, document.body.firstChild); + + window.gtmLoaded = true; +}; + /** * Push event to GTM dataLayer */ export const pushToDataLayer = (data: Record) => { - if (typeof window !== 'undefined' && window.dataLayer) { + if (typeof window !== 'undefined' && window.dataLayer && isMarketingEnabled()) { window.dataLayer.push(data); } };