@hartl-services/medusa-affiliate 0.3.0 → 0.4.1

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.
@@ -1375,252 +1375,6 @@ const config$6 = adminSdk.defineRouteConfig({
1375
1375
  label: texts.routes.affiliates,
1376
1376
  rank: 81
1377
1377
  });
1378
- const useAffiliateApplications = (params) => reactQuery.useQuery({
1379
- queryKey: affiliateKeys.applicationList(params),
1380
- queryFn: () => listAffiliateApplications({
1381
- status: params.status || void 0,
1382
- limit: params.limit,
1383
- offset: params.offset
1384
- })
1385
- });
1386
- const useApproveAffiliateApplication = (applicationId) => {
1387
- const queryClient = reactQuery.useQueryClient();
1388
- return reactQuery.useMutation({
1389
- mutationFn: (payload) => {
1390
- if (!applicationId) {
1391
- throw new Error(texts.hooks.noApplicationSelected);
1392
- }
1393
- return approveAffiliateApplication(applicationId, payload);
1394
- },
1395
- onSuccess: async () => {
1396
- await queryClient.invalidateQueries({
1397
- queryKey: affiliateKeys.applications()
1398
- });
1399
- await queryClient.invalidateQueries({ queryKey: affiliateKeys.lists() });
1400
- }
1401
- });
1402
- };
1403
- const useRejectAffiliateApplication = (applicationId) => {
1404
- const queryClient = reactQuery.useQueryClient();
1405
- return reactQuery.useMutation({
1406
- mutationFn: (payload) => {
1407
- if (!applicationId) {
1408
- throw new Error(texts.hooks.noApplicationSelected);
1409
- }
1410
- return rejectAffiliateApplication(applicationId, payload);
1411
- },
1412
- onSuccess: async () => {
1413
- await queryClient.invalidateQueries({
1414
- queryKey: affiliateKeys.applications()
1415
- });
1416
- await queryClient.invalidateQueries({ queryKey: affiliateKeys.lists() });
1417
- }
1418
- });
1419
- };
1420
- const PercentRateInput = ({
1421
- label,
1422
- value,
1423
- onChange
1424
- }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
1425
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: label }),
1426
- /* @__PURE__ */ jsxRuntime.jsx(
1427
- ui.Input,
1428
- {
1429
- min: 0,
1430
- max: 100,
1431
- step: "0.01",
1432
- type: "number",
1433
- value,
1434
- onChange: (event) => onChange(Number(event.target.value))
1435
- }
1436
- )
1437
- ] });
1438
- const DEFAULT_COMMISSION_RATE = 10;
1439
- const DEFAULT_OWN_ORDER_DISCOUNT_RATE = 0;
1440
- const APPLICATIONS_PAGE_SIZE = 20;
1441
- const ApplicationsTable = ({
1442
- applications,
1443
- onSelect
1444
- }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-left text-sm", children: [
1445
- /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "border-ui-border-base border-b", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-ui-fg-subtle", children: [
1446
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 font-medium", children: texts.applications.columns.applicant }),
1447
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 font-medium", children: texts.applications.columns.customer }),
1448
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 font-medium", children: texts.applications.columns.slug }),
1449
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 font-medium", children: texts.applications.columns.submitted }),
1450
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 text-right font-medium", children: texts.applications.columns.action })
1451
- ] }) }),
1452
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: applications.map((application) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-ui-border-base border-b", children: [
1453
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3 font-medium", children: application.display_name }),
1454
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3 font-mono text-xs", children: application.customer_id }),
1455
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3", children: application.requested_slug ?? texts.common.dash }),
1456
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3", children: formatDateTime(application.created_at) }),
1457
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", onClick: () => onSelect(application), children: texts.applications.review }) })
1458
- ] }, application.id)) })
1459
- ] }) });
1460
- const AffiliateApplicationsPage = () => {
1461
- const [offset, setOffset] = react.useState(0);
1462
- const [selected, setSelected] = react.useState(null);
1463
- const [commissionRate, setCommissionRate] = react.useState(DEFAULT_COMMISSION_RATE);
1464
- const [ownOrderDiscountRate, setOwnOrderDiscountRate] = react.useState(DEFAULT_OWN_ORDER_DISCOUNT_RATE);
1465
- const [slug, setSlug] = react.useState("");
1466
- const [rejectionReason, setRejectionReason] = react.useState("");
1467
- const applicationsQuery = useAffiliateApplications({
1468
- status: "pending",
1469
- limit: APPLICATIONS_PAGE_SIZE,
1470
- offset
1471
- });
1472
- const approveMutation = useApproveAffiliateApplication(selected?.id);
1473
- const rejectMutation = useRejectAffiliateApplication(selected?.id);
1474
- const reviewPending = approveMutation.isPending || rejectMutation.isPending;
1475
- const applications = applicationsQuery.data?.applications ?? [];
1476
- const count = applicationsQuery.data?.count ?? 0;
1477
- const showPagination = !applicationsQuery.isLoading && !applicationsQuery.isError && count > 0;
1478
- const selectApplication = (application) => {
1479
- setSelected(application);
1480
- setSlug(application.requested_slug ?? "");
1481
- setRejectionReason(application.rejection_reason ?? "");
1482
- setCommissionRate(DEFAULT_COMMISSION_RATE);
1483
- setOwnOrderDiscountRate(DEFAULT_OWN_ORDER_DISCOUNT_RATE);
1484
- };
1485
- const approve = (event) => {
1486
- event.preventDefault();
1487
- approveMutation.mutate(
1488
- {
1489
- commission_rate: commissionRate,
1490
- own_order_discount_rate: ownOrderDiscountRate,
1491
- slug: slug || selected?.requested_slug || null
1492
- },
1493
- {
1494
- onSuccess: () => {
1495
- ui.toast.success(texts.applications.toasts.approved);
1496
- setSelected(null);
1497
- },
1498
- onError: (error) => ui.toast.error(texts.applications.toasts.approveFailed, {
1499
- description: getErrorMessage(error)
1500
- })
1501
- }
1502
- );
1503
- };
1504
- const reject = (event) => {
1505
- event.preventDefault();
1506
- rejectMutation.mutate(
1507
- { rejection_reason: rejectionReason || null },
1508
- {
1509
- onSuccess: () => {
1510
- ui.toast.success(texts.applications.toasts.rejected);
1511
- setSelected(null);
1512
- setRejectionReason("");
1513
- },
1514
- onError: (error) => ui.toast.error(texts.applications.toasts.rejectFailed, {
1515
- description: getErrorMessage(error)
1516
- })
1517
- }
1518
- );
1519
- };
1520
- const renderBody = () => {
1521
- if (applicationsQuery.isLoading) {
1522
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.applications.loading }) });
1523
- }
1524
- if (applicationsQuery.isError) {
1525
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.applications.loadError(getErrorMessage(applicationsQuery.error)) }) });
1526
- }
1527
- if (!applications.length) {
1528
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.applications.empty }) });
1529
- }
1530
- return /* @__PURE__ */ jsxRuntime.jsx(ApplicationsTable, { applications, onSelect: selectApplication });
1531
- };
1532
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6", children: [
1533
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1534
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between gap-4 px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1535
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: texts.applications.heading }),
1536
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.applications.description })
1537
- ] }) }),
1538
- renderBody(),
1539
- showPagination ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
1540
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-sm", children: texts.common.pageRange(offset + 1, offset + applications.length, count) }),
1541
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
1542
- /* @__PURE__ */ jsxRuntime.jsx(
1543
- ui.Button,
1544
- {
1545
- size: "small",
1546
- variant: "secondary",
1547
- disabled: offset === 0,
1548
- onClick: () => setOffset((current) => Math.max(0, current - APPLICATIONS_PAGE_SIZE)),
1549
- children: texts.common.back
1550
- }
1551
- ),
1552
- /* @__PURE__ */ jsxRuntime.jsx(
1553
- ui.Button,
1554
- {
1555
- size: "small",
1556
- variant: "secondary",
1557
- disabled: offset + applications.length >= count,
1558
- onClick: () => setOffset((current) => current + APPLICATIONS_PAGE_SIZE),
1559
- children: texts.common.next
1560
- }
1561
- )
1562
- ] })
1563
- ] }) : null
1564
- ] }),
1565
- selected ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1566
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-4", children: [
1567
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: texts.applications.reviewHeading(selected.display_name) }),
1568
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-subtle", children: [
1569
- texts.applications.customerLine(selected.customer_id),
1570
- selected.message ? ` · ${selected.message}` : ""
1571
- ] })
1572
- ] }),
1573
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-5 px-6 py-5 lg:grid-cols-2", children: [
1574
- /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: approve, className: "grid gap-4", children: [
1575
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", children: texts.applications.approveHeading }),
1576
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
1577
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: texts.applications.affiliateSlugLabel }),
1578
- /* @__PURE__ */ jsxRuntime.jsx(
1579
- ui.Input,
1580
- {
1581
- value: slug,
1582
- onChange: (event) => setSlug(event.target.value),
1583
- placeholder: texts.applications.affiliateSlugPlaceholder
1584
- }
1585
- )
1586
- ] }),
1587
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [
1588
- /* @__PURE__ */ jsxRuntime.jsx(
1589
- PercentRateInput,
1590
- {
1591
- label: texts.applications.commissionLabel,
1592
- value: commissionRate,
1593
- onChange: setCommissionRate
1594
- }
1595
- ),
1596
- /* @__PURE__ */ jsxRuntime.jsx(
1597
- PercentRateInput,
1598
- {
1599
- label: texts.applications.ownDiscountLabel,
1600
- value: ownOrderDiscountRate,
1601
- onChange: setOwnOrderDiscountRate
1602
- }
1603
- )
1604
- ] }),
1605
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: reviewPending, children: approveMutation.isPending ? texts.applications.approving : texts.applications.approve }) })
1606
- ] }),
1607
- /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: reject, className: "grid gap-4", children: [
1608
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", children: texts.applications.rejectHeading }),
1609
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
1610
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: texts.applications.reasonLabel }),
1611
- /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { value: rejectionReason, onChange: (event) => setRejectionReason(event.target.value) })
1612
- ] }),
1613
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", variant: "danger", disabled: reviewPending, children: rejectMutation.isPending ? texts.applications.rejecting : texts.applications.reject }) })
1614
- ] })
1615
- ] })
1616
- ] }) : null
1617
- ] });
1618
- };
1619
- const AffiliateApplicationsRoute = () => /* @__PURE__ */ jsxRuntime.jsx(AffiliateApplicationsPage, {});
1620
- const config$5 = adminSdk.defineRouteConfig({
1621
- label: texts.routes.applications,
1622
- rank: 80
1623
- });
1624
1378
  const getCustomerLabel = (customer) => {
1625
1379
  const name = [customer.first_name, customer.last_name].filter(Boolean).join(" ");
1626
1380
  return name ? `${name} (${customer.email})` : customer.email;
@@ -2451,16 +2205,34 @@ const AffiliateCouponPanel = ({ affiliateId }) => {
2451
2205
  )
2452
2206
  ] });
