@nextblock-cms/ecom 0.22.2 → 0.22.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/index.cjs +1 -1
  2. package/index.es.js +31 -31
  3. package/lib/components/Checkout.cjs +1 -1
  4. package/lib/components/Checkout.es.js +1 -0
  5. package/lib/components/SubscriptionSelector.cjs +1 -1
  6. package/lib/components/SubscriptionSelector.es.js +91 -92
  7. package/lib/coupon-server.cjs +1 -1
  8. package/lib/coupon-server.es.js +78 -61
  9. package/lib/coupons.cjs +1 -1
  10. package/lib/coupons.d.ts +9 -0
  11. package/lib/coupons.es.js +11 -2
  12. package/lib/currency-sync.cjs +1 -1
  13. package/lib/currency-sync.es.js +1 -1
  14. package/lib/freemius-coupons.cjs +1 -1
  15. package/lib/freemius-coupons.es.js +88 -92
  16. package/lib/freemius-license-claim.cjs +1 -1
  17. package/lib/freemius-license-claim.d.ts +13 -0
  18. package/lib/freemius-license-claim.es.js +44 -29
  19. package/lib/freemius-license.cjs +1 -1
  20. package/lib/freemius-license.es.js +19 -17
  21. package/lib/freemius-order-sync.cjs +1 -1
  22. package/lib/freemius-order-sync.d.ts +44 -0
  23. package/lib/freemius-order-sync.es.js +164 -77
  24. package/lib/freemius-pricing-server.cjs +1 -0
  25. package/lib/freemius-pricing-server.d.ts +65 -0
  26. package/lib/freemius-pricing-server.es.js +82 -0
  27. package/lib/freemius-pricing.cjs +1 -0
  28. package/lib/freemius-pricing.d.ts +53 -0
  29. package/lib/freemius-pricing.es.js +51 -0
  30. package/lib/invoice-server.cjs +1 -1
  31. package/lib/invoice-server.es.js +1 -0
  32. package/lib/pages/cms/coupons/CouponsPage.cjs +1 -1
  33. package/lib/pages/cms/coupons/CouponsPage.es.js +1 -0
  34. package/lib/pages/cms/coupons/EditCouponPage.cjs +1 -1
  35. package/lib/pages/cms/coupons/EditCouponPage.es.js +1 -0
  36. package/lib/pages/cms/coupons/actions.cjs +1 -1
  37. package/lib/pages/cms/coupons/actions.es.js +1 -0
  38. package/lib/pages/cms/orders/actions.cjs +1 -1
  39. package/lib/pages/cms/orders/actions.es.js +1 -0
  40. package/lib/pages/cms/orders/export-actions.cjs +1 -1
  41. package/lib/pages/cms/orders/export-actions.es.js +1 -0
  42. package/lib/pages/cms/orders/server-actions.cjs +1 -1
  43. package/lib/pages/cms/orders/server-actions.es.js +1 -0
  44. package/lib/pages/cms/products/ProductsPage.cjs +1 -1
  45. package/lib/pages/cms/products/ProductsPage.es.js +1 -0
  46. package/lib/pages/cms/products/[id]/edit/EditProductPage.cjs +1 -1
  47. package/lib/pages/cms/products/[id]/edit/EditProductPage.es.js +1 -0
  48. package/lib/pages/cms/products/actions.cjs +3 -3
  49. package/lib/pages/cms/products/actions.d.ts +11 -5
  50. package/lib/pages/cms/products/actions.es.js +45 -12
  51. package/lib/pages/cms/products/inventory/actions.cjs +1 -1
  52. package/lib/pages/cms/products/inventory/actions.es.js +1 -0
  53. package/lib/pages/cms/products/new/NewProductPage.cjs +1 -1
  54. package/lib/pages/cms/products/new/NewProductPage.es.js +1 -0
  55. package/lib/pages/cms/products/server-actions.cjs +1 -1
  56. package/lib/pages/cms/products/server-actions.es.js +1 -0
  57. package/lib/pages/cms/shipping/ShippingPage.cjs +1 -1
  58. package/lib/pages/cms/shipping/ShippingPage.es.js +1 -0
  59. package/lib/pages/cms/shipping/server-actions.cjs +1 -1
  60. package/lib/pages/cms/shipping/server-actions.es.js +1 -0
  61. package/lib/pages/cms/taxes/TaxesPage.cjs +1 -1
  62. package/lib/pages/cms/taxes/TaxesPage.es.js +1 -0
  63. package/lib/payment-config.cjs +1 -1
  64. package/lib/payment-config.es.js +1 -0
  65. package/lib/providers/freemius.cjs +1 -1
  66. package/lib/providers/freemius.es.js +200 -187
  67. package/lib/providers/stripe.cjs +1 -1
  68. package/lib/providers/stripe.es.js +151 -150
  69. package/lib/server-actions/coupon-actions.cjs +1 -1
  70. package/lib/server-actions/coupon-actions.es.js +1 -0
  71. package/lib/server-actions/customer-actions.d.ts +6 -1
  72. package/lib/server-actions/require-ecom-role.cjs +1 -1
  73. package/lib/server-actions/require-ecom-role.es.js +22 -10
  74. package/lib/server-actions/tax-actions.cjs +1 -1
  75. package/lib/server-actions/tax-actions.es.js +1 -0
  76. package/lib/shared-inventory.cjs +1 -1
  77. package/lib/shared-inventory.es.js +1 -1
  78. package/lib/stripe/checkout.cjs +1 -1
  79. package/lib/stripe/checkout.es.js +1 -0
  80. package/lib/stripe/order-sync.cjs +1 -1
  81. package/lib/stripe/order-sync.es.js +1 -0
  82. package/lib/stripe/webhooks.cjs +1 -1
  83. package/lib/stripe/webhooks.d.ts +10 -0
  84. package/lib/stripe/webhooks.es.js +23 -10
  85. package/package.json +4 -4
  86. package/server.cjs +1 -1
  87. package/server.es.js +31 -31
@@ -1,6 +1,7 @@
1
1
  import { normalizeOrderCustomerDetails as e } from "./customer.es.js";
2
2
  import { DEFAULT_INVOICE_SETTINGS as t, INVOICE_SETTINGS_KEY as n, normalizeInvoiceSettings as r } from "./invoice.es.js";
3
3
  import { normalizeOrderTaxDetails as i } from "./order-tax-details.es.js";
4
+ import "server-only";
4
5
  import { getServiceRoleSupabaseClient as a } from "@nextblock-cms/db/server";
5
6
  //#region src/lib/invoice-server.ts
6
7
  function o(e) {
@@ -1,4 +1,4 @@
1
- const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("./actions.cjs"),n=require("./CreateCouponDialog.cjs"),r=require("./product-options.cjs");let i=require("next/link");i=e.__toESM(i,1);let a=require("lucide-react"),o=require("@nextblock-cms/utils"),s=require("react/jsx-runtime"),c=require("@nextblock-cms/db/server"),l=require("@nextblock-cms/ui");function u(e,t){return e.discount_type===`percent`?`${e.discount_amount}%`:(0,o.formatPrice)(e.discount_amount,t)}function d(e,t){return t?e===`synced`||e===`not_required`?`default`:`secondary`:`outline`}function f(e,t){let n=new Set;for(let r of e||[]){let e=r.product_id;e&&n.add(t.get(e)||e)}return n.size}function p(e,t){let n=f(e,t);return n===0?`All eligible products`:`${n} scoped SKU${n===1?``:`s`}`}async function m({searchParams:e}){let o=(0,c.getServiceRoleSupabaseClient)(),f=o.from(`coupons`).select(`
1
+ const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("./actions.cjs"),n=require("./CreateCouponDialog.cjs"),r=require("./product-options.cjs");let i=require("next/link");i=e.__toESM(i,1);let a=require("lucide-react"),o=require("@nextblock-cms/utils"),s=require("react/jsx-runtime");require("server-only");let c=require("@nextblock-cms/db/server"),l=require("@nextblock-cms/ui");function u(e,t){return e.discount_type===`percent`?`${e.discount_amount}%`:(0,o.formatPrice)(e.discount_amount,t)}function d(e,t){return t?e===`synced`||e===`not_required`?`default`:`secondary`:`outline`}function f(e,t){let n=new Set;for(let r of e||[]){let e=r.product_id;e&&n.add(t.get(e)||e)}return n.size}function p(e,t){let n=f(e,t);return n===0?`All eligible products`:`${n} scoped SKU${n===1?``:`s`}`}async function m({searchParams:e}){let o=(0,c.getServiceRoleSupabaseClient)(),f=o.from(`coupons`).select(`
2
2
  *,
3
3
  coupon_products(product_id),
4
4
  coupon_freemius_mappings(sync_status, sync_error)
@@ -5,6 +5,7 @@ import o from "next/link";
5
5
  import { RefreshCw as s, Trash2 as c } from "lucide-react";
6
6
  import { formatPrice as l } from "@nextblock-cms/utils";
7
7
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
8
+ import "server-only";
8
9
  import { getServiceRoleSupabaseClient as f } from "@nextblock-cms/db/server";
9
10
  import { Badge as p, Button as m, Card as h, CardContent as g, CardDescription as _, CardHeader as v, CardTitle as y } from "@nextblock-cms/ui";
10
11
  //#region src/lib/pages/cms/coupons/CouponsPage.tsx
@@ -1 +1 @@
1
- const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("./actions.cjs"),n=require("./CouponEditorForm.cjs"),r=require("./product-options.cjs");let i=require("next/link");i=e.__toESM(i,1);let a=require("react/jsx-runtime"),o=require("@nextblock-cms/db/server"),s=require("next/navigation"),c=require("@nextblock-cms/ui");async function l({params:e}){let{id:l}=await e,u=(0,o.getServiceRoleSupabaseClient)(),[{data:d},{data:f},{data:p},{data:m}]=await Promise.all([u.from(`coupons`).select(`*`).eq(`id`,l).single(),u.from(`products`).select(`id, title, sku, payment_provider, freemius_product_id, language:languages(code, name), product_media(sort_order, media(file_path, object_key))`).order(`title`,{ascending:!0}),u.from(`coupon_products`).select(`product_id`).eq(`coupon_id`,l),u.from(`currencies`).select(`code, is_default`).eq(`is_active`,!0)]);d||(0,s.notFound)();let h=(p||[]).map(e=>e.product_id),g=m?.find(e=>e.is_default)?.code||m?.[0]?.code||`USD`;return(0,a.jsxs)(`div`,{className:`mx-auto w-full max-w-5xl space-y-6 px-6 py-8`,children:[(0,a.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`h1`,{className:`text-3xl font-bold tracking-tight`,children:`Edit Coupon`}),(0,a.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Changes are resynced to Freemius after saving.`})]}),(0,a.jsx)(c.Button,{asChild:!0,variant:`outline`,children:(0,a.jsx)(i.default,{href:`/cms/coupons`,children:`Back to coupons`})})]}),(0,a.jsx)(n.CouponEditorForm,{action:t.updateCouponAction.bind(null,l),products:r.normalizeCouponProductOptions(f),coupon:d,selectedProductIds:h,submitLabel:`Save Coupon`,currencyCode:g})]})}exports.EditCouponPage=l;
1
+ const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("./actions.cjs"),n=require("./CouponEditorForm.cjs"),r=require("./product-options.cjs");let i=require("next/link");i=e.__toESM(i,1);let a=require("react/jsx-runtime");require("server-only");let o=require("@nextblock-cms/db/server"),s=require("next/navigation"),c=require("@nextblock-cms/ui");async function l({params:e}){let{id:l}=await e,u=(0,o.getServiceRoleSupabaseClient)(),[{data:d},{data:f},{data:p},{data:m}]=await Promise.all([u.from(`coupons`).select(`*`).eq(`id`,l).single(),u.from(`products`).select(`id, title, sku, payment_provider, freemius_product_id, language:languages(code, name), product_media(sort_order, media(file_path, object_key))`).order(`title`,{ascending:!0}),u.from(`coupon_products`).select(`product_id`).eq(`coupon_id`,l),u.from(`currencies`).select(`code, is_default`).eq(`is_active`,!0)]);d||(0,s.notFound)();let h=(p||[]).map(e=>e.product_id),g=m?.find(e=>e.is_default)?.code||m?.[0]?.code||`USD`;return(0,a.jsxs)(`div`,{className:`mx-auto w-full max-w-5xl space-y-6 px-6 py-8`,children:[(0,a.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`h1`,{className:`text-3xl font-bold tracking-tight`,children:`Edit Coupon`}),(0,a.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Changes are resynced to Freemius after saving.`})]}),(0,a.jsx)(c.Button,{asChild:!0,variant:`outline`,children:(0,a.jsx)(i.default,{href:`/cms/coupons`,children:`Back to coupons`})})]}),(0,a.jsx)(n.CouponEditorForm,{action:t.updateCouponAction.bind(null,l),products:r.normalizeCouponProductOptions(f),coupon:d,selectedProductIds:h,submitLabel:`Save Coupon`,currencyCode:g})]})}exports.EditCouponPage=l;
@@ -3,6 +3,7 @@ import { CouponEditorForm as t } from "./CouponEditorForm.es.js";
3
3
  import { normalizeCouponProductOptions as n } from "./product-options.es.js";
4
4
  import r from "next/link";
5
5
  import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ import "server-only";
6
7
  import { getServiceRoleSupabaseClient as o } from "@nextblock-cms/db/server";
7
8
  import { notFound as s } from "next/navigation";
8
9
  import { Button as c } from "@nextblock-cms/ui";
