@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.
- package/LICENSE.md +17 -0
- package/dist/api/getters.cjs +182 -0
- package/dist/api/getters.mjs +166 -0
- package/dist/api/index.cjs +49 -0
- package/dist/api/index.d.cts +975 -0
- package/dist/api/index.d.mts +975 -0
- package/dist/api/index.d.ts +975 -0
- package/dist/api/index.mjs +7 -0
- package/dist/api/mutations.cjs +362 -0
- package/dist/api/mutations.mjs +352 -0
- package/dist/api/operations.cjs +328 -0
- package/dist/api/operations.mjs +326 -0
- package/dist/api/plugin.cjs +146 -0
- package/dist/api/plugin.mjs +144 -0
- package/dist/attribution.cjs +92 -0
- package/dist/attribution.d.cts +20 -0
- package/dist/attribution.d.mts +20 -0
- package/dist/attribution.d.ts +20 -0
- package/dist/attribution.mjs +82 -0
- package/dist/client/components/index.cjs +12 -0
- package/dist/client/components/index.d.cts +13 -0
- package/dist/client/components/index.d.mts +13 -0
- package/dist/client/components/index.d.ts +13 -0
- package/dist/client/components/index.mjs +1 -0
- package/dist/client/components/pages/affiliate-apply-page.internal.cjs +59 -0
- package/dist/client/components/pages/affiliate-apply-page.internal.mjs +57 -0
- package/dist/client/components/pages/affiliate-detail-page.internal.cjs +112 -0
- package/dist/client/components/pages/affiliate-detail-page.internal.mjs +110 -0
- package/dist/client/components/pages/affiliate-portal-page.internal.cjs +252 -0
- package/dist/client/components/pages/affiliate-portal-page.internal.mjs +250 -0
- package/dist/client/components/pages/affiliates-page.internal.cjs +160 -0
- package/dist/client/components/pages/affiliates-page.internal.mjs +158 -0
- package/dist/client/components/pages/commissions-page.internal.cjs +151 -0
- package/dist/client/components/pages/commissions-page.internal.mjs +149 -0
- package/dist/client/components/pages/payouts-page.internal.cjs +230 -0
- package/dist/client/components/pages/payouts-page.internal.mjs +228 -0
- package/dist/client/components/pages.cjs +145 -0
- package/dist/client/components/pages.mjs +138 -0
- package/dist/client/components/shared.cjs +331 -0
- package/dist/client/components/shared.mjs +316 -0
- package/dist/client/constants.cjs +5 -0
- package/dist/client/constants.mjs +3 -0
- package/dist/client/hooks/index.cjs +77 -0
- package/dist/client/hooks/index.d.cts +39 -0
- package/dist/client/hooks/index.d.mts +39 -0
- package/dist/client/hooks/index.d.ts +39 -0
- package/dist/client/hooks/index.mjs +61 -0
- package/dist/client/index.cjs +7 -0
- package/dist/client/index.d.cts +110 -0
- package/dist/client/index.d.mts +110 -0
- package/dist/client/index.d.ts +110 -0
- package/dist/client/index.mjs +1 -0
- package/dist/client/plugin.cjs +77 -0
- package/dist/client/plugin.mjs +75 -0
- package/dist/client.css +311 -0
- package/dist/commission.cjs +24 -0
- package/dist/commission.mjs +22 -0
- package/dist/db.cjs +74 -0
- package/dist/db.mjs +72 -0
- package/dist/permissions.cjs +53 -0
- package/dist/permissions.d.cts +78 -0
- package/dist/permissions.d.mts +78 -0
- package/dist/permissions.d.ts +78 -0
- package/dist/permissions.mjs +51 -0
- package/dist/query-keys.cjs +152 -0
- package/dist/query-keys.d.cts +394 -0
- package/dist/query-keys.d.mts +394 -0
- package/dist/query-keys.d.ts +394 -0
- package/dist/query-keys.mjs +149 -0
- package/dist/schemas.cjs +95 -0
- package/dist/schemas.mjs +77 -0
- package/dist/style.css +313 -0
- package/dist/types.cjs +2 -0
- package/dist/types.d.cts +176 -0
- package/dist/types.d.mts +176 -0
- package/dist/types.d.ts +176 -0
- package/dist/types.mjs +1 -0
- package/package.json +159 -3
- package/README.md +0 -3
|
@@ -0,0 +1,252 @@
|
|
|
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 assetHref(value) {
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(value, window.location.origin);
|
|
15
|
+
return ["https:", "http:"].includes(url.protocol) ? url.href : void 0;
|
|
16
|
+
} catch {
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function AffiliatePortalPage() {
|
|
21
|
+
const { data } = client_hooks_index.useAffiliateDashboard();
|
|
22
|
+
const [landingPath, setLandingPath] = react.useState("/");
|
|
23
|
+
const [link, setLink] = react.useState("");
|
|
24
|
+
const [editing, setEditing] = react.useState(false);
|
|
25
|
+
const createLink = client_hooks_index.useReferralLink();
|
|
26
|
+
const update = client_hooks_index.useUpdateAffiliateProfile();
|
|
27
|
+
const action = shared.useAffiliateAction();
|
|
28
|
+
const { Link, resolve } = context.usePluginSiteNavigation(constants.AFFILIATE_PLUGIN_ID);
|
|
29
|
+
const { localization } = context.usePluginOverrides(constants.AFFILIATE_PLUGIN_ID);
|
|
30
|
+
const { affiliate, stats, commissions, payouts, assets } = data;
|
|
31
|
+
const save = (event) => {
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
const fields = new FormData(event.currentTarget);
|
|
34
|
+
void action.run(async () => {
|
|
35
|
+
await update.mutateAsync(shared.readProfile(fields));
|
|
36
|
+
setEditing(false);
|
|
37
|
+
setLink("");
|
|
38
|
+
}, "Profile saved");
|
|
39
|
+
};
|
|
40
|
+
if (!affiliate)
|
|
41
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42
|
+
shared.AffiliatePage,
|
|
43
|
+
{
|
|
44
|
+
title: localization?.portal ?? "Affiliate portal",
|
|
45
|
+
admin: false,
|
|
46
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "affiliate-stack", children: [
|
|
47
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Start with an affiliate application" }),
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Apply to receive a referral code and track your commissions here." }),
|
|
49
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
50
|
+
Link,
|
|
51
|
+
{
|
|
52
|
+
className: "affiliate-primary",
|
|
53
|
+
href: resolve("affiliate/apply").href,
|
|
54
|
+
children: "Apply to become an affiliate"
|
|
55
|
+
}
|
|
56
|
+
) })
|
|
57
|
+
] })
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
61
|
+
shared.AffiliatePage,
|
|
62
|
+
{
|
|
63
|
+
title: localization?.portal ?? "Affiliate portal",
|
|
64
|
+
description: `Referral activity and earnings for ${affiliate.name}.`,
|
|
65
|
+
admin: false,
|
|
66
|
+
action: /* @__PURE__ */ jsxRuntime.jsx(shared.Status, { value: affiliate.status }),
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.ActionNotice, { ...action }),
|
|
69
|
+
affiliate.status !== "approved" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-notice", children: affiliate.status === "pending" ? "Your application is pending review. Referral tracking starts after approval." : "Your affiliate account is suspended. New referrals are not attributed. Contact the program administrator for help." }),
|
|
70
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.Stats, { stats }),
|
|
71
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
72
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Your referral link" }),
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "affiliate-muted", children: [
|
|
74
|
+
"Code: ",
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: affiliate.code }),
|
|
76
|
+
". Choose a landing page on this site. Visits through your link are recorded before the visitor reaches that page."
|
|
77
|
+
] }),
|
|
78
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
79
|
+
"form",
|
|
80
|
+
{
|
|
81
|
+
className: "affiliate-toolbar",
|
|
82
|
+
onSubmit: (event) => {
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
void action.run(async () => {
|
|
85
|
+
const next = createLink(affiliate.code, landingPath);
|
|
86
|
+
setLink(next);
|
|
87
|
+
}, "Referral link generated");
|
|
88
|
+
},
|
|
89
|
+
children: [
|
|
90
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
91
|
+
shared.Field,
|
|
92
|
+
{
|
|
93
|
+
label: "Landing page path",
|
|
94
|
+
hint: "For example, /pricing or /products?category=books.",
|
|
95
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
|
+
"input",
|
|
97
|
+
{
|
|
98
|
+
value: landingPath,
|
|
99
|
+
onChange: (event) => {
|
|
100
|
+
setLandingPath(event.target.value);
|
|
101
|
+
setLink("");
|
|
102
|
+
},
|
|
103
|
+
required: true,
|
|
104
|
+
placeholder: "/pricing"
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
110
|
+
"button",
|
|
111
|
+
{
|
|
112
|
+
type: "submit",
|
|
113
|
+
className: "affiliate-primary",
|
|
114
|
+
disabled: affiliate.status !== "approved",
|
|
115
|
+
children: "Generate referral link"
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
link && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-toolbar", children: [
|
|
122
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Tracking link", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
123
|
+
"input",
|
|
124
|
+
{
|
|
125
|
+
readOnly: true,
|
|
126
|
+
value: link,
|
|
127
|
+
onFocus: (event) => event.target.select()
|
|
128
|
+
}
|
|
129
|
+
) }),
|
|
130
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
131
|
+
"button",
|
|
132
|
+
{
|
|
133
|
+
type: "button",
|
|
134
|
+
onClick: () => void action.run(async () => {
|
|
135
|
+
await navigator.clipboard.writeText(link);
|
|
136
|
+
}, "Referral link copied"),
|
|
137
|
+
children: "Copy referral link"
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
] })
|
|
141
|
+
] }),
|
|
142
|
+
assets.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
143
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Marketing assets" }),
|
|
144
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "affiliate-assets", children: assets.map((asset) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
145
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: asset.name }),
|
|
146
|
+
asset.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-muted", children: asset.description }),
|
|
147
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-actions", children: [
|
|
148
|
+
assetHref(asset.url) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
149
|
+
"a",
|
|
150
|
+
{
|
|
151
|
+
href: assetHref(asset.url),
|
|
152
|
+
target: "_blank",
|
|
153
|
+
rel: "noreferrer",
|
|
154
|
+
children: "Open link template"
|
|
155
|
+
}
|
|
156
|
+
),
|
|
157
|
+
asset.bannerUrl && assetHref(asset.bannerUrl) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
158
|
+
"a",
|
|
159
|
+
{
|
|
160
|
+
href: assetHref(asset.bannerUrl),
|
|
161
|
+
target: "_blank",
|
|
162
|
+
rel: "noreferrer",
|
|
163
|
+
children: "Open banner"
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
] })
|
|
167
|
+
] }, `${asset.name}-${asset.url}`)) })
|
|
168
|
+
] }),
|
|
169
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
170
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Commissions" }),
|
|
171
|
+
commissions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-muted", children: "Your commissions will appear after an attributed conversion." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
172
|
+
"div",
|
|
173
|
+
{
|
|
174
|
+
className: "affiliate-table-scroll",
|
|
175
|
+
role: "region",
|
|
176
|
+
"aria-label": "Your commissions",
|
|
177
|
+
tabIndex: 0,
|
|
178
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsx("caption", { className: "affiliate-sr-only", children: "Your commission history" }),
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Date" }),
|
|
182
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Conversion" }),
|
|
183
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "affiliate-number", children: "Amount" }),
|
|
184
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Status" })
|
|
185
|
+
] }) }),
|
|
186
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: commissions.map((commission) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
187
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: shared.date(commission.createdAt) }),
|
|
188
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: commission.conversionId }),
|
|
189
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "affiliate-number", children: shared.money(commission.amount, commission.currency) }),
|
|
190
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: /* @__PURE__ */ jsxRuntime.jsx(shared.Status, { value: commission.status }) })
|
|
191
|
+
] }, commission.id)) })
|
|
192
|
+
] })
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
] }),
|
|
196
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
197
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Payout history" }),
|
|
198
|
+
payouts.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-muted", children: "Payouts appear when the program administrator creates a payment batch." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
199
|
+
"div",
|
|
200
|
+
{
|
|
201
|
+
className: "affiliate-table-scroll",
|
|
202
|
+
role: "region",
|
|
203
|
+
"aria-label": "Your payouts",
|
|
204
|
+
tabIndex: 0,
|
|
205
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
|
|
206
|
+
/* @__PURE__ */ jsxRuntime.jsx("caption", { className: "affiliate-sr-only", children: "Your payout history" }),
|
|
207
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
208
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Date" }),
|
|
209
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "affiliate-number", children: "Amount" }),
|
|
210
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Status" }),
|
|
211
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Reference" })
|
|
212
|
+
] }) }),
|
|
213
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: payouts.map((payout) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
214
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: shared.date(payout.paidAt ?? payout.createdAt) }),
|
|
215
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "affiliate-number", children: shared.money(payout.amount, payout.currency) }),
|
|
216
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: /* @__PURE__ */ jsxRuntime.jsx(shared.Status, { value: payout.status }) }),
|
|
217
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: payout.reference || "No reference" })
|
|
218
|
+
] }, payout.id)) })
|
|
219
|
+
] })
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
] }),
|
|
223
|
+
/* @__PURE__ */ jsxRuntime.jsx(context.PermissionAccess, { permission: permissions.affiliatePermissions.portal.update(), children: /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
224
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-section-heading", children: [
|
|
225
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
226
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Profile and payout details" }),
|
|
227
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-muted", children: affiliate.email })
|
|
228
|
+
] }),
|
|
229
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setEditing(!editing), children: editing ? "Close profile" : "Edit profile" })
|
|
230
|
+
] }),
|
|
231
|
+
editing && /* @__PURE__ */ jsxRuntime.jsx(
|
|
232
|
+
"form",
|
|
233
|
+
{
|
|
234
|
+
className: "affiliate-stack",
|
|
235
|
+
onSubmit: save,
|
|
236
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { disabled: action.pending, children: [
|
|
237
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.ProfileFields, { affiliate }),
|
|
238
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-actions", children: [
|
|
239
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: "affiliate-primary", children: action.pending ? "Saving\u2026" : "Save profile" }),
|
|
240
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setEditing(false), children: "Cancel" })
|
|
241
|
+
] })
|
|
242
|
+
] })
|
|
243
|
+
},
|
|
244
|
+
affiliate.updatedAt
|
|
245
|
+
)
|
|
246
|
+
] }) })
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
exports.AffiliatePortalPage = AffiliatePortalPage;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } 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 { useAffiliateDashboard, useReferralLink, useUpdateAffiliateProfile } from '../../hooks/index.mjs';
|
|
7
|
+
import { AFFILIATE_PLUGIN_ID } from '../../constants.mjs';
|
|
8
|
+
import { useAffiliateAction, AffiliatePage, ActionNotice, Stats, Field, date, money, Status, ProfileFields, readProfile } from '../shared.mjs';
|
|
9
|
+
|
|
10
|
+
function assetHref(value) {
|
|
11
|
+
try {
|
|
12
|
+
const url = new URL(value, window.location.origin);
|
|
13
|
+
return ["https:", "http:"].includes(url.protocol) ? url.href : void 0;
|
|
14
|
+
} catch {
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function AffiliatePortalPage() {
|
|
19
|
+
const { data } = useAffiliateDashboard();
|
|
20
|
+
const [landingPath, setLandingPath] = useState("/");
|
|
21
|
+
const [link, setLink] = useState("");
|
|
22
|
+
const [editing, setEditing] = useState(false);
|
|
23
|
+
const createLink = useReferralLink();
|
|
24
|
+
const update = useUpdateAffiliateProfile();
|
|
25
|
+
const action = useAffiliateAction();
|
|
26
|
+
const { Link, resolve } = usePluginSiteNavigation(AFFILIATE_PLUGIN_ID);
|
|
27
|
+
const { localization } = usePluginOverrides(AFFILIATE_PLUGIN_ID);
|
|
28
|
+
const { affiliate, stats, commissions, payouts, assets } = data;
|
|
29
|
+
const save = (event) => {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
const fields = new FormData(event.currentTarget);
|
|
32
|
+
void action.run(async () => {
|
|
33
|
+
await update.mutateAsync(readProfile(fields));
|
|
34
|
+
setEditing(false);
|
|
35
|
+
setLink("");
|
|
36
|
+
}, "Profile saved");
|
|
37
|
+
};
|
|
38
|
+
if (!affiliate)
|
|
39
|
+
return /* @__PURE__ */ jsx(
|
|
40
|
+
AffiliatePage,
|
|
41
|
+
{
|
|
42
|
+
title: localization?.portal ?? "Affiliate portal",
|
|
43
|
+
admin: false,
|
|
44
|
+
children: /* @__PURE__ */ jsxs("section", { className: "affiliate-stack", children: [
|
|
45
|
+
/* @__PURE__ */ jsx("h2", { children: "Start with an affiliate application" }),
|
|
46
|
+
/* @__PURE__ */ jsx("p", { children: "Apply to receive a referral code and track your commissions here." }),
|
|
47
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
48
|
+
Link,
|
|
49
|
+
{
|
|
50
|
+
className: "affiliate-primary",
|
|
51
|
+
href: resolve("affiliate/apply").href,
|
|
52
|
+
children: "Apply to become an affiliate"
|
|
53
|
+
}
|
|
54
|
+
) })
|
|
55
|
+
] })
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
return /* @__PURE__ */ jsxs(
|
|
59
|
+
AffiliatePage,
|
|
60
|
+
{
|
|
61
|
+
title: localization?.portal ?? "Affiliate portal",
|
|
62
|
+
description: `Referral activity and earnings for ${affiliate.name}.`,
|
|
63
|
+
admin: false,
|
|
64
|
+
action: /* @__PURE__ */ jsx(Status, { value: affiliate.status }),
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsx(ActionNotice, { ...action }),
|
|
67
|
+
affiliate.status !== "approved" && /* @__PURE__ */ jsx("p", { className: "affiliate-notice", children: affiliate.status === "pending" ? "Your application is pending review. Referral tracking starts after approval." : "Your affiliate account is suspended. New referrals are not attributed. Contact the program administrator for help." }),
|
|
68
|
+
/* @__PURE__ */ jsx(Stats, { stats }),
|
|
69
|
+
/* @__PURE__ */ jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
70
|
+
/* @__PURE__ */ jsx("h2", { children: "Your referral link" }),
|
|
71
|
+
/* @__PURE__ */ jsxs("p", { className: "affiliate-muted", children: [
|
|
72
|
+
"Code: ",
|
|
73
|
+
/* @__PURE__ */ jsx("strong", { children: affiliate.code }),
|
|
74
|
+
". Choose a landing page on this site. Visits through your link are recorded before the visitor reaches that page."
|
|
75
|
+
] }),
|
|
76
|
+
/* @__PURE__ */ jsxs(
|
|
77
|
+
"form",
|
|
78
|
+
{
|
|
79
|
+
className: "affiliate-toolbar",
|
|
80
|
+
onSubmit: (event) => {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
void action.run(async () => {
|
|
83
|
+
const next = createLink(affiliate.code, landingPath);
|
|
84
|
+
setLink(next);
|
|
85
|
+
}, "Referral link generated");
|
|
86
|
+
},
|
|
87
|
+
children: [
|
|
88
|
+
/* @__PURE__ */ jsx(
|
|
89
|
+
Field,
|
|
90
|
+
{
|
|
91
|
+
label: "Landing page path",
|
|
92
|
+
hint: "For example, /pricing or /products?category=books.",
|
|
93
|
+
children: /* @__PURE__ */ jsx(
|
|
94
|
+
"input",
|
|
95
|
+
{
|
|
96
|
+
value: landingPath,
|
|
97
|
+
onChange: (event) => {
|
|
98
|
+
setLandingPath(event.target.value);
|
|
99
|
+
setLink("");
|
|
100
|
+
},
|
|
101
|
+
required: true,
|
|
102
|
+
placeholder: "/pricing"
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
/* @__PURE__ */ jsx(
|
|
108
|
+
"button",
|
|
109
|
+
{
|
|
110
|
+
type: "submit",
|
|
111
|
+
className: "affiliate-primary",
|
|
112
|
+
disabled: affiliate.status !== "approved",
|
|
113
|
+
children: "Generate referral link"
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
),
|
|
119
|
+
link && /* @__PURE__ */ jsxs("div", { className: "affiliate-toolbar", children: [
|
|
120
|
+
/* @__PURE__ */ jsx(Field, { label: "Tracking link", children: /* @__PURE__ */ jsx(
|
|
121
|
+
"input",
|
|
122
|
+
{
|
|
123
|
+
readOnly: true,
|
|
124
|
+
value: link,
|
|
125
|
+
onFocus: (event) => event.target.select()
|
|
126
|
+
}
|
|
127
|
+
) }),
|
|
128
|
+
/* @__PURE__ */ jsx(
|
|
129
|
+
"button",
|
|
130
|
+
{
|
|
131
|
+
type: "button",
|
|
132
|
+
onClick: () => void action.run(async () => {
|
|
133
|
+
await navigator.clipboard.writeText(link);
|
|
134
|
+
}, "Referral link copied"),
|
|
135
|
+
children: "Copy referral link"
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
] })
|
|
139
|
+
] }),
|
|
140
|
+
assets.length > 0 && /* @__PURE__ */ jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
141
|
+
/* @__PURE__ */ jsx("h2", { children: "Marketing assets" }),
|
|
142
|
+
/* @__PURE__ */ jsx("ul", { className: "affiliate-assets", children: assets.map((asset) => /* @__PURE__ */ jsxs("li", { children: [
|
|
143
|
+
/* @__PURE__ */ jsx("strong", { children: asset.name }),
|
|
144
|
+
asset.description && /* @__PURE__ */ jsx("p", { className: "affiliate-muted", children: asset.description }),
|
|
145
|
+
/* @__PURE__ */ jsxs("div", { className: "affiliate-actions", children: [
|
|
146
|
+
assetHref(asset.url) && /* @__PURE__ */ jsx(
|
|
147
|
+
"a",
|
|
148
|
+
{
|
|
149
|
+
href: assetHref(asset.url),
|
|
150
|
+
target: "_blank",
|
|
151
|
+
rel: "noreferrer",
|
|
152
|
+
children: "Open link template"
|
|
153
|
+
}
|
|
154
|
+
),
|
|
155
|
+
asset.bannerUrl && assetHref(asset.bannerUrl) && /* @__PURE__ */ jsx(
|
|
156
|
+
"a",
|
|
157
|
+
{
|
|
158
|
+
href: assetHref(asset.bannerUrl),
|
|
159
|
+
target: "_blank",
|
|
160
|
+
rel: "noreferrer",
|
|
161
|
+
children: "Open banner"
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
] })
|
|
165
|
+
] }, `${asset.name}-${asset.url}`)) })
|
|
166
|
+
] }),
|
|
167
|
+
/* @__PURE__ */ jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
168
|
+
/* @__PURE__ */ jsx("h2", { children: "Commissions" }),
|
|
169
|
+
commissions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "affiliate-muted", children: "Your commissions will appear after an attributed conversion." }) : /* @__PURE__ */ jsx(
|
|
170
|
+
"div",
|
|
171
|
+
{
|
|
172
|
+
className: "affiliate-table-scroll",
|
|
173
|
+
role: "region",
|
|
174
|
+
"aria-label": "Your commissions",
|
|
175
|
+
tabIndex: 0,
|
|
176
|
+
children: /* @__PURE__ */ jsxs("table", { children: [
|
|
177
|
+
/* @__PURE__ */ jsx("caption", { className: "affiliate-sr-only", children: "Your commission history" }),
|
|
178
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
179
|
+
/* @__PURE__ */ jsx("th", { children: "Date" }),
|
|
180
|
+
/* @__PURE__ */ jsx("th", { children: "Conversion" }),
|
|
181
|
+
/* @__PURE__ */ jsx("th", { className: "affiliate-number", children: "Amount" }),
|
|
182
|
+
/* @__PURE__ */ jsx("th", { children: "Status" })
|
|
183
|
+
] }) }),
|
|
184
|
+
/* @__PURE__ */ jsx("tbody", { children: commissions.map((commission) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
185
|
+
/* @__PURE__ */ jsx("td", { children: date(commission.createdAt) }),
|
|
186
|
+
/* @__PURE__ */ jsx("td", { children: commission.conversionId }),
|
|
187
|
+
/* @__PURE__ */ jsx("td", { className: "affiliate-number", children: money(commission.amount, commission.currency) }),
|
|
188
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Status, { value: commission.status }) })
|
|
189
|
+
] }, commission.id)) })
|
|
190
|
+
] })
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
] }),
|
|
194
|
+
/* @__PURE__ */ jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
195
|
+
/* @__PURE__ */ jsx("h2", { children: "Payout history" }),
|
|
196
|
+
payouts.length === 0 ? /* @__PURE__ */ jsx("p", { className: "affiliate-muted", children: "Payouts appear when the program administrator creates a payment batch." }) : /* @__PURE__ */ jsx(
|
|
197
|
+
"div",
|
|
198
|
+
{
|
|
199
|
+
className: "affiliate-table-scroll",
|
|
200
|
+
role: "region",
|
|
201
|
+
"aria-label": "Your payouts",
|
|
202
|
+
tabIndex: 0,
|
|
203
|
+
children: /* @__PURE__ */ jsxs("table", { children: [
|
|
204
|
+
/* @__PURE__ */ jsx("caption", { className: "affiliate-sr-only", children: "Your payout history" }),
|
|
205
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
206
|
+
/* @__PURE__ */ jsx("th", { children: "Date" }),
|
|
207
|
+
/* @__PURE__ */ jsx("th", { className: "affiliate-number", children: "Amount" }),
|
|
208
|
+
/* @__PURE__ */ jsx("th", { children: "Status" }),
|
|
209
|
+
/* @__PURE__ */ jsx("th", { children: "Reference" })
|
|
210
|
+
] }) }),
|
|
211
|
+
/* @__PURE__ */ jsx("tbody", { children: payouts.map((payout) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
212
|
+
/* @__PURE__ */ jsx("td", { children: date(payout.paidAt ?? payout.createdAt) }),
|
|
213
|
+
/* @__PURE__ */ jsx("td", { className: "affiliate-number", children: money(payout.amount, payout.currency) }),
|
|
214
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Status, { value: payout.status }) }),
|
|
215
|
+
/* @__PURE__ */ jsx("td", { children: payout.reference || "No reference" })
|
|
216
|
+
] }, payout.id)) })
|
|
217
|
+
] })
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
] }),
|
|
221
|
+
/* @__PURE__ */ jsx(PermissionAccess, { permission: affiliatePermissions.portal.update(), children: /* @__PURE__ */ jsxs("section", { className: "affiliate-section affiliate-stack", children: [
|
|
222
|
+
/* @__PURE__ */ jsxs("div", { className: "affiliate-section-heading", children: [
|
|
223
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
224
|
+
/* @__PURE__ */ jsx("h2", { children: "Profile and payout details" }),
|
|
225
|
+
/* @__PURE__ */ jsx("p", { className: "affiliate-muted", children: affiliate.email })
|
|
226
|
+
] }),
|
|
227
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => setEditing(!editing), children: editing ? "Close profile" : "Edit profile" })
|
|
228
|
+
] }),
|
|
229
|
+
editing && /* @__PURE__ */ jsx(
|
|
230
|
+
"form",
|
|
231
|
+
{
|
|
232
|
+
className: "affiliate-stack",
|
|
233
|
+
onSubmit: save,
|
|
234
|
+
children: /* @__PURE__ */ jsxs("fieldset", { disabled: action.pending, children: [
|
|
235
|
+
/* @__PURE__ */ jsx(ProfileFields, { affiliate }),
|
|
236
|
+
/* @__PURE__ */ jsxs("div", { className: "affiliate-actions", children: [
|
|
237
|
+
/* @__PURE__ */ jsx("button", { type: "submit", className: "affiliate-primary", children: action.pending ? "Saving\u2026" : "Save profile" }),
|
|
238
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => setEditing(false), children: "Cancel" })
|
|
239
|
+
] })
|
|
240
|
+
] })
|
|
241
|
+
},
|
|
242
|
+
affiliate.updatedAt
|
|
243
|
+
)
|
|
244
|
+
] }) })
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export { AffiliatePortalPage };
|
|
@@ -0,0 +1,160 @@
|
|
|
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 AffiliatesPage() {
|
|
13
|
+
const [status, setStatus] = react.useState("");
|
|
14
|
+
const [offset, setOffset] = react.useState(0);
|
|
15
|
+
const [adding, setAdding] = react.useState(false);
|
|
16
|
+
const { data } = client_hooks_index.useAffiliates({
|
|
17
|
+
status: status || void 0,
|
|
18
|
+
limit: 25,
|
|
19
|
+
offset
|
|
20
|
+
});
|
|
21
|
+
const create = client_hooks_index.useCreateAffiliate();
|
|
22
|
+
const update = client_hooks_index.useUpdateAffiliate();
|
|
23
|
+
const action = shared.useAffiliateAction();
|
|
24
|
+
const { Link, resolve } = context.usePluginSiteNavigation(constants.AFFILIATE_PLUGIN_ID);
|
|
25
|
+
const { localization } = context.usePluginOverrides(constants.AFFILIATE_PLUGIN_ID);
|
|
26
|
+
const save = (event) => {
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
const fields = new FormData(event.currentTarget);
|
|
29
|
+
void action.run(async () => {
|
|
30
|
+
await create.mutateAsync({
|
|
31
|
+
...shared.readProfile(fields),
|
|
32
|
+
userId: String(fields.get("userId") ?? "")
|
|
33
|
+
});
|
|
34
|
+
setAdding(false);
|
|
35
|
+
}, "Affiliate added. Review the profile to approve the application.");
|
|
36
|
+
};
|
|
37
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
38
|
+
shared.AffiliatePage,
|
|
39
|
+
{
|
|
40
|
+
title: localization?.affiliates ?? "Affiliates",
|
|
41
|
+
description: "Review applications, approve partners, and manage referral profiles.",
|
|
42
|
+
action: /* @__PURE__ */ jsxRuntime.jsx(context.PermissionAccess, { permission: permissions.affiliatePermissions.affiliate.create(), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
43
|
+
"button",
|
|
44
|
+
{
|
|
45
|
+
className: "affiliate-primary",
|
|
46
|
+
type: "button",
|
|
47
|
+
onClick: () => setAdding(!adding),
|
|
48
|
+
children: adding ? "Close form" : "Add affiliate"
|
|
49
|
+
}
|
|
50
|
+
) }),
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.ActionNotice, { ...action }),
|
|
53
|
+
adding && /* @__PURE__ */ jsxRuntime.jsxs("form", { className: "affiliate-panel affiliate-stack", onSubmit: save, children: [
|
|
54
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Add affiliate" }),
|
|
55
|
+
/* @__PURE__ */ jsxRuntime.jsxs("fieldset", { disabled: action.pending, children: [
|
|
56
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.ProfileFields, { userId: true }),
|
|
57
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-actions", children: [
|
|
58
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "affiliate-primary", type: "submit", children: action.pending ? "Saving\u2026" : "Save affiliate" }),
|
|
59
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setAdding(false), children: "Cancel" })
|
|
60
|
+
] })
|
|
61
|
+
] })
|
|
62
|
+
] }),
|
|
63
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-toolbar", children: [
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Filter by status", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
65
|
+
"select",
|
|
66
|
+
{
|
|
67
|
+
value: status,
|
|
68
|
+
onChange: (event) => {
|
|
69
|
+
setStatus(event.target.value);
|
|
70
|
+
setOffset(0);
|
|
71
|
+
},
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "All statuses" }),
|
|
74
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "pending", children: "Pending" }),
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "approved", children: "Approved" }),
|
|
76
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "suspended", children: "Suspended" })
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
) }),
|
|
80
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "affiliate-muted", children: [
|
|
81
|
+
data.total,
|
|
82
|
+
" ",
|
|
83
|
+
data.total === 1 ? "affiliate" : "affiliates"
|
|
84
|
+
] })
|
|
85
|
+
] }),
|
|
86
|
+
data.items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-empty", children: "No affiliates match. Add an affiliate or adjust the status filter." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
87
|
+
"div",
|
|
88
|
+
{
|
|
89
|
+
className: "affiliate-table-scroll",
|
|
90
|
+
role: "region",
|
|
91
|
+
"aria-label": "Affiliates",
|
|
92
|
+
tabIndex: 0,
|
|
93
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsx("caption", { className: "affiliate-sr-only", children: "Affiliate applications and profiles" }),
|
|
95
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
96
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Name" }),
|
|
97
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Referral code" }),
|
|
98
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Status" }),
|
|
99
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Applied" }),
|
|
100
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Actions" })
|
|
101
|
+
] }) }),
|
|
102
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: data.items.map((affiliate) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
103
|
+
/* @__PURE__ */ jsxRuntime.jsxs("td", { children: [
|
|
104
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
105
|
+
Link,
|
|
106
|
+
{
|
|
107
|
+
className: "affiliate-record-link",
|
|
108
|
+
href: resolve(
|
|
109
|
+
"affiliate/admin/affiliates",
|
|
110
|
+
encodeURIComponent(affiliate.id)
|
|
111
|
+
).href,
|
|
112
|
+
children: affiliate.name
|
|
113
|
+
}
|
|
114
|
+
),
|
|
115
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-small affiliate-muted", children: affiliate.email })
|
|
116
|
+
] }),
|
|
117
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: affiliate.code }),
|
|
118
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: /* @__PURE__ */ jsxRuntime.jsx(shared.Status, { value: affiliate.status }) }),
|
|
119
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: shared.date(affiliate.createdAt) }),
|
|
120
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
121
|
+
context.PermissionAccess,
|
|
122
|
+
{
|
|
123
|
+
permission: permissions.affiliatePermissions.affiliate.update({
|
|
124
|
+
affiliateId: affiliate.id,
|
|
125
|
+
userId: affiliate.userId,
|
|
126
|
+
status: affiliate.status
|
|
127
|
+
}),
|
|
128
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
129
|
+
"button",
|
|
130
|
+
{
|
|
131
|
+
type: "button",
|
|
132
|
+
disabled: action.pending,
|
|
133
|
+
"aria-label": `${affiliate.status === "approved" ? "Suspend" : "Approve"} ${affiliate.name}`,
|
|
134
|
+
onClick: () => void action.run(
|
|
135
|
+
async () => {
|
|
136
|
+
await update.mutateAsync({
|
|
137
|
+
id: affiliate.id,
|
|
138
|
+
data: {
|
|
139
|
+
status: affiliate.status === "approved" ? "suspended" : "approved"
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
affiliate.status === "approved" ? "Affiliate suspended" : "Affiliate approved"
|
|
144
|
+
),
|
|
145
|
+
children: affiliate.status === "approved" ? "Suspend" : "Approve"
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
) })
|
|
150
|
+
] }, affiliate.id)) })
|
|
151
|
+
] })
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.Pagination, { offset, total: data.total, onChange: setOffset })
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
exports.AffiliatesPage = AffiliatesPage;
|