2453
2207
  };
2454
- const SlugTable = ({
2455
- affiliateId,
2456
- slugs
2457
- }) => {
2458
- const mutation = useUpdateAffiliateSlug(affiliateId);
2459
- const update = (payload) => mutation.mutate(payload, {
2460
- onSuccess: () => ui.toast.success(texts.slugTable.toasts.updated),
2461
- onError: (error) => ui.toast.error(texts.slugTable.toasts.updateFailed, {
2462
- description: getErrorMessage(error)
2463
- })
2208
+ const PercentRateInput = ({
2209
+ label,
2210
+ value,
2211
+ onChange
2212
+ }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
2213
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: label }),
2214
+ /* @__PURE__ */ jsxRuntime.jsx(
2215
+ ui.Input,
2216
+ {
2217
+ min: 0,
2218
+ max: 100,
2219
+ step: "0.01",
2220
+ type: "number",
2221
+ value,
2222
+ onChange: (event) => onChange(Number(event.target.value))
2223
+ }
2224
+ )
2225
+ ] });
2226
+ const SlugTable = ({
2227
+ affiliateId,
2228
+ slugs
2229
+ }) => {
2230
+ const mutation = useUpdateAffiliateSlug(affiliateId);
2231
+ const update = (payload) => mutation.mutate(payload, {
2232
+ onSuccess: () => ui.toast.success(texts.slugTable.toasts.updated),
2233
+ onError: (error) => ui.toast.error(texts.slugTable.toasts.updateFailed, {
2234
+ description: getErrorMessage(error)
2235
+ })
2464
2236
  });
2465
2237
  if (!slugs.length) {
2466
2238
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.slugTable.empty });
@@ -2852,6 +2624,277 @@ const AffiliateEditRoute = () => {
2852
2624
  const { id } = reactRouterDom.useParams();
2853
2625
  return /* @__PURE__ */ jsxRuntime.jsx(AffiliateFormPage, { mode: "edit", affiliateId: id });
2854
2626
  };
