@burdenoff/microfe-coolandlovely 2026.1101.6 → 2026.1101.8
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/coolandlovely/CoolAndLovelyRoot.d.ts.map +1 -1
- package/dist/coolandlovely/CoolAndLovelyRoot.js +18 -23
- package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
- package/dist/coolandlovely/context/QueryScope.d.ts +5 -0
- package/dist/coolandlovely/context/QueryScope.d.ts.map +1 -0
- package/dist/coolandlovely/context/QueryScope.js +18 -0
- package/dist/coolandlovely/context/QueryScope.js.map +1 -0
- package/dist/coolandlovely/context/queryScopeKey.d.ts +5 -0
- package/dist/coolandlovely/context/queryScopeKey.d.ts.map +1 -0
- package/dist/coolandlovely/context/queryScopeKey.js +14 -0
- package/dist/coolandlovely/context/queryScopeKey.js.map +1 -0
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts +1 -1
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +7 -6
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useCreatorAnalytics.d.ts +19 -0
- package/dist/coolandlovely/hooks/useCreatorAnalytics.d.ts.map +1 -0
- package/dist/coolandlovely/hooks/useCreatorAnalytics.js +24 -0
- package/dist/coolandlovely/hooks/useCreatorAnalytics.js.map +1 -0
- package/dist/coolandlovely/pages/commerce/CreatorAnalyticsSection.d.ts +2 -0
- package/dist/coolandlovely/pages/commerce/CreatorAnalyticsSection.d.ts.map +1 -0
- package/dist/coolandlovely/pages/commerce/CreatorAnalyticsSection.js +184 -0
- package/dist/coolandlovely/pages/commerce/CreatorAnalyticsSection.js.map +1 -0
- package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.js +125 -123
- package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.js.map +1 -1
- package/dist/generated/global-types.d.ts +787 -51
- package/dist/generated/global-types.d.ts.map +1 -1
- package/dist/generated/wspace-operations.d.ts +56 -1
- package/dist/generated/wspace-operations.d.ts.map +1 -1
- package/dist/generated/wspace-operations.js +27 -0
- package/dist/generated/wspace-operations.js.map +1 -0
- package/dist/generated/wspace-types.d.ts +20845 -2889
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/package.json +17 -15
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreatorAnalyticsSection.js","names":[],"sources":["../../../../src/coolandlovely/pages/commerce/CreatorAnalyticsSection.tsx"],"sourcesContent":["import { useId, useState } from 'react';\nimport { BarChart3, Heart, Bookmark, Users, ShoppingBag, Wallet } from 'lucide-react';\nimport { clearGraphqlFetchResponseCache } from '@burdenoff/fe-libs/shared/graphql/fetch';\n\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { ErrorView, LoadingView } from '../../components/StateViews';\nimport { useTr } from '../../hooks';\nimport { useCreatorAnalytics } from '../../hooks/useCreatorAnalytics';\nimport { formatDate, formatPrice } from '../../utils/formatters';\n\nfunction CreatorAnalyticsPanel({ active }: { active: boolean }) {\n const tr = useTr();\n const [currency, setCurrency] = useState('USD');\n const [currencyInput, setCurrencyInput] = useState('USD');\n const analytics = useCreatorAnalytics(currency, active);\n const selectId = useId();\n const refresh = () => {\n // React Query refetch still traverses the canonical short-lived transport cache.\n // This clears read memoization; it does not invalidate mounted query data or abort in-flight reads.\n clearGraphqlFetchResponseCache();\n void analytics.refetch();\n };\n return (\n <div className=\"mt-4\" data-testid=\"creator-analytics\">\n <form\n className=\"mb-4 flex flex-wrap items-center gap-3\"\n onSubmit={(event) => {\n event.preventDefault();\n setCurrency(currencyInput.trim().toUpperCase());\n }}\n >\n <label htmlFor={selectId} className=\"text-sm text-text-secondary\">\n {tr('coolandlovely.analytics.currency', 'Sales currency (3 letters)')}\n </label>\n <input\n id={selectId}\n value={currencyInput}\n onChange={(event) => setCurrencyInput(event.target.value)}\n required\n minLength={3}\n maxLength={3}\n pattern=\"[A-Za-z]{3}\"\n autoComplete=\"off\"\n className=\"w-24 rounded-lg border border-border-seam bg-bg-surface px-3 py-2 uppercase text-text-primary\"\n />\n <button\n type=\"submit\"\n className=\"rounded-lg border border-border-seam px-3 py-2 text-sm text-text-primary\"\n >\n {tr('coolandlovely.analytics.applyCurrency', 'Apply currency')}\n </button>\n <button\n type=\"button\"\n onClick={refresh}\n disabled={analytics.isFetching}\n className=\"rounded-lg border border-border-seam px-3 py-2 text-sm text-text-primary disabled:opacity-50\"\n >\n {tr('coolandlovely.analytics.refresh', 'Refresh analytics')}\n </button>\n </form>\n {analytics.isLoading ? (\n <LoadingView />\n ) : analytics.isError || !analytics.data ? (\n <ErrorView onRetry={refresh} />\n ) : (\n <>\n <p className=\"mb-3 text-sm text-text-secondary\">\n {tr('coolandlovely.analytics.current', 'Current look engagement and followers')}\n </p>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n icon={<BarChart3 className=\"h-5 w-5\" />}\n label={tr('coolandlovely.analytics.looks', 'Looks')}\n value={analytics.data.lookCount}\n />\n <MetricsCard\n icon={<Heart className=\"h-5 w-5\" />}\n label={tr('coolandlovely.analytics.likes', 'Likes')}\n value={analytics.data.likeCount}\n />\n <MetricsCard\n icon={<Bookmark className=\"h-5 w-5\" />}\n label={tr('coolandlovely.analytics.saves', 'Saves')}\n value={analytics.data.saveCount}\n />\n <MetricsCard\n icon={<Users className=\"h-5 w-5\" />}\n label={tr('coolandlovely.analytics.followers', 'Followers')}\n value={analytics.data.followerCount}\n />\n </div>\n <h3 className=\"mb-3 mt-6 text-lg font-semibold text-text-primary\">\n {tr('coolandlovely.analytics.periodDates', '{{start}} – {{end}}', {\n start: formatDate(analytics.data.periodStart, { hour: undefined, minute: undefined }),\n end: formatDate(analytics.data.asOf, { hour: undefined, minute: undefined }),\n })}\n </h3>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <MetricsCard\n icon={<ShoppingBag className=\"h-5 w-5\" />}\n label={tr('coolandlovely.analytics.sales', 'Attributed paid sales')}\n value={formatPrice(analytics.data.attributedSalesAmount, analytics.data.currency)}\n />\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.analytics.commissions', 'Accrued look commissions')}\n value={formatPrice(analytics.data.commissionAmount, analytics.data.currency)}\n />\n </div>\n <p className=\"mt-3 text-sm text-text-secondary\">\n {tr(\n 'coolandlovely.analytics.moneyNote',\n '{{count}} paid order lines in {{currency}}. Reversed commissions and collaboration fees are excluded. Accrued commissions are not your available payout balance.',\n { count: analytics.data.attributedSaleLines, currency: analytics.data.currency }\n )}\n </p>\n <dl className=\"mt-5 flex flex-wrap gap-6 text-sm text-text-primary\">\n <div>\n <dt className=\"text-text-secondary\">\n {tr('coolandlovely.analytics.gained', 'Recorded follows')}\n </dt>\n <dd className=\"font-semibold tabular-nums\">{analytics.data.followersGained}</dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {tr('coolandlovely.analytics.lost', 'Recorded unfollows')}\n </dt>\n <dd className=\"font-semibold tabular-nums\">{analytics.data.followersLost}</dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {tr('coolandlovely.analytics.net', 'Net follower change')}\n </dt>\n <dd className=\"font-semibold tabular-nums\">{analytics.data.netFollowerChange}</dd>\n </div>\n </dl>\n <p className=\"mt-3 text-sm text-text-secondary\">\n {analytics.data.followerHistoryStartedAt\n ? tr(\n 'coolandlovely.analytics.historyStarted',\n 'First follower change recorded {{date}}. Earlier changes are unavailable; this may cover less than 30 days.',\n { date: formatDate(analytics.data.followerHistoryStartedAt) }\n )\n : tr(\n 'coolandlovely.analytics.noHistory',\n 'No follower changes have been recorded yet. Existing followers are included above; earlier changes are unavailable.'\n )}\n </p>\n <p className=\"mt-2 text-xs text-text-muted\">\n {tr('coolandlovely.analytics.asOf', 'Updated {{date}}', {\n date: formatDate(analytics.data.asOf),\n })}\n </p>\n </>\n )}\n </div>\n );\n}\n\nexport function CreatorAnalyticsSection() {\n const tr = useTr();\n const [panelState, setPanelState] = useState<'unopened' | 'open' | 'closed'>('unopened');\n const open = panelState === 'open';\n const panelId = useId();\n return (\n <section className=\"mt-6 rounded-xl border border-border-seam p-4\">\n <h2 id={`${panelId}-title`} className=\"text-lg font-semibold text-text-primary\">\n {tr('coolandlovely.analytics.title', 'Creator analytics')}\n </h2>\n <button\n type=\"button\"\n aria-expanded={open}\n aria-controls={panelId}\n onClick={() => setPanelState((value) => (value === 'open' ? 'closed' : 'open'))}\n className=\"mt-3 rounded-lg border border-border-seam px-3 py-2 text-sm text-text-primary\"\n >\n {open\n ? tr('coolandlovely.analytics.hide', 'Hide analytics')\n : tr('coolandlovely.analytics.show', 'Show analytics')}\n </button>\n <div id={panelId} role=\"region\" aria-labelledby={`${panelId}-title`} hidden={!open}>\n {panelState !== 'unopened' && <CreatorAnalyticsPanel active={open} />}\n </div>\n </section>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreatorEarningsPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/commerce/CreatorEarningsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"CreatorEarningsPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/commerce/CreatorEarningsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAyBH,wBAAgB,mBAAmB,gCA8QlC"}
|
|
@@ -10,245 +10,247 @@ import { formatDate as c, formatPrice as l } from "../../utils/formatters.js";
|
|
|
10
10
|
import { EmptyState as u } from "../../components/EmptyState.js";
|
|
11
11
|
import { TextField as d } from "../../components/Field.js";
|
|
12
12
|
import { useMyCollaborationPayouts as f, useMyCreatorEarnings as p, useMyCreatorEarningsSummary as m, useRequestCreatorPayout as h } from "../../hooks/useCommerceApi.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
13
|
+
import { CreatorAnalyticsSection as g } from "./CreatorAnalyticsSection.js";
|
|
14
|
+
import { useState as _ } from "react";
|
|
15
|
+
import { Loader2 as v, Wallet as y } from "lucide-react";
|
|
16
|
+
import { jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
17
|
+
import { GlassCard as S } from "@burdenoff/fe-libs/ui";
|
|
17
18
|
//#region src/coolandlovely/pages/commerce/CreatorEarningsPage.tsx
|
|
18
|
-
function
|
|
19
|
-
let
|
|
20
|
-
if (
|
|
21
|
-
title:
|
|
22
|
-
children: /* @__PURE__ */
|
|
19
|
+
function C() {
|
|
20
|
+
let C = i(), w = m(), T = p(), E = f(), D = h(), { navigateTo: O } = e(), [k, A] = _(""), j = C("coolandlovely.earnings.title", "Creator earnings");
|
|
21
|
+
if (w.isLoading || T.isLoading) return /* @__PURE__ */ b(n, {
|
|
22
|
+
title: j,
|
|
23
|
+
children: /* @__PURE__ */ b(s, {})
|
|
23
24
|
});
|
|
24
|
-
if (
|
|
25
|
-
title:
|
|
26
|
-
children: /* @__PURE__ */
|
|
27
|
-
|
|
25
|
+
if (w.isError || T.isError || !w.data || !T.data) return /* @__PURE__ */ b(n, {
|
|
26
|
+
title: j,
|
|
27
|
+
children: /* @__PURE__ */ b(o, { onRetry: () => {
|
|
28
|
+
w.refetch(), T.refetch();
|
|
28
29
|
} })
|
|
29
30
|
});
|
|
30
|
-
let
|
|
31
|
-
return /* @__PURE__ */
|
|
32
|
-
title:
|
|
33
|
-
description:
|
|
34
|
-
rate: Math.round(
|
|
35
|
-
days:
|
|
31
|
+
let M = w.data, N = M.currency ?? "USD", P = Number(k), F = M.currency !== null && P > 0 && P <= M.availableAmount;
|
|
32
|
+
return /* @__PURE__ */ x(n, {
|
|
33
|
+
title: j,
|
|
34
|
+
description: C("coolandlovely.earnings.description", "You earn {{rate}}% of every piece bought from your looks, and the agreed fee of every collaboration a brand pays. Commissions become available {{days}} days after payment.", {
|
|
35
|
+
rate: Math.round(M.commissionRate * 100),
|
|
36
|
+
days: M.holdDays
|
|
36
37
|
}),
|
|
37
38
|
children: [
|
|
38
|
-
/* @__PURE__ */ b(
|
|
39
|
-
|
|
39
|
+
/* @__PURE__ */ b(g, {}),
|
|
40
|
+
/* @__PURE__ */ x("div", {
|
|
41
|
+
className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
40
42
|
"data-testid": "earnings-summary",
|
|
41
43
|
children: [
|
|
42
|
-
/* @__PURE__ */
|
|
43
|
-
icon: /* @__PURE__ */ y
|
|
44
|
-
label:
|
|
45
|
-
value: l(
|
|
44
|
+
/* @__PURE__ */ b(r, {
|
|
45
|
+
icon: /* @__PURE__ */ b(y, { className: "h-5 w-5" }),
|
|
46
|
+
label: C("coolandlovely.earnings.available", "Available"),
|
|
47
|
+
value: l(M.availableAmount, N)
|
|
46
48
|
}),
|
|
47
|
-
/* @__PURE__ */
|
|
48
|
-
icon: /* @__PURE__ */ y
|
|
49
|
-
label:
|
|
50
|
-
value: l(
|
|
49
|
+
/* @__PURE__ */ b(r, {
|
|
50
|
+
icon: /* @__PURE__ */ b(y, { className: "h-5 w-5" }),
|
|
51
|
+
label: C("coolandlovely.earnings.pending", "In return window"),
|
|
52
|
+
value: l(M.pendingAmount, N)
|
|
51
53
|
}),
|
|
52
|
-
/* @__PURE__ */
|
|
53
|
-
icon: /* @__PURE__ */ y
|
|
54
|
-
label:
|
|
55
|
-
value: l(
|
|
54
|
+
/* @__PURE__ */ b(r, {
|
|
55
|
+
icon: /* @__PURE__ */ b(y, { className: "h-5 w-5" }),
|
|
56
|
+
label: C("coolandlovely.earnings.reserved", "Payout requested"),
|
|
57
|
+
value: l(M.reservedAmount, N)
|
|
56
58
|
}),
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
-
icon: /* @__PURE__ */ y
|
|
59
|
-
label:
|
|
60
|
-
value: l(
|
|
59
|
+
/* @__PURE__ */ b(r, {
|
|
60
|
+
icon: /* @__PURE__ */ b(y, { className: "h-5 w-5" }),
|
|
61
|
+
label: C("coolandlovely.earnings.paid", "Paid out"),
|
|
62
|
+
value: l(M.paidAmount, N)
|
|
61
63
|
})
|
|
62
64
|
]
|
|
63
65
|
}),
|
|
64
|
-
!
|
|
66
|
+
!M.billingAvailable && /* @__PURE__ */ b("p", {
|
|
65
67
|
className: "mt-3 text-sm text-status-warning-text",
|
|
66
|
-
children:
|
|
68
|
+
children: C("coolandlovely.earnings.billingUnavailable", "Balances could not be confirmed with billing just now; the figures above come from your commission history.")
|
|
67
69
|
}),
|
|
68
|
-
/* @__PURE__ */
|
|
70
|
+
/* @__PURE__ */ x("div", {
|
|
69
71
|
className: "mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
70
|
-
children: [/* @__PURE__ */
|
|
72
|
+
children: [/* @__PURE__ */ x("section", {
|
|
71
73
|
className: "lg:col-span-2",
|
|
72
|
-
children: [/* @__PURE__ */
|
|
74
|
+
children: [/* @__PURE__ */ b("h3", {
|
|
73
75
|
className: "mb-3 text-lg font-semibold text-text-primary",
|
|
74
|
-
children:
|
|
75
|
-
}),
|
|
76
|
-
icon: /* @__PURE__ */ y
|
|
77
|
-
title:
|
|
78
|
-
description:
|
|
79
|
-
}) : /* @__PURE__ */
|
|
76
|
+
children: C("coolandlovely.earnings.history", "Commission history")
|
|
77
|
+
}), T.data.items.length === 0 ? /* @__PURE__ */ b(u, {
|
|
78
|
+
icon: /* @__PURE__ */ b(y, { className: "h-8 w-8" }),
|
|
79
|
+
title: C("coolandlovely.earnings.emptyTitle", "No commissions yet"),
|
|
80
|
+
description: C("coolandlovely.earnings.emptyDescription", "Publish looks with catalogue pieces. When someone buys from your look, the commission shows up here.")
|
|
81
|
+
}) : /* @__PURE__ */ b("div", {
|
|
80
82
|
className: "overflow-x-auto rounded-xl border border-border-seam",
|
|
81
|
-
children: /* @__PURE__ */
|
|
83
|
+
children: /* @__PURE__ */ x("table", {
|
|
82
84
|
className: "w-full text-sm",
|
|
83
|
-
children: [/* @__PURE__ */
|
|
85
|
+
children: [/* @__PURE__ */ b("thead", {
|
|
84
86
|
className: "bg-bg-sunken text-left text-xs uppercase tracking-wide text-text-secondary",
|
|
85
|
-
children: /* @__PURE__ */
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
+
children: /* @__PURE__ */ x("tr", { children: [
|
|
88
|
+
/* @__PURE__ */ b("th", {
|
|
87
89
|
className: "px-4 py-2",
|
|
88
|
-
children:
|
|
90
|
+
children: C("coolandlovely.earnings.order", "Order")
|
|
89
91
|
}),
|
|
90
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ b("th", {
|
|
91
93
|
className: "px-4 py-2 text-right",
|
|
92
|
-
children:
|
|
94
|
+
children: C("coolandlovely.earnings.sale", "Sale")
|
|
93
95
|
}),
|
|
94
|
-
/* @__PURE__ */
|
|
96
|
+
/* @__PURE__ */ b("th", {
|
|
95
97
|
className: "px-4 py-2 text-right",
|
|
96
|
-
children:
|
|
98
|
+
children: C("coolandlovely.earnings.commission", "Commission")
|
|
97
99
|
}),
|
|
98
|
-
/* @__PURE__ */
|
|
100
|
+
/* @__PURE__ */ b("th", {
|
|
99
101
|
className: "px-4 py-2",
|
|
100
|
-
children:
|
|
102
|
+
children: C("coolandlovely.earnings.availableOn", "Available on")
|
|
101
103
|
}),
|
|
102
|
-
/* @__PURE__ */
|
|
104
|
+
/* @__PURE__ */ b("th", {
|
|
103
105
|
className: "px-4 py-2",
|
|
104
|
-
children:
|
|
106
|
+
children: C("coolandlovely.earnings.ledger", "Ledger")
|
|
105
107
|
})
|
|
106
108
|
] })
|
|
107
|
-
}), /* @__PURE__ */
|
|
109
|
+
}), /* @__PURE__ */ b("tbody", { children: T.data.items.map((e) => /* @__PURE__ */ x("tr", {
|
|
108
110
|
className: "border-t border-border-seam",
|
|
109
111
|
children: [
|
|
110
|
-
/* @__PURE__ */
|
|
112
|
+
/* @__PURE__ */ b("td", {
|
|
111
113
|
className: "px-4 py-2 font-mono text-text-primary",
|
|
112
114
|
children: e.orderNumber ?? "—"
|
|
113
115
|
}),
|
|
114
|
-
/* @__PURE__ */
|
|
116
|
+
/* @__PURE__ */ b("td", {
|
|
115
117
|
className: "px-4 py-2 text-right tabular-nums text-text-secondary",
|
|
116
118
|
children: l(e.saleAmount, e.currency)
|
|
117
119
|
}),
|
|
118
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ b("td", {
|
|
119
121
|
className: t("px-4 py-2 text-right font-semibold tabular-nums text-text-primary", e.reversalStatus === "REVERSED" && "text-text-secondary line-through"),
|
|
120
122
|
children: l(e.amount, e.currency)
|
|
121
123
|
}),
|
|
122
|
-
/* @__PURE__ */
|
|
124
|
+
/* @__PURE__ */ b("td", {
|
|
123
125
|
className: "px-4 py-2 text-text-secondary",
|
|
124
126
|
children: c(e.availableAt, {
|
|
125
127
|
hour: void 0,
|
|
126
128
|
minute: void 0
|
|
127
129
|
})
|
|
128
130
|
}),
|
|
129
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ b("td", {
|
|
130
132
|
className: "px-4 py-2",
|
|
131
133
|
"data-testid": "earning-ledger-status",
|
|
132
|
-
children: /* @__PURE__ */
|
|
134
|
+
children: /* @__PURE__ */ b(a, { status: e.reversalStatus === "REVERSED" || e.reversalStatus === "NOT_REVERSIBLE" ? e.reversalStatus : e.billingSyncStatus })
|
|
133
135
|
})
|
|
134
136
|
]
|
|
135
137
|
}, e.id)) })]
|
|
136
138
|
})
|
|
137
139
|
})]
|
|
138
|
-
}), /* @__PURE__ */
|
|
140
|
+
}), /* @__PURE__ */ x(S, {
|
|
139
141
|
treatment: "glass",
|
|
140
142
|
className: "h-fit space-y-4 p-6",
|
|
141
143
|
children: [
|
|
142
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ b("h3", {
|
|
143
145
|
className: "text-base font-semibold text-text-primary",
|
|
144
|
-
children:
|
|
146
|
+
children: C("coolandlovely.earnings.requestTitle", "Request a payout")
|
|
145
147
|
}),
|
|
146
|
-
/* @__PURE__ */
|
|
148
|
+
/* @__PURE__ */ b("p", {
|
|
147
149
|
className: "text-sm text-text-secondary",
|
|
148
|
-
children:
|
|
150
|
+
children: C("coolandlovely.earnings.requestHint", "Payouts are reviewed by the platform and sent to the payout account on your billing profile.")
|
|
149
151
|
}),
|
|
150
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ b(d, {
|
|
151
153
|
id: "coo-payout-amount",
|
|
152
154
|
type: "number",
|
|
153
|
-
label:
|
|
154
|
-
value:
|
|
155
|
-
onChange:
|
|
156
|
-
hint:
|
|
155
|
+
label: C("coolandlovely.earnings.amount", "Amount ({{currency}})", { currency: N }),
|
|
156
|
+
value: k,
|
|
157
|
+
onChange: A,
|
|
158
|
+
hint: C("coolandlovely.earnings.maxHint", "Up to {{amount}}", { amount: l(M.availableAmount, N) })
|
|
157
159
|
}),
|
|
158
|
-
|
|
160
|
+
D.error && /* @__PURE__ */ b("p", {
|
|
159
161
|
className: "text-sm text-status-error-text",
|
|
160
|
-
children:
|
|
162
|
+
children: D.error.message
|
|
161
163
|
}),
|
|
162
|
-
|
|
164
|
+
D.data && /* @__PURE__ */ b("p", {
|
|
163
165
|
className: "text-sm text-status-success-text",
|
|
164
|
-
children:
|
|
165
|
-
amount: l(
|
|
166
|
-
status:
|
|
166
|
+
children: C("coolandlovely.earnings.requested", "Payout of {{amount}} requested ({{status}}).", {
|
|
167
|
+
amount: l(D.data.requestedAmount, D.data.currency),
|
|
168
|
+
status: D.data.status
|
|
167
169
|
})
|
|
168
170
|
}),
|
|
169
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ x("button", {
|
|
170
172
|
type: "button",
|
|
171
|
-
disabled: !
|
|
172
|
-
onClick: () =>
|
|
173
|
-
amount:
|
|
174
|
-
currency:
|
|
175
|
-
}, { onSuccess: () =>
|
|
173
|
+
disabled: !F || D.isPending,
|
|
174
|
+
onClick: () => D.mutate({
|
|
175
|
+
amount: P,
|
|
176
|
+
currency: N
|
|
177
|
+
}, { onSuccess: () => A("") }),
|
|
176
178
|
className: "inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50",
|
|
177
|
-
children: [
|
|
179
|
+
children: [D.isPending && /* @__PURE__ */ b(v, { className: "h-4 w-4 animate-spin" }), C("coolandlovely.earnings.requestButton", "Request payout")]
|
|
178
180
|
})
|
|
179
181
|
]
|
|
180
182
|
})]
|
|
181
183
|
}),
|
|
182
|
-
/* @__PURE__ */
|
|
184
|
+
/* @__PURE__ */ x("section", {
|
|
183
185
|
className: "mt-8",
|
|
184
186
|
"data-testid": "collaboration-fees",
|
|
185
|
-
children: [/* @__PURE__ */
|
|
187
|
+
children: [/* @__PURE__ */ b("h3", {
|
|
186
188
|
className: "mb-3 text-lg font-semibold text-text-primary",
|
|
187
|
-
children:
|
|
188
|
-
}),
|
|
189
|
+
children: C("coolandlovely.earnings.feesTitle", "Collaboration fees")
|
|
190
|
+
}), E.isError ? /* @__PURE__ */ b("p", {
|
|
189
191
|
className: "text-sm text-status-error-text",
|
|
190
|
-
children:
|
|
191
|
-
}) : !
|
|
192
|
+
children: C("coolandlovely.earnings.feesError", "Collaboration fees could not be loaded.")
|
|
193
|
+
}) : !E.data || E.data.items.length === 0 ? /* @__PURE__ */ b("p", {
|
|
192
194
|
className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
193
|
-
children:
|
|
194
|
-
}) : /* @__PURE__ */
|
|
195
|
+
children: E.isLoading ? C("coolandlovely.earnings.feesLoading", "Loading collaboration fees…") : C("coolandlovely.earnings.feesEmpty", "When a brand pays the agreed fee of a published collaboration, it shows up here.")
|
|
196
|
+
}) : /* @__PURE__ */ b("div", {
|
|
195
197
|
className: "overflow-x-auto rounded-xl border border-border-seam",
|
|
196
|
-
children: /* @__PURE__ */
|
|
198
|
+
children: /* @__PURE__ */ x("table", {
|
|
197
199
|
className: "w-full text-sm",
|
|
198
|
-
children: [/* @__PURE__ */
|
|
200
|
+
children: [/* @__PURE__ */ b("thead", {
|
|
199
201
|
className: "bg-bg-sunken text-left text-xs uppercase tracking-wide text-text-secondary",
|
|
200
|
-
children: /* @__PURE__ */
|
|
201
|
-
/* @__PURE__ */
|
|
202
|
+
children: /* @__PURE__ */ x("tr", { children: [
|
|
203
|
+
/* @__PURE__ */ b("th", {
|
|
202
204
|
className: "px-4 py-2",
|
|
203
|
-
children:
|
|
205
|
+
children: C("coolandlovely.earnings.collaboration", "Collaboration")
|
|
204
206
|
}),
|
|
205
|
-
/* @__PURE__ */
|
|
207
|
+
/* @__PURE__ */ b("th", {
|
|
206
208
|
className: "px-4 py-2 text-right",
|
|
207
|
-
children:
|
|
209
|
+
children: C("coolandlovely.earnings.fee", "Fee")
|
|
208
210
|
}),
|
|
209
|
-
/* @__PURE__ */
|
|
211
|
+
/* @__PURE__ */ b("th", {
|
|
210
212
|
className: "px-4 py-2",
|
|
211
|
-
children:
|
|
213
|
+
children: C("coolandlovely.earnings.brandPayment", "Brand payment")
|
|
212
214
|
}),
|
|
213
|
-
/* @__PURE__ */
|
|
215
|
+
/* @__PURE__ */ b("th", {
|
|
214
216
|
className: "px-4 py-2",
|
|
215
|
-
children:
|
|
217
|
+
children: C("coolandlovely.earnings.availableOn", "Available on")
|
|
216
218
|
}),
|
|
217
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ b("th", {
|
|
218
220
|
className: "px-4 py-2",
|
|
219
|
-
children:
|
|
221
|
+
children: C("coolandlovely.earnings.ledger", "Ledger")
|
|
220
222
|
})
|
|
221
223
|
] })
|
|
222
|
-
}), /* @__PURE__ */
|
|
224
|
+
}), /* @__PURE__ */ b("tbody", { children: E.data.items.map((e) => /* @__PURE__ */ x("tr", {
|
|
223
225
|
className: "border-t border-border-seam",
|
|
224
226
|
children: [
|
|
225
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ b("td", {
|
|
226
228
|
className: "px-4 py-2",
|
|
227
|
-
children: /* @__PURE__ */
|
|
229
|
+
children: /* @__PURE__ */ b("button", {
|
|
228
230
|
type: "button",
|
|
229
|
-
onClick: () =>
|
|
231
|
+
onClick: () => O(`/collaborations/${e.collaborationId}`),
|
|
230
232
|
className: "text-left font-medium text-text-primary hover:underline",
|
|
231
233
|
children: e.collaborationTitle ?? "—"
|
|
232
234
|
})
|
|
233
235
|
}),
|
|
234
|
-
/* @__PURE__ */
|
|
236
|
+
/* @__PURE__ */ b("td", {
|
|
235
237
|
className: "px-4 py-2 text-right font-semibold tabular-nums text-text-primary",
|
|
236
238
|
children: l(e.amount, e.currency)
|
|
237
239
|
}),
|
|
238
|
-
/* @__PURE__ */
|
|
240
|
+
/* @__PURE__ */ b("td", {
|
|
239
241
|
className: "px-4 py-2",
|
|
240
|
-
children: /* @__PURE__ */
|
|
242
|
+
children: /* @__PURE__ */ b(a, { status: e.status })
|
|
241
243
|
}),
|
|
242
|
-
/* @__PURE__ */
|
|
244
|
+
/* @__PURE__ */ b("td", {
|
|
243
245
|
className: "px-4 py-2 text-text-secondary",
|
|
244
246
|
children: e.earningAvailableAt ? c(e.earningAvailableAt, {
|
|
245
247
|
hour: void 0,
|
|
246
248
|
minute: void 0
|
|
247
249
|
}) : "—"
|
|
248
250
|
}),
|
|
249
|
-
/* @__PURE__ */
|
|
251
|
+
/* @__PURE__ */ b("td", {
|
|
250
252
|
className: "px-4 py-2",
|
|
251
|
-
children: e.earningSyncStatus ? /* @__PURE__ */
|
|
253
|
+
children: e.earningSyncStatus ? /* @__PURE__ */ b(a, { status: e.earningSyncStatus }) : "—"
|
|
252
254
|
})
|
|
253
255
|
]
|
|
254
256
|
}, e.id)) })]
|
|
@@ -259,6 +261,6 @@ function S() {
|
|
|
259
261
|
});
|
|
260
262
|
}
|
|
261
263
|
//#endregion
|
|
262
|
-
export {
|
|
264
|
+
export { C as CreatorEarningsPage };
|
|
263
265
|
|
|
264
266
|
//# sourceMappingURL=CreatorEarningsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreatorEarningsPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/commerce/CreatorEarningsPage.tsx"],"sourcesContent":["/**\n * Creator Earnings Page (BOFF-3370)\n * @module coolandlovely/pages/commerce\n *\n * A creator's look commissions: every piece bought from one of their published looks earns\n * them a commission once the order is paid. Balances come from global-billing's earnings\n * ledger (`cooMyCreatorEarningsSummary`); a creator can ask for a payout of the available\n * balance (`cooRequestCreatorPayout`), which billing queues for payout review.\n *\n * Collaboration fees (BOFF-9637): when a brand pays the agreed fee of a published collaboration,\n * it lands here too (`cooMyCollaborationPayouts`) and counts towards the same payable balance.\n */\n\nimport { useState } from 'react';\nimport { Loader2, Wallet } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\nimport { EmptyState } from '../../components/EmptyState';\nimport { TextField } from '../../components/Field';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { PageLayout } from '../../components/PageLayout';\nimport { ErrorView, LoadingView } from '../../components/StateViews';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { useTr } from '../../hooks';\nimport {\n useMyCollaborationPayouts,\n useMyCreatorEarnings,\n useMyCreatorEarningsSummary,\n useRequestCreatorPayout,\n} from '../../hooks/useCommerceApi';\nimport { cn } from '../../utils/cn';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { formatDate, formatPrice } from '../../utils/formatters';\n\nexport function CreatorEarningsPage() {\n const tr = useTr();\n const summary = useMyCreatorEarningsSummary();\n const earnings = useMyCreatorEarnings();\n const fees = useMyCollaborationPayouts();\n const payout = useRequestCreatorPayout();\n const { navigateTo } = useCoolAndLovely();\n const [amount, setAmount] = useState('');\n const title = tr('coolandlovely.earnings.title', 'Creator earnings');\n\n if (summary.isLoading || earnings.isLoading) {\n return (\n <PageLayout title={title}>\n <LoadingView />\n </PageLayout>\n );\n }\n if (summary.isError || earnings.isError || !summary.data || !earnings.data) {\n return (\n <PageLayout title={title}>\n <ErrorView\n onRetry={() => {\n void summary.refetch();\n void earnings.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n const s = summary.data;\n const currency = s.currency ?? 'USD';\n const requested = Number(amount);\n const canRequest = s.currency !== null && requested > 0 && requested <= s.availableAmount;\n\n return (\n <PageLayout\n title={title}\n description={tr(\n 'coolandlovely.earnings.description',\n 'You earn {{rate}}% of every piece bought from your looks, and the agreed fee of every collaboration a brand pays. Commissions become available {{days}} days after payment.',\n { rate: Math.round(s.commissionRate * 100), days: s.holdDays }\n )}\n >\n <div\n className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\"\n data-testid=\"earnings-summary\"\n >\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.earnings.available', 'Available')}\n value={formatPrice(s.availableAmount, currency)}\n />\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.earnings.pending', 'In return window')}\n value={formatPrice(s.pendingAmount, currency)}\n />\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.earnings.reserved', 'Payout requested')}\n value={formatPrice(s.reservedAmount, currency)}\n />\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.earnings.paid', 'Paid out')}\n value={formatPrice(s.paidAmount, currency)}\n />\n </div>\n {!s.billingAvailable && (\n <p className=\"mt-3 text-sm text-status-warning-text\">\n {tr(\n 'coolandlovely.earnings.billingUnavailable',\n 'Balances could not be confirmed with billing just now; the figures above come from your commission history.'\n )}\n </p>\n )}\n\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <section className=\"lg:col-span-2\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n {tr('coolandlovely.earnings.history', 'Commission history')}\n </h3>\n {earnings.data.items.length === 0 ? (\n <EmptyState\n icon={<Wallet className=\"h-8 w-8\" />}\n title={tr('coolandlovely.earnings.emptyTitle', 'No commissions yet')}\n description={tr(\n 'coolandlovely.earnings.emptyDescription',\n 'Publish looks with catalogue pieces. When someone buys from your look, the commission shows up here.'\n )}\n />\n ) : (\n <div className=\"overflow-x-auto rounded-xl border border-border-seam\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-bg-sunken text-left text-xs uppercase tracking-wide text-text-secondary\">\n <tr>\n <th className=\"px-4 py-2\">{tr('coolandlovely.earnings.order', 'Order')}</th>\n <th className=\"px-4 py-2 text-right\">\n {tr('coolandlovely.earnings.sale', 'Sale')}\n </th>\n <th className=\"px-4 py-2 text-right\">\n {tr('coolandlovely.earnings.commission', 'Commission')}\n </th>\n <th className=\"px-4 py-2\">\n {tr('coolandlovely.earnings.availableOn', 'Available on')}\n </th>\n <th className=\"px-4 py-2\">{tr('coolandlovely.earnings.ledger', 'Ledger')}</th>\n </tr>\n </thead>\n <tbody>\n {earnings.data.items.map((earning) => (\n <tr key={earning.id} className=\"border-t border-border-seam\">\n <td className=\"px-4 py-2 font-mono text-text-primary\">\n {earning.orderNumber ?? '—'}\n </td>\n <td className=\"px-4 py-2 text-right tabular-nums text-text-secondary\">\n {formatPrice(earning.saleAmount, earning.currency)}\n </td>\n <td\n className={cn(\n 'px-4 py-2 text-right font-semibold tabular-nums text-text-primary',\n earning.reversalStatus === 'REVERSED' &&\n 'text-text-secondary line-through'\n )}\n >\n {formatPrice(earning.amount, earning.currency)}\n </td>\n <td className=\"px-4 py-2 text-text-secondary\">\n {formatDate(earning.availableAt, { hour: undefined, minute: undefined })}\n </td>\n <td className=\"px-4 py-2\" data-testid=\"earning-ledger-status\">\n {/* A refunded line's commission is reversed (BOFF-9702). */}\n <StatusBadge\n status={\n earning.reversalStatus === 'REVERSED' ||\n earning.reversalStatus === 'NOT_REVERSIBLE'\n ? earning.reversalStatus\n : earning.billingSyncStatus\n }\n />\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n\n <GlassCard treatment=\"glass\" className=\"h-fit space-y-4 p-6\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('coolandlovely.earnings.requestTitle', 'Request a payout')}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'coolandlovely.earnings.requestHint',\n 'Payouts are reviewed by the platform and sent to the payout account on your billing profile.'\n )}\n </p>\n <TextField\n id=\"coo-payout-amount\"\n type=\"number\"\n label={tr('coolandlovely.earnings.amount', 'Amount ({{currency}})', { currency })}\n value={amount}\n onChange={setAmount}\n hint={tr('coolandlovely.earnings.maxHint', 'Up to {{amount}}', {\n amount: formatPrice(s.availableAmount, currency),\n })}\n />\n {payout.error && <p className=\"text-sm text-status-error-text\">{payout.error.message}</p>}\n {payout.data && (\n <p className=\"text-sm text-status-success-text\">\n {tr(\n 'coolandlovely.earnings.requested',\n 'Payout of {{amount}} requested ({{status}}).',\n {\n amount: formatPrice(payout.data.requestedAmount, payout.data.currency),\n status: payout.data.status,\n }\n )}\n </p>\n )}\n <button\n type=\"button\"\n disabled={!canRequest || payout.isPending}\n onClick={() =>\n payout.mutate({ amount: requested, currency }, { onSuccess: () => setAmount('') })\n }\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {payout.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {tr('coolandlovely.earnings.requestButton', 'Request payout')}\n </button>\n </GlassCard>\n </div>\n\n <section className=\"mt-8\" data-testid=\"collaboration-fees\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n {tr('coolandlovely.earnings.feesTitle', 'Collaboration fees')}\n </h3>\n {fees.isError ? (\n <p className=\"text-sm text-status-error-text\">\n {tr('coolandlovely.earnings.feesError', 'Collaboration fees could not be loaded.')}\n </p>\n ) : !fees.data || fees.data.items.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n {fees.isLoading\n ? tr('coolandlovely.earnings.feesLoading', 'Loading collaboration fees…')\n : tr(\n 'coolandlovely.earnings.feesEmpty',\n 'When a brand pays the agreed fee of a published collaboration, it shows up here.'\n )}\n </p>\n ) : (\n <div className=\"overflow-x-auto rounded-xl border border-border-seam\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-bg-sunken text-left text-xs uppercase tracking-wide text-text-secondary\">\n <tr>\n <th className=\"px-4 py-2\">\n {tr('coolandlovely.earnings.collaboration', 'Collaboration')}\n </th>\n <th className=\"px-4 py-2 text-right\">\n {tr('coolandlovely.earnings.fee', 'Fee')}\n </th>\n <th className=\"px-4 py-2\">\n {tr('coolandlovely.earnings.brandPayment', 'Brand payment')}\n </th>\n <th className=\"px-4 py-2\">\n {tr('coolandlovely.earnings.availableOn', 'Available on')}\n </th>\n <th className=\"px-4 py-2\">{tr('coolandlovely.earnings.ledger', 'Ledger')}</th>\n </tr>\n </thead>\n <tbody>\n {fees.data.items.map((fee) => (\n <tr key={fee.id} className=\"border-t border-border-seam\">\n <td className=\"px-4 py-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collaborations/${fee.collaborationId}`)}\n className=\"text-left font-medium text-text-primary hover:underline\"\n >\n {fee.collaborationTitle ?? '—'}\n </button>\n </td>\n <td className=\"px-4 py-2 text-right font-semibold tabular-nums text-text-primary\">\n {formatPrice(fee.amount, fee.currency)}\n </td>\n <td className=\"px-4 py-2\">\n <StatusBadge status={fee.status} />\n </td>\n <td className=\"px-4 py-2 text-text-secondary\">\n {fee.earningAvailableAt\n ? formatDate(fee.earningAvailableAt, { hour: undefined, minute: undefined })\n : '—'}\n </td>\n <td className=\"px-4 py-2\">\n {fee.earningSyncStatus ? <StatusBadge status={fee.earningSyncStatus} /> : '—'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkCA,SAAgB,IAAsB;CACpC,IAAM,IAAK,EAAM,GACX,IAAU,EAA4B,GACtC,IAAW,EAAqB,GAChC,IAAO,EAA0B,GACjC,IAAS,EAAwB,GACjC,EAAE,kBAAe,EAAiB,GAClC,CAAC,GAAQ,KAAa,EAAS,EAAE,GACjC,IAAQ,EAAG,gCAAgC,kBAAkB;CAEnE,IAAI,EAAQ,aAAa,EAAS,WAChC,OACE,kBAAC,GAAD;EAAmB;YACjB,kBAAC,GAAD,CAAc,CAAA;CACJ,CAAA;CAGhB,IAAI,EAAQ,WAAW,EAAS,WAAW,CAAC,EAAQ,QAAQ,CAAC,EAAS,MACpE,OACE,kBAAC,GAAD;EAAmB;YACjB,kBAAC,GAAD,EACE,eAAe;GAEb,AADA,EAAa,QAAQ,GACrB,EAAc,QAAQ;EACxB,EACD,CAAA;CACS,CAAA;CAIhB,IAAM,IAAI,EAAQ,MACZ,IAAW,EAAE,YAAY,OACzB,IAAY,OAAO,CAAM,GACzB,IAAa,EAAE,aAAa,QAAQ,IAAY,KAAK,KAAa,EAAE;CAE1E,OACE,kBAAC,GAAD;EACS;EACP,aAAa,EACX,sCACA,+KACA;GAAE,MAAM,KAAK,MAAM,EAAE,iBAAiB,GAAG;GAAG,MAAM,EAAE;EAAS,CAC/D;YANF;GAQE,kBAAC,OAAD;IACE,WAAU;IACV,eAAY;cAFd;KAIE,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;MACnC,OAAO,EAAG,oCAAoC,WAAW;MACzD,OAAO,EAAY,EAAE,iBAAiB,CAAQ;KAC/C,CAAA;KACD,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;MACnC,OAAO,EAAG,kCAAkC,kBAAkB;MAC9D,OAAO,EAAY,EAAE,eAAe,CAAQ;KAC7C,CAAA;KACD,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;MACnC,OAAO,EAAG,mCAAmC,kBAAkB;MAC/D,OAAO,EAAY,EAAE,gBAAgB,CAAQ;KAC9C,CAAA;KACD,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;MACnC,OAAO,EAAG,+BAA+B,UAAU;MACnD,OAAO,EAAY,EAAE,YAAY,CAAQ;KAC1C,CAAA;IACE;;GACJ,CAAC,EAAE,oBACF,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,6CACA,6GACF;GACC,CAAA;GAGL,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,WAAD;KAAS,WAAU;eAAnB,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,kCAAkC,oBAAoB;KACxD,CAAA,GACH,EAAS,KAAK,MAAM,WAAW,IAC9B,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;MACnC,OAAO,EAAG,qCAAqC,oBAAoB;MACnE,aAAa,EACX,2CACA,sGACF;KACD,CAAA,IAED,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,SAAD;QAAO,WAAU;kBACf,kBAAC,MAAD,EAAA,UAAA;SACE,kBAAC,MAAD;UAAI,WAAU;oBAAa,EAAG,gCAAgC,OAAO;SAAM,CAAA;SAC3E,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,+BAA+B,MAAM;SACvC,CAAA;SACJ,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,qCAAqC,YAAY;SACnD,CAAA;SACJ,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,sCAAsC,cAAc;SACtD,CAAA;SACJ,kBAAC,MAAD;UAAI,WAAU;oBAAa,EAAG,iCAAiC,QAAQ;SAAM,CAAA;QAC3E,EAAA,CAAA;OACC,CAAA,GACP,kBAAC,SAAD,EAAA,UACG,EAAS,KAAK,MAAM,KAAK,MACxB,kBAAC,MAAD;QAAqB,WAAU;kBAA/B;SACE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAQ,eAAe;SACtB,CAAA;SACJ,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAY,EAAQ,YAAY,EAAQ,QAAQ;SAC/C,CAAA;SACJ,kBAAC,MAAD;UACE,WAAW,EACT,qEACA,EAAQ,mBAAmB,cACzB,kCACJ;oBAEC,EAAY,EAAQ,QAAQ,EAAQ,QAAQ;SAC3C,CAAA;SACJ,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAW,EAAQ,aAAa;WAAE,MAAM,KAAA;WAAW,QAAQ,KAAA;UAAU,CAAC;SACrE,CAAA;SACJ,kBAAC,MAAD;UAAI,WAAU;UAAY,eAAY;oBAEpC,kBAAC,GAAD,EACE,QACE,EAAQ,mBAAmB,cAC3B,EAAQ,mBAAmB,mBACvB,EAAQ,iBACR,EAAQ,kBAEf,CAAA;SACC,CAAA;QACF;UA9BK,EAAQ,EA8Bb,CACL,EACI,CAAA,CACF;;KACJ,CAAA,CAEA;QAET,kBAAC,GAAD;KAAW,WAAU;KAAQ,WAAU;eAAvC;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,uCAAuC,kBAAkB;MAC3D,CAAA;MACJ,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,sCACA,8FACF;MACC,CAAA;MACH,kBAAC,GAAD;OACE,IAAG;OACH,MAAK;OACL,OAAO,EAAG,iCAAiC,yBAAyB,EAAE,YAAS,CAAC;OAChF,OAAO;OACP,UAAU;OACV,MAAM,EAAG,kCAAkC,oBAAoB,EAC7D,QAAQ,EAAY,EAAE,iBAAiB,CAAQ,EACjD,CAAC;MACF,CAAA;MACA,EAAO,SAAS,kBAAC,KAAD;OAAG,WAAU;iBAAkC,EAAO,MAAM;MAAW,CAAA;MACvF,EAAO,QACN,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,oCACA,gDACA;QACE,QAAQ,EAAY,EAAO,KAAK,iBAAiB,EAAO,KAAK,QAAQ;QACrE,QAAQ,EAAO,KAAK;OACtB,CACF;MACC,CAAA;MAEL,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,CAAC,KAAc,EAAO;OAChC,eACE,EAAO,OAAO;QAAE,QAAQ;QAAW;OAAS,GAAG,EAAE,iBAAiB,EAAU,EAAE,EAAE,CAAC;OAEnF,WAAU;iBANZ,CAQG,EAAO,aAAa,kBAAC,GAAD,EAAS,WAAU,uBAAwB,CAAA,GAC/D,EAAG,wCAAwC,gBAAgB,CACtD;;KACC;MACR;;GAEL,kBAAC,WAAD;IAAS,WAAU;IAAO,eAAY;cAAtC,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,oCAAoC,oBAAoB;IAC1D,CAAA,GACH,EAAK,UACJ,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,oCAAoC,yCAAyC;IAChF,CAAA,IACD,CAAC,EAAK,QAAQ,EAAK,KAAK,MAAM,WAAW,IAC3C,kBAAC,KAAD;KAAG,WAAU;eACV,EAAK,YACF,EAAG,sCAAsC,6BAA6B,IACtE,EACE,oCACA,kFACF;IACH,CAAA,IAEH,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OAAO,WAAU;iBACf,kBAAC,MAAD,EAAA,UAAA;QACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,wCAAwC,eAAe;QACzD,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,8BAA8B,KAAK;QACrC,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,uCAAuC,eAAe;QACxD,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,sCAAsC,cAAc;QACtD,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;mBAAa,EAAG,iCAAiC,QAAQ;QAAM,CAAA;OAC3E,EAAA,CAAA;MACC,CAAA,GACP,kBAAC,SAAD,EAAA,UACG,EAAK,KAAK,MAAM,KAAK,MACpB,kBAAC,MAAD;OAAiB,WAAU;iBAA3B;QACE,kBAAC,MAAD;SAAI,WAAU;mBACZ,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAW,mBAAmB,EAAI,iBAAiB;UAClE,WAAU;oBAET,EAAI,sBAAsB;SACrB,CAAA;QACN,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAY,EAAI,QAAQ,EAAI,QAAQ;QACnC,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;mBACZ,kBAAC,GAAD,EAAa,QAAQ,EAAI,OAAS,CAAA;QAChC,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAI,qBACD,EAAW,EAAI,oBAAoB;UAAE,MAAM,KAAA;UAAW,QAAQ,KAAA;SAAU,CAAC,IACzE;QACF,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAI,oBAAoB,kBAAC,GAAD,EAAa,QAAQ,EAAI,kBAAoB,CAAA,IAAI;QACxE,CAAA;OACF;SAxBK,EAAI,EAwBT,CACL,EACI,CAAA,CACF;;IACJ,CAAA,CAEA;;EACC;;AAEhB"}
|
|
1
|
+
{"version":3,"file":"CreatorEarningsPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/commerce/CreatorEarningsPage.tsx"],"sourcesContent":["/**\n * Creator Earnings Page (BOFF-3370)\n * @module coolandlovely/pages/commerce\n *\n * A creator's look commissions: every piece bought from one of their published looks earns\n * them a commission once the order is paid. Balances come from global-billing's earnings\n * ledger (`cooMyCreatorEarningsSummary`); a creator can ask for a payout of the available\n * balance (`cooRequestCreatorPayout`), which billing queues for payout review.\n *\n * Collaboration fees (BOFF-9637): when a brand pays the agreed fee of a published collaboration,\n * it lands here too (`cooMyCollaborationPayouts`) and counts towards the same payable balance.\n */\n\nimport { useState } from 'react';\nimport { Loader2, Wallet } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\nimport { CreatorAnalyticsSection } from './CreatorAnalyticsSection';\n\nimport { EmptyState } from '../../components/EmptyState';\nimport { TextField } from '../../components/Field';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { PageLayout } from '../../components/PageLayout';\nimport { ErrorView, LoadingView } from '../../components/StateViews';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { useTr } from '../../hooks';\nimport {\n useMyCollaborationPayouts,\n useMyCreatorEarnings,\n useMyCreatorEarningsSummary,\n useRequestCreatorPayout,\n} from '../../hooks/useCommerceApi';\nimport { cn } from '../../utils/cn';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { formatDate, formatPrice } from '../../utils/formatters';\n\nexport function CreatorEarningsPage() {\n const tr = useTr();\n const summary = useMyCreatorEarningsSummary();\n const earnings = useMyCreatorEarnings();\n const fees = useMyCollaborationPayouts();\n const payout = useRequestCreatorPayout();\n const { navigateTo } = useCoolAndLovely();\n const [amount, setAmount] = useState('');\n const title = tr('coolandlovely.earnings.title', 'Creator earnings');\n\n if (summary.isLoading || earnings.isLoading) {\n return (\n <PageLayout title={title}>\n <LoadingView />\n </PageLayout>\n );\n }\n if (summary.isError || earnings.isError || !summary.data || !earnings.data) {\n return (\n <PageLayout title={title}>\n <ErrorView\n onRetry={() => {\n void summary.refetch();\n void earnings.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n const s = summary.data;\n const currency = s.currency ?? 'USD';\n const requested = Number(amount);\n const canRequest = s.currency !== null && requested > 0 && requested <= s.availableAmount;\n\n return (\n <PageLayout\n title={title}\n description={tr(\n 'coolandlovely.earnings.description',\n 'You earn {{rate}}% of every piece bought from your looks, and the agreed fee of every collaboration a brand pays. Commissions become available {{days}} days after payment.',\n { rate: Math.round(s.commissionRate * 100), days: s.holdDays }\n )}\n >\n <CreatorAnalyticsSection />\n <div\n className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\"\n data-testid=\"earnings-summary\"\n >\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.earnings.available', 'Available')}\n value={formatPrice(s.availableAmount, currency)}\n />\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.earnings.pending', 'In return window')}\n value={formatPrice(s.pendingAmount, currency)}\n />\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.earnings.reserved', 'Payout requested')}\n value={formatPrice(s.reservedAmount, currency)}\n />\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n label={tr('coolandlovely.earnings.paid', 'Paid out')}\n value={formatPrice(s.paidAmount, currency)}\n />\n </div>\n {!s.billingAvailable && (\n <p className=\"mt-3 text-sm text-status-warning-text\">\n {tr(\n 'coolandlovely.earnings.billingUnavailable',\n 'Balances could not be confirmed with billing just now; the figures above come from your commission history.'\n )}\n </p>\n )}\n\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <section className=\"lg:col-span-2\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n {tr('coolandlovely.earnings.history', 'Commission history')}\n </h3>\n {earnings.data.items.length === 0 ? (\n <EmptyState\n icon={<Wallet className=\"h-8 w-8\" />}\n title={tr('coolandlovely.earnings.emptyTitle', 'No commissions yet')}\n description={tr(\n 'coolandlovely.earnings.emptyDescription',\n 'Publish looks with catalogue pieces. When someone buys from your look, the commission shows up here.'\n )}\n />\n ) : (\n <div className=\"overflow-x-auto rounded-xl border border-border-seam\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-bg-sunken text-left text-xs uppercase tracking-wide text-text-secondary\">\n <tr>\n <th className=\"px-4 py-2\">{tr('coolandlovely.earnings.order', 'Order')}</th>\n <th className=\"px-4 py-2 text-right\">\n {tr('coolandlovely.earnings.sale', 'Sale')}\n </th>\n <th className=\"px-4 py-2 text-right\">\n {tr('coolandlovely.earnings.commission', 'Commission')}\n </th>\n <th className=\"px-4 py-2\">\n {tr('coolandlovely.earnings.availableOn', 'Available on')}\n </th>\n <th className=\"px-4 py-2\">{tr('coolandlovely.earnings.ledger', 'Ledger')}</th>\n </tr>\n </thead>\n <tbody>\n {earnings.data.items.map((earning) => (\n <tr key={earning.id} className=\"border-t border-border-seam\">\n <td className=\"px-4 py-2 font-mono text-text-primary\">\n {earning.orderNumber ?? '—'}\n </td>\n <td className=\"px-4 py-2 text-right tabular-nums text-text-secondary\">\n {formatPrice(earning.saleAmount, earning.currency)}\n </td>\n <td\n className={cn(\n 'px-4 py-2 text-right font-semibold tabular-nums text-text-primary',\n earning.reversalStatus === 'REVERSED' &&\n 'text-text-secondary line-through'\n )}\n >\n {formatPrice(earning.amount, earning.currency)}\n </td>\n <td className=\"px-4 py-2 text-text-secondary\">\n {formatDate(earning.availableAt, { hour: undefined, minute: undefined })}\n </td>\n <td className=\"px-4 py-2\" data-testid=\"earning-ledger-status\">\n {/* A refunded line's commission is reversed (BOFF-9702). */}\n <StatusBadge\n status={\n earning.reversalStatus === 'REVERSED' ||\n earning.reversalStatus === 'NOT_REVERSIBLE'\n ? earning.reversalStatus\n : earning.billingSyncStatus\n }\n />\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n\n <GlassCard treatment=\"glass\" className=\"h-fit space-y-4 p-6\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('coolandlovely.earnings.requestTitle', 'Request a payout')}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'coolandlovely.earnings.requestHint',\n 'Payouts are reviewed by the platform and sent to the payout account on your billing profile.'\n )}\n </p>\n <TextField\n id=\"coo-payout-amount\"\n type=\"number\"\n label={tr('coolandlovely.earnings.amount', 'Amount ({{currency}})', { currency })}\n value={amount}\n onChange={setAmount}\n hint={tr('coolandlovely.earnings.maxHint', 'Up to {{amount}}', {\n amount: formatPrice(s.availableAmount, currency),\n })}\n />\n {payout.error && <p className=\"text-sm text-status-error-text\">{payout.error.message}</p>}\n {payout.data && (\n <p className=\"text-sm text-status-success-text\">\n {tr(\n 'coolandlovely.earnings.requested',\n 'Payout of {{amount}} requested ({{status}}).',\n {\n amount: formatPrice(payout.data.requestedAmount, payout.data.currency),\n status: payout.data.status,\n }\n )}\n </p>\n )}\n <button\n type=\"button\"\n disabled={!canRequest || payout.isPending}\n onClick={() =>\n payout.mutate({ amount: requested, currency }, { onSuccess: () => setAmount('') })\n }\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {payout.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {tr('coolandlovely.earnings.requestButton', 'Request payout')}\n </button>\n </GlassCard>\n </div>\n\n <section className=\"mt-8\" data-testid=\"collaboration-fees\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n {tr('coolandlovely.earnings.feesTitle', 'Collaboration fees')}\n </h3>\n {fees.isError ? (\n <p className=\"text-sm text-status-error-text\">\n {tr('coolandlovely.earnings.feesError', 'Collaboration fees could not be loaded.')}\n </p>\n ) : !fees.data || fees.data.items.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n {fees.isLoading\n ? tr('coolandlovely.earnings.feesLoading', 'Loading collaboration fees…')\n : tr(\n 'coolandlovely.earnings.feesEmpty',\n 'When a brand pays the agreed fee of a published collaboration, it shows up here.'\n )}\n </p>\n ) : (\n <div className=\"overflow-x-auto rounded-xl border border-border-seam\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-bg-sunken text-left text-xs uppercase tracking-wide text-text-secondary\">\n <tr>\n <th className=\"px-4 py-2\">\n {tr('coolandlovely.earnings.collaboration', 'Collaboration')}\n </th>\n <th className=\"px-4 py-2 text-right\">\n {tr('coolandlovely.earnings.fee', 'Fee')}\n </th>\n <th className=\"px-4 py-2\">\n {tr('coolandlovely.earnings.brandPayment', 'Brand payment')}\n </th>\n <th className=\"px-4 py-2\">\n {tr('coolandlovely.earnings.availableOn', 'Available on')}\n </th>\n <th className=\"px-4 py-2\">{tr('coolandlovely.earnings.ledger', 'Ledger')}</th>\n </tr>\n </thead>\n <tbody>\n {fees.data.items.map((fee) => (\n <tr key={fee.id} className=\"border-t border-border-seam\">\n <td className=\"px-4 py-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collaborations/${fee.collaborationId}`)}\n className=\"text-left font-medium text-text-primary hover:underline\"\n >\n {fee.collaborationTitle ?? '—'}\n </button>\n </td>\n <td className=\"px-4 py-2 text-right font-semibold tabular-nums text-text-primary\">\n {formatPrice(fee.amount, fee.currency)}\n </td>\n <td className=\"px-4 py-2\">\n <StatusBadge status={fee.status} />\n </td>\n <td className=\"px-4 py-2 text-text-secondary\">\n {fee.earningAvailableAt\n ? formatDate(fee.earningAvailableAt, { hour: undefined, minute: undefined })\n : '—'}\n </td>\n <td className=\"px-4 py-2\">\n {fee.earningSyncStatus ? <StatusBadge status={fee.earningSyncStatus} /> : '—'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|