@nextblock-cms/ecom 0.12.14 → 0.12.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/pages/cms/products/actions.cjs.js +4 -4
- package/lib/pages/cms/products/actions.es.js +8 -8
- package/lib/pages/cms/products/components/ProductForm.cjs.js +1 -1
- package/lib/pages/cms/products/components/ProductForm.d.ts +3 -1
- package/lib/pages/cms/products/components/ProductForm.es.js +53 -46
- package/lib/pages/cms/products/components/SyncFreemiusPricingButton.cjs.js +5 -1
- package/lib/pages/cms/products/components/SyncFreemiusPricingButton.d.ts +3 -1
- package/lib/pages/cms/products/components/SyncFreemiusPricingButton.es.js +30 -21
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("@nextblock-cms/db/server"),d=require("../../../product-actions.cjs.js"),l=require("../../../providers/freemius.cjs.js"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("@nextblock-cms/db/server"),d=require("../../../product-actions.cjs.js"),l=require("../../../providers/freemius.cjs.js"),c=require("next/cache");async function _(t){const r=o.createClient(),{data:a,count:e,error:i}=await await d.getProducts(r,{...t,status:"all"});if(i)throw new Error(i.message);return{data:a,count:e}}async function m(t){const r=o.createClient(),{data:a,error:e}=await d.getProduct(r,t);if(e)throw new Error(e.message);return a}async function p(){try{const t=await l.syncFreemiusProductsToSupabase();return c.revalidatePath("/cms/products","page"),{success:!0,data:t}}catch(t){return{error:t.message||"Failed to sync with Freemius"}}}async function g(t){try{const r=await l.syncSingleFreemiusProduct(t);return c.revalidatePath("/cms/products","page"),c.revalidatePath("/cms/products/[id]/edit","page"),{success:!0,data:r}}catch(r){return{error:r.message||"Failed to sync product with Freemius"}}}async function f(t,r){try{const a=o.createClient();return await d.copyProductFromLanguage(a,t,r),c.revalidatePath("/cms/products"),c.revalidatePath(`/cms/products/${t}/edit`),{success:!0}}catch(a){return{success:!1,error:a.message||"Failed to copy product content"}}}async function y(t){const r=o.createClient(),{data:a,error:e}=await r.from("products").select("id, title, language_id, slug").eq("translation_group_id",t);if(e)throw new Error(e.message);return a}async function w(){const t=o.getServiceRoleSupabaseClient(),{data:r,error:a}=await t.from("product_attributes").select(`
|
|
2
2
|
id,
|
|
3
3
|
name,
|
|
4
4
|
name_translations,
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
sort_order,
|
|
12
12
|
value_translations
|
|
13
13
|
)
|
|
14
|
-
`);if(a)throw new Error(a.message);return(r||[]).map(e=>({...e,product_attribute_terms:(e.product_attribute_terms||[]).sort((i,
|
|
14
|
+
`);if(a)throw new Error(a.message);return(r||[]).map(e=>({...e,product_attribute_terms:(e.product_attribute_terms||[]).sort((i,u)=>(i.sort_order??Number.MAX_SAFE_INTEGER)-(u.sort_order??Number.MAX_SAFE_INTEGER)||i.value.localeCompare(u.value))})).sort((e,i)=>e.name.localeCompare(i.name))}async function P(t){const r=o.createClient(),{data:a,error:e}=await r.from("freemius_plans").select(`
|
|
15
15
|
id,
|
|
16
16
|
name,
|
|
17
17
|
title,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
override_lifetime_price,
|
|
27
27
|
is_active
|
|
28
28
|
)
|
|
29
|
-
`).eq("product_id",t);if(e)throw new Error(e.message);return a}async function
|
|
29
|
+
`).eq("product_id",t);if(e)throw new Error(e.message);return a}async function h(t,r){const a=o.createClient(),{error:e}=await a.from("freemius_pricing").update({...r,updated_at:new Date().toISOString()}).eq("id",t);return e?{success:!1,error:e.message}:(c.revalidatePath("/cms/products"),{success:!0})}async function v(t){const r=o.createClient(),{data:a}=await r.from("products").select("translation_group_id").eq("id",t).maybeSingle();let e=[t];if(a?.translation_group_id){const{data:n}=await r.from("products").select("id").eq("translation_group_id",a.translation_group_id);n&&n.length>0&&(e=n.map(s=>s.id))}const{data:i,error:u}=await r.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",e);if(
|
|
44
|
+
`).in("product_id",e);if(u)throw new Error(u.message);return(i||[]).map(n=>({id:n.id,name:n.name,title:n.title,pricing:(n.freemius_pricing||[]).filter(s=>s.is_active!==!1).map(s=>({id:s.id,license_quota:s.license_quota,monthly_price:s.override_monthly_price??s.api_monthly_price,annual_price:s.override_annual_price??s.api_annual_price,lifetime_price:s.override_lifetime_price??s.api_lifetime_price,is_active:s.is_active}))}))}async function b(){const t=o.createClient(),{data:r,error:a}=await t.from("categories").select("id, name, slug, description, created_at, name_translations, description_translations, product_categories(count)").order("name",{ascending:!0});if(a)throw new Error(a.message);return(r||[]).map(e=>{const i=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(i),name_translations:e.name_translations||{},description_translations:e.description_translations||{}}})}async function C(t){const r=o.createClient(),{data:a,error:e}=await r.from("categories").select("id, name, slug, description, created_at").eq("slug",t).maybeSingle();if(e)throw new Error(e.message);return a}async function F(t){const r=o.createClient(),{data:a,error:e}=await r.from("product_categories").select("category:categories(id, name, slug, description, name_translations, description_translations, created_at)").eq("product_id",t);if(e)throw new Error(e.message);return(a||[]).map(i=>i.category).filter(Boolean)}exports.copyProductFromLanguageAction=f;exports.getCategoriesWithCount=b;exports.getCategoryBySlug=C;exports.getFreemiusPricingByProductId=P;exports.getGlobalProductAttributes=w;exports.getProduct=m;exports.getProductCategories=F;exports.getProductTranslations=y;exports.getProducts=_;exports.getPublicFreemiusPricing=v;exports.triggerFreemiusSync=p;exports.triggerSingleProductSync=g;exports.updateFreemiusOverride=h;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createClient as o, getServiceRoleSupabaseClient as d } from "@nextblock-cms/db/server";
|
|
3
3
|
import { getProduct as l, getProducts as _, copyProductFromLanguage as m } from "../../../product-actions.es.js";
|
|
4
4
|
import { syncSingleFreemiusProduct as p, syncFreemiusProductsToSupabase as g } from "../../../providers/freemius.es.js";
|
|
5
|
-
import { revalidatePath as
|
|
5
|
+
import { revalidatePath as c } from "next/cache";
|
|
6
6
|
async function v(r) {
|
|
7
7
|
const t = o(), { data: a, count: e, error: s } = await await _(t, { ...r, status: "all" });
|
|
8
8
|
if (s) throw new Error(s.message);
|
|
@@ -16,7 +16,7 @@ async function P(r) {
|
|
|
16
16
|
async function E() {
|
|
17
17
|
try {
|
|
18
18
|
const r = await g();
|
|
19
|
-
return
|
|
19
|
+
return c("/cms/products", "page"), { success: !0, data: r };
|
|
20
20
|
} catch (r) {
|
|
21
21
|
return { error: r.message || "Failed to sync with Freemius" };
|
|
22
22
|
}
|
|
@@ -24,7 +24,7 @@ async function E() {
|
|
|
24
24
|
async function F(r) {
|
|
25
25
|
try {
|
|
26
26
|
const t = await p(r);
|
|
27
|
-
return
|
|
27
|
+
return c("/cms/products", "page"), c("/cms/products/[id]/edit", "page"), { success: !0, data: t };
|
|
28
28
|
} catch (t) {
|
|
29
29
|
return { error: t.message || "Failed to sync product with Freemius" };
|
|
30
30
|
}
|
|
@@ -32,7 +32,7 @@ async function F(r) {
|
|
|
32
32
|
async function S(r, t) {
|
|
33
33
|
try {
|
|
34
34
|
const a = o();
|
|
35
|
-
return await m(a, r, t),
|
|
35
|
+
return await m(a, r, t), c("/cms/products"), c(`/cms/products/${r}/edit`), { success: !0 };
|
|
36
36
|
} catch (a) {
|
|
37
37
|
return { success: !1, error: a.message || "Failed to copy product content" };
|
|
38
38
|
}
|
|
@@ -62,7 +62,7 @@ async function C() {
|
|
|
62
62
|
return (t || []).map((e) => ({
|
|
63
63
|
...e,
|
|
64
64
|
product_attribute_terms: (e.product_attribute_terms || []).sort(
|
|
65
|
-
(s,
|
|
65
|
+
(s, u) => (s.sort_order ?? Number.MAX_SAFE_INTEGER) - (u.sort_order ?? Number.MAX_SAFE_INTEGER) || s.value.localeCompare(u.value)
|
|
66
66
|
)
|
|
67
67
|
})).sort((e, s) => e.name.localeCompare(s.name));
|
|
68
68
|
}
|
|
@@ -91,7 +91,7 @@ async function N(r, t) {
|
|
|
91
91
|
...t,
|
|
92
92
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
93
93
|
}).eq("id", r);
|
|
94
|
-
return e ? { success: !1, error: e.message } : (
|
|
94
|
+
return e ? { success: !1, error: e.message } : (c("/cms/products"), { success: !0 });
|
|
95
95
|
}
|
|
96
96
|
async function T(r) {
|
|
97
97
|
const t = o(), { data: a } = await t.from("products").select("translation_group_id").eq("id", r).maybeSingle();
|
|
@@ -100,7 +100,7 @@ async function T(r) {
|
|
|
100
100
|
const { data: n } = await t.from("products").select("id").eq("translation_group_id", a.translation_group_id);
|
|
101
101
|
n && n.length > 0 && (e = n.map((i) => i.id));
|
|
102
102
|
}
|
|
103
|
-
const { data: s, error:
|
|
103
|
+
const { data: s, error: u } = await t.from("freemius_plans").select(`
|
|
104
104
|
id,
|
|
105
105
|
name,
|
|
106
106
|
title,
|
|
@@ -116,7 +116,7 @@ async function T(r) {
|
|
|
116
116
|
is_active
|
|
117
117
|
)
|
|
118
118
|
`).in("product_id", e);
|
|
119
|
-
if (
|
|
119
|
+
if (u) throw new Error(u.message);
|
|
120
120
|
return (s || []).map((n) => ({
|
|
121
121
|
id: n.id,
|
|
122
122
|
name: n.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),l=require("react"),Be=require("@hookform/resolvers/zod"),L=require("lucide-react"),r=require("@nextblock-cms/ui"),Ee=require("../../../../product-schema.cjs.js"),Oe=require("react-hook-form"),ze=require("./ProductMediaManager.cjs.js"),Le=require("./SyncFreemiusPricingButton.cjs.js"),Ke=require("./VariationsEditor.cjs.js"),je=require("./CurrencyPriceFields.cjs.js"),ve=require("./SaleScheduleFields.cjs.js"),$e=require("./ProductCategorySelector.cjs.js"),H=require("../product-price-sync.cjs.js"),He=require("../../../../types.cjs.js"),Ne=require("../../../../currency.cjs.js"),K=require("@nextblock-cms/utils");function $({title:s,description:a,action:y,children:h,hideHeader:P}){return e.jsxs("section",{className:"rounded-lg border bg-card p-3 shadow-sm space-y-3",children:[!P&&e.jsxs("div",{className:"flex items-start justify-between gap-4 flex-wrap border-b border-muted/50 pb-2 mb-1",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("h2",{className:"text-sm font-bold tracking-tight",children:s}),a?e.jsx("p",{className:"text-[11px] text-muted-foreground leading-none",children:a}):null]}),y]}),e.jsx("div",{className:P?"":"pt-1",children:h})]})}function Je(s,a,y){const h=a?Number.parseInt(a,10):void 0;return s?.language_id||(Number.isFinite(h)?h:void 0)||y.find(P=>P.is_default)?.id||y[0]?.id||1}function Se(s,a,y,h,P){const k=(h.find(b=>b.is_default)??h[0])?.code||"USD",V=s?.prices&&Object.keys(s.prices).length>0?s.prices:{[k]:typeof s?.price=="number"?s.price/100:0},A=s?.sale_prices&&Object.keys(s.sale_prices).length>0?s.sale_prices:typeof s?.sale_price=="number"?{[k]:s.sale_price/100}:{},q=s?.product_type||"",F=s?.payment_provider||(s?.product_type?He.derivePaymentProviderFromProductType(s.product_type):"stripe");return{...H.sanitizeProductFormValuesForStoreManagedCurrencies({product_type:q||"physical",payment_provider:F,title:s?.title||"",slug:s?.slug||"",sku:s?.sku||"",upc:s?.upc||"",is_taxable:s?.is_taxable??!0,price:typeof s?.price=="number"?s.price/100:0,prices:V,sale_price:typeof s?.sale_price=="number"?s.sale_price/100:null,sale_prices:A,stock:s?.stock||0,meta_title:s?.meta_title||"",meta_description:s?.meta_description||"",custom_canonical:s?.custom_canonical||"",short_description:s?.short_description||"",description_json:s?.description_json||{type:"doc",content:[{type:"paragraph"}]},freemius_product_id:s?.freemius_product_id||"",freemius_plan_id:s?.freemius_plan_id||"",trial_period_days:s?.trial_period_days??0,trial_requires_payment_method:s?.trial_requires_payment_method??!1,status:s?.status||"draft",language_id:Je(s,a,y),translation_group_id:s?.translation_group_id||P||void 0,product_media:s?.product_media?.map(b=>({media_id:b.media_id}))||[],category_ids:s?.category_ids||[],variation_attributes:s?.variation_attributes||[],variants:s?.variants?.map(b=>({...b,prices:b.prices||{},sale_prices:b.sale_prices||{}}))||[]},h),product_type:q,payment_provider:F}}function Pe(s){return s?s.map(a=>({id:a.id||a.media_id,media_id:a.media_id,file_path:a.media?.file_path||a.media?.object_key||"",alt:a.media?.alt_text||"",sort_order:a.sort_order??0})).sort((a,y)=>a.sort_order-y.sort_order):[]}function Xe(s){return s.map(a=>({media_id:a.media_id}))}function Ye(s){return s.map(a=>({media_id:a.media_id,file_path:a.file_path,alt:a.alt}))}const Qe=s=>s.toString().toLowerCase().trim().replace(/\s+/g,"-").replace(/[^\w-]+/g,"").replace(/--+/g,"-").replace(/^-+/,"").replace(/-+$/,"");function We({initialData:s,isEdit:a=!1,mediaPickerNode:y,availableLanguagesProp:h,globalAttributesProp:P,currenciesProp:J,translationGroupId:k,targetLanguageId:V,freemiusDashboardNode:A,enabledProviders:q,configStatus:F,createAction:X,updateAction:b,availableCategoriesProp:we=[]}){const[T,R]=l.useState(!1),[Y,Q]=l.useState(()=>!!s?.variants?.length),u=l.useMemo(()=>J.filter(t=>t.is_active!==!1).sort((t,d)=>t.is_default!==d.is_default?t.is_default?-1:1:t.code.localeCompare(d.code)),[J]),n=l.useMemo(()=>u.find(t=>t.is_default)??u[0],[u]),U=l.useMemo(()=>H.getStoreManagedPriceCurrencyCodes(u),[u]),ae=Oe.useForm({resolver:Be.zodResolver(Ee.productSchema),defaultValues:Se(s,V,h,u,k)}),{register:o,handleSubmit:W,setValue:i,reset:ie,watch:c,setError:B,formState:{errors:g,dirtyFields:de}}=ae,le=l.useRef(!0),Z=l.useRef(null),[Ce,E]=l.useState(!1),[ce,O]=l.useState(null),[ne,ke]=l.useState(null),G=c(),oe=ae.formState.isDirty;l.useEffect(()=>{if(!a)return;if(le.current){le.current=!1,Z.current=JSON.stringify(G);return}if(!oe)return;const t=JSON.stringify(G);if(t===Z.current)return;const d=setTimeout(()=>{T||(Z.current=t,W(be)())},1e3);return()=>clearTimeout(d)},[G,a,oe,T,W]);const ue=c("title"),I=c("product_type"),x=I==="digital"?"freemius":I==="physical"?"stripe":void 0,j=I==="physical",pe=I==="digital",D=x?q[x]:!1,ee=x?F[x].hasKeys:!1,Fe=!!c("freemius_product_id"),me=Number(c("trial_period_days")||0),xe=!!c("trial_requires_payment_method"),Me=c("variants")||[],w=c("price"),M=c("sale_price"),v=c("prices")||{},C=c("sale_prices")||{},N=(Me?.length||0)>0,Ve=c("language_id"),Ie=h.find(t=>t.id===Ve)?.code||h.find(t=>t.is_default)?.code||h[0]?.code,z=l.useMemo(()=>H.resolveEditorCurrencyPriceMaps({currencies:u,prices:v,salePrices:C,fallbackPrice:w,fallbackSalePrice:M}),[w,M,u,v,C]),Ae=l.useMemo(()=>s?.variants?.map(t=>({...t,prices:t.prices||{},sale_prices:t.sale_prices||{}})),[s?.variants]);l.useEffect(()=>{if(de.title&&!a){const t=Qe(ue);i("slug",t,{shouldValidate:!0})}},[ue,de.title,i,a]);const[se,he]=l.useState(()=>Pe(s?.product_media)),[te,ge]=l.useState(new Set);l.useEffect(()=>{ie(Se(s,V,h,u,k)),he(Pe(s?.product_media)),ge(new Set),Q(!!s?.variants?.length)},[h,u,s,ie,V,k]);const qe=t=>{const d=new Set(t.map(m=>m.id)),p=se.filter(m=>!d.has(m.id)),f=new Set(te);p.forEach(m=>{m.media_id&&f.add(m.media_id)}),ge(f),he(t),i("product_media",Xe(t),{shouldDirty:!0}),i("explicitly_removed_media_ids",Array.from(f),{shouldDirty:!0})};l.useEffect(()=>{i("explicitly_removed_media_ids",Array.from(te))},[te,i]),l.useEffect(()=>{N&&Q(!0)},[N]),l.useEffect(()=>{o("is_taxable"),o("price"),o("sale_price"),o("payment_provider"),o("trial_requires_payment_method")},[o]),l.useEffect(()=>{if(!pe){i("trial_period_days",0,{shouldDirty:!1,shouldValidate:!0}),i("trial_requires_payment_method",!1,{shouldDirty:!1,shouldValidate:!0});return}me<=0&&i("trial_requires_payment_method",!1,{shouldDirty:!1,shouldValidate:!0})},[pe,i,me]),l.useEffect(()=>{x&&i("payment_provider",x,{shouldDirty:!1,shouldValidate:!0})},[x,i]),l.useEffect(()=>{n&&v[n.code]===void 0&&i("prices",{...v,[n.code]:w||0},{shouldDirty:!1})},[w,n,v,i]);const fe=l.useCallback((t,d)=>{const p={...v,[t]:d};i("prices",p,{shouldDirty:!0,shouldValidate:!0}),t===n?.code&&i("price",d,{shouldDirty:!0,shouldValidate:!0})},[n?.code,v,i]),_e=l.useCallback((t,d)=>{const p={...C,[t]:d};i("sale_prices",p,{shouldDirty:!0,shouldValidate:!0}),t===n?.code&&i("sale_price",d,{shouldDirty:!0,shouldValidate:!0})},[n?.code,C,i]),ye=l.useCallback(()=>{if(!n)return;const t=new Set(U),d=v[n.code]??w??0,p=C[n.code]??M??null,f=u.reduce((S,_)=>{if(_.code!==n.code&&t.has(_.code))return S;const re=Ne.convertMinorUnitAmount({amount:K.majorUnitAmountToMinor(d,n.code),fromCurrencyCode:n.code,toCurrencyCode:_.code,currencies:u,applyRounding:!0});return S[_.code]=K.minorUnitAmountToMajor(re,_.code),S},{}),m=u.reduce((S,_)=>{if(_.code!==n.code&&t.has(_.code))return S;if(typeof p!="number")return(_.code===n.code||!t.has(_.code))&&(S[_.code]=null),S;const re=Ne.convertMinorUnitAmount({amount:K.majorUnitAmountToMinor(p,n.code),fromCurrencyCode:n.code,toCurrencyCode:_.code,currencies:u,applyRounding:!0});return S[_.code]=K.minorUnitAmountToMajor(re,_.code),S},{});i("prices",f,{shouldDirty:!0,shouldValidate:!0}),i("sale_prices",m,{shouldDirty:!0,shouldValidate:!0}),i("price",f[n.code]??d,{shouldDirty:!0,shouldValidate:!0}),i("sale_price",m[n.code]??null,{shouldDirty:!0,shouldValidate:!0})},[u,n,v,C,i,U,w,M]),Te=l.useCallback(({variationAttributes:t,variants:d})=>{i("variation_attributes",t,{shouldDirty:!0}),i("variants",d,{shouldDirty:!0,shouldValidate:!0})},[i]),be=async t=>{R(!0),E(!0),O(null);try{if(!x){const m="Select whether this product is physical or digital before saving.";B("product_type",{type:"manual",message:m}),a?O(m):alert(m),R(!1),E(!1);return}if(t.status==="active"&&(!D||!ee)){const m=`${x==="stripe"?"Stripe":"Freemius"} must be enabled and fully configured before this product can be published.`;B("product_type",{type:"manual",message:m}),a?O(m):alert(m),R(!1),E(!1);return}const d=j?0:Math.max(0,Number(t.trial_period_days||0)),p={...t,product_type:t.product_type,payment_provider:x,freemius_product_id:j?"":t.freemius_product_id,freemius_plan_id:j?"":t.freemius_plan_id,trial_period_days:d,trial_requires_payment_method:!j&&d>0?t.trial_requires_payment_method:!1,upc:j?t.upc:null,is_taxable:j?t.is_taxable:!1,variation_attributes:j?t.variation_attributes:[],variants:j?t.variants:[]},f=H.sanitizeProductFormValuesForStoreManagedCurrencies(p,u);if(a&&b)await b(f),ke(new Date);else if(X)await X(f);else throw new Error("Product form action is not configured.")}catch(d){if(console.error(d),d.message==="NEXT_REDIRECT")return;let p=d.message||"An error occurred while saving.";if(d.code==="23505"){const f=d.message?.toLowerCase()||"";f.includes("products_slug_key")||f.includes("slug")?(p="This slug is already in use. Please choose another one.",B("slug",{type:"manual",message:p})):(f.includes("products_sku_key")||f.includes("sku"))&&(p="This SKU is already in use.",B("sku",{type:"manual",message:p}))}a?O(p):alert(p)}finally{R(!1),E(!1)}},Re=N?"bg-muted/60 text-muted-foreground opacity-70":"",Ue=Ye(se);return e.jsxs("form",{onSubmit:W(be),className:"space-y-2.5 pb-4",children:[e.jsx("input",{type:"hidden",...o("translation_group_id")}),e.jsx("input",{type:"hidden",...o("payment_provider")}),e.jsxs("div",{className:"space-y-2.5 w-full",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-2.5 px-4 shadow-sm flex items-center justify-between gap-3 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-6",children:[e.jsxs("div",{className:"flex h-9 items-center gap-2",children:[e.jsx("span",{className:"text-sm font-bold whitespace-nowrap leading-none pt-0.5",children:"Product Type"}),g.product_type&&e.jsx(L.AlertCircle,{className:"h-4 w-4 text-destructive"})]}),e.jsx("div",{className:"flex h-9 items-center",children:e.jsxs(r.Select,{onValueChange:t=>i("product_type",t,{shouldDirty:!0,shouldValidate:!0}),value:I||void 0,children:[e.jsx(r.SelectTrigger,{className:"w-[160px] h-9 text-xs",children:e.jsx(r.SelectValue,{placeholder:"Select Type"})}),e.jsxs(r.SelectContent,{children:[e.jsx(r.SelectItem,{value:"physical",children:"Physical Product"}),e.jsx(r.SelectItem,{value:"digital",children:"Digital Product"})]})]})})]}),e.jsxs("div",{className:"flex items-center gap-6",children:[e.jsxs("div",{className:"flex h-9 items-center gap-3",children:[e.jsx("span",{className:"text-[11px] font-semibold text-muted-foreground uppercase tracking-wider leading-none",children:"Payment Provider"}),e.jsx(r.Badge,{variant:"outline",className:"text-xs py-1 font-bold bg-muted/30 leading-none",children:x?x==="stripe"?"Stripe":"Freemius":"—"})]}),x&&e.jsx("div",{className:"flex h-9 items-center gap-2",children:D&&ee?e.jsxs("span",{className:"flex items-center gap-1.5 text-emerald-600 text-[10px] font-bold bg-emerald-50 px-2 py-1 rounded-full border border-emerald-100 uppercase leading-none",children:[e.jsx(L.CheckCircle2,{className:"h-3 w-3"}),"Ready"]}):e.jsxs("span",{className:"flex items-center gap-1.5 text-amber-600 text-[10px] font-bold bg-amber-50 px-2 py-1 rounded-full border border-amber-100 uppercase leading-none",children:[e.jsx(L.AlertCircle,{className:"h-3 w-3"}),D?"Keys Missing":"Disabled"]})}),!ee&&x&&F[x].missing.length>0&&e.jsxs("div",{className:"hidden xl:flex h-9 items-center gap-1 text-[10px] text-muted-foreground bg-muted/50 px-2 py-1 rounded border border-dashed leading-none",children:[e.jsx(L.Info,{className:"h-3 w-3"}),"Missing: ",F[x].missing.join(", ")]})]})]}),e.jsxs($,{title:"Product Information",hideHeader:!0,children:[a&&e.jsxs("div",{className:"flex items-center justify-between text-xs text-muted-foreground pb-2 border-b border-border/40 mb-2.5",children:[e.jsx("span",{className:"font-semibold text-[11px] uppercase tracking-wider text-muted-foreground/80",children:"Product Settings"}),e.jsx("div",{className:"flex items-center gap-1.5 min-h-[16px]",children:Ce?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping absolute inline-flex h-full w-full rounded-full bg-amber-400 opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-amber-500"})]}),e.jsx("span",{className:"text-amber-600 dark:text-amber-400 font-medium",children:"Autosaving settings..."})]}):ce?e.jsxs("span",{className:"text-red-500 font-medium",children:["Error saving settings: ",ce]}):ne?e.jsxs("span",{className:"text-emerald-600 dark:text-emerald-400 font-medium",children:["Settings autosaved at ",ne.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})]}):e.jsx("span",{className:"text-muted-foreground/60",children:"Settings autosave in draft mode"})})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-2.5",children:[e.jsxs("div",{className:"col-span-2 space-y-1",children:[e.jsx(r.Label,{htmlFor:"title",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Title"}),e.jsx(r.Input,{id:"title",placeholder:"Product title",...o("title"),className:"h-8 text-sm"}),g.title&&e.jsx("p",{className:"text-destructive text-[11px] leading-none",children:g.title.message})]}),e.jsxs("div",{className:"col-span-2 space-y-1",children:[e.jsx(r.Label,{htmlFor:"slug",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Slug"}),e.jsx(r.Input,{id:"slug",placeholder:"product-slug",...o("slug"),className:"h-8 text-sm"}),g.slug&&e.jsx("p",{className:"text-destructive text-[11px] leading-none",children:g.slug.message})]}),e.jsxs("div",{className:"col-span-1 space-y-1",children:[e.jsx(r.Label,{htmlFor:"sku",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"SKU"}),e.jsx(r.Input,{id:"sku",placeholder:"SKU",...o("sku"),className:"h-8 text-sm font-mono"}),g.sku&&e.jsx("p",{className:"text-destructive text-[11px] leading-none",children:g.sku.message})]}),e.jsxs("div",{className:"col-span-1 space-y-1",children:[e.jsx(r.Label,{htmlFor:"upc_ean",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"UPC / EAN"}),e.jsx(r.Input,{id:"upc_ean",placeholder:"000000000",...o("upc"),className:"h-8 text-sm font-mono",readOnly:N})]})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-12 gap-2.5 mt-2",children:[e.jsxs("div",{className:`${a?"lg:col-span-3":"lg:col-span-4"} col-span-2 space-y-1`,children:[e.jsx(r.Label,{htmlFor:"meta_title",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Meta Title"}),e.jsx(r.Input,{id:"meta_title",...o("meta_title"),placeholder:"SEO page title (50-60 chars)",className:"h-8 text-sm"})]}),e.jsxs("div",{className:"lg:col-span-4 col-span-2 space-y-1",children:[e.jsx(r.Label,{htmlFor:"meta_description",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Meta Description"}),e.jsx(r.Input,{id:"meta_description",...o("meta_description"),placeholder:"SEO description (150-160 chars)",className:"h-8 text-sm"})]}),e.jsxs("div",{className:`${a?"lg:col-span-3":"lg:col-span-4"} col-span-2 space-y-1`,children:[e.jsx(r.Label,{htmlFor:"custom_canonical",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Canonical URL (optional)"}),e.jsx(r.Input,{id:"custom_canonical",...o("custom_canonical"),placeholder:"Blank = self-referencing. Absolute https://… URL or /relative path to override.",className:"h-8 text-sm"})]}),a&&e.jsxs("div",{className:"lg:col-span-2 col-span-2 space-y-1",children:[e.jsx(r.Label,{htmlFor:"status",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Status"}),e.jsxs(r.Select,{onValueChange:t=>i("status",t,{shouldDirty:!0}),value:c("status"),children:[e.jsx(r.SelectTrigger,{className:"h-8 text-xs",children:e.jsx(r.SelectValue,{placeholder:"Status"})}),e.jsxs(r.SelectContent,{children:[e.jsx(r.SelectItem,{value:"draft",children:"Draft"}),e.jsx(r.SelectItem,{value:"active",children:"Active"}),e.jsx(r.SelectItem,{value:"archived",children:"Archived"})]})]})]})]})]}),e.jsx($,{title:"Product Categories",description:"Assign this product to one or more categories.",children:e.jsx($e.ProductCategorySelector,{categories:we,selectedIds:c("category_ids")||[],onChange:t=>i("category_ids",t,{shouldDirty:!0,shouldValidate:!0})})}),e.jsxs("section",{className:"rounded-lg border bg-card p-3 shadow-sm space-y-3",children:[j&&e.jsxs("div",{className:"flex items-center justify-between gap-4 flex-wrap border-b border-muted/50 pb-2",children:[e.jsx("div",{className:"flex items-center gap-4",children:e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("h2",{className:"text-sm font-bold tracking-tight",children:"Pricing & Inventory"}),e.jsx("p",{className:"text-[11px] text-muted-foreground leading-none",children:"Manage simple or variant pricing."})]})}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2 bg-muted/40 rounded-md px-2.5 py-1.5",children:[e.jsx("span",{className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Stock"}),e.jsx(r.Input,{id:"stock",type:"number",min:"0",...o("stock",{valueAsNumber:!0}),placeholder:"0",readOnly:N,className:`${Re} h-8 w-20 text-sm text-center font-mono bg-background`})]}),N?e.jsx(r.Badge,{variant:"secondary",className:"text-[11px] py-0 px-2 h-5",children:"Variant pricing"}):null]})]}),j?e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"w-full",children:[e.jsx(je.CurrencyPriceFields,{idPrefix:"product",currencies:u,prices:z.prices,salePrices:z.salePrices,managedCurrencyCodes:U,onPriceChange:fe,onSalePriceChange:_e,onAutoFill:ye,readOnly:N,helperText:N?"Parent prices stay as a fallback, but active variants define the live shopper price.":void 0,trailing:e.jsx(ve.SaleScheduleFields,{idPrefix:"product",startAt:c("sale_start_at"),endAt:c("sale_end_at"),onChange:(t,d)=>i(t,d,{shouldDirty:!0,shouldValidate:!0}),error:g.sale_end_at?.message,bare:!0})}),g.price&&e.jsx("p",{className:"text-destructive text-sm mt-1",children:g.price.message}),g.sale_price&&e.jsx("p",{className:"text-destructive text-sm mt-1",children:g.sale_price.message}),g.stock&&e.jsx("p",{className:"text-destructive text-[10px] font-medium leading-none mt-1",children:g.stock.message})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3 rounded border border-dashed p-2.5 bg-muted/5",children:[e.jsx("span",{className:"text-xs font-bold uppercase tracking-wider text-muted-foreground",children:N?"Variations Active":"Variations"}),e.jsx(r.Button,{type:"button",variant:Y?"outline":"default",onClick:()=>Q(t=>!t),size:"sm",className:"h-7 text-xs px-3",children:Y?"Hide":"Manage"})]}),Y&&e.jsx("div",{className:"border-t pt-3",children:e.jsx(Ke.VariationsEditor,{globalAttributes:P,currentLanguageCode:Ie,baseSku:c("sku")||"",basePrice:w||0,basePrices:v,baseSalePrice:typeof M=="number"?M:null,baseSalePrices:C,currencies:u,availableVariantImages:Ue,initialVariationAttributes:s?.variation_attributes,initialVariants:Ae,onChange:Te})})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-end gap-4 w-full",children:[e.jsxs("div",{className:"flex-1",children:[e.jsx(r.Label,{htmlFor:"freemius_product_id",className:"text-[11px] uppercase tracking-wider text-muted-foreground font-bold mb-1.5 block",children:"Freemius Product ID"}),e.jsx(r.Input,{id:"freemius_product_id",...o("freemius_product_id"),className:"h-9"})]}),e.jsxs("div",{className:"flex-1",children:[e.jsx(r.Label,{htmlFor:"freemius_plan_id",className:"text-[11px] uppercase tracking-wider text-muted-foreground font-bold mb-1.5 block",children:"Freemius Plan ID"}),e.jsx(r.Input,{id:"freemius_plan_id",...o("freemius_plan_id"),className:"h-9"})]}),Fe?e.jsx(Le.SyncFreemiusPricingButton,{productId:c("freemius_product_id")}):null]}),e.jsxs("div",{className:"bg-muted/10 border rounded-md overflow-hidden",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-6 bg-muted/20 border-b p-2.5 px-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-[11px] font-bold uppercase tracking-wider text-muted-foreground",children:"Free Trial"}),e.jsxs(r.Badge,{variant:"outline",className:"font-mono text-xs shadow-sm bg-background",children:[String(c("trial_period_days")||0)," Days"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-[11px] font-bold uppercase tracking-wider text-muted-foreground",children:"Card Required"}),e.jsx(r.Badge,{variant:xe?"default":"secondary",className:"text-xs shadow-sm",children:xe?"Yes":"No"})]}),e.jsx("span",{className:"text-[10px] text-muted-foreground ml-auto",children:"Managed in Freemius dashboard"}),e.jsx("input",{type:"hidden",...o("trial_period_days",{valueAsNumber:!0})})]}),e.jsxs("div",{className:"w-full p-4 pt-3 space-y-2",children:[e.jsx(je.CurrencyPriceFields,{idPrefix:"product",currencies:u,prices:z.prices,salePrices:z.salePrices,managedCurrencyCodes:U,onPriceChange:fe,onSalePriceChange:_e,onAutoFill:ye,readOnly:!0,trailing:e.jsx(ve.SaleScheduleFields,{idPrefix:"product",startAt:c("sale_start_at"),endAt:c("sale_end_at"),onChange:(t,d)=>i(t,d,{shouldDirty:!0,shouldValidate:!0}),error:g.sale_end_at?.message,bare:!0})}),e.jsx("p",{className:"text-[10px] leading-snug text-muted-foreground",children:"Scheduling a sale on a Freemius product generates a time-bounded Freemius coupon so the discount is enforced at Freemius checkout."})]})]})]}),A&&e.jsx("div",{className:"pt-2 border-t",children:A})]})]}),e.jsx($,{title:"Product Description",hideHeader:!0,children:e.jsx("div",{className:"space-y-2",children:e.jsxs("div",{className:"space-y-1",children:[e.jsx(r.Label,{htmlFor:"short_description",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Short Description"}),e.jsx(r.Input,{id:"short_description",...o("short_description"),placeholder:"Brief summary for product cards...",className:"h-8 text-sm"})]})})}),e.jsxs($,{title:"Media Gallery",description:"Drag to reorder. First image is the hero.",children:[e.jsx(ze.ProductMediaManager,{initialMedia:se,onUpdate:qe,mediaPickerNode:y}),e.jsx("input",{type:"hidden",...o("product_media")})]}),!a&&e.jsxs("div",{className:"rounded-lg border bg-card p-3 px-4 shadow-sm flex items-center justify-between gap-3 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Status"}),e.jsxs(r.Select,{onValueChange:t=>i("status",t),value:c("status"),children:[e.jsx(r.SelectTrigger,{className:"h-8 w-[110px] text-sm",children:e.jsx(r.SelectValue,{placeholder:"Status"})}),e.jsxs(r.SelectContent,{children:[e.jsx(r.SelectItem,{value:"draft",children:"Draft"}),e.jsx(r.SelectItem,{value:"active",children:"Active"}),e.jsx(r.SelectItem,{value:"archived",children:"Archived"})]})]})]}),e.jsx(r.Button,{disabled:T,type:"submit",size:"sm",className:"h-8 text-sm px-5",children:T?"Saving...":"Save Changes"})]})]})]})}exports.ProductForm=We;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),l=require("react"),Ee=require("@hookform/resolvers/zod"),L=require("lucide-react"),r=require("@nextblock-cms/ui"),Oe=require("../../../../product-schema.cjs.js"),ze=require("react-hook-form"),Le=require("./ProductMediaManager.cjs.js"),Ke=require("./SyncFreemiusPricingButton.cjs.js"),$e=require("./VariationsEditor.cjs.js"),je=require("./CurrencyPriceFields.cjs.js"),ve=require("./SaleScheduleFields.cjs.js"),He=require("./ProductCategorySelector.cjs.js"),H=require("../product-price-sync.cjs.js"),Je=require("../../../../types.cjs.js"),Ne=require("../../../../currency.cjs.js"),K=require("@nextblock-cms/utils");function $({title:s,description:a,action:y,children:h,hideHeader:P}){return e.jsxs("section",{className:"rounded-lg border bg-card p-3 shadow-sm space-y-3",children:[!P&&e.jsxs("div",{className:"flex items-start justify-between gap-4 flex-wrap border-b border-muted/50 pb-2 mb-1",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("h2",{className:"text-sm font-bold tracking-tight",children:s}),a?e.jsx("p",{className:"text-[11px] text-muted-foreground leading-none",children:a}):null]}),y]}),e.jsx("div",{className:P?"":"pt-1",children:h})]})}function Xe(s,a,y){const h=a?Number.parseInt(a,10):void 0;return s?.language_id||(Number.isFinite(h)?h:void 0)||y.find(P=>P.is_default)?.id||y[0]?.id||1}function Se(s,a,y,h,P){const k=(h.find(b=>b.is_default)??h[0])?.code||"USD",V=s?.prices&&Object.keys(s.prices).length>0?s.prices:{[k]:typeof s?.price=="number"?s.price/100:0},A=s?.sale_prices&&Object.keys(s.sale_prices).length>0?s.sale_prices:typeof s?.sale_price=="number"?{[k]:s.sale_price/100}:{},q=s?.product_type||"",F=s?.payment_provider||(s?.product_type?Je.derivePaymentProviderFromProductType(s.product_type):"stripe");return{...H.sanitizeProductFormValuesForStoreManagedCurrencies({product_type:q||"physical",payment_provider:F,title:s?.title||"",slug:s?.slug||"",sku:s?.sku||"",upc:s?.upc||"",is_taxable:s?.is_taxable??!0,price:typeof s?.price=="number"?s.price/100:0,prices:V,sale_price:typeof s?.sale_price=="number"?s.sale_price/100:null,sale_prices:A,stock:s?.stock||0,meta_title:s?.meta_title||"",meta_description:s?.meta_description||"",custom_canonical:s?.custom_canonical||"",short_description:s?.short_description||"",description_json:s?.description_json||{type:"doc",content:[{type:"paragraph"}]},freemius_product_id:s?.freemius_product_id||"",freemius_plan_id:s?.freemius_plan_id||"",trial_period_days:s?.trial_period_days??0,trial_requires_payment_method:s?.trial_requires_payment_method??!1,status:s?.status||"draft",language_id:Xe(s,a,y),translation_group_id:s?.translation_group_id||P||void 0,product_media:s?.product_media?.map(b=>({media_id:b.media_id}))||[],category_ids:s?.category_ids||[],variation_attributes:s?.variation_attributes||[],variants:s?.variants?.map(b=>({...b,prices:b.prices||{},sale_prices:b.sale_prices||{}}))||[]},h),product_type:q,payment_provider:F}}function Pe(s){return s?s.map(a=>({id:a.id||a.media_id,media_id:a.media_id,file_path:a.media?.file_path||a.media?.object_key||"",alt:a.media?.alt_text||"",sort_order:a.sort_order??0})).sort((a,y)=>a.sort_order-y.sort_order):[]}function Ye(s){return s.map(a=>({media_id:a.media_id}))}function Qe(s){return s.map(a=>({media_id:a.media_id,file_path:a.file_path,alt:a.alt}))}const We=s=>s.toString().toLowerCase().trim().replace(/\s+/g,"-").replace(/[^\w-]+/g,"").replace(/--+/g,"-").replace(/^-+/,"").replace(/-+$/,"");function Ze({initialData:s,isEdit:a=!1,mediaPickerNode:y,availableLanguagesProp:h,globalAttributesProp:P,currenciesProp:J,translationGroupId:k,targetLanguageId:V,freemiusDashboardNode:A,enabledProviders:q,configStatus:F,createAction:X,updateAction:b,availableCategoriesProp:we=[],hasOpenDraft:Ce=!1}){const[T,R]=l.useState(!1),[Y,Q]=l.useState(()=>!!s?.variants?.length),u=l.useMemo(()=>J.filter(t=>t.is_active!==!1).sort((t,d)=>t.is_default!==d.is_default?t.is_default?-1:1:t.code.localeCompare(d.code)),[J]),n=l.useMemo(()=>u.find(t=>t.is_default)??u[0],[u]),U=l.useMemo(()=>H.getStoreManagedPriceCurrencyCodes(u),[u]),ae=ze.useForm({resolver:Ee.zodResolver(Oe.productSchema),defaultValues:Se(s,V,h,u,k)}),{register:o,handleSubmit:W,setValue:i,reset:ie,watch:c,setError:B,formState:{errors:g,dirtyFields:de}}=ae,le=l.useRef(!0),Z=l.useRef(null),[ke,E]=l.useState(!1),[ce,O]=l.useState(null),[ne,Fe]=l.useState(null),G=c(),oe=ae.formState.isDirty;l.useEffect(()=>{if(!a)return;if(le.current){le.current=!1,Z.current=JSON.stringify(G);return}if(!oe)return;const t=JSON.stringify(G);if(t===Z.current)return;const d=setTimeout(()=>{T||(Z.current=t,W(be)())},400);return()=>clearTimeout(d)},[G,a,oe,T,W]);const ue=c("title"),I=c("product_type"),x=I==="digital"?"freemius":I==="physical"?"stripe":void 0,j=I==="physical",pe=I==="digital",D=x?q[x]:!1,ee=x?F[x].hasKeys:!1,Me=!!c("freemius_product_id"),me=Number(c("trial_period_days")||0),xe=!!c("trial_requires_payment_method"),Ve=c("variants")||[],w=c("price"),M=c("sale_price"),v=c("prices")||{},C=c("sale_prices")||{},N=(Ve?.length||0)>0,Ie=c("language_id"),Ae=h.find(t=>t.id===Ie)?.code||h.find(t=>t.is_default)?.code||h[0]?.code,z=l.useMemo(()=>H.resolveEditorCurrencyPriceMaps({currencies:u,prices:v,salePrices:C,fallbackPrice:w,fallbackSalePrice:M}),[w,M,u,v,C]),qe=l.useMemo(()=>s?.variants?.map(t=>({...t,prices:t.prices||{},sale_prices:t.sale_prices||{}})),[s?.variants]);l.useEffect(()=>{if(de.title&&!a){const t=We(ue);i("slug",t,{shouldValidate:!0})}},[ue,de.title,i,a]);const[se,he]=l.useState(()=>Pe(s?.product_media)),[te,ge]=l.useState(new Set);l.useEffect(()=>{ie(Se(s,V,h,u,k)),he(Pe(s?.product_media)),ge(new Set),Q(!!s?.variants?.length)},[h,u,s,ie,V,k]);const Te=t=>{const d=new Set(t.map(m=>m.id)),p=se.filter(m=>!d.has(m.id)),f=new Set(te);p.forEach(m=>{m.media_id&&f.add(m.media_id)}),ge(f),he(t),i("product_media",Ye(t),{shouldDirty:!0}),i("explicitly_removed_media_ids",Array.from(f),{shouldDirty:!0})};l.useEffect(()=>{i("explicitly_removed_media_ids",Array.from(te))},[te,i]),l.useEffect(()=>{N&&Q(!0)},[N]),l.useEffect(()=>{o("is_taxable"),o("price"),o("sale_price"),o("payment_provider"),o("trial_requires_payment_method")},[o]),l.useEffect(()=>{if(!pe){i("trial_period_days",0,{shouldDirty:!1,shouldValidate:!0}),i("trial_requires_payment_method",!1,{shouldDirty:!1,shouldValidate:!0});return}me<=0&&i("trial_requires_payment_method",!1,{shouldDirty:!1,shouldValidate:!0})},[pe,i,me]),l.useEffect(()=>{x&&i("payment_provider",x,{shouldDirty:!1,shouldValidate:!0})},[x,i]),l.useEffect(()=>{n&&v[n.code]===void 0&&i("prices",{...v,[n.code]:w||0},{shouldDirty:!1})},[w,n,v,i]);const fe=l.useCallback((t,d)=>{const p={...v,[t]:d};i("prices",p,{shouldDirty:!0,shouldValidate:!0}),t===n?.code&&i("price",d,{shouldDirty:!0,shouldValidate:!0})},[n?.code,v,i]),_e=l.useCallback((t,d)=>{const p={...C,[t]:d};i("sale_prices",p,{shouldDirty:!0,shouldValidate:!0}),t===n?.code&&i("sale_price",d,{shouldDirty:!0,shouldValidate:!0})},[n?.code,C,i]),ye=l.useCallback(()=>{if(!n)return;const t=new Set(U),d=v[n.code]??w??0,p=C[n.code]??M??null,f=u.reduce((S,_)=>{if(_.code!==n.code&&t.has(_.code))return S;const re=Ne.convertMinorUnitAmount({amount:K.majorUnitAmountToMinor(d,n.code),fromCurrencyCode:n.code,toCurrencyCode:_.code,currencies:u,applyRounding:!0});return S[_.code]=K.minorUnitAmountToMajor(re,_.code),S},{}),m=u.reduce((S,_)=>{if(_.code!==n.code&&t.has(_.code))return S;if(typeof p!="number")return(_.code===n.code||!t.has(_.code))&&(S[_.code]=null),S;const re=Ne.convertMinorUnitAmount({amount:K.majorUnitAmountToMinor(p,n.code),fromCurrencyCode:n.code,toCurrencyCode:_.code,currencies:u,applyRounding:!0});return S[_.code]=K.minorUnitAmountToMajor(re,_.code),S},{});i("prices",f,{shouldDirty:!0,shouldValidate:!0}),i("sale_prices",m,{shouldDirty:!0,shouldValidate:!0}),i("price",f[n.code]??d,{shouldDirty:!0,shouldValidate:!0}),i("sale_price",m[n.code]??null,{shouldDirty:!0,shouldValidate:!0})},[u,n,v,C,i,U,w,M]),Re=l.useCallback(({variationAttributes:t,variants:d})=>{i("variation_attributes",t,{shouldDirty:!0}),i("variants",d,{shouldDirty:!0,shouldValidate:!0})},[i]),be=async t=>{R(!0),E(!0),O(null);try{if(!x){const m="Select whether this product is physical or digital before saving.";B("product_type",{type:"manual",message:m}),a?O(m):alert(m),R(!1),E(!1);return}if(t.status==="active"&&(!D||!ee)){const m=`${x==="stripe"?"Stripe":"Freemius"} must be enabled and fully configured before this product can be published.`;B("product_type",{type:"manual",message:m}),a?O(m):alert(m),R(!1),E(!1);return}const d=j?0:Math.max(0,Number(t.trial_period_days||0)),p={...t,product_type:t.product_type,payment_provider:x,freemius_product_id:j?"":t.freemius_product_id,freemius_plan_id:j?"":t.freemius_plan_id,trial_period_days:d,trial_requires_payment_method:!j&&d>0?t.trial_requires_payment_method:!1,upc:j?t.upc:null,is_taxable:j?t.is_taxable:!1,variation_attributes:j?t.variation_attributes:[],variants:j?t.variants:[]},f=H.sanitizeProductFormValuesForStoreManagedCurrencies(p,u);if(a&&b)await b(f),Fe(new Date);else if(X)await X(f);else throw new Error("Product form action is not configured.")}catch(d){if(console.error(d),d.message==="NEXT_REDIRECT")return;let p=d.message||"An error occurred while saving.";if(d.code==="23505"){const f=d.message?.toLowerCase()||"";f.includes("products_slug_key")||f.includes("slug")?(p="This slug is already in use. Please choose another one.",B("slug",{type:"manual",message:p})):(f.includes("products_sku_key")||f.includes("sku"))&&(p="This SKU is already in use.",B("sku",{type:"manual",message:p}))}a?O(p):alert(p)}finally{R(!1),E(!1)}},Ue=N?"bg-muted/60 text-muted-foreground opacity-70":"",Be=Qe(se);return e.jsxs("form",{onSubmit:W(be),className:"space-y-2.5 pb-4",children:[e.jsx("input",{type:"hidden",...o("translation_group_id")}),e.jsx("input",{type:"hidden",...o("payment_provider")}),e.jsxs("div",{className:"space-y-2.5 w-full",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-2.5 px-4 shadow-sm flex items-center justify-between gap-3 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-6",children:[e.jsxs("div",{className:"flex h-9 items-center gap-2",children:[e.jsx("span",{className:"text-sm font-bold whitespace-nowrap leading-none pt-0.5",children:"Product Type"}),g.product_type&&e.jsx(L.AlertCircle,{className:"h-4 w-4 text-destructive"})]}),e.jsx("div",{className:"flex h-9 items-center",children:e.jsxs(r.Select,{onValueChange:t=>i("product_type",t,{shouldDirty:!0,shouldValidate:!0}),value:I||void 0,children:[e.jsx(r.SelectTrigger,{className:"w-[160px] h-9 text-xs",children:e.jsx(r.SelectValue,{placeholder:"Select Type"})}),e.jsxs(r.SelectContent,{children:[e.jsx(r.SelectItem,{value:"physical",children:"Physical Product"}),e.jsx(r.SelectItem,{value:"digital",children:"Digital Product"})]})]})})]}),e.jsxs("div",{className:"flex items-center gap-6",children:[e.jsxs("div",{className:"flex h-9 items-center gap-3",children:[e.jsx("span",{className:"text-[11px] font-semibold text-muted-foreground uppercase tracking-wider leading-none",children:"Payment Provider"}),e.jsx(r.Badge,{variant:"outline",className:"text-xs py-1 font-bold bg-muted/30 leading-none",children:x?x==="stripe"?"Stripe":"Freemius":"—"})]}),x&&e.jsx("div",{className:"flex h-9 items-center gap-2",children:D&&ee?e.jsxs("span",{className:"flex items-center gap-1.5 text-emerald-600 text-[10px] font-bold bg-emerald-50 px-2 py-1 rounded-full border border-emerald-100 uppercase leading-none",children:[e.jsx(L.CheckCircle2,{className:"h-3 w-3"}),"Ready"]}):e.jsxs("span",{className:"flex items-center gap-1.5 text-amber-600 text-[10px] font-bold bg-amber-50 px-2 py-1 rounded-full border border-amber-100 uppercase leading-none",children:[e.jsx(L.AlertCircle,{className:"h-3 w-3"}),D?"Keys Missing":"Disabled"]})}),!ee&&x&&F[x].missing.length>0&&e.jsxs("div",{className:"hidden xl:flex h-9 items-center gap-1 text-[10px] text-muted-foreground bg-muted/50 px-2 py-1 rounded border border-dashed leading-none",children:[e.jsx(L.Info,{className:"h-3 w-3"}),"Missing: ",F[x].missing.join(", ")]})]})]}),e.jsxs($,{title:"Product Information",hideHeader:!0,children:[a&&e.jsxs("div",{className:"flex items-center justify-between text-xs text-muted-foreground pb-2 border-b border-border/40 mb-2.5",children:[e.jsx("span",{className:"font-semibold text-[11px] uppercase tracking-wider text-muted-foreground/80",children:"Product Settings"}),e.jsx("div",{className:"flex items-center gap-1.5 min-h-[16px]",children:ke?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping absolute inline-flex h-full w-full rounded-full bg-amber-400 opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-amber-500"})]}),e.jsx("span",{className:"text-amber-600 dark:text-amber-400 font-medium",children:"Autosaving settings..."})]}):ce?e.jsxs("span",{className:"text-red-500 font-medium",children:["Error saving settings: ",ce]}):ne?e.jsxs("span",{className:"text-emerald-600 dark:text-emerald-400 font-medium",children:["Settings autosaved at ",ne.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})]}):e.jsx("span",{className:"text-muted-foreground/60",children:"Settings autosave in draft mode"})})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-2.5",children:[e.jsxs("div",{className:"col-span-2 space-y-1",children:[e.jsx(r.Label,{htmlFor:"title",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Title"}),e.jsx(r.Input,{id:"title",placeholder:"Product title",...o("title"),className:"h-8 text-sm"}),g.title&&e.jsx("p",{className:"text-destructive text-[11px] leading-none",children:g.title.message})]}),e.jsxs("div",{className:"col-span-2 space-y-1",children:[e.jsx(r.Label,{htmlFor:"slug",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Slug"}),e.jsx(r.Input,{id:"slug",placeholder:"product-slug",...o("slug"),className:"h-8 text-sm"}),g.slug&&e.jsx("p",{className:"text-destructive text-[11px] leading-none",children:g.slug.message})]}),e.jsxs("div",{className:"col-span-1 space-y-1",children:[e.jsx(r.Label,{htmlFor:"sku",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"SKU"}),e.jsx(r.Input,{id:"sku",placeholder:"SKU",...o("sku"),className:"h-8 text-sm font-mono"}),g.sku&&e.jsx("p",{className:"text-destructive text-[11px] leading-none",children:g.sku.message})]}),e.jsxs("div",{className:"col-span-1 space-y-1",children:[e.jsx(r.Label,{htmlFor:"upc_ean",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"UPC / EAN"}),e.jsx(r.Input,{id:"upc_ean",placeholder:"000000000",...o("upc"),className:"h-8 text-sm font-mono",readOnly:N})]})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-12 gap-2.5 mt-2",children:[e.jsxs("div",{className:`${a?"lg:col-span-3":"lg:col-span-4"} col-span-2 space-y-1`,children:[e.jsx(r.Label,{htmlFor:"meta_title",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Meta Title"}),e.jsx(r.Input,{id:"meta_title",...o("meta_title"),placeholder:"SEO page title (50-60 chars)",className:"h-8 text-sm"})]}),e.jsxs("div",{className:"lg:col-span-4 col-span-2 space-y-1",children:[e.jsx(r.Label,{htmlFor:"meta_description",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Meta Description"}),e.jsx(r.Input,{id:"meta_description",...o("meta_description"),placeholder:"SEO description (150-160 chars)",className:"h-8 text-sm"})]}),e.jsxs("div",{className:`${a?"lg:col-span-3":"lg:col-span-4"} col-span-2 space-y-1`,children:[e.jsx(r.Label,{htmlFor:"custom_canonical",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Canonical URL (optional)"}),e.jsx(r.Input,{id:"custom_canonical",...o("custom_canonical"),placeholder:"Blank = self-referencing. Absolute https://… URL or /relative path to override.",className:"h-8 text-sm"})]}),a&&e.jsxs("div",{className:"lg:col-span-2 col-span-2 space-y-1",children:[e.jsx(r.Label,{htmlFor:"status",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Status"}),e.jsxs(r.Select,{onValueChange:t=>i("status",t,{shouldDirty:!0}),value:c("status"),children:[e.jsx(r.SelectTrigger,{className:"h-8 text-xs",children:e.jsx(r.SelectValue,{placeholder:"Status"})}),e.jsxs(r.SelectContent,{children:[e.jsx(r.SelectItem,{value:"draft",children:"Draft"}),e.jsx(r.SelectItem,{value:"active",children:"Active"}),e.jsx(r.SelectItem,{value:"archived",children:"Archived"})]})]})]})]})]}),e.jsx($,{title:"Product Categories",description:"Assign this product to one or more categories.",children:e.jsx(He.ProductCategorySelector,{categories:we,selectedIds:c("category_ids")||[],onChange:t=>i("category_ids",t,{shouldDirty:!0,shouldValidate:!0})})}),e.jsxs("section",{className:"rounded-lg border bg-card p-3 shadow-sm space-y-3",children:[j&&e.jsxs("div",{className:"flex items-center justify-between gap-4 flex-wrap border-b border-muted/50 pb-2",children:[e.jsx("div",{className:"flex items-center gap-4",children:e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("h2",{className:"text-sm font-bold tracking-tight",children:"Pricing & Inventory"}),e.jsx("p",{className:"text-[11px] text-muted-foreground leading-none",children:"Manage simple or variant pricing."})]})}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2 bg-muted/40 rounded-md px-2.5 py-1.5",children:[e.jsx("span",{className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Stock"}),e.jsx(r.Input,{id:"stock",type:"number",min:"0",...o("stock",{valueAsNumber:!0}),placeholder:"0",readOnly:N,className:`${Ue} h-8 w-20 text-sm text-center font-mono bg-background`})]}),N?e.jsx(r.Badge,{variant:"secondary",className:"text-[11px] py-0 px-2 h-5",children:"Variant pricing"}):null]})]}),j?e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"w-full",children:[e.jsx(je.CurrencyPriceFields,{idPrefix:"product",currencies:u,prices:z.prices,salePrices:z.salePrices,managedCurrencyCodes:U,onPriceChange:fe,onSalePriceChange:_e,onAutoFill:ye,readOnly:N,helperText:N?"Parent prices stay as a fallback, but active variants define the live shopper price.":void 0,trailing:e.jsx(ve.SaleScheduleFields,{idPrefix:"product",startAt:c("sale_start_at"),endAt:c("sale_end_at"),onChange:(t,d)=>i(t,d,{shouldDirty:!0,shouldValidate:!0}),error:g.sale_end_at?.message,bare:!0})}),g.price&&e.jsx("p",{className:"text-destructive text-sm mt-1",children:g.price.message}),g.sale_price&&e.jsx("p",{className:"text-destructive text-sm mt-1",children:g.sale_price.message}),g.stock&&e.jsx("p",{className:"text-destructive text-[10px] font-medium leading-none mt-1",children:g.stock.message})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3 rounded border border-dashed p-2.5 bg-muted/5",children:[e.jsx("span",{className:"text-xs font-bold uppercase tracking-wider text-muted-foreground",children:N?"Variations Active":"Variations"}),e.jsx(r.Button,{type:"button",variant:Y?"outline":"default",onClick:()=>Q(t=>!t),size:"sm",className:"h-7 text-xs px-3",children:Y?"Hide":"Manage"})]}),Y&&e.jsx("div",{className:"border-t pt-3",children:e.jsx($e.VariationsEditor,{globalAttributes:P,currentLanguageCode:Ae,baseSku:c("sku")||"",basePrice:w||0,basePrices:v,baseSalePrice:typeof M=="number"?M:null,baseSalePrices:C,currencies:u,availableVariantImages:Be,initialVariationAttributes:s?.variation_attributes,initialVariants:qe,onChange:Re})})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-end gap-4 w-full",children:[e.jsxs("div",{className:"flex-1",children:[e.jsx(r.Label,{htmlFor:"freemius_product_id",className:"text-[11px] uppercase tracking-wider text-muted-foreground font-bold mb-1.5 block",children:"Freemius Product ID"}),e.jsx(r.Input,{id:"freemius_product_id",...o("freemius_product_id"),className:"h-9"})]}),e.jsxs("div",{className:"flex-1",children:[e.jsx(r.Label,{htmlFor:"freemius_plan_id",className:"text-[11px] uppercase tracking-wider text-muted-foreground font-bold mb-1.5 block",children:"Freemius Plan ID"}),e.jsx(r.Input,{id:"freemius_plan_id",...o("freemius_plan_id"),className:"h-9"})]}),Me?e.jsx(Ke.SyncFreemiusPricingButton,{productId:c("freemius_product_id"),hasOpenDraft:Ce}):null]}),e.jsxs("div",{className:"bg-muted/10 border rounded-md overflow-hidden",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-6 bg-muted/20 border-b p-2.5 px-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-[11px] font-bold uppercase tracking-wider text-muted-foreground",children:"Free Trial"}),e.jsxs(r.Badge,{variant:"outline",className:"font-mono text-xs shadow-sm bg-background",children:[String(c("trial_period_days")||0)," Days"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-[11px] font-bold uppercase tracking-wider text-muted-foreground",children:"Card Required"}),e.jsx(r.Badge,{variant:xe?"default":"secondary",className:"text-xs shadow-sm",children:xe?"Yes":"No"})]}),e.jsx("span",{className:"text-[10px] text-muted-foreground ml-auto",children:"Managed in Freemius dashboard"}),e.jsx("input",{type:"hidden",...o("trial_period_days",{valueAsNumber:!0})})]}),e.jsxs("div",{className:"w-full p-4 pt-3 space-y-2",children:[e.jsx(je.CurrencyPriceFields,{idPrefix:"product",currencies:u,prices:z.prices,salePrices:z.salePrices,managedCurrencyCodes:U,onPriceChange:fe,onSalePriceChange:_e,onAutoFill:ye,readOnly:!0,trailing:e.jsx(ve.SaleScheduleFields,{idPrefix:"product",startAt:c("sale_start_at"),endAt:c("sale_end_at"),onChange:(t,d)=>i(t,d,{shouldDirty:!0,shouldValidate:!0}),error:g.sale_end_at?.message,bare:!0})}),e.jsx("p",{className:"text-[10px] leading-snug text-muted-foreground",children:"Scheduling a sale on a Freemius product generates a time-bounded Freemius coupon so the discount is enforced at Freemius checkout."})]})]})]}),A&&e.jsx("div",{className:"pt-2 border-t",children:A})]})]}),e.jsx($,{title:"Product Description",hideHeader:!0,children:e.jsx("div",{className:"space-y-2",children:e.jsxs("div",{className:"space-y-1",children:[e.jsx(r.Label,{htmlFor:"short_description",className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Short Description"}),e.jsx(r.Input,{id:"short_description",...o("short_description"),placeholder:"Brief summary for product cards...",className:"h-8 text-sm"})]})})}),e.jsxs($,{title:"Media Gallery",description:"Drag to reorder. First image is the hero.",children:[e.jsx(Le.ProductMediaManager,{initialMedia:se,onUpdate:Te,mediaPickerNode:y}),e.jsx("input",{type:"hidden",...o("product_media")})]}),!a&&e.jsxs("div",{className:"rounded-lg border bg-card p-3 px-4 shadow-sm flex items-center justify-between gap-3 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none",children:"Status"}),e.jsxs(r.Select,{onValueChange:t=>i("status",t),value:c("status"),children:[e.jsx(r.SelectTrigger,{className:"h-8 w-[110px] text-sm",children:e.jsx(r.SelectValue,{placeholder:"Status"})}),e.jsxs(r.SelectContent,{children:[e.jsx(r.SelectItem,{value:"draft",children:"Draft"}),e.jsx(r.SelectItem,{value:"active",children:"Active"}),e.jsx(r.SelectItem,{value:"archived",children:"Archived"})]})]})]}),e.jsx(r.Button,{disabled:T,type:"submit",size:"sm",className:"h-8 text-sm px-5",children:T?"Saving...":"Save Changes"})]})]})]})}exports.ProductForm=Ze;
|
|
@@ -57,6 +57,8 @@ interface ProductFormProps {
|
|
|
57
57
|
name: string;
|
|
58
58
|
slug: string;
|
|
59
59
|
}>;
|
|
60
|
+
/** Whether an unpublished draft is currently open for this product (drives the Freemius sync warning). */
|
|
61
|
+
hasOpenDraft?: boolean;
|
|
60
62
|
}
|
|
61
|
-
export declare function ProductForm({ initialData, isEdit, mediaPickerNode, availableLanguagesProp, globalAttributesProp, currenciesProp, translationGroupId, targetLanguageId, freemiusDashboardNode, enabledProviders, configStatus, createAction, updateAction, availableCategoriesProp }: ProductFormProps): React.JSX.Element;
|
|
63
|
+
export declare function ProductForm({ initialData, isEdit, mediaPickerNode, availableLanguagesProp, globalAttributesProp, currenciesProp, translationGroupId, targetLanguageId, freemiusDashboardNode, enabledProviders, configStatus, createAction, updateAction, availableCategoriesProp, hasOpenDraft }: ProductFormProps): React.JSX.Element;
|
|
62
64
|
export {};
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsxs as s, jsx as e, Fragment as Me } from "react/jsx-runtime";
|
|
3
3
|
import U, { useState as A, useRef as Ve, useEffect as k, useCallback as X } from "react";
|
|
4
|
-
import { zodResolver as
|
|
5
|
-
import { AlertCircle as Ae, CheckCircle2 as
|
|
4
|
+
import { zodResolver as er } from "@hookform/resolvers/zod";
|
|
5
|
+
import { AlertCircle as Ae, CheckCircle2 as rr, Info as tr } from "lucide-react";
|
|
6
6
|
import { Select as le, SelectTrigger as ne, SelectValue as ce, SelectContent as ue, SelectItem as F, Badge as Y, Label as x, Input as y, Button as Te } from "@nextblock-cms/ui";
|
|
7
|
-
import { productSchema as
|
|
8
|
-
import { useForm as
|
|
9
|
-
import { ProductMediaManager as
|
|
10
|
-
import { SyncFreemiusPricingButton as
|
|
11
|
-
import { VariationsEditor as
|
|
7
|
+
import { productSchema as sr } from "../../../../product-schema.es.js";
|
|
8
|
+
import { useForm as ar } from "react-hook-form";
|
|
9
|
+
import { ProductMediaManager as ir } from "./ProductMediaManager.es.js";
|
|
10
|
+
import { SyncFreemiusPricingButton as dr } from "./SyncFreemiusPricingButton.es.js";
|
|
11
|
+
import { VariationsEditor as or } from "./VariationsEditor.es.js";
|
|
12
12
|
import { CurrencyPriceFields as Ie } from "./CurrencyPriceFields.es.js";
|
|
13
13
|
import { SaleScheduleFields as Re } from "./SaleScheduleFields.es.js";
|
|
14
|
-
import { ProductCategorySelector as
|
|
15
|
-
import { getStoreManagedPriceCurrencyCodes as
|
|
16
|
-
import { derivePaymentProviderFromProductType as
|
|
14
|
+
import { ProductCategorySelector as lr } from "./ProductCategorySelector.es.js";
|
|
15
|
+
import { getStoreManagedPriceCurrencyCodes as nr, resolveEditorCurrencyPriceMaps as cr, sanitizeProductFormValuesForStoreManagedCurrencies as Be } from "../product-price-sync.es.js";
|
|
16
|
+
import { derivePaymentProviderFromProductType as ur } from "../../../../types.es.js";
|
|
17
17
|
import { convertMinorUnitAmount as je } from "../../../../currency.es.js";
|
|
18
18
|
import { majorUnitAmountToMinor as Oe, minorUnitAmountToMajor as Ue } from "@nextblock-cms/utils";
|
|
19
19
|
function Q({ title: r, description: a, action: b, children: h, hideHeader: C }) {
|
|
@@ -28,7 +28,7 @@ function Q({ title: r, description: a, action: b, children: h, hideHeader: C })
|
|
|
28
28
|
/* @__PURE__ */ e("div", { className: C ? "" : "pt-1", children: h })
|
|
29
29
|
] });
|
|
30
30
|
}
|
|
31
|
-
function
|
|
31
|
+
function mr(r, a, b) {
|
|
32
32
|
const h = a ? Number.parseInt(a, 10) : void 0;
|
|
33
33
|
return r?.language_id || (Number.isFinite(h) ? h : void 0) || b.find((C) => C.is_default)?.id || b[0]?.id || 1;
|
|
34
34
|
}
|
|
@@ -37,7 +37,7 @@ function qe(r, a, b, h, C) {
|
|
|
37
37
|
[T]: typeof r?.price == "number" ? r.price / 100 : 0
|
|
38
38
|
}, q = r?.sale_prices && Object.keys(r.sale_prices).length > 0 ? r.sale_prices : typeof r?.sale_price == "number" ? {
|
|
39
39
|
[T]: r.sale_price / 100
|
|
40
|
-
} : {}, z = r?.product_type || "", I = r?.payment_provider || (r?.product_type ?
|
|
40
|
+
} : {}, z = r?.product_type || "", I = r?.payment_provider || (r?.product_type ? ur(r.product_type) : "stripe");
|
|
41
41
|
return {
|
|
42
42
|
...Be({
|
|
43
43
|
product_type: z || "physical",
|
|
@@ -65,7 +65,7 @@ function qe(r, a, b, h, C) {
|
|
|
65
65
|
trial_period_days: r?.trial_period_days ?? 0,
|
|
66
66
|
trial_requires_payment_method: r?.trial_requires_payment_method ?? !1,
|
|
67
67
|
status: r?.status || "draft",
|
|
68
|
-
language_id:
|
|
68
|
+
language_id: mr(
|
|
69
69
|
r,
|
|
70
70
|
a,
|
|
71
71
|
b
|
|
@@ -95,18 +95,18 @@ function ze(r) {
|
|
|
95
95
|
sort_order: a.sort_order ?? 0
|
|
96
96
|
})).sort((a, b) => a.sort_order - b.sort_order) : [];
|
|
97
97
|
}
|
|
98
|
-
function
|
|
98
|
+
function pr(r) {
|
|
99
99
|
return r.map((a) => ({ media_id: a.media_id }));
|
|
100
100
|
}
|
|
101
|
-
function
|
|
101
|
+
function hr(r) {
|
|
102
102
|
return r.map((a) => ({
|
|
103
103
|
media_id: a.media_id,
|
|
104
104
|
file_path: a.file_path,
|
|
105
105
|
alt: a.alt
|
|
106
106
|
}));
|
|
107
107
|
}
|
|
108
|
-
const
|
|
109
|
-
function
|
|
108
|
+
const fr = (r) => r.toString().toLowerCase().trim().replace(/\s+/g, "-").replace(/[^\w-]+/g, "").replace(/--+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
|
|
109
|
+
function Ir({
|
|
110
110
|
initialData: r,
|
|
111
111
|
isEdit: a = !1,
|
|
112
112
|
mediaPickerNode: b,
|
|
@@ -120,7 +120,8 @@ function Tr({
|
|
|
120
120
|
configStatus: I,
|
|
121
121
|
createAction: Z,
|
|
122
122
|
updateAction: v,
|
|
123
|
-
availableCategoriesProp: Ee = []
|
|
123
|
+
availableCategoriesProp: Ee = [],
|
|
124
|
+
hasOpenDraft: Ke = !1
|
|
124
125
|
}) {
|
|
125
126
|
const [B, E] = A(!1), [G, D] = A(() => !!r?.variants?.length), c = U.useMemo(
|
|
126
127
|
() => W.filter((t) => t.is_active !== !1).sort((t, d) => t.is_default !== d.is_default ? t.is_default ? -1 : 1 : t.code.localeCompare(d.code)),
|
|
@@ -129,10 +130,10 @@ function Tr({
|
|
|
129
130
|
() => c.find((t) => t.is_default) ?? c[0],
|
|
130
131
|
[c]
|
|
131
132
|
), K = U.useMemo(
|
|
132
|
-
() =>
|
|
133
|
+
() => nr(c),
|
|
133
134
|
[c]
|
|
134
|
-
), me =
|
|
135
|
-
resolver:
|
|
135
|
+
), me = ar({
|
|
136
|
+
resolver: er(sr),
|
|
136
137
|
defaultValues: qe(
|
|
137
138
|
r,
|
|
138
139
|
j,
|
|
@@ -148,7 +149,7 @@ function Tr({
|
|
|
148
149
|
watch: o,
|
|
149
150
|
setError: $,
|
|
150
151
|
formState: { errors: f, dirtyFields: he }
|
|
151
|
-
} = me, fe = Ve(!0), re = Ve(null), [
|
|
152
|
+
} = me, fe = Ve(!0), re = Ve(null), [$e, H] = A(!1), [ge, J] = A(null), [_e, He] = A(null), te = o(), xe = me.formState.isDirty;
|
|
152
153
|
k(() => {
|
|
153
154
|
if (!a) return;
|
|
154
155
|
if (fe.current) {
|
|
@@ -160,11 +161,11 @@ function Tr({
|
|
|
160
161
|
if (t === re.current) return;
|
|
161
162
|
const d = setTimeout(() => {
|
|
162
163
|
B || (re.current = t, ee(Fe)());
|
|
163
|
-
},
|
|
164
|
+
}, 400);
|
|
164
165
|
return () => clearTimeout(d);
|
|
165
166
|
}, [te, a, xe, B, ee]);
|
|
166
|
-
const ye = o("title"), O = o("product_type"), p = O === "digital" ? "freemius" : O === "physical" ? "stripe" : void 0, N = O === "physical", be = O === "digital", se = p ? z[p] : !1, ae = p ? I[p].hasKeys : !1,
|
|
167
|
-
() =>
|
|
167
|
+
const ye = o("title"), O = o("product_type"), p = O === "digital" ? "freemius" : O === "physical" ? "stripe" : void 0, N = O === "physical", be = O === "digital", se = p ? z[p] : !1, ae = p ? I[p].hasKeys : !1, Je = !!o("freemius_product_id"), ve = Number(o("trial_period_days") || 0), Ne = !!o("trial_requires_payment_method"), Le = o("variants") || [], M = o("price"), R = o("sale_price"), P = o("prices") || {}, V = o("sale_prices") || {}, S = (Le?.length || 0) > 0, Xe = o("language_id"), Ye = h.find((t) => t.id === Xe)?.code || h.find((t) => t.is_default)?.code || h[0]?.code, L = U.useMemo(
|
|
168
|
+
() => cr({
|
|
168
169
|
currencies: c,
|
|
169
170
|
prices: P,
|
|
170
171
|
salePrices: V,
|
|
@@ -172,7 +173,7 @@ function Tr({
|
|
|
172
173
|
fallbackSalePrice: R
|
|
173
174
|
}),
|
|
174
175
|
[M, R, c, P, V]
|
|
175
|
-
),
|
|
176
|
+
), Qe = U.useMemo(
|
|
176
177
|
() => r?.variants?.map((t) => ({
|
|
177
178
|
...t,
|
|
178
179
|
prices: t.prices || {},
|
|
@@ -182,7 +183,7 @@ function Tr({
|
|
|
182
183
|
);
|
|
183
184
|
k(() => {
|
|
184
185
|
if (he.title && !a) {
|
|
185
|
-
const t =
|
|
186
|
+
const t = fr(ye);
|
|
186
187
|
i("slug", t, { shouldValidate: !0 });
|
|
187
188
|
}
|
|
188
189
|
}, [ye, he.title, i, a]);
|
|
@@ -207,11 +208,11 @@ function Tr({
|
|
|
207
208
|
j,
|
|
208
209
|
T
|
|
209
210
|
]);
|
|
210
|
-
const
|
|
211
|
+
const We = (t) => {
|
|
211
212
|
const d = new Set(t.map((m) => m.id)), u = ie.filter((m) => !d.has(m.id)), g = new Set(de);
|
|
212
213
|
u.forEach((m) => {
|
|
213
214
|
m.media_id && g.add(m.media_id);
|
|
214
|
-
}), Se(g), Pe(t), i("product_media",
|
|
215
|
+
}), Se(g), Pe(t), i("product_media", pr(t), { shouldDirty: !0 }), i("explicitly_removed_media_ids", Array.from(g), {
|
|
215
216
|
shouldDirty: !0
|
|
216
217
|
});
|
|
217
218
|
};
|
|
@@ -319,7 +320,7 @@ function Tr({
|
|
|
319
320
|
K,
|
|
320
321
|
M,
|
|
321
322
|
R
|
|
322
|
-
]),
|
|
323
|
+
]), Ze = X(
|
|
323
324
|
({
|
|
324
325
|
variationAttributes: t,
|
|
325
326
|
variants: d
|
|
@@ -363,7 +364,7 @@ function Tr({
|
|
|
363
364
|
c
|
|
364
365
|
);
|
|
365
366
|
if (a && v)
|
|
366
|
-
await v(g),
|
|
367
|
+
await v(g), He(/* @__PURE__ */ new Date());
|
|
367
368
|
else if (Z)
|
|
368
369
|
await Z(g);
|
|
369
370
|
else
|
|
@@ -386,7 +387,7 @@ function Tr({
|
|
|
386
387
|
} finally {
|
|
387
388
|
E(!1), H(!1);
|
|
388
389
|
}
|
|
389
|
-
},
|
|
390
|
+
}, Ge = S ? "bg-muted/60 text-muted-foreground opacity-70" : "", De = hr(ie);
|
|
390
391
|
return /* @__PURE__ */ s("form", { onSubmit: ee(Fe), className: "space-y-2.5 pb-4", children: [
|
|
391
392
|
/* @__PURE__ */ e("input", { type: "hidden", ...n("translation_group_id") }),
|
|
392
393
|
/* @__PURE__ */ e("input", { type: "hidden", ...n("payment_provider") }),
|
|
@@ -421,14 +422,14 @@ function Tr({
|
|
|
421
422
|
/* @__PURE__ */ e(Y, { variant: "outline", className: "text-xs py-1 font-bold bg-muted/30 leading-none", children: p ? p === "stripe" ? "Stripe" : "Freemius" : "—" })
|
|
422
423
|
] }),
|
|
423
424
|
p && /* @__PURE__ */ e("div", { className: "flex h-9 items-center gap-2", children: se && ae ? /* @__PURE__ */ s("span", { className: "flex items-center gap-1.5 text-emerald-600 text-[10px] font-bold bg-emerald-50 px-2 py-1 rounded-full border border-emerald-100 uppercase leading-none", children: [
|
|
424
|
-
/* @__PURE__ */ e(
|
|
425
|
+
/* @__PURE__ */ e(rr, { className: "h-3 w-3" }),
|
|
425
426
|
"Ready"
|
|
426
427
|
] }) : /* @__PURE__ */ s("span", { className: "flex items-center gap-1.5 text-amber-600 text-[10px] font-bold bg-amber-50 px-2 py-1 rounded-full border border-amber-100 uppercase leading-none", children: [
|
|
427
428
|
/* @__PURE__ */ e(Ae, { className: "h-3 w-3" }),
|
|
428
429
|
se ? "Keys Missing" : "Disabled"
|
|
429
430
|
] }) }),
|
|
430
431
|
!ae && p && I[p].missing.length > 0 && /* @__PURE__ */ s("div", { className: "hidden xl:flex h-9 items-center gap-1 text-[10px] text-muted-foreground bg-muted/50 px-2 py-1 rounded border border-dashed leading-none", children: [
|
|
431
|
-
/* @__PURE__ */ e(
|
|
432
|
+
/* @__PURE__ */ e(tr, { className: "h-3 w-3" }),
|
|
432
433
|
"Missing: ",
|
|
433
434
|
I[p].missing.join(", ")
|
|
434
435
|
] })
|
|
@@ -442,7 +443,7 @@ function Tr({
|
|
|
442
443
|
children: [
|
|
443
444
|
a && /* @__PURE__ */ s("div", { className: "flex items-center justify-between text-xs text-muted-foreground pb-2 border-b border-border/40 mb-2.5", children: [
|
|
444
445
|
/* @__PURE__ */ e("span", { className: "font-semibold text-[11px] uppercase tracking-wider text-muted-foreground/80", children: "Product Settings" }),
|
|
445
|
-
/* @__PURE__ */ e("div", { className: "flex items-center gap-1.5 min-h-[16px]", children:
|
|
446
|
+
/* @__PURE__ */ e("div", { className: "flex items-center gap-1.5 min-h-[16px]", children: $e ? /* @__PURE__ */ s(Me, { children: [
|
|
446
447
|
/* @__PURE__ */ s("div", { className: "relative flex h-2 w-2", children: [
|
|
447
448
|
/* @__PURE__ */ e("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-amber-400 opacity-75" }),
|
|
448
449
|
/* @__PURE__ */ e("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-amber-500" })
|
|
@@ -511,7 +512,7 @@ function Tr({
|
|
|
511
512
|
title: "Product Categories",
|
|
512
513
|
description: "Assign this product to one or more categories.",
|
|
513
514
|
children: /* @__PURE__ */ e(
|
|
514
|
-
|
|
515
|
+
lr,
|
|
515
516
|
{
|
|
516
517
|
categories: Ee,
|
|
517
518
|
selectedIds: o("category_ids") || [],
|
|
@@ -538,7 +539,7 @@ function Tr({
|
|
|
538
539
|
...n("stock", { valueAsNumber: !0 }),
|
|
539
540
|
placeholder: "0",
|
|
540
541
|
readOnly: S,
|
|
541
|
-
className: `${
|
|
542
|
+
className: `${Ge} h-8 w-20 text-sm text-center font-mono bg-background`
|
|
542
543
|
}
|
|
543
544
|
)
|
|
544
545
|
] }),
|
|
@@ -592,20 +593,20 @@ function Tr({
|
|
|
592
593
|
)
|
|
593
594
|
] }),
|
|
594
595
|
G && /* @__PURE__ */ e("div", { className: "border-t pt-3", children: /* @__PURE__ */ e(
|
|
595
|
-
|
|
596
|
+
or,
|
|
596
597
|
{
|
|
597
598
|
globalAttributes: C,
|
|
598
|
-
currentLanguageCode:
|
|
599
|
+
currentLanguageCode: Ye,
|
|
599
600
|
baseSku: o("sku") || "",
|
|
600
601
|
basePrice: M || 0,
|
|
601
602
|
basePrices: P,
|
|
602
603
|
baseSalePrice: typeof R == "number" ? R : null,
|
|
603
604
|
baseSalePrices: V,
|
|
604
605
|
currencies: c,
|
|
605
|
-
availableVariantImages:
|
|
606
|
+
availableVariantImages: De,
|
|
606
607
|
initialVariationAttributes: r?.variation_attributes,
|
|
607
|
-
initialVariants:
|
|
608
|
-
onChange:
|
|
608
|
+
initialVariants: Qe,
|
|
609
|
+
onChange: Ze
|
|
609
610
|
}
|
|
610
611
|
) })
|
|
611
612
|
] }) : /* @__PURE__ */ s(Me, { children: [
|
|
@@ -619,7 +620,13 @@ function Tr({
|
|
|
619
620
|
/* @__PURE__ */ e(x, { htmlFor: "freemius_plan_id", className: "text-[11px] uppercase tracking-wider text-muted-foreground font-bold mb-1.5 block", children: "Freemius Plan ID" }),
|
|
620
621
|
/* @__PURE__ */ e(y, { id: "freemius_plan_id", ...n("freemius_plan_id"), className: "h-9" })
|
|
621
622
|
] }),
|
|
622
|
-
|
|
623
|
+
Je ? /* @__PURE__ */ e(
|
|
624
|
+
dr,
|
|
625
|
+
{
|
|
626
|
+
productId: o("freemius_product_id"),
|
|
627
|
+
hasOpenDraft: Ke
|
|
628
|
+
}
|
|
629
|
+
) : null
|
|
623
630
|
] }),
|
|
624
631
|
/* @__PURE__ */ s("div", { className: "bg-muted/10 border rounded-md overflow-hidden", children: [
|
|
625
632
|
/* @__PURE__ */ s("div", { className: "flex flex-wrap items-center gap-6 bg-muted/20 border-b p-2.5 px-4", children: [
|
|
@@ -676,10 +683,10 @@ function Tr({
|
|
|
676
683
|
] }) }) }),
|
|
677
684
|
/* @__PURE__ */ s(Q, { title: "Media Gallery", description: "Drag to reorder. First image is the hero.", children: [
|
|
678
685
|
/* @__PURE__ */ e(
|
|
679
|
-
|
|
686
|
+
ir,
|
|
680
687
|
{
|
|
681
688
|
initialMedia: ie,
|
|
682
|
-
onUpdate:
|
|
689
|
+
onUpdate: We,
|
|
683
690
|
mediaPickerNode: b
|
|
684
691
|
}
|
|
685
692
|
),
|
|
@@ -703,5 +710,5 @@ function Tr({
|
|
|
703
710
|
] });
|
|
704
711
|
}
|
|
705
712
|
export {
|
|
706
|
-
|
|
713
|
+
Ir as ProductForm
|
|
707
714
|
};
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),u=require("react"),l=require("next/navigation"),d=require("@nextblock-cms/ui"),f=require("lucide-react"),r=require("sonner"),g=require("../actions.cjs.js");function y({productId:t,hasOpenDraft:c=!1}){const o=l.useRouter(),[n,i]=u.useState(!1),a=async()=>{if(!t){r.toast.error("Product ID is missing");return}if(!(c&&!window.confirm(`You have unpublished draft changes for this product.
|
|
2
|
+
|
|
3
|
+
Syncing updates the live pricing now, but publishing your draft afterward will overwrite it with the draft’s older values. Publish or discard your draft first to keep the synced prices.
|
|
4
|
+
|
|
5
|
+
Sync anyway?`))){i(!0);try{const e=await g.triggerSingleProductSync(t);e.error?r.toast.error(e.error):(r.toast.success("Pricing sync complete!"),o.refresh())}catch(e){r.toast.error(e.message||"An unexpected error occurred during sync")}finally{i(!1)}}};return s.jsxs(d.Button,{variant:"outline",onClick:a,disabled:n,className:"gap-2",children:[s.jsx(f.RefreshCw,{className:`w-4 h-4 ${n?"animate-spin":""}`}),n?"Syncing...":"Sync Plans & Pricing from Freemius"]})}exports.SyncFreemiusPricingButton=y;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
interface SyncFreemiusPricingButtonProps {
|
|
2
2
|
productId: string;
|
|
3
|
+
/** True when an unpublished product draft is open — publishing it later would revert the synced pricing. */
|
|
4
|
+
hasOpenDraft?: boolean;
|
|
3
5
|
}
|
|
4
|
-
export declare function SyncFreemiusPricingButton({ productId }: SyncFreemiusPricingButtonProps): import("react").JSX.Element;
|
|
6
|
+
export declare function SyncFreemiusPricingButton({ productId, hasOpenDraft }: SyncFreemiusPricingButtonProps): import("react").JSX.Element;
|
|
5
7
|
export {};
|
|
@@ -1,40 +1,49 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsxs as
|
|
3
|
-
import { useState as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { jsxs as c, jsx as a } from "react/jsx-runtime";
|
|
3
|
+
import { useState as u } from "react";
|
|
4
|
+
import { useRouter as f } from "next/navigation";
|
|
5
|
+
import { Button as l } from "@nextblock-cms/ui";
|
|
6
|
+
import { RefreshCw as d } from "lucide-react";
|
|
6
7
|
import { toast as e } from "sonner";
|
|
7
|
-
import { triggerSingleProductSync as
|
|
8
|
-
function
|
|
9
|
-
const [n,
|
|
10
|
-
return /* @__PURE__ */
|
|
11
|
-
|
|
8
|
+
import { triggerSingleProductSync as m } from "../actions.es.js";
|
|
9
|
+
function v({ productId: i, hasOpenDraft: s = !1 }) {
|
|
10
|
+
const o = f(), [n, t] = u(!1);
|
|
11
|
+
return /* @__PURE__ */ c(
|
|
12
|
+
l,
|
|
12
13
|
{
|
|
13
14
|
variant: "outline",
|
|
14
15
|
onClick: async () => {
|
|
15
|
-
if (!
|
|
16
|
+
if (!i) {
|
|
16
17
|
e.error("Product ID is missing");
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
if (!(s && !window.confirm(
|
|
21
|
+
`You have unpublished draft changes for this product.
|
|
22
|
+
|
|
23
|
+
Syncing updates the live pricing now, but publishing your draft afterward will overwrite it with the draft’s older values. Publish or discard your draft first to keep the synced prices.
|
|
24
|
+
|
|
25
|
+
Sync anyway?`
|
|
26
|
+
))) {
|
|
27
|
+
t(!0);
|
|
28
|
+
try {
|
|
29
|
+
const r = await m(i);
|
|
30
|
+
r.error ? e.error(r.error) : (e.success("Pricing sync complete!"), o.refresh());
|
|
31
|
+
} catch (r) {
|
|
32
|
+
e.error(r.message || "An unexpected error occurred during sync");
|
|
33
|
+
} finally {
|
|
34
|
+
t(!1);
|
|
35
|
+
}
|
|
27
36
|
}
|
|
28
37
|
},
|
|
29
38
|
disabled: n,
|
|
30
39
|
className: "gap-2",
|
|
31
40
|
children: [
|
|
32
|
-
/* @__PURE__ */
|
|
33
|
-
n ? "Syncing..." : "Sync
|
|
41
|
+
/* @__PURE__ */ a(d, { className: `w-4 h-4 ${n ? "animate-spin" : ""}` }),
|
|
42
|
+
n ? "Syncing..." : "Sync Plans & Pricing from Freemius"
|
|
34
43
|
]
|
|
35
44
|
}
|
|
36
45
|
);
|
|
37
46
|
}
|
|
38
47
|
export {
|
|
39
|
-
|
|
48
|
+
v as SyncFreemiusPricingButton
|
|
40
49
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextblock-cms/ecom",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.15",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@nextblock-cms/db": "^0.12.
|
|
14
|
-
"@nextblock-cms/ui": "^0.12.
|
|
15
|
-
"@nextblock-cms/utils": "^0.12.
|
|
13
|
+
"@nextblock-cms/db": "^0.12.15",
|
|
14
|
+
"@nextblock-cms/ui": "^0.12.15",
|
|
15
|
+
"@nextblock-cms/utils": "^0.12.15",
|
|
16
16
|
"@freemius/checkout": "^1.4.1",
|
|
17
17
|
"@freemius/sdk": "^0.3.0",
|
|
18
18
|
"@hookform/resolvers": "^5.2.2",
|