2627
+ const useAffiliateApplications = (params) => reactQuery.useQuery({
2628
+ queryKey: affiliateKeys.applicationList(params),
2629
+ queryFn: () => listAffiliateApplications({
2630
+ status: params.status || void 0,
2631
+ limit: params.limit,
2632
+ offset: params.offset
2633
+ })
2634
+ });
2635
+ const useApproveAffiliateApplication = (applicationId) => {
2636
+ const queryClient = reactQuery.useQueryClient();
2637
+ return reactQuery.useMutation({
2638
+ mutationFn: (payload) => {
2639
+ if (!applicationId) {
2640
+ throw new Error(texts.hooks.noApplicationSelected);
2641
+ }
2642
+ return approveAffiliateApplication(applicationId, payload);
2643
+ },
2644
+ onSuccess: async () => {
2645
+ await queryClient.invalidateQueries({
2646
+ queryKey: affiliateKeys.applications()
2647
+ });
2648
+ await queryClient.invalidateQueries({ queryKey: affiliateKeys.lists() });
2649
+ }
2650
+ });
2651
+ };
2652
+ const useRejectAffiliateApplication = (applicationId) => {
2653
+ const queryClient = reactQuery.useQueryClient();
2654
+ return reactQuery.useMutation({
2655
+ mutationFn: (payload) => {
2656
+ if (!applicationId) {
2657
+ throw new Error(texts.hooks.noApplicationSelected);
2658
+ }
2659
+ return rejectAffiliateApplication(applicationId, payload);
2660
+ },
2661
+ onSuccess: async () => {
2662
+ await queryClient.invalidateQueries({
2663
+ queryKey: affiliateKeys.applications()
2664
+ });
2665
+ await queryClient.invalidateQueries({ queryKey: affiliateKeys.lists() });
2666
+ }
2667
+ });
2668
+ };
2669
+ const DEFAULT_COMMISSION_RATE = 10;
2670
+ const DEFAULT_OWN_ORDER_DISCOUNT_RATE = 0;
2671
+ const APPLICATIONS_PAGE_SIZE = 20;
2672
+ const ApplicationsTable = ({
2673
+ applications,
2674
+ onSelect
2675
+ }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-left text-sm", children: [
2676
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "border-ui-border-base border-b", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-ui-fg-subtle", children: [
2677
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 font-medium", children: texts.applications.columns.applicant }),
2678
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 font-medium", children: texts.applications.columns.customer }),
2679
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 font-medium", children: texts.applications.columns.slug }),
2680
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 font-medium", children: texts.applications.columns.submitted }),
2681
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 text-right font-medium", children: texts.applications.columns.action })
2682
+ ] }) }),
2683
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: applications.map((application) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-ui-border-base border-b", children: [
2684
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3 font-medium", children: application.display_name }),
2685
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3 font-mono text-xs", children: application.customer_id }),
2686
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3", children: application.requested_slug ?? texts.common.dash }),
2687
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3", children: formatDateTime(application.created_at) }),
2688
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", onClick: () => onSelect(application), children: texts.applications.review }) })
2689
+ ] }, application.id)) })
2690
+ ] }) });
2691
+ const AffiliateApplicationsPage = () => {
2692
+ const [offset, setOffset] = react.useState(0);
2693
+ const [selected, setSelected] = react.useState(null);
2694
+ const [commissionRate, setCommissionRate] = react.useState(DEFAULT_COMMISSION_RATE);
2695
+ const [ownOrderDiscountRate, setOwnOrderDiscountRate] = react.useState(DEFAULT_OWN_ORDER_DISCOUNT_RATE);
2696
+ const [slug, setSlug] = react.useState("");
2697
+ const [rejectionReason, setRejectionReason] = react.useState("");
2698
+ const applicationsQuery = useAffiliateApplications({
2699
+ status: "pending",
2700
+ limit: APPLICATIONS_PAGE_SIZE,
2701
+ offset
2702
+ });
2703
+ const approveMutation = useApproveAffiliateApplication(selected?.id);
2704
+ const rejectMutation = useRejectAffiliateApplication(selected?.id);
2705
+ const reviewPending = approveMutation.isPending || rejectMutation.isPending;
2706
+ const applications = applicationsQuery.data?.applications ?? [];
2707
+ const count = applicationsQuery.data?.count ?? 0;
2708
+ const showPagination = !applicationsQuery.isLoading && !applicationsQuery.isError && count > 0;
2709
+ const selectApplication = (application) => {
2710
+ setSelected(application);
2711
+ setSlug(application.requested_slug ?? "");
2712
+ setRejectionReason(application.rejection_reason ?? "");
2713
+ setCommissionRate(DEFAULT_COMMISSION_RATE);
2714
+ setOwnOrderDiscountRate(DEFAULT_OWN_ORDER_DISCOUNT_RATE);
2715
+ };
2716
+ const approve = (event) => {
2717
+ event.preventDefault();
2718
+ approveMutation.mutate(
2719
+ {
2720
+ commission_rate: commissionRate,
2721
+ own_order_discount_rate: ownOrderDiscountRate,
2722
+ slug: slug || selected?.requested_slug || null
2723
+ },
2724
+ {
2725
+ onSuccess: () => {
2726
+ ui.toast.success(texts.applications.toasts.approved);
2727
+ setSelected(null);
2728
+ },
2729
+ onError: (error) => ui.toast.error(texts.applications.toasts.approveFailed, {
2730
+ description: getErrorMessage(error)
2731
+ })
2732
+ }
2733
+ );
2734
+ };
2735
+ const reject = (event) => {
2736
+ event.preventDefault();
2737
+ rejectMutation.mutate(
2738
+ { rejection_reason: rejectionReason || null },
2739
+ {
2740
+ onSuccess: () => {
2741
+ ui.toast.success(texts.applications.toasts.rejected);
2742
+ setSelected(null);
2743
+ setRejectionReason("");
2744
+ },
2745
+ onError: (error) => ui.toast.error(texts.applications.toasts.rejectFailed, {
2746
+ description: getErrorMessage(error)
2747
+ })
2748
+ }
2749
+ );
2750
+ };
2751
+ const renderBody = () => {
2752
+ if (applicationsQuery.isLoading) {
2753
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.applications.loading }) });
2754
+ }
2755
+ if (applicationsQuery.isError) {
2756
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.applications.loadError(getErrorMessage(applicationsQuery.error)) }) });
2757
+ }
2758
+ if (!applications.length) {
2759
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.applications.empty }) });
2760
+ }
2761
+ return /* @__PURE__ */ jsxRuntime.jsx(ApplicationsTable, { applications, onSelect: selectApplication });
2762
+ };
2763
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6", children: [
2764
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2765
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between gap-4 px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2766
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: texts.applications.heading }),
2767
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: texts.applications.description })
2768
+ ] }) }),
2769
+ renderBody(),
2770
+ showPagination ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
2771
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-sm", children: texts.common.pageRange(offset + 1, offset + applications.length, count) }),
2772
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
2773
+ /* @__PURE__ */ jsxRuntime.jsx(
2774
+ ui.Button,
2775
+ {
2776
+ size: "small",
2777
+ variant: "secondary",
2778
+ disabled: offset === 0,
2779
+ onClick: () => setOffset((current) => Math.max(0, current - APPLICATIONS_PAGE_SIZE)),
2780
+ children: texts.common.back
2781
+ }
2782
+ ),
2783
+ /* @__PURE__ */ jsxRuntime.jsx(
2784
+ ui.Button,
2785
+ {
2786
+ size: "small",
2787
+ variant: "secondary",
2788
+ disabled: offset + applications.length >= count,
2789
+ onClick: () => setOffset((current) => current + APPLICATIONS_PAGE_SIZE),
2790
+ children: texts.common.next
2791
+ }
2792
+ )
2793
+ ] })
2794
+ ] }) : null
2795
+ ] }),
2796
+ selected ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2797
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-4", children: [
2798
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: texts.applications.reviewHeading(selected.display_name) }),
2799
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-subtle", children: [
2800
+ texts.applications.customerLine(selected.customer_id),
2801
+ selected.message ? ` · ${selected.message}` : ""
2802
+ ] })
2803
+ ] }),
2804
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-5 px-6 py-5 lg:grid-cols-2", children: [
2805
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: approve, className: "grid gap-4", children: [
2806
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", children: texts.applications.approveHeading }),
2807
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
2808
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: texts.applications.affiliateSlugLabel }),
2809
+ /* @__PURE__ */ jsxRuntime.jsx(
2810
+ ui.Input,
2811
+ {
2812
+ value: slug,
2813
+ onChange: (event) => setSlug(event.target.value),
2814
+ placeholder: texts.applications.affiliateSlugPlaceholder
2815
+ }
2816
+ )
2817
+ ] }),
2818
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [
2819
+ /* @__PURE__ */ jsxRuntime.jsx(
2820
+ PercentRateInput,
2821
+ {
2822
+ label: texts.applications.commissionLabel,
2823
+ value: commissionRate,
2824
+ onChange: setCommissionRate
2825
+ }
2826
+ ),
2827
+ /* @__PURE__ */ jsxRuntime.jsx(
2828
+ PercentRateInput,
2829
+ {
2830
+ label: texts.applications.ownDiscountLabel,
2831
+ value: ownOrderDiscountRate,
2832
+ onChange: setOwnOrderDiscountRate
2833
+ }
2834
+ )
2835
+ ] }),
2836
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: reviewPending, children: approveMutation.isPending ? texts.applications.approving : texts.applications.approve }) })
2837
+ ] }),
2838
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: reject, className: "grid gap-4", children: [
2839
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", children: texts.applications.rejectHeading }),
2840
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
2841
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: texts.applications.reasonLabel }),
2842
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { value: rejectionReason, onChange: (event) => setRejectionReason(event.target.value) })
2843
+ ] }),
2844
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", variant: "danger", disabled: reviewPending, children: rejectMutation.isPending ? texts.applications.rejecting : texts.applications.reject }) })
2845
+ ] })
2846
+ ] })
2847
+ ] }) : null
2848
+ ] });
2849
+ };
2850
+ const AffiliateApplicationsRoute = () => /* @__PURE__ */ jsxRuntime.jsx(AffiliateApplicationsPage, {});
2851
+ const config$5 = adminSdk.defineRouteConfig({
2852
+ label: texts.routes.applications,
2853
+ rank: 80
2854
+ });
2855
+ function ConsignmentReportsPage() {
2856
+ const reports = reactQuery.useQuery({
2857
+ queryKey: ["affiliate", "consignment-reports"],
2858
+ queryFn: () => listAdminConsignmentReports({ limit: 100, offset: 0 })
2859
+ });
2860
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "grid gap-5", children: [
2861
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2862
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Kommissions-Monatsmeldungen" }),
2863
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: "Eingereichte Inventuren prüfen und abrechnen." })
2864
+ ] }),
2865
+ reports.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Monatsmeldungen werden geladen …" }) : reports.isError ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error", children: getErrorMessage(reports.error) }) : !reports.data?.reports.length ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: "Keine Monatsmeldungen vorhanden." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-left text-sm", children: [
2866
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b", children: [
2867
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Affiliate" }),
2868
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Zeitraum" }),
2869
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Status" }),
2870
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Abweichungen" }),
2871
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Draft / Order" }),
2872
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2" })
2873
+ ] }) }),
2874
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: reports.data.reports.map((report) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b", children: [
2875
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: report.affiliate_id }),
2876
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: formatDate(report.period_start) }),
2877
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: report.status }),
2878
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: report.lines.filter(
2879
+ (line) => line.requires_admin_clarification || line.expected_quantity !== line.counted_quantity
2880
+ ).length }),
2881
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: report.order_id ?? report.draft_order_id ?? "–" }),
2882
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
2883
+ reactRouterDom.Link,
2884
+ {
2885
+ to: `/affiliates/consignment-reports/${report.id}`,
2886
+ children: "Prüfen"
2887
+ }
2888
+ ) }) })
2889
+ ] }, report.id)) })
2890
+ ] }) })
2891
+ ] });
2892
+ }
2893
+ const ConsignmentReportsRoute = () => /* @__PURE__ */ jsxRuntime.jsx(ConsignmentReportsPage, {});
2894
+ const config$4 = adminSdk.defineRouteConfig({
2895
+ label: "Kommissionsmeldungen",
2896
+ rank: 83
2897
+ });
2855
2898
  const yearStart = () => `${(/* @__PURE__ */ new Date()).getFullYear()}-01-01`;