@@ -1 +1 @@
1
- "use server";const e=require("../../../coupons.cjs"),t=require("../../../freemius-coupons.cjs");let n=require("@nextblock-cms/utils"),r=require("@nextblock-cms/db/server"),i=require("next/navigation"),a=require("next/cache");async function o(){let e=(0,r.createClient)(),{data:{user:t}}=await e.auth.getUser();if(!t)throw Error(`Unauthorized`);let{data:n}=await e.from(`profiles`).select(`role`).eq(`id`,t.id).single();if(n?.role!==`ADMIN`)throw Error(`Forbidden`);return(0,r.getServiceRoleSupabaseClient)()}function s(e){return(typeof e==`string`?e.trim():``)||null}function c(e){let t=s(e);if(!t)return null;let n=new Date(t);return Number.isNaN(n.getTime())?null:n.toISOString()}function l(e){let t=s(e.value),r=t?Number.parseFloat(t):NaN;if(!Number.isFinite(r)||r<=0)throw Error(`Discount amount must be greater than zero.`);return e.discountType===`fixed`?(0,n.majorUnitAmountToMinor)(r,e.currencyCode):Math.round(r)}function u(e,t){return e.getAll(t).some(e=>e===`true`)}function d(t){let r=e.normalizeCouponCode(s(t.get(`code`))),i=s(t.get(`name`)),a=s(t.get(`provider_scope`))||`all`,o=s(t.get(`discount_type`))||`percent`,d=(0,n.normalizeCurrencyCode)(s(t.get(`currency_code`))),f=l({value:t.get(`discount_amount`),discountType:o,currencyCode:d}),p=s(t.get(`redemption_limit`));if(!r)throw Error(`Coupon code is required.`);if(!i)throw Error(`Coupon name is required.`);if(o===`percent`&&f>100)throw Error(`Percent discounts cannot exceed 100.`);return{coupon:{code:r,name:i,internal_note:s(t.get(`internal_note`)),provider_scope:a,discount_type:o,discount_amount:f,is_active:u(t,`is_active`),starts_at:c(t.get(`starts_at`)),ends_at:c(t.get(`ends_at`)),redemption_limit:p?Number.parseInt(p,10):null,freemius_sync_status:a===`stripe`?`not_required`:`pending`,freemius_sync_error:null},productIds:t.getAll(`product_ids`).map(e=>typeof e==`string`?e.trim():``).filter(Boolean)}}async function f(e){if(await e.client.from(`coupon_products`).delete().eq(`coupon_id`,e.couponId),e.productIds.length===0)return;let{error:t}=await e.client.from(`coupon_products`).insert(e.productIds.map(t=>({coupon_id:e.couponId,product_id:t})));if(t)throw Error(t.message)}async function p(e){let n=await o(),r=d(e),{data:s,error:c}=await n.from(`coupons`).insert(r.coupon).select(`id`).single();if(c||!s)throw Error(c?.message||`Failed to create coupon.`);await f({client:n,couponId:s.id,productIds:r.productIds}),await t.syncCouponToFreemius({couponId:s.id,client:n}),(0,a.revalidatePath)(`/cms/coupons`),(0,i.redirect)(`/cms/coupons`)}async function m(e,n){let r=await o(),s=d(n),{error:c}=await r.from(`coupons`).update(s.coupon).eq(`id`,e);if(c)throw Error(c.message);await f({client:r,couponId:e,productIds:s.productIds}),s.coupon.provider_scope===`stripe`?await t.deleteCouponFromFreemius({couponId:e,client:r}):await t.syncCouponToFreemius({couponId:e,client:r}),(0,a.revalidatePath)(`/cms/coupons`),(0,a.revalidatePath)(`/cms/coupons/${e}/edit`),(0,i.redirect)(`/cms/coupons`)}async function h(e,n){let r=await o(),{error:i}=await r.from(`coupons`).update({is_active:n,freemius_sync_status:`pending`,updated_at:new Date().toISOString()}).eq(`id`,e);if(i)throw Error(i.message);await t.syncCouponToFreemius({couponId:e,client:r}),(0,a.revalidatePath)(`/cms/coupons`)}async function g(e){let n=await o();await t.syncCouponToFreemius({couponId:e,client:n}),(0,a.revalidatePath)(`/cms/coupons`),(0,a.revalidatePath)(`/cms/coupons/${e}/edit`)}async function _(e){let n=await o();await t.deleteCouponFromFreemius({couponId:e,client:n});let{error:r}=await n.from(`coupons`).delete().eq(`id`,e);if(r)throw Error(r.message);(0,a.revalidatePath)(`/cms/coupons`)}exports.createCouponAction=p,exports.deleteCouponAction=_,exports.syncCouponAction=g,exports.toggleCouponActiveAction=h,exports.updateCouponAction=m;
1
+ "use server";const e=require("../../../coupons.cjs"),t=require("../../../freemius-coupons.cjs");let n=require("@nextblock-cms/utils");require("server-only");let r=require("@nextblock-cms/db/server"),i=require("next/navigation"),a=require("next/cache");async function o(){let e=(0,r.createClient)(),{data:{user:t}}=await e.auth.getUser();if(!t)throw Error(`Unauthorized`);let{data:n}=await e.from(`profiles`).select(`role`).eq(`id`,t.id).single();if(n?.role!==`ADMIN`)throw Error(`Forbidden`);return(0,r.getServiceRoleSupabaseClient)()}function s(e){return(typeof e==`string`?e.trim():``)||null}function c(e){let t=s(e);if(!t)return null;let n=new Date(t);return Number.isNaN(n.getTime())?null:n.toISOString()}function l(e){let t=s(e.value),r=t?Number.parseFloat(t):NaN;if(!Number.isFinite(r)||r<=0)throw Error(`Discount amount must be greater than zero.`);return e.discountType===`fixed`?(0,n.majorUnitAmountToMinor)(r,e.currencyCode):Math.round(r)}function u(e,t){return e.getAll(t).some(e=>e===`true`)}function d(t){let r=e.normalizeCouponCode(s(t.get(`code`))),i=s(t.get(`name`)),a=s(t.get(`provider_scope`))||`all`,o=s(t.get(`discount_type`))||`percent`,d=(0,n.normalizeCurrencyCode)(s(t.get(`currency_code`))),f=l({value:t.get(`discount_amount`),discountType:o,currencyCode:d}),p=s(t.get(`redemption_limit`));if(!r)throw Error(`Coupon code is required.`);if(!i)throw Error(`Coupon name is required.`);if(o===`percent`&&f>100)throw Error(`Percent discounts cannot exceed 100.`);return{coupon:{code:r,name:i,internal_note:s(t.get(`internal_note`)),provider_scope:a,discount_type:o,discount_amount:f,is_active:u(t,`is_active`),starts_at:c(t.get(`starts_at`)),ends_at:c(t.get(`ends_at`)),redemption_limit:p?Number.parseInt(p,10):null,freemius_sync_status:a===`stripe`?`not_required`:`pending`,freemius_sync_error:null},productIds:t.getAll(`product_ids`).map(e=>typeof e==`string`?e.trim():``).filter(Boolean)}}async function f(e){if(await e.client.from(`coupon_products`).delete().eq(`coupon_id`,e.couponId),e.productIds.length===0)return;let{error:t}=await e.client.from(`coupon_products`).insert(e.productIds.map(t=>({coupon_id:e.couponId,product_id:t})));if(t)throw Error(t.message)}async function p(e){let n=await o(),r=d(e),{data:s,error:c}=await n.from(`coupons`).insert(r.coupon).select(`id`).single();if(c||!s)throw Error(c?.message||`Failed to create coupon.`);await f({client:n,couponId:s.id,productIds:r.productIds}),await t.syncCouponToFreemius({couponId:s.id,client:n}),(0,a.revalidatePath)(`/cms/coupons`),(0,i.redirect)(`/cms/coupons`)}async function m(e,n){let r=await o(),s=d(n),{error:c}=await r.from(`coupons`).update(s.coupon).eq(`id`,e);if(c)throw Error(c.message);await f({client:r,couponId:e,productIds:s.productIds}),s.coupon.provider_scope===`stripe`?await t.deleteCouponFromFreemius({couponId:e,client:r}):await t.syncCouponToFreemius({couponId:e,client:r}),(0,a.revalidatePath)(`/cms/coupons`),(0,a.revalidatePath)(`/cms/coupons/${e}/edit`),(0,i.redirect)(`/cms/coupons`)}async function h(e,n){let r=await o(),{error:i}=await r.from(`coupons`).update({is_active:n,freemius_sync_status:`pending`,updated_at:new Date().toISOString()}).eq(`id`,e);if(i)throw Error(i.message);await t.syncCouponToFreemius({couponId:e,client:r}),(0,a.revalidatePath)(`/cms/coupons`)}async function g(e){let n=await o();await t.syncCouponToFreemius({couponId:e,client:n}),(0,a.revalidatePath)(`/cms/coupons`),(0,a.revalidatePath)(`/cms/coupons/${e}/edit`)}async function _(e){let n=await o();await t.deleteCouponFromFreemius({couponId:e,client:n});let{error:r}=await n.from(`coupons`).delete().eq(`id`,e);if(r)throw Error(r.message);(0,a.revalidatePath)(`/cms/coupons`)}exports.createCouponAction=p,exports.deleteCouponAction=_,exports.syncCouponAction=g,exports.toggleCouponActiveAction=h,exports.updateCouponAction=m;
@@ -2,6 +2,7 @@
2
2
  import { normalizeCouponCode as e } from "../../../coupons.es.js";
3
3
  import { deleteCouponFromFreemius as t, syncCouponToFreemius as n } from "../../../freemius-coupons.es.js";
4
4
  import { majorUnitAmountToMinor as r, normalizeCurrencyCode as i } from "@nextblock-cms/utils";
5
+ import "server-only";
5
6
  import { createClient as a, getServiceRoleSupabaseClient as o } from "@nextblock-cms/db/server";
6
7
  import { redirect as s } from "next/navigation";
7
8
  import { revalidatePath as c } from "next/cache";
