@btst/plugin-affiliate 0.0.0-stage → 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.
Files changed (79) hide show
  1. package/LICENSE.md +17 -0
  2. package/dist/api/getters.cjs +182 -0
  3. package/dist/api/getters.mjs +166 -0
  4. package/dist/api/index.cjs +49 -0
  5. package/dist/api/index.d.cts +975 -0
  6. package/dist/api/index.d.mts +975 -0
  7. package/dist/api/index.d.ts +975 -0
  8. package/dist/api/index.mjs +7 -0
  9. package/dist/api/mutations.cjs +362 -0
  10. package/dist/api/mutations.mjs +352 -0
  11. package/dist/api/operations.cjs +328 -0
  12. package/dist/api/operations.mjs +326 -0
  13. package/dist/api/plugin.cjs +146 -0
  14. package/dist/api/plugin.mjs +144 -0
  15. package/dist/attribution.cjs +92 -0
  16. package/dist/attribution.d.cts +20 -0
  17. package/dist/attribution.d.mts +20 -0
  18. package/dist/attribution.d.ts +20 -0
  19. package/dist/attribution.mjs +82 -0
  20. package/dist/client/components/index.cjs +12 -0
  21. package/dist/client/components/index.d.cts +13 -0
  22. package/dist/client/components/index.d.mts +13 -0
  23. package/dist/client/components/index.d.ts +13 -0
  24. package/dist/client/components/index.mjs +1 -0
  25. package/dist/client/components/pages/affiliate-apply-page.internal.cjs +59 -0
  26. package/dist/client/components/pages/affiliate-apply-page.internal.mjs +57 -0
  27. package/dist/client/components/pages/affiliate-detail-page.internal.cjs +112 -0
  28. package/dist/client/components/pages/affiliate-detail-page.internal.mjs +110 -0
  29. package/dist/client/components/pages/affiliate-portal-page.internal.cjs +252 -0
  30. package/dist/client/components/pages/affiliate-portal-page.internal.mjs +250 -0
  31. package/dist/client/components/pages/affiliates-page.internal.cjs +160 -0
  32. package/dist/client/components/pages/affiliates-page.internal.mjs +158 -0
  33. package/dist/client/components/pages/commissions-page.internal.cjs +151 -0
  34. package/dist/client/components/pages/commissions-page.internal.mjs +149 -0
  35. package/dist/client/components/pages/payouts-page.internal.cjs +230 -0
  36. package/dist/client/components/pages/payouts-page.internal.mjs +228 -0
  37. package/dist/client/components/pages.cjs +145 -0
  38. package/dist/client/components/pages.mjs +138 -0
  39. package/dist/client/components/shared.cjs +331 -0
  40. package/dist/client/components/shared.mjs +316 -0
  41. package/dist/client/constants.cjs +5 -0
  42. package/dist/client/constants.mjs +3 -0
  43. package/dist/client/hooks/index.cjs +77 -0
  44. package/dist/client/hooks/index.d.cts +39 -0
  45. package/dist/client/hooks/index.d.mts +39 -0
  46. package/dist/client/hooks/index.d.ts +39 -0
  47. package/dist/client/hooks/index.mjs +61 -0
  48. package/dist/client/index.cjs +7 -0
  49. package/dist/client/index.d.cts +110 -0
  50. package/dist/client/index.d.mts +110 -0
  51. package/dist/client/index.d.ts +110 -0
  52. package/dist/client/index.mjs +1 -0
  53. package/dist/client/plugin.cjs +77 -0
  54. package/dist/client/plugin.mjs +75 -0
  55. package/dist/client.css +311 -0
  56. package/dist/commission.cjs +24 -0
  57. package/dist/commission.mjs +22 -0
  58. package/dist/db.cjs +74 -0
  59. package/dist/db.mjs +72 -0
  60. package/dist/permissions.cjs +53 -0
  61. package/dist/permissions.d.cts +78 -0
  62. package/dist/permissions.d.mts +78 -0
  63. package/dist/permissions.d.ts +78 -0
  64. package/dist/permissions.mjs +51 -0
  65. package/dist/query-keys.cjs +152 -0
  66. package/dist/query-keys.d.cts +394 -0
  67. package/dist/query-keys.d.mts +394 -0
  68. package/dist/query-keys.d.ts +394 -0
  69. package/dist/query-keys.mjs +149 -0
  70. package/dist/schemas.cjs +95 -0
  71. package/dist/schemas.mjs +77 -0
  72. package/dist/style.css +313 -0
  73. package/dist/types.cjs +2 -0
  74. package/dist/types.d.cts +176 -0
  75. package/dist/types.d.mts +176 -0
  76. package/dist/types.d.ts +176 -0
  77. package/dist/types.mjs +1 -0
  78. package/package.json +159 -3
  79. package/README.md +0 -3
