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 */} + +
+ +
+
+ +
+
+ Beliebt +
+
+ +

+ 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 +
+
+ + +
+
+ + {/* Wind Calculator Card */} + +
+ +
+
+ +
+
+ Neu +
+
+ +

+ 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 +
+
+ + +
+
+
+ + {/* Bottom CTA */} +
+

+ Unsicher, welche Lösung für Sie geeignet ist? +

+ +
+
+
+ ); +}; + +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 = () => { -
  • {/* 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 */}
    Renewable Energy Solutions in Germany -
    + {/* 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 */} +
    -
    - +
    +
    -
    - - - -
    -
    - {/* CTA Buttons */} + {/* Clean CTA buttons */}
    - -
    - {/* 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) => ( +
    +
    + + {bar.label} + +
    + ))} +
    + ); + }; + + return ( +
    +
    +
    + {/* Header */} +
    +
    +
    +
    +

    + Solar-Einsparungsrechner +

    +

    + Entdecken Sie, wie viel Sie mit Solarenergie sparen können +

    +
    + +
    + {/* Calculator Section */} +
    +
    +
    +
    +
    +
    +
    +
    + +

    + Berechnen Sie Ihre Solar-Einsparungen +
    +

    + + + +
    +
    + +
    + + setMonthlyBill(e.target.value)} + placeholder="150" + className="pl-8 h-12 border-2 border-gray-200 focus:border-blue-500" + /> +
    +
    + +
    + + setHomeSize(e.target.value)} + placeholder="200" + className="h-12 border-2 border-gray-200 focus:border-blue-500" + /> +
    + +
    + + +
    +
    +
    +
    + + + +
    +
    + + +
    + +
    + +
    + + setElectricityRate(e.target.value)} + step="0.01" + placeholder="0.33" + className="pl-8 h-12 border-2 border-gray-200 focus:border-blue-500" + /> +
    +
    + +
    + + setZipCode(e.target.value)} + placeholder="12345" + pattern="[0-9]{5}" + className="h-12 border-2 border-gray-200 focus:border-blue-500" + /> +
    +
    +
    +
    + + +
    + + {/* 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 */} +
    + +
    +
    + ) : ( +
    +
    Bereit zur Berechnung
    +
    Füllen Sie das Formular aus und klicken Sie auf "Berechnen"
    +
    + )} + + {/* Quote Form Modal */} + {showQuoteForm && ( +
    + + + Kostenloses Angebot anfordern + + +
    +
    + + setCustomerName(e.target.value)} + required + placeholder="Ihr vollständiger Name" + /> +
    + +
    + + setCustomerEmail(e.target.value)} + required + placeholder="ihre.email@beispiel.de" + /> +
    + +
    + + setCustomerPhone(e.target.value)} + placeholder="+49 123 456 7890" + /> +
    + +
    + + +
    +
    +
    +
    +
    + )} +
    +
    +
    +
    +
    + ); +}; + +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) => ( +
    +
    + + {bar.label} + +
    + ))} +
    + ); + }; + + return ( +
    +
    +
    + {/* Header */} +
    +
    +
    +
    +

    + + Windenergie-Einsparungsrechner +

    +

    + Nutzen Sie die Kraft des Windes, um Ihre Energiekosten zu senken +

    +
    + +
    + {/* Calculator Section */} +
    +
    +
    +
    +
    +
    +
    +
    + +

    + + Berechnen Sie Ihre Windenergie-Einsparungen +
    +

    + + + +
    +
    + +
    + + setMonthlyBill(e.target.value)} + placeholder="150" + className="pl-8 h-12 border-2 border-green-200 focus:border-emerald-500" + /> +
    +
    + +
    + + setPropertySize(e.target.value)} + placeholder="0.8" + step="0.1" + min="0" + className="h-12 border-2 border-green-200 focus:border-emerald-500" + /> +
    + +
    + + +
    +
    +
    +
    + + + +
    +
    + + +
    + +
    + + +
    + +
    + +
    + + setElectricityRate(e.target.value)} + step="0.01" + placeholder="0.35" + className="pl-8 h-12 border-2 border-green-200 focus:border-emerald-500" + /> +
    +
    + +
    + + setZipCode(e.target.value)} + placeholder="12345" + pattern="[0-9]{5}" + className="h-12 border-2 border-green-200 focus:border-emerald-500" + /> +
    +
    +
    +
    + + +
    + + {/* 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 = () => {
    +