@@ -1,4 +1,4 @@
1
- "use server";const e=require("../../../server-actions/require-ecom-role.cjs");let t=require("@nextblock-cms/db/server");var n=20,r=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function i(e){let t=typeof e==`string`?e.trim():``;return!t||!r.test(t)?null:t.toLowerCase()}async function a(){return await e.getEcomActorRole()===`ADMIN`?(0,t.getServiceRoleSupabaseClient)():null}async function o(e=1,t,r){let o=i(r);if(r&&!o)return{data:[],total:0,totalPages:0};let s=await a();if(!s)return{data:[],total:0,totalPages:0};let c=((Number.isInteger(e)&&e>0?e:1)-1)*n,l=c+n-1,u=s.from(`orders`).select(`
1
+ "use server";const e=require("../../../server-actions/require-ecom-role.cjs");require("server-only");let t=require("@nextblock-cms/db/server");var n=20,r=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function i(e){let t=typeof e==`string`?e.trim():``;return!t||!r.test(t)?null:t.toLowerCase()}async function a(){return await e.getEcomActorRole()===`ADMIN`?(0,t.getServiceRoleSupabaseClient)():null}async function o(e=1,t,r){let o=i(r);if(r&&!o)return{data:[],total:0,totalPages:0};let s=await a();if(!s)return{data:[],total:0,totalPages:0};let c=((Number.isInteger(e)&&e>0?e:1)-1)*n,l=c+n-1,u=s.from(`orders`).select(`
2
2
  *,
3
3
  order_items (*)
4
4
  `,{count:`exact`}).order(`created_at`,{ascending:!1}).range(c,l);t&&t!==`all`&&(u=u.eq(`status`,t)),o&&(u=u.or(`id.eq.${o},user_id.eq.${o}`));let{data:d,error:f,count:p}=await u;if(f)throw console.error(`Error fetching orders:`,f),Error(`Failed to fetch orders`);let m=d||[],h=Array.from(new Set(m.map(e=>e.user_id).filter(Boolean))),g=new Map;if(h.length>0){let{data:e,error:t}=await s.from(`profiles`).select(`*`).in(`id`,h);!t&&e&&e.forEach(e=>g.set(e.id,e))}return{data:m.map(e=>({...e,customer:e.user_id?g.get(e.user_id):null})),total:p||0,totalPages:p?Math.ceil(p/n):0}}async function s(e){let t=await a();if(!t)return null;let{data:n,error:r}=await t.from(`orders`).select(`
@@ -1,5 +1,6 @@
1
1
  "use server";
2
2
  import { getEcomActorRole as e } from "../../../server-actions/require-ecom-role.es.js";
3
+ import "server-only";
3
4
  import { getServiceRoleSupabaseClient as t } from "@nextblock-cms/db/server";
4
5
  //#region src/lib/pages/cms/orders/actions.ts
5
6
  var n = 20, r = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -1 +1 @@
1
- "use server";const e=require("../../../server-actions/require-ecom-role.cjs");let t=require("@nextblock-cms/db/server");async function n(n,r){if(await e.getEcomActorRole()!==`ADMIN`)return[];let i=(0,t.getServiceRoleSupabaseClient)(),a=i.from(`orders`).select(`*, order_items(*)`);if(n&&(a=a.gte(`created_at`,n)),r){let e=new Date(r);e.setHours(23,59,59,999),a=a.lte(`created_at`,e.toISOString())}let{data:o,error:s}=await a.order(`created_at`,{ascending:!0});if(s)throw console.error(`Error fetching report data:`,s),Error(`Failed to fetch report data: ${s.message}`);if(!o||o.length===0)return[];let c=Array.from(new Set(o.map(e=>e.user_id).filter(e=>!!e))),l=new Map;if(c.length>0){let{data:e}=await i.from(`profiles`).select(`id, full_name`).in(`id`,c);e&&e.forEach(e=>l.set(e.id,e))}return o.map(e=>({...e,customer:e.user_id?l.get(e.user_id):null}))}exports.fetchOrderReportData=n;
1
+ "use server";const e=require("../../../server-actions/require-ecom-role.cjs");require("server-only");let t=require("@nextblock-cms/db/server");async function n(n,r){if(await e.getEcomActorRole()!==`ADMIN`)return[];let i=(0,t.getServiceRoleSupabaseClient)(),a=i.from(`orders`).select(`*, order_items(*)`);if(n&&(a=a.gte(`created_at`,n)),r){let e=new Date(r);e.setHours(23,59,59,999),a=a.lte(`created_at`,e.toISOString())}let{data:o,error:s}=await a.order(`created_at`,{ascending:!0});if(s)throw console.error(`Error fetching report data:`,s),Error(`Failed to fetch report data: ${s.message}`);if(!o||o.length===0)return[];let c=Array.from(new Set(o.map(e=>e.user_id).filter(e=>!!e))),l=new Map;if(c.length>0){let{data:e}=await i.from(`profiles`).select(`id, full_name`).in(`id`,c);e&&e.forEach(e=>l.set(e.id,e))}return o.map(e=>({...e,customer:e.user_id?l.get(e.user_id):null}))}exports.fetchOrderReportData=n;
@@ -1,5 +1,6 @@
1
1
  "use server";
2
2
  import { getEcomActorRole as e } from "../../../server-actions/require-ecom-role.es.js";
3
+ import "server-only";
3
4
  import { getServiceRoleSupabaseClient as t } from "@nextblock-cms/db/server";
4
5
  //#region src/lib/pages/cms/orders/export-actions.ts
5
6
  async function n(n, r) {
@@ -1 +1 @@
1
- "use server";const e=require("../../../order-inventory.cjs"),t=require("../../../invoice-server.cjs");let n=require("@nextblock-cms/db/server"),r=require("@supabase/supabase-js");var i=[`pending`,`trial`,`paid`,`shipped`,`cancelled`,`refunded`];async function a(){let e=(0,n.createClient)(),{data:{user:t},error:r}=await e.auth.getUser();if(r||!t)return{error:`Unauthorized`};let{data:i,error:a}=await e.from(`profiles`).select(`role`).eq(`id`,t.id).single();return a||!i||![`ADMIN`,`WRITER`].includes(i.role)?{error:`Forbidden`}:{supabase:e,user:t,role:i.role}}var o=new Set([`paid`,`cancelled`,`refunded`]);function s(){let e=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY,t=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL;if(!e||!t)throw Error(`Server configuration error`);return(0,r.createClient)(t,e,{auth:{autoRefreshToken:!1,persistSession:!1}})}async function c(n,r){let c=await a();if(`error`in c)return{success:!1,error:c.error};if(!i.includes(r))return{success:!1,error:`Invalid order status`};if(o.has(r)&&c.role!==`ADMIN`)return{success:!1,error:`Forbidden`};let l;try{l=s()}catch(e){return{success:!1,error:e instanceof Error?e.message:`Server configuration error`}}let{data:u,error:d}=await l.from(`orders`).update({status:r}).eq(`id`,n).select();return d?(console.error(`Order status update error:`,d),{success:!1,error:d.message}):!u||u.length===0?{success:!1,error:`Order not found or update failed.`}:(r===`paid`&&(await t.assignInvoiceMetadata({orderId:n,client:l}),await e.applyOrderInventoryDeduction(l,n)),{success:!0})}exports.updateOrderStatus=c;
1
+ "use server";const e=require("../../../order-inventory.cjs"),t=require("../../../invoice-server.cjs");require("server-only");let n=require("@nextblock-cms/db/server"),r=require("@supabase/supabase-js");var i=[`pending`,`trial`,`paid`,`shipped`,`cancelled`,`refunded`];async function a(){let e=(0,n.createClient)(),{data:{user:t},error:r}=await e.auth.getUser();if(r||!t)return{error:`Unauthorized`};let{data:i,error:a}=await e.from(`profiles`).select(`role`).eq(`id`,t.id).single();return a||!i||![`ADMIN`,`WRITER`].includes(i.role)?{error:`Forbidden`}:{supabase:e,user:t,role:i.role}}var o=new Set([`paid`,`cancelled`,`refunded`]);function s(){let e=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY,t=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL;if(!e||!t)throw Error(`Server configuration error`);return(0,r.createClient)(t,e,{auth:{autoRefreshToken:!1,persistSession:!1}})}async function c(n,r){let c=await a();if(`error`in c)return{success:!1,error:c.error};if(!i.includes(r))return{success:!1,error:`Invalid order status`};if(o.has(r)&&c.role!==`ADMIN`)return{success:!1,error:`Forbidden`};let l;try{l=s()}catch(e){return{success:!1,error:e instanceof Error?e.message:`Server configuration error`}}let{data:u,error:d}=await l.from(`orders`).update({status:r}).eq(`id`,n).select();return d?(console.error(`Order status update error:`,d),{success:!1,error:d.message}):!u||u.length===0?{success:!1,error:`Order not found or update failed.`}:(r===`paid`&&(await t.assignInvoiceMetadata({orderId:n,client:l}),await e.applyOrderInventoryDeduction(l,n)),{success:!0})}exports.updateOrderStatus=c;
@@ -1,6 +1,7 @@
1
1
  "use server";
2
2
  import { applyOrderInventoryDeduction as e } from "../../../order-inventory.es.js";
3
3
  import { assignInvoiceMetadata as t } from "../../../invoice-server.es.js";
4
+ import "server-only";
4
5
  import { createClient as n } from "@nextblock-cms/db/server";
5
6
  import { createClient as r } from "@supabase/supabase-js";
6
7
  //#region src/lib/pages/cms/orders/server-actions.ts
@@ -1 +1 @@
1
- const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("./actions.cjs"),n=require("./server-actions.cjs"),r=require("./components/ProductsBulkTable.cjs"),i=require("./components/SyncFreemiusButton.cjs");let a=require("next/link");a=e.__toESM(a,1);let o=require("react/jsx-runtime"),s=require("@nextblock-cms/db/server"),c=require("@nextblock-cms/ui"),l=require("@nextblock-cms/utils/seo");async function u({searchParams:e,languageFilterNode:u,transferControlsNode:d}){let f=(0,s.getServiceRoleSupabaseClient)(),[p,{data:m}]=await Promise.all([(0,s.getActiveLanguagesServerSide)(),f.from(`currencies`).select(`code, is_default`).eq(`is_active`,!0).order(`is_default`,{ascending:!1}).order(`code`,{ascending:!0})]),h=e?.lang?parseInt(e.lang,10):void 0,{data:g}=await t.getProducts({languageId:h}),_=g||[],v=_.map(e=>e.id),{data:y}=v.length>0?await f.from(`blocks`).select(`id, product_id, block_type, content, order`).in(`product_id`,v).order(`order`,{ascending:!0}):{data:[]},b=new Map;for(let e of y||[]){if(!e.product_id)continue;let t=b.get(e.product_id)||[];t.push(e),b.set(e.product_id,t)}let x=_.map(e=>{let t=b.get(e.id)||[],n=(0,l.buildPageSeoDocument)(t,{documentTitle:e.title,documentType:`product`}),r=(0,l.auditSeo)({document:n,metaTitle:e.meta_title??void 0,metaDescription:e.meta_description??void 0,scope:`page`});return{...e,seo_score:r.score}}),S=Object.fromEntries(p.map(e=>[String(e.id),e.code.toUpperCase()])),C=m?.find(e=>e.is_default)?.code||m?.[0]?.code||`USD`;return(0,o.jsxs)(`div`,{className:`p-8 space-y-6`,children:[(0,o.jsxs)(`div`,{className:`flex justify-between items-center`,children:[(0,o.jsx)(`h1`,{className:`text-3xl font-bold`,children:`Products`}),(0,o.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4`,children:[(0,o.jsx)(`div`,{className:`h-10 w-[1px] bg-slate-200 dark:bg-slate-800 mx-2 hidden sm:block`}),d,u,(0,o.jsx)(i.SyncFreemiusButton,{title:`Sync Full Store`}),(0,o.jsx)(a.default,{href:`/cms/products/new`,children:(0,o.jsx)(c.Button,{children:`New Product`})})]})]}),(0,o.jsx)(r.ProductsBulkTable,{products:x,languageLabels:S,defaultCurrencyCode:C,deleteProductAction:n.deleteProductAction,bulkDeleteProductsAction:n.bulkDeleteProductsAction,bulkDraftProductsAction:n.bulkDraftProductsAction})]})}exports.ProductsPage=u;
1
+ const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("./actions.cjs"),n=require("./server-actions.cjs"),r=require("./components/ProductsBulkTable.cjs"),i=require("./components/SyncFreemiusButton.cjs");let a=require("next/link");a=e.__toESM(a,1);let o=require("react/jsx-runtime");require("server-only");let s=require("@nextblock-cms/db/server"),c=require("@nextblock-cms/ui"),l=require("@nextblock-cms/utils/seo");async function u({searchParams:e,languageFilterNode:u,transferControlsNode:d}){let f=(0,s.getServiceRoleSupabaseClient)(),[p,{data:m}]=await Promise.all([(0,s.getActiveLanguagesServerSide)(),f.from(`currencies`).select(`code, is_default`).eq(`is_active`,!0).order(`is_default`,{ascending:!1}).order(`code`,{ascending:!0})]),h=e?.lang?parseInt(e.lang,10):void 0,{data:g}=await t.getProducts({languageId:h}),_=g||[],v=_.map(e=>e.id),{data:y}=v.length>0?await f.from(`blocks`).select(`id, product_id, block_type, content, order`).in(`product_id`,v).order(`order`,{ascending:!0}):{data:[]},b=new Map;for(let e of y||[]){if(!e.product_id)continue;let t=b.get(e.product_id)||[];t.push(e),b.set(e.product_id,t)}let x=_.map(e=>{let t=b.get(e.id)||[],n=(0,l.buildPageSeoDocument)(t,{documentTitle:e.title,documentType:`product`}),r=(0,l.auditSeo)({document:n,metaTitle:e.meta_title??void 0,metaDescription:e.meta_description??void 0,scope:`page`});return{...e,seo_score:r.score}}),S=Object.fromEntries(p.map(e=>[String(e.id),e.code.toUpperCase()])),C=m?.find(e=>e.is_default)?.code||m?.[0]?.code||`USD`;return(0,o.jsxs)(`div`,{className:`p-8 space-y-6`,children:[(0,o.jsxs)(`div`,{className:`flex justify-between items-center`,children:[(0,o.jsx)(`h1`,{className:`text-3xl font-bold`,children:`Products`}),(0,o.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4`,children:[(0,o.jsx)(`div`,{className:`h-10 w-[1px] bg-slate-200 dark:bg-slate-800 mx-2 hidden sm:block`}),d,u,(0,o.jsx)(i.SyncFreemiusButton,{title:`Sync Full Store`}),(0,o.jsx)(a.default,{href:`/cms/products/new`,children:(0,o.jsx)(c.Button,{children:`New Product`})})]})]}),(0,o.jsx)(r.ProductsBulkTable,{products:x,languageLabels:S,defaultCurrencyCode:C,deleteProductAction:n.deleteProductAction,bulkDeleteProductsAction:n.bulkDeleteProductsAction,bulkDraftProductsAction:n.bulkDraftProductsAction})]})}exports.ProductsPage=u;
@@ -4,6 +4,7 @@ import { ProductsBulkTable as i } from "./components/ProductsBulkTable.es.js";
4
4
  import { SyncFreemiusButton as a } from "./components/SyncFreemiusButton.es.js";
5
5
  import o from "next/link";
6
6
  import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
+ import "server-only";
7
8
  import { getActiveLanguagesServerSide as l, getServiceRoleSupabaseClient as u } from "@nextblock-cms/db/server";
8
9
  import { Button as d } from "@nextblock-cms/ui";
9
10
  import { auditSeo as f, buildPageSeoDocument as p } from "@nextblock-cms/utils/seo";
@@ -1 +1 @@
1
- const e=require("../../../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../../../currency.cjs"),n=require("../../../../../variation-utils.cjs"),r=require("../../actions.cjs"),i=require("../../server-actions.cjs"),a=require("../../components/ProductForm.cjs"),o=require("../../../payments/queries.cjs"),s=require("../../components/DeleteProductButton.cjs"),c=require("../../components/FreemiusPricingDashboard.cjs");let l=require("next/link");l=e.__toESM(l,1);let u=require("lucide-react"),d=require("@nextblock-cms/utils"),f=require("react/jsx-runtime"),p=require("@nextblock-cms/db/server"),m=require("next/navigation"),h=require("@nextblock-cms/ui");async function g({params:e,mediaPickerNode:g,availableLanguagesProp:_,languageSwitcherNode:v,copyContentNode:y,translationCtaNode:b}){let{id:x}=await e,S=await r.getProduct(x);S||(0,m.notFound)();let C=S.product_type===`digital`||S.payment_provider===`freemius`,[w,T,E,D,O]=await Promise.all([o.getEnabledPaymentProviders(),o.getStoreConfigStatus(),C&&S.freemius_product_id?r.getFreemiusPricingByProductId(S.id):Promise.resolve(null),r.getGlobalProductAttributes(),(0,p.getServiceRoleSupabaseClient)().from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}).then(e=>e.data||[])]),k=(O||[]).map(e=>t.normalizeCurrencyRecord(e)),A=_.find(e=>e.id===S.language_id)?.code,{attributes:j,variants:M}=n.mapRawVariantRelations(S.product_variants||[],A),N=(D||[]).map(e=>({id:e.id,name:e.name,name_translations:e.name_translations||{},slug:e.slug,terms:(e.product_attribute_terms||[]).map(e=>({...e,value_translations:e.value_translations||{}}))})),P=s.DeleteProductButton,F=c.FreemiusPricingDashboard;return(0,f.jsxs)(`div`,{className:`space-y-8 w-full max-w-[1400px] mx-auto px-6 py-8`,children:[(0,f.jsxs)(`div`,{className:`flex justify-between items-center flex-wrap gap-4 w-full`,children:[(0,f.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,f.jsx)(h.Button,{variant:`outline`,size:`icon`,"aria-label":`Back to products`,asChild:!0,children:(0,f.jsx)(l.default,{href:`/cms/products`,children:(0,f.jsx)(u.ArrowLeft,{className:`h-4 w-4`})})}),(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`h1`,{className:`text-2xl font-bold`,children:`Edit Product`}),(0,f.jsx)(`p`,{className:`text-sm text-muted-foreground truncate max-w-md`,title:S.title,children:S.title})]})]}),(0,f.jsxs)(`div`,{className:`flex items-center gap-3 flex-wrap`,children:[v,y,b,P?(0,f.jsx)(P,{productName:S.title,redirectTo:`/cms/products`,className:`border-red-200 hover:bg-red-50 hover:text-red-700`,deleteAction:i.deleteProductAction.bind(null,S.id)}):null,S.slug&&S.status===`active`&&(0,f.jsx)(h.Button,{variant:`outline`,asChild:!0,children:(0,f.jsxs)(l.default,{href:`/product/${S.slug}`,target:`_blank`,children:[(0,f.jsx)(u.ExternalLink,{className:`w-4 h-4 mr-2`}),`View`]})})]})]}),(0,f.jsx)(a.ProductForm,{initialData:{id:S.id,title:S.title,slug:S.slug,sku:S.sku,upc:S.upc??void 0,stock:S.stock||0,price:S.price||0,prices:Object.entries(S.prices||{}).reduce((e,[t,n])=>(e[t]=(0,d.minorUnitAmountToMajor)(n,t),e),{}),is_taxable:typeof S.is_taxable!=`boolean`||S.is_taxable,product_type:S.product_type,payment_provider:S.payment_provider,status:S.status,short_description:S.short_description??void 0,description_json:S.description_json,sale_price:typeof S.sale_price==`number`?S.sale_price:void 0,sale_prices:Object.entries(S.sale_prices||{}).reduce((e,[t,n])=>(e[t]=typeof n==`number`?(0,d.minorUnitAmountToMajor)(n,t):null,e),{}),freemius_plan_id:S.freemius_plan_id??void 0,freemius_product_id:S.freemius_product_id??void 0,trial_period_days:S.trial_period_days??0,trial_requires_payment_method:S.trial_requires_payment_method??!1,language_id:S.language_id,translation_group_id:S.translation_group_id,product_media:S.product_media,variation_attributes:j.map(e=>({attribute_id:e.id,term_ids:e.terms.map(e=>e.id)})),variants:M.map(e=>({...e,upc:e.upc??null,price:e.price/100,prices:Object.entries(e.prices||{}).reduce((e,[t,n])=>(e[t]=(0,d.minorUnitAmountToMajor)(n,t),e),{}),sale_price:typeof e.sale_price==`number`?e.sale_price/100:null,sale_prices:Object.entries(e.sale_prices||{}).reduce((e,[t,n])=>(e[t]=typeof n==`number`?(0,d.minorUnitAmountToMajor)(n,t):null,e),{}),main_media_id:e.main_media_id??null,main_image_url:e.image_url??null}))},isEdit:!0,mediaPickerNode:g,availableLanguagesProp:_,globalAttributesProp:N,currenciesProp:k,enabledProviders:w,configStatus:T,updateAction:i.updateProductAction.bind(null,S.id),freemiusDashboardNode:C&&S.freemius_product_id&&E&&F?(0,f.jsx)(F,{productId:S.id,freemiusProductId:S.freemius_product_id,plans:E}):void 0})]})}exports.EditProductPage=g;
1
+ const e=require("../../../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../../../currency.cjs"),n=require("../../../../../variation-utils.cjs"),r=require("../../actions.cjs"),i=require("../../server-actions.cjs"),a=require("../../components/ProductForm.cjs"),o=require("../../../payments/queries.cjs"),s=require("../../components/DeleteProductButton.cjs"),c=require("../../components/FreemiusPricingDashboard.cjs");let l=require("next/link");l=e.__toESM(l,1);let u=require("lucide-react"),d=require("@nextblock-cms/utils"),f=require("react/jsx-runtime");require("server-only");let p=require("@nextblock-cms/db/server"),m=require("next/navigation"),h=require("@nextblock-cms/ui");async function g({params:e,mediaPickerNode:g,availableLanguagesProp:_,languageSwitcherNode:v,copyContentNode:y,translationCtaNode:b}){let{id:x}=await e,S=await r.getProduct(x);S||(0,m.notFound)();let C=S.product_type===`digital`||S.payment_provider===`freemius`,[w,T,E,D,O]=await Promise.all([o.getEnabledPaymentProviders(),o.getStoreConfigStatus(),C&&S.freemius_product_id?r.getFreemiusPricingByProductId(S.id):Promise.resolve(null),r.getGlobalProductAttributes(),(0,p.getServiceRoleSupabaseClient)().from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}).then(e=>e.data||[])]),k=(O||[]).map(e=>t.normalizeCurrencyRecord(e)),A=_.find(e=>e.id===S.language_id)?.code,{attributes:j,variants:M}=n.mapRawVariantRelations(S.product_variants||[],A),N=(D||[]).map(e=>({id:e.id,name:e.name,name_translations:e.name_translations||{},slug:e.slug,terms:(e.product_attribute_terms||[]).map(e=>({...e,value_translations:e.value_translations||{}}))})),P=s.DeleteProductButton,F=c.FreemiusPricingDashboard;return(0,f.jsxs)(`div`,{className:`space-y-8 w-full max-w-[1400px] mx-auto px-6 py-8`,children:[(0,f.jsxs)(`div`,{className:`flex justify-between items-center flex-wrap gap-4 w-full`,children:[(0,f.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,f.jsx)(h.Button,{variant:`outline`,size:`icon`,"aria-label":`Back to products`,asChild:!0,children:(0,f.jsx)(l.default,{href:`/cms/products`,children:(0,f.jsx)(u.ArrowLeft,{className:`h-4 w-4`})})}),(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`h1`,{className:`text-2xl font-bold`,children:`Edit Product`}),(0,f.jsx)(`p`,{className:`text-sm text-muted-foreground truncate max-w-md`,title:S.title,children:S.title})]})]}),(0,f.jsxs)(`div`,{className:`flex items-center gap-3 flex-wrap`,children:[v,y,b,P?(0,f.jsx)(P,{productName:S.title,redirectTo:`/cms/products`,className:`border-red-200 hover:bg-red-50 hover:text-red-700`,deleteAction:i.deleteProductAction.bind(null,S.id)}):null,S.slug&&S.status===`active`&&(0,f.jsx)(h.Button,{variant:`outline`,asChild:!0,children:(0,f.jsxs)(l.default,{href:`/product/${S.slug}`,target:`_blank`,children:[(0,f.jsx)(u.ExternalLink,{className:`w-4 h-4 mr-2`}),`View`]})})]})]}),(0,f.jsx)(a.ProductForm,{initialData:{id:S.id,title:S.title,slug:S.slug,sku:S.sku,upc:S.upc??void 0,stock:S.stock||0,price:S.price||0,prices:Object.entries(S.prices||{}).reduce((e,[t,n])=>(e[t]=(0,d.minorUnitAmountToMajor)(n,t),e),{}),is_taxable:typeof S.is_taxable!=`boolean`||S.is_taxable,product_type:S.product_type,payment_provider:S.payment_provider,status:S.status,short_description:S.short_description??void 0,description_json:S.description_json,sale_price:typeof S.sale_price==`number`?S.sale_price:void 0,sale_prices:Object.entries(S.sale_prices||{}).reduce((e,[t,n])=>(e[t]=typeof n==`number`?(0,d.minorUnitAmountToMajor)(n,t):null,e),{}),freemius_plan_id:S.freemius_plan_id??void 0,freemius_product_id:S.freemius_product_id??void 0,trial_period_days:S.trial_period_days??0,trial_requires_payment_method:S.trial_requires_payment_method??!1,language_id:S.language_id,translation_group_id:S.translation_group_id,product_media:S.product_media,variation_attributes:j.map(e=>({attribute_id:e.id,term_ids:e.terms.map(e=>e.id)})),variants:M.map(e=>({...e,upc:e.upc??null,price:e.price/100,prices:Object.entries(e.prices||{}).reduce((e,[t,n])=>(e[t]=(0,d.minorUnitAmountToMajor)(n,t),e),{}),sale_price:typeof e.sale_price==`number`?e.sale_price/100:null,sale_prices:Object.entries(e.sale_prices||{}).reduce((e,[t,n])=>(e[t]=typeof n==`number`?(0,d.minorUnitAmountToMajor)(n,t):null,e),{}),main_media_id:e.main_media_id??null,main_image_url:e.image_url??null}))},isEdit:!0,mediaPickerNode:g,availableLanguagesProp:_,globalAttributesProp:N,currenciesProp:k,enabledProviders:w,configStatus:T,updateAction:i.updateProductAction.bind(null,S.id),freemiusDashboardNode:C&&S.freemius_product_id&&E&&F?(0,f.jsx)(F,{productId:S.id,freemiusProductId:S.freemius_product_id,plans:E}):void 0})]})}exports.EditProductPage=g;
@@ -10,6 +10,7 @@ import f from "next/link";
10
10
  import { ArrowLeft as p, ExternalLink as m } from "lucide-react";
