diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 0000000..b9c0375
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,9 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(npm run dev:*)"
+ ],
+ "deny": [],
+ "ask": []
+ }
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index a547bf3..3b0b403 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,5 @@ dist-ssr
*.njsproj
*.sln
*.sw?
+
+.env
\ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..dda3a77
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,87 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Development Commands
+
+- `npm run dev` - Start development server (Vite, runs on port 8080)
+- `npm run build` - Build for production
+- `npm run build:dev` - Build in development mode
+- `npm run lint` - Run ESLint to check code quality
+- `npm run preview` - Preview production build locally
+
+## Project Architecture
+
+This is a React + TypeScript application built with Vite, targeting the German renewable energy market. The app connects energy customers with solar and wind installation professionals.
+
+### Core Technologies
+- **Vite** - Build tool and dev server
+- **React 18** - UI framework
+- **TypeScript** - Type safety
+- **React Router** - Client-side routing
+- **TanStack Query** - Server state management
+- **Supabase** - Backend database and authentication
+- **shadcn/ui** - Component library built on Radix UI
+- **Tailwind CSS** - Styling with custom energy-themed colors
+
+### Application Structure
+
+**Pages** (`src/pages/`):
+- `Index.tsx` - Landing page with hero section and energy type overview
+- `Solar.tsx` / `Wind.tsx` - Energy-specific information pages
+- `InstallateurFinden.tsx` - Installer search/listing page
+- `KostenloseBeratung.tsx` - Free consultation request page
+- `UnternehmenListen.tsx` - Business listing page
+
+**Components** (`src/components/`):
+- Standard layout components: `Header`, `Footer`, `HeroSection`
+- Feature components: `EnergyTypesSection`, `WhyChooseUsSection`, `EnergyTypeCard`
+- Complete shadcn/ui component library in `ui/` subdirectory
+
+**Database Integration** (`src/integrations/supabase/`):
+- `client.ts` - Supabase client configuration
+- `types.ts` - Auto-generated TypeScript types from Supabase schema
+
+### Database Schema (Supabase)
+
+Key tables:
+- `installers` - Installation companies with location, certifications, ratings
+- `quotes` - Customer quote requests with project details
+- `installer_quotes` - Installer responses to quote requests
+- `reviews` - Customer reviews for installers
+- `contact_clicks` - Analytics for installer contact interactions
+- `analytics_events` - General application usage analytics
+
+Energy types: `solar` | `wind`
+Quote status: `pending` | `accepted` | `rejected` | `expired`
+
+### Styling System
+
+Custom Tailwind configuration with energy-themed colors:
+- `solar` colors - Orange/yellow theme for solar energy
+- `wind` colors - Blue/teal theme for wind energy
+- CSS custom properties defined in `src/index.css`
+- Gradient backgrounds and shadows for visual branding
+
+### Path Aliases
+- `@/*` maps to `src/*` for clean imports
+
+### TypeScript Configuration
+- Relaxed strictness settings for rapid development
+- Path mapping configured for `@/` alias
+- Composite project structure with separate app and node configs
+
+### Routing Architecture
+All routes are defined in `src/App.tsx`:
+- `/` - Homepage
+- `/solar`, `/wind` - Energy type pages
+- `/installateur-finden` - Installer search
+- `/kostenlose-beratung` - Consultation requests
+- `/unternehmen-listen` - Business listings
+- `*` - 404 catch-all
+
+### Component Patterns
+- Functional components with hooks
+- shadcn/ui components for consistent design
+- Lucide React icons throughout the application
+- German language content and URLs
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 8628be7..047b871 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -83,7 +83,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -847,7 +846,6 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
- "dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^5.1.2",
@@ -865,7 +863,6 @@
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
@@ -880,7 +877,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -890,7 +886,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -900,14 +895,12 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -918,7 +911,6 @@
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
@@ -932,7 +924,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@@ -942,7 +933,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
@@ -956,7 +946,6 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
- "dev": true,
"license": "MIT",
"optional": true,
"engines": {
@@ -3008,14 +2997,14 @@
"version": "15.7.13",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.3.23",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz",
"integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
@@ -3026,7 +3015,7 @@
"version": "18.3.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^18.0.0"
@@ -3357,7 +3346,6 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -3370,7 +3358,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
@@ -3386,14 +3373,12 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
- "dev": true,
"license": "MIT"
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
@@ -3407,7 +3392,6 @@
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
- "dev": true,
"license": "MIT"
},
"node_modules/argparse": {
@@ -3471,14 +3455,12 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true,
"license": "MIT"
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3502,7 +3484,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
@@ -3558,7 +3539,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -3606,7 +3586,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
@@ -3631,7 +3610,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
@@ -3680,7 +3658,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
@@ -3693,14 +3670,12 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
"license": "MIT"
},
"node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -3717,7 +3692,6 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
- "dev": true,
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -3731,7 +3705,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
- "dev": true,
"license": "MIT",
"bin": {
"cssesc": "bin/cssesc"
@@ -3918,14 +3891,12 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
- "dev": true,
"license": "Apache-2.0"
},
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
- "dev": true,
"license": "MIT"
},
"node_modules/dom-helpers": {
@@ -3942,7 +3913,6 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
- "dev": true,
"license": "MIT"
},
"node_modules/electron-to-chromium": {
@@ -3984,7 +3954,6 @@
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
- "dev": true,
"license": "MIT"
},
"node_modules/esbuild": {
@@ -4263,7 +4232,6 @@
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
@@ -4280,7 +4248,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
@@ -4307,7 +4274,6 @@
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
- "dev": true,
"license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
@@ -4330,7 +4296,6 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -4381,7 +4346,6 @@
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
- "dev": true,
"license": "ISC",
"dependencies": {
"cross-spawn": "^7.0.0",
@@ -4412,7 +4376,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -4427,7 +4390,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -4446,7 +4408,6 @@
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
- "dev": true,
"license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
@@ -4467,7 +4428,6 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
@@ -4480,7 +4440,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -4490,7 +4449,6 @@
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
@@ -4536,7 +4494,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -4605,7 +4562,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
@@ -4618,7 +4574,6 @@
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
@@ -4634,7 +4589,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -4644,7 +4598,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -4654,7 +4607,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -4667,7 +4619,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
@@ -4677,14 +4628,12 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true,
"license": "ISC"
},
"node_modules/jackspeak": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
- "dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
@@ -4700,7 +4649,6 @@
"version": "1.21.6",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
- "dev": true,
"license": "MIT",
"bin": {
"jiti": "bin/jiti.js"
@@ -4774,7 +4722,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
@@ -4787,7 +4734,6 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
- "dev": true,
"license": "MIT"
},
"node_modules/locate-path": {
@@ -5297,7 +5243,6 @@
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
- "dev": true,
"license": "ISC"
},
"node_modules/lucide-react": {
@@ -5322,7 +5267,6 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@@ -5332,7 +5276,6 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
@@ -5359,7 +5302,6 @@
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
- "dev": true,
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -5376,7 +5318,6 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"any-promise": "^1.0.0",
@@ -5388,7 +5329,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -5431,7 +5371,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -5460,7 +5399,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -5520,7 +5458,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
- "dev": true,
"license": "BlueOak-1.0.0"
},
"node_modules/parent-module": {
@@ -5550,7 +5487,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -5560,14 +5496,12 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true,
"license": "MIT"
},
"node_modules/path-scurry": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
- "dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^10.2.0",
@@ -5584,14 +5518,12 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -5604,7 +5536,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -5614,7 +5545,6 @@
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -5624,7 +5554,6 @@
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -5653,7 +5582,6 @@
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
- "dev": true,
"license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.0.0",
@@ -5671,7 +5599,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"camelcase-css": "^2.0.1"
@@ -5691,7 +5618,6 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
"integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -5727,7 +5653,6 @@
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -5753,7 +5678,6 @@
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
@@ -5767,7 +5691,6 @@
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/prelude-ls": {
@@ -5811,7 +5734,6 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -6035,7 +5957,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"pify": "^2.3.0"
@@ -6045,7 +5966,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
@@ -6090,7 +6010,6 @@
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.13.0",
@@ -6118,7 +6037,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
"license": "MIT",
"engines": {
"iojs": ">=1.0.0",
@@ -6165,7 +6083,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -6211,7 +6128,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -6224,7 +6140,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -6234,7 +6149,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
- "dev": true,
"license": "ISC",
"engines": {
"node": ">=14"
@@ -6257,7 +6171,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -6267,7 +6180,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
@@ -6286,7 +6198,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
@@ -6301,7 +6212,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -6311,14 +6221,12 @@
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
"license": "MIT"
},
"node_modules/string-width-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -6331,7 +6239,6 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
@@ -6348,7 +6255,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -6361,7 +6267,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -6384,7 +6289,6 @@
"version": "3.35.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
"integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.2",
@@ -6420,7 +6324,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -6443,7 +6346,6 @@
"version": "3.4.17",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
@@ -6490,7 +6392,6 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"any-promise": "^1.0.0"
@@ -6500,7 +6401,6 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"thenify": ">= 3.1.0 < 4"
@@ -6519,7 +6419,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
@@ -6551,7 +6450,6 @@
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
- "dev": true,
"license": "Apache-2.0"
},
"node_modules/tslib": {
@@ -6714,7 +6612,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true,
"license": "MIT"
},
"node_modules/vaul": {
@@ -6832,7 +6729,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
@@ -6858,7 +6754,6 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
@@ -6877,7 +6772,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
@@ -6895,7 +6789,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -6905,14 +6798,12 @@
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
"license": "MIT"
},
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
@@ -6927,7 +6818,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -6940,7 +6830,6 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -6974,7 +6863,6 @@
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz",
"integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==",
- "dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
diff --git a/public/sun_flow_banner.png b/public/sun_flow_banner.png
new file mode 100644
index 0000000..70186f1
Binary files /dev/null and b/public/sun_flow_banner.png differ
diff --git a/src/App.tsx b/src/App.tsx
index bab50a2..abb4d61 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -6,6 +6,9 @@ import { BrowserRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import Solar from "./pages/Solar";
import Wind from "./pages/Wind";
+import InstallateurFinden from "./pages/InstallateurFinden";
+import KostenloseBeratung from "./pages/KostenloseBeratung";
+import UnternehmenListen from "./pages/UnternehmenListen";
import NotFound from "./pages/NotFound";
const queryClient = new QueryClient();
@@ -15,11 +18,14 @@ const App = () => (
-
+
} />
} />
} />
+ } />
+ } />
+ } />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
} />
diff --git a/src/components/CalculatorNavigation.tsx b/src/components/CalculatorNavigation.tsx
new file mode 100644
index 0000000..f0feaa8
--- /dev/null
+++ b/src/components/CalculatorNavigation.tsx
@@ -0,0 +1,146 @@
+import React from 'react';
+import { Card, CardContent } from '@/components/ui/card';
+import { Button } from '@/components/ui/button';
+import { Sun, Wind, Calculator, ArrowRight, Zap } from 'lucide-react';
+import { Link } from 'react-router-dom';
+
+const CalculatorNavigation = () => {
+ return (
+
+
+
+
+
+ Einsparungsrechner
+
+
+ Berechnen Sie Ihre potentiellen Einsparungen mit unseren
+ spezialisierten Rechnern für Solar- und Windenergie
+
+
+
+
+ {/* Solar Calculator Card */}
+
+
+
+
+
+
+ Solar-Einsparungsrechner
+
+
+
+ Erfahren Sie, wie viel Sie mit einer Photovoltaik-Anlage sparen können.
+ Berechnung basierend auf Ihrer Dachgröße, Standort und Energieverbrauch.
+
+
+
+
+
+ Monatliche & jährliche Einsparungen
+
+
+
+ 25-Jahre Gesamteinsparungen
+
+
+
+ Amortisationsdauer
+
+
+
+
+
+ Solar-Rechner öffnen
+
+
+
+
+
+
+ {/* Wind Calculator Card */}
+
+
+
+
+
+
+ Windenergie-Rechner
+
+
+
+ Berechnen Sie das Potential von Windenergie für Ihr Grundstück.
+ Berücksichtigt Grundstücksgröße, Windgeschwindigkeit und lokale Bestimmungen.
+
+
+
+
+
+ Anlagengröße-Empfehlung
+
+
+
+ 20-Jahre Einsparpotential
+
+
+
+ Förderungen & Zuschüsse
+
+
+
+
+
+ Wind-Rechner öffnen
+
+
+
+
+
+
+
+ {/* Bottom CTA */}
+
+
+ Unsicher, welche Lösung für Sie geeignet ist?
+
+
+
+ Alle Installateure ansehen
+
+
+
+
+
+
+ );
+};
+
+export default CalculatorNavigation;
\ No newline at end of file
diff --git a/src/components/EnergyTypeCard.tsx b/src/components/EnergyTypeCard.tsx
index e9f6fe9..7868b6d 100644
--- a/src/components/EnergyTypeCard.tsx
+++ b/src/components/EnergyTypeCard.tsx
@@ -8,7 +8,7 @@ interface EnergyTypeCardProps {
description: string;
image: string;
gradient: string;
- buttonVariant: "solar" | "wind" | "geo" | "battery";
+ buttonVariant: "solar" | "wind";
href: string;
features: string[];
}
diff --git a/src/components/EnergyTypesSection.tsx b/src/components/EnergyTypesSection.tsx
index 865d6eb..d4c0649 100644
--- a/src/components/EnergyTypesSection.tsx
+++ b/src/components/EnergyTypesSection.tsx
@@ -1,8 +1,6 @@
import EnergyTypeCard from "./EnergyTypeCard";
import solarImage from "@/assets/solar-installation.jpg";
import windImage from "@/assets/wind-turbines.jpg";
-import geoImage from "@/assets/geothermal-system.jpg";
-import batteryImage from "@/assets/battery-storage.jpg";
const EnergyTypesSection = () => {
const energyTypes = [
@@ -33,34 +31,6 @@ const EnergyTypesSection = () => {
"Wartungsarme Technologie",
"Ideale Ergänzung zu Solar"
]
- },
- {
- title: "Geothermie",
- description: "Heizen und kühlen Sie Ihr Gebäude mit der natürlichen Erdwärme - effizient und umweltschonend.",
- image: geoImage,
- gradient: "bg-gradient-geo",
- buttonVariant: "geo" as const,
- href: "/geothermie",
- features: [
- "Ganzjährig konstante Temperaturen",
- "Niedrige Betriebskosten",
- "Heizen und Kühlen in einem System",
- "Sehr lange Lebensdauer"
- ]
- },
- {
- title: "Batteriespeicher",
- description: "Speichern Sie überschüssige Energie und nutzen Sie sie bei Bedarf - für maximale Unabhängigkeit.",
- image: batteryImage,
- gradient: "bg-gradient-battery",
- buttonVariant: "battery" as const,
- href: "/batteriespeicher",
- features: [
- "24/7 Energieverfügbarkeit",
- "Notstromfunktion",
- "Intelligente Steuerung",
- "Erhöhte Eigenverbrauchsquote"
- ]
}
];
@@ -77,7 +47,7 @@ const EnergyTypesSection = () => {
-
+
{energyTypes.map((type) => (
))}
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index bc90642..0a91cba 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -52,16 +52,6 @@ const Footer = () => {
Wind-Installateure
-
-
- Geothermie-Installateure
-
-
-
-
- Batteriespeicher-Installateure
-
-
@@ -74,11 +64,6 @@ const Footer = () => {
Installateur Finden
-
-
- Kostenlose Beratung
-
-
Unternehmen Listen
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 1a7a6a6..773a2fb 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -23,12 +23,6 @@ const Header = () => {
Wind
-
- Geothermie
-
-
- Batteriespeicher
-
Installateur Finden
@@ -39,12 +33,6 @@ const Header = () => {
Unternehmen Listen
-
-
-
- Kostenlose Beratung
-
-
{/* Mobile Menu Button */}
diff --git a/src/components/HeroSection.tsx b/src/components/HeroSection.tsx
index 347f468..a898c8c 100644
--- a/src/components/HeroSection.tsx
+++ b/src/components/HeroSection.tsx
@@ -1,96 +1,111 @@
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
-import { Search, MapPin, Zap } from "lucide-react";
+import { Search, MapPin, Zap, ArrowRight } from "lucide-react";
import { Link } from "react-router-dom";
-import heroImage from "@/assets/hero-renewable-energy.jpg";
const HeroSection = () => {
return (
- {/* Background Image with Overlay */}
+ {/* Background Image with Minimal Overlay */}
-
+ {/* Subtle overlay for text readability */}
+
{/* Content */}
-
- Finden Sie Ihren perfekten{" "}
-
- Erneuerbaren Energie
- {" "}
- Installateur
-
+ {/* Clean headline with subtle color accents */}
+
+
+ Finden Sie Ihren perfekten{" "}
+
+ Erneuerbaren
+ {" "}
+
+ Energie
+ {" "}
+
+ Installateur
+
+
+
-
- Vergleichen Sie qualifizierte Fachbetriebe für Solar, Wind, Geothermie
- und Batteriespeicher in Ihrer Region. Kostenlos und unverbindlich.
+ {/* Clean description with subtle accents */}
+
+ Vergleichen Sie qualifizierte Fachbetriebe für{" "}
+ Solar und{" "}
+ Wind
+ in Ihrer Region.{" "}
+ Kostenlos und{" "}
+ unverbindlich .
- {/* Search Box */}
-
+ {/* Clean search box */}
+
-
-
+
+
-
-
-
+
+
+
Energieart wählen
Solar
Wind
- Geothermie
- Batteriespeicher
-
+
Installateur Finden
- {/* CTA Buttons */}
+ {/* Clean CTA buttons */}
-
-
- Kostenlose Beratung Anfordern
-
-
-
-
+
+
Alle Installateure Ansehen
+
- {/* Floating Stats */}
+ {/* Clean floating stats */}
-
+
-
500+
-
Installateure
+
500+
+
Installateure
-
2,500+
-
Projekte
+
2,500+
+
Projekte
-
4.8★
-
Bewertung
+
4.8★
+
Bewertung
diff --git a/src/components/SolarCalculator.tsx b/src/components/SolarCalculator.tsx
new file mode 100644
index 0000000..e21cc2c
--- /dev/null
+++ b/src/components/SolarCalculator.tsx
@@ -0,0 +1,538 @@
+import React, { useState, useEffect } from 'react';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
+import { HelpCircle } from 'lucide-react';
+import { analyticsService, quoteService } from '@/lib/database';
+
+interface CalculatorResults {
+ monthlySavings: number;
+ yearlySavings: number;
+ lifetimeSavings: number;
+ systemSize: number;
+ installCost: number;
+ taxCredit: number;
+ netCost: number;
+ paybackPeriod: number;
+}
+
+const SolarCalculator = () => {
+ const [monthlyBill, setMonthlyBill] = useState
('150');
+ const [homeSize, setHomeSize] = useState('2000');
+ const [roofType, setRoofType] = useState('asphalt');
+ const [sunlightHours, setSunlightHours] = useState('6');
+ const [electricityRate, setElectricityRate] = useState('0.12');
+ const [zipCode, setZipCode] = useState('');
+ const [results, setResults] = useState(null);
+ const [showResults, setShowResults] = useState(false);
+ const [showQuoteForm, setShowQuoteForm] = useState(false);
+
+ // Quote form fields
+ const [customerName, setCustomerName] = useState('');
+ const [customerEmail, setCustomerEmail] = useState('');
+ const [customerPhone, setCustomerPhone] = useState('');
+
+ const calculateSavings = async () => {
+ const monthlyBillNum = parseFloat(monthlyBill) || 0;
+ const homeSizeNum = parseFloat(homeSize) || 0;
+ const sunlightHoursNum = parseFloat(sunlightHours) || 6;
+ const electricityRateNum = parseFloat(electricityRate) || 0.12;
+
+ if (monthlyBillNum === 0) {
+ alert('Bitte geben Sie Ihre monatliche Stromrechnung ein');
+ return;
+ }
+
+ // Calculate system size based on monthly usage
+ const monthlyUsage = monthlyBillNum / electricityRateNum; // kWh per month
+ const dailyUsage = monthlyUsage / 30; // kWh per day
+ const systemSize = Math.ceil(dailyUsage / sunlightHoursNum); // kW system size
+
+ // Roof type efficiency factors
+ const roofFactors: { [key: string]: number } = {
+ asphalt: 1.0,
+ tile: 0.95,
+ metal: 1.05,
+ flat: 0.9
+ };
+
+ const roofFactor = roofFactors[roofType] || 1.0;
+ const adjustedSystemSize = Math.max(3, Math.min(20, systemSize * roofFactor));
+
+ // Cost calculations (converted to EUR for German market)
+ const costPerWatt = 2.8; // Average cost per watt installed in EUR
+ const installCost = adjustedSystemSize * 1000 * costPerWatt;
+ const federalTaxCredit = installCost * 0.19; // German VAT can be deducted
+ const netCost = installCost - federalTaxCredit;
+
+ // Energy production calculations
+ const annualProduction = adjustedSystemSize * sunlightHoursNum * 365 * 0.85; // 85% efficiency
+ const monthlyProduction = annualProduction / 12;
+
+ // Savings calculations
+ const monthlySavings = Math.min(monthlyProduction * electricityRateNum, monthlyBillNum * 0.9);
+ const yearlySavings = monthlySavings * 12;
+ const lifetimeSavings = yearlySavings * 25; // 25-year system life
+
+ // Payback period
+ const paybackPeriod = Math.round(netCost / yearlySavings * 10) / 10;
+
+ setResults({
+ monthlySavings: Math.round(monthlySavings),
+ yearlySavings: Math.round(yearlySavings),
+ lifetimeSavings: Math.round(lifetimeSavings),
+ systemSize: Math.round(adjustedSystemSize * 10) / 10,
+ installCost: Math.round(installCost),
+ taxCredit: Math.round(federalTaxCredit),
+ netCost: Math.round(netCost),
+ paybackPeriod
+ });
+
+ setShowResults(true);
+
+ // Track calculator usage
+ try {
+ await analyticsService.trackEvent({
+ event_type: 'solar_calculator_used',
+ page_url: window.location.pathname,
+ user_agent: navigator.userAgent,
+ session_id: sessionStorage.getItem('session_id') || 'anonymous',
+ event_data: {
+ monthly_bill: monthlyBillNum,
+ home_size: homeSizeNum,
+ roof_type: roofType,
+ sunlight_hours: sunlightHoursNum,
+ electricity_rate: electricityRateNum,
+ zip_code: zipCode,
+ calculated_savings: {
+ monthly: Math.round(monthlySavings),
+ yearly: Math.round(yearlySavings),
+ lifetime: Math.round(lifetimeSavings),
+ system_size: Math.round(adjustedSystemSize * 10) / 10,
+ payback_period: paybackPeriod
+ }
+ }
+ });
+ } catch (error) {
+ console.error('Error tracking calculator usage:', error);
+ }
+ };
+
+ // Auto-populate electricity rate based on ZIP code (German postal codes)
+ useEffect(() => {
+ if (zipCode.length === 5) {
+ // Simplified German electricity rates by region
+ const rates: { [key: string]: number } = {
+ '0': 0.32, // Eastern Germany
+ '1': 0.34, // Berlin/Brandenburg
+ '2': 0.33, // Northern Germany
+ '3': 0.35, // Central Germany
+ '4': 0.33, // Western Germany
+ '5': 0.34, // NRW
+ '6': 0.35, // Hessen/Baden-Württemberg
+ '7': 0.33, // Baden-Württemberg
+ '8': 0.32, // Bavaria
+ '9': 0.31 // Bavaria
+ };
+
+ const firstDigit = zipCode[0];
+ const rate = rates[firstDigit] || 0.33;
+ setElectricityRate(rate.toFixed(2));
+ }
+ }, [zipCode]);
+
+ // Submit quote request
+ const handleQuoteSubmission = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (!customerName || !customerEmail || !results) {
+ alert('Bitte füllen Sie alle Pflichtfelder aus.');
+ return;
+ }
+
+ try {
+ await quoteService.submitQuote({
+ customer_name: customerName,
+ customer_email: customerEmail,
+ customer_phone: customerPhone,
+ energy_type: 'solar',
+ location: zipCode,
+ monthly_bill: parseFloat(monthlyBill),
+ property_size: parseFloat(homeSize),
+ property_type: 'residential',
+ roof_type: roofType,
+ estimated_cost: results.installCost,
+ estimated_savings: results.yearlySavings,
+ additional_requirements: `Berechnet: ${results.systemSize} kW System, ${results.paybackPeriod} Jahre Amortisation`,
+ status: 'pending'
+ });
+
+ alert('Ihr Angebot wurde erfolgreich eingereicht! Sie erhalten bald Kontakt von qualifizierten Installateuren.');
+ setShowQuoteForm(false);
+
+ // Reset form
+ setCustomerName('');
+ setCustomerEmail('');
+ setCustomerPhone('');
+
+ } catch (error) {
+ console.error('Error submitting quote:', error);
+ alert('Fehler beim Senden des Angebots. Bitte versuchen Sie es später erneut.');
+ }
+ };
+
+ const createSavingsChart = () => {
+ if (!results) return null;
+
+ const bars = [
+ { label: 'Monat 1', value: results.monthlySavings },
+ { label: 'Jahr 1', value: results.yearlySavings },
+ { label: '5 Jahre', value: results.yearlySavings * 5 },
+ { label: '10 Jahre', value: results.yearlySavings * 10 },
+ { label: '25 Jahre', value: results.lifetimeSavings }
+ ];
+
+ const maxValue = results.lifetimeSavings;
+
+ return (
+
+ {bars.map((bar, index) => (
+
+ ))}
+
+ );
+ };
+
+ return (
+
+
+
+ {/* Header */}
+
+
+
+ Solar-Einsparungsrechner
+
+
+ Entdecken Sie, wie viel Sie mit Solarenergie sparen können
+
+
+
+
+ {/* Calculator Section */}
+
+
+
+
+ Berechnen Sie Ihre Solar-Einsparungen
+
+
+
+
+
+
+
+
+ Durchschnittliche monatliche Stromrechnung
+
+
+
+ €
+ setMonthlyBill(e.target.value)}
+ placeholder="150"
+ className="pl-8 h-12 border-2 border-gray-200 focus:border-blue-500"
+ />
+
+
+
+
+
+ Hausgröße (m²)
+
+
+ setHomeSize(e.target.value)}
+ placeholder="200"
+ className="h-12 border-2 border-gray-200 focus:border-blue-500"
+ />
+
+
+
+
+ Dachtyp
+
+
+
+
+
+
+
+ Ziegeldach
+ Tonziegel
+ Metalldach
+ Flachdach
+
+
+
+
+
+
+
+
+
+
+
+
+ Tägliche Sonnenstunden
+
+
+
+
+
+
+
+ 4 Stunden (Weniger sonnige Gebiete)
+ 5 Stunden (Mäßige Sonne)
+ 6 Stunden (Gute Sonneneinstrahlung)
+ 7 Stunden (Sehr sonnig)
+ 8+ Stunden (Ausgezeichnete Sonne)
+
+
+
+
+
+
+ Strompreis (pro kWh)
+
+
+
+ €
+ setElectricityRate(e.target.value)}
+ step="0.01"
+ placeholder="0.33"
+ className="pl-8 h-12 border-2 border-gray-200 focus:border-blue-500"
+ />
+
+
+
+
+
+ Postleitzahl
+
+
+ setZipCode(e.target.value)}
+ placeholder="12345"
+ pattern="[0-9]{5}"
+ className="h-12 border-2 border-gray-200 focus:border-blue-500"
+ />
+
+
+
+
+
+
+ Meine Einsparungen berechnen
+
+
+
+ {/* Results Section */}
+
+
+ Ihre Solar-Einsparungen
+
+
+
+ {showResults && results ? (
+
+
+
+ €{results.monthlySavings}
+ Monatliche Einsparungen
+
+
+
+
+
+ €{results.yearlySavings.toLocaleString()}
+ Jährliche Einsparungen
+
+
+
+
+
+ €{results.lifetimeSavings.toLocaleString()}
+ 25-Jahre Einsparungen
+
+
+
+
+
+ Kostenaufschlüsselung
+
+
+
+
+ Anlagengröße:
+ {results.systemSize} kW
+
+
+ Installationskosten:
+ €{results.installCost.toLocaleString()}
+
+
+ Förderung/MwSt. (19%):
+ -€{results.taxCredit.toLocaleString()}
+
+
+ Nettokosten:
+ €{results.netCost.toLocaleString()}
+
+
+ Amortisationsdauer:
+ {results.paybackPeriod} Jahre
+
+
+
+
+
+
+
+
+ Einsparungen über die Zeit
+
+ {createSavingsChart()}
+
+
+
+ {/* Quote Request Button */}
+
+ setShowQuoteForm(true)}
+ className="bg-green-600 hover:bg-green-700 text-white font-semibold shadow-lg"
+ size="lg"
+ >
+ Kostenloses Angebot anfordern
+
+
+
+ ) : (
+
+
Bereit zur Berechnung
+
Füllen Sie das Formular aus und klicken Sie auf "Berechnen"
+
+ )}
+
+ {/* Quote Form Modal */}
+ {showQuoteForm && (
+
+
+
+ Kostenloses Angebot anfordern
+
+
+
+
+
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default SolarCalculator;
\ No newline at end of file
diff --git a/src/components/WhyChooseUsSection.tsx b/src/components/WhyChooseUsSection.tsx
index b586563..3259f89 100644
--- a/src/components/WhyChooseUsSection.tsx
+++ b/src/components/WhyChooseUsSection.tsx
@@ -19,13 +19,13 @@ const WhyChooseUsSection = () => {
icon: Award,
title: "Beste Preise",
description: "Durch unseren Vergleich erhalten Sie garantiert die besten Konditionen für Ihr Projekt.",
- gradient: "bg-gradient-geo"
+ gradient: "bg-gradient-solar"
},
{
icon: Clock,
title: "Schnelle Vermittlung",
description: "In nur wenigen Minuten erhalten Sie passende Installateur-Vorschläge für Ihre Region.",
- gradient: "bg-gradient-battery"
+ gradient: "bg-gradient-wind"
},
{
icon: HeartHandshake,
diff --git a/src/components/WindCalculator.tsx b/src/components/WindCalculator.tsx
new file mode 100644
index 0000000..91be394
--- /dev/null
+++ b/src/components/WindCalculator.tsx
@@ -0,0 +1,478 @@
+import React, { useState, useEffect } from 'react';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
+import { HelpCircle, Wind, Zap } from 'lucide-react';
+import { analyticsService } from '@/lib/database';
+
+interface WindCalculatorResults {
+ monthlySavings: number;
+ yearlySavings: number;
+ lifetimeSavings: number;
+ turbineSize: number;
+ installCost: number;
+ taxCredit: number;
+ netCost: number;
+ paybackPeriod: number;
+}
+
+const WindCalculator = () => {
+ const [monthlyBill, setMonthlyBill] = useState('150');
+ const [propertySize, setPropertySize] = useState('2');
+ const [zoning, setZoning] = useState('rural');
+ const [windSpeed, setWindSpeed] = useState('12');
+ const [turbineHeight, setTurbineHeight] = useState('80');
+ const [electricityRate, setElectricityRate] = useState('0.33');
+ const [zipCode, setZipCode] = useState('');
+ const [results, setResults] = useState(null);
+ const [showResults, setShowResults] = useState(false);
+
+ const calculateWindSavings = async () => {
+ const monthlyBillNum = parseFloat(monthlyBill) || 0;
+ const propertySizeNum = parseFloat(propertySize) || 0;
+ const windSpeedNum = parseFloat(windSpeed) || 12;
+ const turbineHeightNum = parseFloat(turbineHeight) || 80;
+ const electricityRateNum = parseFloat(electricityRate) || 0.33;
+
+ if (monthlyBillNum === 0) {
+ alert('Bitte geben Sie Ihre monatliche Stromrechnung ein');
+ return;
+ }
+
+ // Wind power calculation (simplified for German market)
+ const airDensity = 1.225; // kg/m³ at sea level
+ const powerCoefficient = 0.35; // Typical for small wind turbines
+ const efficiency = 0.85;
+
+ // Determine turbine size based on property and zoning
+ let maxTurbineKW = 0;
+ const zoningSizeFactors: { [key: string]: number } = {
+ rural: 1.5,
+ agricultural: 2.0,
+ suburban: 0.8,
+ urban: 0.5
+ };
+
+ const sizeFactor = zoningSizeFactors[zoning] || 1.0;
+
+ // Base turbine size on property size and height allowance
+ if (propertySizeNum >= 0.8 && turbineHeightNum >= 80) { // 0.8 hectares ≈ 2 acres
+ maxTurbineKW = Math.min(20, propertySizeNum * 3 * sizeFactor);
+ } else if (propertySizeNum >= 0.4 && turbineHeightNum >= 60) {
+ maxTurbineKW = Math.min(10, propertySizeNum * 2 * sizeFactor);
+ } else {
+ maxTurbineKW = Math.min(5, propertySizeNum * 1.5 * sizeFactor);
+ }
+
+ // Wind speed factor affects actual output
+ let windSpeedFactor = 1.0;
+ if (windSpeedNum >= 15) windSpeedFactor = 1.4;
+ else if (windSpeedNum >= 12) windSpeedFactor = 1.0;
+ else if (windSpeedNum >= 10) windSpeedFactor = 0.7;
+ else windSpeedFactor = 0.4;
+
+ const effectiveTurbineKW = maxTurbineKW * windSpeedFactor;
+
+ // Height bonus (higher = better wind)
+ let heightFactor = 1.0;
+ if (turbineHeightNum >= 120) heightFactor = 1.3;
+ else if (turbineHeightNum >= 100) heightFactor = 1.2;
+ else if (turbineHeightNum >= 80) heightFactor = 1.1;
+ else if (turbineHeightNum >= 60) heightFactor = 1.0;
+ else heightFactor = 0.9;
+
+ const finalTurbineKW = Math.max(1, effectiveTurbineKW * heightFactor);
+
+ // Annual energy production (kWh/year)
+ // Small wind turbines typically produce 25-35% capacity factor
+ const capacityFactor = Math.min(0.35, windSpeedNum * 0.025);
+ const annualProduction = finalTurbineKW * 8760 * capacityFactor; // 8760 hours/year
+ const monthlyProduction = annualProduction / 12;
+
+ // Cost calculations (adapted for German market)
+ const costPerKW = 6500; // EUR - Higher than solar due to complexity, adapted for German market
+ const installCost = finalTurbineKW * costPerKW;
+ const germanIncentives = installCost * 0.25; // KfW subsidies and regional incentives
+ const netCost = installCost - germanIncentives;
+
+ // Savings calculations
+ const monthlyUsage = monthlyBillNum / electricityRateNum;
+ const monthlySavings = Math.min(monthlyProduction * electricityRateNum, monthlyBillNum * 0.8);
+ const yearlySavings = monthlySavings * 12;
+ const lifetimeSavings = yearlySavings * 20; // 20-year turbine life
+
+ // Payback period
+ const paybackPeriod = Math.round(netCost / yearlySavings * 10) / 10;
+
+ setResults({
+ monthlySavings: Math.round(monthlySavings),
+ yearlySavings: Math.round(yearlySavings),
+ lifetimeSavings: Math.round(lifetimeSavings),
+ turbineSize: Math.round(finalTurbineKW * 10) / 10,
+ installCost: Math.round(installCost),
+ taxCredit: Math.round(germanIncentives),
+ netCost: Math.round(netCost),
+ paybackPeriod
+ });
+
+ setShowResults(true);
+
+ // Track wind calculator usage
+ try {
+ await analyticsService.trackEvent({
+ event_type: 'wind_calculator_used',
+ page_url: window.location.pathname,
+ user_agent: navigator.userAgent,
+ session_id: sessionStorage.getItem('session_id') || 'anonymous',
+ event_data: {
+ monthly_bill: monthlyBillNum,
+ property_size: propertySizeNum,
+ zoning: zoning,
+ wind_speed: windSpeedNum,
+ turbine_height: turbineHeightNum,
+ electricity_rate: electricityRateNum,
+ zip_code: zipCode,
+ calculated_savings: {
+ monthly: Math.round(monthlySavings),
+ yearly: Math.round(yearlySavings),
+ lifetime: Math.round(lifetimeSavings),
+ turbine_size: Math.round(finalTurbineKW * 10) / 10,
+ payback_period: paybackPeriod
+ }
+ }
+ });
+ } catch (error) {
+ console.error('Error tracking wind calculator usage:', error);
+ }
+ };
+
+ // Auto-populate electricity rate based on German ZIP code
+ useEffect(() => {
+ if (zipCode.length === 5) {
+ // German electricity rates by region (higher than solar calculator due to wind being less common)
+ const rates: { [key: string]: number } = {
+ '0': 0.34, // Eastern Germany
+ '1': 0.36, // Berlin/Brandenburg
+ '2': 0.35, // Northern Germany (better wind resources)
+ '3': 0.37, // Central Germany
+ '4': 0.35, // Western Germany
+ '5': 0.36, // NRW
+ '6': 0.37, // Hessen/Baden-Württemberg
+ '7': 0.35, // Baden-Württemberg
+ '8': 0.34, // Bavaria
+ '9': 0.33 // Bavaria
+ };
+
+ const firstDigit = zipCode[0];
+ const rate = rates[firstDigit] || 0.35;
+ setElectricityRate(rate.toFixed(2));
+ }
+ }, [zipCode]);
+
+ const createSavingsChart = () => {
+ if (!results) return null;
+
+ const bars = [
+ { label: 'Monat 1', value: results.monthlySavings },
+ { label: 'Jahr 1', value: results.yearlySavings },
+ { label: '5 Jahre', value: results.yearlySavings * 5 },
+ { label: '10 Jahre', value: results.yearlySavings * 10 },
+ { label: '20 Jahre', value: results.lifetimeSavings }
+ ];
+
+ const maxValue = results.lifetimeSavings;
+
+ return (
+
+ {bars.map((bar, index) => (
+
+ ))}
+
+ );
+ };
+
+ return (
+
+
+
+ {/* Header */}
+
+
+
+
+ Windenergie-Einsparungsrechner
+
+
+ Nutzen Sie die Kraft des Windes, um Ihre Energiekosten zu senken
+
+
+
+
+ {/* Calculator Section */}
+
+
+
+
+
+ Berechnen Sie Ihre Windenergie-Einsparungen
+
+
+
+
+
+
+
+
+ Durchschnittliche monatliche Stromrechnung
+
+
+
+ €
+ setMonthlyBill(e.target.value)}
+ placeholder="150"
+ className="pl-8 h-12 border-2 border-green-200 focus:border-emerald-500"
+ />
+
+
+
+
+
+ Grundstücksgröße (Hektar)
+
+
+ setPropertySize(e.target.value)}
+ placeholder="0.8"
+ step="0.1"
+ min="0"
+ className="h-12 border-2 border-green-200 focus:border-emerald-500"
+ />
+
+
+
+
+ Grundstücksart
+
+
+
+
+
+
+
+ Ländlich
+ Vorstädtisch
+ Städtisch
+ Landwirtschaftlich
+
+
+
+
+
+
+
+
+
+
+
+
+ Durchschnittliche Windgeschwindigkeit (km/h)
+
+
+
+
+
+
+
+ 13 km/h (Schwache Windzone)
+ 16 km/h (Mäßiger Wind)
+ 19 km/h (Gute Windressource)
+ 24 km/h (Ausgezeichneter Wind)
+ 29+ km/h (Hervorragender Wind)
+
+
+
+
+
+
+ Max. erlaubte Anlagenhöhe (m)
+
+
+
+
+
+
+
+ 12 m (Eingeschränkte Gebiete)
+ 18 m (Vorstädtisches Limit)
+ 24 m (Standard Wohngebiet)
+ 30 m (Ländliche Gebiete)
+ 36+ m (Keine Beschränkungen)
+
+
+
+
+
+
+ Strompreis (pro kWh)
+
+
+
+ €
+ setElectricityRate(e.target.value)}
+ step="0.01"
+ placeholder="0.35"
+ className="pl-8 h-12 border-2 border-green-200 focus:border-emerald-500"
+ />
+
+
+
+
+
+ Postleitzahl
+
+
+ setZipCode(e.target.value)}
+ placeholder="12345"
+ pattern="[0-9]{5}"
+ className="h-12 border-2 border-green-200 focus:border-emerald-500"
+ />
+
+
+
+
+
+
+
+ Meine Windenergie-Einsparungen berechnen
+
+
+
+ {/* Results Section */}
+
+
+
+ Ihre Windenergie-Einsparungen
+
+
+
+ {showResults && results ? (
+
+
+
+
+ €{results.monthlySavings}
+ Monatliche Einsparungen
+
+
+
+
+
+
+ €{results.yearlySavings.toLocaleString()}
+ Jährliche Einsparungen
+
+
+
+
+
+
+ €{results.lifetimeSavings.toLocaleString()}
+ 20-Jahre Einsparungen
+
+
+
+
+
+ Windenergie-System Aufschlüsselung
+
+
+
+
+ Anlagengröße:
+ {results.turbineSize} kW
+
+
+ Installationskosten:
+ €{results.installCost.toLocaleString()}
+
+
+ Förderung/Zuschüsse (25%):
+ -€{results.taxCredit.toLocaleString()}
+
+
+ Nettokosten nach Förderung:
+ €{results.netCost.toLocaleString()}
+
+
+ Amortisationsdauer:
+ {results.paybackPeriod} Jahre
+
+
+
+
+
+
+
+
+ Windenergie-Einsparungen über die Zeit
+
+ {createSavingsChart()}
+
+
+
+ ) : (
+
+
+
Bereit zur Berechnung
+
Füllen Sie das Formular aus und klicken Sie auf "Berechnen"
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default WindCalculator;
\ No newline at end of file
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index d41793a..3162778 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -21,12 +21,8 @@ const buttonVariants = cva(
// Energy-specific variants
solar: "bg-gradient-solar text-white hover:shadow-solar transform hover:scale-105",
wind: "bg-gradient-wind text-white hover:shadow-wind transform hover:scale-105",
- geo: "bg-gradient-geo text-white hover:shadow-geo transform hover:scale-105",
- battery: "bg-gradient-battery text-white hover:shadow-battery transform hover:scale-105",
"solar-outline": "border-2 border-solar bg-transparent text-solar hover:bg-solar hover:text-white",
"wind-outline": "border-2 border-wind bg-transparent text-wind hover:bg-wind hover:text-white",
- "geo-outline": "border-2 border-geo bg-transparent text-geo hover:bg-geo hover:text-white",
- "battery-outline": "border-2 border-battery bg-transparent text-battery hover:bg-battery hover:text-white",
hero: "bg-gradient-hero text-white hover:shadow-lg transform hover:scale-105 border border-white/20",
},
size: {
diff --git a/src/index.css b/src/index.css
index 6510a5c..0133649 100644
--- a/src/index.css
+++ b/src/index.css
@@ -26,18 +26,6 @@
--wind-light: 207 100% 85%;
--wind-dark: 207 80% 41%;
- /* Energy Type Colors - Geothermal Green */
- --geo-primary: 122 39% 49%;
- --geo-secondary: 122 40% 56%;
- --geo-light: 122 45% 80%;
- --geo-dark: 122 35% 36%;
-
- /* Energy Type Colors - Battery Purple */
- --battery-primary: 291 64% 42%;
- --battery-secondary: 291 64% 49%;
- --battery-light: 291 70% 80%;
- --battery-dark: 291 60% 29%;
-
/* Brand Colors */
--primary: 218 47% 18%;
--primary-foreground: 210 40% 98%;
@@ -58,8 +46,6 @@
/* Energy Gradients */
--gradient-solar: linear-gradient(135deg, hsl(var(--solar-primary)) 0%, hsl(var(--solar-secondary)) 100%);
--gradient-wind: linear-gradient(135deg, hsl(var(--wind-primary)) 0%, hsl(var(--wind-secondary)) 100%);
- --gradient-geo: linear-gradient(135deg, hsl(var(--geo-primary)) 0%, hsl(var(--geo-secondary)) 100%);
- --gradient-battery: linear-gradient(135deg, hsl(var(--battery-primary)) 0%, hsl(var(--battery-secondary)) 100%);
--gradient-hero: linear-gradient(135deg, hsl(var(--primary)) 0%, hsl(218 47% 25%) 100%);
/* Shadows */
@@ -68,8 +54,6 @@
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-solar: 0 8px 32px hsl(var(--solar-primary) / 0.25);
--shadow-wind: 0 8px 32px hsl(var(--wind-primary) / 0.25);
- --shadow-geo: 0 8px 32px hsl(var(--geo-primary) / 0.25);
- --shadow-battery: 0 8px 32px hsl(var(--battery-primary) / 0.25);
/* Animations */
--transition-smooth: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
@@ -189,17 +173,28 @@
background-clip: text;
}
- .gradient-text-geo {
- background: var(--gradient-geo);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
+ /* Solar Calculator Animations */
+ @keyframes float {
+ 0% { transform: translate(0, 0); }
+ 100% { transform: translate(-60px, -60px); }
}
- .gradient-text-battery {
- background: var(--gradient-battery);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
+ @keyframes growUp {
+ from { height: 0; }
+ }
+
+ @keyframes fade-in {
+ from { opacity: 0; transform: translateY(20px); }
+ to { opacity: 1; transform: translateY(0); }
+ }
+
+ .animate-in {
+ animation: fade-in 0.5s ease-out;
+ }
+
+ /* Wind Calculator Animations */
+ @keyframes windFlow {
+ 0% { transform: translate(0, 0) rotate(0deg); }
+ 100% { transform: translate(-60px, -60px) rotate(360deg); }
}
}
\ No newline at end of file
diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts
index 76d3031..9e82c3c 100644
--- a/src/integrations/supabase/types.ts
+++ b/src/integrations/supabase/types.ts
@@ -398,7 +398,7 @@ export type Database = {
}
}
Enums: {
- energy_type: "solar" | "wind" | "geothermal" | "battery"
+ energy_type: "solar" | "wind"
installer_status: "active" | "inactive" | "pending" | "suspended"
quote_status: "pending" | "accepted" | "rejected" | "expired"
}
@@ -528,7 +528,7 @@ export type CompositeTypes<
export const Constants = {
public: {
Enums: {
- energy_type: ["solar", "wind", "geothermal", "battery"],
+ energy_type: ["solar", "wind"],
installer_status: ["active", "inactive", "pending", "suspended"],
quote_status: ["pending", "accepted", "rejected", "expired"],
},
diff --git a/src/lib/cleanDatabase.ts b/src/lib/cleanDatabase.ts
new file mode 100644
index 0000000..f45b44f
--- /dev/null
+++ b/src/lib/cleanDatabase.ts
@@ -0,0 +1,180 @@
+import { supabase } from "@/integrations/supabase/client";
+
+export const cleanAndReseedDatabase = async () => {
+ console.log('Cleaning existing installer data...');
+
+ try {
+ // First, delete all existing installers
+ const { error: deleteError } = await supabase
+ .from('installers')
+ .delete()
+ .not('id', 'is', null); // Delete all records
+
+ if (deleteError) {
+ console.error('Error deleting existing data:', deleteError);
+ throw deleteError;
+ }
+
+ console.log('Existing data cleaned successfully!');
+
+ // Now insert our proper German installer data
+ const germanInstallers = [
+ {
+ name: "SolarTech Pro München",
+ company_name: "SolarTech Pro GmbH",
+ email: "info@solartech-pro.de",
+ phone: "+49 89 123 4567",
+ website: "www.solartech-pro.de",
+ address: "Maximilianstrasse 15, 80539 München",
+ location: "München, Bayern",
+ energy_type: "solar",
+ description: "Spezialisiert auf hochwertige Photovoltaik-Anlagen für Privathaushalte und Gewerbe. Mit über 15 Jahren Erfahrung sind wir Ihr vertrauensvoller Partner für nachhaltige Energielösungen.",
+ specialties: ["Photovoltaik", "Solarthermie", "Energiespeicher", "Smart Home Integration"],
+ certifications: ["IHK Zertifiziert", "VDE Prüfung", "TÜV Süd"],
+ experience_years: 15,
+ rating: 4.8,
+ review_count: 127,
+ verified: true,
+ status: "active",
+ service_areas: ["München", "Augsburg", "Ingolstadt", "Landshut"],
+ languages: ["Deutsch", "Englisch"],
+ latitude: 48.1351,
+ longitude: 11.5820
+ },
+ {
+ name: "WindEnergie Solutions Hamburg",
+ company_name: "WindEnergie Solutions GmbH",
+ email: "kontakt@windenergie-solutions.de",
+ phone: "+49 40 987 6543",
+ website: "www.windenergie-solutions.de",
+ address: "Hafenstraße 42, 20359 Hamburg",
+ location: "Hamburg, Hamburg",
+ energy_type: "wind",
+ description: "Experten für Windkraftanlagen und erneuerbare Energielösungen. Wir planen und installieren Windenergieanlagen für private und gewerbliche Kunden.",
+ specialties: ["Windkraft", "Kleinwindanlagen", "Planung", "Wartung"],
+ certifications: ["BWE Mitglied", "VDMA Zertifikat", "ISO 9001"],
+ experience_years: 12,
+ rating: 4.6,
+ review_count: 89,
+ verified: true,
+ status: "active",
+ service_areas: ["Hamburg", "Bremen", "Schleswig-Holstein", "Niedersachsen"],
+ languages: ["Deutsch", "Englisch", "Dänisch"],
+ latitude: 53.5511,
+ longitude: 9.9937
+ },
+ {
+ name: "Grüne Energie Partner Berlin",
+ company_name: "Grüne Energie Partner GmbH",
+ email: "info@gruene-energie-partner.de",
+ phone: "+49 30 555 1234",
+ website: "www.gruene-energie-partner.de",
+ address: "Unter den Linden 77, 10117 Berlin",
+ location: "Berlin, Berlin",
+ energy_type: "solar",
+ description: "Vollständige Lösungen für erneuerbare Energien mit Fokus auf Nachhaltigkeit. Wir bieten sowohl Solar- als auch Windenergie-Lösungen aus einer Hand.",
+ specialties: ["Solar", "Wind", "Energieberatung", "Förderung", "Hybrid-Systeme"],
+ certifications: ["DGS Zertifikat", "Handwerkskammer Berlin", "KfW Effizienzexperte"],
+ experience_years: 18,
+ rating: 4.9,
+ review_count: 203,
+ verified: true,
+ status: "active",
+ service_areas: ["Berlin", "Brandenburg", "Potsdam"],
+ languages: ["Deutsch", "Englisch", "Polnisch"],
+ latitude: 52.5200,
+ longitude: 13.4050
+ },
+ {
+ name: "EcoSolar Systems Stuttgart",
+ company_name: "EcoSolar Systems GmbH",
+ email: "service@ecosolar-systems.de",
+ phone: "+49 711 789 0123",
+ website: "www.ecosolar-systems.de",
+ address: "Königstraße 28, 70173 Stuttgart",
+ location: "Stuttgart, Baden-Württemberg",
+ energy_type: "solar",
+ description: "Innovative Solaranlagen mit modernster Technologie für maximale Effizienz. Spezialisiert auf High-End Photovoltaik-Systeme mit intelligenter Steuerung.",
+ specialties: ["Hochleistungs-Solar", "Smart Home Integration", "Wartung", "Monitoring"],
+ certifications: ["Solarfachbetrieb", "E-Handwerk Innungsbetrieb", "BSW Solar"],
+ experience_years: 14,
+ rating: 4.7,
+ review_count: 156,
+ verified: true,
+ status: "active",
+ service_areas: ["Stuttgart", "Karlsruhe", "Heilbronn", "Tübingen"],
+ languages: ["Deutsch", "Englisch"],
+ latitude: 48.7758,
+ longitude: 9.1829
+ },
+ {
+ name: "NordWind Energie Bremen",
+ company_name: "NordWind Energie GmbH",
+ email: "info@nordwind-energie.de",
+ phone: "+49 421 456 7890",
+ website: "www.nordwind-energie.de",
+ address: "Weserstraße 50, 28199 Bremen",
+ location: "Bremen, Bremen",
+ energy_type: "wind",
+ description: "Spezialisten für Windenergie-Projekte in Norddeutschland. Von der Planung bis zur Wartung - wir begleiten Ihr Windenergie-Projekt vom ersten Tag an.",
+ specialties: ["Windparks", "Offshore", "Wartung", "Repowering"],
+ certifications: ["BWE Vollmitglied", "GWO Zertifikat", "VDMA Wind Power"],
+ experience_years: 16,
+ rating: 4.5,
+ review_count: 67,
+ verified: true,
+ status: "active",
+ service_areas: ["Bremen", "Bremerhaven", "Oldenburg", "Cuxhaven"],
+ languages: ["Deutsch", "Englisch", "Niederländisch"],
+ latitude: 53.0793,
+ longitude: 8.8017
+ },
+ {
+ name: "Bayerische Solar Solutions",
+ company_name: "Bayerische Solar Solutions GmbH",
+ email: "kontakt@bayerische-solar.de",
+ phone: "+49 89 321 6547",
+ website: "www.bayerische-solar.de",
+ address: "Marienplatz 8, 80331 München",
+ location: "München, Bayern",
+ energy_type: "solar",
+ description: "Traditioneller Handwerksbetrieb mit moderner Solartechnik. Seit 20 Jahren verlässlicher Partner für Photovoltaik-Anlagen in ganz Bayern.",
+ specialties: ["Dachintegration", "Fassadenmontage", "Carports", "Gewerbeanlagen"],
+ certifications: ["Handwerkskammer München", "BSW Solar", "TÜV Bayern"],
+ experience_years: 20,
+ rating: 4.6,
+ review_count: 189,
+ verified: true,
+ status: "active",
+ service_areas: ["München", "Rosenheim", "Freising", "Garmisch-Partenkirchen"],
+ languages: ["Deutsch", "Bayerisch"],
+ latitude: 48.1372,
+ longitude: 11.5755
+ }
+ ];
+
+ // Insert the proper German installer data
+ const { data, error: insertError } = await supabase
+ .from('installers')
+ .insert(germanInstallers)
+ .select();
+
+ if (insertError) {
+ console.error('Error inserting German installer data:', insertError);
+ console.error('Insert error details:', {
+ message: insertError.message,
+ details: insertError.details,
+ code: insertError.code,
+ hint: insertError.hint
+ });
+ throw insertError;
+ }
+
+ console.log('German installer data inserted successfully:', data?.length, 'installers added');
+ return data;
+
+ } catch (error) {
+ console.error('Error in cleanAndReseedDatabase:', error);
+ throw error;
+ }
+};
\ No newline at end of file
diff --git a/src/lib/database.ts b/src/lib/database.ts
new file mode 100644
index 0000000..7c80e2f
--- /dev/null
+++ b/src/lib/database.ts
@@ -0,0 +1,208 @@
+import React from "react";
+import { supabase } from "@/integrations/supabase/client";
+import type { Database } from "@/integrations/supabase/types";
+
+type Installer = Database['public']['Tables']['installers']['Row'];
+type InstallerInsert = Database['public']['Tables']['installers']['Insert'];
+type Quote = Database['public']['Tables']['quotes']['Row'];
+type QuoteInsert = Database['public']['Tables']['quotes']['Insert'];
+type ContactClick = Database['public']['Tables']['contact_clicks']['Insert'];
+type AnalyticsEvent = Database['public']['Tables']['analytics_events']['Insert'];
+
+// Installer Services
+export const installerService = {
+ // Get all installers with optional filters
+ async getInstallers(filters?: {
+ energyType?: string;
+ location?: string;
+ searchTerm?: string;
+ }) {
+ let query = supabase
+ .from('installers')
+ .select('*')
+ .eq('status', 'active')
+ .order('rating', { ascending: false });
+
+ if (filters?.energyType && filters.energyType !== 'all') {
+ query = query.contains('energy_type', [filters.energyType]);
+ }
+
+ if (filters?.location) {
+ query = query.ilike('location', `%${filters.location}%`);
+ }
+
+ if (filters?.searchTerm) {
+ query = query.or(`name.ilike.%${filters.searchTerm}%,description.ilike.%${filters.searchTerm}%,specialties.cs.{${filters.searchTerm}}`);
+ }
+
+ const { data, error } = await query;
+
+ if (error) {
+ console.error('Error fetching installers:', error);
+ console.error('Error details:', {
+ message: error.message,
+ details: error.details,
+ code: error.code,
+ hint: error.hint
+ });
+ throw error;
+ }
+
+ return data;
+ },
+
+ // Get installer by ID
+ async getInstaller(id: string) {
+ const { data, error } = await supabase
+ .from('installers')
+ .select('*')
+ .eq('id', id)
+ .single();
+
+ if (error) {
+ console.error('Error fetching installer:', error);
+ throw error;
+ }
+
+ return data;
+ },
+
+ // Add new installer
+ async createInstaller(installer: InstallerInsert) {
+ const { data, error } = await supabase
+ .from('installers')
+ .insert(installer)
+ .select()
+ .single();
+
+ if (error) {
+ console.error('Error creating installer:', error);
+ throw error;
+ }
+
+ return data;
+ }
+};
+
+// Quote Services
+export const quoteService = {
+ // Submit new quote request
+ async submitQuote(quote: QuoteInsert) {
+ const { data, error } = await supabase
+ .from('quotes')
+ .insert(quote)
+ .select()
+ .single();
+
+ if (error) {
+ console.error('Error submitting quote:', error);
+ throw error;
+ }
+
+ return data;
+ },
+
+ // Get quotes for an installer
+ async getInstallerQuotes(installerId: string) {
+ const { data, error } = await supabase
+ .from('quotes')
+ .select('*')
+ .eq('assigned_installer_id', installerId)
+ .order('created_at', { ascending: false });
+
+ if (error) {
+ console.error('Error fetching installer quotes:', error);
+ throw error;
+ }
+
+ return data;
+ }
+};
+
+// Analytics Services
+export const analyticsService = {
+ // Track contact click
+ async trackContactClick(contactClick: ContactClick) {
+ const { data, error } = await supabase
+ .from('contact_clicks')
+ .insert(contactClick);
+
+ if (error) {
+ console.error('Error tracking contact click:', error);
+ // Don't throw error for analytics - just log it
+ }
+
+ return data;
+ },
+
+ // Track general analytics event
+ async trackEvent(event: AnalyticsEvent) {
+ const { data, error } = await supabase
+ .from('analytics_events')
+ .insert(event);
+
+ if (error) {
+ console.error('Error tracking analytics event:', error);
+ // Don't throw error for analytics - just log it
+ }
+
+ return data;
+ }
+};
+
+// Utility functions
+export const dbUtils = {
+ // Get user's IP address (simplified)
+ async getUserIP(): Promise {
+ try {
+ const response = await fetch('https://api.ipify.org?format=json');
+ const data = await response.json();
+ return data.ip;
+ } catch {
+ return 'unknown';
+ }
+ },
+
+ // Get user agent
+ getUserAgent(): string {
+ return navigator.userAgent;
+ },
+
+ // Generate session ID
+ generateSessionId(): string {
+ return 'session_' + Math.random().toString(36).substr(2, 9) + '_' + Date.now();
+ }
+};
+
+// Hook for getting installers with loading state
+export const useInstallers = () => {
+ const [installers, setInstallers] = React.useState([]);
+ const [loading, setLoading] = React.useState(true);
+ const [error, setError] = React.useState(null);
+
+ const fetchInstallers = async (filters?: {
+ energyType?: string;
+ location?: string;
+ searchTerm?: string;
+ }) => {
+ try {
+ setLoading(true);
+ setError(null);
+ const data = await installerService.getInstallers(filters);
+ setInstallers(data || []);
+ } catch (err) {
+ setError(err instanceof Error ? err.message : 'An error occurred');
+ setInstallers([]);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return {
+ installers,
+ loading,
+ error,
+ fetchInstallers,
+ refetch: fetchInstallers
+ };
+};
\ No newline at end of file
diff --git a/src/lib/debugDatabase.ts b/src/lib/debugDatabase.ts
new file mode 100644
index 0000000..fc03f13
--- /dev/null
+++ b/src/lib/debugDatabase.ts
@@ -0,0 +1,102 @@
+import { supabase } from "@/integrations/supabase/client";
+
+export const testConnection = async () => {
+ console.log('=== TESTING SUPABASE CONNECTION ===');
+
+ try {
+ // Test basic connection
+ const { data, error } = await supabase
+ .from('installers')
+ .select('count', { count: 'exact', head: true });
+
+ if (error) {
+ console.error('Connection test failed:', error);
+ console.error('Error details:', {
+ message: error.message,
+ details: error.details,
+ code: error.code,
+ hint: error.hint
+ });
+ return false;
+ }
+
+ console.log('✅ Connection successful! Table has', data?.length || 0, 'records');
+ return true;
+ } catch (error) {
+ console.error('Connection test exception:', error);
+ return false;
+ }
+};
+
+export const debugDatabase = async () => {
+ console.log('=== DATABASE DEBUG ===');
+
+ try {
+ // Get all installers
+ const { data, error } = await supabase
+ .from('installers')
+ .select('*')
+ .order('created_at', { ascending: false });
+
+ if (error) {
+ console.error('Error fetching installers:', error);
+ return;
+ }
+
+ console.log(`Found ${data?.length || 0} installers in database:`);
+
+ data?.forEach((installer, index) => {
+ console.log(`\n${index + 1}. ${installer.name}`);
+ console.log(` Company: ${installer.company_name}`);
+ console.log(` Location: ${installer.location}`);
+ console.log(` Energy Type: ${installer.energy_type}`);
+ console.log(` Created: ${installer.created_at}`);
+ console.log(` ID: ${installer.id}`);
+ });
+
+ return data;
+ } catch (error) {
+ console.error('Debug error:', error);
+ }
+};
+
+export const forceDeleteAll = async () => {
+ console.log('=== FORCE DELETE ALL INSTALLERS ===');
+
+ try {
+ // First, let's see what's there
+ const { data: allData } = await supabase
+ .from('installers')
+ .select('*');
+
+ console.log('Records before deletion:', allData?.length || 0);
+ allData?.forEach((record, index) => {
+ console.log(`${index + 1}. ${record.name} (ID: ${record.id})`);
+ });
+
+ // Delete ALL records without any conditions
+ const { data, error } = await supabase
+ .from('installers')
+ .delete()
+ .not('id', 'is', null); // This will delete all records
+
+ if (error) {
+ console.error('Error in force delete:', error);
+ throw error;
+ }
+
+ console.log('All installers deleted successfully');
+
+ // Verify deletion
+ const { data: remainingData } = await supabase
+ .from('installers')
+ .select('*');
+
+ console.log('Records after deletion:', remainingData?.length || 0);
+
+ return data;
+ } catch (error) {
+ console.error('Force delete error:', error);
+ throw error;
+ }
+};
\ No newline at end of file
diff --git a/src/lib/seedData.ts b/src/lib/seedData.ts
new file mode 100644
index 0000000..bcebe8a
--- /dev/null
+++ b/src/lib/seedData.ts
@@ -0,0 +1,155 @@
+import { installerService } from "./database";
+import type { Database } from "@/integrations/supabase/types";
+
+type InstallerInsert = Database['public']['Tables']['installers']['Insert'];
+
+const sampleInstallers: InstallerInsert[] = [
+ {
+ name: "SolarTech Pro München",
+ company_name: "SolarTech Pro GmbH",
+ email: "info@solartech-pro.de",
+ phone: "+49 89 123 4567",
+ website: "www.solartech-pro.de",
+ address: "Maximilianstrasse 15, 80539 München",
+ location: "München, Bayern",
+ energy_type: "solar",
+ description: "Spezialisiert auf hochwertige Photovoltaik-Anlagen für Privathaushalte und Gewerbe. Mit über 15 Jahren Erfahrung sind wir Ihr vertrauensvoller Partner für nachhaltige Energielösungen.",
+ specialties: ["Photovoltaik", "Solarthermie", "Energiespeicher", "Smart Home Integration"],
+ certifications: ["IHK Zertifiziert", "VDE Prüfung", "TÜV Süd"],
+ experience_years: 15,
+ rating: 4.8,
+ review_count: 127,
+ verified: true,
+ status: "active",
+ service_areas: ["München", "Augsburg", "Ingolstadt", "Landshut"],
+ languages: ["Deutsch", "Englisch"],
+ latitude: 48.1351,
+ longitude: 11.5820
+ },
+ {
+ name: "WindEnergie Solutions Hamburg",
+ company_name: "WindEnergie Solutions GmbH",
+ email: "kontakt@windenergie-solutions.de",
+ phone: "+49 40 987 6543",
+ website: "www.windenergie-solutions.de",
+ address: "Hafenstraße 42, 20359 Hamburg",
+ location: "Hamburg, Hamburg",
+ energy_type: "wind",
+ description: "Experten für Windkraftanlagen und erneuerbare Energielösungen. Wir planen und installieren Windenergieanlagen für private und gewerbliche Kunden.",
+ specialties: ["Windkraft", "Kleinwindanlagen", "Planung", "Wartung"],
+ certifications: ["BWE Mitglied", "VDMA Zertifikat", "ISO 9001"],
+ experience_years: 12,
+ rating: 4.6,
+ review_count: 89,
+ verified: true,
+ status: "active",
+ service_areas: ["Hamburg", "Bremen", "Schleswig-Holstein", "Niedersachsen"],
+ languages: ["Deutsch", "Englisch", "Dänisch"],
+ latitude: 53.5511,
+ longitude: 9.9937
+ },
+ {
+ name: "Grüne Energie Partner Berlin",
+ company_name: "Grüne Energie Partner GmbH",
+ email: "info@gruene-energie-partner.de",
+ phone: "+49 30 555 1234",
+ website: "www.gruene-energie-partner.de",
+ address: "Unter den Linden 77, 10117 Berlin",
+ location: "Berlin, Berlin",
+ energy_type: "solar",
+ description: "Vollständige Lösungen für erneuerbare Energien mit Fokus auf Nachhaltigkeit. Wir bieten sowohl Solar- als auch Windenergie-Lösungen aus einer Hand.",
+ specialties: ["Solar", "Wind", "Energieberatung", "Förderung", "Hybrid-Systeme"],
+ certifications: ["DGS Zertifikat", "Handwerkskammer Berlin", "KfW Effizienzexperte"],
+ experience_years: 18,
+ rating: 4.9,
+ review_count: 203,
+ verified: true,
+ status: "active",
+ service_areas: ["Berlin", "Brandenburg", "Potsdam"],
+ languages: ["Deutsch", "Englisch", "Polnisch"],
+ latitude: 52.5200,
+ longitude: 13.4050
+ },
+ {
+ name: "EcoSolar Systems Stuttgart",
+ company_name: "EcoSolar Systems GmbH",
+ email: "service@ecosolar-systems.de",
+ phone: "+49 711 789 0123",
+ website: "www.ecosolar-systems.de",
+ address: "Königstraße 28, 70173 Stuttgart",
+ location: "Stuttgart, Baden-Württemberg",
+ energy_type: "solar",
+ description: "Innovative Solaranlagen mit modernster Technologie für maximale Effizienz. Spezialisiert auf High-End Photovoltaik-Systeme mit intelligenter Steuerung.",
+ specialties: ["Hochleistungs-Solar", "Smart Home Integration", "Wartung", "Monitoring"],
+ certifications: ["Solarfachbetrieb", "E-Handwerk Innungsbetrieb", "BSW Solar"],
+ experience_years: 14,
+ rating: 4.7,
+ review_count: 156,
+ verified: true,
+ status: "active",
+ service_areas: ["Stuttgart", "Karlsruhe", "Heilbronn", "Tübingen"],
+ languages: ["Deutsch", "Englisch"],
+ latitude: 48.7758,
+ longitude: 9.1829
+ },
+ {
+ name: "NordWind Energie Bremen",
+ company_name: "NordWind Energie GmbH",
+ email: "info@nordwind-energie.de",
+ phone: "+49 421 456 7890",
+ website: "www.nordwind-energie.de",
+ address: "Weserstraße 50, 28199 Bremen",
+ location: "Bremen, Bremen",
+ energy_type: "wind",
+ description: "Spezialisten für Windenergie-Projekte in Norddeutschland. Von der Planung bis zur Wartung - wir begleiten Ihr Windenergie-Projekt vom ersten Tag an.",
+ specialties: ["Windparks", "Offshore", "Wartung", "Repowering"],
+ certifications: ["BWE Vollmitglied", "GWO Zertifikat", "VDMA Wind Power"],
+ experience_years: 16,
+ rating: 4.5,
+ review_count: 67,
+ verified: true,
+ status: "active",
+ service_areas: ["Bremen", "Bremerhaven", "Oldenburg", "Cuxhaven"],
+ languages: ["Deutsch", "Englisch", "Niederländisch"],
+ latitude: 53.0793,
+ longitude: 8.8017
+ },
+ {
+ name: "Bayerische Solar Solutions",
+ company_name: "Bayerische Solar Solutions GmbH",
+ email: "kontakt@bayerische-solar.de",
+ phone: "+49 89 321 6547",
+ website: "www.bayerische-solar.de",
+ address: "Marienplatz 8, 80331 München",
+ location: "München, Bayern",
+ energy_type: "solar",
+ description: "Traditioneller Handwerksbetrieb mit moderner Solartechnik. Seit 20 Jahren verlässlicher Partner für Photovoltaik-Anlagen in ganz Bayern.",
+ specialties: ["Dachintegration", "Fassadenmontage", "Carports", "Gewerbeanlagen"],
+ certifications: ["Handwerkskammer München", "BSW Solar", "TÜV Bayern"],
+ experience_years: 20,
+ rating: 4.6,
+ review_count: 189,
+ verified: true,
+ status: "active",
+ service_areas: ["München", "Rosenheim", "Freising", "Garmisch-Partenkirchen"],
+ languages: ["Deutsch", "Bayerisch"],
+ latitude: 48.1372,
+ longitude: 11.5755
+ }
+];
+
+export const seedDatabase = async () => {
+ console.log('Starting to seed database with sample installer data...');
+
+ try {
+ for (const installer of sampleInstallers) {
+ await installerService.createInstaller(installer);
+ console.log(`Added installer: ${installer.name}`);
+ }
+ console.log('Database seeding completed successfully!');
+ } catch (error) {
+ console.error('Error seeding database:', error);
+ }
+};
+
+export { sampleInstallers };
\ No newline at end of file
diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx
index 3dddef8..6c5d513 100644
--- a/src/pages/Index.tsx
+++ b/src/pages/Index.tsx
@@ -1,6 +1,7 @@
import Header from "@/components/Header";
import HeroSection from "@/components/HeroSection";
import EnergyTypesSection from "@/components/EnergyTypesSection";
+import CalculatorNavigation from "@/components/CalculatorNavigation";
import WhyChooseUsSection from "@/components/WhyChooseUsSection";
import Footer from "@/components/Footer";
@@ -11,6 +12,7 @@ const Index = () => {
+
diff --git a/src/pages/InstallateurFinden.tsx b/src/pages/InstallateurFinden.tsx
new file mode 100644
index 0000000..d39f6b7
--- /dev/null
+++ b/src/pages/InstallateurFinden.tsx
@@ -0,0 +1,382 @@
+import { useState, useEffect } from "react";
+import { useSearchParams } from "react-router-dom";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+import { Badge } from "@/components/ui/badge";
+import { Search, MapPin, Star, Phone, Mail, Globe, Filter, AlertCircle } from "lucide-react";
+import Header from "@/components/Header";
+import { installerService, analyticsService } from "@/lib/database";
+import { cleanAndReseedDatabase } from "@/lib/cleanDatabase";
+import { debugDatabase, forceDeleteAll, testConnection } from "@/lib/debugDatabase";
+import type { Database } from "@/integrations/supabase/types";
+
+type Installer = Database['public']['Tables']['installers']['Row'];
+
+const InstallateurFinden = () => {
+ const [searchParams, setSearchParams] = useSearchParams();
+ const [installers, setInstallers] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ const [searchTerm, setSearchTerm] = useState(searchParams.get("search") || "");
+ const [energyType, setEnergyType] = useState(searchParams.get("type") || "all");
+ const [location, setLocation] = useState(searchParams.get("location") || "");
+
+ // Load installers from database
+ const loadInstallers = async () => {
+ try {
+ setLoading(true);
+ setError(null);
+
+ const filters = {
+ energyType: energyType && energyType !== "all" ? energyType : undefined,
+ location: location || undefined,
+ searchTerm: searchTerm || undefined
+ };
+
+ const data = await installerService.getInstallers(filters);
+ setInstallers(data || []);
+
+ // Track search event
+ if (searchTerm || energyType !== "all" || location) {
+ analyticsService.trackEvent({
+ event_type: 'installer_search',
+ page_url: window.location.pathname,
+ event_data: filters,
+ user_agent: navigator.userAgent,
+ session_id: sessionStorage.getItem('session_id') || 'anonymous'
+ });
+ }
+ } catch (err) {
+ console.error('Error loading installers:', err);
+ setError('Fehler beim Laden der Installateure. Bitte versuchen Sie es später erneut.');
+ setInstallers([]);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Initial load
+ useEffect(() => {
+ loadInstallers();
+ }, []);
+
+ // Reload when filters change
+ useEffect(() => {
+ const timeoutId = setTimeout(() => {
+ loadInstallers();
+ }, 500); // Debounce search
+
+ return () => clearTimeout(timeoutId);
+ }, [searchTerm, energyType, location]);
+
+ // Update URL params when filters change
+ useEffect(() => {
+ const params = new URLSearchParams();
+ if (searchTerm) params.set("search", searchTerm);
+ if (energyType && energyType !== "all") params.set("type", energyType);
+ if (location) params.set("location", location);
+ setSearchParams(params);
+ }, [searchTerm, energyType, location, setSearchParams]);
+
+ const handleReset = () => {
+ setSearchTerm("");
+ setEnergyType("all");
+ setLocation("");
+ };
+
+ // Test connection
+ const handleTestConnection = async () => {
+ await testConnection();
+ };
+
+ // Debug database
+ const handleDebugDatabase = async () => {
+ await debugDatabase();
+ };
+
+ // Force delete all and reseed
+ const handleForceReseed = async () => {
+ try {
+ await forceDeleteAll();
+ await cleanAndReseedDatabase();
+ alert('Database forcefully reseeded!');
+ loadInstallers();
+ } catch (error) {
+ console.error('Error in force reseed:', error);
+ alert('Error in force reseed. Check console.');
+ }
+ };
+
+ // Clean and reseed with proper German data
+ const handleSeedDatabase = async () => {
+ try {
+ await cleanAndReseedDatabase();
+ alert('Deutsche Installateure erfolgreich geladen!');
+ loadInstallers(); // Reload the data
+ } catch (error) {
+ console.error('Error seeding database:', error);
+ alert('Fehler beim Laden der Installateure. Details in der Konsole.');
+ }
+ };
+
+ // Track contact clicks
+ const handleContactClick = async (installerId: string, contactType: string) => {
+ try {
+ await analyticsService.trackContactClick({
+ installer_id: installerId,
+ contact_type: contactType,
+ page_url: window.location.pathname,
+ user_agent: navigator.userAgent,
+ ip_address: await getClientIP()
+ });
+ } catch (error) {
+ console.error('Error tracking contact click:', error);
+ }
+ };
+
+ // Simple IP detection (fallback)
+ const getClientIP = async (): Promise => {
+ try {
+ const response = await fetch('https://api.ipify.org?format=json');
+ const data = await response.json();
+ return data.ip;
+ } catch {
+ return 'unknown';
+ }
+ };
+
+ if (loading) {
+ return (
+
+
+
+
Installateure werden geladen...
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+
+
+
+
Fehler beim Laden
+
{error}
+
loadInstallers()} className="mb-4">
+ Erneut versuchen
+
+
+
+
+ );
+ }
+
+ return (
+
+ {/* Header Navigation */}
+
+
+ {/* Page Header */}
+
+
+
+ Installateure Finden
+
+
+ Entdecken Sie qualifizierte Fachbetriebe für erneuerbare Energien in Ihrer Region
+
+
+
+
+ {/* Search and Filters */}
+
+
+
+
+
+ Suche & Filter
+
+
+
+
+
+
+ setSearchTerm(e.target.value)}
+ className="pl-10"
+ />
+
+
+
+
+
+
+
+ Alle Energiearten
+ Solar
+ Wind
+
+
+
+
+
+ setLocation(e.target.value)}
+ className="pl-10"
+ />
+
+
+
+ Filter zurücksetzen
+
+
+
+
+
+
+ {/* Results */}
+
+
+ {installers.length} Installateur{installers.length !== 1 ? 'e' : ''} gefunden
+
+
+
+ {/* Installer Cards */}
+
+ {installers.map((installer) => (
+
+
+
+
+
{installer.name}
+
+
+ {installer.location}
+
+
+
+
+ {installer.rating}
+ ({installer.review_count || 0})
+
+
{installer.experience_years || 0} Jahre Erfahrung
+ {installer.verified && (
+
+ Verifiziert
+
+ )}
+
+
+
+
+ {installer.energy_type === 'solar' ? 'Solar' : 'Wind'}
+
+
+
+
+
+
+ {installer.description}
+
+
+
Spezialitäten:
+
+ {installer.specialties?.map((specialty, index) => (
+
+ {specialty}
+
+ )) || (
+ Keine Spezialitäten angegeben
+ )}
+
+
+
+ {installer.certifications && installer.certifications.length > 0 && (
+
+
Zertifizierungen:
+
+ {installer.certifications.map((cert, index) => (
+
+ {cert}
+
+ ))}
+
+
+ )}
+
+
+
{
+ handleContactClick(installer.id, 'phone');
+ window.location.href = `tel:${installer.phone}`;
+ }}
+ >
+
+ Anrufen
+
+
{
+ handleContactClick(installer.id, 'email');
+ window.location.href = `mailto:${installer.email}`;
+ }}
+ >
+
+ E-Mail
+
+ {installer.website && (
+
{
+ handleContactClick(installer.id, 'website');
+ window.open(`https://${installer.website}`, '_blank');
+ }}
+ >
+
+ Website
+
+ )}
+
+
+
+ ))}
+
+
+ {installers.length === 0 && (
+
+
+
+ Keine Installateure gefunden, die Ihren Kriterien entsprechen.
+
+
+ Alle Filter zurücksetzen
+
+
+
+ )}
+
+
+ );
+};
+
+export default InstallateurFinden;
diff --git a/src/pages/KostenloseBeratung.tsx b/src/pages/KostenloseBeratung.tsx
new file mode 100644
index 0000000..c03eb5e
--- /dev/null
+++ b/src/pages/KostenloseBeratung.tsx
@@ -0,0 +1,364 @@
+import { useState } from "react";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+import { Label } from "@/components/ui/label";
+import { Checkbox } from "@/components/ui/checkbox";
+import { Phone, Mail, MapPin, Calendar, Clock, CheckCircle } from "lucide-react";
+import Header from "@/components/Header";
+
+const KostenloseBeratung = () => {
+ const [formData, setFormData] = useState({
+ firstName: "",
+ lastName: "",
+ email: "",
+ phone: "",
+ zipCode: "",
+ city: "",
+ energyType: "",
+ projectType: "",
+ description: "",
+ budget: "",
+ timeline: "",
+ contactPreference: "email",
+ newsletter: false,
+ privacyPolicy: false
+ });
+
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [isSubmitted, setIsSubmitted] = useState(false);
+
+ const handleInputChange = (field: string, value: string | boolean) => {
+ setFormData(prev => ({
+ ...prev,
+ [field]: value
+ }));
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsSubmitting(true);
+
+ // Simulate API call
+ await new Promise(resolve => setTimeout(resolve, 2000));
+
+ setIsSubmitting(false);
+ setIsSubmitted(true);
+ };
+
+ if (isSubmitted) {
+ return (
+
+
+
+
+ Beratungsanfrage gesendet!
+
+ Vielen Dank für Ihr Interesse. Wir werden uns innerhalb von 24 Stunden bei Ihnen melden.
+
+ window.location.href = "/"} className="w-full">
+ Zurück zur Startseite
+
+
+
+
+ );
+ }
+
+ return (
+
+ {/* Header Navigation */}
+
+
+ {/* Page Header */}
+
+
+
+ Kostenlose Beratung
+
+
+ Lassen Sie sich von unseren Experten beraten und erhalten Sie ein maßgeschneidertes Angebot
+
+
+
+
+
+
+ {/* Form */}
+
+
+
+ Ihre Beratungsanfrage
+
+
+
+
+
+
+
+ {/* Sidebar */}
+
+ {/* Benefits */}
+
+
+ Ihre Vorteile
+
+
+
+
+
+
Kostenlose Beratung
+
Unverbindliche Erstberatung ohne Kosten
+
+
+
+
+
+
Expertenwissen
+
Beratung durch zertifizierte Fachleute
+
+
+
+
+
+
Maßgeschneiderte Lösungen
+
Individuelle Beratung für Ihr Projekt
+
+
+
+
+
+
Förderung & Finanzierung
+
Informationen zu staatlichen Förderungen
+
+
+
+
+
+ {/* Contact Info */}
+
+
+ Kontakt
+
+
+
+
+
+49 (0) 800 123 4567
+
+
+
+ beratung@energieprofis.de
+
+
+
+ München, Deutschland
+
+
+
+ Mo-Fr: 8:00 - 18:00
+
+
+
+
+
+
+
+ );
+};
+
+export default KostenloseBeratung;
diff --git a/src/pages/Solar.tsx b/src/pages/Solar.tsx
index fa28619..46d2587 100644
--- a/src/pages/Solar.tsx
+++ b/src/pages/Solar.tsx
@@ -1,5 +1,6 @@
import Header from "@/components/Header";
import Footer from "@/components/Footer";
+import SolarCalculator from "@/components/SolarCalculator";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Sun, Zap, TrendingUp, Shield, ArrowRight } from "lucide-react";
@@ -62,11 +63,6 @@ const Solar = () => {
Solar-Installateur Finden
-
-
- Kostenlose Beratung
-
-
@@ -106,6 +102,9 @@ const Solar = () => {
+ {/* Solar Calculator Section */}
+
+
{/* CTA Section */}
@@ -118,8 +117,8 @@ const Solar = () => {
-
- Jetzt kostenlose Beratung anfordern
+
+ Solar-Installateure finden
diff --git a/src/pages/UnternehmenListen.tsx b/src/pages/UnternehmenListen.tsx
new file mode 100644
index 0000000..370eddc
--- /dev/null
+++ b/src/pages/UnternehmenListen.tsx
@@ -0,0 +1,446 @@
+import { useState } from "react";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+import { Label } from "@/components/ui/label";
+import { Checkbox } from "@/components/ui/checkbox";
+import { Building2, MapPin, Phone, Mail, Globe, CheckCircle, Users, Award, Clock } from "lucide-react";
+import Header from "@/components/Header";
+
+const UnternehmenListen = () => {
+ const [formData, setFormData] = useState({
+ companyName: "",
+ contactPerson: "",
+ email: "",
+ phone: "",
+ website: "",
+ zipCode: "",
+ city: "",
+ energyTypes: [] as string[],
+ services: [] as string[],
+ description: "",
+ experience: "",
+ certifications: [] as string[],
+ coverageArea: "",
+ contactPreference: "email",
+ newsletter: false,
+ privacyPolicy: false
+ });
+
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [isSubmitted, setIsSubmitted] = useState(false);
+
+ const handleInputChange = (field: string, value: string | boolean | string[]) => {
+ setFormData(prev => ({
+ ...prev,
+ [field]: value
+ }));
+ };
+
+ const handleEnergyTypeChange = (type: string, checked: boolean) => {
+ if (checked) {
+ setFormData(prev => ({
+ ...prev,
+ energyTypes: [...prev.energyTypes, type]
+ }));
+ } else {
+ setFormData(prev => ({
+ ...prev,
+ energyTypes: prev.energyTypes.filter(t => t !== type)
+ }));
+ }
+ };
+
+ const handleServiceChange = (service: string, checked: boolean) => {
+ if (checked) {
+ setFormData(prev => ({
+ ...prev,
+ services: [...prev.services, service]
+ }));
+ } else {
+ setFormData(prev => ({
+ ...prev,
+ services: prev.services.filter(s => s !== service)
+ }));
+ }
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsSubmitting(true);
+
+ // Simulate API call
+ await new Promise(resolve => setTimeout(resolve, 2000));
+
+ setIsSubmitting(false);
+ setIsSubmitted(true);
+ };
+
+ if (isSubmitted) {
+ return (
+
+
+
+
+ Anmeldung erfolgreich!
+
+ Vielen Dank für Ihre Anmeldung. Wir werden Ihr Unternehmen innerhalb von 48 Stunden prüfen und freischalten.
+
+ window.location.href = "/"} className="w-full">
+ Zurück zur Startseite
+
+
+
+
+ );
+ }
+
+ return (
+
+ {/* Header Navigation */}
+
+
+ {/* Page Header */}
+
+
+
+ Unternehmen Listen
+
+
+ Werden Sie Teil unseres Netzwerks und erreichen Sie neue Kunden für erneuerbare Energien
+
+
+
+
+
+
+ {/* Form */}
+
+
+
+ Unternehmensanmeldung
+
+
+
+ {/* Company Information */}
+
+ Firmenname *
+ handleInputChange("companyName", e.target.value)}
+ required
+ />
+
+
+
+
+
+
+
+
+ {/* Energy Types */}
+
+
Energiearten *
+
+
+ handleEnergyTypeChange("solar", checked as boolean)}
+ />
+ Solar
+
+
+ handleEnergyTypeChange("wind", checked as boolean)}
+ />
+ Wind
+
+
+
+
+ {/* Services */}
+
+
Angebotene Leistungen *
+
+
+ handleServiceChange("planning", checked as boolean)}
+ />
+ Planung & Beratung
+
+
+ handleServiceChange("installation", checked as boolean)}
+ />
+ Installation
+
+
+ handleServiceChange("maintenance", checked as boolean)}
+ />
+ Wartung & Service
+
+
+ handleServiceChange("financing", checked as boolean)}
+ />
+ Finanzierung
+
+
+
+
+
+
+ Jahre Erfahrung *
+ handleInputChange("experience", value)}>
+
+
+
+
+ 0-2 Jahre
+ 3-5 Jahre
+ 6-10 Jahre
+ Über 10 Jahre
+
+
+
+
+ Einzugsgebiet
+ handleInputChange("coverageArea", e.target.value)}
+ placeholder="z.B. Bayern, 50km Umkreis"
+ />
+
+
+
+
+ Unternehmensbeschreibung *
+ handleInputChange("description", e.target.value)}
+ rows={4}
+ required
+ />
+
+
+
+
+
+
+ handleInputChange("newsletter", checked as boolean)}
+ />
+
+ Ich möchte über neue Funktionen und Marketing-Möglichkeiten informiert werden
+
+
+
+
handleInputChange("privacyPolicy", checked as boolean)}
+ required
+ />
+
+ Ich akzeptiere die Datenschutzerklärung *
+
+
+
+
+
+ {isSubmitting ? "Wird gesendet..." : "Unternehmen anmelden"}
+
+
+
+
+
+
+ {/* Sidebar */}
+
+ {/* Benefits */}
+
+
+ Ihre Vorteile
+
+
+
+
+
+
Neue Kunden gewinnen
+
Erreichen Sie potenzielle Kunden in Ihrer Region
+
+
+
+
+
+
Vertrauen aufbauen
+
Präsentieren Sie sich als verifizierter Experte
+
+
+
+
+
+
Zeit sparen
+
Kunden finden Sie automatisch über unsere Plattform
+
+
+
+
+
+
Professioneller Auftritt
+
Präsentieren Sie Ihr Unternehmen professionell
+
+
+
+
+
+ {/* Process */}
+
+
+ Ablauf
+
+
+
+
1
+
+
Anmeldung
+
Füllen Sie das Formular aus
+
+
+
+
2
+
+
Prüfung
+
Wir prüfen Ihre Angaben (48h)
+
+
+
+
3
+
+
Freischaltung
+
Ihr Profil wird veröffentlicht
+
+
+
+
4
+
+
Kundenkontakte
+
Erhalten Sie Anfragen von Kunden
+
+
+
+
+
+
+
+
+ );
+};
+
+export default UnternehmenListen;
diff --git a/src/pages/Wind.tsx b/src/pages/Wind.tsx
index 08ceaa4..67142b7 100644
--- a/src/pages/Wind.tsx
+++ b/src/pages/Wind.tsx
@@ -1,5 +1,6 @@
import Header from "@/components/Header";
import Footer from "@/components/Footer";
+import WindCalculator from "@/components/WindCalculator";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Wind, Zap, TrendingUp, Shield, ArrowRight } from "lucide-react";
@@ -62,11 +63,6 @@ const WindPage = () => {
Wind-Installateur Finden
-
-
- Kostenlose Beratung
-
-
@@ -106,6 +102,9 @@ const WindPage = () => {
+ {/* Wind Calculator Section */}
+
+
{/* CTA Section */}
@@ -118,8 +117,8 @@ const WindPage = () => {
-
- Jetzt kostenlose Beratung anfordern
+
+ Wind-Installateure finden
diff --git a/tailwind.config.ts b/tailwind.config.ts
index bbc045d..630083a 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -65,18 +65,6 @@ export default {
light: 'hsl(var(--wind-light))',
dark: 'hsl(var(--wind-dark))'
},
- geo: {
- DEFAULT: 'hsl(var(--geo-primary))',
- secondary: 'hsl(var(--geo-secondary))',
- light: 'hsl(var(--geo-light))',
- dark: 'hsl(var(--geo-dark))'
- },
- battery: {
- DEFAULT: 'hsl(var(--battery-primary))',
- secondary: 'hsl(var(--battery-secondary))',
- light: 'hsl(var(--battery-light))',
- dark: 'hsl(var(--battery-dark))'
- },
sidebar: {
DEFAULT: 'hsl(var(--sidebar-background))',
foreground: 'hsl(var(--sidebar-foreground))',
@@ -91,15 +79,11 @@ export default {
backgroundImage: {
'gradient-solar': 'var(--gradient-solar)',
'gradient-wind': 'var(--gradient-wind)',
- 'gradient-geo': 'var(--gradient-geo)',
- 'gradient-battery': 'var(--gradient-battery)',
'gradient-hero': 'var(--gradient-hero)'
},
boxShadow: {
'solar': 'var(--shadow-solar)',
- 'wind': 'var(--shadow-wind)',
- 'geo': 'var(--shadow-geo)',
- 'battery': 'var(--shadow-battery)'
+ 'wind': 'var(--shadow-wind)'
},
transitionTimingFunction: {
'smooth': 'cubic-bezier(0.4, 0, 0.2, 1)',