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:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"]),
|
||||
|
||||
Reference in New Issue
Block a user