PageSourceSearch

https://tadlo.ai/static/js/5584.ca3de0ae.chunk.js

js tadlo.ai collected 2026-10-05 14:38:12 UTC 17,410 bytes, 2 lines download raw bytes

1"use strict";(globalThis.webpackChunkfrontend=globalThis.webpackChunkfrontend||[]).push([[5584],{31555(e,t,s){s.d(t,{E:()=>l});var a=s(1089),r=s(70579);function l(e){let{className:t,...s}=e;return(0,r.jsx)("div",{className:(0,a.cn)("animate-pulse rounded-md bg-primary/10",t),...s})}},13416(e,t,s){s.d(t,{T:()=>i});var a=s(65043),r=s(1089),l=s(70579);const i=a.forwardRef((e,t)=>{let{className:s,...a}=e;return(0,l.jsx)("textarea",{className:(0,r.cn)("flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",s),ref:t,...a})});i.displayName="Textarea"},15584(e,t,s){s.r(t),s.d(t,{ProductEditor:()=>D,blankDraft:()=>A,default:()=>$});var a=s(65043),r=s(56328),l=s(27233),i=s(22024),d=s(37719),n=s(55731),o=s(70067),c=s(58487),u=s(81990),m=s(65505),x=s(71360),p=s(9855),h=s(50797),b=s(40614),g=s(45621),f=s(92264),v=s(13390),j=s(13416),N=s(31555),y=s(67589),k=s(70579);const w={free:"Free",creator:"Creator",pro:"Pro"},C="grid gap-3 grid-cols-2 sm:grid-cols-3 lg:grid-cols-4",A=()=>({title:"",subtitle:"",image_url:"",price:null,currency:null,links:[{label:"",url:""}],isNew:!0});function $(){const[e,t]=(0,a.useState)([]),[s,i]=(0,a.useState)(!0),[n,o]=(0,a.useState)(null),[c,m]=(0,a.useState)({limit:null,planId:null,overBy:0}),p=(0,a.useCallback)(async function(){let{quiet:e=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};e||i(!0);try{const{data:e}=await l.FH.get("/products");t(e.products||[]),m({limit:"number"===typeof e.limit?e.limit:null,planId:e.plan_id||null,overBy:e.over_by||0})}catch(s){r.toast.error("Could not load your products")}finally{e||i(!1)}},[]);(0,a.useEffect)(()=>{p()},[p]);const{limit:h,planId:b,overBy:f}=c,j=e.length,y=null!==h&&j>=h,$=w[b]||null;return(0,k.jsxs)("div",{className:"max-w-5xl mx-auto px-4 py-6 md:py-8","data-testid":"products-page",children:[(0,k.jsxs)("header",{className:"flex items-start justify-between gap-4 mb-6",children:[(0,k.jsxs)("div",{children:[(0,k.jsxs)("h1",{className:"text-xl md:text-2xl font-semibold flex items-center gap-2",children:[(0,k.jsx)(u.A,{className:"w-5 h-5 text-violet-500"}),"Products"]}),(0,k.jsx)("p",{className:"text-sm text-muted-foreground mt-1",children:"Everything you sell, in one place. Use them in automations and on your link-in-bio."}),null!==h&&j>0&&(0,k.jsxs)("p",{className:"text-xs mt-1.5 font-medium "+(y?"text-red-600 dark:text-red-400":"text-muted-foreground"),"data-testid":"product-count",children:[j," of ",h," products",$?` \xb7 ${$} plan`:""]})]}),(0,k.jsxs)(v.$,{onClick:()=>o(A()),"data-testid":"product-add",className:"shrink-0",disabled:y,title:y?`Your ${$||"current"} plan includes ${h} products`:void 0,children:[(0,k.jsx)(x.A,{className:"w-4 h-4 mr-1.5"}),"Add product"]})]}),f>0&&(0,k.jsxs)("div",{className:"mb-5 rounded-xl border border-red-500/60 bg-red-500/5 dark:bg-red-500/10 p-4\r flex items-start gap-3",role:"alert","data-testid":"product-over-limit-banner",children:[(0,k.jsx)(d.A,{className:"w-4 h-4 mt-0.5 shrink-0 text-red-600 dark:text-red-400"}),(0,k.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,k.jsxs)("p",{className:"text-sm font-semibold text-red-700 dark:text-red-300",children:["Delete ",f," ",1===f?"product":"products"," to get back to ",h]}),(0,k.jsxs)("p",{className:"text-xs text-red-700/80 dark:text-red-300/80 mt-1",children:["You have ",j," products and the ",$||"current"," plan includes ",h,". The ones outlined in red are over the limit. They still work everywhere \u2014 on your link-in-bio and in your automations \u2014 but you can't add another until you're back to ",h,"."]}),(0,k.jsx)(g.N_,{to:"/pricing?f=product_limit",className:"inline-block mt-2 text-xs font-semibold text-red-700 dark:text-red-300 hover:underline","data-testid":"product-limit-upgrade",children:"Or upgrade for more room \u2192"})]})]}),y&&0===f&&(0,k.jsxs)("div",{className:"mb-5 rounded-xl border border-amber-500/50 bg-amber-500/5 dark:bg-amber-500/10\r px-4 py-3 text-xs text-amber-800 dark:text-amber-300","data-testid":"product-at-limit-banner",children:["You've used all ",h," products on the ",$||"current"," plan. Delete one to add another, or"," ",(0,k.jsx)(g.N_,{to:"/pricing?f=product_limit",className:"font-semibold hover:underline",children:"upgrade for more room"}),"."]}),s?(0,k.jsx)("div",{className:C,children:[0,1,2,3].map(e=>(0,k.jsx)(N.E,{className:"h-40 rounded-xl"},e))}):0===e.length?(0,k.jsx)(_,{onAdd:()=>o(A())}):(0,k.jsx)("div",{className:C,"data-testid":"product-grid",children:e.map(e=>(0,k.jsx)(S,{product:e,onEdit:()=>o({...e}),onDelete:()=>(async e=>{if(window.confirm(`Delete \u201c${e.title}\u201d? This cannot be undone.`))try{await l.FH.delete(`/products/${e.id}`),t(t=>t.filter(t=>t.id!==e.id)),r.toast.success("Product deleted"),p({quiet:!0})}catch{r.toast.error("Delete failed")}})(e)},e.id))}),n&&(0,k.jsx)(D,{initial:n,onClose:()=>o(null),onSaved:e=>{t(t=>{const s=t.findIndex(t=>t.id===e.id);if(-1===s)return[...t,e];const a=[...t];return a[s]=e,a}),o(null),p({quiet:!0})}})]})}function _(e){let{onAdd:t}=e;return(0,k.jsxs)("div",{className:"rounded-xl border border-dashed border-border p-10 text-center","data-testid":"products-empty",children:[(0,k.jsx)(u.A,{className:"w-10 h-10 mx-auto text-muted-foreground
1/50 mb-3"}),(0,k.jsx)("p",{className:"font-medium",children:"No products yet"}),(0,k.jsx)("p",{className:"text-sm text-muted-foreground mt-1 mb-4",children:"Add one manually, or paste a product URL and we\u2019ll fill in the details."}),(0,k.jsxs)(v.$,{onClick:t,children:[(0,k.jsx)(x.A,{className:"w-4 h-4 mr-1.5"}),"Add your first product"]})]})}function S(e){let{product:t,onEdit:s,onDelete:a}=e;const r=t.links||[],l=!!t.over_limit;return(0,k.jsxs)("div",{className:"rounded-xl border bg-card overflow-hidden flex flex-col "+(l?"border-red-500 border-2":"border-border"),"data-over-limit":l?"true":void 0,"data-testid":`product-card-${t.id}`,children:[l&&(0,k.jsxs)("div",{className:"bg-red-500/10 text-red-700 dark:text-red-300 text-[10px] font-semibold\r px-2 py-1 flex items-center gap-1 border-b border-red-500/40","data-testid":`product-over-limit-${t.id}`,children:[(0,k.jsx)(d.A,{className:"w-3 h-3 shrink-0"}),"Over your plan limit"]}),(0,k.jsx)("div",{className:"aspect-[4/3] bg-secondary/40 flex items-center justify-center overflow-hidden",children:t.image_url?(0,k.jsx)("img",{src:t.image_url,alt:t.title,className:"w-full h-full object-cover",loading:"lazy"}):(0,k.jsx)(o.A,{className:"w-8 h-8 text-muted-foreground/40"})}),(0,k.jsxs)("div",{className:"p-2.5 flex-1 flex flex-col",children:[(0,k.jsx)("div",{className:"font-medium text-sm leading-snug line-clamp-2",children:t.title}),t.subtitle&&(0,k.jsx)("div",{className:"text-xs text-muted-foreground mt-0.5 line-clamp-1",children:t.subtitle}),t.price&&(0,k.jsxs)("div",{className:"text-sm font-semibold mt-1",children:[t.currency?`${t.currency} `:"",t.price]}),(0,k.jsxs)("div",{className:"text-[11px] text-muted-foreground mt-2 flex items-center gap-1",children:[(0,k.jsx)(c.A,{className:"w-3 h-3"}),r.length," ",1===r.length?"link":"links","url"===t.source&&(0,k.jsxs)("span",{className:"ml-auto inline-flex items-center gap-1",title:t.source_url,children:[(0,k.jsx)(n.A,{className:"w-3 h-3"})," imported"]})]}),(0,k.jsxs)("div",{className:"flex gap-1.5 mt-auto pt-3",children:[(0,k.jsxs)(v.$,{size:"sm",variant:"secondary",className:"flex-1",onClick:s,"data-testid":`product-edit-${t.id}`,children:[(0,k.jsx)(m.A,{className:"w-3.5 h-3.5 mr-1"})," Edit"]}),(0,k.jsx)(v.$,{size:"sm",variant:"ghost",onClick:a,className:"text-red-500 hover:text-red-600","data-testid":`product-delete-${t.id}`,"aria-label":"Delete product",children:(0,k.jsx)(p.A,{className:"w-3.5 h-3.5"})})]})]})]})}function D(e){let{initial:t,onClose:s,onSaved:d}=e;const[c,u]=(0,a.useState)(t),[p,g]=(0,a.useState)(!1),[N,w]=(0,a.useState)(""),[C,A]=(0,a.useState)("link"),[$,_]=(0,a.useState)(!1),[S,D]=(0,a.useState)(!1),F=(0,a.useRef)(null),P=e=>u(t=>({...t,...e})),E=c.links||[],T=(e,t)=>{const s=[...E];s[e]={...s[e],...t},P({links:s})},z=async()=>{const e=N.trim();if(e){_(!0);try{const{data:t}=await l.FH.post("/products/import-url",{url:e}),s=t.draft||{};P({title:c.title||s.title||"",subtitle:c.subtitle||s.subtitle||"",image_url:c.image_url||s.image_url||"",price:c.price||s.price||null,currency:c.currency||s.currency||null,links:E.some(e=>e.url)?E:s.links||[{label:"",url:""}]}),A("manual"),r.toast.success(t.image_rehosted?"Details imported \u2713":"Details imported \u2014 add an image manually")}catch(a){var t,s;r.toast.error((null===a||void 0===a||null===(t=a.response)||void 0===t||null===(s=t.data)||void 0===s?void 0:s.detail)||"Could not fetch that link.")}finally{_(!1)}}};return(0,k.jsx)("div",{className:"fixed inset-0 z-[60] bg-black/50 backdrop-blur-sm flex items-end sm:items-center justify-center p-0 sm:p-4",onClick:s,"data-testid":"product-editor",children:(0,k.jsxs)("div",{className:"bg-background w-full sm:max-w-lg sm:rounded-2xl rounded-t-2xl max-h-[92vh] overflow-y-auto",onClick:e=>e.stopPropagation(),children:[(0,k.jsxs)("div",{className:"sticky top-0 bg-background border-b border-border px-4 py-3 flex items-center justify-between",children:[(0,k.jsx)("div",{className:"font-semibold text-sm",children:c.isNew?"Add product":"Edit product"}),(0,k.jsx)("button",{onClick:s,"aria-label":"Close",className:"h-8 w-8 inline-flex items-center justify-center rounded-full hover:bg-secondary",children:(0,k.jsx)(b.A,{className:"w-4 h-4"})})]}),(0,k.jsxs)("div",{className:"p-4 space-y-4",children:[c.isNew&&(0,k.jsx)("div",{className:"flex gap-1 p-0.5 rounded-lg bg-secondary/50",role:"tablist","aria-label":"How to add this product",children:[{id:"link",label:"Paste a link",icon:n.A},{id:"manual",label:"Add manually",icon:m.A}].map(e=>{const t=e.icon;return(0,k.jsxs)("button",{type:"button",role:"tab","aria-selected":C===e.id,onClick:()=>A(e.id),"data-testid":`product-tab-${e.id}`,className:"flex-1 inline-flex items-center justify-center gap-1.5 text-xs\n                      font-medium py-2 px-2 rounded-md transition-colors\n                      focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring "+(C===e.id?"bg-background shadow-sm text-foreground":"text-muted-foreground hover:text-foreground"),children:[(0,k.jsx)(t,{className:"w-3.5 h-3.5"}),e.label]},e.id)})}),c.isNew&&"link"===C&&(0,k.jsxs)("div",{className:"rounded-xl border border-border p-3 bg-secondary/30","data-testid":"product-pane-link",children:[(0,k.jsxs)("div",{className:"text-xs font-medium mb-2 flex items-center gap-1.5",children:[(0,k.jsx)(n.A,{className:"w-3.5 h-3.5"})," Paste a product URL"]}),(0,k.jsxs)("div",{className:"flex gap-2",children:[(0,k.jsx)(f.p,{value:N,onChange:e=>w(e.target.value),onPaste:e=>(0,y.VP)(e,w),onKeyDown:e=>"Enter"===e.key&&z(),placeholder:"https://yourstore.com/product","data-testid":"product-import-url"}),(0,k.jsx)(v.$,{onClick:z,disabled:$||!N.trim(),variant:"secondary","data-testid":"product-import-go",children:$?(0,k.jsx)(i.A,{className:"w-4 h-4 animate-spin"}):"Fetch"})]}),(0,k.jsx)("p",{className:"text-[11px] text-muted-foreground mt-1.5",children:"We\u2019ll read the title, image and price. You can change anything before saving."}),(0,k.jsx)("button",{type:"button",onClick:()=>A("manual"),className:"mt-2 text-[11px] font-medium text-violet-600 hover:text-violet-700","data-testid":"product-skip-import",children:"Or fill it in yourself \u2192"})]}),(!c.isNew||"manual"===C)&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)("div",{children:[(0,k.jsxs)("label",{className:"text-xs font-medium mb-1.5 block",children:["Image ",(0,k.jsx)("span",{className:"text-red-500","aria-hidden":!0,
1children:"*"}),(0,k.jsx)("span",{className:"sr-only",children:"(required)"})]}),(0,k.jsxs)("div",{className:"flex items-center gap-3",children:[(0,k.jsx)("div",{className:"w-20 h-20 rounded-lg bg-secondary/40 overflow-hidden flex items-center justify-center shrink-0",children:c.image_url?(0,k.jsx)("img",{src:c.image_url,alt:"",className:"w-full h-full object-cover"}):(0,k.jsx)(o.A,{className:"w-6 h-6 text-muted-foreground/40"})}),(0,k.jsxs)("div",{className:"flex flex-col gap-1.5",children:[(0,k.jsx)("input",{ref:F,type:"file",accept:"image/jpeg,image/png,image/webp,image/gif",className:"hidden",onChange:async e=>{var t;const s=null===(t=e.target.files)||void 0===t?void 0:t[0];if(!s)return;if(s.size>5242880)return r.toast.error("Image exceeds 5 MB limit.");const a=new FormData;a.append("file",s),D(!0);try{const{data:e}=await l.FH.post("/upload/image",a,{headers:{"Content-Type":"multipart/form-data"}});P({image_url:(null===e||void 0===e?void 0:e.url)||""})}catch(n){var i,d;r.toast.error((null===n||void 0===n||null===(i=n.response)||void 0===i||null===(d=i.data)||void 0===d?void 0:d.detail)||"Upload failed")}finally{D(!1),F.current&&(F.current.value="")}},"data-testid":"product-image-input"}),(0,k.jsx)(v.$,{size:"sm",variant:"secondary",onClick:()=>{var e;return null===(e=F.current)||void 0===e?void 0:e.click()},disabled:S,"data-testid":"product-image-upload",children:S?(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(i.A,{className:"w-3.5 h-3.5 mr-1 animate-spin"})," Uploading\u2026"]}):(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(h.A,{className:"w-3.5 h-3.5 mr-1"})," Upload"]})}),c.image_url&&(0,k.jsx)(v.$,{size:"sm",variant:"ghost",className:"text-red-500",onClick:()=>P({image_url:""}),children:"Remove"})]})]})]}),(0,k.jsxs)("div",{children:[(0,k.jsxs)("label",{className:"text-xs font-medium mb-1.5 block",children:["Title ",(0,k.jsx)("span",{className:"text-red-500","aria-hidden":!0,children:"*"}),(0,k.jsx)("span",{className:"sr-only",children:"(required)"})]}),(0,k.jsx)(f.p,{value:c.title,maxLength:200,"data-testid":"product-title",onChange:e=>P({title:e.target.value}),placeholder:"Brass desk lamp"})]}),(0,k.jsxs)("div",{children:[(0,k.jsxs)("label",{className:"text-xs font-medium mb-1.5 block",children:["Description ",(0,k.jsx)("span",{className:"font-normal text-muted-foreground",children:"(optional)"})]}),(0,k.jsx)(j.T,{value:c.subtitle||"",maxLength:300,rows:2,"data-testid":"product-subtitle",onChange:e=>P({subtitle:e.target.value}),placeholder:"Warm light, solid brass"})]}),(0,k.jsxs)("div",{children:[(0,k.jsxs)("div",{className:"flex items-center justify-between mb-1.5",children:[(0,k.jsxs)("label",{className:"text-xs font-medium",children:["Buttons & links ",(0,k.jsx)("span",{className:"text-red-500","aria-hidden":!0,children:"*"}),(0,k.jsx)("span",{className:"sr-only",children:"(at least one required)"})]}),(0,k.jsxs)(v.$,{size:"sm",variant:"ghost",onClick:()=>{E.length>=10||P({links:[...E,{label:"",url:""}]})},disabled:E.length>=10,"data-testid":"product-add-link",children:[(0,k.jsx)(x.A,{className:"w-3.5 h-3.5 mr-1"})," Add link"]})]}),(0,k.jsxs)("div",{className:"space-y-2",children:[E.map((e,t)=>(0,k.jsxs)("div",{className:"flex gap-2 items-center",children:[(0,k.jsx)(f.p,{value:e.label,maxLength:80,className:"w-28 shrink-0","data-testid":`product-link-label-${t}`,onChange:e=>T(t,{label:e.target.value}),placeholder:"Shop"}),(0,k.jsx)(f.p,{value:e.url,"data-testid":`product-link-url-${t}`,onChange:e=>T(t,{url:e.target.value}),onPaste:e=>(0,y.VP)(e,e=>T(t,{url:e})),onBlur:e=>{const s=(0,y.HD)(e.target.value);s&&s!==e.target.value&&T(t,{url:s})},placeholder:"yourstore.com/item"}),(0,k.jsx)("button",{onClick:()=>(e=>P({links:E.filter((t,s)=>s!==e)}))(t),"aria-label":"Remove link",className:"h-8 w-8 shrink-0 inline-flex items-center justify-center rounded-md text-muted-foreground hover:text-red-500",children:(0,k.jsx)(b.A,{className:"w-3.5 h-3.5"})})]},t)),0===E.length&&(0,k.jsx)("p",{className:"text-xs text-muted-foreground",children:"No links yet."})]}),(0,k.jsx)("p",{className:"text-[11px] text-muted-foreground mt-1.5",children:"Instagram carousels show at most 3 buttons per card \u2014 extras still appear on your link-in-bio."})]})]})]}),(0,k.jsxs)("div",{className:"sticky bottom-0 bg-background border-t border-border px-4 py-3 flex gap-2",children:[(0,k.jsx)(v.$,{variant:"secondary",className:"flex-1",onClick:s,children:"Cancel"}),c.isNew&&"manual"!==C?(0,k.jsx)(v.$,{className:"flex-1",variant:"secondary",onClick:()=>A("manual"),"data-testid":"product-continue-manual",children:"Enter details"}):(0,k.jsx)(v.$,{className:"flex-1",onClick:async()=>
1{if(!c.title.trim())return r.toast.error("Give the product a title");if(!(c.image_url||"").trim())return r.toast.error("Add an image \u2014 cards without one can't be sent");if(!E.some(e=>(e.url||"").trim()))return r.toast.error("Add at least one link");const e={title:c.title.trim(),subtitle:c.subtitle||"",image_url:c.image_url||"",price:c.price||null,currency:c.currency||null,links:E.filter(e=>(e.url||"").trim())};g(!0);const t=!c.id;try{const{data:s}=t?await l.FH.post("/products",e):await l.FH.patch(`/products/${c.id}`,e);r.toast.success(t?"Product added \u2713":"Saved \u2713"),d(s)}catch(i){var s,a;r.toast.error((null===i||void 0===i||null===(s=i.response)||void 0===s||null===(a=s.data)||void 0===a?void 0:a.detail)||"Save failed")}finally{g(!1)}},disabled:p,"data-testid":"product-save",children:p?(0,k.jsx)(i.A,{className:"w-4 h-4 animate-spin"}):c.isNew?"Add product":"Save"})]})]})})}}}]);
2//# sourceMappingURL=5584.ca3de0ae.chunk.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.