2856
2899
  const formatCurrencyTotals = (totals) => totals.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-1", children: totals.map((total) => /* @__PURE__ */ jsxRuntime.jsx("span", { children: total.currency_code ? formatAmount(total.amount, total.currency_code) : `${total.amount} (Währung unbekannt)` }, total.currency_code ?? "unknown-currency")) }) : "–";
2857
2900
  function AffiliateDistributionReportPage() {
@@ -2962,53 +3005,10 @@ function AffiliateDistributionReportPage() {
2962
3005
  ] });
2963
3006
  }
2964
3007
  const AffiliateDistributionReportRoute = () => /* @__PURE__ */ jsxRuntime.jsx(AffiliateDistributionReportPage, {});
2965
- const config$4 = adminSdk.defineRouteConfig({
3008
+ const config$3 = adminSdk.defineRouteConfig({
2966
3009
  label: "Vertriebsreport",
2967
3010
  rank: 85
2968
3011
  });
2969
- function ConsignmentReportsPage() {
2970
- const reports = reactQuery.useQuery({
2971
- queryKey: ["affiliate", "consignment-reports"],
2972
- queryFn: () => listAdminConsignmentReports({ limit: 100, offset: 0 })
2973
- });
2974
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "grid gap-5", children: [
2975
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2976
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Kommissions-Monatsmeldungen" }),
2977
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: "Eingereichte Inventuren prüfen und abrechnen." })
2978
- ] }),
2979
- reports.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Monatsmeldungen werden geladen …" }) : reports.isError ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error", children: getErrorMessage(reports.error) }) : !reports.data?.reports.length ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: "Keine Monatsmeldungen vorhanden." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-left text-sm", children: [
2980
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b", children: [
2981
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Affiliate" }),
2982
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Zeitraum" }),
2983
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Status" }),
2984
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Abweichungen" }),
2985
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2", children: "Draft / Order" }),
2986
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "p-2" })
2987
- ] }) }),
2988
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: reports.data.reports.map((report) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b", children: [
2989
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: report.affiliate_id }),
2990
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: formatDate(report.period_start) }),
2991
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: report.status }),
2992
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: report.lines.filter(
2993
- (line) => line.requires_admin_clarification || line.expected_quantity !== line.counted_quantity
2994
- ).length }),
2995
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2", children: report.order_id ?? report.draft_order_id ?? "–" }),
2996
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-2 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
2997
- reactRouterDom.Link,
2998
- {
2999
- to: `/affiliates/consignment-reports/${report.id}`,
3000
- children: "Prüfen"
3001
- }
3002
- ) }) })
3003
- ] }, report.id)) })
3004
- ] }) })
3005
- ] });
3006
- }
3007
- const ConsignmentReportsRoute = () => /* @__PURE__ */ jsxRuntime.jsx(ConsignmentReportsPage, {});
3008
- const config$3 = adminSdk.defineRouteConfig({
3009
- label: "Kommissionsmeldungen",
3010
- rank: 83
3011
- });
3012
3012
  const NewAffiliateRoute = () => /* @__PURE__ */ jsxRuntime.jsx(AffiliateFormPage, { mode: "create" });
