@flowselections/actie-mail-kwekers-erp-mathot 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/_core-safelist.d.ts +2 -0
- package/dist-lib/_core-safelist.d.ts.map +1 -0
- package/dist-lib/_core-safelist.js +15 -0
- package/dist-lib/components/AanbiedingsmailtjePage.d.ts +2 -0
- package/dist-lib/components/AanbiedingsmailtjePage.d.ts.map +1 -0
- package/dist-lib/components/AanbiedingsmailtjePage.js +239 -0
- package/dist-lib/components/ActiePage.d.ts +2 -0
- package/dist-lib/components/ActiePage.d.ts.map +1 -0
- package/dist-lib/components/ActiePage.js +173 -0
- package/dist-lib/components/CampagneDetail.d.ts +2 -0
- package/dist-lib/components/CampagneDetail.d.ts.map +1 -0
- package/dist-lib/components/CampagneDetail.js +61 -0
- package/dist-lib/components/CampagneOverzicht.d.ts +2 -0
- package/dist-lib/components/CampagneOverzicht.d.ts.map +1 -0
- package/dist-lib/components/CampagneOverzicht.js +16 -0
- package/dist-lib/components/DateRangePicker.d.ts +20 -0
- package/dist-lib/components/DateRangePicker.d.ts.map +1 -0
- package/dist-lib/components/DateRangePicker.js +140 -0
- package/dist-lib/components/RapportagePage.d.ts +2 -0
- package/dist-lib/components/RapportagePage.d.ts.map +1 -0
- package/dist-lib/components/RapportagePage.js +60 -0
- package/dist-lib/components/settings/AfzenderSettingsCard.d.ts +2 -0
- package/dist-lib/components/settings/AfzenderSettingsCard.d.ts.map +1 -0
- package/dist-lib/components/settings/AfzenderSettingsCard.js +30 -0
- package/dist-lib/components/settings/HuisstijlSettingsCard.d.ts +2 -0
- package/dist-lib/components/settings/HuisstijlSettingsCard.d.ts.map +1 -0
- package/dist-lib/components/settings/HuisstijlSettingsCard.js +30 -0
- package/dist-lib/components/settings/StickerSettingsCard.d.ts +2 -0
- package/dist-lib/components/settings/StickerSettingsCard.d.ts.map +1 -0
- package/dist-lib/components/settings/StickerSettingsCard.js +41 -0
- package/dist-lib/components/settings/TestmailCard.d.ts +2 -0
- package/dist-lib/components/settings/TestmailCard.d.ts.map +1 -0
- package/dist-lib/components/settings/TestmailCard.js +21 -0
- package/dist-lib/components/settings/TrackingSettingsCard.d.ts +2 -0
- package/dist-lib/components/settings/TrackingSettingsCard.d.ts.map +1 -0
- package/dist-lib/components/settings/TrackingSettingsCard.js +30 -0
- package/dist-lib/components/settings/UitsluitingenSettingsCard.d.ts +2 -0
- package/dist-lib/components/settings/UitsluitingenSettingsCard.d.ts.map +1 -0
- package/dist-lib/components/settings/UitsluitingenSettingsCard.js +41 -0
- package/dist-lib/index.d.ts +17 -0
- package/dist-lib/index.d.ts.map +1 -0
- package/dist-lib/index.js +34 -0
- package/dist-lib/integrations/supabase/auth-attacher.d.ts +2 -0
- package/dist-lib/integrations/supabase/auth-attacher.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/auth-attacher.js +12 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +2555 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/auth-middleware.js +52 -0
- package/dist-lib/integrations/supabase/client.d.ts +2551 -0
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/client.js +13 -0
- package/dist-lib/integrations/supabase/client.server.d.ts +2551 -0
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/client.server.js +30 -0
- package/dist-lib/integrations/supabase/types.d.ts +2685 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/types.js +8 -0
- package/dist-lib/lib/campaigns.functions.d.ts +12881 -0
- package/dist-lib/lib/campaigns.functions.d.ts.map +1 -0
- package/dist-lib/lib/campaigns.functions.js +358 -0
- package/dist-lib/lib/public-offer.functions.d.ts +68 -0
- package/dist-lib/lib/public-offer.functions.d.ts.map +1 -0
- package/dist-lib/lib/public-offer.functions.js +116 -0
- package/dist-lib/lib/stats.functions.d.ts +5180 -0
- package/dist-lib/lib/stats.functions.d.ts.map +1 -0
- package/dist-lib/lib/stats.functions.js +63 -0
- package/dist-lib/lib/utils.d.ts +3 -0
- package/dist-lib/lib/utils.d.ts.map +1 -0
- package/dist-lib/lib/utils.js +5 -0
- package/dist-lib/lib/validationSchemas.d.ts +15 -0
- package/dist-lib/lib/validationSchemas.d.ts.map +1 -0
- package/dist-lib/lib/validationSchemas.js +25 -0
- package/dist-lib/styles.css +1 -0
- package/package.json +76 -0
- package/public/flowselections-assets/template-module/README.md +15 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { createServerFn } from "@tanstack/react-start";
|
|
2
|
+
import { createClient } from "@supabase/supabase-js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
// Publieke endpoint: gebruikt anon-key (RLS / SECURITY DEFINER beschermt de data).
|
|
5
|
+
// Bewust GEEN service-role client — die secret is hier niet nodig en is in
|
|
6
|
+
// veel omgevingen niet beschikbaar.
|
|
7
|
+
function getPublicClient() {
|
|
8
|
+
const url = process.env.SUPABASE_URL ?? process.env.VITE_SUPABASE_URL;
|
|
9
|
+
const key = process.env.SUPABASE_PUBLISHABLE_KEY ??
|
|
10
|
+
process.env.SUPABASE_ANON_KEY ??
|
|
11
|
+
process.env.VITE_SUPABASE_PUBLISHABLE_KEY;
|
|
12
|
+
if (!url || !key) {
|
|
13
|
+
throw new Error("Supabase publieke configuratie ontbreekt (SUPABASE_URL / SUPABASE_PUBLISHABLE_KEY).");
|
|
14
|
+
}
|
|
15
|
+
return createClient(url, key, {
|
|
16
|
+
auth: { persistSession: false, autoRefreshToken: false },
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export const getOfferByLinkCode = createServerFn({ method: "GET" })
|
|
20
|
+
.inputValidator((d) => z.object({ code: z.string().min(8).max(64).regex(/^[a-f0-9]+$/) }).parse(d))
|
|
21
|
+
.handler(async ({ data }) => {
|
|
22
|
+
const client = getPublicClient();
|
|
23
|
+
const { data: result, error } = await client.rpc("get_offer_by_link_code", {
|
|
24
|
+
p_code: data.code,
|
|
25
|
+
});
|
|
26
|
+
if (error)
|
|
27
|
+
throw new Error(error.message);
|
|
28
|
+
return result;
|
|
29
|
+
});
|
|
30
|
+
export const trackOfferClick = createServerFn({ method: "POST" })
|
|
31
|
+
.inputValidator((d) => z.object({ code: z.string().min(8).max(64).regex(/^[a-f0-9]+$/) }).parse(d))
|
|
32
|
+
.handler(async ({ data }) => {
|
|
33
|
+
const client = getPublicClient();
|
|
34
|
+
const { data: rec } = await client
|
|
35
|
+
.from("offer_recipients")
|
|
36
|
+
.select("id, campaign_id, clicked_at")
|
|
37
|
+
.eq("link_code", data.code)
|
|
38
|
+
.maybeSingle();
|
|
39
|
+
if (!rec)
|
|
40
|
+
return { ok: false };
|
|
41
|
+
if (!rec.clicked_at) {
|
|
42
|
+
await client.from("offer_recipients").update({ clicked_at: new Date().toISOString() }).eq("id", rec.id);
|
|
43
|
+
}
|
|
44
|
+
await client.from("offer_events").insert({
|
|
45
|
+
recipient_id: rec.id,
|
|
46
|
+
campaign_id: rec.campaign_id,
|
|
47
|
+
event_type: "click",
|
|
48
|
+
});
|
|
49
|
+
return { ok: true };
|
|
50
|
+
});
|
|
51
|
+
const orderItemSchema = z.object({
|
|
52
|
+
product_id: z.string().uuid(),
|
|
53
|
+
product_name: z.string().min(1).max(255),
|
|
54
|
+
quantity: z.number().int().min(1).max(100000),
|
|
55
|
+
unit_price: z.number().min(0).max(1000000),
|
|
56
|
+
sticker: z.boolean().optional().default(false),
|
|
57
|
+
sticker_unit_price: z.number().min(0).max(1000000).optional().default(0),
|
|
58
|
+
});
|
|
59
|
+
export const placeOfferOrder = createServerFn({ method: "POST" })
|
|
60
|
+
.inputValidator((d) => z.object({
|
|
61
|
+
code: z.string().min(8).max(64).regex(/^[a-f0-9]+$/),
|
|
62
|
+
customer_name: z.string().min(1).max(255),
|
|
63
|
+
customer_email: z.string().email().max(255),
|
|
64
|
+
customer_phone: z.string().max(50).optional(),
|
|
65
|
+
notes: z.string().max(2000).optional(),
|
|
66
|
+
items: z.array(orderItemSchema).min(1).max(100),
|
|
67
|
+
}).parse(d))
|
|
68
|
+
.handler(async ({ data }) => {
|
|
69
|
+
const client = getPublicClient();
|
|
70
|
+
const { data: rec } = await client
|
|
71
|
+
.from("offer_recipients")
|
|
72
|
+
.select("id, campaign_id, customer_id")
|
|
73
|
+
.eq("link_code", data.code)
|
|
74
|
+
.maybeSingle();
|
|
75
|
+
if (!rec)
|
|
76
|
+
throw new Error("Ongeldige link");
|
|
77
|
+
// Realtime voorraadcontrole: haal actuele voorraad op via RPC
|
|
78
|
+
const { data: offerSnapshot } = await client.rpc("get_offer_by_link_code", { p_code: data.code });
|
|
79
|
+
const liveProducts = Array.isArray(offerSnapshot?.products) ? offerSnapshot.products : [];
|
|
80
|
+
for (const it of data.items) {
|
|
81
|
+
const lp = liveProducts.find((p) => p.id === it.product_id);
|
|
82
|
+
const stock = Number(lp?.live_stock ?? lp?.available_stock ?? 0);
|
|
83
|
+
if (!lp)
|
|
84
|
+
throw new Error(`Product niet meer beschikbaar: ${it.product_name}`);
|
|
85
|
+
if (stock <= 0)
|
|
86
|
+
throw new Error(`${it.product_name} is uitverkocht`);
|
|
87
|
+
if (it.quantity > stock)
|
|
88
|
+
throw new Error(`${it.product_name}: slechts ${stock} op voorraad`);
|
|
89
|
+
}
|
|
90
|
+
const total = data.items.reduce((s, i) => s + i.quantity * (i.unit_price + (i.sticker ? i.sticker_unit_price : 0)), 0);
|
|
91
|
+
const orderId = crypto.randomUUID();
|
|
92
|
+
const { error } = await client
|
|
93
|
+
.from("offer_orders")
|
|
94
|
+
.insert({
|
|
95
|
+
id: orderId,
|
|
96
|
+
recipient_id: rec.id,
|
|
97
|
+
campaign_id: rec.campaign_id,
|
|
98
|
+
customer_id: rec.customer_id,
|
|
99
|
+
customer_name: data.customer_name,
|
|
100
|
+
customer_email: data.customer_email,
|
|
101
|
+
customer_phone: data.customer_phone ?? null,
|
|
102
|
+
notes: data.notes ?? null,
|
|
103
|
+
items: data.items,
|
|
104
|
+
total_amount: total,
|
|
105
|
+
});
|
|
106
|
+
if (error)
|
|
107
|
+
throw new Error(error.message);
|
|
108
|
+
await client.from("offer_recipients").update({ ordered_at: new Date().toISOString() }).eq("id", rec.id);
|
|
109
|
+
await client.from("offer_events").insert({
|
|
110
|
+
recipient_id: rec.id,
|
|
111
|
+
campaign_id: rec.campaign_id,
|
|
112
|
+
event_type: "order",
|
|
113
|
+
metadata: { order_id: orderId, total },
|
|
114
|
+
});
|
|
115
|
+
return { ok: true, orderId, total };
|
|
116
|
+
});
|