@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,158 @@
|
|
|
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 { useAffiliates, useCreateAffiliate, useUpdateAffiliate } from '../../hooks/index.mjs';
|
|
7
|
+
import { AFFILIATE_PLUGIN_ID } from '../../constants.mjs';
|
|
8
|
+
import { useAffiliateAction, AffiliatePage, ActionNotice, ProfileFields, Field, Status, date, Pagination, readProfile } from '../shared.mjs';
|
|
9
|
+
|
|
10
|
+
function AffiliatesPage() {
|
|
11
|
+
const [status, setStatus] = useState("");
|
|
12
|
+
const [offset, setOffset] = useState(0);
|
|
13
|
+
const [adding, setAdding] = useState(false);
|
|
14
|
+
const { data } = useAffiliates({
|
|
15
|
+
status: status || void 0,
|
|
16
|
+
limit: 25,
|
|
17
|
+
offset
|
|
18
|
+
});
|
|
19
|
+
const create = useCreateAffiliate();
|
|
20
|
+
const update = useUpdateAffiliate();
|
|
21
|
+
const action = useAffiliateAction();
|
|
22
|
+
const { Link, resolve } = usePluginSiteNavigation(AFFILIATE_PLUGIN_ID);
|
|
23
|
+
const { localization } = usePluginOverrides(AFFILIATE_PLUGIN_ID);
|
|
24
|
+
const save = (event) => {
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
const fields = new FormData(event.currentTarget);
|
|
27
|
+
void action.run(async () => {
|
|
28
|
+
await create.mutateAsync({
|
|
29
|
+
...readProfile(fields),
|
|
30
|
+
userId: String(fields.get("userId") ?? "")
|
|
31
|
+
});
|
|
32
|
+
setAdding(false);
|
|
33
|
+
}, "Affiliate added. Review the profile to approve the application.");
|
|
34
|
+
};
|
|
35
|
+
return /* @__PURE__ */ jsxs(
|
|
36
|
+
AffiliatePage,
|
|
37
|
+
{
|
|
38
|
+
title: localization?.affiliates ?? "Affiliates",
|
|
39
|
+
description: "Review applications, approve partners, and manage referral profiles.",
|
|
40
|
+
action: /* @__PURE__ */ jsx(PermissionAccess, { permission: affiliatePermissions.affiliate.create(), children: /* @__PURE__ */ jsx(
|
|
41
|
+
"button",
|
|
42
|
+
{
|
|
43
|
+
className: "affiliate-primary",
|
|
44
|
+
type: "button",
|
|
45
|
+
onClick: () => setAdding(!adding),
|
|
46
|
+
children: adding ? "Close form" : "Add affiliate"
|
|
47
|
+
}
|
|
48
|
+
) }),
|
|
49
|
+
children: [
|
|
50
|
+
/* @__PURE__ */ jsx(ActionNotice, { ...action }),
|
|
51
|
+
adding && /* @__PURE__ */ jsxs("form", { className: "affiliate-panel affiliate-stack", onSubmit: save, children: [
|
|
52
|
+
/* @__PURE__ */ jsx("h2", { children: "Add affiliate" }),
|
|
53
|
+
/* @__PURE__ */ jsxs("fieldset", { disabled: action.pending, children: [
|
|
54
|
+
/* @__PURE__ */ jsx(ProfileFields, { userId: true }),
|
|
55
|
+
/* @__PURE__ */ jsxs("div", { className: "affiliate-actions", children: [
|
|
56
|
+
/* @__PURE__ */ jsx("button", { className: "affiliate-primary", type: "submit", children: action.pending ? "Saving\u2026" : "Save affiliate" }),
|
|
57
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => setAdding(false), children: "Cancel" })
|
|
58
|
+
] })
|
|
59
|
+
] })
|
|
60
|
+
] }),
|
|
61
|
+
/* @__PURE__ */ jsxs("div", { className: "affiliate-toolbar", children: [
|
|
62
|
+
/* @__PURE__ */ jsx(Field, { label: "Filter by status", children: /* @__PURE__ */ jsxs(
|
|
63
|
+
"select",
|
|
64
|
+
{
|
|
65
|
+
value: status,
|
|
66
|
+
onChange: (event) => {
|
|
67
|
+
setStatus(event.target.value);
|
|
68
|
+
setOffset(0);
|
|
69
|
+
},
|
|
70
|
+
children: [
|
|
71
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "All statuses" }),
|
|
72
|
+
/* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
|
|
73
|
+
/* @__PURE__ */ jsx("option", { value: "approved", children: "Approved" }),
|
|
74
|
+
/* @__PURE__ */ jsx("option", { value: "suspended", children: "Suspended" })
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
) }),
|
|
78
|
+
/* @__PURE__ */ jsxs("p", { className: "affiliate-muted", children: [
|
|
79
|
+
data.total,
|
|
80
|
+
" ",
|
|
81
|
+
data.total === 1 ? "affiliate" : "affiliates"
|
|
82
|
+
] })
|
|
83
|
+
] }),
|
|
84
|
+
data.items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "affiliate-empty", children: "No affiliates match. Add an affiliate or adjust the status filter." }) : /* @__PURE__ */ jsx(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
className: "affiliate-table-scroll",
|
|
88
|
+
role: "region",
|
|
89
|
+
"aria-label": "Affiliates",
|
|
90
|
+
tabIndex: 0,
|
|
91
|
+
children: /* @__PURE__ */ jsxs("table", { children: [
|
|
92
|
+
/* @__PURE__ */ jsx("caption", { className: "affiliate-sr-only", children: "Affiliate applications and profiles" }),
|
|
93
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
94
|
+
/* @__PURE__ */ jsx("th", { children: "Name" }),
|
|
95
|
+
/* @__PURE__ */ jsx("th", { children: "Referral code" }),
|
|
96
|
+
/* @__PURE__ */ jsx("th", { children: "Status" }),
|
|
97
|
+
/* @__PURE__ */ jsx("th", { children: "Applied" }),
|
|
98
|
+
/* @__PURE__ */ jsx("th", { children: "Actions" })
|
|
99
|
+
] }) }),
|
|
100
|
+
/* @__PURE__ */ jsx("tbody", { children: data.items.map((affiliate) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
101
|
+
/* @__PURE__ */ jsxs("td", { children: [
|
|
102
|
+
/* @__PURE__ */ jsx(
|
|
103
|
+
Link,
|
|
104
|
+
{
|
|
105
|
+
className: "affiliate-record-link",
|
|
106
|
+
href: resolve(
|
|
107
|
+
"affiliate/admin/affiliates",
|
|
108
|
+
encodeURIComponent(affiliate.id)
|
|
109
|
+
).href,
|
|
110
|
+
children: affiliate.name
|
|
111
|
+
}
|
|
112
|
+
),
|
|
113
|
+
/* @__PURE__ */ jsx("p", { className: "affiliate-small affiliate-muted", children: affiliate.email })
|
|
114
|
+
] }),
|
|
115
|
+
/* @__PURE__ */ jsx("td", { children: affiliate.code }),
|
|
116
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Status, { value: affiliate.status }) }),
|
|
117
|
+
/* @__PURE__ */ jsx("td", { children: date(affiliate.createdAt) }),
|
|
118
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(
|
|
119
|
+
PermissionAccess,
|
|
120
|
+
{
|
|
121
|
+
permission: affiliatePermissions.affiliate.update({
|
|
122
|
+
affiliateId: affiliate.id,
|
|
123
|
+
userId: affiliate.userId,
|
|
124
|
+
status: affiliate.status
|
|
125
|
+
}),
|
|
126
|
+
children: /* @__PURE__ */ jsx(
|
|
127
|
+
"button",
|
|
128
|
+
{
|
|
129
|
+
type: "button",
|
|
130
|
+
disabled: action.pending,
|
|
131
|
+
"aria-label": `${affiliate.status === "approved" ? "Suspend" : "Approve"} ${affiliate.name}`,
|
|
132
|
+
onClick: () => void action.run(
|
|
133
|
+
async () => {
|
|
134
|
+
await update.mutateAsync({
|
|
135
|
+
id: affiliate.id,
|
|
136
|
+
data: {
|
|
137
|
+
status: affiliate.status === "approved" ? "suspended" : "approved"
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
affiliate.status === "approved" ? "Affiliate suspended" : "Affiliate approved"
|
|
142
|
+
),
|
|
143
|
+
children: affiliate.status === "approved" ? "Suspend" : "Approve"
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
) })
|
|
148
|
+
] }, affiliate.id)) })
|
|
149
|
+
] })
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
/* @__PURE__ */ jsx(Pagination, { offset, total: data.total, onChange: setOffset })
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { AffiliatesPage };
|
|
@@ -0,0 +1,151 @@
|
|
|
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 CommissionsPage() {
|
|
13
|
+
const [status, setStatus] = react.useState("");
|
|
14
|
+
const [affiliateId, setAffiliateId] = react.useState("");
|
|
15
|
+
const [offset, setOffset] = react.useState(0);
|
|
16
|
+
const { data } = client_hooks_index.useCommissions({
|
|
17
|
+
status: status || void 0,
|
|
18
|
+
affiliateId: affiliateId || void 0,
|
|
19
|
+
offset,
|
|
20
|
+
limit: 25
|
|
21
|
+
});
|
|
22
|
+
const update = client_hooks_index.useUpdateCommission();
|
|
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
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
27
|
+
shared.AffiliatePage,
|
|
28
|
+
{
|
|
29
|
+
title: localization?.commissions ?? "Commissions",
|
|
30
|
+
description: "Review attributed conversions before including commissions in a payout.",
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.ActionNotice, { ...action }),
|
|
33
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-toolbar", children: [
|
|
34
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Filter by status", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
35
|
+
"select",
|
|
36
|
+
{
|
|
37
|
+
value: status,
|
|
38
|
+
onChange: (event) => {
|
|
39
|
+
setStatus(event.target.value);
|
|
40
|
+
setOffset(0);
|
|
41
|
+
},
|
|
42
|
+
children: [
|
|
43
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "All statuses" }),
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "pending", children: "Pending" }),
|
|
45
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "approved", children: "Approved" }),
|
|
46
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "paid", children: "Paid" }),
|
|
47
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "voided", children: "Voided" })
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
) }),
|
|
51
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.Field, { label: "Affiliate ID", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
52
|
+
"input",
|
|
53
|
+
{
|
|
54
|
+
value: affiliateId,
|
|
55
|
+
onChange: (event) => {
|
|
56
|
+
setAffiliateId(event.target.value);
|
|
57
|
+
setOffset(0);
|
|
58
|
+
},
|
|
59
|
+
placeholder: "All affiliates"
|
|
60
|
+
}
|
|
61
|
+
) })
|
|
62
|
+
] }),
|
|
63
|
+
data.items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-empty", children: "No commissions match. Commissions appear after an attributed conversion is recorded." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
64
|
+
"div",
|
|
65
|
+
{
|
|
66
|
+
className: "affiliate-table-scroll",
|
|
67
|
+
role: "region",
|
|
68
|
+
"aria-label": "Commissions",
|
|
69
|
+
tabIndex: 0,
|
|
70
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
|
|
71
|
+
/* @__PURE__ */ jsxRuntime.jsx("caption", { className: "affiliate-sr-only", children: "Affiliate commission review" }),
|
|
72
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Affiliate / conversion" }),
|
|
74
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "affiliate-number", children: "Commission" }),
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Status" }),
|
|
76
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Created" }),
|
|
77
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Review" })
|
|
78
|
+
] }) }),
|
|
79
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: data.items.map((commission) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
80
|
+
/* @__PURE__ */ jsxRuntime.jsxs("td", { children: [
|
|
81
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
82
|
+
Link,
|
|
83
|
+
{
|
|
84
|
+
href: resolve(
|
|
85
|
+
"affiliate/admin/affiliates",
|
|
86
|
+
encodeURIComponent(commission.affiliateId)
|
|
87
|
+
).href,
|
|
88
|
+
children: commission.affiliateId
|
|
89
|
+
}
|
|
90
|
+
),
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-small affiliate-muted", children: commission.conversionId })
|
|
92
|
+
] }),
|
|
93
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "affiliate-number", children: shared.money(commission.amount, commission.currency) }),
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsxs("td", { children: [
|
|
95
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.Status, { value: commission.status }),
|
|
96
|
+
commission.payoutId && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "affiliate-small affiliate-muted", children: "Included in payout" })
|
|
97
|
+
] }),
|
|
98
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: shared.date(commission.createdAt) }),
|
|
99
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
100
|
+
context.PermissionAccess,
|
|
101
|
+
{
|
|
102
|
+
permission: permissions.affiliatePermissions.commission.update({
|
|
103
|
+
commissionId: commission.id,
|
|
104
|
+
affiliateId: commission.affiliateId,
|
|
105
|
+
status: commission.status
|
|
106
|
+
}),
|
|
107
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "affiliate-actions", children: [
|
|
108
|
+
commission.status === "pending" && !commission.payoutId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
109
|
+
"button",
|
|
110
|
+
{
|
|
111
|
+
type: "button",
|
|
112
|
+
disabled: action.pending,
|
|
113
|
+
"aria-label": `Approve commission ${commission.id}`,
|
|
114
|
+
onClick: () => void action.run(async () => {
|
|
115
|
+
await update.mutateAsync({
|
|
116
|
+
id: commission.id,
|
|
117
|
+
status: "approved"
|
|
118
|
+
});
|
|
119
|
+
}, "Commission approved"),
|
|
120
|
+
children: "Approve"
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
["pending", "approved"].includes(commission.status) && !commission.payoutId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
124
|
+
"button",
|
|
125
|
+
{
|
|
126
|
+
type: "button",
|
|
127
|
+
disabled: action.pending,
|
|
128
|
+
"aria-label": `Void commission ${commission.id}`,
|
|
129
|
+
onClick: () => void action.run(async () => {
|
|
130
|
+
await update.mutateAsync({
|
|
131
|
+
id: commission.id,
|
|
132
|
+
status: "voided"
|
|
133
|
+
});
|
|
134
|
+
}, "Commission voided"),
|
|
135
|
+
children: "Void"
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
] })
|
|
139
|
+
}
|
|
140
|
+
) })
|
|
141
|
+
] }, commission.id)) })
|
|
142
|
+
] })
|
|
143
|
+
}
|
|
144
|
+
),
|
|
145
|
+
/* @__PURE__ */ jsxRuntime.jsx(shared.Pagination, { offset, total: data.total, onChange: setOffset })
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
exports.CommissionsPage = CommissionsPage;
|
|
@@ -0,0 +1,149 @@
|
|
|
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 { useCommissions, useUpdateCommission } 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 CommissionsPage() {
|
|
11
|
+
const [status, setStatus] = useState("");
|
|
12
|
+
const [affiliateId, setAffiliateId] = useState("");
|
|
13
|
+
const [offset, setOffset] = useState(0);
|
|
14
|
+
const { data } = useCommissions({
|
|
15
|
+
status: status || void 0,
|
|
16
|
+
affiliateId: affiliateId || void 0,
|
|
17
|
+
offset,
|
|
18
|
+
limit: 25
|
|
19
|
+
});
|
|
20
|
+
const update = useUpdateCommission();
|
|
21
|
+
const action = useAffiliateAction();
|
|
22
|
+
const { Link, resolve } = usePluginSiteNavigation(AFFILIATE_PLUGIN_ID);
|
|
23
|
+
const { localization } = usePluginOverrides(AFFILIATE_PLUGIN_ID);
|
|
24
|
+
return /* @__PURE__ */ jsxs(
|
|
25
|
+
AffiliatePage,
|
|
26
|
+
{
|
|
27
|
+
title: localization?.commissions ?? "Commissions",
|
|
28
|
+
description: "Review attributed conversions before including commissions in a payout.",
|
|
29
|
+
children: [
|
|
30
|
+
/* @__PURE__ */ jsx(ActionNotice, { ...action }),
|
|
31
|
+
/* @__PURE__ */ jsxs("div", { className: "affiliate-toolbar", children: [
|
|
32
|
+
/* @__PURE__ */ jsx(Field, { label: "Filter by status", children: /* @__PURE__ */ jsxs(
|
|
33
|
+
"select",
|
|
34
|
+
{
|
|
35
|
+
value: status,
|
|
36
|
+
onChange: (event) => {
|
|
37
|
+
setStatus(event.target.value);
|
|
38
|
+
setOffset(0);
|
|
39
|
+
},
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "All statuses" }),
|
|
42
|
+
/* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
|
|
43
|
+
/* @__PURE__ */ jsx("option", { value: "approved", children: "Approved" }),
|
|
44
|
+
/* @__PURE__ */ jsx("option", { value: "paid", children: "Paid" }),
|
|
45
|
+
/* @__PURE__ */ jsx("option", { value: "voided", children: "Voided" })
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
) }),
|
|
49
|
+
/* @__PURE__ */ jsx(Field, { label: "Affiliate ID", children: /* @__PURE__ */ jsx(
|
|
50
|
+
"input",
|
|
51
|
+
{
|
|
52
|
+
value: affiliateId,
|
|
53
|
+
onChange: (event) => {
|
|
54
|
+
setAffiliateId(event.target.value);
|
|
55
|
+
setOffset(0);
|
|
56
|
+
},
|
|
57
|
+
placeholder: "All affiliates"
|
|
58
|
+
}
|
|
59
|
+
) })
|
|
60
|
+
] }),
|
|
61
|
+
data.items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "affiliate-empty", children: "No commissions match. Commissions appear after an attributed conversion is recorded." }) : /* @__PURE__ */ jsx(
|
|
62
|
+
"div",
|
|
63
|
+
{
|
|
64
|
+
className: "affiliate-table-scroll",
|
|
65
|
+
role: "region",
|
|
66
|
+
"aria-label": "Commissions",
|
|
67
|
+
tabIndex: 0,
|
|
68
|
+
children: /* @__PURE__ */ jsxs("table", { children: [
|
|
69
|
+
/* @__PURE__ */ jsx("caption", { className: "affiliate-sr-only", children: "Affiliate commission review" }),
|
|
70
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
71
|
+
/* @__PURE__ */ jsx("th", { children: "Affiliate / conversion" }),
|
|
72
|
+
/* @__PURE__ */ jsx("th", { className: "affiliate-number", children: "Commission" }),
|
|
73
|
+
/* @__PURE__ */ jsx("th", { children: "Status" }),
|
|
74
|
+
/* @__PURE__ */ jsx("th", { children: "Created" }),
|
|
75
|
+
/* @__PURE__ */ jsx("th", { children: "Review" })
|
|
76
|
+
] }) }),
|
|
77
|
+
/* @__PURE__ */ jsx("tbody", { children: data.items.map((commission) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
78
|
+
/* @__PURE__ */ jsxs("td", { children: [
|
|
79
|
+
/* @__PURE__ */ jsx(
|
|
80
|
+
Link,
|
|
81
|
+
{
|
|
82
|
+
href: resolve(
|
|
83
|
+
"affiliate/admin/affiliates",
|
|
84
|
+
encodeURIComponent(commission.affiliateId)
|
|
85
|
+
).href,
|
|
86
|
+
children: commission.affiliateId
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
/* @__PURE__ */ jsx("p", { className: "affiliate-small affiliate-muted", children: commission.conversionId })
|
|
90
|
+
] }),
|
|
91
|
+
/* @__PURE__ */ jsx("td", { className: "affiliate-number", children: money(commission.amount, commission.currency) }),
|
|
92
|
+
/* @__PURE__ */ jsxs("td", { children: [
|
|
93
|
+
/* @__PURE__ */ jsx(Status, { value: commission.status }),
|
|
94
|
+
commission.payoutId && /* @__PURE__ */ jsx("p", { className: "affiliate-small affiliate-muted", children: "Included in payout" })
|
|
95
|
+
] }),
|
|
96
|
+
/* @__PURE__ */ jsx("td", { children: date(commission.createdAt) }),
|
|
97
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(
|
|
98
|
+
PermissionAccess,
|
|
99
|
+
{
|
|
100
|
+
permission: affiliatePermissions.commission.update({
|
|
101
|
+
commissionId: commission.id,
|
|
102
|
+
affiliateId: commission.affiliateId,
|
|
103
|
+
status: commission.status
|
|
104
|
+
}),
|
|
105
|
+
children: /* @__PURE__ */ jsxs("div", { className: "affiliate-actions", children: [
|
|
106
|
+
commission.status === "pending" && !commission.payoutId && /* @__PURE__ */ jsx(
|
|
107
|
+
"button",
|
|
108
|
+
{
|
|
109
|
+
type: "button",
|
|
110
|
+
disabled: action.pending,
|
|
111
|
+
"aria-label": `Approve commission ${commission.id}`,
|
|
112
|
+
onClick: () => void action.run(async () => {
|
|
113
|
+
await update.mutateAsync({
|
|
114
|
+
id: commission.id,
|
|
115
|
+
status: "approved"
|
|
116
|
+
});
|
|
117
|
+
}, "Commission approved"),
|
|
118
|
+
children: "Approve"
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
["pending", "approved"].includes(commission.status) && !commission.payoutId && /* @__PURE__ */ jsx(
|
|
122
|
+
"button",
|
|
123
|
+
{
|
|
124
|
+
type: "button",
|
|
125
|
+
disabled: action.pending,
|
|
126
|
+
"aria-label": `Void commission ${commission.id}`,
|
|
127
|
+
onClick: () => void action.run(async () => {
|
|
128
|
+
await update.mutateAsync({
|
|
129
|
+
id: commission.id,
|
|
130
|
+
status: "voided"
|
|
131
|
+
});
|
|
132
|
+
}, "Commission voided"),
|
|
133
|
+
children: "Void"
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
] })
|
|
137
|
+
}
|
|
138
|
+
) })
|
|
139
|
+
] }, commission.id)) })
|
|
140
|
+
] })
|
|
141
|
+
}
|
|
142
|
+
),
|
|
143
|
+
/* @__PURE__ */ jsx(Pagination, { offset, total: data.total, onChange: setOffset })
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { CommissionsPage };
|