3013
3013
  const config$2 = adminSdk.defineRouteConfig({
3014
3014
  label: texts.routes.newAffiliate
@@ -3615,23 +3615,23 @@ const routeModule = {
3615
3615
  path: "/affiliates",
3616
3616
  handle: { label: config$6.label, translationNs: config$6.translationNs }
3617
3617
  },
3618
+ {
3619
+ Component: AffiliateEditRoute,
3620
+ path: "/affiliates/:id"
3621
+ },
3618
3622
  {
3619
3623
  Component: AffiliateApplicationsRoute,
3620
3624
  path: "/affiliates/applications",
3621
3625
  handle: { label: config$5.label, translationNs: config$5.translationNs }
3622
3626
  },
3623
3627
  {
3624
- Component: AffiliateEditRoute,
3625
- path: "/affiliates/:id"
3628
+ Component: ConsignmentReportsRoute,
3629
+ path: "/affiliates/consignment-reports",
3630
+ handle: { label: config$4.label, translationNs: config$4.translationNs }
3626
3631
  },
3627
3632
  {
3628
3633
  Component: AffiliateDistributionReportRoute,
3629
3634
  path: "/affiliates/distribution-reports",
3630
- handle: { label: config$4.label, translationNs: config$4.translationNs }
3631
- },
3632
- {
3633
- Component: ConsignmentReportsRoute,
3634
- path: "/affiliates/consignment-reports",
3635
3635
  handle: { label: config$3.label, translationNs: config$3.translationNs }
3636
3636
  },
3637
3637
  {
@@ -3678,7 +3678,7 @@ const menuItemModule = {
3678
3678
  translationNs: void 0
3679
3679
  },
3680
3680
  {
3681
- label: config$3.label,
3681
+ label: config$4.label,
3682
3682
  icon: void 0,
3683
3683
  path: "/affiliates/consignment-reports",
3684
3684
  nested: void 0,
@@ -3686,7 +3686,7 @@ const menuItemModule = {
3686
3686
  translationNs: void 0
3687
3687
  },
3688
3688
  {
3689
- label: config$4.label,
3689
+ label: config$3.label,
3690
3690
  icon: void 0,
3691
3691
  path: "/affiliates/distribution-reports",
3692
3692
  nested: void 0,