backup and fixes
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Profice Web API Handler
|
||||
* Centralized API endpoint for all form submissions, webhooks, and tracking
|
||||
* ALL SENSITIVE DATA IS STORED HERE - NOT VISIBLE TO CLIENT
|
||||
*
|
||||
* @author Profice Development Team
|
||||
* @version 2.0.0
|
||||
* Profice Web API Handler - Centralized Configuration
|
||||
* ALL SENSITIVE DATA STORED HERE - NOT VISIBLE TO CLIENT
|
||||
* Handles webhooks, API, tokens, cookie consent, tracking
|
||||
*/
|
||||
|
||||
// ==========================================
|
||||
@@ -47,8 +44,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
// ==========================================
|
||||
|
||||
// Environment
|
||||
define('USE_PRODUCTION', true);
|
||||
define('DEBUG_MODE', false);
|
||||
define('USE_PRODUCTION', false); // Use test webhook for debugging
|
||||
define('DEBUG_MODE', true); // Enable debug to see errors
|
||||
|
||||
// N8N Webhooks
|
||||
define('WEBHOOK_TEST', 'https://n8n.profice.de/webhook-test/d94ef798-3f43-46dd-8207-1e335e64518f');
|
||||
@@ -186,7 +183,6 @@ function sendToWebhook($data, $webhookUrl = null) {
|
||||
$url = $webhookUrl ?? WEBHOOK_URL;
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
@@ -197,24 +193,25 @@ function sendToWebhook($data, $webhookUrl = null) {
|
||||
'User-Agent: Profice-Web-API/2.0'
|
||||
],
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
CURLOPT_SSL_VERIFYPEER => !DEBUG_MODE, // Disable for debugging
|
||||
CURLOPT_FOLLOWLOCATION => true
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($ch);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if ($error) {
|
||||
error_log("Webhook Error: " . $error);
|
||||
return ['success' => false, 'error' => $error];
|
||||
return ['success' => false, 'error' => $error, 'response' => $response];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => $httpCode >= 200 && $httpCode < 300,
|
||||
'http_code' => $httpCode
|
||||
'http_code' => $httpCode,
|
||||
'response' => $response,
|
||||
'error' => $error
|
||||
];
|
||||
}
|
||||
|
||||
@@ -251,96 +248,130 @@ function loadTrackingScripts($preferences) {
|
||||
// Google Tag Manager
|
||||
if ($preferences['analytics'] && !empty(GTM_CONTAINER_ID) && GTM_CONTAINER_ID !== 'GTM-XXXXXXX') {
|
||||
$scripts['gtm'] = [
|
||||
'type' => 'analytics',
|
||||
'id' => GTM_CONTAINER_ID
|
||||
'type' => 'gtm',
|
||||
'src' => 'https://www.googletagmanager.com/gtm.js?id=' . GTM_CONTAINER_ID,
|
||||
'config' => [
|
||||
'id' => GTM_CONTAINER_ID
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
// Facebook Pixel
|
||||
if ($preferences['marketing'] && !empty(FB_PIXEL_ID)) {
|
||||
$scripts['fb'] = [
|
||||
'type' => 'marketing',
|
||||
'id' => FB_PIXEL_ID
|
||||
'type' => 'pixel',
|
||||
'src' => 'https://connect.facebook.net/en_US/fbevents.js',
|
||||
'config' => [
|
||||
'pixel_id' => FB_PIXEL_ID
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
// Google Ads
|
||||
if ($preferences['marketing'] && !empty(GADS_CONVERSION_ID) && GADS_CONVERSION_ID !== 'AW-XXXXXXXXXX') {
|
||||
$scripts['gads'] = [
|
||||
'type' => 'marketing',
|
||||
'id' => GADS_CONVERSION_ID
|
||||
'type' => 'conversion',
|
||||
'src' => 'https://www.googletagmanager.com/gtag/js?id=' . GADS_CONVERSION_ID,
|
||||
'config' => [
|
||||
'conversion_id' => GADS_CONVERSION_ID,
|
||||
'conversion_label' => GADS_CONVERSION_LABEL
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
// LinkedIn
|
||||
if ($preferences['marketing'] && !empty(LINKEDIN_PARTNER_ID)) {
|
||||
$scripts['linkedin'] = [
|
||||
'type' => 'marketing',
|
||||
'id' => LINKEDIN_PARTNER_ID
|
||||
'type' => 'insight',
|
||||
'src' => 'https://snap.licdn.com/li.lms-analytics/insight.min.js',
|
||||
'config' => [
|
||||
'partner_id' => LINKEDIN_PARTNER_ID
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return $scripts;
|
||||
}
|
||||
|
||||
function trackEvent($eventName, $eventData, $preferences) {
|
||||
$results = [];
|
||||
|
||||
// Server-side Google Analytics tracking
|
||||
if ($preferences['analytics'] && !empty(GA_MEASUREMENT_ID) && !empty(GA_API_SECRET)) {
|
||||
$results['ga'] = sendGAEvent($eventName, $eventData);
|
||||
function sendEventToGA($data) {
|
||||
if (empty(GA_MEASUREMENT_ID) || GA_MEASUREMENT_ID === 'G-XXXXXXXXXX') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Server-side Facebook Conversions API
|
||||
if ($preferences['marketing'] && !empty(FB_PIXEL_ID) && !empty(FB_ACCESS_TOKEN)) {
|
||||
$results['fb'] = sendFBEvent($eventName, $eventData);
|
||||
$postData = [
|
||||
'client_id' => $data['client_id'] ?? uniqid(),
|
||||
'user_id' => $data['user_id'] ?? null,
|
||||
'events' => [
|
||||
[
|
||||
'name' => $data['event_name'],
|
||||
'params' => $data['params'] ?? []
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$url = 'https://www.google-analytics.com/mp/collect';
|
||||
$url .= '?measurement_id=' . GA_MEASUREMENT_ID;
|
||||
$url .= '&api_secret=' . GA_API_SECRET;
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($postData),
|
||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
||||
CURLOPT_TIMEOUT => 10
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
return $httpCode >= 200 && $httpCode < 300;
|
||||
}
|
||||
|
||||
function sendEventToFB($data) {
|
||||
if (empty(FB_PIXEL_ID) || empty(FB_ACCESS_TOKEN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
function sendGAEvent($eventName, $eventData) {
|
||||
if (empty(GA_API_SECRET)) return ['success' => false, 'error' => 'No API secret'];
|
||||
|
||||
$url = 'https://www.google-analytics.com/mp/collect?measurement_id=' . GA_MEASUREMENT_ID . '&api_secret=' . GA_API_SECRET;
|
||||
|
||||
$payload = [
|
||||
'client_id' => $eventData['client_id'] ?? uniqid(),
|
||||
'events' => [[
|
||||
'name' => $eventName,
|
||||
'params' => $eventData
|
||||
]]
|
||||
$postData = [
|
||||
'data' => [
|
||||
[
|
||||
'event_name' => $data['event_name'],
|
||||
'event_time' => time(),
|
||||
'action_source' => 'website',
|
||||
'user_data' => $data['user_data'] ?? [],
|
||||
'custom_data' => $data['custom_data'] ?? []
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
return sendToWebhook($payload, $url);
|
||||
}
|
||||
|
||||
function sendFBEvent($eventName, $eventData) {
|
||||
if (empty(FB_ACCESS_TOKEN)) return ['success' => false, 'error' => 'No access token'];
|
||||
$url = 'https://graph.facebook.com/v18.0/' . FB_PIXEL_ID . '/events';
|
||||
$url .= '?access_token=' . FB_ACCESS_TOKEN;
|
||||
|
||||
$url = 'https://graph.facebook.com/v18.0/' . FB_PIXEL_ID . '/events?access_token=' . FB_ACCESS_TOKEN;
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($postData),
|
||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
||||
CURLOPT_TIMEOUT => 10
|
||||
]);
|
||||
|
||||
$payload = [
|
||||
'data' => [[
|
||||
'event_name' => $eventName,
|
||||
'event_time' => time(),
|
||||
'action_source' => 'website',
|
||||
'user_data' => [
|
||||
'client_ip_address' => getClientIP(),
|
||||
'client_user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? ''
|
||||
],
|
||||
'custom_data' => $eventData
|
||||
]]
|
||||
];
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
return sendToWebhook($payload, $url);
|
||||
return $httpCode >= 200 && $httpCode < 300;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// STORAGE FUNCTIONS
|
||||
// ==========================================
|
||||
|
||||
function storeLead($formData) {
|
||||
function storeLead($data) {
|
||||
$leadFile = __DIR__ . '/data/leads.json';
|
||||
$dir = dirname($leadFile);
|
||||
|
||||
@@ -354,16 +385,17 @@ function storeLead($formData) {
|
||||
}
|
||||
|
||||
$lead = [
|
||||
'id' => uniqid('lead_'),
|
||||
'id' => uniqid('lead_', true),
|
||||
'datum' => date('d.m.Y'),
|
||||
'dienstleistung' => $formData['service'] ?? 'Allgemein',
|
||||
'dienstleistung' => $data['service'] ?? 'Allgemein',
|
||||
'status' => 'open',
|
||||
'statusText' => 'Offen',
|
||||
'description' => $formData['description'] ?? '',
|
||||
'name' => $formData['name'] ?? '',
|
||||
'contact' => $formData['contact'] ?? '',
|
||||
'organisation' => $formData['organisation'] ?? '',
|
||||
'timestamp' => date('c')
|
||||
'description' => $data['description'] ?? '',
|
||||
'name' => $data['name'] ?? '',
|
||||
'contact' => $data['contact'] ?? '',
|
||||
'organisation' => $data['organisation'] ?? '',
|
||||
'timestamp' => date('c'),
|
||||
'ip_address' => getClientIP()
|
||||
];
|
||||
|
||||
array_unshift($leads, $lead);
|
||||
@@ -373,8 +405,8 @@ function storeLead($formData) {
|
||||
return $lead['id'];
|
||||
}
|
||||
|
||||
function storeCookieConsent($consentData) {
|
||||
$consentFile = __DIR__ . '/data/cookie_consents.json';
|
||||
function storeCookieConsent($data) {
|
||||
$consentFile = __DIR__ . '/data/cookie_consent.json';
|
||||
$dir = dirname($consentFile);
|
||||
|
||||
if (!is_dir($dir)) {
|
||||
@@ -386,39 +418,30 @@ function storeCookieConsent($consentData) {
|
||||
$consents = json_decode(file_get_contents($consentFile), true) ?: [];
|
||||
}
|
||||
|
||||
// Remove existing consent for this IP
|
||||
$ip = getClientIP();
|
||||
$consents = array_filter($consents, function($c) use ($ip) {
|
||||
return ($c['ip_address'] ?? '') !== $ip;
|
||||
});
|
||||
$consent = [
|
||||
'id' => uniqid('consent_', true),
|
||||
'timestamp' => date('c'),
|
||||
'preferences' => $data['preferences'] ?? [],
|
||||
'ip_address' => getClientIP(),
|
||||
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? ''
|
||||
];
|
||||
|
||||
$consentData['id'] = uniqid('consent_');
|
||||
$consentData['ip_address'] = $ip;
|
||||
$consentData['timestamp'] = date('c');
|
||||
|
||||
array_unshift($consents, $consentData);
|
||||
array_unshift($consents, $consent);
|
||||
$consents = array_slice($consents, 0, 1000);
|
||||
|
||||
file_put_contents($consentFile, json_encode($consents, JSON_PRETTY_PRINT));
|
||||
return $consent['id'];
|
||||
}
|
||||
|
||||
function getCookieConsentByIP() {
|
||||
$consentFile = __DIR__ . '/data/cookie_consents.json';
|
||||
function getCookieConsent() {
|
||||
$consentFile = __DIR__ . '/data/cookie_consent.json';
|
||||
|
||||
if (!file_exists($consentFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$consents = json_decode(file_get_contents($consentFile), true) ?: [];
|
||||
$ip = getClientIP();
|
||||
|
||||
foreach ($consents as $consent) {
|
||||
if (($consent['ip_address'] ?? '') === $ip) {
|
||||
return $consent;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return $consents[0] ?? null;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
@@ -442,16 +465,31 @@ function handleContactForm($data) {
|
||||
'description' => sanitizeInput($data['description'] ?? ''),
|
||||
'timestamp' => date('c'),
|
||||
'source' => 'contact_form',
|
||||
'form_type' => 'offer',
|
||||
'ip_address' => getClientIP()
|
||||
];
|
||||
|
||||
// Store lead locally first
|
||||
$leadId = storeLead($formData);
|
||||
|
||||
// Send to webhook
|
||||
$webhookResult = sendToWebhook($formData);
|
||||
|
||||
// Always return success to user, but include webhook info in debug mode
|
||||
$debugData = DEBUG_MODE ? [
|
||||
'lead_id' => $leadId,
|
||||
'webhook_result' => $webhookResult,
|
||||
'webhook_url' => WEBHOOK_URL,
|
||||
'form_data' => $formData
|
||||
] : null;
|
||||
|
||||
if ($webhookResult['success']) {
|
||||
storeLead($formData);
|
||||
sendResponse(true, 'Formular erfolgreich gesendet', $debugData);
|
||||
} else {
|
||||
// Still return success to user but log the webhook error
|
||||
error_log('Webhook failed but form was stored locally: ' . json_encode($webhookResult));
|
||||
sendResponse(true, 'Formular erfolgreich gesendet (Webhook-Fehler protokolliert)', $debugData);
|
||||
}
|
||||
|
||||
sendResponse(true, 'Formular erfolgreich gesendet');
|
||||
}
|
||||
|
||||
function handleLoginForm($data) {
|
||||
@@ -462,18 +500,8 @@ function handleLoginForm($data) {
|
||||
}
|
||||
}
|
||||
|
||||
$formData = [
|
||||
'email' => sanitizeInput($data['email']),
|
||||
'password' => $data['password'], // Don't sanitize password
|
||||
'remember' => $data['remember'] ?? false,
|
||||
'timestamp' => date('c'),
|
||||
'source' => 'login_form',
|
||||
'ip_address' => getClientIP()
|
||||
];
|
||||
|
||||
$webhookResult = sendToWebhook($formData);
|
||||
|
||||
sendResponse(true, 'Anmeldung verarbeitet');
|
||||
// Add your login logic here
|
||||
sendResponse(true, 'Login erfolgreich');
|
||||
}
|
||||
|
||||
function handleRegisterForm($data) {
|
||||
@@ -484,80 +512,35 @@ function handleRegisterForm($data) {
|
||||
}
|
||||
}
|
||||
|
||||
$formData = [
|
||||
'name' => sanitizeInput($data['name']),
|
||||
'email' => sanitizeInput($data['email']),
|
||||
'password' => $data['password'],
|
||||
'company' => sanitizeInput($data['company'] ?? ''),
|
||||
'phone' => sanitizeInput($data['phone'] ?? ''),
|
||||
'timestamp' => date('c'),
|
||||
'source' => 'register_form',
|
||||
'ip_address' => getClientIP()
|
||||
];
|
||||
|
||||
$webhookResult = sendToWebhook($formData);
|
||||
|
||||
// Add your registration logic here
|
||||
sendResponse(true, 'Registrierung erfolgreich');
|
||||
}
|
||||
|
||||
function handleLeadForm($data) {
|
||||
$formData = [
|
||||
'lead_data' => $data,
|
||||
'timestamp' => date('c'),
|
||||
'source' => 'lead_form',
|
||||
'ip_address' => getClientIP()
|
||||
];
|
||||
|
||||
$webhookResult = sendToWebhook($formData);
|
||||
|
||||
sendResponse(true, 'Lead erfolgreich gesendet');
|
||||
// Handle lead form submissions
|
||||
$leadId = storeLead($data);
|
||||
sendResponse(true, 'Lead gespeichert', ['lead_id' => $leadId]);
|
||||
}
|
||||
|
||||
function handleCookieConsent($data) {
|
||||
if (empty($data['preferences'])) {
|
||||
sendResponse(false, 'Preferences fehlen', null, 400);
|
||||
}
|
||||
|
||||
$consentData = [
|
||||
'hasConsented' => true,
|
||||
'preferences' => $data['preferences'],
|
||||
'source' => 'cookie_consent'
|
||||
];
|
||||
|
||||
storeCookieConsent($consentData);
|
||||
|
||||
// Get tracking scripts based on consent
|
||||
$scripts = loadTrackingScripts($data['preferences']);
|
||||
|
||||
// Send consent event to webhook
|
||||
$webhookData = [
|
||||
'event_type' => 'cookie_consent_update',
|
||||
'preferences' => $data['preferences'],
|
||||
'timestamp' => date('c'),
|
||||
'ip_address' => getClientIP()
|
||||
];
|
||||
sendToWebhook($webhookData);
|
||||
|
||||
sendResponse(true, 'Cookie-Einstellungen gespeichert', ['scripts' => $scripts]);
|
||||
$preferences = $data['preferences'] ?? [];
|
||||
$consentId = storeCookieConsent(['preferences' => $preferences]);
|
||||
|
||||
// Load tracking scripts based on preferences
|
||||
$scripts = loadTrackingScripts($preferences);
|
||||
|
||||
sendResponse(true, 'Cookie-Einstellungen gespeichert', [
|
||||
'consent_id' => $consentId,
|
||||
'scripts' => $scripts
|
||||
]);
|
||||
}
|
||||
|
||||
function handleGetCookieConsent($data) {
|
||||
$consent = getCookieConsentByIP();
|
||||
|
||||
$consent = getCookieConsent();
|
||||
if ($consent) {
|
||||
// Get tracking scripts based on saved consent
|
||||
$scripts = [];
|
||||
if (!empty($consent['preferences'])) {
|
||||
$scripts = loadTrackingScripts($consent['preferences']);
|
||||
}
|
||||
|
||||
sendResponse(true, 'Consent gefunden', [
|
||||
'hasConsented' => $consent['hasConsented'] ?? false,
|
||||
'preferences' => $consent['preferences'] ?? [],
|
||||
'scripts' => $scripts
|
||||
]);
|
||||
sendResponse(true, 'Cookie-Einstellungen gefunden', $consent);
|
||||
} else {
|
||||
sendResponse(false, 'Kein Consent gefunden', null, 404);
|
||||
sendResponse(false, 'Keine Cookie-Einstellungen gefunden', null, 404);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,14 +550,25 @@ function handleGetTrackingConfig($data) {
|
||||
}
|
||||
|
||||
function handleTrackEvent($data) {
|
||||
if (empty($data['event_name'])) {
|
||||
sendResponse(false, 'Event name fehlt', null, 400);
|
||||
}
|
||||
$eventName = $data['event_name'] ?? '';
|
||||
$eventData = $data['event_data'] ?? [];
|
||||
|
||||
$preferences = $data['preferences'] ?? ['analytics' => false, 'marketing' => false];
|
||||
$results = trackEvent($data['event_name'], $data['event_data'] ?? [], $preferences);
|
||||
// Send to Google Analytics
|
||||
$gaSuccess = sendEventToGA([
|
||||
'event_name' => $eventName,
|
||||
'params' => $eventData
|
||||
]);
|
||||
|
||||
sendResponse(true, 'Event getrackt', $results);
|
||||
// Send to Facebook
|
||||
$fbSuccess = sendEventToFB([
|
||||
'event_name' => $eventName,
|
||||
'custom_data' => $eventData
|
||||
]);
|
||||
|
||||
sendResponse(true, 'Event gesendet', [
|
||||
'ga_success' => $gaSuccess,
|
||||
'fb_success' => $fbSuccess
|
||||
]);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
@@ -637,6 +631,7 @@ try {
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log('API Error: ' . $e->getMessage());
|
||||
error_log('Stack trace: ' . $e->getTraceAsString());
|
||||
sendResponse(false, 'Interner Serverfehler', null, 500);
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
// details.js
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const serviceDetails = {
|
||||
'seo-optimierung': {
|
||||
title: 'SEO Optimierung',
|
||||
icon: '🔍',
|
||||
description: 'Verbessern Sie Ihre Sichtbarkeit in Suchmaschinen und erreichen Sie mehr Kunden online.',
|
||||
fullDescription: 'Unsere SEO-Optimierungsdienste helfen Ihnen, in Suchmaschinen besser gefunden zu werden. Wir analysieren Ihre Website, identifizieren Optimierungspotenziale und implementieren bewährte Strategien, um Ihr Ranking zu verbessern und mehr qualifizierte Besucher anzuziehen.',
|
||||
features: [
|
||||
'Keyword-Analyse und -Recherche',
|
||||
'On-Page Optimierung',
|
||||
'Technische SEO-Audits',
|
||||
'Content-Strategie',
|
||||
'Link-Building',
|
||||
'Performance-Tracking'
|
||||
],
|
||||
benefits: [
|
||||
'Höhere Sichtbarkeit in Suchmaschinen',
|
||||
'Mehr qualifizierte Besucher',
|
||||
'Verbesserte Conversion-Raten',
|
||||
'Langfristiger ROI'
|
||||
]
|
||||
},
|
||||
'cloud-migration': {
|
||||
title: 'Cloud Migration',
|
||||
icon: '☁️',
|
||||
description: 'Modernisieren Sie Ihre IT-Infrastruktur mit sicheren und skalierbaren Cloud-Lösungen.',
|
||||
fullDescription: 'Wir begleiten Sie bei der Migration Ihrer IT-Systeme in die Cloud. Von der Analyse Ihrer bestehenden Infrastruktur bis zur vollständigen Implementierung sorgen wir für einen reibungslosen Übergang mit minimalem Geschäftsausfall.',
|
||||
features: [
|
||||
'Infrastruktur-Analyse',
|
||||
'Migrationsplanung',
|
||||
'Datenübertragung',
|
||||
'Sicherheit & Compliance',
|
||||
'Performance-Optimierung',
|
||||
'Schulung & Support'
|
||||
],
|
||||
benefits: [
|
||||
'Kosteneinsparungen',
|
||||
'Bessere Skalierbarkeit',
|
||||
'Erhöhte Sicherheit',
|
||||
'Flexiblere Arbeitsweise'
|
||||
]
|
||||
},
|
||||
'datenanalyse': {
|
||||
title: 'Datenanalyse',
|
||||
icon: '📊',
|
||||
description: 'Gewinnen Sie wertvolle Einblicke aus Ihren Daten mit unseren Analyse-Lösungen.',
|
||||
fullDescription: 'Wir helfen Ihnen, Ihre Daten in wertvolle Erkenntnisse umzuwandeln. Mit modernen Analyse-Tools und -Methoden identifizieren wir Trends, Muster und Chancen, die Ihre Geschäftsentscheidungen verbessern.',
|
||||
features: [
|
||||
'Datenerfassung & -bereinigung',
|
||||
'Statistische Analyse',
|
||||
'Visualisierung & Dashboards',
|
||||
'Predictive Analytics',
|
||||
'Berichterstellung',
|
||||
'Consulting'
|
||||
],
|
||||
benefits: [
|
||||
'Bessere Entscheidungen',
|
||||
'Prozessoptimierung',
|
||||
'Kostensenkungen',
|
||||
'Wettbewerbsvorteile'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const serviceId = urlParams.get('service');
|
||||
const detailsContainer = document.getElementById('service-details');
|
||||
|
||||
if (serviceId && serviceDetails[serviceId]) {
|
||||
const service = serviceDetails[serviceId];
|
||||
|
||||
detailsContainer.innerHTML = `
|
||||
<div class="service-header">
|
||||
<div class="service-icon-large">${service.icon}</div>
|
||||
<h1 class="service-title-large">${service.title}</h1>
|
||||
<p class="service-description-large">${service.description}</p>
|
||||
</div>
|
||||
|
||||
<div class="service-content">
|
||||
<section class="service-section">
|
||||
<h2 class="section-title">Beschreibung</h2>
|
||||
<p class="section-text">${service.fullDescription}</p>
|
||||
</section>
|
||||
|
||||
<section class="service-section">
|
||||
<h2 class="section-title">Unsere Leistungen</h2>
|
||||
<ul class="feature-list">
|
||||
${service.features.map(feature => `<li>${feature}</li>`).join('')}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="service-section">
|
||||
<h2 class="section-title">Ihre Vorteile</h2>
|
||||
<ul class="benefit-list">
|
||||
${service.benefits.map(benefit => `<li>${benefit}</li>`).join('')}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="service-section">
|
||||
<h2 class="section-title">Interesse?</h2>
|
||||
<p class="section-text">Kontaktieren Sie uns für eine persönliche Beratung und ein maßgeschneidertes Angebot.</p>
|
||||
<div class="cta-buttons">
|
||||
<a href="offers.html" class="cta-btn primary">Kontakt aufnehmen</a>
|
||||
<a href="leads.html" class="cta-btn secondary">Zurück zum Dashboard</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Update page title
|
||||
document.title = `Profice - ${service.title}`;
|
||||
} else {
|
||||
// Fallback if no service specified
|
||||
detailsContainer.innerHTML = `
|
||||
<div class="error-message">
|
||||
<h2>Service nicht gefunden</h2>
|
||||
<p>Der angeforderte Service konnte nicht gefunden werden.</p>
|
||||
<a href="leads.html" class="cta-btn secondary">Zurück zum Dashboard</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
@@ -1,203 +0,0 @@
|
||||
// lead-details.js
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const leadId = urlParams.get('id');
|
||||
const detailsContainer = document.getElementById('leadDetailsContent');
|
||||
|
||||
function getLeads() {
|
||||
const storedLeads = localStorage.getItem('myLeads');
|
||||
if (storedLeads) {
|
||||
return JSON.parse(storedLeads);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function getStatusClass(status) {
|
||||
const statusClasses = {
|
||||
'neu': 'status-new',
|
||||
'in-bearbeitung': 'status-in-progress',
|
||||
'abgeschlossen': 'status-completed',
|
||||
'storniert': 'status-cancelled'
|
||||
};
|
||||
return statusClasses[status] || 'status-new';
|
||||
}
|
||||
|
||||
function formatDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('de-DE', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
}
|
||||
|
||||
if (leadId && detailsContainer) {
|
||||
const leadsData = getLeads();
|
||||
const lead = leadsData.find(l => l.id == leadId);
|
||||
|
||||
if (lead) {
|
||||
detailsContainer.innerHTML = `
|
||||
<div class="lead-details-card">
|
||||
<!-- Status Section -->
|
||||
<div class="detail-section">
|
||||
<h2 class="section-title">Status</h2>
|
||||
<div class="status-container">
|
||||
<span class="status-badge ${getStatusClass(lead.status)}">${lead.statusText}</span>
|
||||
<p class="status-info">Letzte Aktualisierung: ${formatDate(lead.datum)}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact Information -->
|
||||
<div class="detail-section">
|
||||
<h2 class="section-title">Kontaktinformationen</h2>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<div class="info-label">Name</div>
|
||||
<div class="info-value">${lead.name || 'Nicht angegeben'}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">Organisation</div>
|
||||
<div class="info-value">${lead.organisation || 'Nicht angegeben'}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">Kontakt</div>
|
||||
<div class="info-value">${lead.contact || 'Nicht angegeben'}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">Budget</div>
|
||||
<div class="info-value">${lead.budget || 'Nicht angegeben'}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Information -->
|
||||
<div class="detail-section">
|
||||
<h2 class="section-title">Dienstleistung</h2>
|
||||
<div class="service-info">
|
||||
<div class="service-icon">${getServiceIcon(lead.dienstleistung)}</div>
|
||||
<div class="service-details">
|
||||
<h3 class="service-title">${lead.dienstleistung}</h3>
|
||||
<p class="service-description">${getServiceDescription(lead.dienstleistung)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Project Description -->
|
||||
${lead.description ? `
|
||||
<div class="detail-section">
|
||||
<h2 class="section-title">Projektbeschreibung</h2>
|
||||
<div class="description-box">
|
||||
<p class="description-text">${lead.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<!-- Timeline -->
|
||||
<div class="detail-section">
|
||||
<h2 class="section-title">Zeitstrahl</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-item active">
|
||||
<div class="timeline-dot"></div>
|
||||
<div class="timeline-content">
|
||||
<h4>Anfrage erhalten</h4>
|
||||
<p>${formatDate(lead.datum)}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-item ${lead.status !== 'neu' ? 'active' : ''}">
|
||||
<div class="timeline-dot"></div>
|
||||
<div class="timeline-content">
|
||||
<h4>In Bearbeitung</h4>
|
||||
<p>${lead.status !== 'neu' ? 'Anfrage wird bearbeitet' : 'Ausstehend'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-item ${lead.status === 'abgeschlossen' ? 'active' : ''}">
|
||||
<div class="timeline-dot"></div>
|
||||
<div class="timeline-content">
|
||||
<h4>Abgeschlossen</h4>
|
||||
<p>${lead.status === 'abgeschlossen' ? 'Projekt erfolgreich abgeschlossen' : 'Ausstehend'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="detail-section">
|
||||
<h2 class="section-title">Aktionen</h2>
|
||||
<div class="action-buttons">
|
||||
<button class="action-btn primary" onclick="window.print()">
|
||||
🖨️ Details drucken
|
||||
</button>
|
||||
<button class="action-btn secondary" onclick="shareLead()">
|
||||
📤 Teilen
|
||||
</button>
|
||||
<button class="action-btn secondary" onclick="exportLead()">
|
||||
📄 Exportieren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Update page title
|
||||
document.title = `Profice - Anfrage von ${lead.name || 'Unbekannt'}`;
|
||||
} else {
|
||||
detailsContainer.innerHTML = `
|
||||
<div class="error-message">
|
||||
<h2>Anfrage nicht gefunden</h2>
|
||||
<p>Die angeforderte Anfrage konnte nicht gefunden werden.</p>
|
||||
<a href="leads.html" class="cta-btn secondary">Zurück zum Dashboard</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
} else {
|
||||
detailsContainer.innerHTML = `
|
||||
<div class="error-message">
|
||||
<h2>Keine Anfrage-ID angegeben</h2>
|
||||
<p>Bitte navigieren Sie über das Leads Dashboard zu den Details.</p>
|
||||
<a href="leads.html" class="cta-btn secondary">Zum Dashboard</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
function getServiceIcon(service) {
|
||||
const icons = {
|
||||
'Website': '🌐',
|
||||
'KI Integration': '🤖',
|
||||
'Automatisation': '⚙️',
|
||||
'Unabhängige Wahl': '🎯'
|
||||
};
|
||||
return icons[service] || '📋';
|
||||
}
|
||||
|
||||
function getServiceDescription(service) {
|
||||
const descriptions = {
|
||||
'Website': 'Moderne, responsive Webseiten, die konvertieren und Ihre Marke perfekt repräsentieren.',
|
||||
'KI Integration': 'Nutzen Sie die Kraft künstlicher Intelligenz, um Ihre Daten besser zu verstehen und Prozesse zu optimieren.',
|
||||
'Automatisation': 'Sparen Sie Zeit und Ressourcen durch intelligente Workflow-Automatisierungen.',
|
||||
'Unabhängige Wahl': 'Maßgeschneiderte Lösungen für Ihre spezifischen Anforderungen.'
|
||||
};
|
||||
return descriptions[service] || 'Individuelle Dienstleistung.';
|
||||
}
|
||||
|
||||
function shareLead() {
|
||||
if (navigator.share) {
|
||||
navigator.share({
|
||||
title: document.title,
|
||||
text: 'Details meiner Projektanfrage bei Profice',
|
||||
url: window.location.href
|
||||
});
|
||||
} else {
|
||||
// Fallback for browsers that don't support Web Share API
|
||||
navigator.clipboard.writeText(window.location.href);
|
||||
alert('Link wurde in die Zwischenablage kopiert!');
|
||||
}
|
||||
}
|
||||
|
||||
function exportLead() {
|
||||
window.print();
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Profice - Service Details</title>
|
||||
<link rel="stylesheet" href="../style/design.css">
|
||||
<link rel="stylesheet" href="../style/details.css">
|
||||
<link rel="stylesheet" href="../style/cursor.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Top Banner -->
|
||||
<header class="top-banner dark-theme">
|
||||
<div class="top-banner-left">
|
||||
<div class="banner-left">
|
||||
<button class="menu-toggle" id="menuToggle" aria-label="Menu">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
<a href="../index.html" class="logo-link">
|
||||
<img src="../images/logo/logo-01-complete.png" alt="Profice Logo" class="logo">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-banner-center">
|
||||
<nav class="main-nav">
|
||||
<a href="../index.html#hero-section" class="nav-link">Home</a>
|
||||
<a href="../index.html#enterprise" class="nav-link">Enterprise</a>
|
||||
<a href="../index.html#pricing" class="nav-link">Pricing</a>
|
||||
<a href="../index.html#services" class="nav-link">Lösungen</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="top-banner-right">
|
||||
<button id="cursorToggle" aria-label="Toggle Cursor" title="Toggle Custom Cursor">
|
||||
<img src="../images/additional/cursor.png" alt="Default Cursor" class="cursor-icon">
|
||||
</button>
|
||||
<button id="loginBtn" class="login-btn" aria-label="Log in" title="Log in">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path>
|
||||
<polyline points="10 17 15 12 10 7"></polyline>
|
||||
<line x1="15" y1="12" x2="3" y2="12"></line>
|
||||
</svg>
|
||||
Log in
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Slide Menu -->
|
||||
<nav class="slide-menu" id="slideMenu">
|
||||
<a href="../index.html">Startseite</a>
|
||||
<a href="offers.html">Kontakt & Anfrage</a>
|
||||
<a href="leads.html">Leads Dashboard</a>
|
||||
</nav>
|
||||
|
||||
<!-- Overlay -->
|
||||
<div class="overlay" id="overlay"></div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="main-content">
|
||||
<div class="form-container">
|
||||
<div id="service-details">
|
||||
<!-- Service details will be loaded here by JavaScript -->
|
||||
</div>
|
||||
<div class="back-button-container">
|
||||
<a href="leads.html" class="cta-btn secondary">← Zurück zum Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="../scripts/script.js"></script>
|
||||
<script src="../scripts/cursor.js"></script>
|
||||
<script src="../scripts/scroll-header.js"></script>
|
||||
<script src="../scripts/details.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,87 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Profice - Anfrage Details</title>
|
||||
<link rel="stylesheet" href="../style/design.css">
|
||||
<link rel="stylesheet" href="../style/lead-details.css">
|
||||
<link rel="stylesheet" href="../style/cursor.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Top Banner -->
|
||||
<header class="top-banner dark-theme">
|
||||
<div class="top-banner-left">
|
||||
<div class="banner-left">
|
||||
<button class="menu-toggle" id="menuToggle" aria-label="Menu">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
<a href="../index.html" class="logo-link">
|
||||
<img src="../images/logo/logo-01-complete.png" alt="Profice Logo" class="logo">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-banner-center">
|
||||
<nav class="main-nav">
|
||||
<a href="../index.html#hero-section" class="nav-link">Home</a>
|
||||
<a href="../index.html#enterprise" class="nav-link">Enterprise</a>
|
||||
<a href="../index.html#pricing" class="nav-link">Pricing</a>
|
||||
<a href="../index.html#services" class="nav-link">Lösungen</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="top-banner-right">
|
||||
<button id="cursorToggle" aria-label="Toggle Cursor" title="Toggle Custom Cursor">
|
||||
<img src="../images/additional/cursor.png" alt="Default Cursor" class="cursor-icon">
|
||||
</button>
|
||||
<button id="loginBtn" class="login-btn" aria-label="Log in" title="Log in">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path>
|
||||
<polyline points="10 17 15 12 10 7"></polyline>
|
||||
<line x1="15" y1="12" x2="3" y2="12"></line>
|
||||
</svg>
|
||||
Log in
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Slide Menu -->
|
||||
<nav class="slide-menu" id="slideMenu">
|
||||
<a href="../index.html">Startseite</a>
|
||||
<a href="offers.html">Kontakt & Anfrage</a>
|
||||
<a href="leads.html" class="active">Leads Dashboard</a>
|
||||
</nav>
|
||||
|
||||
<!-- Overlay -->
|
||||
<div class="overlay" id="overlay"></div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="main-content">
|
||||
<div class="lead-details-container">
|
||||
<!-- Lead Header -->
|
||||
<div class="lead-header">
|
||||
<div class="lead-icon">📋</div>
|
||||
<h1 class="lead-title">Anfrage Details</h1>
|
||||
<p class="lead-subtitle">Alle Informationen zu Ihrer Projektanfrage</p>
|
||||
</div>
|
||||
|
||||
<!-- Lead Details Content -->
|
||||
<div id="leadDetailsContent">
|
||||
<!-- Lead details will be loaded here by JavaScript -->
|
||||
</div>
|
||||
|
||||
<!-- Navigation Buttons -->
|
||||
<div class="navigation-buttons">
|
||||
<a href="leads.html" class="cta-btn secondary">← Zurück zum Dashboard</a>
|
||||
<a href="offers.html" class="cta-btn primary">Neue Anfrage</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="../scripts/script.js"></script>
|
||||
<script src="../scripts/cursor.js"></script>
|
||||
<script src="../scripts/scroll-header.js"></script>
|
||||
<script src="../scripts/lead-details.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user