@@ -0,0 +1,230 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const react = require('react');
6
+ const context = require('@btst/stack/context');
7
+ const permissions = require('../../../permissions.cjs');
8
+ const client_hooks_index = require('../../hooks/index.cjs');
9
+ const constants = require('../../constants.cjs');
10
+ const shared = require('../shared.cjs');
11
+
12
+ function PayoutsPage() {
13
+ const [status, setStatus] = react.useState("");
14
+ const [offset, setOffset] = react.useState(0);
15
+ const [affiliateId, setAffiliateId] = react.useState("");
16
+ const [currency, setCurrency] = react.useState("USD");
17
+ const [recording, setRecording] = react.useState(null);
18
+ const { data } = client_hooks_index.usePayouts({
19
+ status: status || void 0,
20
+ offset,
21
+ limit: 25
22
+ });
23
+ const exportCSV = client_hooks_index.usePayoutExport({ status: status || void 0 });
24
+ const create = client_hooks_index.useCreatePayout();
25
+ const update = client_hooks_index.useUpdatePayout();
26
+ const action = shared.useAffiliateAction();
27
+ const { Link, resolve } = context.usePluginSiteNavigation(constants.AFFILIATE_PLUGIN_ID);
28
+ const { localization } = context.usePluginOverrides(constants.AFFILIATE_PLUGIN_ID);
29
+ const save = (event) => {
30
+ event.preventDefault();
31
+ void action.run(async () => {
32
+ await create.mutateAsync({ affiliateId, currency });
33
+ }, "Payout batch created. Arrange the payment, then record its result below.");
34
+ };
35
+ const record = (event) => {
36
+ event.preventDefault();
37
+ if (!recording) return;
38
+ const fields = new FormData(event.currentTarget);
39
+ const payout = recording;
40
+ void action.run(async () => {
41
+ await update.mutateAsync({
42
+ id: payout.id,
43
+ status: String(fields.get("status")),
44
+ reference: String(fields.get("reference") ?? "")
45
+ });
46
+ setRecording(null);
47
+ }, "Payout result recorded");
48
+ };
49
+ return /* @__PURE__ */ jsxRuntime.jsxs(
50
+ shared.AffiliatePage,
51
+ {
52
+ title: localization?.payouts ?? "Payouts",
53
+ description: "Group approved commissions, arrange payment, and record the result.",
54
+ action: /* @__PURE__ */ jsxRuntime.jsx(context.PermissionAccess, { permission: permissions.affiliatePermissions.payout.export(), children: /* @__PURE__ */ jsxRuntime.jsx(
55
+ "button",
56
+ {
57
+ type: "button",
58
+ disabled: action.pending || exportCSV.isFetching,
59
+ onClick: () => void action.run(async () => {
60
+ const result = await exportCSV.refetch();
61
+ if (result.error) throw result.error;
62
+ if (!result.data)
63
+ throw new Error(
64
+ "The payout CSV could not be exported. Try again."
65
+ );
66
+ const url = URL.createObjectURL(
67
+ new Blob([result.data.csv], {
68
+ type: "text/csv;charset=utf-8"
69
+ })
70
+ );
71
+ const anchor = document.createElement("a");
72
+ anchor.href = url;
73
+ anchor.download = "affiliate-payouts.csv";
74
+ anchor.click();
75
+ URL.revokeObjectURL(url);
76
+ }, "Payouts exported"),
77
+ children: "Export CSV"
78
+ }
79
+ ) }),
80
+ children: [
81
+ /* @__PURE__ */ jsxRuntime.jsx(shared.ActionNotice, { ...action }),
82
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { className: "affiliate-panel affiliate-stack", onSubmit: save, children: [
83
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Create payout batch" }),
84
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-muted", children: "Includes all approved, unpaid commissions for one affiliate and currency. Payment is arranged manually." }),
85
+ /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { disabled: action.pending, children: [
86
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-form-grid", children: [
87
+ /* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Affiliate ID", children: /* @__PURE__ */ jsxRuntime.jsx(
88
+ "input",
89
+ {
90
+ value: affiliateId,
91
+ onChange: (event) => setAffiliateId(event.target.value),
92
+ required: true
93
+ }
94
+ ) }),
95
+ /* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Currency", children: /* @__PURE__ */ jsxRuntime.jsx(
96
+ "input",
97
+ {
98
+ value: currency,
99
+ onChange: (event) => setCurrency(event.target.value.toUpperCase()),
100
+ pattern: "[A-Z]{3}",
101
+ maxLength: 3,
102
+ minLength: 3,
103
+ required: true
104
+ }
105
+ ) })
106
+ ] }),
107
+ /* @__PURE__ */ jsxRuntime.jsx(
108
+ context.PermissionAccess,
109
+ {
110
+ permission: permissions.affiliatePermissions.payout.create({
111
+ affiliateId,
112
+ currency
113
+ }),
114
+ children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "affiliate-primary", type: "submit", children: create.isPending ? "Creating\u2026" : "Create payout batch" })
115
+ }
116
+ )
117
+ ] })
118
+ ] }),
119
+ recording && /* @__PURE__ */ jsxRuntime.jsxs("form", { className: "affiliate-panel affiliate-stack", onSubmit: record, children: [
120
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Record payout result" }),
121
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
122
+ shared.money(recording.amount, recording.currency),
123
+ " for affiliate",
124
+ " ",
125
+ recording.affiliateId
126
+ ] }),
127
+ /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { disabled: action.pending, children: [
128
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-form-grid", children: [
129
+ /* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Payment result", children: /* @__PURE__ */ jsxRuntime.jsxs("select", { name: "status", defaultValue: "sent", children: [
130
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "sent", children: "Sent" }),
131
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "failed", children: "Failed" })
132
+ ] }) }),
133
+ /* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Payment reference", children: /* @__PURE__ */ jsxRuntime.jsx(
134
+ "input",
135
+ {
136
+ name: "reference",
137
+ maxLength: 1e3,
138
+ placeholder: "Bank transfer or accounting reference"
139
+ }
140
+ ) })
141
+ ] }),
142
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-actions", children: [
143
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "affiliate-primary", type: "submit", children: "Save payout result" }),
144
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setRecording(null), children: "Cancel" })
145
+ ] })
146
+ ] })
147
+ ] }),
148
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "affiliate-toolbar", children: /* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Filter by status", children: /* @__PURE__ */ jsxRuntime.jsxs(
149
+ "select",
150
+ {
151
+ value: status,
152
+ onChange: (event) => {
153
+ setStatus(event.target.value);
154
+ setOffset(0);
155
+ },
156
+ children: [
157
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "All statuses" }),
158
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "pending", children: "Pending" }),
159
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "sent", children: "Sent" }),
160
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "failed", children: "Failed" })
161
+ ]
162
+ }
163
+ ) }) }),
164
+ data.items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-empty", children: "No payouts match. Create a batch when an affiliate has approved commissions." }) : /* @__PURE__ */ jsxRuntime.jsx(
165
+ "div",
166
+ {
167
+ className: "affiliate-table-scroll",
168
+ role: "region",
169
+ "aria-label": "Payout history",
170
+ tabIndex: 0,
171
+ children: /* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
172
+ /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "affiliate-sr-only", children: "Manual affiliate payouts" }),
173
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
174
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: "Affiliate" }),
175
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "affiliate-number", children: "Amount" }),
176
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: "Status" }),
177
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: "Reference / date" }),
178
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: "Actions" })
179
+ ] }) }),
180
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: data.items.map((payout) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
181
+ /* @__PURE__ */ jsxRuntime.jsxs("td", { children: [
182
+ /* @__PURE__ */ jsxRuntime.jsx(
183
+ Link,
184
+ {
185
+ href: resolve(
186
+ "affiliate/admin/affiliates",
187
+ encodeURIComponent(payout.affiliateId)
188
+ ).href,
189
+ children: payout.affiliateId
190
+ }
191
+ ),
192
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-small affiliate-muted", children: payout.id })
193
+ ] }),
194
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "affiliate-number", children: shared.money(payout.amount, payout.currency) }),
195
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: /* @__PURE__ */ jsxRuntime.jsx(shared.Status, { value: payout.status }) }),
196
+ /* @__PURE__ */ jsxRuntime.jsxs("td", { children: [
197
+ payout.reference || "No reference",
198
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-small affiliate-muted", children: shared.date(payout.paidAt ?? payout.createdAt) })
199
+ ] }),
200
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: payout.status === "pending" && /* @__PURE__ */ jsxRuntime.jsx(
201
+ context.PermissionAccess,
202
+ {
203
+ permission: permissions.affiliatePermissions.payout.update({
204
+ payoutId: payout.id,
205
+ affiliateId: payout.affiliateId,
206
+ status: payout.status
207
+ }),
208
+ children: /* @__PURE__ */ jsxRuntime.jsx(
209
+ "button",
210
+ {
211
+ type: "button",
212
+ disabled: action.pending,
213
+ "aria-label": `Record payout result ${payout.id}`,
214
+ onClick: () => setRecording(payout),
215
+ children: "Record result"
216
+ }
217
+ )
218
+ }
219
+ ) })
220
+ ] }, payout.id)) })
221
+ ] })
222
+ }
223
+ ),
224
+ /* @__PURE__ */ jsxRuntime.jsx(shared.Pagination, { offset, total: data.total, onChange: setOffset })
225
+ ]
226
+ }
227
+ );
228
+ }
229
+
230
+ exports.PayoutsPage = PayoutsPage;
@@ -0,0 +1,228 @@
1
+ 'use client';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useState } from 'react';
4
+ import { usePluginSiteNavigation, usePluginOverrides, PermissionAccess } from '@btst/stack/context';
5
+ import { affiliatePermissions } from '../../../permissions.mjs';
6
+ import { usePayouts, usePayoutExport, useCreatePayout, useUpdatePayout } from '../../hooks/index.mjs';
7
+ import { AFFILIATE_PLUGIN_ID } from '../../constants.mjs';
8
+ import { useAffiliateAction, AffiliatePage, ActionNotice, Field, money, Status, date, Pagination } from '../shared.mjs';
9
+
10
+ function PayoutsPage() {
11
+ const [status, setStatus] = useState("");
12
+ const [offset, setOffset] = useState(0);
13
+ const [affiliateId, setAffiliateId] = useState("");
14
+ const [currency, setCurrency] = useState("USD");
15
+ const [recording, setRecording] = useState(null);
16
+ const { data } = usePayouts({
17
+ status: status || void 0,
18
+ offset,
19
+ limit: 25
20
+ });
21
+ const exportCSV = usePayoutExport({ status: status || void 0 });
22
+ const create = useCreatePayout();
23
+ const update = useUpdatePayout();
24
+ const action = useAffiliateAction();
25
+ const { Link, resolve } = usePluginSiteNavigation(AFFILIATE_PLUGIN_ID);
26
+ const { localization } = usePluginOverrides(AFFILIATE_PLUGIN_ID);
27
+ const save = (event) => {
28
+ event.preventDefault();
29
+ void action.run(async () => {
30
+ await create.mutateAsync({ affiliateId, currency });
31
+ }, "Payout batch created. Arrange the payment, then record its result below.");
32
+ };
33
+ const record = (event) => {
34
+ event.preventDefault();
35
+ if (!recording) return;
36
+ const fields = new FormData(event.currentTarget);
37
+ const payout = recording;
38
+ void action.run(async () => {
39
+ await update.mutateAsync({
40
+ id: payout.id,
41
+ status: String(fields.get("status")),
42
+ reference: String(fields.get("reference") ?? "")
43
+ });
44
+ setRecording(null);
45
+ }, "Payout result recorded");
46
+ };
47
+ return /* @__PURE__ */ jsxs(
48
+ AffiliatePage,
49
+ {
50
+ title: localization?.payouts ?? "Payouts",
51
+ description: "Group approved commissions, arrange payment, and record the result.",
52
+ action: /* @__PURE__ */ jsx(PermissionAccess, { permission: affiliatePermissions.payout.export(), children: /* @__PURE__ */ jsx(
53
+ "button",
54
+ {
55
+ type: "button",
56
+ disabled: action.pending || exportCSV.isFetching,
57
+ onClick: () => void action.run(async () => {
58
+ const result = await exportCSV.refetch();
59
+ if (result.error) throw result.error;
60
+ if (!result.data)
61
+ throw new Error(
62
+ "The payout CSV could not be exported. Try again."
63
+ );
64
+ const url = URL.createObjectURL(
65
+ new Blob([result.data.csv], {
66
+ type: "text/csv;charset=utf-8"
67
+ })
68
+ );
69
+ const anchor = document.createElement("a");
70
+ anchor.href = url;
71
+ anchor.download = "affiliate-payouts.csv";
72
+ anchor.click();
73
+ URL.revokeObjectURL(url);
74
+ }, "Payouts exported"),
75
+ children: "Export CSV"
76
+ }
77
+ ) }),
78
+ children: [
79
+ /* @__PURE__ */ jsx(ActionNotice, { ...action }),
80
+ /* @__PURE__ */ jsxs("form", { className: "affiliate-panel affiliate-stack", onSubmit: save, children: [
81
+ /* @__PURE__ */ jsx("h2", { children: "Create payout batch" }),
82
+ /* @__PURE__ */ jsx("p", { className: "affiliate-muted", children: "Includes all approved, unpaid commissions for one affiliate and currency. Payment is arranged manually." }),
83
+ /* @__PURE__ */ jsxs("fieldset", { disabled: action.pending, children: [
84
+ /* @__PURE__ */ jsxs("div", { className: "affiliate-form-grid", children: [
85
+ /* @__PURE__ */ jsx(Field, { label: "Affiliate ID", children: /* @__PURE__ */ jsx(
86
+ "input",
87
+ {
88
+ value: affiliateId,
89
+ onChange: (event) => setAffiliateId(event.target.value),
90
+ required: true
91
+ }
92
+ ) }),
93
+ /* @__PURE__ */ jsx(Field, { label: "Currency", children: /* @__PURE__ */ jsx(
94
+ "input",
95
+ {
96
+ value: currency,
97
+ onChange: (event) => setCurrency(event.target.value.toUpperCase()),
98
+ pattern: "[A-Z]{3}",
99
+ maxLength: 3,
100
+ minLength: 3,
101
+ required: true
102
+ }
103
+ ) })
104
+ ] }),
105
+ /* @__PURE__ */ jsx(
106
+ PermissionAccess,
107
+ {
108
+ permission: affiliatePermissions.payout.create({
109
+ affiliateId,
110
+ currency
111
+ }),
112
+ children: /* @__PURE__ */ jsx("button", { className: "affiliate-primary", type: "submit", children: create.isPending ? "Creating\u2026" : "Create payout batch" })
113
+ }
114
+ )
115
+ ] })
116
+ ] }),
117
+ recording && /* @__PURE__ */ jsxs("form", { className: "affiliate-panel affiliate-stack", onSubmit: record, children: [
118
+ /* @__PURE__ */ jsx("h2", { children: "Record payout result" }),
119
+ /* @__PURE__ */ jsxs("p", { children: [
120
+ money(recording.amount, recording.currency),
121
+ " for affiliate",
122
+ " ",
123
+ recording.affiliateId
124
+ ] }),
125
+ /* @__PURE__ */ jsxs("fieldset", { disabled: action.pending, children: [
126
+ /* @__PURE__ */ jsxs("div", { className: "affiliate-form-grid", children: [
127
+ /* @__PURE__ */ jsx(Field, { label: "Payment result", children: /* @__PURE__ */ jsxs("select", { name: "status", defaultValue: "sent", children: [
128
+ /* @__PURE__ */ jsx("option", { value: "sent", children: "Sent" }),
129
+ /* @__PURE__ */ jsx("option", { value: "failed", children: "Failed" })
130
+ ] }) }),
131
+ /* @__PURE__ */ jsx(Field, { label: "Payment reference", children: /* @__PURE__ */ jsx(
132
+ "input",
133
+ {
134
+ name: "reference",
135
+ maxLength: 1e3,
136
+ placeholder: "Bank transfer or accounting reference"
137
+ }
138
+ ) })
139
+ ] }),
140
+ /* @__PURE__ */ jsxs("div", { className: "affiliate-actions", children: [
141
+ /* @__PURE__ */ jsx("button", { className: "affiliate-primary", type: "submit", children: "Save payout result" }),
142
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setRecording(null), children: "Cancel" })
143
+ ] })
144
+ ] })
145
+ ] }),
146
+ /* @__PURE__ */ jsx("div", { className: "affiliate-toolbar", children: /* @__PURE__ */ jsx(Field, { label: "Filter by status", children: /* @__PURE__ */ jsxs(
147
+ "select",
148
+ {
149
+ value: status,
150
+ onChange: (event) => {
151
+ setStatus(event.target.value);
152
+ setOffset(0);
153
+ },
154
+ children: [
155
+ /* @__PURE__ */ jsx("option", { value: "", children: "All statuses" }),
156
+ /* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
157
+ /* @__PURE__ */ jsx("option", { value: "sent", children: "Sent" }),
158
+ /* @__PURE__ */ jsx("option", { value: "failed", children: "Failed" })
159
+ ]
160
+ }
161
+ ) }) }),
162
+ data.items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "affiliate-empty", children: "No payouts match. Create a batch when an affiliate has approved commissions." }) : /* @__PURE__ */ jsx(
163
+ "div",
164
+ {
165
+ className: "affiliate-table-scroll",
166
+ role: "region",
167
+ "aria-label": "Payout history",
168
+ tabIndex: 0,
169
+ children: /* @__PURE__ */ jsxs("table", { children: [
170
+ /* @__PURE__ */ jsx("caption", { className: "affiliate-sr-only", children: "Manual affiliate payouts" }),
171
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
172
+ /* @__PURE__ */ jsx("th", { children: "Affiliate" }),
173
+ /* @__PURE__ */ jsx("th", { className: "affiliate-number", children: "Amount" }),
174
+ /* @__PURE__ */ jsx("th", { children: "Status" }),
175
+ /* @__PURE__ */ jsx("th", { children: "Reference / date" }),
176
+ /* @__PURE__ */ jsx("th", { children: "Actions" })
177
+ ] }) }),
178
+ /* @__PURE__ */ jsx("tbody", { children: data.items.map((payout) => /* @__PURE__ */ jsxs("tr", { children: [
179
+ /* @__PURE__ */ jsxs("td", { children: [
180
+ /* @__PURE__ */ jsx(
181
+ Link,
182
+ {
183
+ href: resolve(
184
+ "affiliate/admin/affiliates",
185
+ encodeURIComponent(payout.affiliateId)
186
+ ).href,
187
+ children: payout.affiliateId
188
+ }
189
+ ),
190
+ /* @__PURE__ */ jsx("p", { className: "affiliate-small affiliate-muted", children: payout.id })
191
+ ] }),
192
+ /* @__PURE__ */ jsx("td", { className: "affiliate-number", children: money(payout.amount, payout.currency) }),
193
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Status, { value: payout.status }) }),
194
+ /* @__PURE__ */ jsxs("td", { children: [
195
+ payout.reference || "No reference",
196
+ /* @__PURE__ */ jsx("p", { className: "affiliate-small affiliate-muted", children: date(payout.paidAt ?? payout.createdAt) })
197
+ ] }),
198
+ /* @__PURE__ */ jsx("td", { children: payout.status === "pending" && /* @__PURE__ */ jsx(
199
+ PermissionAccess,
200
+ {
201
+ permission: affiliatePermissions.payout.update({
202
+ payoutId: payout.id,
203
+ affiliateId: payout.affiliateId,
204
+ status: payout.status
205
+ }),
206
+ children: /* @__PURE__ */ jsx(
207
+ "button",
208
+ {
209
+ type: "button",
210
+ disabled: action.pending,
211
+ "aria-label": `Record payout result ${payout.id}`,
212
+ onClick: () => setRecording(payout),
213
+ children: "Record result"
214
+ }
215
+ )
216
+ }
217
+ ) })
218
+ ] }, payout.id)) })
219
+ ] })
220
+ }
221
+ ),
222
+ /* @__PURE__ */ jsx(Pagination, { offset, total: data.total, onChange: setOffset })
223
+ ]
224
+ }
225
+ );
226
+ }
227
+
228
+ export { PayoutsPage };
@@ -0,0 +1,145 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const react = require('react');
6
+ const components = require('@btst/stack/client/components');
7
+ const permissions = require('../../permissions.cjs');
8
+ const shared = require('./shared.cjs');
9
+
10
+ const Affiliates = react.lazy(
11
+ () => import('./pages/affiliates-page.internal.cjs').then((m) => ({
12
+ default: m.AffiliatesPage
13
+ }))
14
+ );
15
+ const Detail = react.lazy(
16
+ () => import('./pages/affiliate-detail-page.internal.cjs').then((m) => ({
17
+ default: m.AffiliateDetailPage
18
+ }))
19
+ );
20
+ const Commissions = react.lazy(
21
+ () => import('./pages/commissions-page.internal.cjs').then((m) => ({
22
+ default: m.CommissionsPage
23
+ }))
24
+ );
25
+ const Payouts = react.lazy(
26
+ () => import('./pages/payouts-page.internal.cjs').then((m) => ({
27
+ default: m.PayoutsPage
28
+ }))
29
+ );
30
+ const Apply = react.lazy(
31
+ () => import('./pages/affiliate-apply-page.internal.cjs').then((m) => ({
32
+ default: m.AffiliateApplyPage
33
+ }))
34
+ );
35
+ const Portal = react.lazy(
36
+ () => import('./pages/affiliate-portal-page.internal.cjs').then((m) => ({
37
+ default: m.AffiliatePortalPage
38
+ }))
39
+ );
40
+ function BrowserPage({ children }) {
41
+ const [mounted, setMounted] = react.useState(false);
42
+ react.useEffect(() => setMounted(true), []);
43
+ return mounted ? children : /* @__PURE__ */ jsxRuntime.jsx(shared.AffiliateLoading, {});
44
+ }
45
+ const boundary = {
46
+ ErrorComponent: shared.AffiliateError,
47
+ LoadingComponent: shared.AffiliateLoading,
48
+ NotFoundComponent: shared.AffiliateNotFound,
49
+ onError: (error) => console.error("[btst/affiliate]", error)
50
+ };
51
+ function AffiliateList() {
52
+ return /* @__PURE__ */ jsxRuntime.jsx(BrowserPage, { children: /* @__PURE__ */ jsxRuntime.jsx(Affiliates, {}) });
53
+ }
54
+ function AffiliateDetail(props) {
55
+ return /* @__PURE__ */ jsxRuntime.jsx(BrowserPage, { children: /* @__PURE__ */ jsxRuntime.jsx(Detail, { ...props }) });
56
+ }
57
+ function CommissionList() {
58
+ return /* @__PURE__ */ jsxRuntime.jsx(BrowserPage, { children: /* @__PURE__ */ jsxRuntime.jsx(Commissions, {}) });
59
+ }
60
+ function PayoutList() {
61
+ return /* @__PURE__ */ jsxRuntime.jsx(BrowserPage, { children: /* @__PURE__ */ jsxRuntime.jsx(Payouts, {}) });
62
+ }
63
+ function Application() {
64
+ return /* @__PURE__ */ jsxRuntime.jsx(BrowserPage, { children: /* @__PURE__ */ jsxRuntime.jsx(Apply, {}) });
65
+ }
66
+ function PortalDashboard() {
67
+ return /* @__PURE__ */ jsxRuntime.jsx(BrowserPage, { children: /* @__PURE__ */ jsxRuntime.jsx(Portal, {}) });
68
+ }
69
+ function AffiliatesPageComponent() {
70
+ return /* @__PURE__ */ jsxRuntime.jsx(
71
+ components.ComposedRoute,
72
+ {
73
+ ...boundary,
74
+ path: "/affiliate/admin/affiliates",
75
+ permission: permissions.affiliatePermissions.affiliate.read({ scope: "collection" }),
76
+ PageComponent: AffiliateList
77
+ }
78
+ );
79
+ }
80
+ function AffiliateDetailPageComponent({ id }) {
81
+ return /* @__PURE__ */ jsxRuntime.jsx(
82
+ components.ComposedRoute,
83
+ {
84
+ ...boundary,
85
+ path: `/affiliate/admin/affiliates/${id}`,
86
+ permission: permissions.affiliatePermissions.affiliate.read({
87
+ scope: "record",
88
+ affiliateId: id
89
+ }),
90
+ PageComponent: AffiliateDetail,
91
+ props: { id }
92
+ }
93
+ );
94
+ }
95
+ function CommissionsPageComponent() {
96
+ return /* @__PURE__ */ jsxRuntime.jsx(
97
+ components.ComposedRoute,
98
+ {
99
+ ...boundary,
100
+ path: "/affiliate/admin/commissions",
101
+ permission: permissions.affiliatePermissions.commission.read(),
102
+ PageComponent: CommissionList
103
+ }
104
+ );
105
+ }
106
+ function PayoutsPageComponent() {
107
+ return /* @__PURE__ */ jsxRuntime.jsx(
108
+ components.ComposedRoute,
109
+ {
110
+ ...boundary,
111
+ path: "/affiliate/admin/payouts",
112
+ permission: permissions.affiliatePermissions.payout.read(),
113
+ PageComponent: PayoutList
114
+ }
115
+ );
116
+ }
117
+ function AffiliateApplyPageComponent() {
118
+ return /* @__PURE__ */ jsxRuntime.jsx(
119
+ components.ComposedRoute,
120
+ {
121
+ ...boundary,
122
+ path: "/affiliate/apply",
123
+ permission: permissions.affiliatePermissions.application.create(),
124
+ PageComponent: Application
125
+ }
126
+ );
127
+ }
128
+ function AffiliatePortalPageComponent() {
129
+ return /* @__PURE__ */ jsxRuntime.jsx(
130
+ components.ComposedRoute,
131
+ {
132
+ ...boundary,
133
+ path: "/affiliate/portal",
134
+ permission: permissions.affiliatePermissions.portal.read(),
135
+ PageComponent: PortalDashboard
136
+ }
137
+ );
138
+ }
139
+
140
+ exports.AffiliateApplyPageComponent = AffiliateApplyPageComponent;
141
+ exports.AffiliateDetailPageComponent = AffiliateDetailPageComponent;
142
+ exports.AffiliatePortalPageComponent = AffiliatePortalPageComponent;
143
+ exports.AffiliatesPageComponent = AffiliatesPageComponent;
144
+ exports.CommissionsPageComponent = CommissionsPageComponent;
145
+ exports.PayoutsPageComponent = PayoutsPageComponent;