11
11
  import { minorUnitAmountToMajor as h } from "@nextblock-cms/utils";
12
12
  import { jsx as g, jsxs as _ } from "react/jsx-runtime";
13
+ import "server-only";
13
14
  import { getServiceRoleSupabaseClient as v } from "@nextblock-cms/db/server";
14
15
  import { notFound as y } from "next/navigation";
15
16
  import { Button as b } from "@nextblock-cms/ui";
@@ -1,4 +1,4 @@
1
- "use server";const e=require("../../../server-actions/require-ecom-role.cjs"),t=require("../../../product-actions.cjs"),n=require("../../../providers/freemius.cjs");let r=require("@nextblock-cms/db/server"),i=require("next/cache");async function a(e){let n=(0,r.createClient)(),{data:i,count:a,error:o}=await await t.getProducts(n,{...e,status:`all`});if(o)throw Error(o.message);return{data:i,count:a}}async function o(e){let n=(0,r.createClient)(),{data:i,error:a}=await t.getProduct(n,e);if(a)throw Error(a.message);return i}async function s(){try{await e.requireEcomAdmin();let t=await n.syncFreemiusProductsToSupabase();return(0,i.revalidatePath)(`/cms/products`,`page`),{success:!0,data:t}}catch(e){return{error:e.message||`Failed to sync with Freemius`}}}async function c(t){try{await e.requireEcomAdmin();let r=await n.syncSingleFreemiusProduct(t);return(0,i.revalidatePath)(`/cms/products`,`page`),(0,i.revalidatePath)(`/cms/products/[id]/edit`,`page`),{success:!0,data:r}}catch(e){return{error:e.message||`Failed to sync product with Freemius`}}}async function l(e,n){try{let a=(0,r.createClient)();return await t.copyProductFromLanguage(a,e,n),(0,i.revalidatePath)(`/cms/products`),(0,i.revalidatePath)(`/cms/products/${e}/edit`),{success:!0}}catch(e){return{success:!1,error:e.message||`Failed to copy product content`}}}async function u(e){let{data:t,error:n}=await(0,r.createClient)().from(`products`).select(`id, title, language_id, slug`).eq(`translation_group_id`,e);if(n)throw Error(n.message);return t}async function d(){let{data:e,error:t}=await(0,r.getServiceRoleSupabaseClient)().from(`product_attributes`).select(`
1
+ "use server";const e=require("../../../server-actions/require-ecom-role.cjs"),t=require("../../../product-actions.cjs"),n=require("../../../providers/freemius.cjs");require("server-only");let r=require("@nextblock-cms/db/server"),i=require("next/cache");async function a(e){let n=(0,r.createClient)(),{data:i,count:a,error:o}=await await t.getProducts(n,{...e,status:`all`});if(o)throw Error(o.message);return{data:i,count:a}}async function o(e){let n=(0,r.createClient)(),{data:i,error:a}=await t.getProduct(n,e);if(a)throw Error(a.message);return i}async function s(){try{await e.requireEcomAdmin();let t=await n.syncFreemiusProductsToSupabase();return(0,i.revalidatePath)(`/cms/products`,`page`),{success:!0,data:t}}catch(e){return{error:e.message||`Failed to sync with Freemius`}}}async function c(t){try{await e.requireEcomAdmin();let r=await n.syncSingleFreemiusProduct(t);return(0,i.revalidatePath)(`/cms/products`,`page`),(0,i.revalidatePath)(`/cms/products/[id]/edit`,`page`),{success:!0,data:r}}catch(e){return{error:e.message||`Failed to sync product with Freemius`}}}async function l(e,n){try{let a=(0,r.createClient)();return await t.copyProductFromLanguage(a,e,n),(0,i.revalidatePath)(`/cms/products`),(0,i.revalidatePath)(`/cms/products/${e}/edit`),{success:!0}}catch(e){return{success:!1,error:e.message||`Failed to copy product content`}}}async function u(e){let{data:t,error:n}=await(0,r.createClient)().from(`products`).select(`id, title, language_id, slug`).eq(`translation_group_id`,e);if(n)throw Error(n.message);return t}async function d(){let{data:e,error:t}=await(0,r.getServiceRoleSupabaseClient)().from(`product_attributes`).select(`
2
2
  id,
3
3
  name,
4
4
  name_translations,
@@ -26,7 +26,7 @@
26
26
  override_lifetime_price,
27
27
  is_active
28
28
  )
29
- `).eq(`product_id`,e);if(n)throw Error(n.message);return t}async function p(e,t){let{error:n}=await(0,r.createClient)().from(`freemius_pricing`).update({...t,updated_at:new Date().toISOString()}).eq(`id`,e);return n?{success:!1,error:n.message}:((0,i.revalidatePath)(`/cms/products`),{success:!0})}async function m(e){let t=(0,r.createClient)(),{data:n}=await t.from(`products`).select(`translation_group_id`).eq(`id`,e).maybeSingle(),i=[e];if(n?.translation_group_id){let{data:e}=await t.from(`products`).select(`id`).eq(`translation_group_id`,n.translation_group_id);e&&e.length>0&&(i=e.map(e=>e.id))}let{data:a,error:o}=await t.from(`freemius_plans`).select(`
29
+ `).eq(`product_id`,e);if(n)throw Error(n.message);return t}var p=[`override_monthly_price`,`override_annual_price`,`override_lifetime_price`];async function m(t,n){let r;try{r=await e.requireEcomAdmin()}catch(e){return{success:!1,error:e?.message===`Unauthorized`?`Sign in as an administrator to change Freemius price overrides.`:e?.message===`Forbidden`?`Only administrators can change Freemius price overrides.`:e?.message||`Failed to update pricing`}}let a=n&&typeof n==`object`?n:{},o={};for(let e of p){let t=a[e];if(t!==void 0){if(t!==null&&(typeof t!=`number`||!Number.isFinite(t)||t<0))return{success:!1,error:`A price override must be empty or a number of 0 or more.`};o[e]=t}}if(Object.keys(o).length===0)return{success:!1,error:`No price override to save.`};let{data:s,error:c}=await r.from(`freemius_pricing`).update({...o,updated_at:new Date().toISOString()}).eq(`id`,t).select(`id`);return c?{success:!1,error:c.message}:!s||s.length===0?{success:!1,error:`This pricing row no longer exists. Reload the page and try again.`}:((0,i.revalidatePath)(`/cms/products`),(0,i.revalidatePath)(`/cms/products/[id]/edit`,`page`),{success:!0})}async function h(e){let t=(0,r.createClient)(),{data:n}=await t.from(`products`).select(`translation_group_id`).eq(`id`,e).maybeSingle(),i=[e];if(n?.translation_group_id){let{data:e}=await t.from(`products`).select(`id`).eq(`translation_group_id`,n.translation_group_id);e&&e.length>0&&(i=e.map(e=>e.id))}let{data:a,error:o}=await t.from(`freemius_plans`).select(`
30
30
  id,
31
31
  name,
32
32
  title,
@@ -41,4 +41,4 @@
41
41
  override_lifetime_price,
42
42
  is_active
43
43
  )
44
- `).in(`product_id`,i);if(o)throw Error(o.message);return(a||[]).map(e=>({id:e.id,name:e.name,title:e.title,pricing:(e.freemius_pricing||[]).filter(e=>e.is_active!==!1).map(e=>({id:e.id,license_quota:e.license_quota,monthly_price:e.override_monthly_price??e.api_monthly_price,annual_price:e.override_annual_price??e.api_annual_price,lifetime_price:e.override_lifetime_price??e.api_lifetime_price,is_active:e.is_active}))}))}async function h(){let{data:e,error:t}=await(0,r.createClient)().from(`categories`).select(`id, name, slug, description, created_at, name_translations, description_translations, product_categories(count)`).order(`name`,{ascending:!0});if(t)throw Error(t.message);return(e||[]).map(e=>{let t=e.product_categories?.[0]?.count??e.product_categories?.count??0;return{id:e.id,name:e.name,slug:e.slug,description:e.description??``,created_at:e.created_at,productCount:Number(t),name_translations:e.name_translations||{},description_translations:e.description_translations||{}}})}async function g(e){let{data:t,error:n}=await(0,r.createClient)().from(`categories`).select(`id, name, slug, description, created_at`).eq(`slug`,e).maybeSingle();if(n)throw Error(n.message);return t}async function _(e){let{data:t,error:n}=await(0,r.createClient)().from(`product_categories`).select(`category:categories(id, name, slug, description, name_translations, description_translations, created_at)`).eq(`product_id`,e);if(n)throw Error(n.message);return(t||[]).map(e=>e.category).filter(Boolean)}exports.copyProductFromLanguageAction=l,exports.getCategoriesWithCount=h,exports.getCategoryBySlug=g,exports.getFreemiusPricingByProductId=f,exports.getGlobalProductAttributes=d,exports.getProduct=o,exports.getProductCategories=_,exports.getProductTranslations=u,exports.getProducts=a,exports.getPublicFreemiusPricing=m,exports.triggerFreemiusSync=s,exports.triggerSingleProductSync=c,exports.updateFreemiusOverride=p;
44
+ `).in(`product_id`,i);if(o)throw Error(o.message);return(a||[]).map(e=>({id:e.id,name:e.name,title:e.title,pricing:(e.freemius_pricing||[]).filter(e=>e.is_active!==!1).map(e=>({id:e.id,license_quota:e.license_quota,monthly_price:e.override_monthly_price??e.api_monthly_price,annual_price:e.override_annual_price??e.api_annual_price,lifetime_price:e.override_lifetime_price??e.api_lifetime_price,is_active:e.is_active}))}))}async function g(){let{data:e,error:t}=await(0,r.createClient)().from(`categories`).select(`id, name, slug, description, created_at, name_translations, description_translations, product_categories(count)`).order(`name`,{ascending:!0});if(t)throw Error(t.message);return(e||[]).map(e=>{let t=e.product_categories?.[0]?.count??e.product_categories?.count??0;return{id:e.id,name:e.name,slug:e.slug,description:e.description??``,created_at:e.created_at,productCount:Number(t),name_translations:e.name_translations||{},description_translations:e.description_translations||{}}})}async function _(e){let{data:t,error:n}=await(0,r.createClient)().from(`categories`).select(`id, name, slug, description, created_at`).eq(`slug`,e).maybeSingle();if(n)throw Error(n.message);return t}async function v(e){let{data:t,error:n}=await(0,r.createClient)().from(`product_categories`).select(`category:categories(id, name, slug, description, name_translations, description_translations, created_at)`).eq(`product_id`,e);if(n)throw Error(n.message);return(t||[]).map(e=>e.category).filter(Boolean)}exports.copyProductFromLanguageAction=l,exports.getCategoriesWithCount=g,exports.getCategoryBySlug=_,exports.getFreemiusPricingByProductId=f,exports.getGlobalProductAttributes=d,exports.getProduct=o,exports.getProductCategories=v,exports.getProductTranslations=u,exports.getProducts=a,exports.getPublicFreemiusPricing=h,exports.triggerFreemiusSync=s,exports.triggerSingleProductSync=c,exports.updateFreemiusOverride=m;
@@ -241,11 +241,16 @@ export declare function getProductTranslations(translationGroupId: string): Prom
241
241
  }[]>;
242
242
  export declare function getGlobalProductAttributes(): Promise<any[]>;
243
243
  export declare function getFreemiusPricingByProductId(productId: string): Promise<any>;
