Legt obligatorisk adress

X-Lovable-Edit-ID: edt-26169ea6-0c33-440a-a5e3-2aacf6f1d0cc
Co-authored-by: wolfoftyreso-debug <250630591+wolfoftyreso-debug@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-07-11 13:57:56 +00:00
3 changed files with 83 additions and 34 deletions
+32 -8
View File
@@ -24,13 +24,13 @@ 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().max(200).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().max(100).optional(),
stad: z.string().trim().min(1, "Fyll i stad").max(100),
kommentarer: z.string().trim().max(1000).optional(),
});
@@ -67,7 +67,7 @@ const PlansSection = () => {
(async () => {
const { data } = await supabase
.from("profiles")
.select("company_name, phone, street_address, postal_code")
.select("company_name, phone, street_address, postal_code, city")
.eq("user_id", user.id)
.maybeSingle();
setForm((prev) => ({
@@ -77,6 +77,7 @@ const PlansSection = () => {
telefon: prev.telefon || data?.phone || "",
adress: prev.adress || data?.street_address || "",
postnummer: prev.postnummer || data?.postal_code || "",
stad: prev.stad || data?.city || "",
}));
})();
}, [user, showForm]);
@@ -118,9 +119,9 @@ const PlansSection = () => {
company: result.data.företag,
email: result.data.epost,
phone: result.data.telefon ?? "",
address: result.data.adress ?? "",
address: result.data.adress,
postal_code: result.data.postnummer,
city: "Storstockholm",
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(),
@@ -371,16 +372,23 @@ const PlansSection = () => {
</div>
<div>
<label className="block mb-1.5 text-sm font-semibold">Leveransadress</label>
<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>
<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>
@@ -397,9 +405,25 @@ const PlansSection = () => {
<p className="text-destructive text-xs mt-1">{errors.postnummer}</p>
)}
<p className="text-muted-foreground text-xs mt-1">
Beställningen kan endast fortsätta för postnummer inom Storstockholm.
Endast postnummer inom Storstockholm.
</p>
</div>
<div>
<label className="block mb-1.5 text-sm font-semibold">
Stad <span className="text-primary">*</span>
</label>
<input
name="stad"
placeholder="t.ex. Stockholm"
value={form.stad}
onChange={handleChange}
aria-invalid={!!errors.stad}
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.stad && (
<p className="text-destructive text-xs mt-1">{errors.stad}</p>
)}
</div>
</div>
<div>
+48 -23
View File
@@ -93,6 +93,7 @@ export function OrdersTable() {
<TableRow>
<TableHead>Ordernummer</TableHead>
<TableHead>Kund</TableHead>
<TableHead>Leveransadress</TableHead>
<TableHead>Datum</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Belopp</TableHead>
@@ -101,33 +102,57 @@ export function OrdersTable() {
<TableBody>
{filteredOrders?.length === 0 ? (
<TableRow>
<TableCell colSpan={5} className="text-center py-8 text-muted-foreground">
<TableCell colSpan={6} className="text-center py-8 text-muted-foreground">
Inga ordrar hittades
</TableCell>
</TableRow>
) : (
filteredOrders?.map((order) => (
<TableRow key={order.id}>
<TableCell className="font-medium">{order.order_number}</TableCell>
<TableCell>
<div>
<div className="font-medium">{order.customer_name || "—"}</div>
<div className="text-sm text-muted-foreground">{order.customer_email}</div>
</div>
</TableCell>
<TableCell>
{format(new Date(order.created_at), "d MMM yyyy, HH:mm", { locale: sv })}
</TableCell>
<TableCell>
<Badge variant="outline" className={statusColors[order.status] || ""}>
{statusLabels[order.status] || order.status}
</Badge>
</TableCell>
<TableCell className="text-right font-medium">
{Number(order.total_amount).toLocaleString("sv-SE")} {order.currency}
</TableCell>
</TableRow>
))
filteredOrders?.map((order) => {
const item = Array.isArray(order.items) ? order.items[0] : null;
const lev = item?.leverans;
const phone = item?.telefon;
const comments = item?.kommentarer;
return (
<TableRow key={order.id}>
<TableCell className="font-medium align-top">{order.order_number}</TableCell>
<TableCell className="align-top">
<div>
<div className="font-medium">{order.customer_name || "—"}</div>
<div className="text-sm text-muted-foreground">{order.customer_email}</div>
{phone && <div className="text-sm text-muted-foreground">{phone}</div>}
</div>
</TableCell>
<TableCell className="align-top">
{lev ? (
<div className="text-sm">
<div>{lev.adress || "—"}</div>
<div className="text-muted-foreground">
{[lev.postnummer, lev.stad].filter(Boolean).join(" ")}
</div>
{comments && (
<div className="text-xs text-muted-foreground mt-1 italic">
"{comments}"
</div>
)}
</div>
) : (
<span className="text-muted-foreground text-sm"></span>
)}
</TableCell>
<TableCell className="align-top">
{format(new Date(order.created_at), "d MMM yyyy, HH:mm", { locale: sv })}
</TableCell>
<TableCell className="align-top">
<Badge variant="outline" className={statusColors[order.status] || ""}>
{statusLabels[order.status] || order.status}
</Badge>
</TableCell>
<TableCell className="text-right font-medium align-top">
{Number(order.total_amount).toLocaleString("sv-SE")} {order.currency}
</TableCell>
</TableRow>
);
})
)}
</TableBody>
</Table>
+3 -3
View File
@@ -56,7 +56,7 @@ async function insertOrder(row: {
leverans: {
adress: b.address,
postnummer: cleaned,
stad: "Storstockholm",
stad: b.city,
},
telefon: b.phone,
kommentarer: b.comments,
@@ -100,9 +100,9 @@ const BodySchema = z.object({
company: z.string().trim().min(1).max(200),
email: z.string().trim().email().max(255),
phone: z.string().trim().max(30).optional().default(""),
address: z.string().trim().max(200).optional().default(""),
address: z.string().trim().min(1).max(200),
postal_code: z.string().trim().min(1).max(20),
city: z.string().trim().max(100).optional().default(""),
city: z.string().trim().min(1).max(100),
comments: z.string().trim().max(1000).optional().default(""),
return_url: z.string().url(),
environment: z.enum(["sandbox", "live"]),