Changes
Co-authored-by: wolfoftyreso-debug <250630591+wolfoftyreso-debug@users.noreply.github.com>
This commit is contained in:
+1
-2
@@ -12,12 +12,11 @@ import AccountConfirmation from "./pages/AccountConfirmation";
|
|||||||
import Contact from "./pages/Contact";
|
import Contact from "./pages/Contact";
|
||||||
import Admin from "./pages/Admin";
|
import Admin from "./pages/Admin";
|
||||||
import FAQ from "./pages/FAQ";
|
import FAQ from "./pages/FAQ";
|
||||||
import { useCartSync } from "./hooks/useCartSync";
|
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
function AppContent() {
|
function AppContent() {
|
||||||
useCartSync();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import AccountMenu from "./AccountMenu";
|
import AccountMenu from "./AccountMenu";
|
||||||
import CartDrawer from "./CartDrawer";
|
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
return (
|
return (
|
||||||
@@ -13,7 +12,6 @@ const Header = () => {
|
|||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<CartDrawer />
|
|
||||||
<AccountMenu />
|
<AccountMenu />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -21,4 +19,4 @@ const Header = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { useState, useMemo } from "react";
|
import { useState, useMemo } from "react";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2, CreditCard, FileText } from "lucide-react";
|
||||||
import { useShopifyProducts } from "@/hooks/useShopifyProducts";
|
import { useShopifyProducts } from "@/hooks/useShopifyProducts";
|
||||||
import { useCartStore } from "@/stores/cartStore";
|
import {
|
||||||
|
storefrontApiRequest,
|
||||||
|
CART_CREATE_MUTATION,
|
||||||
|
formatCheckoutUrl,
|
||||||
|
} from "@/lib/shopify";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
const PRICE_PER_KG = 325;
|
const PRICE_PER_KG = 325;
|
||||||
@@ -19,12 +23,15 @@ const pickPlan = (kg: number) => {
|
|||||||
return match || availablePlans[availablePlans.length - 1];
|
return match || availablePlans[availablePlans.length - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type PaymentMethod = "card" | "invoice";
|
||||||
|
|
||||||
const PlansSection = () => {
|
const PlansSection = () => {
|
||||||
const [employees, setEmployees] = useState(10);
|
const [employees, setEmployees] = useState(10);
|
||||||
const [checkoutLoading, setCheckoutLoading] = useState(false);
|
const [loadingMethod, setLoadingMethod] = useState<PaymentMethod | null>(null);
|
||||||
|
|
||||||
const { products, isLoading: productsLoading } = useShopifyProducts("product_type:Abonnemang");
|
const { products, isLoading: productsLoading } = useShopifyProducts(
|
||||||
const { addItem, clearCart, isLoading: cartLoading } = useCartStore();
|
"product_type:Abonnemang"
|
||||||
|
);
|
||||||
|
|
||||||
const recommendedKg = useMemo(
|
const recommendedKg = useMemo(
|
||||||
() => Math.max(1, Math.round(employees * KG_PER_EMPLOYEE)),
|
() => Math.max(1, Math.round(employees * KG_PER_EMPLOYEE)),
|
||||||
@@ -32,7 +39,7 @@ const PlansSection = () => {
|
|||||||
);
|
);
|
||||||
const weeklyPrice = recommendedKg * PRICE_PER_KG;
|
const weeklyPrice = recommendedKg * PRICE_PER_KG;
|
||||||
|
|
||||||
const handleStart = async () => {
|
const handleStart = async (method: PaymentMethod) => {
|
||||||
const plan = pickPlan(recommendedKg);
|
const plan = pickPlan(recommendedKg);
|
||||||
const shopifyProduct = products.find((p) => p.node.handle === plan.handle);
|
const shopifyProduct = products.find((p) => p.node.handle === plan.handle);
|
||||||
|
|
||||||
@@ -46,29 +53,46 @@ const PlansSection = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCheckoutLoading(true);
|
setLoadingMethod(method);
|
||||||
try {
|
try {
|
||||||
clearCart();
|
const data = await storefrontApiRequest(CART_CREATE_MUTATION, {
|
||||||
await addItem({
|
input: {
|
||||||
product: shopifyProduct,
|
lines: [{ quantity: 1, merchandiseId: variant.id }],
|
||||||
variantId: variant.id,
|
attributes: [
|
||||||
variantTitle: variant.title,
|
{ key: "Antal anställda", value: String(employees) },
|
||||||
price: variant.price,
|
{ key: "Rekommenderad mängd", value: `${recommendedKg} kg/vecka` },
|
||||||
quantity: 1,
|
{ key: "Veckopris (exkl. moms)", value: `${weeklyPrice} kr` },
|
||||||
selectedOptions: variant.selectedOptions || [],
|
{
|
||||||
});
|
key: "Önskad betalningsmetod",
|
||||||
toast.success(`Abonnemang tillagt (${plan.name} – ${plan.kg} kg/vecka)`, {
|
value: method === "card" ? "Automatiskt kort varje månad" : "Månadsfaktura",
|
||||||
description: "Klicka på varukorgen för att gå till betalning",
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const errors = data?.data?.cartCreate?.userErrors || [];
|
||||||
|
if (errors.length > 0) {
|
||||||
|
console.error("Cart creation failed:", errors);
|
||||||
|
toast.error("Kunde inte skapa checkout");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkoutUrl = data?.data?.cartCreate?.cart?.checkoutUrl;
|
||||||
|
if (!checkoutUrl) {
|
||||||
|
toast.error("Ingen checkout-länk mottagen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.open(formatCheckoutUrl(checkoutUrl), "_blank");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
toast.error("Något gick fel");
|
toast.error("Något gick fel");
|
||||||
} finally {
|
} finally {
|
||||||
setCheckoutLoading(false);
|
setLoadingMethod(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLoading = productsLoading || cartLoading || checkoutLoading;
|
const isBusy = productsLoading || loadingMethod !== null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="abonnemang" className="py-16 md:py-28 px-6 bg-background">
|
<section id="abonnemang" className="py-16 md:py-28 px-6 bg-background">
|
||||||
@@ -139,20 +163,40 @@ const PlansSection = () => {
|
|||||||
<div className="text-muted-foreground text-xs mt-1">exklusive moms</div>
|
<div className="text-muted-foreground text-xs mt-1">exklusive moms</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
{/* Two CTAs — pick payment method, then straight to Shopify checkout */}
|
||||||
onClick={handleStart}
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 pt-2">
|
||||||
disabled={isLoading}
|
<button
|
||||||
className="btn-classic w-full py-4 text-base md:text-lg rounded-sm disabled:opacity-50 mt-4"
|
onClick={() => handleStart("card")}
|
||||||
>
|
disabled={isBusy}
|
||||||
{isLoading ? (
|
className="btn-classic py-4 px-4 text-base rounded-sm disabled:opacity-50 flex items-center justify-center gap-2"
|
||||||
<span className="flex items-center justify-center gap-2">
|
>
|
||||||
|
{loadingMethod === "card" ? (
|
||||||
<Loader2 className="w-5 h-5 animate-spin" />
|
<Loader2 className="w-5 h-5 animate-spin" />
|
||||||
Laddar...
|
) : (
|
||||||
</span>
|
<>
|
||||||
) : (
|
<CreditCard className="w-5 h-5" />
|
||||||
"Starta abonnemang"
|
<span>Automatiskt varje månad</span>
|
||||||
)}
|
</>
|
||||||
</button>
|
)}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleStart("invoice")}
|
||||||
|
disabled={isBusy}
|
||||||
|
className="py-4 px-4 text-base rounded-sm border-2 border-primary text-primary hover:bg-primary hover:text-primary-foreground transition-colors disabled:opacity-50 flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
{loadingMethod === "invoice" ? (
|
||||||
|
<Loader2 className="w-5 h-5 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<FileText className="w-5 h-5" />
|
||||||
|
<span>Månadsfaktura</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p className="text-muted-foreground text-xs">
|
||||||
|
Du slutför beställningen säkert hos Shopify.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user