244
- export declare function updateFreemiusOverride(pricingId: string, overrides: {
245
- override_monthly_price?: number | null;
246
- override_annual_price?: number | null;
247
- override_lifetime_price?: number | null;
248
- }): Promise<{
244
+ declare const FREEMIUS_OVERRIDE_FIELDS: readonly ["override_monthly_price", "override_annual_price", "override_lifetime_price"];
245
+ type FreemiusOverrides = Partial<Record<(typeof FREEMIUS_OVERRIDE_FIELDS)[number], number | null>>;
246
+ /**
247
+ * Save the per-plan price overrides from the CMS Freemius pricing dashboard. ADMIN-only, and the
248
+ * write goes through the service role: no RLS policy lets `authenticated` UPDATE
249
+ * `freemius_pricing` (only the Freemius sync writes it, with the service role), so the old
250
+ * cookie-client update matched zero rows while reporting success, and since 02026 revoked the
251
+ * grant it fails with "permission denied". Only the three override columns are writable here.
252
+ */
253
+ export declare function updateFreemiusOverride(pricingId: string, overrides: FreemiusOverrides): Promise<{
249
254
  success: boolean;
250
255
  error: any;
251
256
  } | {
@@ -265,3 +270,4 @@ export declare function getCategoriesWithCount(): Promise<{
265
270
  }[]>;
266
271
  export declare function getCategoryBySlug(slug: string): Promise<any>;
267
272
  export declare function getProductCategories(productId: string): Promise<any[]>;
273
+ export {};
@@ -2,6 +2,7 @@
2
2
  import { requireEcomAdmin as e } from "../../../server-actions/require-ecom-role.es.js";
3
3
  import { copyProductFromLanguage as t, getProduct as n, getProducts as r } from "../../../product-actions.es.js";
4
4
  import { syncFreemiusProductsToSupabase as i, syncSingleFreemiusProduct as a } from "../../../providers/freemius.es.js";
5
+ import "server-only";
5
6
  import { createClient as o, getServiceRoleSupabaseClient as s } from "@nextblock-cms/db/server";
6
7
  import { revalidatePath as c } from "next/cache";
7
8
  //#region src/lib/pages/cms/products/actions.ts
@@ -74,17 +75,49 @@ async function g(e) {
74
75
  if (n) throw Error(n.message);
75
76
  return t;
76
77
  }
77
- async function _(e, t) {
78
- let { error: n } = await o().from("freemius_pricing").update({
79
- ...t,
78
+ var _ = [
79
+ "override_monthly_price",
80
+ "override_annual_price",
81
+ "override_lifetime_price"
82
+ ];
83
+ async function v(t, n) {
84
+ let r;
85
+ try {
86
+ r = await e();
87
+ } catch (e) {
88
+ return {
89
+ success: !1,
90
+ error: e?.message === "Unauthorized" ? "Sign in as an administrator to change Freemius price overrides." : e?.message === "Forbidden" ? "Only administrators can change Freemius price overrides." : e?.message || "Failed to update pricing"
91
+ };
92
+ }
93
+ let i = n && typeof n == "object" ? n : {}, a = {};
94
+ for (let e of _) {
95
+ let t = i[e];
96
+ if (t !== void 0) {
97
+ if (t !== null && (typeof t != "number" || !Number.isFinite(t) || t < 0)) return {
98
+ success: !1,
99
+ error: "A price override must be empty or a number of 0 or more."
100
+ };
101
+ a[e] = t;
102
+ }
103
+ }
104
+ if (Object.keys(a).length === 0) return {
105
+ success: !1,
106
+ error: "No price override to save."
107
+ };
108
+ let { data: o, error: s } = await r.from("freemius_pricing").update({
109
+ ...a,
80
110
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
81
- }).eq("id", e);
82
- return n ? {
111
+ }).eq("id", t).select("id");
112
+ return s ? {
83
113
  success: !1,
84
- error: n.message
85
- } : (c("/cms/products"), { success: !0 });
114
+ error: s.message
115
+ } : !o || o.length === 0 ? {
116
+ success: !1,
117
+ error: "This pricing row no longer exists. Reload the page and try again."
118
+ } : (c("/cms/products"), c("/cms/products/[id]/edit", "page"), { success: !0 });
86
119
  }
87
- async function v(e) {
120
+ async function y(e) {
88
121
  let t = o(), { data: n } = await t.from("products").select("translation_group_id").eq("id", e).maybeSingle(), r = [e];
89
122
  if (n?.translation_group_id) {
90
123
  let { data: e } = await t.from("products").select("id").eq("translation_group_id", n.translation_group_id);
@@ -106,7 +139,7 @@ async function v(e) {
106
139
  }))
107
140
  }));
108
141
  }
