PageSourceSearch

https://lipflip.ai/assets/TummyTuckPreviewTool-BkJI4AnT.js

js lipflip.ai collected 2026-10-05 12:13:49 UTC 10,288 bytes, 1 lines download raw bytes

1import{u as ee,a as se,r as o,c as te,b as m,s as ae,g as re,d as oe,e as f,f as ne,h as le,j as e,B as h,S as $,L as F,U as ie,C as ce,i as de,k as ue,l as me,D as fe,m as he,n as ge,o as xe,p as pe,q as ve,t as we,v as je}from"./index-ybl9RtYI.js";const be="/assets/default-preview-Di9yGrwl.jpg",w="tummy-tuck",ye="/tummy-tuck-before-and-after",ke=()=>{const{user:l}=ee(),G=se(),[i,j]=o.useState(null),[g,P]=o.useState(!1),[c,b]=o.useState(null),[x,R]=o.useState("Moderate"),[y,S]=o.useState([50]),[B,N]=o.useState(!1),[O,I]=o.useState("free"),V=async()=>{if(!l)return;const{data:s}=await f.from("user_subscriptions").select("plan, status").eq("user_id",l.id).maybeSingle();(s==null?void 0:s.status)==="active"&&(s!=null&&s.plan)&&I(s.plan)};o.useEffect(()=>{V()},[l]),o.useEffect(()=>{const s=te(w);s&&(j(s.image),s.option&&R(s.option),l&&m.success("Welcome back! Continuing with your photo."))},[]);const M=o.useRef(!1);o.useEffect(()=>{l&&i&&!c&&!g&&!M.current&&sessionStorage.getItem(`auto_generate:${w}`)&&(sessionStorage.removeItem(`auto_generate:${w}`),M.current=!0,L())},[l,i]);const U=o.useRef(null),u=o.useRef(!1),k=s=>{if(!U.current)return;const t=U.current.getBoundingClientRect(),n=s-t.left,r=Math.max(0,Math.min(100,n/t.width*100));S([r])},W=s=>{u.current=!0,k(s.clientX)},X=s=>{u.current&&k(s.clientX)},E=()=>{u.current=!1},Y=s=>{u.current=!0,k(s.touches[0].clientX)},q=s=>{u.current&&k(s.touches[0].clientX)},z=()=>{u.current=!1},H=["Front or side view photo","Full torso visible in frame","Well-lit, clear photo","Fitted clothing for best results"],K=o.useCallback(s=>{var n;const t=(n=s.target.files)==null?void 0:n[0];if(t){const r=new FileReader;r.onload=a=>{var d;j((d=a.target)==null?void 0:d.result),b(null)},r.readAsDataURL(t)}},[]),J=o.useCallback(s=>{s.preventDefault();const t=s.dataTransfer.files[0];if(t&&t.type.startsWith("image/")){const n=new FileReader;n.onload=r=>{var a;j((a=r.target)==null?void 0:a.result),b(null)},n.readAsDataURL(t)}},[]),L=async()=>{var n,r;if(!i)return;if(!l){ae(w,{image:i,option:x}),sessionStorage.setItem(`auto_generate:${w}`,"1"),m.message("Please sign in to continue",{description:"Your photo will be ready when you return."}),G(`/auth?redirect=${encodeURIComponent(ye)}`);return}const s=await re(l.id);I(s);let t=null;try{t=await oe(s)}catch{m.error("Could not verify your usage. Please try again.");return}if(t===null){N(!0);return}P(!0);try{const{data:a,error:d}=await f.functions.invoke("generate-tummy-tuck",{body:{image:i,intensity:x}});if(d)throw d;const D=(r=(n=a==null?void 0:a.data)==null?void 0:n[0])==null?void 0:r.url,C=a==null?void 0:a._imageBase64;if(!D&&!C)throw new Error("No image returned from AI model");b(C||D),m.success("Tummy tuck AI preview generated!");try{let p;C?p=await(await fetch(C)).blob():p=await(await fetch(D)).blob();const A=`${l.id}/${Date.now()}.jpg`,{error:Z}=await f.storage.from("user-photos").upload(A,p,{contentType:"image/jpeg"});if(!Z){const{data:T}=f.storage.from("user-photos").getPublicUrl(A),{data:v}=await f.from("user_photos").insert({user_id:l.id,photo_url:T.publicUrl,title:`Tummy Tuck - ${x}`}).select("id").single();if(v!=null&&v.id){const _=await ne(l.id,i,v.id);_&&await f.from("user_photos").update({before_photo_url:_}).eq("id",v.id)}}}catch(p){console.error("Auto-save failed:",p)}}catch(a){console.error("Generation error:",a),t!==null&&await le(l.id);const d=a instanceof Error?a.message:"Generation failed";m.error(d)}finally{P(!1)}},Q=()=>{j(null),b(null),P(!1)};return e.jsxs("div",{className:"grid lg:grid-cols-2 gap-6 lg:gap-8 items-start",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"card-elevated p-6 rounded-2xl",children:[e.jsx("h2",{className:"text-lg font-semibold mb-4",children:"Upload Your Photo"}),e.jsx("div",{onDrop:J,onDragOver:s=>s.preventDefault(),className:"border-2 border-dashed border-border rounded-xl p-6 text-center transition-colors hover:border-primary/50 hover:bg-accent/30",children:i?e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"mx-auto w-full max-w-[200px] aspect-[3/4] rounded-xl overflow-hidden",children:e.jsx("img",{src:i,alt:"Uploaded photo",className:"h-full w-full object-cover"})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground mb-2",children:"Transformation Level"}),e.jsx("div",{className:"flex flex-wrap gap-2 justify-center",children:["Subtle","Moderate","Full"].map(s=>e.jsx("button",{onClick:()=>R(s),className:`px-3 py-1.5 rounded-full text-sm font-medium transition-colors ${x===s?"bg-primary text-primary-foreground":"bg-secondary text-secondary-foreground hover:bg-accent"}`,children:s},s))})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 justify-center",children:[!c&&!g&&e.jsxs(h,{onClick:L,className:"rounded-full px-6",children:[e.jsx($,{className:"mr-2 h-4 w-4"}),"Generate Tummy Tuck Preview"]}),e.jsx(h,{variant:"outline",onClick:Q,className:"rounded-full",children:"Change Photo"})]}),g&&e.jsxs("div",{className:"flex items-center justify-center gap-2 text-muted-foreground",children:[e.jsx(F,{className:"h-4 w-4 animate-spin"}),e.jsx("span",{className:"text-sm",children:"Generating AI preview..."})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"mx-auto mb-4 h-14 w-14 roun
1ded-full bg-accent flex items-center justify-center",children:e.jsx(ie,{className:"h-7 w-7 text-accent-foreground"})}),e.jsx("p",{className:"mb-4 text-muted-foreground text-sm",children:"Drag and drop or click to select"}),e.jsxs("label",{children:[e.jsx("input",{type:"file",accept:"image/jpeg,image/png",onChange:K,className:"hidden"}),e.jsx(h,{asChild:!0,className:"rounded-full px-6",children:e.jsx("span",{children:"Choose Photo"})})]})]})}),e.jsx("div",{className:"mt-5 grid gap-2 sm:grid-cols-2",children:H.map((s,t)=>e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(ce,{className:"h-4 w-4 text-primary flex-shrink-0"}),e.jsx("span",{children:s})]},t))})]}),e.jsxs("div",{className:"mt-4 p-4 bg-accent/50 rounded-xl flex items-start gap-3",children:[e.jsx(de,{className:"h-5 w-5 text-accent-foreground flex-shrink-0 mt-0.5"}),e.jsx("p",{className:"text-sm text-accent-foreground",children:"This preview is for visualization only and does not guarantee surgical results. Consult with a board-certified plastic surgeon."})]})]}),e.jsxs("div",{className:"card-elevated p-6 rounded-2xl",children:[e.jsx("h2",{className:"text-lg font-semibold mb-4",children:"Preview Result"}),!c&&!i&&e.jsx("div",{className:"aspect-[3/4] rounded-xl overflow-hidden border border-border",children:e.jsx("img",{src:be,alt:"tummy tuck before and after AI preview example",className:"h-full w-full object-cover"})}),i&&!c&&!g&&e.jsx("div",{className:"aspect-[3/4] rounded-xl overflow-hidden",children:e.jsx("img",{src:i,alt:"Uploaded photo preview",className:"h-full w-full object-cover rounded-xl"})}),g&&e.jsxs("div",{className:"aspect-[3/4] rounded-xl bg-secondary/60 border border-border flex flex-col items-center justify-center",children:[e.jsx(F,{className:"h-8 w-8 animate-spin text-primary mb-3"}),e.jsx("span",{className:"text-sm font-medium text-muted-foreground",children:"Generating your tummy tuck preview..."})]}),c&&e.jsxs("div",{children:[e.jsxs("div",{ref:U,className:"relative aspect-[3/4] rounded-xl overflow-hidden mb-4 cursor-ew-resize select-none",onMouseDown:W,onMouseMove:X,onMouseUp:E,onMouseLeave:E,onTouchStart:Y,onTouchMove:q,onTouchEnd:z,children:[e.jsx("img",{src:c,alt:"AI tummy tuck preview result",className:"absolute inset-0 h-full w-full object-cover pointer-events-none",draggable:!1}),e.jsx("div",{className:"absolute inset-0 overflow-hidden pointer-events-none",style:{width:`${y[0]}%`},children:e.jsx("img",{src:i,alt:"Original photo",className:"h-full w-full object-cover",style:{width:`${100/(y[0]/100)}%`,maxWidth:"none"},draggable:!1})}),e.jsx("div",{className:"absolute top-0 bottom-0 w-0.5 bg-white shadow-lg pointer-events-none",style:{left:`${y[0]}%`},children:e.jsx("div",{className:"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 h-8 w-8 rounded-full bg-white shadow-elevated flex items-center justify-center",children:e.jsxs("div",{className:"flex gap-0.5",children:[e.jsx("div",{className:"w-0.5 h-3 bg-muted-foreground rounded-full"}),e.jsx("div",{className:"w-0.5 h-3 bg-muted-foreground rounded-full"})]})})}),e.jsx("div",{className:"absolute bottom-2 left-2 bg-foreground
1/80 text-background text-xs font-medium px-2 py-1 rounded pointer-events-none",children:"Before"}),e.jsx("div",{className:"absolute bottom-2 right-2 bg-foreground/80 text-background text-xs font-medium px-2 py-1 rounded pointer-events-none",children:"After"}),e.jsxs("div",{className:"absolute top-2 right-2 bg-primary/90 text-primary-foreground text-xs font-medium px-2 py-1 rounded-full flex items-center gap-1 pointer-events-none",children:[e.jsx($,{className:"h-3 w-3"}),"AI-generated"]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(ue,{value:y,onValueChange:S,max:100,min:0,step:1,className:"flex-1"}),e.jsxs(h,{variant:"outline",size:"sm",className:"shrink-0",onClick:async()=>{if(!me(O)){N(!0);return}try{const t=await(await fetch(c)).blob(),n=URL.createObjectURL(t),r=document.createElement("a");r.href=n,r.download=`tummy-tuck-preview-${x.toLowerCase()}.jpg`,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(n)}catch{m.error("Download failed")}},children:[e.jsx(fe,{className:"h-4 w-4 mr-2"}),"Download"]})]})]})]}),e.jsx(he,{open:B,onOpenChange:N,children:e.jsxs(ge,{className:"sm:max-w-md",children:[e.jsxs(xe,{children:[e.jsx("div",{className:"mx-auto mb-2 h-12 w-12 rounded-full bg-primary/10 flex items-center justify-center",children:e.jsx(pe,{className:"h-6 w-6 text-primary"})}),e.jsx(ve,{className:"text-center",children:"Preview Limit Reached"}),e.jsx(we,{className:"text-center",children:"You've used all your AI previews for this plan. Upgrade to get more previews and features."})]}),e.jsxs("div",{className:"flex flex-col gap-2 mt-2",children:[e.jsx(h,{asChild:!0,className:"w-full",children:e.jsx(je,{to:"/pricing",children:"View Pricing Plans"})}),e.jsx(h,{variant:"ghost",className:"w-full",onClick:()=>N(!1),children:"Maybe Later"})]})]})})]})};export{ke as default};

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.