From bc971a1a4d3e8738a390c27738763457ee8ac458 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 18:22:44 +0000 Subject: [PATCH] Changes Co-authored-by: wolfoftyreso-debug <250630591+wolfoftyreso-debug@users.noreply.github.com> --- src/App.tsx | 2 + src/pages/ChangeSubscription.tsx | 216 +++++++++++++++++++++++++++++++ supabase/config.toml | 3 + 3 files changed, 221 insertions(+) create mode 100644 src/pages/ChangeSubscription.tsx diff --git a/src/App.tsx b/src/App.tsx index ba9379f..3912121 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import Contact from "./pages/Contact"; import Admin from "./pages/Admin"; import FAQ from "./pages/FAQ"; import OrderConfirmation from "./pages/OrderConfirmation"; +import ChangeSubscription from "./pages/ChangeSubscription"; import { PaymentTestModeBanner } from "@/components/PaymentTestModeBanner"; const queryClient = new QueryClient(); @@ -31,6 +32,7 @@ function AppContent() { } /> } /> } /> + } /> {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} } /> diff --git a/src/pages/ChangeSubscription.tsx b/src/pages/ChangeSubscription.tsx new file mode 100644 index 0000000..c1bfd66 --- /dev/null +++ b/src/pages/ChangeSubscription.tsx @@ -0,0 +1,216 @@ +import { useEffect, useMemo, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { supabase } from "@/integrations/supabase/client"; +import { useAuth } from "@/hooks/useAuth"; +import { useToast } from "@/hooks/use-toast"; +import { getStripeEnvironment, hasPaymentsConfigured } from "@/lib/stripe"; +import Header from "@/components/Header"; +import { Button } from "@/components/ui/button"; +import { ArrowLeft, Loader2 } from "lucide-react"; + +const PRICE_PER_KG_EXKL = 325; +const VAT_RATE = 0.25; +const PRICE_PER_KG_INK = PRICE_PER_KG_EXKL * (1 + VAT_RATE); +const WEEKS_PER_MONTH = 4; + +const ChangeSubscription = () => { + const navigate = useNavigate(); + const { user, loading: authLoading } = useAuth(); + const { toast } = useToast(); + const [currentKg, setCurrentKg] = useState(null); + const [newKg, setNewKg] = useState(10); + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); + + useEffect(() => { + if (!authLoading && !user) navigate("/"); + }, [authLoading, user, navigate]); + + useEffect(() => { + (async () => { + if (!user) return; + const env = hasPaymentsConfigured() ? getStripeEnvironment() : "sandbox"; + const { data } = await supabase + .from("subscriptions") + .select("kg_per_week, status") + .eq("user_id", user.id) + .eq("environment", env) + .in("status", ["active", "trialing", "past_due"]) + .order("created_at", { ascending: false }) + .limit(1) + .maybeSingle(); + + if (!data) { + toast({ + title: "Inget aktivt abonnemang", + description: "Du behöver ett aktivt abonnemang för att ändra mängd.", + variant: "destructive", + }); + navigate("/account"); + return; + } + const kg = Number(data.kg_per_week ?? 10); + setCurrentKg(kg); + setNewKg(kg); + setLoading(false); + })(); + }, [user, navigate, toast]); + + const newMonthlyInk = useMemo( + () => newKg * WEEKS_PER_MONTH * PRICE_PER_KG_INK, + [newKg], + ); + const currentMonthlyInk = useMemo( + () => (currentKg ?? 0) * WEEKS_PER_MONTH * PRICE_PER_KG_INK, + [currentKg], + ); + const diff = newMonthlyInk - currentMonthlyInk; + const unchanged = currentKg !== null && newKg === currentKg; + + const handleSave = async () => { + if (!hasPaymentsConfigured()) { + toast({ title: "Betalningar inte konfigurerade", variant: "destructive" }); + return; + } + setSaving(true); + try { + const { data, error } = await supabase.functions.invoke("update-subscription-quantity", { + body: { new_kg_per_week: newKg, environment: getStripeEnvironment() }, + }); + if (error) throw error; + if ((data as any)?.error) throw new Error((data as any).error); + toast({ + title: "Abonnemang uppdaterat", + description: `Ny mängd: ${newKg} kg/vecka. Prisdifferens justeras på nästa faktura.`, + }); + navigate("/account"); + } catch (e: any) { + toast({ + title: "Kunde inte uppdatera", + description: e?.message ?? String(e), + variant: "destructive", + }); + } finally { + setSaving(false); + } + }; + + if (authLoading || loading) { + return ( +
+
+
+ +
+
+ ); + } + + return ( +
+
+
+
+ + +
+
+

+ Ändra abonnemang +

+

+ Justera antal kg kakor per vecka +

+
+ +
+
+
+ Ny mängd +
+
+ {newKg} kg +
+
per vecka
+
+ +
+ setNewKg(parseInt(e.target.value, 10))} + className="calculator-slider w-full" + aria-label="Kg per vecka" + /> +
+ 1 kg + 100 kg +
+
+ +
+
+ Nuvarande månadskostnad + + {Math.round(currentMonthlyInk).toLocaleString("sv-SE")} kr + +
+
+ Ny månadskostnad + + {Math.round(newMonthlyInk).toLocaleString("sv-SE")} kr + +
+ {!unchanged && ( +
+ Skillnad + 0 ? "text-foreground" : "text-primary" + }`} + > + {diff > 0 ? "+" : ""} + {Math.round(diff).toLocaleString("sv-SE")} kr/mån + +
+ )} +

+ ink moms · prisdifferens proportioneras på nästa faktura +

+
+ + +
+
+
+
+ ); +}; + +export default ChangeSubscription; diff --git a/supabase/config.toml b/supabase/config.toml index d8caa1e..7724f20 100644 --- a/supabase/config.toml +++ b/supabase/config.toml @@ -20,3 +20,6 @@ verify_jwt = false [functions.create-portal-session] verify_jwt = false + +[functions.update-subscription-quantity] +verify_jwt = false