Compare commits
3
Commits
44fe30a781
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c5cbd8f3a | ||
|
|
7cfb7fd5ac | ||
|
|
467dae14a2 |
@@ -31,6 +31,15 @@ type ExpandingCard = {
|
|||||||
/** which side of the container the open card sits on – the rail takes the other */
|
/** which side of the container the open card sits on – the rail takes the other */
|
||||||
type Side = "left" | "right"
|
type Side = "left" | "right"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where the minimised cards are allowed to gather. `auto` mirrors the pointer –
|
||||||
|
* the picked card keeps its half, so the rail changes sides as you browse.
|
||||||
|
* Pinning it to one side trades that spatial cue for calm: picking out of the
|
||||||
|
* rail then shifts the column by a single slot instead of sending every card
|
||||||
|
* across the container.
|
||||||
|
*/
|
||||||
|
type RailSide = Side | "auto"
|
||||||
|
|
||||||
/** the face a card currently shows */
|
/** the face a card currently shows */
|
||||||
type Face = "brief" | "rail" | "open"
|
type Face = "brief" | "rail" | "open"
|
||||||
|
|
||||||
@@ -567,9 +576,10 @@ function GridCard({
|
|||||||
/**
|
/**
|
||||||
* Card grid that unpacks in place. Clicking a card grows it to the full height
|
* Card grid that unpacks in place. Clicking a card grows it to the full height
|
||||||
* of the grid it was part of, while the remaining cards gather into a column of
|
* of the grid it was part of, while the remaining cards gather into a column of
|
||||||
* a third of the width beside it – on the side the open card came *from*, so
|
* a third of the width beside it – by default on the side the open card came
|
||||||
* the card you picked stays where you clicked it and everything else moves out
|
* *from*, so the card you picked stays where you clicked it and everything else
|
||||||
* of its way. Opening a card out of the rail therefore flips the composition.
|
* moves out of its way. Opening a card out of the rail therefore flips the
|
||||||
|
* composition; pass `railSide` to pin the column and keep the travel short.
|
||||||
*
|
*
|
||||||
* Every card is absolutely positioned from measured geometry, which keeps a
|
* Every card is absolutely positioned from measured geometry, which keeps a
|
||||||
* state change to a transform plus a size: the faces are pre-laid out at the
|
* state change to a transform plus a size: the faces are pre-laid out at the
|
||||||
@@ -578,9 +588,12 @@ function GridCard({
|
|||||||
*/
|
*/
|
||||||
function ExpandingCardGrid({
|
function ExpandingCardGrid({
|
||||||
items,
|
items,
|
||||||
|
railSide = "auto",
|
||||||
className,
|
className,
|
||||||
}: {
|
}: {
|
||||||
items: ExpandingCard[]
|
items: ExpandingCard[]
|
||||||
|
/** side the minimised cards stack on; `auto` follows the card you clicked */
|
||||||
|
railSide?: RailSide
|
||||||
className?: string
|
className?: string
|
||||||
}) {
|
}) {
|
||||||
const [open, setOpen] = React.useState<{ id: string; side: Side } | null>(
|
const [open, setOpen] = React.useState<{ id: string; side: Side } | null>(
|
||||||
@@ -592,13 +605,18 @@ function ExpandingCardGrid({
|
|||||||
const uid = React.useId()
|
const uid = React.useId()
|
||||||
|
|
||||||
const active = open ? items.findIndex((item) => item.id === open.id) : -1
|
const active = open ? items.findIndex((item) => item.id === open.id) : -1
|
||||||
|
/* a pinned rail decides the composition outright; the pointer-driven side
|
||||||
|
stays in state either way, so switching back to `auto` resumes from the
|
||||||
|
half the reader last picked instead of jumping */
|
||||||
|
const pinned =
|
||||||
|
railSide === "auto" ? null : railSide === "left" ? "right" : "left"
|
||||||
const plan = planLayout({
|
const plan = planLayout({
|
||||||
count: items.length,
|
count: items.length,
|
||||||
width: metrics.width,
|
width: metrics.width,
|
||||||
teaserHeights: metrics.teaser,
|
teaserHeights: metrics.teaser,
|
||||||
copyHeights: metrics.copy,
|
copyHeights: metrics.copy,
|
||||||
active,
|
active,
|
||||||
side: open?.side ?? "left",
|
side: pinned ?? open?.side ?? "left",
|
||||||
})
|
})
|
||||||
|
|
||||||
/* transitions only after the measured geometry has been painted once, and
|
/* transitions only after the measured geometry has been painted once, and
|
||||||
@@ -622,7 +640,8 @@ function ExpandingCardGrid({
|
|||||||
}
|
}
|
||||||
const frame = plan.frames[index]
|
const frame = plan.frames[index]
|
||||||
/* the card keeps its side: whichever half it is sitting in when clicked is
|
/* the card keeps its side: whichever half it is sitting in when clicked is
|
||||||
the half it opens into, so the rail always forms on the other one */
|
the half it opens into, so the rail forms on the other one – unless a
|
||||||
|
pinned `railSide` overrules it above */
|
||||||
const onRight = frame
|
const onRight = frame
|
||||||
? frame.x + frame.w / 2 > metrics.width / 2 + 1
|
? frame.x + frame.w / 2 > metrics.width / 2 + 1
|
||||||
: false
|
: false
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ function PriceCard({
|
|||||||
cadence: React.ReactNode
|
cadence: React.ReactNode
|
||||||
price: React.ReactNode
|
price: React.ReactNode
|
||||||
unit: React.ReactNode
|
unit: React.ReactNode
|
||||||
/** umlagefähig? tone drives soft-teal vs. soft-red pill */
|
/** optional legal cost-allocation note, shown only after review */
|
||||||
allocation: { label: React.ReactNode; tone: "positive" | "negative" }
|
allocation?: { label: React.ReactNode; tone: "positive" | "negative" }
|
||||||
description: React.ReactNode
|
description: React.ReactNode
|
||||||
media?: React.ReactNode
|
media?: React.ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
@@ -47,6 +47,7 @@ function PriceCard({
|
|||||||
{price}
|
{price}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1.5 text-sm text-muted-foreground">{unit}</div>
|
<div className="mt-1.5 text-sm text-muted-foreground">{unit}</div>
|
||||||
|
{allocation ? (
|
||||||
<Badge
|
<Badge
|
||||||
variant={allocation.tone === "positive" ? "default" : "destructive"}
|
variant={allocation.tone === "positive" ? "default" : "destructive"}
|
||||||
className="mt-4"
|
className="mt-4"
|
||||||
@@ -54,6 +55,7 @@ function PriceCard({
|
|||||||
{allocation.tone === "positive" ? <CircleCheck /> : <Ban />}
|
{allocation.tone === "positive" ? <CircleCheck /> : <Ban />}
|
||||||
{allocation.label}
|
{allocation.label}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
) : null}
|
||||||
<Separator className="mt-5 mb-4" />
|
<Separator className="mt-5 mb-4" />
|
||||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||||
{description}
|
{description}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const COLUMNS: { title: string; links: { to: string; label: string }[] }[] = [
|
|||||||
title: "Produkt",
|
title: "Produkt",
|
||||||
links: [
|
links: [
|
||||||
{ to: "/produkte", label: "Produkte" },
|
{ to: "/produkte", label: "Produkte" },
|
||||||
{ to: "/produkte/uvi", label: "UVI" },
|
{ to: "/produkte/uvi", label: "Verbrauchsinformation (UVI)" },
|
||||||
{ to: "/produkte/heizkostenabrechnung", label: "Heizkostenabrechnung" },
|
{ to: "/produkte/heizkostenabrechnung", label: "Heizkostenabrechnung" },
|
||||||
{ to: "/produkte/rauchwarnmelder", label: "Rauchwarnmelder" },
|
{ to: "/produkte/rauchwarnmelder", label: "Rauchwarnmelder" },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { ChevronDown, Menu } from "lucide-react"
|
import { Check, ChevronDown, Menu } from "lucide-react"
|
||||||
import { Link, NavLink, matchPath, useLocation } from "react-router-dom"
|
import { Link, NavLink, matchPath, useLocation } from "react-router-dom"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
@@ -24,7 +24,7 @@ const AUDIENCES = [
|
|||||||
|
|
||||||
/** mirrors the product registry in `@/pages/products/product-page` */
|
/** mirrors the product registry in `@/pages/products/product-page` */
|
||||||
const PRODUCTS = [
|
const PRODUCTS = [
|
||||||
{ to: "/produkte/uvi", label: "UVI" },
|
{ to: "/produkte/uvi", label: "Verbrauchsinformation (UVI)" },
|
||||||
{ to: "/produkte/heizkostenabrechnung", label: "Heizkostenabrechnung" },
|
{ to: "/produkte/heizkostenabrechnung", label: "Heizkostenabrechnung" },
|
||||||
{ to: "/produkte/rauchwarnmelder", label: "Rauchwarnmelder" },
|
{ to: "/produkte/rauchwarnmelder", label: "Rauchwarnmelder" },
|
||||||
{
|
{
|
||||||
@@ -131,7 +131,33 @@ function useActivePill(activeKey: string | undefined) {
|
|||||||
return { navRef, pill }
|
return { navRef, pill }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function MenuLink({
|
||||||
|
to,
|
||||||
|
label,
|
||||||
|
pathname,
|
||||||
|
}: {
|
||||||
|
to: string
|
||||||
|
label: string
|
||||||
|
pathname: string
|
||||||
|
}) {
|
||||||
|
const current = Boolean(matchPath({ path: to, end: true }, pathname))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenuItem
|
||||||
|
asChild
|
||||||
|
className={cn(current && "bg-accent font-bold text-brand-800")}
|
||||||
|
>
|
||||||
|
<Link to={to} aria-current={current ? "page" : undefined}>
|
||||||
|
<span className="min-w-0 flex-1">{label}</span>
|
||||||
|
{current ? <Check aria-hidden="true" className="size-4" /> : null}
|
||||||
|
</Link>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function NavMenu({ item, active }: { item: NavItem; active: boolean }) {
|
function NavMenu({ item, active }: { item: NavItem; active: boolean }) {
|
||||||
|
const { pathname } = useLocation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger
|
<DropdownMenuTrigger
|
||||||
@@ -145,14 +171,10 @@ function NavMenu({ item, active }: { item: NavItem; active: boolean }) {
|
|||||||
<ChevronDown className="size-3.5 opacity-60" />
|
<ChevronDown className="size-3.5 opacity-60" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="start">
|
<DropdownMenuContent align="start">
|
||||||
<DropdownMenuItem asChild>
|
<MenuLink to={item.to} label="Übersicht" pathname={pathname} />
|
||||||
<Link to={item.to}>Übersicht</Link>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
{item.menu?.map((a) => (
|
{item.menu?.map((link) => (
|
||||||
<DropdownMenuItem key={a.to} asChild>
|
<MenuLink key={link.to} {...link} pathname={pathname} />
|
||||||
<Link to={a.to}>{a.label}</Link>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
))}
|
))}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
@@ -200,6 +222,8 @@ function DesktopNav() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function MobileMenu() {
|
function MobileMenu() {
|
||||||
|
const { pathname } = useLocation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
@@ -208,26 +232,25 @@ function MobileMenu() {
|
|||||||
<span className="sr-only">Menü öffnen</span>
|
<span className="sr-only">Menü öffnen</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="w-64">
|
<DropdownMenuContent align="end" className="w-72">
|
||||||
{NAV_ITEMS.map((item) =>
|
{NAV_ITEMS.map((item) =>
|
||||||
item.menu ? (
|
item.menu ? (
|
||||||
<React.Fragment key={item.to}>
|
<React.Fragment key={item.to}>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuLabel>{item.label}</DropdownMenuLabel>
|
<DropdownMenuLabel>{item.label}</DropdownMenuLabel>
|
||||||
<DropdownMenuItem asChild>
|
<MenuLink to={item.to} label="Übersicht" pathname={pathname} />
|
||||||
<Link to={item.to}>Übersicht</Link>
|
{item.menu.map((link) => (
|
||||||
</DropdownMenuItem>
|
<MenuLink key={link.to} {...link} pathname={pathname} />
|
||||||
{item.menu.map((a) => (
|
|
||||||
<DropdownMenuItem key={a.to} asChild>
|
|
||||||
<Link to={a.to}>{a.label}</Link>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
))}
|
))}
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
) : (
|
) : (
|
||||||
<DropdownMenuItem key={item.to} asChild>
|
<MenuLink
|
||||||
<Link to={item.to}>{item.label}</Link>
|
key={item.to}
|
||||||
</DropdownMenuItem>
|
to={item.to}
|
||||||
|
label={item.label}
|
||||||
|
pathname={pathname}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
@@ -257,9 +280,6 @@ function SiteHeader() {
|
|||||||
<DesktopNav />
|
<DesktopNav />
|
||||||
|
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{/* <Button asChild size="sm" className="hidden sm:inline-flex">
|
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
|
||||||
</Button> */}
|
|
||||||
<Button asChild variant="ghost" size="sm" className="hidden sm:inline-flex">
|
<Button asChild variant="ghost" size="sm" className="hidden sm:inline-flex">
|
||||||
<a href="https://app.gebos.online">Login</a>
|
<a href="https://app.gebos.online">Login</a>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
|
import { Link } from "react-router-dom"
|
||||||
|
import { ArrowRight } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { AssetRender, renders } from "@/components/solenos/site-assets"
|
import { AssetRender, renders } from "@/components/solenos/site-assets"
|
||||||
@@ -6,6 +8,7 @@ import { AssetRender, renders } from "@/components/solenos/site-assets"
|
|||||||
type TrustPanelItem = {
|
type TrustPanelItem = {
|
||||||
icon: React.ReactNode
|
icon: React.ReactNode
|
||||||
label: React.ReactNode
|
label: React.ReactNode
|
||||||
|
to?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,6 +17,38 @@ type TrustPanelItem = {
|
|||||||
* so the labels stay on one line next to the security render, with the
|
* so the labels stay on one line next to the security render, with the
|
||||||
* follow-up link on the baseline underneath.
|
* follow-up link on the baseline underneath.
|
||||||
*/
|
*/
|
||||||
|
function TrustProperty({ item }: { item: TrustPanelItem }) {
|
||||||
|
const content = (
|
||||||
|
<>
|
||||||
|
<span className="flex shrink-0 text-brand-600 [&_svg]:size-7">
|
||||||
|
{item.icon}
|
||||||
|
</span>
|
||||||
|
<span className="min-w-0 flex-1 text-[0.9375rem] leading-snug font-medium text-balance text-navy/75">
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
{item.to ? (
|
||||||
|
<ArrowRight
|
||||||
|
aria-hidden="true"
|
||||||
|
className="size-4 shrink-0 text-brand-600"
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
const className =
|
||||||
|
"flex items-center gap-4 rounded-xl bg-card px-5 py-3.5 shadow-card"
|
||||||
|
|
||||||
|
return item.to ? (
|
||||||
|
<Link
|
||||||
|
to={item.to}
|
||||||
|
className={`${className} outline-none transition-colors hover:bg-brand-50 focus-visible:ring-[3px] focus-visible:ring-ring/40`}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className={className}>{content}</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function TrustPanel({
|
function TrustPanel({
|
||||||
title,
|
title,
|
||||||
items,
|
items,
|
||||||
@@ -44,17 +79,7 @@ function TrustPanel({
|
|||||||
</h2>
|
</h2>
|
||||||
<div className="mt-6 grid gap-4 sm:grid-cols-2">
|
<div className="mt-6 grid gap-4 sm:grid-cols-2">
|
||||||
{items.map((item, i) => (
|
{items.map((item, i) => (
|
||||||
<div
|
<TrustProperty key={i} item={item} />
|
||||||
key={i}
|
|
||||||
className="bg-card shadow-card flex items-center gap-5 rounded-xl px-5 py-3.5"
|
|
||||||
>
|
|
||||||
<span className="text-brand-600 flex shrink-0 [&_svg]:size-7">
|
|
||||||
{item.icon}
|
|
||||||
</span>
|
|
||||||
<span className="text-navy/75 text-[0.9375rem] leading-snug font-medium text-balance">
|
|
||||||
{item.label}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ function AudienceBreadcrumb({ current }: { current: string }) {
|
|||||||
*/
|
*/
|
||||||
function AudiencePage({
|
function AudiencePage({
|
||||||
breadcrumb,
|
breadcrumb,
|
||||||
|
eyebrow,
|
||||||
title,
|
title,
|
||||||
tagline,
|
tagline,
|
||||||
lead,
|
lead,
|
||||||
@@ -40,6 +41,7 @@ function AudiencePage({
|
|||||||
closing,
|
closing,
|
||||||
}: {
|
}: {
|
||||||
breadcrumb: string
|
breadcrumb: string
|
||||||
|
eyebrow?: React.ReactNode
|
||||||
title: React.ReactNode
|
title: React.ReactNode
|
||||||
/** short bold subline under the H1 (e.g. "Bestellen. Montieren. Fertig.") */
|
/** short bold subline under the H1 (e.g. "Bestellen. Montieren. Fertig.") */
|
||||||
tagline?: React.ReactNode
|
tagline?: React.ReactNode
|
||||||
@@ -60,6 +62,7 @@ function AudiencePage({
|
|||||||
<>
|
<>
|
||||||
<PageHero
|
<PageHero
|
||||||
breadcrumb={<AudienceBreadcrumb current={breadcrumb} />}
|
breadcrumb={<AudienceBreadcrumb current={breadcrumb} />}
|
||||||
|
eyebrow={eyebrow}
|
||||||
title={title}
|
title={title}
|
||||||
lead={
|
lead={
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -110,9 +110,9 @@ const SELF_INSTALL_STEPS = [
|
|||||||
media: (
|
media: (
|
||||||
<AssetRender render={renders.houseSmallIso} imgClassName="w-28" />
|
<AssetRender render={renders.houseSmallIso} imgClassName="w-28" />
|
||||||
),
|
),
|
||||||
title: "Gebäude angeben",
|
title: "Gebäudedaten online erfassen",
|
||||||
description:
|
description:
|
||||||
"Daten zu Ihrem Gebäude und den Wohneinheiten in wenigen Schritten erfassen.",
|
"Daten zum Gebäude und zu den Wohneinheiten direkt online eingeben.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: (
|
media: (
|
||||||
@@ -121,29 +121,31 @@ const SELF_INSTALL_STEPS = [
|
|||||||
<AssetRender render={renders.smokeAlarm} imgClassName="w-20" />
|
<AssetRender render={renders.smokeAlarm} imgClassName="w-20" />
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
title: "Passende Ausstattung zusammenstellen",
|
title: "Benötigte Ausstattung bestimmen lassen",
|
||||||
description: "Wir empfehlen die benötigte Ausstattung – Sie wählen aus.",
|
description:
|
||||||
|
"SolenOS ermittelt und konfiguriert aus den Objektdaten die passende notwendige beziehungsweise gesetzliche Mindestausstattung.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: (
|
media: (
|
||||||
<AssetRender render={renders.shippingBoxClosed} imgClassName="w-36" />
|
<AssetRender render={renders.shippingBoxClosed} imgClassName="w-36" />
|
||||||
),
|
),
|
||||||
title: "Vorkonfiguriert erhalten",
|
title: "Vorkonfiguriert erhalten",
|
||||||
description: "Ihre Technik kommt vorkonfiguriert und einsatzbereit an.",
|
description:
|
||||||
|
"SolenOS prüft die Ausstattung vor dem Versand und ordnet die Geräte den vorgesehenen Wohnungen zu.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: <AssetRender render={renders.drillTool} imgClassName="w-32" />,
|
media: <AssetRender render={renders.drillTool} imgClassName="w-32" />,
|
||||||
title: "Montieren",
|
title: "Montieren",
|
||||||
description:
|
description:
|
||||||
"Sie montieren mit Ihrem Handwerker oder selbst – flexibel und unkompliziert.",
|
"Sie montieren selbst oder gemeinsam mit Ihrem eigenen Handwerker.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: (
|
media: (
|
||||||
<AssetRender render={renders.refreshLoopCloud} imgClassName="w-28" />
|
<AssetRender render={renders.refreshLoopCloud} imgClassName="w-28" />
|
||||||
),
|
),
|
||||||
title: "SolenOS übernimmt",
|
title: "Betrieb übernehmen lassen",
|
||||||
description:
|
description:
|
||||||
"Wir übernehmen Ablesung, Übertragung und Auswertung automatisch.",
|
"SolenOS übernimmt Einrichtung, Datenübertragung und laufenden Betrieb.",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -165,13 +167,13 @@ const WHY_SOLENOS: BenefitGridItem[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <PortalGaugeIcon />,
|
icon: <PortalGaugeIcon />,
|
||||||
title: "Alles an einem Ort",
|
title: "Getrennte Portalrechte",
|
||||||
text: "UVI, Abrechnung, Geräte und weitere Gebäudedienstleistungen werden zentral verwaltet.",
|
text: "Sie sehen Gebäude, Wohnungen, Geräte, Status und Verbrauchswerte an einer Stelle. Bewohner sehen ausschließlich Daten ihrer eigenen Wohnung und ihres eigenen Nutzungszeitraums.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Clock strokeWidth={1.6} />,
|
icon: <Clock strokeWidth={1.6} />,
|
||||||
title: "Weniger laufender Aufwand",
|
title: "Keine regelmäßigen Ablesebesuche",
|
||||||
text: "Nach der Einrichtung werden Verbrauchsdaten automatisch erfasst und verarbeitet.",
|
text: "Verbrauchsdaten werden fernabgelesen; Heizkostenabrechnungen werden im Portal erstellt und versandfertig bereitgestellt.",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -187,7 +189,7 @@ const VARIANT_ROWS: ComparisonRow[] = [
|
|||||||
label: "Installation",
|
label: "Installation",
|
||||||
cells: ["Kunde / eigener Fachbetrieb", "organisiert durch SolenOS"],
|
cells: ["Kunde / eigener Fachbetrieb", "organisiert durch SolenOS"],
|
||||||
},
|
},
|
||||||
{ label: "Softwareeinrichtung", cells: ["vorbereitet durch SolenOS", "SolenOS"] },
|
{ label: "Softwarekonfiguration vor Ort", cells: ["nicht erforderlich – durch SolenOS eingerichtet", "nicht erforderlich – durch SolenOS eingerichtet"] },
|
||||||
{ label: "Laufender Betrieb", cells: ["SolenOS", "SolenOS"] },
|
{ label: "Laufender Betrieb", cells: ["SolenOS", "SolenOS"] },
|
||||||
{
|
{
|
||||||
label: "Kosten",
|
label: "Kosten",
|
||||||
@@ -199,12 +201,12 @@ const FAQS: FaqItem[] = [
|
|||||||
{
|
{
|
||||||
question: "Kann ich die Geräte wirklich selbst installieren?",
|
question: "Kann ich die Geräte wirklich selbst installieren?",
|
||||||
answer:
|
answer:
|
||||||
"Ja. Die Technik kommt vorkonfiguriert und objektbezogen bei Ihnen an. Montiert wird von Ihnen, Ihrem Handwerker oder – wenn Sie die Komplettlösung wählen – von SolenOS. Eine aufwendige Softwarekonfiguration vor Ort ist in keinem Fall erforderlich.",
|
"Ja. Die Technik kommt vorkonfiguriert und objektbezogen bei Ihnen an. Montiert wird von Ihnen, Ihrem Handwerker oder – bei der Komplettlösung – von SolenOS. Eine Softwarekonfiguration vor Ort ist in keinem Fall erforderlich.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Was kostet SolenOS für mein Gebäude?",
|
question: "Wann erhalte ich den verbindlichen Gesamtpreis?",
|
||||||
answer:
|
answer:
|
||||||
"Der Konfigurator gibt Ihnen mit wenigen Angaben zu Gebäude, Wohnungen und gewünschten Leistungen eine erste Preisindikation. Den genauen Preis erhalten Sie, sobald die tatsächlichen Gebäudedaten ergänzt sind.",
|
"Nach dem Schnellkonfigurator ergänzen Sie die Gebäudedetails und Fotos vorhandener Einbausituationen. SolenOS prüft die notwendige Ausstattung und erstellt anschließend das verbindliche Gesamtangebot.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Wer übernimmt Ablesung, Übertragung und Auswertung?",
|
question: "Wer übernimmt Ablesung, Übertragung und Auswertung?",
|
||||||
@@ -214,7 +216,7 @@ const FAQS: FaqItem[] = [
|
|||||||
{
|
{
|
||||||
question: "Was sehe ich im SolenOS Portal?",
|
question: "Was sehe ich im SolenOS Portal?",
|
||||||
answer:
|
answer:
|
||||||
"Ihre Gebäude, Wohnungen und Geräte an einer Stelle – inklusive Status der Geräte und der laufenden Verbrauchswerte. Bewohner erhalten ihren eigenen Zugang zum Mieterportal.",
|
"Sie sehen Gebäude, Wohnungen, Geräte, Gerätestatus und Verbrauchswerte an einer Stelle. Bewohner erhalten einen eigenen Zugang und sehen ausschließlich Daten ihrer eigenen Wohnung und ihres eigenen Nutzungszeitraums. Heizkostenabrechnungen werden im Portal erstellt und versandfertig bereitgestellt.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Kann ich später weitere Gebäude oder Geräte ergänzen?",
|
question: "Kann ich später weitere Gebäude oder Geräte ergänzen?",
|
||||||
@@ -227,15 +229,16 @@ export default function HauseigentuemerPage() {
|
|||||||
return (
|
return (
|
||||||
<AudiencePage
|
<AudiencePage
|
||||||
breadcrumb="Hauseigentümer"
|
breadcrumb="Hauseigentümer"
|
||||||
|
eyebrow="Für Hauseigentümer"
|
||||||
title={
|
title={
|
||||||
<span className="block text-[2.25rem] text-pretty sm:text-[2.75rem]">
|
<span className="block text-[2.25rem] text-pretty sm:text-[2.75rem]">
|
||||||
Messdienstleistungen für Ihr Mehrfamilienhaus. Einfach organisiert.
|
Messdienstleistungen für Ihr Mehrfamilienhaus. Einfach organisiert.
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
lead="UVI, Heizkostenabrechnung und Rauchwarnmelder mit vorkonfigurierter Technik – selbst installieren oder als Komplettlösung beauftragen."
|
lead="Monatliche Verbrauchsinformation (UVI), Heizkostenabrechnung und Rauchwarnmelder mit vorkonfigurierter Technik – selbst installieren oder als Komplettlösung beauftragen."
|
||||||
actions={
|
actions={
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">Preis für mein Gebäude berechnen</Link>
|
<Link to="/konfigurator">Konfiguration für mein Gebäude starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
visual={<HomeownerArt />}
|
visual={<HomeownerArt />}
|
||||||
@@ -267,12 +270,12 @@ export default function HauseigentuemerPage() {
|
|||||||
<CtaBanner
|
<CtaBanner
|
||||||
icon={<Euro />}
|
icon={<Euro />}
|
||||||
title="Welche Lösung passt zu Ihrem Gebäude?"
|
title="Welche Lösung passt zu Ihrem Gebäude?"
|
||||||
description="Mit wenigen Angaben zur ersten Preisindikation – oder direkt die Komplettlösung anfragen."
|
description="Leistungen und Gebäudedaten online erfassen – oder direkt die Komplettlösung anfragen."
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild variant="inverse" size="lg">
|
<Button asChild variant="inverse" size="lg">
|
||||||
<Link to="/konfigurator">
|
<Link to="/konfigurator">
|
||||||
Preis für mein Gebäude berechnen
|
Konfiguration für mein Gebäude starten
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="inverse" size="lg">
|
<Button asChild variant="inverse" size="lg">
|
||||||
@@ -293,13 +296,7 @@ export default function HauseigentuemerPage() {
|
|||||||
<OptionCard
|
<OptionCard
|
||||||
title="Selbst installieren"
|
title="Selbst installieren"
|
||||||
lead="Sie erhalten vorkonfigurierte Technik und installieren mit Ihrem Handwerker oder in Eigenregie."
|
lead="Sie erhalten vorkonfigurierte Technik und installieren mit Ihrem Handwerker oder in Eigenregie."
|
||||||
takeaway={
|
takeaway="Sie montieren selbst oder mit Ihrem Handwerker. Sobald die Geräte installiert sind, übernimmt SolenOS Einrichtung, Datenübertragung und laufenden Betrieb."
|
||||||
<>
|
|
||||||
Sie organisieren die Montage.
|
|
||||||
<br />
|
|
||||||
SolenOS übernimmt den digitalen Betrieb.
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
visual={
|
visual={
|
||||||
<AssetRender
|
<AssetRender
|
||||||
render={renders.shippingBoxMeters}
|
render={renders.shippingBoxMeters}
|
||||||
@@ -308,24 +305,18 @@ export default function HauseigentuemerPage() {
|
|||||||
}
|
}
|
||||||
action={
|
action={
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator?installation=0">Preis berechnen</Link>
|
<Link to="/konfigurator?installation=0">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<OptionCard
|
<OptionCard
|
||||||
title="Komplett installieren lassen"
|
title="Komplett installieren lassen"
|
||||||
lead="Lehnen Sie sich zurück. SolenOS übernimmt Planung, Installation und Einrichtung – inklusive Service."
|
lead="SolenOS übernimmt Installation und Einrichtung – inklusive Service."
|
||||||
takeaway={
|
takeaway="Komplettlösung mit voller Betreuung."
|
||||||
<>
|
|
||||||
Ein Ansprechpartner. Alles aus einer Hand.
|
|
||||||
<br />
|
|
||||||
Komplettlösung mit voller Betreuung.
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
visual={<FullServiceArt />}
|
visual={<FullServiceArt />}
|
||||||
action={
|
action={
|
||||||
<Button asChild size="lg" variant="outline">
|
<Button asChild size="lg" variant="outline">
|
||||||
<Link to="/konfigurator?installation=1">Preis berechnen</Link>
|
<Link to="/konfigurator?installation=1">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ const rolloutSteps = [
|
|||||||
"Die Geräte werden passend zum jeweiligen Gebäude beziehungsweise zur jeweiligen Nutzungseinheit ausgeliefert.",
|
"Die Geräte werden passend zum jeweiligen Gebäude beziehungsweise zur jeweiligen Nutzungseinheit ausgeliefert.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Bestehende Monteure installieren",
|
title: "Vor Ort nur montieren",
|
||||||
description:
|
description:
|
||||||
"Eigene Mitarbeiter, Hausmeister oder bestehende Installationspartner können die Montage übernehmen. Eine umfangreiche Softwarekonfiguration vor Ort ist nicht erforderlich.",
|
"Eigene Mitarbeiter, Hausmeister oder bestehende Installationspartner montieren ausschließlich die Geräte. SolenOS übernimmt die Softwarekonfiguration.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Bewohner einladen",
|
title: "Bewohner einladen",
|
||||||
@@ -79,7 +79,7 @@ const rolloutSteps = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const noEffortItems = [
|
const noEffortItems = [
|
||||||
{ icon: <Ban />, title: "Keine aufwendige Gerätekonfiguration." },
|
{ icon: <Ban />, title: "Keine Softwarekonfiguration vor Ort." },
|
||||||
{ icon: <X />, title: "Keine manuelle Anlage jedes einzelnen Gerätes." },
|
{ icon: <X />, title: "Keine manuelle Anlage jedes einzelnen Gerätes." },
|
||||||
{
|
{
|
||||||
icon: <Unlock />,
|
icon: <Unlock />,
|
||||||
@@ -135,7 +135,7 @@ const faqs: FaqItem[] = [
|
|||||||
{
|
{
|
||||||
question: "Wie viel Aufwand entsteht für unser Team?",
|
question: "Wie viel Aufwand entsteht für unser Team?",
|
||||||
answer:
|
answer:
|
||||||
"Die Gebäude- und Wohnungsdaten werden bei der Auftragserstellung einmal erfasst und anschließend weiterverwendet. Es entfällt die aufwendige Gerätekonfiguration und die manuelle Anlage jedes einzelnen Gerätes.",
|
"Die Gebäude- und Wohnungsdaten werden bei der Auftragserstellung einmal erfasst und anschließend weiterverwendet. Vor Ort werden nur die Geräte montiert; SolenOS übernimmt die Softwarekonfiguration und Geräteanlage.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Können unsere bestehenden Monteure installieren?",
|
question: "Können unsere bestehenden Monteure installieren?",
|
||||||
@@ -188,12 +188,12 @@ export default function HausverwaltungenPage() {
|
|||||||
<AudiencePage
|
<AudiencePage
|
||||||
breadcrumb="Hausverwaltungen"
|
breadcrumb="Hausverwaltungen"
|
||||||
title="Für Hausverwaltungen"
|
title="Für Hausverwaltungen"
|
||||||
tagline="Skalieren Sie Ihre Bestände einfach."
|
tagline="Wachsende Bestände einfach betreuen."
|
||||||
lead="Rollout über viele Gebäude mit minimalem Aufwand – von der Planung bis zum laufenden Betrieb."
|
lead="Gebäude strukturiert ausrollen und vor Ort ausschließlich die Geräte montieren. SolenOS übernimmt die Softwarekonfiguration und den laufenden Betrieb."
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">Portfolio kalkulieren</Link>
|
<Link to="/konfigurator">Portfolio konfigurieren</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild size="lg" variant="outline">
|
<Button asChild size="lg" variant="outline">
|
||||||
<Link to="/kontakt">Rollout besprechen</Link>
|
<Link to="/kontakt">Rollout besprechen</Link>
|
||||||
@@ -204,11 +204,12 @@ export default function HausverwaltungenPage() {
|
|||||||
features={[
|
features={[
|
||||||
{
|
{
|
||||||
icon: <Package />,
|
icon: <Package />,
|
||||||
title: "Vorkonfigurierte Hardware",
|
title: "Zum Einbau vorkonfigurierte Messeinrichtungen",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Timer />,
|
icon: <Timer />,
|
||||||
title: "Wenig Aufwand vor Ort",
|
title: "Vor Ort nur montieren",
|
||||||
|
sub: "Keine Softwarekonfiguration vor Ort",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <LayoutDashboard />,
|
icon: <LayoutDashboard />,
|
||||||
@@ -216,7 +217,7 @@ export default function HausverwaltungenPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <TrendingUp />,
|
icon: <TrendingUp />,
|
||||||
title: "Skalierbar für wachsende Portfolios",
|
title: "Für wachsende Portfolios",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
closing={
|
closing={
|
||||||
@@ -224,11 +225,11 @@ export default function HausverwaltungenPage() {
|
|||||||
<CtaBanner
|
<CtaBanner
|
||||||
icon={<Euro />}
|
icon={<Euro />}
|
||||||
title="Wie sieht Ihr Portfolio aus?"
|
title="Wie sieht Ihr Portfolio aus?"
|
||||||
description="Erhalten Sie zunächst mit wenigen Angaben eine Preisindikation für mehrere Gebäude – oder sprechen Sie mit uns über vorhandene Messtechnik und den geplanten Rollout."
|
description="Erfassen Sie Gebäude und Leistungen online – oder sprechen Sie mit uns über vorhandene Messtechnik und den geplanten Rollout."
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild variant="inverse" size="lg">
|
<Button asChild variant="inverse" size="lg">
|
||||||
<Link to="/konfigurator">Portfolio kalkulieren</Link>
|
<Link to="/konfigurator">Portfolio konfigurieren</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="inverse" size="lg">
|
<Button asChild variant="inverse" size="lg">
|
||||||
<Link to="/kontakt">Rollout besprechen</Link>
|
<Link to="/kontakt">Rollout besprechen</Link>
|
||||||
@@ -242,7 +243,7 @@ export default function HausverwaltungenPage() {
|
|||||||
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
||||||
<SectionHeading
|
<SectionHeading
|
||||||
align="center"
|
align="center"
|
||||||
eyebrow="Skalierung"
|
eyebrow="Wachsende Bestände"
|
||||||
title="Weniger Projektaufwand pro Gebäude"
|
title="Weniger Projektaufwand pro Gebäude"
|
||||||
lead="Bei einem einzelnen Gebäude sind manuelle Arbeitsschritte überschaubar. Bei dutzenden Gebäuden werden sie zum Problem. SolenOS reduziert genau diese wiederkehrenden Aufgaben."
|
lead="Bei einem einzelnen Gebäude sind manuelle Arbeitsschritte überschaubar. Bei dutzenden Gebäuden werden sie zum Problem. SolenOS reduziert genau diese wiederkehrenden Aufgaben."
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { AssetRender, renders, vectors } from "@/components/solenos/site-assets"
|
|||||||
import { AudiencePage, AudienceClosing } from "@/pages/audiences/audience-page"
|
import { AudiencePage, AudienceClosing } from "@/pages/audiences/audience-page"
|
||||||
|
|
||||||
const KUNDEN_BEDARFE = [
|
const KUNDEN_BEDARFE = [
|
||||||
"UVI",
|
"Monatliche Verbrauchsinformation (UVI)",
|
||||||
"Heizkostenabrechnung",
|
"Heizkostenabrechnung",
|
||||||
"fernauslesbare Messtechnik",
|
"fernauslesbare Messtechnik",
|
||||||
"Rauchwarnmelder",
|
"Rauchwarnmelder",
|
||||||
@@ -42,7 +42,7 @@ const KEINE_HUERDEN = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Wrench />,
|
icon: <Wrench />,
|
||||||
title: "Keine komplizierte Softwareeinrichtung auf der Baustelle",
|
title: "Keinerlei Softwarekonfiguration vor Ort",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ const FAQS: FaqItem[] = [
|
|||||||
{
|
{
|
||||||
question: "Muss ich vor Ort Software konfigurieren?",
|
question: "Muss ich vor Ort Software konfigurieren?",
|
||||||
answer:
|
answer:
|
||||||
"Nein. Auf der Baustelle bleibt im Wesentlichen die Montage. Eine komplizierte Softwareeinrichtung am Gebäude ist nicht vorgesehen.",
|
"Nein. Vor Ort montieren Sie ausschließlich die vorgesehenen Geräte. Die gesamte Softwarekonfiguration übernimmt SolenOS.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Bleibt der Kunde mein Kunde?",
|
question: "Bleibt der Kunde mein Kunde?",
|
||||||
@@ -102,7 +102,7 @@ export default function InstallateurePage() {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
tagline="Bestellen. Montieren. Fertig."
|
tagline="Bestellen. Montieren. Fertig."
|
||||||
lead="SolenOS für Ihre Kunden installieren – ohne Partnerprogramm, verpflichtende Zertifizierung oder aufwendige Softwarekonfiguration."
|
lead="SolenOS für Ihre Kunden installieren – ohne Partnerprogramm, verpflichtende Zertifizierung oder jegliche Softwarekonfiguration vor Ort."
|
||||||
actions={
|
actions={
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">Gebäude für meinen Kunden konfigurieren</Link>
|
<Link to="/konfigurator">Gebäude für meinen Kunden konfigurieren</Link>
|
||||||
@@ -140,12 +140,12 @@ export default function InstallateurePage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Package />,
|
icon: <Package />,
|
||||||
title: "Vorkonfigurierte Hardware",
|
title: "Zum Einbau vorkonfigurierte Messeinrichtungen",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Wrench />,
|
icon: <Wrench />,
|
||||||
title: "Einfache Installation",
|
title: "Vor Ort nur montieren",
|
||||||
sub: "Keine Softwarekonfiguration",
|
sub: "Keinerlei Softwarekonfiguration vor Ort",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Users />,
|
icon: <Users />,
|
||||||
@@ -156,7 +156,7 @@ export default function InstallateurePage() {
|
|||||||
closing={
|
closing={
|
||||||
<AudienceClosing
|
<AudienceClosing
|
||||||
title="SolenOS bei einem Kunden einsetzen?"
|
title="SolenOS bei einem Kunden einsetzen?"
|
||||||
lead="Stellen Sie mit wenigen Angaben zunächst die ungefähre Ausstattung und den Preis für das Gebäude zusammen."
|
lead="Erfassen Sie Leistungen und Gebäudedaten online. SolenOS bestimmt daraus die notwendige Ausstattung für das geprüfte Gesamtangebot."
|
||||||
actions={
|
actions={
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">
|
<Link to="/konfigurator">
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ const platformRequirements = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const whiteLabelItems = [
|
const whiteLabelItems = [
|
||||||
"eigenes Branding",
|
"Optionen für Ihr eigenes Logo im abgestimmten Umfang",
|
||||||
"eigene Kundenbeziehung",
|
"eigene Kundenbeziehung",
|
||||||
"mandantenfähige Verwaltung",
|
"mandantenfähige Verwaltung",
|
||||||
"Endkundenportale",
|
"klar vereinbarte SolenOS- und Anbieterkennzeichnung",
|
||||||
"APIs und Datenexporte",
|
"APIs und Datenexporte",
|
||||||
"Geräteverwaltung",
|
"Geräteverwaltung",
|
||||||
"technischer Support",
|
"technischer Support",
|
||||||
@@ -40,7 +40,7 @@ const whiteLabelItems = [
|
|||||||
const platformCapabilities = [
|
const platformCapabilities = [
|
||||||
{
|
{
|
||||||
title: "Gerätekompatibilität",
|
title: "Gerätekompatibilität",
|
||||||
sub: "Einbindung unterschiedlicher Zähler- und Gerätetypen auf Basis geeigneter Standards.",
|
sub: "OMS-kompatible Geräte verschiedener Hersteller einbinden.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Gateway-Infrastruktur",
|
title: "Gateway-Infrastruktur",
|
||||||
@@ -63,8 +63,8 @@ const platformCapabilities = [
|
|||||||
sub: "Kunden und Bestände getrennt innerhalb einer gemeinsamen Plattform verwalten.",
|
sub: "Kunden und Bestände getrennt innerhalb einer gemeinsamen Plattform verwalten.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "White Label",
|
title: "Eigenmarken-Option",
|
||||||
sub: "SolenOS-Infrastruktur unter der Marke des Messdienstleisters einsetzen.",
|
sub: "Logo und Kennzeichnung im gemeinsam festgelegten Umfang einsetzen.",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ const businessComponents = [
|
|||||||
"Plattformgebühren",
|
"Plattformgebühren",
|
||||||
"Mengenstaffeln",
|
"Mengenstaffeln",
|
||||||
"wiederkehrende Gebühren",
|
"wiederkehrende Gebühren",
|
||||||
"White-Label-Konditionen",
|
"Konditionen für Eigenmarken-Optionen",
|
||||||
"Support- und Servicelevel",
|
"Support- und Servicelevel",
|
||||||
"mögliche Mindestmengen",
|
"mögliche Mindestmengen",
|
||||||
]
|
]
|
||||||
@@ -82,9 +82,9 @@ const stackFlow = ["Ihre Kunden", "Ihr Messdienst", "SolenOS Plattform"]
|
|||||||
|
|
||||||
const faqs: FaqItem[] = [
|
const faqs: FaqItem[] = [
|
||||||
{
|
{
|
||||||
question: "Können wir SolenOS unter unserer eigenen Marke anbieten?",
|
question: "Können wir SolenOS mit unserem eigenen Logo anbieten?",
|
||||||
answer:
|
answer:
|
||||||
"Ja. SolenOS ist als technische Grundlage für Dienstleistungen unter Ihrer Marke vorgesehen – mit eigenem Branding, mandantenfähiger Verwaltung und Endkundenportalen in Ihrem Auftritt.",
|
"Optional kann SolenOS mit Ihrem eigenen Logo beziehungsweise unter Ihrer Eigenmarke eingesetzt werden. Für welche Oberflächen das gilt und wie SolenOS dort gekennzeichnet wird, legen wir vorab gemeinsam fest.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Behalten wir die Kundenbeziehung?",
|
question: "Behalten wir die Kundenbeziehung?",
|
||||||
@@ -104,7 +104,7 @@ const faqs: FaqItem[] = [
|
|||||||
{
|
{
|
||||||
question: "Wie werden die Konditionen festgelegt?",
|
question: "Wie werden die Konditionen festgelegt?",
|
||||||
answer:
|
answer:
|
||||||
"Individuell beziehungsweise mengenabhängig – mit anderen Geschäftsmodellen, Mengenstaffeln und gegebenenfalls White-Label-Konditionen als im öffentlichen Preiskonfigurator. Die konkreten Konditionen werden nicht öffentlich dargestellt.",
|
"Die Konditionen werden passend zu Leistungsumfang, Bestandsgröße, Support und vereinbarten Eigenmarken-Optionen gemeinsam festgelegt. Unbestätigte Tarife oder Mindestmengen werden nicht vorab zugesagt.",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ export default function MessdienstleisterPage() {
|
|||||||
breadcrumb="Messdienstleister"
|
breadcrumb="Messdienstleister"
|
||||||
title="Für Messdienstleister"
|
title="Für Messdienstleister"
|
||||||
tagline="Ihre Services. Unsere Plattform."
|
tagline="Ihre Services. Unsere Plattform."
|
||||||
lead="Nutzen Sie SolenOS als technische Grundlage für Ihren eigenen Messdienst – skalierbar und zuverlässig."
|
lead="Nutzen Sie SolenOS als technische Grundlage für Ihren eigenen Messdienst – für kleine Bestände und große Wohnungsportfolios."
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
@@ -153,8 +153,8 @@ export default function MessdienstleisterPage() {
|
|||||||
features={[
|
features={[
|
||||||
{
|
{
|
||||||
icon: <Tag />,
|
icon: <Tag />,
|
||||||
title: "White Label",
|
title: "Optional mit Ihrem eigenen Logo",
|
||||||
sub: "Ihr Branding, Ihre Kunden",
|
sub: "Unter Ihrer Eigenmarke im vereinbarten Umfang",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Code2 />,
|
icon: <Code2 />,
|
||||||
@@ -163,8 +163,8 @@ export default function MessdienstleisterPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Layers />,
|
icon: <Layers />,
|
||||||
title: "Skalierbare Plattform",
|
title: "Für wachsende Bestände",
|
||||||
sub: "Für jedes Geschäftsmodell",
|
sub: "Von kleinen Beständen bis zu großen Wohnungsportfolios",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <ShieldCheck />,
|
icon: <ShieldCheck />,
|
||||||
@@ -233,8 +233,8 @@ export default function MessdienstleisterPage() {
|
|||||||
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
||||||
<SectionHeading
|
<SectionHeading
|
||||||
eyebrow="Ihre Marke"
|
eyebrow="Ihre Marke"
|
||||||
title="White Label"
|
title="Unter Ihrer Eigenmarke (White Label)"
|
||||||
lead="SolenOS kann als technische Grundlage für Dienstleistungen unter Ihrer eigenen Marke eingesetzt werden. Je nach Geschäftsmodell können unter anderem relevant sein:"
|
lead="SolenOS kann optional mit Ihrem eigenen Logo eingesetzt werden. Welche Oberflächen die Eigenmarke tragen und wie SolenOS gekennzeichnet wird, vereinbaren wir vorab verbindlich."
|
||||||
/>
|
/>
|
||||||
<div className="mt-8 grid max-w-3xl gap-x-10 gap-y-2.5 sm:grid-cols-2">
|
<div className="mt-8 grid max-w-3xl gap-x-10 gap-y-2.5 sm:grid-cols-2">
|
||||||
<Checklist items={whiteLabelItems.slice(0, 4)} />
|
<Checklist items={whiteLabelItems.slice(0, 4)} />
|
||||||
@@ -267,8 +267,8 @@ export default function MessdienstleisterPage() {
|
|||||||
<SectionHeading
|
<SectionHeading
|
||||||
align="center"
|
align="center"
|
||||||
eyebrow="Konditionen"
|
eyebrow="Konditionen"
|
||||||
title="Das Geschäftsmodell muss funktionieren"
|
title="Konditionen passend zum vereinbarten Umfang"
|
||||||
lead="Eine Plattform für Messdienstleister ist nur interessant, wenn auch der wirtschaftliche Rahmen stimmt. Deshalb werden kommerzielle Konditionen individuell beziehungsweise mengenabhängig vereinbart – mit anderen Geschäftsmodellen, Mengenstaffeln und gegebenenfalls White-Label-Konditionen als im öffentlichen Preiskonfigurator."
|
lead="Leistungsumfang, Bestandsgröße, Support und Eigenmarken-Optionen bestimmen den wirtschaftlichen Rahmen. Die konkreten Konditionen werden gemeinsam festgelegt; die Website macht dazu keine unbestätigten Zusagen."
|
||||||
/>
|
/>
|
||||||
<div className="mx-auto mt-8 max-w-2xl text-center">
|
<div className="mx-auto mt-8 max-w-2xl text-center">
|
||||||
<p className="text-xs font-bold text-muted-foreground">
|
<p className="text-xs font-bold text-muted-foreground">
|
||||||
@@ -291,8 +291,8 @@ export default function MessdienstleisterPage() {
|
|||||||
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
||||||
<SectionHeading
|
<SectionHeading
|
||||||
align="center"
|
align="center"
|
||||||
title="Gemeinsam skalieren"
|
title="Mit Ihren Beständen wachsen"
|
||||||
lead="SolenOS soll insbesondere Messdienstleistern ermöglichen, neue digitale Dienstleistungen anzubieten, ohne dafür eine vollständige eigene Hardware- und Softwareentwicklung aufbauen zu müssen. Der Messdienstleister behält dabei seine Kundenbeziehung und sein eigenes Geschäftsmodell."
|
lead="SolenOS unterstützt kleine Bestände ebenso wie große Wohnungsportfolios. Messdienstleister können neue digitale Dienstleistungen anbieten, ohne dafür eine vollständige eigene Hardware- und Softwareentwicklung aufbauen zu müssen; die Kundenbeziehung bleibt bei ihnen."
|
||||||
/>
|
/>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { useSearchParams } from "react-router-dom"
|
import { Link, useSearchParams } from "react-router-dom"
|
||||||
import { Ban, Check, CircleCheck, Euro, Plus, X } from "lucide-react"
|
import { Ban, Check, CircleCheck, Euro, Plus, X } from "lucide-react"
|
||||||
|
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { Checkbox } from "@/components/ui/checkbox"
|
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||||
@@ -50,15 +49,14 @@ const INITIAL_BUILDING: Building = {
|
|||||||
zimmer: 3,
|
zimmer: 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Grundpreise je Wohnung / Monat – Selbstmontage, wie in der Klarpreis-Liste. */
|
/** Grundpreise je Wohnung / Monat – wie in der Klarpreis-Liste. */
|
||||||
const UVI_MONTHLY = 10.5
|
const UVI_MONTHLY = 10.5
|
||||||
const INSPECTION_MONTHLY = 2.2
|
const INSPECTION_MONTHLY = 2.2
|
||||||
/** Aufschlag je Monatsposition, wenn SolenOS montiert – Platzhalter bis zum finalen Preismodell. */
|
/** RWM-Hardware je Wohnung einmalig – ohne Montage, die eine eigene Position ist. */
|
||||||
const INSTALL_MONTHLY_SURCHARGE = 2
|
const RWM_ONE_TIME = 30
|
||||||
/** RWM-Hardware je Wohnung einmalig, inklusive Montage – wie in der Klarpreis-Liste. */
|
/** Montage durch SolenOS: je neuem Melder und je Wohnung mit Messtechnik. */
|
||||||
const RWM_ONE_TIME_INSTALLED = 42
|
const INSTALL_PER_RWM = 10
|
||||||
/** Selbstmontage durch Kunde oder Fachbetrieb – Platzhalter bis zum finalen Preismodell. */
|
const INSTALL_PER_UNIT = 10
|
||||||
const RWM_ONE_TIME_SELF = 30
|
|
||||||
|
|
||||||
function formatEuro(value: number) {
|
function formatEuro(value: number) {
|
||||||
return value.toLocaleString("de-DE", {
|
return value.toLocaleString("de-DE", {
|
||||||
@@ -90,13 +88,14 @@ function settle(value: number | "", min: number) {
|
|||||||
/**
|
/**
|
||||||
* Deep-link preset. Pages elsewhere on the site link into the configurator with
|
* Deep-link preset. Pages elsewhere on the site link into the configurator with
|
||||||
* parts of the form already answered, e.g. `/konfigurator?installation=0` for
|
* parts of the form already answered, e.g. `/konfigurator?installation=0` for
|
||||||
* the self-install route. Supported params: `installation`, `uvi`, `rwm`,
|
* the self-install route. Supported params: `installation`, `uvi`,
|
||||||
* `adresse`, `heizung`, `wohnungen`, `zimmer`. Missing or unreadable values
|
* `abrechnung`, `rwm`, `adresse`, `heizung`, `wohnungen`, `zimmer`. Missing or
|
||||||
* keep the page defaults; numbers below the field minimum settle at it, just
|
* unreadable values keep the page defaults; numbers below the field minimum
|
||||||
* as they do when typed into the form.
|
* settle at it, just as they do when typed into the form.
|
||||||
*/
|
*/
|
||||||
type Preset = {
|
type Preset = {
|
||||||
uvi?: boolean
|
uvi?: boolean
|
||||||
|
billing?: boolean
|
||||||
rwm?: boolean
|
rwm?: boolean
|
||||||
install?: boolean
|
install?: boolean
|
||||||
/** Seeds the single building the configurator starts with. */
|
/** Seeds the single building the configurator starts with. */
|
||||||
@@ -149,6 +148,7 @@ function readPreset(params: URLSearchParams): Preset {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
uvi: presetFlag(params.get("uvi")),
|
uvi: presetFlag(params.get("uvi")),
|
||||||
|
billing: presetFlag(params.get("abrechnung")),
|
||||||
rwm: presetFlag(params.get("rwm")),
|
rwm: presetFlag(params.get("rwm")),
|
||||||
install: presetFlag(params.get("installation")),
|
install: presetFlag(params.get("installation")),
|
||||||
building,
|
building,
|
||||||
@@ -182,14 +182,17 @@ function StepCard({
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selectable service tile (step 1) — the active option carries a brand border.
|
* Selectable service tile (step 1) — the whole tile is the toggle, the switch
|
||||||
|
* mirrors the state. The active option carries a brand border.
|
||||||
*/
|
*/
|
||||||
function ServiceOption({
|
function ServiceOption({
|
||||||
|
id,
|
||||||
checked,
|
checked,
|
||||||
onCheckedChange,
|
onCheckedChange,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
}: {
|
}: {
|
||||||
|
id: string
|
||||||
checked: boolean
|
checked: boolean
|
||||||
onCheckedChange: (checked: boolean) => void
|
onCheckedChange: (checked: boolean) => void
|
||||||
title: string
|
title: string
|
||||||
@@ -198,21 +201,44 @@ function ServiceOption({
|
|||||||
return (
|
return (
|
||||||
<label
|
<label
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-pointer items-start gap-3 rounded-xl border p-4 transition-colors",
|
"flex cursor-pointer items-start justify-between gap-4 rounded-xl border p-4 transition-colors",
|
||||||
checked
|
checked
|
||||||
? "border-primary bg-brand-50/60 shadow-pill"
|
? "border-primary bg-brand-50/60 shadow-pill"
|
||||||
: "border-border bg-card hover:border-brand-200 hover:bg-brand-50/40"
|
: "border-border bg-card hover:border-brand-200 hover:bg-brand-50/40"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Checkbox
|
<div className="min-w-0 flex-1">
|
||||||
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
|
<span
|
||||||
|
id={`${id}-title`}
|
||||||
|
className="text-sm font-bold leading-snug text-navy"
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</span>
|
||||||
|
<Badge
|
||||||
|
id={`${id}-state`}
|
||||||
|
variant={checked ? "default" : "muted"}
|
||||||
|
aria-live="polite"
|
||||||
|
className="shrink-0"
|
||||||
|
>
|
||||||
|
{checked ? "Enthalten · abwählbar" : "Hinzufügen"}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
id={`${id}-description`}
|
||||||
|
className="mt-1 text-sm leading-relaxed text-muted-foreground"
|
||||||
|
>
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
id={id}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onCheckedChange={(v) => onCheckedChange(v === true)}
|
onCheckedChange={onCheckedChange}
|
||||||
|
aria-labelledby={`${id}-title`}
|
||||||
|
aria-describedby={`${id}-description ${id}-state`}
|
||||||
className="mt-0.5"
|
className="mt-0.5"
|
||||||
/>
|
/>
|
||||||
<span>
|
|
||||||
<span className="block text-sm font-bold text-navy">{title}</span>
|
|
||||||
<span className="block text-sm text-muted-foreground">{description}</span>
|
|
||||||
</span>
|
|
||||||
</label>
|
</label>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -282,23 +308,28 @@ function PackageCard({
|
|||||||
* position can be passed on to tenants (umlagefähig). Wording follows the
|
* position can be passed on to tenants (umlagefähig). Wording follows the
|
||||||
* Klarpreis price list.
|
* Klarpreis price list.
|
||||||
*/
|
*/
|
||||||
|
type Position = {
|
||||||
|
label: string
|
||||||
|
amount: number
|
||||||
|
unit: string
|
||||||
|
note?: string
|
||||||
|
allocatable: boolean
|
||||||
|
/** A deselected position stays on the card as a faint zero. */
|
||||||
|
active: boolean
|
||||||
|
}
|
||||||
|
|
||||||
function PriceRow({
|
function PriceRow({
|
||||||
label,
|
label,
|
||||||
amount,
|
amount,
|
||||||
unit,
|
unit,
|
||||||
note,
|
note,
|
||||||
allocatable,
|
allocatable,
|
||||||
}: {
|
active,
|
||||||
label: string
|
}: Position) {
|
||||||
amount: number
|
|
||||||
unit: string
|
|
||||||
note?: string
|
|
||||||
allocatable: boolean
|
|
||||||
}) {
|
|
||||||
const shown = useAnimatedNumber(amount)
|
const shown = useAnimatedNumber(amount)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={cn("transition-opacity", !active && "opacity-45")}>
|
||||||
<p className="text-sm font-bold text-navy">{label}</p>
|
<p className="text-sm font-bold text-navy">{label}</p>
|
||||||
<p className="mt-1 text-3xl font-extrabold tracking-tight text-navy tabular-nums">
|
<p className="mt-1 text-3xl font-extrabold tracking-tight text-navy tabular-nums">
|
||||||
ca. {formatEuro(shown)}
|
ca. {formatEuro(shown)}
|
||||||
@@ -321,6 +352,7 @@ export default function ConfiguratorPage() {
|
|||||||
const preset = React.useMemo(() => readPreset(searchParams), [searchParams])
|
const preset = React.useMemo(() => readPreset(searchParams), [searchParams])
|
||||||
|
|
||||||
const [uvi, setUvi] = React.useState(preset.uvi ?? true)
|
const [uvi, setUvi] = React.useState(preset.uvi ?? true)
|
||||||
|
const [billing, setBilling] = React.useState(preset.billing ?? true)
|
||||||
const [rwm, setRwm] = React.useState(preset.rwm ?? true)
|
const [rwm, setRwm] = React.useState(preset.rwm ?? true)
|
||||||
const [buildings, setBuildings] = React.useState<Building[]>(() => [
|
const [buildings, setBuildings] = React.useState<Building[]>(() => [
|
||||||
{ ...INITIAL_BUILDING, ...preset.building },
|
{ ...INITIAL_BUILDING, ...preset.building },
|
||||||
@@ -338,6 +370,7 @@ export default function ConfiguratorPage() {
|
|||||||
if (appliedPreset.current === preset) return
|
if (appliedPreset.current === preset) return
|
||||||
appliedPreset.current = preset
|
appliedPreset.current = preset
|
||||||
setUvi(preset.uvi ?? true)
|
setUvi(preset.uvi ?? true)
|
||||||
|
setBilling(preset.billing ?? true)
|
||||||
setRwm(preset.rwm ?? true)
|
setRwm(preset.rwm ?? true)
|
||||||
setInstall(preset.install ?? true)
|
setInstall(preset.install ?? true)
|
||||||
setBuildings([{ ...INITIAL_BUILDING, ...preset.building }])
|
setBuildings([{ ...INITIAL_BUILDING, ...preset.building }])
|
||||||
@@ -360,15 +393,77 @@ export default function ConfiguratorPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const totalUnits = buildings.reduce((sum, b) => sum + (b.wohnungen || 0), 0)
|
const totalUnits = buildings.reduce((sum, b) => sum + (b.wohnungen || 0), 0)
|
||||||
const installSurcharge = install ? INSTALL_MONTHLY_SURCHARGE : 0
|
const unitWord = totalUnits === 1 ? "Wohnung" : "Wohnungen"
|
||||||
const uviMonthly = UVI_MONTHLY + installSurcharge
|
/*
|
||||||
const inspectionMonthly = INSPECTION_MONTHLY + installSurcharge
|
* Melder je Wohnung: einer je Zimmer plus einer im Flur als Rettungsweg
|
||||||
const installNote = install
|
* (DIN 14676). Die Hardware wird je Wohnung abgerechnet, die Montage je
|
||||||
? `inklusive ${formatEuro(INSTALL_MONTHLY_SURCHARGE)}\u00A0€ Installationsanteil`
|
* Gerät; die endgültige Anzahl ergibt sich aus der Detailkonfiguration.
|
||||||
: undefined
|
*/
|
||||||
const rwmRatePerUnit = install ? RWM_ONE_TIME_INSTALLED : RWM_ONE_TIME_SELF
|
const rwmDevices = rwm
|
||||||
/* RWM hardware is billed once per Wohnung – the estimate is the sum. */
|
? Math.round(
|
||||||
const rwmOneTimeTotal = rwm ? rwmRatePerUnit * totalUnits : 0
|
buildings.reduce(
|
||||||
|
(sum, b) => sum + (b.wohnungen || 0) * ((b.zimmer || 0) + 1),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: 0
|
||||||
|
/* UVI und Abrechnung teilen sich die Messtechnik – sie wird einmal montiert. */
|
||||||
|
const meteringUnits = uvi || billing ? totalUnits : 0
|
||||||
|
const installTotal =
|
||||||
|
rwmDevices * INSTALL_PER_RWM + meteringUnits * INSTALL_PER_UNIT
|
||||||
|
|
||||||
|
const installNotes: string[] = []
|
||||||
|
if (install && rwmDevices > 0) {
|
||||||
|
installNotes.push(
|
||||||
|
`${rwmDevices} Rauchwarnmelder × ${formatEuro(INSTALL_PER_RWM)}\u00A0€`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (install && meteringUnits > 0) {
|
||||||
|
installNotes.push(
|
||||||
|
`Messtechnik in ${meteringUnits} ${unitWord} × ${formatEuro(INSTALL_PER_UNIT)}\u00A0€`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Every position stays on the card. A deselected one counts down to a faint
|
||||||
|
* zero, so a toggle reads as a change in the price instead of a row that
|
||||||
|
* vanishes.
|
||||||
|
*/
|
||||||
|
const positions: Position[] = [
|
||||||
|
{
|
||||||
|
label: "UVI-Komplettbetrieb",
|
||||||
|
amount: uvi ? UVI_MONTHLY : 0,
|
||||||
|
unit: "je Wohnung / Monat",
|
||||||
|
allocatable: true,
|
||||||
|
active: uvi,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Ferninspektion Rauchwarnmelder",
|
||||||
|
amount: rwm ? INSPECTION_MONTHLY : 0,
|
||||||
|
unit: "je Wohnung / Monat",
|
||||||
|
allocatable: true,
|
||||||
|
active: rwm,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Rauchwarnmelder-Geräte",
|
||||||
|
/* Hardware is billed once per Wohnung – the estimate is the sum. */
|
||||||
|
amount: rwm ? RWM_ONE_TIME * totalUnits : 0,
|
||||||
|
unit: "einmalig gesamt",
|
||||||
|
note: rwm
|
||||||
|
? `${totalUnits} ${unitWord} × ${formatEuro(RWM_ONE_TIME)}\u00A0€`
|
||||||
|
: undefined,
|
||||||
|
allocatable: false,
|
||||||
|
active: rwm,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Montage durch SolenOS",
|
||||||
|
amount: install ? installTotal : 0,
|
||||||
|
unit: "einmalig gesamt",
|
||||||
|
note: installNotes.length > 0 ? installNotes.join(" · ") : undefined,
|
||||||
|
allocatable: false,
|
||||||
|
active: install && installTotal > 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
@@ -383,7 +478,7 @@ export default function ConfiguratorPage() {
|
|||||||
/>
|
/>
|
||||||
<SectionHeading
|
<SectionHeading
|
||||||
title="Konfigurator"
|
title="Konfigurator"
|
||||||
lead="In 3 Schritten zur Preisindikation."
|
lead="Leistungen auswählen, Gebäudedaten erfassen und sofort eine Preisindikation erhalten."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -393,50 +488,69 @@ export default function ConfiguratorPage() {
|
|||||||
<StepCard step={1} title="Leistungen wählen">
|
<StepCard step={1} title="Leistungen wählen">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
<ServiceOption
|
<ServiceOption
|
||||||
|
id="service-uvi"
|
||||||
checked={uvi}
|
checked={uvi}
|
||||||
onCheckedChange={setUvi}
|
onCheckedChange={setUvi}
|
||||||
title="UVI"
|
title="Monatliche Verbrauchsinformation (UVI)"
|
||||||
description="Unterjährige Verbrauchsinformation inklusive Messtechnik"
|
description="Monatliche Verbrauchswerte und Vergleiche für jede Wohnung einschließlich der benötigten Messtechnik."
|
||||||
/>
|
/>
|
||||||
<ServiceOption
|
<ServiceOption
|
||||||
|
id="service-billing"
|
||||||
|
checked={billing}
|
||||||
|
onCheckedChange={setBilling}
|
||||||
|
title="Heizkostenabrechnung"
|
||||||
|
description="Jährliche Heizkostenabrechnung einschließlich der gesetzlich vorgeschriebenen Pflichtangaben und Dokumente."
|
||||||
|
/>
|
||||||
|
<ServiceOption
|
||||||
|
id="service-smoke-alarms"
|
||||||
checked={rwm}
|
checked={rwm}
|
||||||
onCheckedChange={setRwm}
|
onCheckedChange={setRwm}
|
||||||
title="Rauchwarnmelder"
|
title="Rauchwarnmelder"
|
||||||
description="Rauchwarnmelder inklusive digitaler Dienstleistungen"
|
description="Rauchwarnmelder mit Ferninspektion, Geräteverwaltung sowie Prüf- und Statusdokumentation."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Separator className="my-6" />
|
<Separator className="my-6" />
|
||||||
<div
|
<label
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-start justify-between gap-4 rounded-xl border p-4 transition-colors",
|
"flex cursor-pointer items-start justify-between gap-4 rounded-xl border p-4 transition-colors",
|
||||||
install
|
install
|
||||||
? "border-primary bg-brand-50/60 shadow-pill"
|
? "border-primary bg-brand-50/60 shadow-pill"
|
||||||
: "border-border bg-card"
|
: "border-border bg-card hover:border-brand-200 hover:bg-brand-50/40"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0 flex-1">
|
||||||
<Label
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
htmlFor="installation"
|
<span
|
||||||
className="cursor-pointer text-sm font-bold text-navy"
|
id="installation-title"
|
||||||
|
className="text-sm font-bold text-navy"
|
||||||
|
>
|
||||||
|
Montage durch SolenOS
|
||||||
|
</span>
|
||||||
|
<Badge variant={install ? "default" : "muted"}>
|
||||||
|
{install ? "SolenOS montiert" : "Selbstmontage"}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
id="installation-description"
|
||||||
|
className="mt-1 text-sm text-muted-foreground"
|
||||||
>
|
>
|
||||||
Installation durch SolenOS
|
|
||||||
</Label>
|
|
||||||
<p className="mt-1 text-sm text-muted-foreground">
|
|
||||||
{install
|
{install
|
||||||
? "SolenOS organisiert die Montage – Geräte- und Monatspreise enthalten die Installation."
|
? "SolenOS übernimmt Montage und Softwarekonfiguration – die Montage erscheint als eigene Position."
|
||||||
: "Sie selbst, Ihr Hausmeister oder Ihr Fachbetrieb montiert die Geräte."}
|
: "Sie, Ihr Hausmeister oder Ihr Fachbetrieb montieren. Eine Softwarekonfiguration vor Ort ist nicht erforderlich."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Switch
|
<Switch
|
||||||
id="installation"
|
id="installation"
|
||||||
checked={install}
|
checked={install}
|
||||||
onCheckedChange={setInstall}
|
onCheckedChange={setInstall}
|
||||||
|
aria-labelledby="installation-title"
|
||||||
|
aria-describedby="installation-description"
|
||||||
className="mt-0.5"
|
className="mt-0.5"
|
||||||
/>
|
/>
|
||||||
</div>
|
</label>
|
||||||
</StepCard>
|
</StepCard>
|
||||||
|
|
||||||
<StepCard step={2} title="Gebäude angeben">
|
<StepCard step={2} title="Gebäudedaten online erfassen">
|
||||||
<div className="flex flex-col gap-5">
|
<div className="flex flex-col gap-5">
|
||||||
{buildings.map((b, i) => (
|
{buildings.map((b, i) => (
|
||||||
<div
|
<div
|
||||||
@@ -549,10 +663,37 @@ export default function ConfiguratorPage() {
|
|||||||
</div>
|
</div>
|
||||||
</StepCard>
|
</StepCard>
|
||||||
|
|
||||||
<StepCard step={3} title="Konfiguration speichern">
|
<StepCard step={3} title="Persönlichen Link anfordern">
|
||||||
|
<div className="rounded-xl border border-brand-200 bg-brand-50/60 p-4">
|
||||||
|
<p className="text-sm font-bold text-navy">
|
||||||
|
So geht es nach der E-Mail weiter
|
||||||
|
</p>
|
||||||
|
<ol className="mt-3 list-decimal space-y-2 pl-5 text-sm leading-relaxed text-muted-foreground">
|
||||||
|
<li>
|
||||||
|
Wir speichern Ihre bisherige Auswahl und senden Ihnen einen
|
||||||
|
persönlichen Link.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Über den Link ergänzen Sie die Gebäudedetails und laden im
|
||||||
|
Portal Fotos vorhandener wasserführender Einbausituationen
|
||||||
|
hoch. Fotos ersetzen Maße und Typangaben, soweit sie eine
|
||||||
|
eindeutige Prüfung ermöglichen.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
SolenOS prüft die Angaben und Fotos manuell, bestimmt die
|
||||||
|
endgültige Ausstattung und erstellt anschließend den genauen
|
||||||
|
Gesamtpreis beziehungsweise ein verbindliches Angebot.
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<p className="mt-3 text-xs leading-relaxed text-muted-foreground">
|
||||||
|
Beispiel für spätere Detailfragen: Kinderzimmer und regelmäßig
|
||||||
|
genutzte Gästezimmer zählen als Schlafräume; ein dauerhaftes
|
||||||
|
Büro nicht.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => e.preventDefault()}
|
onSubmit={(event) => event.preventDefault()}
|
||||||
className="flex flex-col gap-3"
|
className="mt-5 flex flex-col gap-3"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<Label htmlFor="config-email">E-Mail-Adresse</Label>
|
<Label htmlFor="config-email">E-Mail-Adresse</Label>
|
||||||
@@ -561,18 +702,28 @@ export default function ConfiguratorPage() {
|
|||||||
type="email"
|
type="email"
|
||||||
placeholder="name@unternehmen.de"
|
placeholder="name@unternehmen.de"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(event) => setEmail(event.target.value)}
|
||||||
|
aria-describedby="config-email-privacy"
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit" className="self-start">
|
<p
|
||||||
Konfiguration speichern & fortsetzen
|
id="config-email-privacy"
|
||||||
</Button>
|
className="text-xs leading-relaxed text-muted-foreground"
|
||||||
<p className="text-xs text-muted-foreground">
|
>
|
||||||
Sie erhalten einen persönlichen Link
|
Wir verwenden Ihre E-Mail-Adresse, um den persönlichen Link
|
||||||
zu Ihrer Konfiguration. Damit kannst du
|
zu versenden. Einzelheiten finden Sie in unseren{" "}
|
||||||
sofort weitermachen, später zurückkehren
|
<Link
|
||||||
oder den Link intern weitergeben.
|
to="/wissen/datenschutz-sicherheit"
|
||||||
|
className="font-semibold text-primary underline underline-offset-2"
|
||||||
|
>
|
||||||
|
Hinweisen zu Datenschutz & Sicherheit
|
||||||
|
</Link>
|
||||||
|
.
|
||||||
</p>
|
</p>
|
||||||
|
<Button type="submit" className="self-start">
|
||||||
|
Persönlichen Link anfordern
|
||||||
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</StepCard>
|
</StepCard>
|
||||||
</div>
|
</div>
|
||||||
@@ -589,74 +740,61 @@ export default function ConfiguratorPage() {
|
|||||||
</IconBadge>
|
</IconBadge>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-6 sm:p-7">
|
<div className="p-6 sm:p-7">
|
||||||
{uvi || rwm ? (
|
<p className="text-sm font-bold text-navy">
|
||||||
<div className="flex flex-col gap-5">
|
{buildings.length} Gebäude · {totalUnits} {unitWord}
|
||||||
{uvi ? (
|
</p>
|
||||||
<PriceRow
|
<Separator className="my-5" />
|
||||||
label="UVI-Komplettbetrieb"
|
<div className="flex flex-col gap-5" aria-live="polite">
|
||||||
amount={uviMonthly}
|
{positions.map((position, index) => (
|
||||||
unit="je Wohnung / Monat"
|
<React.Fragment key={position.label}>
|
||||||
note={installNote}
|
{index > 0 ? <Separator /> : null}
|
||||||
allocatable
|
<PriceRow {...position} />
|
||||||
/>
|
</React.Fragment>
|
||||||
) : null}
|
))}
|
||||||
{rwm ? (
|
|
||||||
<>
|
|
||||||
{uvi ? <Separator /> : null}
|
|
||||||
<PriceRow
|
|
||||||
label="Ferninspektion Rauchwarnmelder"
|
|
||||||
amount={inspectionMonthly}
|
|
||||||
unit="je Wohnung / Monat"
|
|
||||||
note={installNote}
|
|
||||||
allocatable
|
|
||||||
/>
|
|
||||||
<Separator />
|
|
||||||
<PriceRow
|
|
||||||
label="Rauchwarnmelder-Geräte"
|
|
||||||
amount={rwmOneTimeTotal}
|
|
||||||
unit="einmalig gesamt"
|
|
||||||
note={`${totalUnits} ${totalUnits === 1 ? "Wohnung" : "Wohnungen"} × ${formatEuro(rwmRatePerUnit)}\u00A0€ · ${install ? "inklusive Montage" : "Selbstmontage"}`}
|
|
||||||
allocatable={false}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
<div className="mt-6 space-y-2 text-xs leading-relaxed text-muted-foreground">
|
||||||
<p className="text-sm text-muted-foreground">
|
{billing ? (
|
||||||
Wählen Sie in Schritt 1 mindestens eine Leistung, um eine
|
<p>
|
||||||
Preisindikation zu erhalten.
|
Die Heizkostenabrechnung wird mit dem verbindlichen
|
||||||
|
Angebot bepreist.
|
||||||
</p>
|
</p>
|
||||||
)}
|
) : null}
|
||||||
<p className="mt-6 text-xs leading-relaxed text-muted-foreground">
|
<p>
|
||||||
{install
|
Die erste Berechnung ist eine unverbindliche
|
||||||
? "Preise inklusive Montage durch SolenOS. "
|
Preisindikation. Der genaue Preis ergibt sich aus der
|
||||||
: "Preise ohne Montage – Installation durch Sie oder Ihren Fachbetrieb. "}
|
vollständigen Objektkonfiguration.
|
||||||
Die erste Berechnung ist eine unverbindliche Preisindikation.
|
|
||||||
Der genaue Preis ergibt sich aus der vollständigen
|
|
||||||
Objektkonfiguration.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{/* Was ist in der Schätzung enthalten? */}
|
{/* Was ist in dem Preis enthalten? */}
|
||||||
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
||||||
<SectionHeading
|
<SectionHeading title="Was ist in dem Preis enthalten?" />
|
||||||
title="Was ist in dem Preis enthalten?"
|
<div className="mt-8 grid gap-6 lg:grid-cols-3">
|
||||||
/>
|
|
||||||
<div className="mt-8 grid gap-6 lg:grid-cols-2">
|
|
||||||
<PackageCard
|
<PackageCard
|
||||||
render={renders.gateway}
|
render={renders.gateway}
|
||||||
title="UVI"
|
title="Monatliche Verbrauchsinformation (UVI)"
|
||||||
included={uvi}
|
included={uvi}
|
||||||
items={[
|
items={[
|
||||||
"geschätzte benötigte Messtechnik",
|
"von SolenOS ermittelte notwendige Messtechnik",
|
||||||
"SolenOS Plattform",
|
"erforderliche Gateway- und Kommunikationsinfrastruktur",
|
||||||
"Datenerfassung",
|
"SolenOS Plattform, Datenerfassung und laufender digitaler Betrieb",
|
||||||
"Unterjährige Verbrauchsinformation",
|
"monatliche Verbrauchswerte und Vergleiche für jede Wohnung",
|
||||||
"laufender digitaler Betrieb",
|
]}
|
||||||
|
/>
|
||||||
|
<PackageCard
|
||||||
|
render={renders.glassMoney}
|
||||||
|
title="Heizkostenabrechnung"
|
||||||
|
included={billing}
|
||||||
|
items={[
|
||||||
|
"jährliche Heizkostenabrechnung im Online-Portal",
|
||||||
|
"Verteilung nach den Vorgaben der HeizkostenV",
|
||||||
|
"Berücksichtigung von Nutzerwechseln und Leerständen",
|
||||||
|
"Pflichtangaben nach § 6a Absatz 3 HeizkostenV",
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<PackageCard
|
<PackageCard
|
||||||
@@ -664,12 +802,12 @@ export default function ConfiguratorPage() {
|
|||||||
title="Rauchwarnmelder"
|
title="Rauchwarnmelder"
|
||||||
included={rwm}
|
included={rwm}
|
||||||
items={[
|
items={[
|
||||||
"geschätzte Anzahl Rauchwarnmelder",
|
"von SolenOS ermittelte Anzahl Rauchwarnmelder",
|
||||||
"Verwaltung der Geräte",
|
"Verwaltung und Ferninspektion der Geräte",
|
||||||
"gebuchte digitale Dienstleistungen",
|
"Prüf- und Statusdokumentation",
|
||||||
install
|
install
|
||||||
? "Montage und Eigentumsübertragung"
|
? "Montage durch SolenOS als eigene Position"
|
||||||
: "Eigentumsübertragung – Montage durch Sie",
|
: "Montage durch Sie oder Ihren Fachbetrieb",
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,11 +62,11 @@ const AUDIENCES: Record<
|
|||||||
tab: "Hausverwaltungen",
|
tab: "Hausverwaltungen",
|
||||||
tabIcon: <Building2 />,
|
tabIcon: <Building2 />,
|
||||||
headline: "Viele Gebäude. Ein einfacher Rollout.",
|
headline: "Viele Gebäude. Ein einfacher Rollout.",
|
||||||
text: "Erfassen Sie Ihre Objekte einmal, erhalten Sie vorkonfigurierte Hardware und nutzen Sie bestehende Mitarbeiter oder Installationspartner für die Montage.",
|
text: "Erfassen Sie Ihre Objekte einmal, erhalten Sie vorkonfigurierte Messeinrichtungen und nutzen Sie bestehende Mitarbeiter oder Installationspartner ausschließlich für die Montage.",
|
||||||
bullets: [
|
bullets: [
|
||||||
"standardisierter Rollout",
|
"standardisierter Rollout",
|
||||||
"vorkonfigurierte Geräte",
|
"vorkonfigurierte Geräte",
|
||||||
"wenig Softwarearbeit vor Ort",
|
"keine Softwarekonfiguration vor Ort",
|
||||||
"zentrale Portfolioverwaltung",
|
"zentrale Portfolioverwaltung",
|
||||||
"geringer administrativer Aufwand",
|
"geringer administrativer Aufwand",
|
||||||
"schnelle Erweiterung um weitere Gebäude",
|
"schnelle Erweiterung um weitere Gebäude",
|
||||||
@@ -79,14 +79,14 @@ const AUDIENCES: Record<
|
|||||||
tab: "Messdienstleister",
|
tab: "Messdienstleister",
|
||||||
tabIcon: <LineChart />,
|
tabIcon: <LineChart />,
|
||||||
headline: "Ihre Messdienstleistung. Unsere Infrastruktur.",
|
headline: "Ihre Messdienstleistung. Unsere Infrastruktur.",
|
||||||
text: "Nutzen Sie SolenOS als technische Grundlage für Ihre eigenen Dienstleistungen – mit Hardware, Plattform, Gerätemanagement und optionalem White Label.",
|
text: "Nutzen Sie SolenOS als technische Grundlage für Ihre eigenen Dienstleistungen – mit Hardware, Plattform, Gerätemanagement und optional mit Ihrem eigenen Logo (White Label).",
|
||||||
bullets: [
|
bullets: [
|
||||||
"technische Plattform",
|
"technische Plattform",
|
||||||
"Gerätekompatibilität",
|
"OMS-kompatible Geräte verschiedener Hersteller",
|
||||||
"Skalierbarkeit",
|
"für kleine Bestände und große Wohnungsportfolios",
|
||||||
"APIs und Integrationen",
|
"APIs und Integrationen",
|
||||||
"White Label",
|
"Optionen für eigenes Logo und Eigenmarke",
|
||||||
"individuelles Geschäftsmodell",
|
"individuell vereinbarte Konditionen",
|
||||||
],
|
],
|
||||||
cta: "SolenOS für Messdienstleister",
|
cta: "SolenOS für Messdienstleister",
|
||||||
href: "/fuer-wen/messdienstleister",
|
href: "/fuer-wen/messdienstleister",
|
||||||
@@ -100,8 +100,8 @@ const AUDIENCES: Record<
|
|||||||
bullets: [
|
bullets: [
|
||||||
"kein verpflichtender Partnerstatus",
|
"kein verpflichtender Partnerstatus",
|
||||||
"keine Mindestabnahme",
|
"keine Mindestabnahme",
|
||||||
"vorkonfigurierte Hardware",
|
"zum Einbau vorkonfigurierte Messeinrichtungen",
|
||||||
"keine aufwendige Softwarekonfiguration",
|
"keinerlei Softwarekonfiguration vor Ort",
|
||||||
"bestehende Kundenbeziehung bleibt erhalten",
|
"bestehende Kundenbeziehung bleibt erhalten",
|
||||||
],
|
],
|
||||||
cta: "SolenOS für Installateure",
|
cta: "SolenOS für Installateure",
|
||||||
|
|||||||
@@ -104,11 +104,12 @@ const operationsScope: ExpandingCard[] = [
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
title: "Heizkostenabrechnung",
|
title: "Heizkostenabrechnung",
|
||||||
text: "Die erfassten Verbrauchsdaten bilden die Grundlage für die jährliche Heizkostenabrechnung.",
|
text: "Aus den erfassten Verbrauchsdaten wird die jährliche Heizkostenabrechnung im Online-Portal erstellt und bereitgestellt.",
|
||||||
points: [
|
points: [
|
||||||
"Verteilung der Wärme- und Warmwasserkosten nach HeizkostenV",
|
"Verteilung der Wärme- und Warmwasserkosten nach HeizkostenV",
|
||||||
"Berücksichtigung von Nutzerwechseln und Leerständen",
|
"Berücksichtigung von Nutzerwechseln und Leerständen",
|
||||||
"Einzelabrechnung je Wohnung mit den Pflichtangaben nach § 6a Absatz 3",
|
"versandfertige Einzelabrechnung je Wohnung im Online-Portal",
|
||||||
|
"Pflichtangaben nach § 6a Absatz 3 HeizkostenV",
|
||||||
],
|
],
|
||||||
to: "/produkte/heizkostenabrechnung",
|
to: "/produkte/heizkostenabrechnung",
|
||||||
},
|
},
|
||||||
@@ -171,7 +172,7 @@ const operationsScope: ExpandingCard[] = [
|
|||||||
title: "Gateway und Datenübertragung",
|
title: "Gateway und Datenübertragung",
|
||||||
text: "Die Messdaten werden zentral gesammelt und an SolenOS übertragen.",
|
text: "Die Messdaten werden zentral gesammelt und an SolenOS übertragen.",
|
||||||
points: [
|
points: [
|
||||||
"ein Gateway je Gebäude empfängt die Funkpakete aller angebundenen Geräte",
|
"die erforderliche Gateway-Infrastruktur wird passend zum Objekt bestimmt",
|
||||||
"Übertragung per Mobilfunk, ohne Internetanschluss im Gebäude",
|
"Übertragung per Mobilfunk, ohne Internetanschluss im Gebäude",
|
||||||
"TLS-verschlüsselte Übertragung an die Plattform",
|
"TLS-verschlüsselte Übertragung an die Plattform",
|
||||||
],
|
],
|
||||||
@@ -191,11 +192,11 @@ const operationsScope: ExpandingCard[] = [
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
title: "Portale und Verwaltung",
|
title: "Portale und Verwaltung",
|
||||||
text: "Gebäude, Wohnungen, Geräte und Verbrauchsdaten werden zentral verwaltet. Bewohner erhalten Zugriff auf die für sie vorgesehenen Informationen.",
|
text: "Eigentümer betreuen Gebäude, Wohnungen, Geräte und Verbrauchsdaten zentral. Bewohner haben ihre persönliche Übersicht im Mieterportal.",
|
||||||
points: [
|
points: [
|
||||||
"Portalzugang für Eigentümer und Verwaltung",
|
"Portalzugang für Eigentümer und Verwaltung",
|
||||||
"Bewohner rufen ihre Information im Mieterportal ab",
|
"eigener Mieterportal-Zugang für jede Wohnung",
|
||||||
"rollenbasierte Zugriffsrechte",
|
"ausschließlich Daten der eigenen Wohnung und des eigenen Nutzungszeitraums sichtbar",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -203,52 +204,42 @@ const operationsScope: ExpandingCard[] = [
|
|||||||
const processSteps = [
|
const processSteps = [
|
||||||
{
|
{
|
||||||
media: <AssetRender render={renders.building} imgClassName="w-52" />,
|
media: <AssetRender render={renders.building} imgClassName="w-52" />,
|
||||||
title: "Gebäude erfassen",
|
title: "Gebäudedaten online erfassen",
|
||||||
description: "Adresse, Wohnungen und Heizart angeben.",
|
description:
|
||||||
},
|
"Adresse, Wohnungen und Heizart online angeben. SolenOS ermittelt daraus die notwendige Ausstattung und prüft sie vor dem Versand.",
|
||||||
{
|
|
||||||
media: (
|
|
||||||
<>
|
|
||||||
<AssetRender render={renders.heatMeter} imgClassName="w-32" />
|
|
||||||
<AssetRender
|
|
||||||
render={renders.smokeAlarm}
|
|
||||||
className="-ml-3 self-start"
|
|
||||||
imgClassName="w-24"
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
title: "Ausstattung bestimmen",
|
|
||||||
description: "SolenOS ermittelt passende Geräte und Mengen.",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: (
|
media: (
|
||||||
<AssetRender render={renders.shippingBoxMeters} imgClassName="w-36" />
|
<AssetRender render={renders.shippingBoxMeters} imgClassName="w-36" />
|
||||||
),
|
),
|
||||||
title: "Vorkonfiguriert erhalten",
|
title: "Vorkonfiguriert erhalten",
|
||||||
description: "Geräte bereits jeder Wohnung zugeordnet geliefert.",
|
description:
|
||||||
|
"Die geprüften Geräte werden bereits den vorgesehenen Wohnungen zugeordnet geliefert.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: <AssetRender render={renders.drillTool} imgClassName="w-32" />,
|
media: <AssetRender render={renders.drillTool} imgClassName="w-32" />,
|
||||||
title: "Geräte montieren",
|
title: "Vor Ort montieren",
|
||||||
description: "Selbst installieren oder Montage beauftragen.",
|
description:
|
||||||
|
"Selbst, mit dem eigenen Fachbetrieb oder durch SolenOS montieren lassen. Eine Softwarekonfiguration vor Ort ist nicht erforderlich.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: (
|
media: (
|
||||||
<AssetRender render={renders.laptopDashboard} imgClassName="w-44" />
|
<AssetRender render={renders.laptopDashboard} imgClassName="w-44" />
|
||||||
),
|
),
|
||||||
title: "Betrieb starten",
|
title: "Betrieb übernehmen lassen",
|
||||||
description: "Bewohner einladen und digital verwalten.",
|
description:
|
||||||
|
"SolenOS übernimmt Einrichtung, Datenübertragung und laufenden Betrieb; Bewohner erhalten ihren Portalzugang.",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const lessEffort = [
|
const lessEffort = [
|
||||||
{
|
{
|
||||||
title: "Vorkonfigurierte Hardware",
|
title: "Zum Einbau vorkonfigurierte Messeinrichtungen",
|
||||||
text: "Geräte werden passend zum jeweiligen Gebäude und zur vorgesehenen Nutzung vorbereitet.",
|
text: "SolenOS bestimmt die Ausstattung aus den Objektdaten, prüft sie und ordnet die Geräte vor dem Versand zu.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Keine aufwendige Einrichtung auf der Baustelle",
|
title: "Keine Softwarekonfiguration vor Ort",
|
||||||
text: "Der Installateur kann sich auf die fachgerechte Montage konzentrieren.",
|
text: "Vor Ort wird nur montiert. Eine Softwarekonfiguration ist nicht erforderlich.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Bestehende Fachbetriebe nutzen",
|
title: "Bestehende Fachbetriebe nutzen",
|
||||||
@@ -308,7 +299,7 @@ const audiences = [
|
|||||||
"Ausstattung aus Gebäudedaten ermitteln",
|
"Ausstattung aus Gebäudedaten ermitteln",
|
||||||
"vorkonfigurierte Geräte erhalten",
|
"vorkonfigurierte Geräte erhalten",
|
||||||
"eigenen Fachbetrieb nutzen",
|
"eigenen Fachbetrieb nutzen",
|
||||||
"laufenden Messbetrieb digital verwalten",
|
"laufenden Messbetrieb digital betreuen",
|
||||||
],
|
],
|
||||||
cta: "SolenOS für Hauseigentümer",
|
cta: "SolenOS für Hauseigentümer",
|
||||||
to: "/fuer-wen/hauseigentuemer",
|
to: "/fuer-wen/hauseigentuemer",
|
||||||
@@ -353,7 +344,7 @@ const audiences = [
|
|||||||
"Geräte- und Verbrauchsdaten",
|
"Geräte- und Verbrauchsdaten",
|
||||||
"UVI",
|
"UVI",
|
||||||
"Heizkostenabrechnungsprozesse",
|
"Heizkostenabrechnungsprozesse",
|
||||||
"White-Label-Optionen",
|
"Optionen für eigenes Logo und Eigenmarke",
|
||||||
],
|
],
|
||||||
cta: "SolenOS für Messdienstleister",
|
cta: "SolenOS für Messdienstleister",
|
||||||
to: "/fuer-wen/messdienstleister",
|
to: "/fuer-wen/messdienstleister",
|
||||||
@@ -409,11 +400,11 @@ const portfolioScopes = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const priceFlow = [
|
const priceFlow = [
|
||||||
{ title: "Wenige Angaben" },
|
{ title: "Leistungen auswählen" },
|
||||||
{ title: "Erste Preisindikation" },
|
{ title: "Gebäudedaten online erfassen" },
|
||||||
{ title: "Konfiguration speichern" },
|
{ title: "Persönlichen Link erhalten" },
|
||||||
{ title: "Gebäude vollständig konfigurieren" },
|
{ title: "Details und Fotos im Portal ergänzen" },
|
||||||
{ title: "Genauer Preis" },
|
{ title: "Geprüftes Gesamtangebot erhalten" },
|
||||||
]
|
]
|
||||||
|
|
||||||
const faqs: FaqItem[] = [
|
const faqs: FaqItem[] = [
|
||||||
@@ -429,19 +420,19 @@ const faqs: FaqItem[] = [
|
|||||||
"In vielen Fällen kann ein vorhandener geeigneter Fachbetrieb eingesetzt werden. Welche Arbeiten erforderlich sind, hängt von der jeweiligen Messtechnik und Einbausituation ab.",
|
"In vielen Fällen kann ein vorhandener geeigneter Fachbetrieb eingesetzt werden. Welche Arbeiten erforderlich sind, hängt von der jeweiligen Messtechnik und Einbausituation ab.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Muss vor Ort jedes Gerät einzeln in SolenOS eingerichtet werden?",
|
question: "Muss vor Ort Software konfiguriert werden?",
|
||||||
answer:
|
answer:
|
||||||
"Die Geräte werden soweit vorgesehen bereits vor dem Versand dem Gebäude und den geplanten Einheiten zugeordnet. Dadurch reduziert sich die Softwareeinrichtung vor Ort deutlich.",
|
"Nein. SolenOS ordnet die Geräte vor dem Versand dem Gebäude und den vorgesehenen Einheiten zu. Vor Ort wird nur montiert; eine Softwarekonfiguration ist nicht erforderlich.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Wie genau ist die erste Preisschätzung?",
|
question: "Wann erhalte ich den verbindlichen Gesamtpreis?",
|
||||||
answer:
|
answer:
|
||||||
"Die erste Schätzung basiert auf wenigen Gebäudedaten und Annahmen zur benötigten Ausstattung. Die vollständige Gebäudekonfiguration bestimmt anschließend die konkreten Geräte und den finalen Preis.",
|
"Nach dem Schnellkonfigurator ergänzen Sie Gebäudedetails und Fotos vorhandener Einbausituationen im Portal. SolenOS prüft die Angaben manuell, bestimmt die konkrete Ausstattung und erstellt anschließend das verbindliche Gesamtangebot.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Kann ich nur UVI buchen?",
|
question: "Welche Leistungen kann ich auswählen?",
|
||||||
answer:
|
answer:
|
||||||
"Ja. UVI und Rauchwarnmelder sind einzeln oder gemeinsam wählbar. Das UVI-Paket umfasst die dafür benötigte Messtechnik und die zugehörigen digitalen Dienstleistungen; die Heizkostenabrechnung baut auf denselben erfassten Verbrauchsdaten auf. Rauchwarnmelder können auch später ergänzt werden – die bereits erfasste Gebäudestruktur wird dabei weiterverwendet.",
|
"Monatliche Verbrauchsinformation, Heizkostenabrechnung und Rauchwarnmelder lassen sich im Schnellkonfigurator unabhängig voneinander hinzufügen oder abwählen."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Kann ich bestehende Messtechnik weiterverwenden?",
|
question: "Kann ich bestehende Messtechnik weiterverwenden?",
|
||||||
@@ -461,10 +452,27 @@ const faqs: FaqItem[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const trustProperties = [
|
const trustProperties = [
|
||||||
{ icon: <GermanyIcon />, label: "Hosting in Deutschland" },
|
{
|
||||||
{ icon: <ShieldCheck />, label: "AES-geschützte Messdaten" },
|
icon: <GermanyIcon />,
|
||||||
{ icon: <Lock />, label: "TLS-verschlüsselte Übertragung" },
|
label: "Daten ausschließlich in Deutschland gehostet",
|
||||||
{ icon: <Users />, label: "Rollenbasierte Zugriffsrechte" },
|
to: "/wissen/datenschutz-sicherheit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <ShieldCheck />,
|
||||||
|
label: "AES-Verschlüsselung schützt gespeicherte Messdaten",
|
||||||
|
to: "/wissen/datenschutz-sicherheit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Lock />,
|
||||||
|
label: "TLS schützt Daten während der Übertragung",
|
||||||
|
to: "/wissen/datenschutz-sicherheit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Users />,
|
||||||
|
label:
|
||||||
|
"Bewohner sehen nur Daten ihrer eigenen Wohnung und ihres eigenen Nutzungszeitraums",
|
||||||
|
to: "/wissen/datenschutz-sicherheit",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
@@ -478,18 +486,18 @@ export default function HomePage() {
|
|||||||
<span className="text-primary">einfach</span> gemacht.
|
<span className="text-primary">einfach</span> gemacht.
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
lead="Fernauslesbare Messtechnik, monatliche UVI, Heizkostenabrechnung und Rauchwarnmelder – vorkonfiguriert geliefert, digital verwaltet und auf Wunsch komplett installiert."
|
lead="Fernauslesbare Messtechnik, monatliche Verbrauchsinformation (UVI), Heizkostenabrechnung und Rauchwarnmelder – vorkonfiguriert geliefert, digital betreut und auf Wunsch komplett installiert."
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="outline" size="lg">
|
<Button asChild variant="outline" size="lg">
|
||||||
<Link to="/so-funktionierts">So funktioniert SolenOS</Link>
|
<Link to="/so-funktionierts">So funktioniert SolenOS</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
note="Wenige Angaben · unverbindliche Kostenschätzung"
|
note="Wenige Angaben · vollständige Prüfung im Folgeprozess"
|
||||||
visual={<HeroArt />}
|
visual={<HeroArt />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -529,17 +537,21 @@ export default function HomePage() {
|
|||||||
align="center"
|
align="center"
|
||||||
eyebrow="Das System"
|
eyebrow="Das System"
|
||||||
title="Alles, was für den laufenden Messbetrieb benötigt wird"
|
title="Alles, was für den laufenden Messbetrieb benötigt wird"
|
||||||
lead="SolenOS verbindet Messtechnik, Datenerfassung und Software zu einem durchgängigen System. Statt einzelne Komponenten selbst zusammenzustellen und miteinander zu verbinden, erhalten Sie eine Lösung, bei der Bestellung, Hardware, Konfiguration und laufender Betrieb zusammenspielen."
|
lead="SolenOS verbindet Messtechnik, Datenerfassung und Software in einem durchgängigen System. Bestellung, Hardware, Konfiguration und laufender Betrieb greifen dabei ineinander."
|
||||||
|
/>
|
||||||
|
<ExpandingCardGrid
|
||||||
|
items={operationsScope}
|
||||||
|
railSide="right"
|
||||||
|
className="mt-12"
|
||||||
/>
|
/>
|
||||||
<ExpandingCardGrid items={operationsScope} className="mt-12" />
|
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Section>
|
<Section>
|
||||||
<div className="rounded-3xl bg-gradient-to-b from-secondary to-card px-6 py-10 sm:px-10 sm:py-12 lg:px-12">
|
<div className="rounded-3xl bg-gradient-to-b from-secondary to-card px-6 py-10 sm:px-10 sm:py-12 lg:px-12">
|
||||||
<SectionHeading
|
<SectionHeading
|
||||||
eyebrow="So funktioniert's"
|
eyebrow="So funktioniert's"
|
||||||
title="In fünf Schritten zum laufenden Messbetrieb"
|
title="Online in vier Schritten zum laufenden Messbetrieb"
|
||||||
lead="Statt Geräte, Software und Messdienst getrennt zu organisieren, verbindet SolenOS die einzelnen Schritte zu einem durchgängigen Ablauf."
|
lead="Sie starten ohne Erstgespräch: Objektdaten online erfassen, die passende Ausstattung von SolenOS bestimmen lassen, vorkonfiguriert erhalten und montieren."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<StepFlow steps={processSteps} className="mt-4" />
|
<StepFlow steps={processSteps} className="mt-4" />
|
||||||
@@ -549,8 +561,8 @@ export default function HomePage() {
|
|||||||
<SectionHeading
|
<SectionHeading
|
||||||
align="center"
|
align="center"
|
||||||
eyebrow="Installation"
|
eyebrow="Installation"
|
||||||
title="Weniger Aufwand vor Ort"
|
title="Vor Ort nur montieren"
|
||||||
lead="Die Installation eines Messsystems sollte nicht daran scheitern, dass vor Ort komplizierte Software eingerichtet oder jedes Gerät manuell zugeordnet werden muss. SolenOS bereitet die digitale Struktur bereits vor der Installation vor."
|
lead="Vor Ort wird nur montiert. Eine Softwarekonfiguration ist nicht erforderlich. SolenOS bereitet Gebäudestruktur und Gerätezuordnung vor dem Versand vor."
|
||||||
/>
|
/>
|
||||||
<div className="mt-12 grid gap-5 sm:grid-cols-2 lg:grid-cols-4">
|
<div className="mt-12 grid gap-5 sm:grid-cols-2 lg:grid-cols-4">
|
||||||
{lessEffort.map((item) => (
|
{lessEffort.map((item) => (
|
||||||
@@ -666,11 +678,11 @@ export default function HomePage() {
|
|||||||
<div>
|
<div>
|
||||||
<SectionHeading
|
<SectionHeading
|
||||||
eyebrow="Preis"
|
eyebrow="Preis"
|
||||||
title="Was kostet SolenOS?"
|
title="Wie entsteht der Gesamtpreis?"
|
||||||
lead="Mit dem SolenOS-Konfigurator erhalten Sie schnell einen ersten Preis und können sofort bestellen."
|
lead="Im Konfigurator wählen Sie Leistungen und erfassen die grundlegenden Gebäudedaten online. Der verbindliche Gesamtpreis folgt nach der vollständigen Konfiguration und manuellen Prüfung."
|
||||||
/>
|
/>
|
||||||
<p className="mt-10 text-sm leading-relaxed text-muted-foreground">
|
<p className="mt-10 text-sm leading-relaxed text-muted-foreground">
|
||||||
Für einen ersten Preis brauchen wir Grundlegende Informationen:
|
Für die erste Ermittlung der Ausstattung benötigen wir:
|
||||||
</p>
|
</p>
|
||||||
<Checklist
|
<Checklist
|
||||||
className="mt-4"
|
className="mt-4"
|
||||||
@@ -683,11 +695,12 @@ export default function HomePage() {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<p className="mt-4 text-sm leading-relaxed text-muted-foreground">
|
<p className="mt-4 text-sm leading-relaxed text-muted-foreground">
|
||||||
Auf Basis dieser Angaben schätzt SolenOS die voraussichtlich
|
SolenOS bestimmt daraus den voraussichtlichen Gerätebedarf. Im
|
||||||
benötigte Geräteanzahl und berechnet einen ungefähren Preis.
|
Folgeprozess ergänzen Sie Details und Fotos; danach erhalten Sie
|
||||||
|
den geprüften Gesamtpreis.
|
||||||
</p>
|
</p>
|
||||||
<Button asChild size="lg" className="mt-6">
|
<Button asChild size="lg" className="mt-6">
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -695,16 +708,16 @@ export default function HomePage() {
|
|||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-base font-bold text-navy">
|
<h3 className="text-base font-bold text-navy">
|
||||||
In fünf Schritten zum genauen Preis
|
In fünf Schritten zum verbindlichen Gesamtangebot
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<NumberedList steps={priceFlow} className="mt-6" />
|
<NumberedList steps={priceFlow} className="mt-6" />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<p className="mt-5 text-xs leading-relaxed text-muted-foreground italic">
|
<p className="mt-5 text-xs leading-relaxed text-muted-foreground italic">
|
||||||
Die erste Berechnung ist eine unverbindliche Preisindikation.
|
SolenOS veröffentlicht keine ungeprüften Preiswerte. Das
|
||||||
Die tatsächliche Ausstattung und der genaue Preis ergeben sich
|
Gesamtangebot enthält die gewählten Leistungen, erforderliche
|
||||||
aus der vollständigen Objektkonfiguration.
|
Gateway-Infrastruktur und die gewählte Montagevariante.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -783,7 +796,7 @@ export default function HomePage() {
|
|||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild variant="inverse" size="lg">
|
<Button asChild variant="inverse" size="lg">
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="inverseOutline" size="lg">
|
<Button asChild variant="inverseOutline" size="lg">
|
||||||
<Link to="/so-funktionierts">So funktioniert SolenOS</Link>
|
<Link to="/so-funktionierts">So funktioniert SolenOS</Link>
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ const steps = [
|
|||||||
<img src={vectors.uviBadge} alt="" className="w-9" />
|
<img src={vectors.uviBadge} alt="" className="w-9" />
|
||||||
</StepMedia>
|
</StepMedia>
|
||||||
),
|
),
|
||||||
title: "Gebäude anlegen und bestellen",
|
title: "Gebäudedaten online erfassen",
|
||||||
description:
|
description:
|
||||||
"Bei der Konfiguration werden Gebäude, Wohnungen und die benötigten Leistungen erfasst. Auf Basis dieser Daten wird automatisch ermittelt, welche Messtechnik, Rauchwarnmelder und weiteren Komponenten benötigt werden.",
|
"Sie erfassen Gebäude, Wohnungen und Leistungen online. SolenOS ermittelt daraus die notwendige Ausstattung und prüft sie vor dem Versand.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: (
|
media: (
|
||||||
@@ -51,13 +51,12 @@ const steps = [
|
|||||||
<AssetRender render={renders.gateway} imgClassName="w-9" />
|
<AssetRender render={renders.gateway} imgClassName="w-9" />
|
||||||
</StepMedia>
|
</StepMedia>
|
||||||
),
|
),
|
||||||
title: "Geräte montieren",
|
title: "Vor Ort nur montieren",
|
||||||
description: (
|
description: (
|
||||||
<>
|
<>
|
||||||
Die Geräte müssen vor Ort im Wesentlichen nur noch fachgerecht montiert
|
Die vorgesehenen Geräte werden vor Ort fachgerecht montiert.{" "}
|
||||||
werden.{" "}
|
|
||||||
<strong className="font-bold text-navy">
|
<strong className="font-bold text-navy">
|
||||||
Keine aufwendige Softwarekonfiguration bei der Installation.
|
Eine Softwarekonfiguration vor Ort ist nicht erforderlich.
|
||||||
</strong>
|
</strong>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
@@ -86,13 +85,15 @@ const steps = [
|
|||||||
const journey = [
|
const journey = [
|
||||||
"Besucher versteht SolenOS",
|
"Besucher versteht SolenOS",
|
||||||
"identifiziert seinen Anwendungsfall",
|
"identifiziert seinen Anwendungsfall",
|
||||||
"berechnet einen ungefähren Preis",
|
"wählt Leistungen aus",
|
||||||
"speichert seine Konfiguration",
|
"erfasst Gebäudedaten online",
|
||||||
"ergänzt die tatsächlichen Gebäudedaten",
|
"erhält einen persönlichen Link",
|
||||||
"erhält den genauen Preis",
|
"ergänzt Details und Fotos",
|
||||||
|
"SolenOS prüft die Ausstattung",
|
||||||
|
"erhält ein verbindliches Gesamtangebot",
|
||||||
"erteilt den Auftrag",
|
"erteilt den Auftrag",
|
||||||
"SolenOS bereitet Gebäude und Geräte vor",
|
"SolenOS bereitet Gebäude und Geräte vor",
|
||||||
"vorkonfigurierte Hardware wird geliefert",
|
"vorkonfigurierte Technik wird geliefert",
|
||||||
"Montage vor Ort",
|
"Montage vor Ort",
|
||||||
"automatischer laufender Betrieb",
|
"automatischer laufender Betrieb",
|
||||||
]
|
]
|
||||||
@@ -101,22 +102,22 @@ const faqs: FaqItem[] = [
|
|||||||
{
|
{
|
||||||
question: "Wo fange ich an?",
|
question: "Wo fange ich an?",
|
||||||
answer:
|
answer:
|
||||||
"Im Konfigurator. Dort erfassen Sie Gebäude, Wohnungen und die benötigten Leistungen und erhalten eine erste Preisindikation. Aus denselben Daten wird anschließend der Auftrag aufgebaut.",
|
"Im Konfigurator. Dort wählen Sie Leistungen und erfassen Gebäude sowie Wohnungen online. Die Angaben werden in die anschließende Detailkonfiguration übernommen.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Wie verbindlich ist der Preis aus dem Konfigurator?",
|
question: "Wann erhalte ich den verbindlichen Gesamtpreis?",
|
||||||
answer:
|
answer:
|
||||||
"Er ist eine Preisschätzung auf Basis Ihrer Angaben. Den genauen Preis erhalten Sie, sobald die tatsächlichen Gebäudedaten ergänzt und geprüft sind – erst danach wird der Auftrag erteilt.",
|
"Nach dem Schnellkonfigurator ergänzen Sie Gebäudedetails und Fotos im Portal. SolenOS prüft die Einbausituationen und die notwendige Ausstattung manuell und erstellt anschließend das verbindliche Gesamtangebot.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Muss ich meine Gebäudedaten mehrfach erfassen?",
|
question: "Muss ich meine Gebäudedaten mehrfach erfassen?",
|
||||||
answer:
|
answer:
|
||||||
"Nein. Die einmal eingegebenen Gebäudedaten werden durch den gesamten Prozess weiterverwendet: von der Preisschätzung über die Gerätevorbereitung bis in den laufenden Betrieb.",
|
"Nein. Die einmal eingegebenen Gebäudedaten werden von der ersten Online-Erfassung über Gerätevorbereitung und Montage bis in den laufenden Betrieb weiterverwendet.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Wer montiert die Geräte?",
|
question: "Wer montiert die Geräte?",
|
||||||
answer:
|
answer:
|
||||||
"Das entscheiden Sie: Sie selbst, Ihr Fachbetrieb oder SolenOS als Komplettlösung. Die Hardware kommt objektbezogen vorkonfiguriert an, eine aufwendige Softwarekonfiguration vor Ort entfällt.",
|
"Das entscheiden Sie: Sie selbst, Ihr Fachbetrieb oder SolenOS als Komplettlösung. Die Technik kommt objektbezogen vorkonfiguriert an; eine Softwarekonfiguration vor Ort ist nicht erforderlich.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Was passiert nach der Installation?",
|
question: "Was passiert nach der Installation?",
|
||||||
@@ -182,8 +183,8 @@ export default function HowItWorksPage() {
|
|||||||
sondern durch den gesamten Prozess weiterverwendet.
|
sondern durch den gesamten Prozess weiterverwendet.
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-6 font-mono text-xs tracking-wide text-muted-foreground uppercase">
|
<p className="mt-6 font-mono text-xs tracking-wide text-muted-foreground uppercase">
|
||||||
Preisschätzung → Konfiguration → Bestellung → Gerätevorbereitung →
|
Online-Erfassung → Detailkonfiguration → Gesamtangebot →
|
||||||
Installation → Betrieb
|
Gerätevorbereitung → Installation → Betrieb
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
@@ -194,7 +195,7 @@ export default function HowItWorksPage() {
|
|||||||
align="center"
|
align="center"
|
||||||
eyebrow="Häufige Fragen"
|
eyebrow="Häufige Fragen"
|
||||||
title="Fragen zum Ablauf"
|
title="Fragen zum Ablauf"
|
||||||
lead="Von der ersten Preisindikation bis zum laufenden Betrieb – die häufigsten Fragen zum SolenOS-Prozess."
|
lead="Von der Online-Erfassung bis zum laufenden Betrieb – die häufigsten Fragen zum SolenOS-Prozess."
|
||||||
/>
|
/>
|
||||||
<FaqAccordion className="mt-10" items={faqs} />
|
<FaqAccordion className="mt-10" items={faqs} />
|
||||||
</Section>
|
</Section>
|
||||||
@@ -203,11 +204,11 @@ export default function HowItWorksPage() {
|
|||||||
<Section className="pt-0">
|
<Section className="pt-0">
|
||||||
<CtaBanner
|
<CtaBanner
|
||||||
icon={<Calculator />}
|
icon={<Calculator />}
|
||||||
title="Was kostet SolenOS für Ihr Gebäude?"
|
title="Konfiguration für Ihr Gebäude starten"
|
||||||
description="Mit wenigen Angaben erhalten Sie eine erste Preisindikation."
|
description="Leistungen auswählen, Gebäudedaten online erfassen und die geprüfte Ausstattung vorbereiten."
|
||||||
actions={
|
actions={
|
||||||
<Button variant="inverse" size="lg" asChild>
|
<Button variant="inverse" size="lg" asChild>
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import {
|
|||||||
} from "@/components/solenos/illustrations"
|
} from "@/components/solenos/illustrations"
|
||||||
|
|
||||||
const trustItems = [
|
const trustItems = [
|
||||||
{ icon: ClipboardCheck, label: ["Klare", "Vertragsstruktur"] },
|
{ icon: ClipboardCheck, label: ["Geprüfter", "Leistungsumfang"] },
|
||||||
{ icon: ShieldCheck, label: ["Keine versteckten", "Gebühren"] },
|
{ icon: ShieldCheck, label: ["Verbindliches", "Gesamtangebot"] },
|
||||||
{ icon: Users2, label: ["Rabatte für", "große Objekte"] },
|
{ icon: Users2, label: ["Passend zum", "konkreten Objekt"] },
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export default function KlarpreisPage() {
|
export default function KlarpreisPage() {
|
||||||
@@ -35,7 +35,7 @@ export default function KlarpreisPage() {
|
|||||||
SolenOS <span className="text-primary">Klarpreis</span>
|
SolenOS <span className="text-primary">Klarpreis</span>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
lead="Drei sauber getrennte Leistungen. Einfache Preise. Keine Überraschungen."
|
lead="Ein vollständiger Leistungsumfang und ein verbindlicher Gesamtpreis nach Prüfung der konkreten Objektdaten."
|
||||||
extra={
|
extra={
|
||||||
<div className="inline-flex items-center gap-3 rounded-full border border-border bg-card px-4 py-2 text-sm text-muted-foreground shadow-pill">
|
<div className="inline-flex items-center gap-3 rounded-full border border-border bg-card px-4 py-2 text-sm text-muted-foreground shadow-pill">
|
||||||
<IconBadge variant="soft" size="sm">
|
<IconBadge variant="soft" size="sm">
|
||||||
@@ -57,20 +57,18 @@ export default function KlarpreisPage() {
|
|||||||
<Section className="pt-0">
|
<Section className="pt-0">
|
||||||
<div className="grid gap-6 lg:grid-cols-3">
|
<div className="grid gap-6 lg:grid-cols-3">
|
||||||
<PriceCard
|
<PriceCard
|
||||||
title="RWM-Hardware"
|
title="Rauchwarnmelder"
|
||||||
cadence="Einmalig"
|
cadence="Gesamtangebot"
|
||||||
price="42,00 €"
|
price="Nach Prüfung"
|
||||||
unit="je Wohnung einmalig"
|
unit="Geräteanzahl und Montagevariante"
|
||||||
allocation={{ label: "Nicht umlagefähig", tone: "negative" }}
|
description="Benötigte Rauchwarnmelder, vereinbarte Montage und Eigentumsübertragung."
|
||||||
description="Rauchwarnmelder inklusive Montage und Eigentumsübertragung."
|
|
||||||
media={<SmokeDetectorIllustration />}
|
media={<SmokeDetectorIllustration />}
|
||||||
/>
|
/>
|
||||||
<PriceCard
|
<PriceCard
|
||||||
title="Ferninspektion"
|
title="Ferninspektion"
|
||||||
cadence="Monatlich"
|
cadence="Gesamtangebot"
|
||||||
price="2,20 €"
|
price="Nach Prüfung"
|
||||||
unit="je Wohnung / Monat"
|
unit="passend zum vereinbarten Leistungsumfang"
|
||||||
allocation={{ label: "Grundsätzlich umlagefähig", tone: "positive" }}
|
|
||||||
description="Regelmäßige Prüfung, Nachweise, Meldungen und Support."
|
description="Regelmäßige Prüfung, Nachweise, Meldungen und Support."
|
||||||
media={
|
media={
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -80,16 +78,11 @@ export default function KlarpreisPage() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<PriceCard
|
<PriceCard
|
||||||
title={
|
title="Messbetrieb und Abrechnung"
|
||||||
<span className="text-[1.15rem] whitespace-nowrap">
|
cadence="Gesamtangebot"
|
||||||
UVI-Komplettbetrieb
|
price="Nach Prüfung"
|
||||||
</span>
|
unit="nach vollständiger Objektkonfiguration"
|
||||||
}
|
description="Je nach Auswahl: Messtechnik, erforderliche Gateway-Infrastruktur, Daten, Portale, Heizkostenabrechnung und monatliche Verbrauchsinformation (UVI)."
|
||||||
cadence="Monatlich"
|
|
||||||
price="10,50 €"
|
|
||||||
unit="je Wohnung / Monat"
|
|
||||||
allocation={{ label: "Grundsätzlich umlagefähig", tone: "positive" }}
|
|
||||||
description="Sensoren, Daten, Portal und Verbrauchsinformation inklusive."
|
|
||||||
media={<SensorCubesIllustration />}
|
media={<SensorCubesIllustration />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -102,16 +95,13 @@ export default function KlarpreisPage() {
|
|||||||
</IconBadge>
|
</IconBadge>
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-white/80">
|
<div className="font-semibold text-white/80">
|
||||||
Gesamtkosten laufend
|
Verbindlicher Gesamtpreis
|
||||||
</div>
|
|
||||||
<div className="mt-1 flex flex-wrap items-baseline gap-x-3">
|
|
||||||
<span className="text-4xl font-extrabold tracking-tight text-white">
|
|
||||||
12,70 €
|
|
||||||
</span>
|
|
||||||
<span className="text-sm text-white/75">
|
|
||||||
je Wohnung / Monat
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="mt-1 max-w-md text-sm leading-relaxed text-white/85">
|
||||||
|
Nach der vollständigen Objektkonfiguration und manuellen
|
||||||
|
Prüfung erhalten Sie ein Gesamtangebot statt ungeprüfter
|
||||||
|
Einzelpreise.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Separator
|
<Separator
|
||||||
orientation="vertical"
|
orientation="vertical"
|
||||||
@@ -121,9 +111,9 @@ export default function KlarpreisPage() {
|
|||||||
<IconBadge variant="glass" size="sm">
|
<IconBadge variant="glass" size="sm">
|
||||||
<Tag />
|
<Tag />
|
||||||
</IconBadge>
|
</IconBadge>
|
||||||
<p className="max-w-56 text-sm leading-snug text-white/80">
|
<p className="max-w-64 text-sm leading-snug text-white/80">
|
||||||
Alle laufenden Leistungen klar gebündelt – ohne versteckte
|
Gewählte Leistungen, erforderliche Gateway-Infrastruktur und
|
||||||
Zusatzkosten.
|
Montagevariante werden gemeinsam ausgewiesen.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -194,18 +194,18 @@ export default function HeizkostenabrechnungProductPage() {
|
|||||||
eyebrow="Produkt"
|
eyebrow="Produkt"
|
||||||
title={<>Heizkosten­abrechnung</>}
|
title={<>Heizkosten­abrechnung</>}
|
||||||
tagline="Aus den Daten, die ohnehin laufen."
|
tagline="Aus den Daten, die ohnehin laufen."
|
||||||
lead="Die jährliche Abrechnung der Heiz- und Warmwasserkosten entsteht aus denselben fernabgelesenen Verbrauchswerten wie die monatliche UVI – verteilt nach den Maßstäben der Heizkostenverordnung, ohne Ablesetermin im Gebäude."
|
lead="Die jährliche Abrechnung der Heiz- und Warmwasserkosten entsteht aus denselben fernabgelesenen Verbrauchswerten wie die monatliche Verbrauchsinformation (UVI) – verteilt nach den Maßstäben der Heizkostenverordnung, ohne Ablesetermin im Gebäude."
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">Preis für mein Gebäude berechnen</Link>
|
<Link to="/konfigurator">Konfiguration für mein Gebäude starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="outline" size="lg">
|
<Button asChild variant="outline" size="lg">
|
||||||
<Link to="/produkte/uvi">UVI ansehen</Link>
|
<Link to="/produkte/uvi">Verbrauchsinformation ansehen</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
note="Wenige Angaben · unverbindliche Kostenschätzung"
|
note="Wenige Angaben · vollständige Prüfung im Folgeprozess"
|
||||||
visual={<BillingHeroArt />}
|
visual={<BillingHeroArt />}
|
||||||
features={[
|
features={[
|
||||||
{
|
{
|
||||||
@@ -238,7 +238,7 @@ export default function HeizkostenabrechnungProductPage() {
|
|||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild variant="inverse" size="lg">
|
<Button asChild variant="inverse" size="lg">
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="inverseOutline" size="lg">
|
<Button asChild variant="inverseOutline" size="lg">
|
||||||
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
||||||
|
|||||||
@@ -101,11 +101,11 @@ export default function ProductsPage() {
|
|||||||
<Section className="pt-0">
|
<Section className="pt-0">
|
||||||
<CtaBanner
|
<CtaBanner
|
||||||
icon={<Euro />}
|
icon={<Euro />}
|
||||||
title="Jetzt Preis für Ihr Gebäude berechnen"
|
title="Ausstattung für Ihr Gebäude konfigurieren"
|
||||||
description="In wenigen Minuten zur ersten Preisindikation."
|
description="Leistungen auswählen, Gebäudedaten online erfassen und die Prüfung vorbereiten."
|
||||||
actions={
|
actions={
|
||||||
<Button variant="inverse" size="lg" asChild>
|
<Button variant="inverse" size="lg" asChild>
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ const DATA_PATH = [
|
|||||||
media: <AssetRender render={renders.gateway} imgClassName="w-28" />,
|
media: <AssetRender render={renders.gateway} imgClassName="w-28" />,
|
||||||
title: "Gateway sammelt",
|
title: "Gateway sammelt",
|
||||||
description:
|
description:
|
||||||
"Ein Gateway je Gebäude empfängt die Funkpakete aller angebundenen Geräte.",
|
"Die erforderliche Gateway-Infrastruktur empfängt die Funkpakete der angebundenen Geräte und wird von SolenOS passend zum Objekt bestimmt.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
media: (
|
media: (
|
||||||
@@ -167,7 +167,7 @@ const FAQS: FaqItem[] = [
|
|||||||
{
|
{
|
||||||
question: "Was kostet die Messtechnik?",
|
question: "Was kostet die Messtechnik?",
|
||||||
answer:
|
answer:
|
||||||
"Die für den Messbetrieb benötigten Sensoren sind im UVI-Komplettbetrieb enthalten: 10,50 € je Wohnung und Monat, grundsätzlich umlagefähig. Welche Geräte in welcher Anzahl erforderlich sind, ergibt sich aus der Gebäudekonfiguration.",
|
"SolenOS bestimmt die benötigten Sensoren und die erforderliche Gateway-Infrastruktur aus der vollständigen Gebäudekonfiguration. Beides wird im geprüften Gesamtangebot gemeinsam mit den gewählten Leistungen ausgewiesen; ungeprüfte Einzelpreise veröffentlichen wir nicht.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Kann ich vorhandene Zähler weiterverwenden?",
|
question: "Kann ich vorhandene Zähler weiterverwenden?",
|
||||||
@@ -202,11 +202,11 @@ export default function MesstechnikProductPage() {
|
|||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
tagline="Die Grundlage für alles andere."
|
tagline="Die Grundlage für alles andere."
|
||||||
lead="Zähler, Heizkostenverteiler und Gateway erfassen und übertragen die Werte, aus denen UVI und Heizkostenabrechnung entstehen – fernablesbar, interoperabel und objektbezogen vorkonfiguriert geliefert."
|
lead="Zähler, Heizkostenverteiler und Gateway erfassen und übertragen die Werte, aus denen monatliche Verbrauchsinformation (UVI) und Heizkostenabrechnung entstehen – fernablesbar, interoperabel und objektbezogen vorkonfiguriert geliefert."
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">Ausstattung und Preis ermitteln</Link>
|
<Link to="/konfigurator">Ausstattung ermitteln</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="outline" size="lg">
|
<Button asChild variant="outline" size="lg">
|
||||||
<Link to="/wissen/datenschutz-sicherheit">
|
<Link to="/wissen/datenschutz-sicherheit">
|
||||||
@@ -215,7 +215,7 @@ export default function MesstechnikProductPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
note="Wenige Angaben · unverbindliche Kostenschätzung"
|
note="Wenige Angaben · vollständige Prüfung im Folgeprozess"
|
||||||
visual={<InfrastructureHeroArt />}
|
visual={<InfrastructureHeroArt />}
|
||||||
features={[
|
features={[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ type Product = {
|
|||||||
const PRODUCTS: Product[] = [
|
const PRODUCTS: Product[] = [
|
||||||
{
|
{
|
||||||
to: "/produkte/uvi",
|
to: "/produkte/uvi",
|
||||||
label: "UVI",
|
label: "Verbrauchsinformation (UVI)",
|
||||||
title: "UVI",
|
title: "Verbrauchsinformation (UVI)",
|
||||||
sub: "Monatliche Verbrauchsinformation",
|
sub: "Monatlich für Bewohner",
|
||||||
summary:
|
summary:
|
||||||
"Verbrauchsdaten werden automatisch erfasst und die monatliche Verbrauchsinformation für die Bewohner erzeugt und bereitgestellt – ohne Ablesetermin in der Wohnung.",
|
"Verbrauchsdaten werden automatisch erfasst und die monatliche Verbrauchsinformation für die Bewohner erzeugt und bereitgestellt – ohne Ablesetermin in der Wohnung.",
|
||||||
icon: icons.uvi,
|
icon: icons.uvi,
|
||||||
@@ -102,6 +102,7 @@ function ProductPage({
|
|||||||
lead,
|
lead,
|
||||||
actions,
|
actions,
|
||||||
note,
|
note,
|
||||||
|
extra,
|
||||||
visual,
|
visual,
|
||||||
features,
|
features,
|
||||||
children,
|
children,
|
||||||
@@ -116,6 +117,7 @@ function ProductPage({
|
|||||||
lead?: React.ReactNode
|
lead?: React.ReactNode
|
||||||
actions?: React.ReactNode
|
actions?: React.ReactNode
|
||||||
note?: React.ReactNode
|
note?: React.ReactNode
|
||||||
|
extra?: React.ReactNode
|
||||||
visual?: React.ReactNode
|
visual?: React.ReactNode
|
||||||
features: FeatureBandItem[]
|
features: FeatureBandItem[]
|
||||||
/** the product's spec sections between feature band and closing */
|
/** the product's spec sections between feature band and closing */
|
||||||
@@ -140,6 +142,7 @@ function ProductPage({
|
|||||||
}
|
}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
note={note}
|
note={note}
|
||||||
|
extra={extra}
|
||||||
visual={visual}
|
visual={visual}
|
||||||
/>
|
/>
|
||||||
<Container>
|
<Container>
|
||||||
|
|||||||
@@ -199,14 +199,14 @@ export default function RauchwarnmelderProductPage() {
|
|||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">Preis für mein Gebäude berechnen</Link>
|
<Link to="/konfigurator">Konfiguration für mein Gebäude starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="outline" size="lg">
|
<Button asChild variant="outline" size="lg">
|
||||||
<Link to="/klarpreis">Preise ansehen</Link>
|
<Link to="/klarpreis">Gesamtangebot ansehen</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
note="Wenige Angaben · unverbindliche Kostenschätzung"
|
note="Wenige Angaben · vollständige Prüfung im Folgeprozess"
|
||||||
visual={<SmokeAlarmHeroArt />}
|
visual={<SmokeAlarmHeroArt />}
|
||||||
features={[
|
features={[
|
||||||
{
|
{
|
||||||
@@ -239,7 +239,7 @@ export default function RauchwarnmelderProductPage() {
|
|||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild variant="inverse" size="lg">
|
<Button asChild variant="inverse" size="lg">
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="inverseOutline" size="lg">
|
<Button asChild variant="inverseOutline" size="lg">
|
||||||
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
||||||
@@ -283,29 +283,24 @@ export default function RauchwarnmelderProductPage() {
|
|||||||
|
|
||||||
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
||||||
<SectionHeading
|
<SectionHeading
|
||||||
eyebrow="Preis"
|
eyebrow="Gesamtangebot"
|
||||||
title="Hardware einmalig, Betrieb monatlich"
|
title="Hardware, Ferninspektion und Montage transparent zusammenführen"
|
||||||
lead="Die Rauchwarnmelder werden einmalig abgerechnet und gehen in Ihr Eigentum über. Die laufende Ferninspektion wird monatlich je Wohnung berechnet."
|
lead="Geräteanzahl, Inspektionsumfang und gewählte Montagevariante werden nach der vollständigen Objektkonfiguration geprüft und gemeinsam angeboten."
|
||||||
/>
|
/>
|
||||||
<div className="mt-10 grid gap-6 lg:grid-cols-[1fr_1fr_1.1fr]">
|
<div className="mt-10 grid gap-6 lg:grid-cols-[1fr_1fr_1.1fr]">
|
||||||
<PriceCard
|
<PriceCard
|
||||||
title="RWM-Hardware"
|
title="Rauchwarnmelder"
|
||||||
cadence="Einmalig"
|
cadence="Gesamtangebot"
|
||||||
price="42,00 €"
|
price="Nach Prüfung"
|
||||||
unit="je Wohnung einmalig"
|
unit="Geräteanzahl und Montagevariante"
|
||||||
allocation={{ label: "Nicht umlagefähig", tone: "negative" }}
|
description="Benötigte Rauchwarnmelder, vereinbarte Montage und Eigentumsübertragung."
|
||||||
description="Rauchwarnmelder inklusive Montage und Eigentumsübertragung."
|
|
||||||
media={<SmokeDetectorIllustration />}
|
media={<SmokeDetectorIllustration />}
|
||||||
/>
|
/>
|
||||||
<PriceCard
|
<PriceCard
|
||||||
title="Ferninspektion"
|
title="Ferninspektion"
|
||||||
cadence="Monatlich"
|
cadence="Gesamtangebot"
|
||||||
price="2,20 €"
|
price="Nach Prüfung"
|
||||||
unit="je Wohnung / Monat"
|
unit="passend zum vereinbarten Leistungsumfang"
|
||||||
allocation={{
|
|
||||||
label: "Grundsätzlich umlagefähig",
|
|
||||||
tone: "positive",
|
|
||||||
}}
|
|
||||||
description="Regelmäßige Prüfung, Nachweise, Meldungen und Support."
|
description="Regelmäßige Prüfung, Nachweise, Meldungen und Support."
|
||||||
media={
|
media={
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -322,8 +317,8 @@ export default function RauchwarnmelderProductPage() {
|
|||||||
variant="link"
|
variant="link"
|
||||||
className="mt-6 h-auto self-start p-0 font-bold"
|
className="mt-6 h-auto self-start p-0 font-bold"
|
||||||
>
|
>
|
||||||
<Link to="/klarpreis">
|
<Link to="/konfigurator">
|
||||||
Alle Preise im SolenOS Klarpreis
|
Gesamtangebot konfigurieren
|
||||||
<ArrowRight />
|
<ArrowRight />
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -149,11 +149,11 @@ const FAQS: FaqItem[] = [
|
|||||||
export default function UviProductPage() {
|
export default function UviProductPage() {
|
||||||
return (
|
return (
|
||||||
<ProductPage
|
<ProductPage
|
||||||
breadcrumb="UVI"
|
breadcrumb="Verbrauchsinformation (UVI)"
|
||||||
eyebrow="Produkt"
|
eyebrow="Produkt"
|
||||||
title={
|
title={
|
||||||
<span className="block text-[2.25rem] text-pretty sm:text-[2.75rem]">
|
<span className="block text-[2.25rem] text-pretty sm:text-[2.75rem]">
|
||||||
Unterjährige Verbrauchs­information
|
Unterjährige Verbrauchs­information (UVI)
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
tagline="Monatlich. Automatisch. Nachweisbar."
|
tagline="Monatlich. Automatisch. Nachweisbar."
|
||||||
@@ -161,7 +161,7 @@ export default function UviProductPage() {
|
|||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild size="lg">
|
<Button asChild size="lg">
|
||||||
<Link to="/konfigurator">Preis für mein Gebäude berechnen</Link>
|
<Link to="/konfigurator">Konfiguration für mein Gebäude starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="outline" size="lg">
|
<Button asChild variant="outline" size="lg">
|
||||||
<Link to="/wissen/gesetzliche-anforderungen">
|
<Link to="/wissen/gesetzliche-anforderungen">
|
||||||
@@ -170,7 +170,45 @@ export default function UviProductPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
note="Wenige Angaben · unverbindliche Kostenschätzung"
|
note="Wenige Angaben · vollständige Prüfung im Folgeprozess"
|
||||||
|
extra={
|
||||||
|
<div
|
||||||
|
role="note"
|
||||||
|
className="rounded-2xl border border-brand-300 bg-brand-50/80 p-4 shadow-card"
|
||||||
|
>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Euro
|
||||||
|
aria-hidden="true"
|
||||||
|
className="mt-0.5 size-6 shrink-0 text-brand-700"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<p className="font-extrabold text-navy">
|
||||||
|
Bis zu 3 % Kürzungsrecht
|
||||||
|
</p>
|
||||||
|
<p className="mt-1 text-sm leading-relaxed text-muted-foreground">
|
||||||
|
Fehlt die monatliche Verbrauchsinformation oder ist sie
|
||||||
|
unvollständig, können Nutzer ihren Kostenanteil um 3 %
|
||||||
|
kürzen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3 flex flex-wrap items-center gap-x-4 gap-y-2 text-sm font-semibold">
|
||||||
|
<Link
|
||||||
|
to="/wissen/gesetzliche-anforderungen"
|
||||||
|
className="inline-flex items-center gap-1 text-brand-800 underline decoration-brand-400 underline-offset-4"
|
||||||
|
>
|
||||||
|
Anforderungen im Detail
|
||||||
|
<ArrowRight className="size-4" />
|
||||||
|
</Link>
|
||||||
|
<a
|
||||||
|
href={heizkostenv("6a")}
|
||||||
|
className="text-muted-foreground underline underline-offset-4"
|
||||||
|
>
|
||||||
|
Quelle: § 6a HeizkostenV
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
visual={<UviHeroArt />}
|
visual={<UviHeroArt />}
|
||||||
features={[
|
features={[
|
||||||
{
|
{
|
||||||
@@ -198,12 +236,12 @@ export default function UviProductPage() {
|
|||||||
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
<Section className="pt-0 sm:pt-0 lg:pt-0">
|
||||||
<CtaBanner
|
<CtaBanner
|
||||||
icon={<Euro />}
|
icon={<Euro />}
|
||||||
title="Was kostet die UVI für Ihr Gebäude?"
|
title="Verbrauchsinformation für Ihr Gebäude konfigurieren"
|
||||||
description="Mit wenigen Angaben zu Gebäude, Wohnungen und Wärmeverteilung erhalten Sie eine erste Preisindikation."
|
description="Gebäude und Leistungen online erfassen; SolenOS prüft anschließend Ausstattung und Gesamtpreis."
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<Button asChild variant="inverse" size="lg">
|
<Button asChild variant="inverse" size="lg">
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="inverseOutline" size="lg">
|
<Button asChild variant="inverseOutline" size="lg">
|
||||||
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
||||||
@@ -302,19 +340,11 @@ export default function UviProductPage() {
|
|||||||
</Card>
|
</Card>
|
||||||
<div>
|
<div>
|
||||||
<PriceCard
|
<PriceCard
|
||||||
title={
|
title="Monatliche Verbrauchsinformation (UVI)"
|
||||||
<span className="text-[1.15rem] whitespace-nowrap">
|
cadence="Gesamtangebot"
|
||||||
UVI-Komplettbetrieb
|
price="Nach Prüfung"
|
||||||
</span>
|
unit="nach vollständiger Objektkonfiguration"
|
||||||
}
|
description="Messtechnik, erforderliche Gateway-Infrastruktur, Daten, Portal und Verbrauchsinformation werden gemeinsam angeboten."
|
||||||
cadence="Monatlich"
|
|
||||||
price="10,50 €"
|
|
||||||
unit="je Wohnung / Monat"
|
|
||||||
allocation={{
|
|
||||||
label: "Grundsätzlich umlagefähig",
|
|
||||||
tone: "positive",
|
|
||||||
}}
|
|
||||||
description="Sensoren, Daten, Portal und Verbrauchsinformation inklusive."
|
|
||||||
media={
|
media={
|
||||||
<AssetRender
|
<AssetRender
|
||||||
render={renders.uviGlassPane}
|
render={renders.uviGlassPane}
|
||||||
@@ -324,8 +354,8 @@ export default function UviProductPage() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Button asChild variant="link" className="mt-4 h-auto p-0 font-bold">
|
<Button asChild variant="link" className="mt-4 h-auto p-0 font-bold">
|
||||||
<Link to="/klarpreis">
|
<Link to="/konfigurator">
|
||||||
Alle Preise im SolenOS Klarpreis
|
Gesamtangebot konfigurieren
|
||||||
<ArrowRight />
|
<ArrowRight />
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export default function DatenschutzSicherheitPage() {
|
|||||||
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="inverseOutline" size="lg">
|
<Button asChild variant="inverseOutline" size="lg">
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export default function GesetzlicheAnforderungenPage() {
|
|||||||
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
<Link to="/kontakt">Kontakt aufnehmen</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="inverseOutline" size="lg">
|
<Button asChild variant="inverseOutline" size="lg">
|
||||||
<Link to="/konfigurator">Preis berechnen</Link>
|
<Link to="/konfigurator">Konfiguration starten</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user