109
- async function y() {
142
+ async function b() {
110
143
  let { data: e, error: t } = await o().from("categories").select("id, name, slug, description, created_at, name_translations, description_translations, product_categories(count)").order("name", { ascending: !0 });
111
144
  if (t) throw Error(t.message);
112
145
  return (e || []).map((e) => {
@@ -123,15 +156,15 @@ async function y() {
123
156
  };
124
157
  });
125
158
  }
126
- async function b(e) {
159
+ async function x(e) {
127
160
  let { data: t, error: n } = await o().from("categories").select("id, name, slug, description, created_at").eq("slug", e).maybeSingle();
128
161
  if (n) throw Error(n.message);
129
162
  return t;
130
163
  }
131
- async function x(e) {
164
+ async function S(e) {
132
165
  let { data: t, error: n } = await o().from("product_categories").select("category:categories(id, name, slug, description, name_translations, description_translations, created_at)").eq("product_id", e);
133
166
  if (n) throw Error(n.message);
134
167
  return (t || []).map((e) => e.category).filter(Boolean);
135
168
  }
136
169
  //#endregion
137
- export { p as copyProductFromLanguageAction, y as getCategoriesWithCount, b as getCategoryBySlug, g as getFreemiusPricingByProductId, h as getGlobalProductAttributes, u as getProduct, x as getProductCategories, m as getProductTranslations, l as getProducts, v as getPublicFreemiusPricing, d as triggerFreemiusSync, f as triggerSingleProductSync, _ as updateFreemiusOverride };
170
+ export { p as copyProductFromLanguageAction, b as getCategoriesWithCount, x as getCategoryBySlug, g as getFreemiusPricingByProductId, h as getGlobalProductAttributes, u as getProduct, S as getProductCategories, m as getProductTranslations, l as getProducts, y as getPublicFreemiusPricing, d as triggerFreemiusSync, f as triggerSingleProductSync, v as updateFreemiusOverride };
@@ -1,3 +1,3 @@
1
- "use server";const e=require("../../../../server-actions/require-ecom-role.cjs"),t=require("../../../../shared-inventory.cjs");let n=require("next/cache");function r(e){let t=[],n=[],r=``,i=!1;for(let a=0;a<e.length;a+=1){let o=e[a],s=e[a+1];if(o===`"`){i&&s===`"`?(r+=`"`,a+=1):i=!i;continue}if(o===`,`&&!i){n.push(r),r=``;continue}if((o===`
1
+ "use server";const e=require("../../../../server-actions/require-ecom-role.cjs"),t=require("../../../../shared-inventory.cjs");require("server-only");let n=require("next/cache");function r(e){let t=[],n=[],r=``,i=!1;for(let a=0;a<e.length;a+=1){let o=e[a],s=e[a+1];if(o===`"`){i&&s===`"`?(r+=`"`,a+=1):i=!i;continue}if(o===`,`&&!i){n.push(r),r=``;continue}if((o===`
2
2
  `||o===`\r`)&&!i){o===`\r`&&s===`
3
3
  `&&(a+=1),(r.length>0||n.length>0)&&(n.push(r),t.push(n)),n=[],r=``;continue}r+=o}return(r.length>0||n.length>0)&&(n.push(r),t.push(n)),t.filter(e=>e.some(e=>e.trim().length>0))}function i(e){return e.sku}async function a(r){try{let a=await e.requireEcomAdmin(),o=Math.max(0,Math.trunc(r.stock));return await t.setSharedInventoryQuantity({sku:r.sku,stock:o},a),(0,n.revalidatePath)(`/cms/products`),(0,n.revalidatePath)(`/cms/products/inventory`),{success:!0,itemKey:i(r),stock:o}}catch(e){return{success:!1,error:e instanceof Error?e.message:`Failed to update inventory.`}}}async function o(i){try{let a=await e.requireEcomAdmin(),o=r(i);if(o.length<2)return{success:!1,error:`The CSV file is empty.`};let[s,...c]=o,l=s.map(e=>e.trim().toLowerCase()),u=l.indexOf(`sku`),d=l.indexOf(`stock`);if(u===-1||d===-1)return{success:!1,error:`The CSV format is invalid. Please import a file exported from the Inventory page.`};let f=0;for(let e of c){let n=(e[u]||``).trim(),r=Number.parseInt((e[d]||``).trim(),10);if(n){if(!Number.isFinite(r)||r<0)return{success:!1,error:`Invalid stock value for SKU "${n}".`};await t.setSharedInventoryQuantity({sku:n,stock:r},a),f+=1}}let p=await t.getInventoryItems(a);return(0,n.revalidatePath)(`/cms/products`),(0,n.revalidatePath)(`/cms/products/inventory`),{success:!0,updatedCount:f,items:p}}catch(e){return{success:!1,error:e instanceof Error?e.message:`Failed to import inventory CSV.`}}}exports.importInventoryCsvAction=o,exports.updateInventoryQuantityAction=a;
@@ -1,6 +1,7 @@
1
1
  "use server";
2
2
  import { requireEcomAdmin as e } from "../../../../server-actions/require-ecom-role.es.js";
3
3
  import { getInventoryItems as t, setSharedInventoryQuantity as n } from "../../../../shared-inventory.es.js";
4
+ import "server-only";
4
5
  import { revalidatePath as r } from "next/cache";
5
6
  //#region src/lib/pages/cms/products/inventory/actions.ts
6
7
  function i(e) {
@@ -1 +1 @@
1
- const e=require("../../../../currency.cjs"),t=require("../../../../variation-utils.cjs"),n=require("../actions.cjs"),r=require("../server-actions.cjs"),i=require("../components/ProductForm.cjs"),a=require("../../payments/queries.cjs");let o=require("@nextblock-cms/utils"),s=require("react/jsx-runtime"),c=require("@nextblock-cms/db/server");async function l({mediaPickerNode:l,availableLanguagesProp:u,translationGroupId:d,targetLanguageId:f,initialData:p}){let[m,h,g,_]=await Promise.all([a.getEnabledPaymentProviders(),a.getStoreConfigStatus(),n.getGlobalProductAttributes(),(0,c.getServiceRoleSupabaseClient)().from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}).then(e=>e.data||[])]),v=(_||[]).map(t=>e.normalizeCurrencyRecord(t)),y=(g||[]).map(e=>({id:e.id,name:e.name,name_translations:e.name_translations||{},slug:e.slug,terms:(e.product_attribute_terms||[]).map(e=>({...e,value_translations:e.value_translations||{}}))})),b=u.find(e=>e.id===p?.language_id)?.code||u.find(e=>e.id===(f?parseInt(f,10):void 0))?.code||u.find(e=>e.is_default)?.code,{attributes:x,variants:S}=t.mapRawVariantRelations(p?.product_variants||[],b),C=p&&{...p,variation_attributes:p.variation_attributes||x.map(e=>({attribute_id:e.id,term_ids:e.terms.map(e=>e.id)})),variants:p.variants||S.map(e=>({...e,upc:e.upc??null,price:e.price/100,prices:Object.entries(e.prices||{}).reduce((e,[t,n])=>(e[t]=(0,o.minorUnitAmountToMajor)(n,t),e),{}),sale_price:typeof e.sale_price==`number`?e.sale_price/100:null,sale_prices:Object.entries(e.sale_prices||{}).reduce((e,[t,n])=>(e[t]=typeof n==`number`?(0,o.minorUnitAmountToMajor)(n,t):null,e),{}),main_media_id:e.main_media_id??null,main_image_url:e.image_url??null}))};return(0,s.jsx)(`div`,{className:`p-8`,children:(0,s.jsx)(i.ProductForm,{mediaPickerNode:l,availableLanguagesProp:u,globalAttributesProp:y,currenciesProp:v,translationGroupId:d,targetLanguageId:f,initialData:C,enabledProviders:m,configStatus:h,createAction:r.createProductAction})})}exports.NewProductPage=l;
1
+ const e=require("../../../../currency.cjs"),t=require("../../../../variation-utils.cjs"),n=require("../actions.cjs"),r=require("../server-actions.cjs"),i=require("../components/ProductForm.cjs"),a=require("../../payments/queries.cjs");let o=require("@nextblock-cms/utils"),s=require("react/jsx-runtime");require("server-only");let c=require("@nextblock-cms/db/server");async function l({mediaPickerNode:l,availableLanguagesProp:u,translationGroupId:d,targetLanguageId:f,initialData:p}){let[m,h,g,_]=await Promise.all([a.getEnabledPaymentProviders(),a.getStoreConfigStatus(),n.getGlobalProductAttributes(),(0,c.getServiceRoleSupabaseClient)().from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}).then(e=>e.data||[])]),v=(_||[]).map(t=>e.normalizeCurrencyRecord(t)),y=(g||[]).map(e=>({id:e.id,name:e.name,name_translations:e.name_translations||{},slug:e.slug,terms:(e.product_attribute_terms||[]).map(e=>({...e,value_translations:e.value_translations||{}}))})),b=u.find(e=>e.id===p?.language_id)?.code||u.find(e=>e.id===(f?parseInt(f,10):void 0))?.code||u.find(e=>e.is_default)?.code,{attributes:x,variants:S}=t.mapRawVariantRelations(p?.product_variants||[],b),C=p&&{...p,variation_attributes:p.variation_attributes||x.map(e=>({attribute_id:e.id,term_ids:e.terms.map(e=>e.id)})),variants:p.variants||S.map(e=>({...e,upc:e.upc??null,price:e.price/100,prices:Object.entries(e.prices||{}).reduce((e,[t,n])=>(e[t]=(0,o.minorUnitAmountToMajor)(n,t),e),{}),sale_price:typeof e.sale_price==`number`?e.sale_price/100:null,sale_prices:Object.entries(e.sale_prices||{}).reduce((e,[t,n])=>(e[t]=typeof n==`number`?(0,o.minorUnitAmountToMajor)(n,t):null,e),{}),main_media_id:e.main_media_id??null,main_image_url:e.image_url??null}))};return(0,s.jsx)(`div`,{className:`p-8`,children:(0,s.jsx)(i.ProductForm,{mediaPickerNode:l,availableLanguagesProp:u,globalAttributesProp:y,currenciesProp:v,translationGroupId:d,targetLanguageId:f,initialData:C,enabledProviders:m,configStatus:h,createAction:r.createProductAction})})}exports.NewProductPage=l;
@@ -6,6 +6,7 @@ import { ProductForm as i } from "../components/ProductForm.es.js";
6
6
  import { getEnabledPaymentProviders as a, getStoreConfigStatus as o } from "../../payments/queries.es.js";
7
7
  import { minorUnitAmountToMajor as s } from "@nextblock-cms/utils";
8
8
  import { jsx as c } from "react/jsx-runtime";
9
+ import "server-only";
9
10
  import { getServiceRoleSupabaseClient as l } from "@nextblock-cms/db/server";
10
11
  //#region src/lib/pages/cms/products/new/NewProductPage.tsx
11
12
  async function u({ mediaPickerNode: u, availableLanguagesProp: d, translationGroupId: f, targetLanguageId: p, initialData: m }) {
@@ -1 +1 @@
1
- "use server";const e=require("../../../currency.cjs"),t=require("../../../server-actions/require-ecom-role.cjs"),n=require("../../../product-actions.cjs"),r=require("./product-price-sync.cjs"),i=require("../../../freemius-coupons.cjs");let a=require("@nextblock-cms/db/server"),o=require("next/navigation"),s=require("next/cache");function c(e){return e.toLowerCase().trim().replace(/\s+/g,`-`).replace(/[^a-z0-9-]/g,``).replace(/-+/g,`-`).replace(/^-|-$/g,``)}async function l(t){let c=(0,a.createClient)(),{data:l}=await c.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),u=r.sanitizeProductFormValuesForStoreManagedCurrencies(t,(l||[]).map(t=>e.normalizeCurrencyRecord(t))),d=await n.createProduct(c,u);if(u.payment_provider===`freemius`&&d?.id)try{await i.syncProductSaleCouponToFreemius({productId:d.id,client:(0,a.getServiceRoleSupabaseClient)()})}catch(e){console.error(`Failed to sync Freemius sale coupon on create:`,e)}(0,s.revalidatePath)(`/cms/products`),(0,o.redirect)(`/cms/products`)}async function u(e,t,n,r){let i={author_id:n,meta:r,updated_at:new Date().toISOString()},a=async()=>{let{error:n}=await e.from(`product_drafts`).update(i).eq(`product_id`,t);if(n)throw Error(`Failed to save product draft: ${n.message}`)},{data:o,error:s}=await e.from(`product_drafts`).select(`id`).eq(`product_id`,t).maybeSingle();if(s)throw Error(`Failed to read product draft: ${s.message}`);if(o){await a();return}let{data:c,error:l}=await e.from(`blocks`).select(`id, page_id, post_id, product_id, language_id, block_type, content, order, created_at, updated_at`).eq(`product_id`,t).order(`order`,{ascending:!0});if(l)throw Error(`Failed to read product blocks: ${l.message}`);let{error:u}=await e.from(`product_drafts`).insert({...i,blocks:c??[],product_id:t});if(u){if(u.code===`23505`){await a();return}throw Error(`Failed to save product draft: ${u.message}`)}}async function d(t,n){let i=(0,a.createClient)(),{data:{user:o}}=await i.auth.getUser();if(!o)throw Error(`User not authenticated.`);let{data:s}=await i.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),c=r.sanitizeProductFormValuesForStoreManagedCurrencies(n,(s||[]).map(t=>e.normalizeCurrencyRecord(t)));return await u(i,t,o.id,c),{success:!0}}async function f(e){let t=(0,a.createClient)();await n.deleteProduct(t,e),(0,s.revalidatePath)(`/cms/products`)}function p(e){return Array.from(new Set(e.map(e=>e.trim()).filter(Boolean)))}async function m(e){let t=p(e);if(t.length===0)return{success:!1,error:`Select at least one product.`};let{error:n}=await(0,a.createClient)().from(`products`).delete().in(`id`,t);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products`),{success:!0,count:t.length})}async function h(e){let t=p(e);if(t.length===0)return{success:!1,error:`Select at least one product.`};let{error:n}=await(0,a.createClient)().from(`products`).update({status:`draft`,updated_at:new Date().toISOString()}).in(`id`,t);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products`),{success:!0,count:t.length})}async function g(e){let t=String(e||``).trim();if(!t)return{error:`Missing product id.`};let n=(0,a.createClient)(),{data:{user:r}}=await n.auth.getUser();if(!r)return{error:`You must be signed in to publish a product.`};let{data:i,error:o}=await n.from(`products`).update({status:`active`,updated_at:new Date().toISOString()}).eq(`id`,t).select(`slug`).single();return o||!i?{error:o?.message||`Could not publish the product.`}:((0,s.revalidatePath)(`/cms/products`),(0,s.revalidatePath)(`/cms/products/${t}/edit`),i.slug&&(0,s.revalidatePath)(`/product/${i.slug}`),{})}async function _(e){let n=await t.requireEcomStaff(),r=e.name.trim(),i=c(e.slug?.trim()||e.name);if(!r||!i)return{success:!1,error:`Attribute name is required.`};let{error:a}=await n.from(`product_attributes`).insert({name:r,slug:i});return a?{success:!1,error:a.message}:((0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function v(e){let{error:n}=await(await t.requireEcomStaff()).from(`product_attributes`).delete().eq(`id`,e);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function y(e){let n=await t.requireEcomStaff(),r=e.value.trim(),i=c(e.slug?.trim()||e.value);if(!r||!i)return{success:!1,error:`Term value is required.`};let{data:a}=await n.from(`product_attribute_terms`).select(`sort_order`).eq(`attribute_id`,e.attributeId).order(`sort_order`,{ascending:!1}).limit(1),o=typeof a?.[0]?.sort_order==`number`?a[0].sort_order+1:0,{error:l}=await n.from(`product_attribute_terms`).insert({attribute_id:e.attributeId,value:r,slug:i,sort_order:o});return l?{success:!1,error:l.message}:((0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function b(e){let n=await t.requireEcomStaff();for(let[t,r]of e.orderedTermIds.entries()){let{error:i}=await n.from(`product_attribute_terms`).update({sort_order:t,updated_at:new Date().toISOString()}).eq(`id`,r).eq(`attribute_id`,e.attributeId);if(i)return{success:!1,error:i.message}}return(0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0}}async function x(e){let n=await t.requireEcomStaff(),{error:r}=await n.from(`product_attributes`).update({name_translations:e.nameTranslations,updated_at:new Date().toISOString()}).eq(`id`,e.attributeId);if(r)return{success:!1,error:r.message};for(let t of e.termTranslations){let{error:r}=await n.from(`product_attribute_terms`).update({value_translations:t.valueTranslations,updated_at:new Date().toISOString()}).eq(`id`,t.termId).eq(`attribute_id`,e.attributeId);if(r)return{success:!1,error:r.message}}return(0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0}}async function S(e){let{error:n}=await(await t.requireEcomStaff()).from(`product_attribute_terms`).delete().eq(`id`,e);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function C(e){let n=await t.requireEcomStaff(),r=e.name.trim(),i=c(e.slug?.trim()||e.name);if(!r||!i)return{success:!1,error:`Category name is required.`};let{data:a,error:o}=await n.from(`categories`).insert({name:r,slug:i,description:e.description?.trim()||null,name_translations:e.nameTranslations||{},description_translations:e.descriptionTranslations||{}}).select().single();return o?{success:!1,error:o.message}:((0,s.revalidatePath)(`/cms/products/categories`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0,category:a})}async function w(e,n){let r=await t.requireEcomStaff(),i=n.name.trim(),a=c(n.slug?.trim()||n.name);if(!i||!a)return{success:!1,error:`Category name is required.`};let{error:o}=await r.from(`categories`).update({name:i,slug:a,description:n.description?.trim()||null,name_translations:n.nameTranslations||{},description_translations:n.descriptionTranslations||{}}).eq(`id`,e);return o?{success:!1,error:o.message}:((0,s.revalidatePath)(`/cms/products/categories`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function T(e){let{error:n}=await(await t.requireEcomStaff()).from(`categories`).delete().eq(`id`,e);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products/categories`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function E(e,r){let i=await t.requireEcomStaff();try{return await n.syncCategoriesForTranslationGroup(i,e,r),(0,s.revalidatePath)(`/cms/products`),(0,s.revalidatePath)(`/cms/products/${e}/edit`),{success:!0}}catch(e){return{success:!1,error:e.message}}}exports.bulkDeleteProductsAction=m,exports.bulkDraftProductsAction=h,exports.createCategoryAction=C,exports.createProductAction=l,exports.createProductAttributeAction=_,exports.createProductAttributeTermAction=y,exports.deleteCategoryAction=T,exports.deleteProductAction=f,exports.deleteProductAttributeAction=v,exports.deleteProductAttributeTermAction=S,exports.publishProductAction=g,exports.reorderProductAttributeTermsAction=b,exports.syncProductCategoriesAction=E,exports.updateCategoryAction=w,exports.updateProductAction=d,exports.updateProductAttributeTranslationsAction=x;
1
+ "use server";const e=require("../../../currency.cjs"),t=require("../../../server-actions/require-ecom-role.cjs"),n=require("../../../product-actions.cjs"),r=require("./product-price-sync.cjs"),i=require("../../../freemius-coupons.cjs");require("server-only");let a=require("@nextblock-cms/db/server"),o=require("next/navigation"),s=require("next/cache");function c(e){return e.toLowerCase().trim().replace(/\s+/g,`-`).replace(/[^a-z0-9-]/g,``).replace(/-+/g,`-`).replace(/^-|-$/g,``)}async function l(t){let c=(0,a.createClient)(),{data:l}=await c.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),u=r.sanitizeProductFormValuesForStoreManagedCurrencies(t,(l||[]).map(t=>e.normalizeCurrencyRecord(t))),d=await n.createProduct(c,u);if(u.payment_provider===`freemius`&&d?.id)try{await i.syncProductSaleCouponToFreemius({productId:d.id,client:(0,a.getServiceRoleSupabaseClient)()})}catch(e){console.error(`Failed to sync Freemius sale coupon on create:`,e)}(0,s.revalidatePath)(`/cms/products`),(0,o.redirect)(`/cms/products`)}async function u(e,t,n,r){let i={author_id:n,meta:r,updated_at:new Date().toISOString()},a=async()=>{let{error:n}=await e.from(`product_drafts`).update(i).eq(`product_id`,t);if(n)throw Error(`Failed to save product draft: ${n.message}`)},{data:o,error:s}=await e.from(`product_drafts`).select(`id`).eq(`product_id`,t).maybeSingle();if(s)throw Error(`Failed to read product draft: ${s.message}`);if(o){await a();return}let{data:c,error:l}=await e.from(`blocks`).select(`id, page_id, post_id, product_id, language_id, block_type, content, order, created_at, updated_at`).eq(`product_id`,t).order(`order`,{ascending:!0});if(l)throw Error(`Failed to read product blocks: ${l.message}`);let{error:u}=await e.from(`product_drafts`).insert({...i,blocks:c??[],product_id:t});if(u){if(u.code===`23505`){await a();return}throw Error(`Failed to save product draft: ${u.message}`)}}async function d(t,n){let i=(0,a.createClient)(),{data:{user:o}}=await i.auth.getUser();if(!o)throw Error(`User not authenticated.`);let{data:s}=await i.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),c=r.sanitizeProductFormValuesForStoreManagedCurrencies(n,(s||[]).map(t=>e.normalizeCurrencyRecord(t)));return await u(i,t,o.id,c),{success:!0}}async function f(e){let t=(0,a.createClient)();await n.deleteProduct(t,e),(0,s.revalidatePath)(`/cms/products`)}function p(e){return Array.from(new Set(e.map(e=>e.trim()).filter(Boolean)))}async function m(e){let t=p(e);if(t.length===0)return{success:!1,error:`Select at least one product.`};let{error:n}=await(0,a.createClient)().from(`products`).delete().in(`id`,t);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products`),{success:!0,count:t.length})}async function h(e){let t=p(e);if(t.length===0)return{success:!1,error:`Select at least one product.`};let{error:n}=await(0,a.createClient)().from(`products`).update({status:`draft`,updated_at:new Date().toISOString()}).in(`id`,t);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products`),{success:!0,count:t.length})}async function g(e){let t=String(e||``).trim();if(!t)return{error:`Missing product id.`};let n=(0,a.createClient)(),{data:{user:r}}=await n.auth.getUser();if(!r)return{error:`You must be signed in to publish a product.`};let{data:i,error:o}=await n.from(`products`).update({status:`active`,updated_at:new Date().toISOString()}).eq(`id`,t).select(`slug`).single();return o||!i?{error:o?.message||`Could not publish the product.`}:((0,s.revalidatePath)(`/cms/products`),(0,s.revalidatePath)(`/cms/products/${t}/edit`),i.slug&&(0,s.revalidatePath)(`/product/${i.slug}`),{})}async function _(e){let n=await t.requireEcomStaff(),r=e.name.trim(),i=c(e.slug?.trim()||e.name);if(!r||!i)return{success:!1,error:`Attribute name is required.`};let{error:a}=await n.from(`product_attributes`).insert({name:r,slug:i});return a?{success:!1,error:a.message}:((0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function v(e){let{error:n}=await(await t.requireEcomStaff()).from(`product_attributes`).delete().eq(`id`,e);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function y(e){let n=await t.requireEcomStaff(),r=e.value.trim(),i=c(e.slug?.trim()||e.value);if(!r||!i)return{success:!1,error:`Term value is required.`};let{data:a}=await n.from(`product_attribute_terms`).select(`sort_order`).eq(`attribute_id`,e.attributeId).order(`sort_order`,{ascending:!1}).limit(1),o=typeof a?.[0]?.sort_order==`number`?a[0].sort_order+1:0,{error:l}=await n.from(`product_attribute_terms`).insert({attribute_id:e.attributeId,value:r,slug:i,sort_order:o});return l?{success:!1,error:l.message}:((0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function b(e){let n=await t.requireEcomStaff();for(let[t,r]of e.orderedTermIds.entries()){let{error:i}=await n.from(`product_attribute_terms`).update({sort_order:t,updated_at:new Date().toISOString()}).eq(`id`,r).eq(`attribute_id`,e.attributeId);if(i)return{success:!1,error:i.message}}return(0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0}}async function x(e){let n=await t.requireEcomStaff(),{error:r}=await n.from(`product_attributes`).update({name_translations:e.nameTranslations,updated_at:new Date().toISOString()}).eq(`id`,e.attributeId);if(r)return{success:!1,error:r.message};for(let t of e.termTranslations){let{error:r}=await n.from(`product_attribute_terms`).update({value_translations:t.valueTranslations,updated_at:new Date().toISOString()}).eq(`id`,t.termId).eq(`attribute_id`,e.attributeId);if(r)return{success:!1,error:r.message}}return(0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0}}async function S(e){let{error:n}=await(await t.requireEcomStaff()).from(`product_attribute_terms`).delete().eq(`id`,e);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products/attributes`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function C(e){let n=await t.requireEcomStaff(),r=e.name.trim(),i=c(e.slug?.trim()||e.name);if(!r||!i)return{success:!1,error:`Category name is required.`};let{data:a,error:o}=await n.from(`categories`).insert({name:r,slug:i,description:e.description?.trim()||null,name_translations:e.nameTranslations||{},description_translations:e.descriptionTranslations||{}}).select().single();return o?{success:!1,error:o.message}:((0,s.revalidatePath)(`/cms/products/categories`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0,category:a})}async function w(e,n){let r=await t.requireEcomStaff(),i=n.name.trim(),a=c(n.slug?.trim()||n.name);if(!i||!a)return{success:!1,error:`Category name is required.`};let{error:o}=await r.from(`categories`).update({name:i,slug:a,description:n.description?.trim()||null,name_translations:n.nameTranslations||{},description_translations:n.descriptionTranslations||{}}).eq(`id`,e);return o?{success:!1,error:o.message}:((0,s.revalidatePath)(`/cms/products/categories`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function T(e){let{error:n}=await(await t.requireEcomStaff()).from(`categories`).delete().eq(`id`,e);return n?{success:!1,error:n.message}:((0,s.revalidatePath)(`/cms/products/categories`),(0,s.revalidatePath)(`/cms/products/new`),(0,s.revalidatePath)(`/cms/products`),{success:!0})}async function E(e,r){let i=await t.requireEcomStaff();try{return await n.syncCategoriesForTranslationGroup(i,e,r),(0,s.revalidatePath)(`/cms/products`),(0,s.revalidatePath)(`/cms/products/${e}/edit`),{success:!0}}catch(e){return{success:!1,error:e.message}}}exports.bulkDeleteProductsAction=m,exports.bulkDraftProductsAction=h,exports.createCategoryAction=C,exports.createProductAction=l,exports.createProductAttributeAction=_,exports.createProductAttributeTermAction=y,exports.deleteCategoryAction=T,exports.deleteProductAction=f,exports.deleteProductAttributeAction=v,exports.deleteProductAttributeTermAction=S,exports.publishProductAction=g,exports.reorderProductAttributeTermsAction=b,exports.syncProductCategoriesAction=E,exports.updateCategoryAction=w,exports.updateProductAction=d,exports.updateProductAttributeTranslationsAction=x;
@@ -4,6 +4,7 @@ import { requireEcomStaff as t } from "../../../server-actions/require-ecom-role
4
4
  import { createProduct as n, deleteProduct as r, syncCategoriesForTranslationGroup as i } from "../../../product-actions.es.js";
5
5
  import { sanitizeProductFormValuesForStoreManagedCurrencies as a } from "./product-price-sync.es.js";
6
6
  import { syncProductSaleCouponToFreemius as o } from "../../../freemius-coupons.es.js";
7
+ import "server-only";
7
8
  import { createClient as s, getServiceRoleSupabaseClient as c } from "@nextblock-cms/db/server";
8
9
  import { redirect as l } from "next/navigation";
9
10
  import { revalidatePath as u } from "next/cache";
@@ -1,4 +1,4 @@
1
- const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../currency.cjs"),n=require("../../../states.cjs"),r=require("../../../inventory-settings.cjs"),i=require("./server-actions.cjs"),a=require("./components/ZoneForm.cjs"),o=require("./components/RateForm.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("lucide-react"),l=require("@nextblock-cms/utils"),u=require("react/jsx-runtime"),d=require("@nextblock-cms/db/server"),f=require("@nextblock-cms/ui");async function p({searchParams:e}){let s=(0,d.getServiceRoleSupabaseClient)(),[{data:p},m,{data:h},{data:g}]=await Promise.all([s.from(`shipping_zones`).select(`
1
+ const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../currency.cjs"),n=require("../../../states.cjs"),r=require("../../../inventory-settings.cjs"),i=require("./server-actions.cjs"),a=require("./components/ZoneForm.cjs"),o=require("./components/RateForm.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("lucide-react"),l=require("@nextblock-cms/utils"),u=require("react/jsx-runtime");require("server-only");let d=require("@nextblock-cms/db/server"),f=require("@nextblock-cms/ui");async function p({searchParams:e}){let s=(0,d.getServiceRoleSupabaseClient)(),[{data:p},m,{data:h},{data:g}]=await Promise.all([s.from(`shipping_zones`).select(`
2
2
  *,
3
3
  shipping_zone_locations (*),
4
4
  shipping_zone_methods (*)
@@ -8,6 +8,7 @@ import "react";
8
8
  import { Boxes as c, Globe as l, Info as u, Trash2 as d, Truck as f } from "lucide-react";
9
9
  import { formatPrice as p } from "@nextblock-cms/utils";
10
10
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
11
+ import "server-only";
11
12
  import { getServiceRoleSupabaseClient as g } from "@nextblock-cms/db/server";
12
13
  import { Badge as _, Button as v, Card as y, CardContent as b, CardDescription as x, CardHeader as S, CardTitle as C, Tooltip as w, TooltipContent as T, TooltipProvider as E, TooltipTrigger as D } from "@nextblock-cms/ui";
13
14
  //#region src/lib/pages/cms/shipping/ShippingPage.tsx
@@ -1 +1 @@
1
- "use server";const e=require("../../../currency.cjs"),t=require("../../../countries.cjs"),n=require("../../../shipping-rate-currency.cjs"),r=require("../../../states.cjs"),i=require("../../../inventory-settings.cjs"),a=require("../../../server-actions/require-ecom-role.cjs");let o=require("@nextblock-cms/db/server"),s=require("next/navigation"),c=require("next/cache");function l(e){return Object.entries(e||{}).reduce((e,[t,n])=>{let r=t.trim().toLowerCase(),i=n.trim();return r&&i&&(e[r]=i),e},{})}async function u(e){let t=(0,o.createClient)(),{data:{user:n}}=await t.auth.getUser();if(!n)throw Error(`Unauthorized`);let{data:r}=await t.from(`profiles`).select(`role`).eq(`id`,n.id).single();if(!r||r.role!==`ADMIN`)throw Error(`Forbidden`);let a=e.getAll(`trackQuantities`).includes(`true`),l=await i.getEcommerceInventorySettings(t),{error:u}=await i.upsertEcommerceInventorySettings(t,{trackQuantities:a,enableTaxes:l.enableTaxes,taxCalculationMode:l.taxCalculationMode});if(u)throw Error(u.message);(0,c.revalidatePath)(`/cms/shipping`),(0,s.redirect)(`/cms/shipping?success=Inventory settings updated`)}function d(e){let n=new Map;for(let i of e){let e=t.normalizeCountryCode(i.country_code);if(!e)continue;let a=r.normalizeSubdivisionCode(e,i.state_code)||null,o=`${e}:${a??`*`}`;n.set(o,{country_code:e,state_code:a})}return[...n.values()]}async function f(e){let{data:t,error:n}=await e.from(`currencies`).select(`code, is_default`).eq(`is_active`,!0).order(`is_default`,{ascending:!1}).order(`code`,{ascending:!0});return n?{error:n.message}:{currencies:t||[]}}async function p(e,t,n){let r=await a.requireEcomAdmin(),i=d(n),{data:o,error:s}=await r.from(`shipping_zones`).insert({name:e,priority_order:t}).select().single();if(s||!o)return{error:s?.message||`Failed to create zone`};if(i.length>0){let e=i.map(e=>({zone_id:o.id,country_code:e.country_code,state_code:e.state_code??null})),{error:t}=await r.from(`shipping_zone_locations`).insert(e);if(t)return{error:t.message}}return(0,c.revalidatePath)(`/cms/shipping`),{success:!0}}async function m(e,t,n,r){let i=await a.requireEcomAdmin(),o=d(r),{error:s}=await i.from(`shipping_zones`).update({name:t,priority_order:n,updated_at:new Date().toISOString()}).eq(`id`,e);if(s)return{error:s.message||`Failed to update zone`};let{error:l}=await i.from(`shipping_zone_locations`).delete().eq(`zone_id`,e);if(l)return{error:`Failed to refresh locations`};if(o.length>0){let t=o.map(t=>({zone_id:e,country_code:t.country_code,state_code:t.state_code??null})),{error:n}=await i.from(`shipping_zone_locations`).insert(t);if(n)return{error:n.message}}return(0,c.revalidatePath)(`/cms/shipping`),{success:!0}}async function h(e){let{error:t}=await(await a.requireEcomAdmin()).from(`shipping_zones`).delete().eq(`id`,e);return t?{error:t.message}:((0,c.revalidatePath)(`/cms/shipping`),{success:!0})}async function g(t,r){let i=await a.requireEcomAdmin(),o=await f(i);if(`error`in o)return{error:o.error};let s=n.sanitizeShippingRateAmountMaps({currencies:o.currencies.map(t=>e.normalizeCurrencyRecord(t)),mode:r.currencyPricingMode,sourceCurrencyCode:r.sourceCurrencyCode,costAmounts:r.costAmounts,minOrderAmounts:r.minOrderAmounts,fallbackCostAmount:r.cost,fallbackMinOrderAmount:r.minOrderAmount}),{error:u}=await i.from(`shipping_zone_methods`).insert({zone_id:t,name:r.name.trim(),name_translations:l(r.nameTranslations),method_type:r.type,currency_pricing_mode:s.mode,cost_amount:s.costAmounts[s.sourceCurrencyCode],cost_amounts:s.costAmounts,cost_currency:s.sourceCurrencyCode,min_order_amount:s.minOrderAmounts[s.sourceCurrencyCode],min_order_amounts:s.minOrderAmounts});return u?{error:u.message}:((0,c.revalidatePath)(`/cms/shipping`),{success:!0})}async function _(t,r){let i=await a.requireEcomAdmin(),o=await f(i);if(`error`in o)return{error:o.error};let s=n.sanitizeShippingRateAmountMaps({currencies:o.currencies.map(t=>e.normalizeCurrencyRecord(t)),mode:r.currencyPricingMode,sourceCurrencyCode:r.sourceCurrencyCode,costAmounts:r.costAmounts,minOrderAmounts:r.minOrderAmounts,fallbackCostAmount:r.cost,fallbackMinOrderAmount:r.minOrderAmount}),{error:u}=await i.from(`shipping_zone_methods`).update({name:r.name.trim(),name_translations:l(r.nameTranslations),method_type:r.type,currency_pricing_mode:s.mode,cost_amount:s.costAmounts[s.sourceCurrencyCode],cost_amounts:s.costAmounts,cost_currency:s.sourceCurrencyCode,min_order_amount:s.minOrderAmounts[s.sourceCurrencyCode],min_order_amounts:s.minOrderAmounts,updated_at:new Date().toISOString()}).eq(`id`,t);return u?{error:u.message}:((0,c.revalidatePath)(`/cms/shipping`),{success:!0})}async function v(e){let{error:t}=await(await a.requireEcomAdmin()).from(`shipping_zone_methods`).delete().eq(`id`,e);return t?{error:t.message}:((0,c.revalidatePath)(`/cms/shipping`),{success:!0})}exports.createShippingRate=g,exports.createShippingZone=p,exports.deleteShippingRate=v,exports.deleteShippingZone=h,exports.updateInventoryTrackingAction=u,exports.updateShippingRate=_,exports.updateShippingZone=m;
1
+ "use server";const e=require("../../../currency.cjs"),t=require("../../../countries.cjs"),n=require("../../../shipping-rate-currency.cjs"),r=require("../../../states.cjs"),i=require("../../../inventory-settings.cjs"),a=require("../../../server-actions/require-ecom-role.cjs");require("server-only");let o=require("@nextblock-cms/db/server"),s=require("next/navigation"),c=require("next/cache");function l(e){return Object.entries(e||{}).reduce((e,[t,n])=>{let r=t.trim().toLowerCase(),i=n.trim();return r&&i&&(e[r]=i),e},{})}async function u(e){let t=(0,o.createClient)(),{data:{user:n}}=await t.auth.getUser();if(!n)throw Error(`Unauthorized`);let{data:r}=await t.from(`profiles`).select(`role`).eq(`id`,n.id).single();if(!r||r.role!==`ADMIN`)throw Error(`Forbidden`);let a=e.getAll(`trackQuantities`).includes(`true`),l=await i.getEcommerceInventorySettings(t),{error:u}=await i.upsertEcommerceInventorySettings(t,{trackQuantities:a,enableTaxes:l.enableTaxes,taxCalculationMode:l.taxCalculationMode});if(u)throw Error(u.message);(0,c.revalidatePath)(`/cms/shipping`),(0,s.redirect)(`/cms/shipping?success=Inventory settings updated`)}function d(e){let n=new Map;for(let i of e){let e=t.normalizeCountryCode(i.country_code);if(!e)continue;let a=r.normalizeSubdivisionCode(e,i.state_code)||null,o=`${e}:${a??`*`}`;n.set(o,{country_code:e,state_code:a})}return[...n.values()]}async function f(e){let{data:t,error:n}=await e.from(`currencies`).select(`code, is_default`).eq(`is_active`,!0).order(`is_default`,{ascending:!1}).order(`code`,{ascending:!0});return n?{error:n.message}:{currencies:t||[]}}async function p(e,t,n){let r=await a.requireEcomAdmin(),i=d(n),{data:o,error:s}=await r.from(`shipping_zones`).insert({name:e,priority_order:t}).select().single();if(s||!o)return{error:s?.message||`Failed to create zone`};if(i.length>0){let e=i.map(e=>({zone_id:o.id,country_code:e.country_code,state_code:e.state_code??null})),{error:t}=await r.from(`shipping_zone_locations`).insert(e);if(t)return{error:t.message}}return(0,c.revalidatePath)(`/cms/shipping`),{success:!0}}async function m(e,t,n,r){let i=await a.requireEcomAdmin(),o=d(r),{error:s}=await i.from(`shipping_zones`).update({name:t,priority_order:n,updated_at:new Date().toISOString()}).eq(`id`,e);if(s)return{error:s.message||`Failed to update zone`};let{error:l}=await i.from(`shipping_zone_locations`).delete().eq(`zone_id`,e);if(l)return{error:`Failed to refresh locations`};if(o.length>0){let t=o.map(t=>({zone_id:e,country_code:t.country_code,state_code:t.state_code??null})),{error:n}=await i.from(`shipping_zone_locations`).insert(t);if(n)return{error:n.message}}return(0,c.revalidatePath)(`/cms/shipping`),{success:!0}}async function h(e){let{error:t}=await(await a.requireEcomAdmin()).from(`shipping_zones`).delete().eq(`id`,e);return t?{error:t.message}:((0,c.revalidatePath)(`/cms/shipping`),{success:!0})}async function g(t,r){let i=await a.requireEcomAdmin(),o=await f(i);if(`error`in o)return{error:o.error};let s=n.sanitizeShippingRateAmountMaps({currencies:o.currencies.map(t=>e.normalizeCurrencyRecord(t)),mode:r.currencyPricingMode,sourceCurrencyCode:r.sourceCurrencyCode,costAmounts:r.costAmounts,minOrderAmounts:r.minOrderAmounts,fallbackCostAmount:r.cost,fallbackMinOrderAmount:r.minOrderAmount}),{error:u}=await i.from(`shipping_zone_methods`).insert({zone_id:t,name:r.name.trim(),name_translations:l(r.nameTranslations),method_type:r.type,currency_pricing_mode:s.mode,cost_amount:s.costAmounts[s.sourceCurrencyCode],cost_amounts:s.costAmounts,cost_currency:s.sourceCurrencyCode,min_order_amount:s.minOrderAmounts[s.sourceCurrencyCode],min_order_amounts:s.minOrderAmounts});return u?{error:u.message}:((0,c.revalidatePath)(`/cms/shipping`),{success:!0})}async function _(t,r){let i=await a.requireEcomAdmin(),o=await f(i);if(`error`in o)return{error:o.error};let s=n.sanitizeShippingRateAmountMaps({currencies:o.currencies.map(t=>e.normalizeCurrencyRecord(t)),mode:r.currencyPricingMode,sourceCurrencyCode:r.sourceCurrencyCode,costAmounts:r.costAmounts,minOrderAmounts:r.minOrderAmounts,fallbackCostAmount:r.cost,fallbackMinOrderAmount:r.minOrderAmount}),{error:u}=await i.from(`shipping_zone_methods`).update({name:r.name.trim(),name_translations:l(r.nameTranslations),method_type:r.type,currency_pricing_mode:s.mode,cost_amount:s.costAmounts[s.sourceCurrencyCode],cost_amounts:s.costAmounts,cost_currency:s.sourceCurrencyCode,min_order_amount:s.minOrderAmounts[s.sourceCurrencyCode],min_order_amounts:s.minOrderAmounts,updated_at:new Date().toISOString()}).eq(`id`,t);return u?{error:u.message}:((0,c.revalidatePath)(`/cms/shipping`),{success:!0})}async function v(e){let{error:t}=await(await a.requireEcomAdmin()).from(`shipping_zone_methods`).delete().eq(`id`,e);return t?{error:t.message}:((0,c.revalidatePath)(`/cms/shipping`),{success:!0})}exports.createShippingRate=g,exports.createShippingZone=p,exports.deleteShippingRate=v,exports.deleteShippingZone=h,exports.updateInventoryTrackingAction=u,exports.updateShippingRate=_,exports.updateShippingZone=m;
@@ -5,6 +5,7 @@ import { sanitizeShippingRateAmountMaps as n } from "../../../shipping-rate-curr
5
5
  import { normalizeSubdivisionCode as r } from "../../../states.es.js";
6
6
  import { getEcommerceInventorySettings as i, upsertEcommerceInventorySettings as a } from "../../../inventory-settings.es.js";
7
7
  import { requireEcomAdmin as o } from "../../../server-actions/require-ecom-role.es.js";
8
+ import "server-only";
8
9
  import { createClient as s } from "@nextblock-cms/db/server";
9
10
  import { redirect as c } from "next/navigation";
10
11
  import { revalidatePath as l } from "next/cache";
@@ -1 +1 @@
1
- const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../states.cjs"),n=require("../../../inventory-settings.cjs"),r=require("../payments/queries.cjs"),i=require("./actions.cjs"),a=require("./components/TaxRateForm.cjs");let o=require("next/link");o=e.__toESM(o,1);let s=require("lucide-react"),c=require("react/jsx-runtime"),l=require("@nextblock-cms/db/server"),u=require("@nextblock-cms/ui");function d(e){return`${e.toFixed(4).replace(/\.?0+$/,``)}%`}function f(e){return e.state_code?`${e.country_code} - ${t.resolveSubdivisionName(e.country_code,e.state_code)}`:`${e.country_code} - Country-wide`}async function p({searchParams:e}){let t=(0,l.createClient)(),p=(0,l.getServiceRoleSupabaseClient)(),[m,h,g]=await Promise.all([n.getEcommerceInventorySettings(t),r.getEnabledPaymentProviders(),p.from(`tax_rates`).select(`id, country_code, state_code, tax_name, tax_rate, created_at, updated_at`).order(`country_code`).order(`state_code`).order(`tax_name`)]),_=g.data||[],v=g.error,y=h.stripe;return(0,c.jsxs)(`div`,{className:`mx-auto w-full max-w-6xl space-y-6 px-6 py-8`,children:[e?.success?(0,c.jsx)(`div`,{className:`rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-700`,children:e.success}):null,(0,c.jsxs)(`div`,{className:`flex items-center justify-between gap-4`,children:[(0,c.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,c.jsx)(u.Button,{asChild:!0,variant:`outline`,size:`icon`,"aria-label":`Back to shipping`,children:(0,c.jsx)(o.default,{href:`/cms/shipping`,children:(0,c.jsx)(s.ArrowLeft,{className:`h-4 w-4`})})}),(0,c.jsxs)(`div`,{children:[(0,c.jsx)(`h1`,{className:`text-2xl font-bold`,children:`Tax Settings`}),(0,c.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Configure Stripe tax behavior globally and maintain manual country or state/province tax rates for physical goods.`})]})]}),(0,c.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,c.jsxs)(u.Badge,{variant:y?`default`:`outline`,className:`uppercase`,children:[`Stripe `,y?`Enabled`:`Disabled`]}),(0,c.jsx)(`div`,{className:`rounded-full border bg-muted/30 p-3 text-muted-foreground`,children:(0,c.jsx)(s.Settings2,{className:`h-5 w-5`})})]})]}),y?(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)(u.Card,{children:[(0,c.jsxs)(u.CardHeader,{children:[(0,c.jsx)(u.CardTitle,{children:`Global Tax Controls`}),(0,c.jsx)(u.CardDescription,{children:`Manual mode uses the tax rates below. Automatic mode uses Stripe Tax during Stripe Checkout instead of a free third-party tax API.`})]}),(0,c.jsx)(u.CardContent,{children:(0,c.jsxs)(`form`,{action:i.updateTaxSettingsAction,className:`space-y-6`,children:[(0,c.jsxs)(`div`,{className:`rounded-lg border bg-muted/20 p-4`,children:[(0,c.jsx)(`input`,{type:`hidden`,name:`enableTaxes`,value:`false`}),(0,c.jsxs)(`label`,{htmlFor:`enable-taxes`,className:`flex cursor-pointer items-start gap-3`,children:[(0,c.jsx)(`input`,{id:`enable-taxes`,name:`enableTaxes`,type:`checkbox`,value:`true`,defaultChecked:m.enableTaxes,className:`mt-1 h-4 w-4 rounded border-slate-300 text-primary focus:ring-primary`}),(0,c.jsxs)(`span`,{className:`space-y-1`,children:[(0,c.jsx)(`span`,{className:`block font-medium`,children:`Enable taxes`}),(0,c.jsx)(`span`,{className:`block text-sm text-muted-foreground`,children:`When disabled, tax totals resolve to zero even if product or jurisdiction records exist.`})]})]})]}),(0,c.jsxs)(`div`,{className:`grid gap-4 md:grid-cols-[minmax(0,1fr)_auto] md:items-end`,children:[(0,c.jsxs)(`div`,{className:`space-y-2`,children:[(0,c.jsx)(`label`,{htmlFor:`tax-calculation-mode`,className:`text-sm font-medium text-foreground`,children:`Tax calculation mode`}),(0,c.jsxs)(`select`,{id:`tax-calculation-mode`,name:`taxCalculationMode`,defaultValue:m.taxCalculationMode,className:`flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm`,children:[(0,c.jsx)(`option`,{value:`manual`,children:`Manual tax rates`}),(0,c.jsx)(`option`,{value:`automatic`,children:`Automatic via Stripe Tax`})]}),(0,c.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Automatic mode depends on your Stripe Tax setup. Manual rates stay saved and can be used again if you switch back later.`})]}),(0,c.jsx)(`div`,{className:`flex justify-end`,children:(0,c.jsx)(u.Button,{type:`submit`,children:`Save Tax Settings`})})]})]})})]}),(0,c.jsxs)(u.Card,{children:[(0,c.jsx)(u.CardHeader,{children:(0,c.jsxs)(`div`,{className:`flex items-center justify-between gap-4`,children:[(0,c.jsxs)(`div`,{children:[(0,c.jsx)(u.CardTitle,{children:`Manual Tax Rates`}),(0,c.jsx)(u.CardDescription,{children:`Add combined taxes as separate rows. For example, create both GST and PST for the same province if they should stack.`})]}),(0,c.jsx)(u.Badge,{variant:m.taxCalculationMode===`manual`?`default`:`outline`,children:m.taxCalculationMode===`manual`?`Active Mode`:`Stored for Manual Mode`})]})}),(0,c.jsxs)(u.CardContent,{className:`space-y-6`,children:[v?(0,c.jsx)(`div`,{className:`rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800`,children:`Tax rates couldn't be loaded yet. This usually means the new tax migration hasn't been applied to the current database.`}):null,v?null:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)(`div`,{className:`rounded-xl border bg-card p-4`,children:[(0,c.jsxs)(`div`,{className:`mb-4 flex items-center gap-2`,children:[(0,c.jsx)(s.ShieldCheck,{className:`h-4 w-4 text-primary`}),(0,c.jsx)(`h2`,{className:`font-semibold`,children:`Create a Tax Rate`})]}),(0,c.jsx)(a.TaxRateForm,{})]}),(0,c.jsx)(`div`,{className:`space-y-4`,children:_.length===0?(0,c.jsxs)(`div`,{className:`rounded-xl border border-dashed bg-muted/10 px-4 py-8 text-center`,children:[(0,c.jsx)(`p`,{className:`font-medium`,children:`No manual tax rates yet`}),(0,c.jsx)(`p`,{className:`mt-1 text-sm text-muted-foreground`,children:`Add country-wide or state/province-specific rows to start calculating manual taxes.`})]}):_.map(e=>(0,c.jsxs)(u.Card,{className:`border-muted`,children:[(0,c.jsx)(u.CardHeader,{className:`pb-4`,children:(0,c.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,c.jsxs)(`div`,{className:`space-y-1`,children:[(0,c.jsx)(u.CardTitle,{className:`text-base`,children:e.tax_name}),(0,c.jsx)(u.CardDescription,{children:f(e)})]}),(0,c.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,c.jsx)(u.Badge,{variant:`outline`,children:d(Number(e.tax_rate))}),(0,c.jsx)(`form`,{action:async()=>{"use server";await i.deleteTaxRateAction(e.id)},children:(0,c.jsx)(u.Button,{type:`submit`,variant:`ghost`,size:`icon`,"aria-label":`Delete tax rate`,children:(0,c.jsx)(s.Trash2,{className:`h-4 w-4`})})})]})]})}),(0,c.jsx)(u.CardContent,{children:(0,c.jsx)(a.TaxRateForm,{initialData:e,submitLabel:`Update tax rate`,compact:!0})})]},e.id))})]})]})]})]}):(0,c.jsxs)(u.Card,{className:`border-dashed`,children:[(0,c.jsxs)(u.CardHeader,{children:[(0,c.jsx)(u.CardTitle,{children:`Enable Stripe to configure physical-product taxes`}),(0,c.jsx)(u.CardDescription,{children:`Stripe tax settings apply whenever Stripe is enabled for physical products. Freemius still handles taxes on its own digital checkout flow.`})]}),(0,c.jsx)(u.CardContent,{children:(0,c.jsx)(u.Button,{asChild:!0,variant:`outline`,children:(0,c.jsx)(o.default,{href:`/cms/payments`,children:`Open Payment Settings`})})})]})]})}exports.TaxesPage=p;
1
+ const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../states.cjs"),n=require("../../../inventory-settings.cjs"),r=require("../payments/queries.cjs"),i=require("./actions.cjs"),a=require("./components/TaxRateForm.cjs");let o=require("next/link");o=e.__toESM(o,1);let s=require("lucide-react"),c=require("react/jsx-runtime");require("server-only");let l=require("@nextblock-cms/db/server"),u=require("@nextblock-cms/ui");function d(e){return`${e.toFixed(4).replace(/\.?0+$/,``)}%`}function f(e){return e.state_code?`${e.country_code} - ${t.resolveSubdivisionName(e.country_code,e.state_code)}`:`${e.country_code} - Country-wide`}async function p({searchParams:e}){let t=(0,l.createClient)(),p=(0,l.getServiceRoleSupabaseClient)(),[m,h,g]=await Promise.all([n.getEcommerceInventorySettings(t),r.getEnabledPaymentProviders(),p.from(`tax_rates`).select(`id, country_code, state_code, tax_name, tax_rate, created_at, updated_at`).order(`country_code`).order(`state_code`).order(`tax_name`)]),_=g.data||[],v=g.error,y=h.stripe;return(0,c.jsxs)(`div`,{className:`mx-auto w-full max-w-6xl space-y-6 px-6 py-8`,children:[e?.success?(0,c.jsx)(`div`,{className:`rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-700`,children:e.success}):null,(0,c.jsxs)(`div`,{className:`flex items-center justify-between gap-4`,children:[(0,c.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,c.jsx)(u.Button,{asChild:!0,variant:`outline`,size:`icon`,"aria-label":`Back to shipping`,children:(0,c.jsx)(o.default,{href:`/cms/shipping`,children:(0,c.jsx)(s.ArrowLeft,{className:`h-4 w-4`})})}),(0,c.jsxs)(`div`,{children:[(0,c.jsx)(`h1`,{className:`text-2xl font-bold`,children:`Tax Settings`}),(0,c.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Configure Stripe tax behavior globally and maintain manual country or state/province tax rates for physical goods.`})]})]}),(0,c.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,c.jsxs)(u.Badge,{variant:y?`default`:`outline`,className:`uppercase`,children:[`Stripe `,y?`Enabled`:`Disabled`]}),(0,c.jsx)(`div`,{className:`rounded-full border bg-muted/30 p-3 text-muted-foreground`,children:(0,c.jsx)(s.Settings2,{className:`h-5 w-5`})})]})]}),y?(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)(u.Card,{children:[(0,c.jsxs)(u.CardHeader,{children:[(0,c.jsx)(u.CardTitle,{children:`Global Tax Controls`}),(0,c.jsx)(u.CardDescription,{children:`Manual mode uses the tax rates below. Automatic mode uses Stripe Tax during Stripe Checkout instead of a free third-party tax API.`})]}),(0,c.jsx)(u.CardContent,{children:(0,c.jsxs)(`form`,{action:i.updateTaxSettingsAction,className:`space-y-6`,children:[(0,c.jsxs)(`div`,{className:`rounded-lg border bg-muted/20 p-4`,children:[(0,c.jsx)(`input`,{type:`hidden`,name:`enableTaxes`,value:`false`}),(0,c.jsxs)(`label`,{htmlFor:`enable-taxes`,className:`flex cursor-pointer items-start gap-3`,children:[(0,c.jsx)(`input`,{id:`enable-taxes`,name:`enableTaxes`,type:`checkbox`,value:`true`,defaultChecked:m.enableTaxes,className:`mt-1 h-4 w-4 rounded border-slate-300 text-primary focus:ring-primary`}),(0,c.jsxs)(`span`,{className:`space-y-1`,children:[(0,c.jsx)(`span`,{className:`block font-medium`,children:`Enable taxes`}),(0,c.jsx)(`span`,{className:`block text-sm text-muted-foreground`,children:`When disabled, tax totals resolve to zero even if product or jurisdiction records exist.`})]})]})]}),(0,c.jsxs)(`div`,{className:`grid gap-4 md:grid-cols-[minmax(0,1fr)_auto] md:items-end`,children:[(0,c.jsxs)(`div`,{className:`space-y-2`,children:[(0,c.jsx)(`label`,{htmlFor:`tax-calculation-mode`,className:`text-sm font-medium text-foreground`,children:`Tax calculation mode`}),(0,c.jsxs)(`select`,{id:`tax-calculation-mode`,name:`taxCalculationMode`,defaultValue:m.taxCalculationMode,className:`flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm`,children:[(0,c.jsx)(`option`,{value:`manual`,children:`Manual tax rates`}),(0,c.jsx)(`option`,{value:`automatic`,children:`Automatic via Stripe Tax`})]}),(0,c.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Automatic mode depends on your Stripe Tax setup. Manual rates stay saved and can be used again if you switch back later.`})]}),(0,c.jsx)(`div`,{className:`flex justify-end`,children:(0,c.jsx)(u.Button,{type:`submit`,children:`Save Tax Settings`})})]})]})})]}),(0,c.jsxs)(u.Card,{children:[(0,c.jsx)(u.CardHeader,{children:(0,c.jsxs)(`div`,{className:`flex items-center justify-between gap-4`,children:[(0,c.jsxs)(`div`,{children:[(0,c.jsx)(u.CardTitle,{children:`Manual Tax Rates`}),(0,c.jsx)(u.CardDescription,{children:`Add combined taxes as separate rows. For example, create both GST and PST for the same province if they should stack.`})]}),(0,c.jsx)(u.Badge,{variant:m.taxCalculationMode===`manual`?`default`:`outline`,children:m.taxCalculationMode===`manual`?`Active Mode`:`Stored for Manual Mode`})]})}),(0,c.jsxs)(u.CardContent,{className:`space-y-6`,children:[v?(0,c.jsx)(`div`,{className:`rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800`,children:`Tax rates couldn't be loaded yet. This usually means the new tax migration hasn't been applied to the current database.`}):null,v?null:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)(`div`,{className:`rounded-xl border bg-card p-4`,children:[(0,c.jsxs)(`div`,{className:`mb-4 flex items-center gap-2`,children:[(0,c.jsx)(s.ShieldCheck,{className:`h-4 w-4 text-primary`}),(0,c.jsx)(`h2`,{className:`font-semibold`,children:`Create a Tax Rate`})]}),(0,c.jsx)(a.TaxRateForm,{})]}),(0,c.jsx)(`div`,{className:`space-y-4`,children:_.length===0?(0,c.jsxs)(`div`,{className:`rounded-xl border border-dashed bg-muted/10 px-4 py-8 text-center`,children:[(0,c.jsx)(`p`,{className:`font-medium`,children:`No manual tax rates yet`}),(0,c.jsx)(`p`,{className:`mt-1 text-sm text-muted-foreground`,children:`Add country-wide or state/province-specific rows to start calculating manual taxes.`})]}):_.map(e=>(0,c.jsxs)(u.Card,{className:`border-muted`,children:[(0,c.jsx)(u.CardHeader,{className:`pb-4`,children:(0,c.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,c.jsxs)(`div`,{className:`space-y-1`,children:[(0,c.jsx)(u.CardTitle,{className:`text-base`,children:e.tax_name}),(0,c.jsx)(u.CardDescription,{children:f(e)})]}),(0,c.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,c.jsx)(u.Badge,{variant:`outline`,children:d(Number(e.tax_rate))}),(0,c.jsx)(`form`,{action:async()=>{"use server";await i.deleteTaxRateAction(e.id)},children:(0,c.jsx)(u.Button,{type:`submit`,variant:`ghost`,size:`icon`,"aria-label":`Delete tax rate`,children:(0,c.jsx)(s.Trash2,{className:`h-4 w-4`})})})]})]})}),(0,c.jsx)(u.CardContent,{children:(0,c.jsx)(a.TaxRateForm,{initialData:e,submitLabel:`Update tax rate`,compact:!0})})]},e.id))})]})]})]})]}):(0,c.jsxs)(u.Card,{className:`border-dashed`,children:[(0,c.jsxs)(u.CardHeader,{children:[(0,c.jsx)(u.CardTitle,{children:`Enable Stripe to configure physical-product taxes`}),(0,c.jsx)(u.CardDescription,{children:`Stripe tax settings apply whenever Stripe is enabled for physical products. Freemius still handles taxes on its own digital checkout flow.`})]}),(0,c.jsx)(u.CardContent,{children:(0,c.jsx)(u.Button,{asChild:!0,variant:`outline`,children:(0,c.jsx)(o.default,{href:`/cms/payments`,children:`Open Payment Settings`})})})]})]})}exports.TaxesPage=p;
@@ -6,6 +6,7 @@ import { TaxRateForm as a } from "./components/TaxRateForm.es.js";
6
6
  import o from "next/link";
7
7
  import { ArrowLeft as s, Settings2 as c, ShieldCheck as l, Trash2 as u } from "lucide-react";
8
8
  import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
9
+ import "server-only";
9
10
  import { createClient as m, getServiceRoleSupabaseClient as h } from "@nextblock-cms/db/server";
10
11
  import { Badge as g, Button as _, Card as v, CardContent as y, CardDescription as b, CardHeader as x, CardTitle as S } from "@nextblock-cms/ui";
11
12
  //#region src/lib/pages/cms/taxes/TaxesPage.tsx