Files
alva/src/components/PlansSection.tsx
T
gpt-engineer-app[bot] 807c208226 Changes
Co-authored-by: wolfoftyreso-debug <250630591+wolfoftyreso-debug@users.noreply.github.com>
2026-07-12 14:03:32 +00:00

708 lines
30 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useMemo, useEffect } from "react";
import { Loader2, CheckCircle2, CreditCard, FileText, ChevronsUpDown, Check, Lock, Eye, EyeOff, Sparkles } from "lucide-react";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/hooks/useAuth";
import { toast } from "sonner";
import { z } from "zod";
import { StripeEmbeddedCheckout } from "@/components/StripeEmbeddedCheckout";
import { getStripeEnvironment, hasPaymentsConfigured } from "@/lib/stripe";
import { cn } from "@/lib/utils";
const STORSTOCKHOLM_CITIES = [
"Stockholm", "Solna", "Sundbyberg", "Nacka", "Lidingö", "Danderyd",
"Täby", "Sollentuna", "Järfälla", "Upplands Väsby", "Sigtuna",
"Vallentuna", "Österåker", "Vaxholm", "Värmdö", "Tyresö", "Haninge",
"Nynäshamn", "Botkyrka", "Salem", "Södertälje", "Nykvarn", "Huddinge",
"Bromma", "Ekerö", "Upplands-Bro",
];
// Map första 3 siffrorna i postnummer → kommun/ort inom Storstockholm.
const POSTAL_PREFIX_TO_CITY: Record<string, string> = {
"100": "Stockholm", "101": "Stockholm", "102": "Stockholm", "103": "Stockholm",
"104": "Stockholm", "105": "Stockholm", "106": "Stockholm", "107": "Stockholm",
"108": "Stockholm", "110": "Stockholm", "111": "Stockholm", "112": "Stockholm",
"113": "Stockholm", "114": "Stockholm", "115": "Stockholm", "116": "Stockholm",
"117": "Stockholm", "118": "Stockholm", "119": "Stockholm", "120": "Stockholm",
"121": "Stockholm", "122": "Stockholm", "123": "Stockholm", "124": "Stockholm",
"125": "Stockholm", "126": "Stockholm", "127": "Stockholm", "128": "Stockholm",
"129": "Stockholm",
"131": "Nacka", "132": "Nacka", "133": "Nacka", "138": "Nacka",
"134": "Värmdö", "139": "Värmdö",
"135": "Tyresö",
"136": "Haninge", "137": "Haninge",
"141": "Huddinge", "142": "Huddinge", "143": "Huddinge",
"144": "Salem",
"145": "Botkyrka", "146": "Botkyrka", "147": "Botkyrka",
"148": "Nynäshamn", "149": "Nynäshamn",
"150": "Södertälje", "151": "Södertälje", "152": "Södertälje", "153": "Södertälje",
"155": "Nykvarn",
"168": "Bromma", "169": "Bromma",
"170": "Solna", "171": "Solna", "173": "Solna",
"172": "Sundbyberg", "174": "Sundbyberg",
"175": "Järfälla", "176": "Järfälla", "177": "Järfälla",
"178": "Ekerö", "179": "Ekerö",
"181": "Lidingö",
"182": "Danderyd",
"183": "Täby", "187": "Täby",
"184": "Österåker",
"185": "Vaxholm",
"186": "Vallentuna",
"191": "Sollentuna", "192": "Sollentuna",
"193": "Sigtuna", "195": "Sigtuna",
"194": "Upplands Väsby",
"196": "Upplands-Bro", "197": "Upplands-Bro",
};
const cityFromPostalCode = (postalCode: string): string | null => {
const cleaned = postalCode.replace(/\s/g, "");
if (!/^\d{5}$/.test(cleaned)) return null;
return POSTAL_PREFIX_TO_CITY[cleaned.slice(0, 3)] ?? null;
};
const PRICE_PER_KG_EXKL = 325; // exkl. moms, används för Stripe/faktura
const VAT_RATE = 0.25;
const PRICE_PER_KG = PRICE_PER_KG_EXKL * (1 + VAT_RATE); // 406,25 kr ink moms visas för kunden
const KG_PER_EMPLOYEE = 0.3;
const WEEKS_PER_MONTH = 4;
const isStockholmPostalCode = (postalCode: string) => {
const cleaned = postalCode.replace(/\s/g, "");
if (!/^\d{5}$/.test(cleaned)) return false;
const num = parseInt(cleaned, 10);
return num >= 10000 && num <= 19999;
};
const stockholmDeliveryMessage = "Vi levererar endast till företag inom Storstockholm.";
const formSchema = z.object({
företag: z.string().trim().min(1, "Fyll i företagsnamn").max(100),
epost: z.string().trim().email("Ange en giltig e-postadress").max(255),
telefon: z.string().trim().max(30).optional(),
adress: z.string().trim().min(1, "Fyll i leveransadress").max(200),
postnummer: z
.string()
.trim()
.min(1, "Fyll i postnummer")
.refine(isStockholmPostalCode, "Vi levererar endast inom Storstockholm (100 00 199 99)"),
stad: z.string().trim().min(1, "Fyll i stad").max(100),
kommentarer: z.string().trim().max(1000).optional(),
password: z.string().max(100).optional(),
});
type Method = "card" | "invoice";
const PlansSection = () => {
const { user } = useAuth();
const [employees, setEmployees] = useState(10);
const [showForm, setShowForm] = useState(false);
const [method, setMethod] = useState<Method>("card");
const [submitting, setSubmitting] = useState(false);
const [submitted, setSubmitted] = useState<null | "card" | "invoice">(null);
const [errors, setErrors] = useState<Record<string, string>>({});
const [clientSecret, setClientSecret] = useState<string | null>(null);
const [cityOpen, setCityOpen] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const [form, setForm] = useState({
företag: "",
epost: "",
telefon: "",
adress: "",
postnummer: "",
stad: "",
kommentarer: "",
password: "",
});
const filteredCities = useMemo(() => {
const query = form.stad.trim().toLocaleLowerCase("sv-SE");
if (!query) return STORSTOCKHOLM_CITIES;
return STORSTOCKHOLM_CITIES.filter((city) =>
city.toLocaleLowerCase("sv-SE").includes(query)
);
}, [form.stad]);
const recommendedKg = useMemo(
() => Math.max(1, Math.round(employees * KG_PER_EMPLOYEE)),
[employees]
);
const weeklyPrice = recommendedKg * PRICE_PER_KG;
const monthlyPrice = weeklyPrice * WEEKS_PER_MONTH;
useEffect(() => {
if (!user || !showForm) return;
(async () => {
const { data } = await supabase
.from("profiles")
.select("company_name, phone, street_address, postal_code, city")
.eq("user_id", user.id)
.maybeSingle();
setForm((prev) => {
const postalCode = prev.postnummer || data?.postal_code || "";
const suggestedCity = cityFromPostalCode(postalCode);
return {
...prev,
företag: prev.företag || data?.company_name || "",
epost: prev.epost || user.email || "",
telefon: prev.telefon || data?.phone || "",
adress: prev.adress || data?.street_address || "",
postnummer: postalCode,
stad: suggestedCity || prev.stad || data?.city || "",
};
});
})();
}, [user, showForm]);
useEffect(() => {
const suggestedCity = cityFromPostalCode(form.postnummer);
if (!suggestedCity || form.stad === suggestedCity) return;
setForm((prev) => ({ ...prev, stad: suggestedCity }));
setErrors((prev) => ({ ...prev, stad: "", postnummer: "" }));
}, [form.postnummer, form.stad]);
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
setForm((p) => {
const next = { ...p, [name]: value };
if (name === "postnummer") {
const suggested = cityFromPostalCode(value);
if (suggested) next.stad = suggested;
}
return next;
});
if (errors[name]) setErrors((p) => ({ ...p, [name]: "" }));
if (name === "postnummer") {
setErrors((p) => ({ ...p, postnummer: "", stad: "" }));
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const result = formSchema.safeParse(form);
if (!result.success) {
const fe: Record<string, string> = {};
result.error.errors.forEach((err) => {
if (err.path[0]) fe[err.path[0] as string] = err.message;
});
setErrors(fe);
return;
}
// Password required for guests (auto-create account)
if (!user) {
const pw = form.password || "";
if (pw.length < 8) {
setErrors((prev) => ({ ...prev, password: "Lösenordet måste vara minst 8 tecken" }));
return;
}
}
if (!hasPaymentsConfigured()) {
toast.error("Betalningar är inte konfigurerade ännu.");
return;
}
setSubmitting(true);
try {
// Auto-create account for guests, then sign in
if (!user && form.password) {
const { data: accData, error: accErr } = await supabase.functions.invoke("create-account", {
body: {
email: result.data.epost,
password: form.password,
company: result.data.företag,
phone: result.data.telefon ?? "",
},
});
if (accErr) throw accErr;
if ((accData as any)?.error) throw new Error((accData as any).error);
const { error: signInErr } = await supabase.auth.signInWithPassword({
email: result.data.epost,
password: form.password,
});
if (signInErr) {
if ((accData as any)?.existed) {
throw new Error(
"Ett konto finns redan för denna e-post. Fel lösenord — logga in eller använd 'Glömt lösenord'.",
);
}
throw signInErr;
}
}
const body = {
method,
employees,
kg_per_week: recommendedKg,
company: result.data.företag,
email: result.data.epost,
phone: result.data.telefon ?? "",
address: result.data.adress,
postal_code: result.data.postnummer,
city: result.data.stad,
comments: result.data.kommentarer ?? "",
return_url: `${window.location.origin}/order-confirmation?session_id={CHECKOUT_SESSION_ID}&method=card&kg=${recommendedKg}&email=${encodeURIComponent(result.data.epost)}`,
environment: getStripeEnvironment(),
};
const { data, error } = await supabase.functions.invoke("create-checkout", { body });
if (error) throw error;
if ((data as any)?.error) throw new Error((data as any).error);
if (method === "card") {
if (!(data as any)?.clientSecret) throw new Error("Kunde inte skapa checkout-session");
setClientSecret((data as any).clientSecret);
} else {
window.location.href = `/order-confirmation?method=invoice&kg=${recommendedKg}&email=${encodeURIComponent(result.data.epost)}`;
return;
}
} catch (err: any) {
console.error(err);
toast.error(err?.message || "Kunde inte starta abonnemang. Försök igen.");
} finally {
setSubmitting(false);
}
};
// Show embedded checkout after we get clientSecret
if (clientSecret) {
return (
<section id="abonnemang" className="py-16 md:py-28 px-6 bg-background">
<div className="max-w-3xl mx-auto">
<div className="text-center mb-8">
<div className="w-24 h-px bg-primary/40 mx-auto mb-6"></div>
<h2 className="font-display text-3xl md:text-5xl font-semibold mb-2">
Slutför betalning
</h2>
<p className="text-muted-foreground text-sm">
{recommendedKg} kg/vecka · {monthlyPrice.toLocaleString("sv-SE")} kr/månad (ink moms)
</p>
</div>
<div className="bg-card border border-border rounded-sm p-4 md:p-6">
<StripeEmbeddedCheckout fetchClientSecret={async () => clientSecret} />
</div>
<div className="text-center mt-4">
<button
onClick={() => setClientSecret(null)}
className="text-sm text-muted-foreground underline hover:text-foreground"
>
Avbryt och tillbaka
</button>
</div>
</div>
</section>
);
}
return (
<section id="abonnemang" className="py-16 md:py-28 px-6 bg-background">
<div className="max-w-3xl mx-auto">
<div className="text-center mb-10 md:mb-14">
<div className="w-24 h-px bg-primary/40 mx-auto mb-6"></div>
<h2 className="font-display text-3xl md:text-5xl font-semibold mb-4">
Hur många anställda har ni?
</h2>
<p className="text-muted-foreground text-base md:text-lg max-w-xl mx-auto">
Vi rekommenderar automatiskt rätt mängd kakor utifrån antalet medarbetare.
</p>
</div>
<div className="bg-card border border-border rounded-sm shadow-[0_10px_40px_-15px_rgba(0,0,0,0.15)] p-6 md:p-12">
{submitted === "invoice" ? (
<div className="text-center py-8 animate-fade-in">
<CheckCircle2 className="w-16 h-16 text-primary mx-auto mb-4" />
<h3 className="font-display text-3xl md:text-4xl font-semibold mb-3">
Abonnemang startat!
</h3>
<p className="text-muted-foreground max-w-md mx-auto">
Vi har skapat ditt abonnemang {" "}
<strong className="text-foreground">
{recommendedKg} kg kakor per vecka
</strong>
. Första fakturan skickas till <strong>{form.epost}</strong> inom kort.
</p>
</div>
) : !showForm ? (
<>
<div className="text-center mb-8">
<div
key={employees}
className="font-display text-6xl md:text-8xl font-semibold text-primary tabular-nums animate-fade-in"
>
{employees}
</div>
<div className="text-muted-foreground text-sm md:text-base mt-2 tracking-wide uppercase">
{employees === 1 ? "anställd" : "anställda"}
</div>
</div>
<div className="mb-10 md:mb-12">
<input
type="range"
min={1}
max={100}
step={1}
value={employees}
onChange={(e) => setEmployees(parseInt(e.target.value, 10))}
className="calculator-slider w-full"
aria-label="Antal anställda"
/>
<div className="flex justify-between text-xs text-muted-foreground mt-3">
<span>1</span>
<span>100</span>
</div>
</div>
<div className="text-center border-t border-border pt-8 md:pt-10 space-y-6">
<div>
<div className="text-muted-foreground text-xs md:text-sm uppercase tracking-widest mb-2">
Rekommenderad mängd
</div>
<div className="font-display text-4xl md:text-5xl font-semibold text-foreground tabular-nums">
{recommendedKg} kg
</div>
<div className="text-muted-foreground text-sm mt-1">per vecka</div>
</div>
<div>
<div className="text-muted-foreground text-xs md:text-sm uppercase tracking-widest mb-2">
Pris per månad
</div>
<div className="font-display text-3xl md:text-4xl font-semibold text-primary tabular-nums">
{monthlyPrice.toLocaleString("sv-SE")} kr
</div>
<div className="text-muted-foreground text-xs mt-1">
ink moms
</div>
</div>
<button
onClick={() => setShowForm(true)}
className="btn-classic w-full py-4 text-base md:text-lg rounded-sm mt-2"
>
Starta abonnemang
</button>
</div>
</>
) : (
<form onSubmit={handleSubmit} className="space-y-5 animate-fade-in">
<div className="text-center mb-2">
<div className="text-muted-foreground text-xs uppercase tracking-widest mb-1">
Ditt abonnemang
</div>
<div className="font-display text-2xl md:text-3xl font-semibold">
{recommendedKg} kg/vecka {" "}
<span className="text-primary">
{monthlyPrice.toLocaleString("sv-SE")} kr/mån
</span>
</div>
<div className="text-muted-foreground text-xs">
ink moms · {employees} {employees === 1 ? "anställd" : "anställda"}
</div>
</div>
{/* Betalningsmetod */}
<div>
<label className="block mb-2 text-sm font-semibold">Betalningsmetod</label>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<button
type="button"
onClick={() => setMethod("card")}
className={`flex items-center gap-3 p-4 rounded-sm border text-left transition-colors ${
method === "card"
? "border-primary bg-primary/5"
: "border-border hover:border-primary/50"
}`}
>
<CreditCard className="w-5 h-5 text-primary" />
<div>
<div className="font-semibold text-sm">Kort</div>
<div className="text-xs text-muted-foreground">
Automatiskt varje månad
</div>
</div>
</button>
<button
type="button"
onClick={() => setMethod("invoice")}
className={`flex items-center gap-3 p-4 rounded-sm border text-left transition-colors ${
method === "invoice"
? "border-primary bg-primary/5"
: "border-border hover:border-primary/50"
}`}
>
<FileText className="w-5 h-5 text-primary" />
<div>
<div className="font-semibold text-sm">Faktura</div>
<div className="text-xs text-muted-foreground">
Månadsvis via e-post
</div>
</div>
</button>
</div>
</div>
<div className="border border-primary/30 bg-primary/5 px-4 py-3 rounded-sm text-sm text-foreground">
{stockholmDeliveryMessage} Ange postnummer 100 00199 99 för att vidare.
</div>
<div>
<label className="block mb-1.5 text-sm font-semibold">
Företagsnamn <span className="text-primary">*</span>
</label>
<input
name="företag"
value={form.företag}
onChange={handleChange}
className="w-full px-4 py-3 rounded-sm bg-background border border-border focus:outline-none focus:ring-2 focus:ring-primary/30"
/>
{errors.företag && (
<p className="text-destructive text-xs mt-1">{errors.företag}</p>
)}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-1.5 text-sm font-semibold">
E-post <span className="text-primary">*</span>
</label>
<input
type="email"
name="epost"
value={form.epost}
onChange={handleChange}
className="w-full px-4 py-3 rounded-sm bg-background border border-border focus:outline-none focus:ring-2 focus:ring-primary/30"
/>
{errors.epost && (
<p className="text-destructive text-xs mt-1">{errors.epost}</p>
)}
</div>
<div>
<label className="block mb-1.5 text-sm font-semibold">Telefon</label>
<input
type="tel"
name="telefon"
value={form.telefon}
onChange={handleChange}
className="w-full px-4 py-3 rounded-sm bg-background border border-border focus:outline-none focus:ring-2 focus:ring-primary/30"
/>
</div>
</div>
{!user && (
<div className="relative overflow-hidden rounded-sm border border-primary/40 bg-gradient-to-br from-primary/[0.06] via-background to-primary/[0.03] p-5 md:p-6 shadow-[0_2px_20px_-8px_rgba(0,0,0,0.15)]">
<div className="absolute -top-10 -right-10 w-32 h-32 rounded-full bg-primary/10 blur-2xl pointer-events-none" />
<div className="relative flex items-start gap-3 mb-4">
<div className="flex-shrink-0 w-10 h-10 rounded-full bg-primary/15 flex items-center justify-center border border-primary/30">
<Sparkles className="w-5 h-5 text-primary" />
</div>
<div>
<div className="font-display text-lg md:text-xl font-semibold text-foreground leading-tight">
Ditt konto skapas automatiskt
</div>
<p className="text-muted-foreground text-xs md:text-sm mt-1 leading-relaxed">
Välj ett lösenord loggar vi in dig direkt. Hantera ditt abonnemang, ändra leveranser och se fakturor i "Mitt konto" när som helst.
</p>
</div>
</div>
<label className="block mb-1.5 text-sm font-semibold text-foreground">
Välj lösenord <span className="text-primary">*</span>
</label>
<div className="relative">
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground pointer-events-none" />
<input
name="password"
type={showPassword ? "text" : "password"}
value={form.password}
onChange={handleChange}
placeholder="Minst 8 tecken"
autoComplete="new-password"
aria-invalid={!!errors.password}
className="w-full pl-10 pr-11 py-3 rounded-sm bg-background border border-border focus:outline-none focus:ring-2 focus:ring-primary/40 focus:border-primary/60 transition-colors"
/>
<button
type="button"
onClick={() => setShowPassword((s) => !s)}
aria-label={showPassword ? "Dölj lösenord" : "Visa lösenord"}
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors"
>
{showPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
{errors.password ? (
<p className="text-destructive text-xs mt-1.5">{errors.password}</p>
) : (
<p className="text-muted-foreground text-xs mt-1.5">
Använd minst 8 tecken. Vi rekommenderar en blandning av bokstäver och siffror.
</p>
)}
</div>
)}
<div>
<label className="block mb-1.5 text-sm font-semibold">
Leveransadress <span className="text-primary">*</span>
</label>
<input
name="adress"
placeholder="Gatuadress, t.ex. Kungsgatan 12"
value={form.adress}
onChange={handleChange}
aria-invalid={!!errors.adress}
className="w-full px-4 py-3 rounded-sm bg-background border border-border focus:outline-none focus:ring-2 focus:ring-primary/30"
/>
{errors.adress && (
<p className="text-destructive text-xs mt-1">{errors.adress}</p>
)}
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="block mb-1.5 text-sm font-semibold">
Postnummer <span className="text-primary">*</span>
</label>
<input
name="postnummer"
placeholder="t.ex. 114 32"
value={form.postnummer}
onChange={handleChange}
aria-invalid={!!errors.postnummer}
className="w-full px-4 py-3 rounded-sm bg-background border border-border focus:outline-none focus:ring-2 focus:ring-primary/30"
/>
{errors.postnummer && (
<p className="text-destructive text-xs mt-1">{errors.postnummer}</p>
)}
<p className="text-muted-foreground text-xs mt-1">
Endast postnummer inom Storstockholm.
</p>
</div>
<div>
<label className="block mb-1.5 text-sm font-semibold">
Stad <span className="text-primary">*</span>
</label>
<div className="relative">
<div className="relative">
<input
name="stad"
role="combobox"
aria-expanded={cityOpen}
aria-controls="city-options"
aria-autocomplete="list"
aria-invalid={!!errors.stad}
placeholder="Sök eller välj stad..."
value={form.stad}
onFocus={() => setCityOpen(true)}
onBlur={() => window.setTimeout(() => setCityOpen(false), 120)}
onChange={(e) => {
handleChange(e);
setCityOpen(true);
}}
className="w-full px-4 py-3 pr-10 rounded-sm bg-background border border-border focus:outline-none focus:ring-2 focus:ring-primary/30"
/>
<button
type="button"
aria-label="Visa städer"
onMouseDown={(e) => e.preventDefault()}
onClick={() => setCityOpen((open) => !open)}
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
>
<ChevronsUpDown className="h-4 w-4" />
</button>
</div>
{cityOpen && (
<div
id="city-options"
role="listbox"
className="absolute z-50 mt-1 max-h-56 w-full overflow-auto rounded-sm border border-border bg-popover shadow-md"
>
{filteredCities.length > 0 ? (
filteredCities.map((city) => (
<button
key={city}
type="button"
role="option"
aria-selected={form.stad === city}
onMouseDown={(e) => e.preventDefault()}
onClick={() => {
setForm((f) => ({ ...f, stad: city }));
setErrors((e) => ({ ...e, stad: "" }));
setCityOpen(false);
}}
className={cn(
"flex w-full items-center gap-2 px-3 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground",
form.stad === city && "bg-accent text-accent-foreground"
)}
>
<Check className={cn("h-4 w-4", form.stad === city ? "opacity-100" : "opacity-0")} />
<span>{city}</span>
</button>
))
) : (
<div className="px-3 py-2 text-sm text-muted-foreground">
Ingen stad hittades.
</div>
)}
</div>
)}
</div>
{errors.stad && (
<p className="text-destructive text-xs mt-1">{errors.stad}</p>
)}
</div>
</div>
<div>
<label className="block mb-1.5 text-sm font-semibold">Kommentarer</label>
<textarea
name="kommentarer"
value={form.kommentarer}
onChange={handleChange}
rows={3}
className="w-full px-4 py-3 rounded-sm bg-background border border-border focus:outline-none focus:ring-2 focus:ring-primary/30"
/>
</div>
<div className="flex flex-col sm:flex-row gap-3 pt-2">
<button
type="button"
onClick={() => setShowForm(false)}
disabled={submitting}
className="sm:w-1/3 py-3 rounded-sm border border-border hover:bg-muted text-sm"
>
Tillbaka
</button>
<button
type="submit"
disabled={submitting}
className="btn-classic flex-1 py-3 rounded-sm disabled:opacity-50 flex items-center justify-center gap-2"
>
{submitting ? (
<>
<Loader2 className="w-4 h-4 animate-spin" />
{method === "card" ? "Öppnar betalning..." : "Startar abonnemang..."}
</>
) : method === "card" ? (
"Fortsätt till betalning"
) : (
"Starta abonnemang (faktura)"
)}
</button>
</div>
<p className="text-center text-muted-foreground text-xs">
Alla priser inklusive moms (25%).
</p>
</form>
)}
</div>
</div>
</section>
);
};
export default PlansSection;