1import{c as ee,r,s as m,j as e,L as g,B as h,u as d,a as te,b as se,d as A,I as ae}from"./index-nonPsb46.js";import{i as w}from"./edgeError-bjdWlj11.js";import{A as re,C as ne}from"./AppLayout-DJLfdIN2.js";import{T as ie,a as oe,b as I,c as l,d as ce,e as p}from"./table-DEIGsUWU.js";import{T as le,a as de,b as k,c as S}from"./tabs-BjX-Uatj.js";import{M as me}from"./MetaIntegration-gmUIU_Ah.js";import{T as C}from"./textarea-DgApuyzQ.js";import{S as P}from"./save-66PnZ7X4.js";import{R as F}from"./rotate-ccw-Bf87P7E0.js";import{C as z}from"./circle-x-BHbdToV-.js";import{L as he}from"./layout-grid-dHzPkSU5.js";import{C as pe}from"./coins-DtodoB8r.js";import{R as ue}from"./rocket-BXOoIzGo.js";import{R as V}from"./refresh-cw-CsVqe2Qe.js";import{P as fe}from"./plus-cVzVpo8g.js";import"./index-Ce_vaiTW.js";import"./Combination-oM-Zh7aE.js";import"./shield-BGzQCK3Z.js";import"./users-x_m7CZ_w.js";import"./moon-DxM7P1SS.js";import"./download-CmxGb0pE.js";import"./layout-template-D5Dx7DCx.js";import"./card-B4wnQoDO.js";import"./select-JazlT5pz.js";import"./index-BdQq_4o_.js";import"./index-CEZArC-L.js";import"./badge-Bd_THlyF.js";import"./circle-check-ByqWabt7.js";import"./circle-alert-CUq4vnJX.js";import"./upload-9Va2RZRg.js";import"./external-link-Bu5OXgwj.js";/** 2 * @license lucide-react v0.462.0 - ISC 3 * 4 * This source code is licensed under the ISC license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const ge=ee("LogIn",[["path",{d:"M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4",key:"u53s6r"}],["polyline",{points:"10 17 15 12 10 7",key:"1ail0h"}],["line",{x1:"15",x2:"3",y1:"12",y2:"12",key:"v6grx8"}]]),L="video_script_prompt",M="video_script_base_prompt",B=`First analyze the attached image. Then write a short scene with dialogue using the style below along with the style of the attached image. 7 8{{brand_dna}} 9 10{{base_prompt}} 11 12-- 13Style reference: {{instructions}} 14 15NAME BAN (MANDATORY): Never write a brand name, product trademark, wordmark, shop URL, or "SHOP â¦" call-to-action anywhere in the output â not in shot descriptions, dialogue, SFX notes, or on-screen text. Describe the product only by what it is and how it is used (shape, closures, where it sits on the body). If the instructions mention a proper name, treat it as private context and do not copy it into the script.`,X=`Write the scene with dialogue, in the shot-list notation shown below (SHOT N: shot size, lens/camera move / action described in one sentence / SFX: ...). 16SHOT 1: ECU, 85mm push-in / on the phone screen as it shakes on rumpled sheets / SFX: alarm, sheet rustle. 17SHOT 2: WS, 35mm handheld jolt / Rhythmic cut into the subject jolting upright through side light, throwing the blanket aside, and planting their feet on the floor in one rushed motion, still in a sleep tee and lounge shorts / SFX: mattress bounce, blanket whip, sharp breath. 18SHOT 3: MCU, 50mm slide / Cut on action into face wash at the sink, droplets catching the top light / SFX: faucet rush, water slap. 19SHOT 4: Insert shot, 85mm lens focus / Match cut into the toothbrush held at a natural forward brushing angle against the front teeth; hand relaxed and upright, mint foam and mirror eye / SFX: bristle scrape, sink drip. 20SHOT 5: Interior fridge view, 24mm wide / Object pass into the camera inside the fridge looking out as the door snaps open and the subject's hand darts in, blue light framing a hurried grab for breakfast ingredients / SFX: fridge hum, bottle clink, shelf scrape. 21SHOT 6: Insert shot, 50mm handheld / Rhythmic cut into egg and toast hitting the pan under warm practical light / SFX: butter sizzle, chop tap. 22SHOT 7: MCU, centered 50mm push-in / Match cut into one rushed bite, a quick clock glance, and an immediate rise from the chair / SFX: crunch, ceramic clink, chair scrape. 23SHOT 8: Bird's-eye, 35mm overhead / Match cut on action as the sleep tee disappears under a fitted top and tailored jacket; then their keys, transit card, and bag get scooped up in one messy grab / SFX: fabric whip, key jingle, zipper pull, bag rustle. 24SHOT 9: MS, 35mm pan / Camera slips into a rushed outfit change as the sleep tee disappears under a fitted to
24p and tailored jacket; then their keys, transit card, and bag get scooped up in one messy grab / SFX: fabric whip, key jingle, zipper pull, bag rustle. 25SHOT 10: Insert shot, 50mm overhead / Match cut into lace-up shoes slamming on as the laces yank tight in one impatient pull / SFX: sole thump, lace tug, short breath. 26SHOT 11: WS, 24mm parallel / Whip pan transition into the subject, now in the tailored outside outfit, rushing through the apartment corridor into bright light without breaking stride / SFX: latch click, rapid footsteps, hallway air. 27SHOT 12: MS to CU, 35mm glide, 85mm push-in / Sound bridge into the metro interior as they grip the pole and slip through just before the closing doors, reflected chrome streaking around them and the city blurring outside / SFX: train rattle, carriage screech, door warning chime, light breath. 28SHOT 13: Insert to MCU, 50mm snap zoom / Smash cut to the office entrance as their access card hits the reader, the glass door unlocks, and they slip through before dropping into a chair and opening a laptop / SFX: badge beep, door click, laptop chime. 29SHOT 14: OTS, 35mm handheld / Rhythmic cut into their fingers racing across the keyboard with blue monitor light illuminating their face / SFX: keyboard clicks, notification sounds, mouse click. 30SHOT 15: WS, 24mm pull-out / Match cut back to the bedroom composition from the opening shot as they collapse onto the bed after a long day / SFX: body drop, fabric rustle, heavy exhale.`;function xe(){const[o,i]=r.useState(B),[x,b]=r.useState(X),[u,f]=r.useState(!0),[y,s]=r.useState(!1);r.useEffect(()=>{(async()=>{var _,E;const{data:n}=await m.from("prompt_templates").select("key, content").in("key",[L,M]),v=(_=n==null?void 0:n.find(T=>T.key===L))==null?void 0:_.content,N=(E=n==null?void 0:n.find(T=>T.key===M))==null?void 0:E.content;v&&i(v),N&&b(N),f(!1)})()},[]);const c=async()=>{var n;s(!0);try{const v=((n=(await m.auth.getUser()).data.user)==null?void 0:n.id)??null,{error:N}=await m.from("prompt_templates").upsert([{key:L,content:o,updated_by:v},{key:M,content:x,updated_by:v}],{onConflict:"key"});if(N)throw N;d.success("Video script prompts saved")}catch(v){w(v)||d.error(v.message||"Failed to save prompt")}finally{s(!1)}};return u?e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground py-8",children:[e.jsx(g,{className:"w-4 h-4 animate-spin"})," Loading promptâ¦"]}):e.jsxs("div",{className:"space-y-6 max-w-4xl",children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"text-sm text-muted-foreground space-y-1",children:[e.jsx("p",{children:"This is the exact prompt sent to the script model for the Video tab."}),e.jsxs("p",{children:["Placeholders inserted at run time:"," ",e.jsx("code",{className:"px-1 rounded bg-muted",children:"{{brand}}"})," (project name),"," ",e.jsx("code",{className:"px-1 rounded bg-muted",children:"{{brand_dna}}"})," (brand guidelines from Brand DNA / custom instructions),"," ",e.jsx("code",{className:"px-1 rounded bg-muted",children:"{{base_prompt}}"})," (the shot-list craft reference below), and"," ",e.jsx("code",{className:"px-1 rounded bg-muted",children:"{{instructions}}"})," (user idea instructions)."]}),e.jsxs("p",{children:["Leave ",e.jsx("code",{className:"px-1 rounded bg-muted",children:"{{brand_dna}}"})," out of the template if you do not want brand DNA injected into the script."]})]}),e.jsx(C,{value:o,onChange:n=>i(n.target.value),rows:14,className:"font-mono text-xs",spellCheck:!1})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"text-sm font-medium",children:["Base prompt (","{{base_prompt}}",")"]}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["The shot-list craft reference injected wherever ",e.jsx("code",{className:"px-1 rounded bg-muted",children:"{{base_prompt}}"})," ","appears above."]}),e.jsx(C,{value:x,onChange:n=>b(n.target.value),rows:24,className:"font-mono text-xs",spellCheck:!1})]}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs(h,{onClick:c,disabled:y,children:[y?e.jsx(g,{className:"w-4 h-4 mr-2 animate-spin"}):e.jsx(P,{className:"w-4 h-4 mr-2"}),"Save prompts"]}),e.jsxs(h,{variant:"outline",onClick:()=>{i(B),b(X)},disabled:y,children:[e.jsx(F,{className:"w-4 h-4 mr-2"}),"Reset to default"]})]})]})}const Y="storyboard_image_base_prompt",be=`PANEL 1 = OPENING FRAME (MANDATORY â HIGHEST PRIORITY): 31The attached OPENING FRAME is the approved first frame of the video. Panel 1 of the sheet must be a sketch of THAT EXACT image â same location, same subject(s), same faces and body types, same wardrobe, same props, same product, same camera angle, same shot size, same lighting and same composition. 32Do not restage, reframe, recast, relight, re-dress or 'improve' it, and do not substitute a different moment from the script. Only the drawing medium changes (photo â sketch). 33Panels 2-4 continue from that frame and must keep the same characters, wardrobe, product and location continuity established by it.`,G=`Create a storyboard "sketch" of each scene (black and white is fine) 34SKETCH SCOPE (IMPORTANT): the loose sketch treatment applies to the environment, the figures, the staging and the background only. The brand product itself is the exception â wherever it appears it must be drawn as an accurate, carefully observed rendering of the supplied product reference (correct shape, proportions, construction, hardware, closures, colour blocking and markings), not a loose or generic impression of it. Never simplify the product into a stand-in shape "because it is a sketch". 35PANEL COUNT (MANDATORY): exactly 4 panels in a 2x2 grid. Draw only SHOT 1 through SHOT 4 of the script. Later shots stay in the script for the video â do not add panels for them and do not merge them into these 4. 36NO OVERLAY TEXT RULE (MANDATORY): the panel artwork must contain NO headlines, taglines, ad copy, on-screen text, logos, captions, subtitles or lettering of any kind drawn into the scene. The only marks allowed on top of the artwork are directional/technical annotations â motion arrows, camera-move arrows, pan/zoom/push-in indicators and the panel number. Short shot captions (timecode, shot size, lens, dialogue/SFX notes) belong OUTSIDE the panel image, in the caption strip beneath it â never inside the drawing. 37CAPTION / LETTERING BAN (MANDATORY): captions may include only shot number, timecode, shot size, lens, camera move, generic action and SFX. Never write a brand name, product trademark, wordmark, shop URL, shop CTA, or marketing copy in a caption or anywhere on the sheet. If the script or instructions contain a proper name, do not copy it onto the sheet.`;function ye(){const[o,i]=r.useState(G),[x,b]=r.useState(!0),[u,f]=r.useState(!1);r.useEffect(()=>{(async()=>{const{data:s}=await m.from("prompt_templates").select("content").eq("key",Y).maybeSingle();s!=null&&s.content&&i(s.content),b(!1)})()},[]);const y=async()=>{var s;f(!0);try{const c=((s=(await m.auth.getUser()).data.user)==null?void 0:s.id)??null,{error:n}=await m.from("prompt_templates").upsert([{key:Y,content:o,updated_by:c}],{onConflict:"key"});if(n)throw n;d.success("Storyboard prompt saved")}catch(c){w(c)||d.error(c.message||"Failed to save prompt")}finally{f(!1)}};return x?e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground py-8",children:[e.jsx(g,{className:"w-4 h-4 animate-spin"})," Loading promptâ¦"]}):e.jsxs("div",{className:"space-y-4 max-w-4xl",children:[e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Base instructions sent to the image model for every storyboard sheet (new boards and revisions), for all users. The script, attached image roles and user direction are appended automatically below this text. The brand ",e.jsx("strong",{children:"Instructions"})," tab is also appended after this as CRITICAL INSTRUCTIONS â keep this base generic; put brand-specific product rules in that tab, not here."]}),e.jsxs("div",{className:"rounded-md border bg-muted/40 p-3 space-y-2",children:[e.jsx("p",{className:"text-xs font-medium",children:"Always appended (not editable)"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"When an approved / transformed starting frame exists it is attached as the first image and this rule is forced after your text, so panel 1 always matches the frame the user approved:"}),e.jsx("pre",{className:"whitespace-pre-wrap font-mono text-[11px] text-muted-foreground",children:be})]}),e.jsx(C,{value:o,onChange:s=>i(s.target.value),rows:20,className:"font-mono text-xs",spellCheck:!1}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs(h,{onClick:y,disabled:u,children:[u?e.jsx(g,{className:"w-4 h-4 mr-2 animate-spin"}):e.jsx(P,{className:"w-4 h-4 mr-2"}),"Save prompt"]}),e.jsxs(h,{variant:"outline",onClick:()=>i(G),disabled:u,children:[e.jsx(F,{className:"w-4 h-4 mr-2"}),"Reset to default"]})]})]})}const q="start_frame_transform_prompt",K=`Create a near-identical copy of the attached reference image to serve as the opening frame of a new video. This is a MINIMAL edit pass, not a reinterpretation. 38 39KEEP EVERYTHING THE SAME unless listed under REQUIRED CHANGES: 40- same scene, same environment, same background, same props and secondary objects 41- same composition, framing, shot size, camera angle, perspective, subject placement 42- same clothing (same garments, colors, materials, patterns and cuts) 43- same lighting, color grade, mood, photographic/cinematic style and image quality 44- same pose, body position, expression intensity and overall visual energy 45 46REQUIRED CHANGES (only these): 471. RECAST EVERY VISIBLE PERSON AS A COMPLETELY DIFFERENT HUMAN BEING. This is the single most important requirement: the new person must be legally and visually unrecognizable as the original, and must fail any face-matching comparison against the source. Change ALL of the following: 48 - overall face shape and bone structure (jawline, chin shape, cheekbones, brow ridge, skull proportions) 49 - eyes: shape, spacing, eyelid type, iris color, eyebrow shape and thickness
50 - nose: bridge width, length, tip shape and nostril shape 51 - mouth: lip fullness, mouth width, smile shape, teeth 52 - ears, hairline, hair color, hair length and hair texture 53 - skin tone and complexion, and a clearly DIFFERENT ethnicity from the original person 54 - distinguishing marks: remove or replace freckles, moles, scars, tattoos, beard/stubble style, glasses style, and any facial jewelry 55 Keep only: approximate age range, gender presentation, pose, head angle, gaze direction, expression and framing. A viewer who knows the original person must NOT be able to recognize them. Do not merely soften, retouch or nudge the original face â replace it entirely with a new individual. 56 IF TWO OR MORE PEOPLE ARE VISIBLE: every single one of them must be recast, not just the main subject. Recast each person independently â no background person, partially visible person, out-of-focus person, child or bystander may keep their original face. The recast people must also look clearly different from EACH OTHER (different bone structure, hair, skin tone and ethnicity per person) â do not turn them into siblings, twins or the same face repeated. Work through them one by one and confirm each face has been fully replaced before finishing. 572. Remove ALL text, captions, logos, watermarks, UI elements, graphic overlays, arrows, numbers, borders, stickers, subtitles and social-media interface elements. Reconstruct whatever was behind them so the area matches the surrounding scene. 583. Do not reproduce recognizable logos, trademarks, copyrighted characters or branded graphics from the source. Replace branded surfaces with plain, unbranded equivalents of the same shape and color. 59 60DO NOT redesign, restyle or "improve" the scene. Do not change the background architecture, furniture, decor, vegetation, props or textures. Do not change wardrobe. Do not add or remove objects, people or animals. Do not add text or graphic overlays. 61Someone comparing the two images should see the same photograph performed by entirely different, unrecognizable people, with no text or logos. If any face still looks like the original person, the result is a failure â including secondary or background people.`;function je(){const[o,i]=r.useState(K),[x,b]=r.useState(!0),[u,f]=r.useState(!1);r.useEffect(()=>{(async()=>{const{data:s}=await m.from("prompt_templates").select("content").eq("key",q).maybeSingle();s!=null&&s.content&&i(s.content),b(!1)})()},[]);const y=async()=>{var s;f(!0);try{const c=((s=(await m.auth.getUser()).data.user)==null?void 0:s.id)??null,{error:n}=await m.from("prompt_templates").upsert([{key:q,content:o,updated_by:c}],{onConflict:"key"});if(n)throw n;d.success("Starting frame prompt saved")}catch(c){w(c)||d.error(c.message||"Failed to save prompt")}finally{f(!1)}};return x?e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground py-8",children:[e.jsx(g,{className:"w-4 h-4 animate-spin"})," Loading prompt\\u2026"]}):e.jsxs("div",{className:"space-y-4 max-w-4xl",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"Base instructions used to transform each of the 9 starting frame candidates (competitor, stock and manual frames) before they are used as a video opening frame. Product reference rules, per-candidate variation and the user\\u2019s own edit instructions are appended automatically below this text."}),e.jsx(C,{value:o,onChange:s=>i(s.target.value),rows:24,className:"font-mono text-xs",spellCheck:!1}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs(h,{onClick:y,disabled:u,children:[u?e.jsx(g,{className:"w-4 h-4 mr-2 animate-spin"}):e.jsx(P,{className:"w-4 h-4 mr-2"}),"Save prompt"]}),e.jsxs(h,{variant:"outline",onClick:()=>i(K),disabled:u,children:[e.jsx(F,{className:"w-4 h-4 mr-2"}),"Reset to default"]})]})]})}const W="video_generation_prompt",Q=`{{scene_directive}} 62 63{{pacing_directive}} 64 65Short-form vertical video ad{{brand_suffix}}. {{slogan_line}} 66 67{{concept_summary}} 68 69Hook: "{{hook}}" 70{{setting_line}} 71Mood: {{mood}} 72Visual style: {{visual_style}} 73{{target_audience_line}} 74 75{{product_features_line}} 76{{brand_voice_line}} 77
78{{compliance_line}} 79 80{{custom_instructions_line}} 81 82{{v4_realism}} 83 84{{reference_images}} 85{{first_frame}} 86 87Shot on iPhone, portrait 9:16. One continuous take. Raw, unpolished, real. The kind of video someone casually filmed and it happened to be incredible.`,ve=[["{{scene_directive}}","Scene/theme directive built from the selected scene format"],["{{pacing_directive}}","Pacing directive from the cuts setting (quick / moderate / few)"],["{{brand_suffix}}",'" for <Brand>" â empty when brand guidelines are off'],["{{brand_name}}","Project name (empty when brand guidelines are off)"],["{{slogan_line}}","Randomly selected brand slogan line"],["{{concept_summary}}","The idea's concept summary"],["{{hook}}","The idea's hook"],["{{setting_line}}","Setting line when a scene format is selected"],["{{scene}}","Raw scene format value"],["{{mood}}","Idea emotions, comma separated"],["{{visual_style}}","Idea visual style tags, comma separated"],["{{target_audience_line}}","Brand target audience line"],["{{product_features_line}}","Brand product bullets line"],["{{brand_voice_line}}","Brand voice notes line"],["{{compliance_line}}","Compliance rules line"],["{{custom_instructions_line}}","Brand custom instructions line"],["{{v4_realism}}","The V4 realism block"],["{{text_policy}}","Overlay text policy rule (also auto-pinned to the top of every prompt)"],["{{reference_images}}","Backend note describing the attached reference image files (empty when none)"],["{{first_frame}}","Backend note for the attached opening-frame image (product frame / approved start frame)"]];function we(){const[o,i]=r.useState(Q),[x,b]=r.useState(!0),[u,f]=r.useState(!1);r.useEffect(()=>{(async()=>{const{data:s}=await m.from("prompt_templates").select("content").eq("key",W).maybeSingle();s!=null&&s.content&&i(s.content),b(!1)})()},[]);const y=async()=>{var s;f(!0);try{const c=((s=(await m.auth.getUser()).data.user)==null?void 0:s.id)??null,{error:n}=await m.from("prompt_templates").upsert([{key:W,content:o,updated_by:c}],{onConflict:"key"});if(n)throw n;d.success("Video generation prompt saved")}catch(c){w(c)||d.error(c.message||"Failed to save prompt")}finally{f(!1)}};return x?e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground py-8",children:[e.jsx(g,{className:"w-4 h-4 animate-spin"})," Loading promptâ¦"]}):e.jsxs("div",{className:"space-y-6 max-w-4xl",children:[e.jsx("div",{className:"text-sm text-muted-foreground space-y-1",children:e.jsx("p",{children:"This is the standard prompt used to generate videos from ideas (all providers). Saving takes effect immediately for every new video submission. Storyboard videos use their own script prompt."})}),e.jsx(C,{value:o,onChange:s=>i(s.target.value),rows:26,className:"font-mono text-xs",spellCheck:!1}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"text-sm font-medium",children:"Placeholders"}),e.jsx("ul",{className:"text-sm text-muted-foreground space-y-1",children:ve.map(([s,c])=>e.jsxs("li",{children:[e.jsx("code",{className:"px-1 rounded bg-muted",children:s})," â ",c]},s))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Empty placeholders collapse cleanly, so blank lines are removed automatically."})]}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs(h,{onClick:y,disabled:u,children:[u?e.jsx(g,{className:"w-4 h-4 mr-2 animate-spin"}):e.jsx(P,{className:"w-4 h-4 mr-2"}),"Save prompt"]}),e.jsxs(h,{variant:"outline",onClick:()=>i(Q),disabled:u,children:[e.jsx(F,{className:"w-4 h-4 mr-2"}),"Reset to default"]})]})]})}function O({value:o}){return e.jsx(p,{className:"text-right font-mono text-sm",children:e.jsxs("span",{className:o>=0?"text-green-500":"text-destructive",children:["$",o.toFixed(2)]})})}function Ne({plan:o}){const i={pro:"bg-primary/15 text-primary",growth:"bg-blue-500/15 text-blue-400",starter:"bg-orange-500/15 text-orange-400",free:"bg-muted text-muted-foreground"};return e.jsx("span",{className:`text-[10px] px-1.5 py-0.5 rounded font-medium ${i[o]??i.free}`,children:o})}function tt(){const{isAdmin:o,metaReady:i}=te(),x=se(),[b,u]=r.useState([]),[f,y]=r.useState(!0),[s,c]=r.useState(null),[n,v]=r.useState(null),[N,_]=r.useState(!1),[E,T]=r.useState("5"),[D,H]=r.useState(!1),[U,$]=r.useState(!1);r.useEffect(()=>{if(i){if(!o){x("/brands");return}R()}},[o,i,x]);const R=async()=>{y(!0);try{const{data:t,error:a}=await m.functions.invoke("admin-stats");if(a)throw a;u((t==null?void 0:t.users)??[])}catch(t){w(t)||d.error(t.message||"Failed to load admin stats")}
87finally{y(!1)}},J=async t=>{const a=parseFloat(E);if(isNaN(a)||a<=0){d.error("Enter a valid amount");return}c(t);try{const{error:j}=await m.functions.invoke("admin-stats",{body:{action:"add_credits",userId:t,amount:a}});if(j)throw j;d.success(`Added ${a} credits`),await R()}catch(j){w(j)||d.error(j.message||"Failed to add credits")}finally{c(null)}},Z=async()=>{if(window.confirm("Fail every queued or in-progress job (storyboards, images, videos, landing pages)? Users will need to retry them.")){_(!0);try{const{data:t,error:a}=await m.functions.invoke("admin-clear-stuck",{body:{}});if(a)throw a;const j=Number(t==null?void 0:t.total)||0;d.success(j?`Cleared ${j} stuck job${j===1?"":"s"}`:"Nothing was stuck")}catch(t){if(w(t))return;d.error(t instanceof Error?t.message:"Could not clear stuck jobs")}finally{_(!1)}}};return!i||!o?null:e.jsx(re,{children:e.jsxs("div",{className:"w-full px-4 sm:px-6 space-y-6",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Admin Dashboard"}),e.jsxs(le,{defaultValue:"users",className:"w-full",children:[e.jsx("div",{className:"-mx-4 px-4 sm:mx-0 sm:px-0",children:e.jsxs(de,{className:"grid h-auto w-full grid-cols-2 gap-1 p-1 sm:inline-flex sm:h-10 sm:w-max sm:min-w-full sm:justify-start sm:gap-0",children:[e.jsx(k,{value:"users",children:"Users"}),e.jsx(k,{value:"meta",children:"Meta"}),e.jsx(k,{value:"video-script-prompt",className:"h-auto min-h-10 whitespace-normal leading-tight",children:"Video Script Prompt"}),e.jsx(k,{value:"storyboard-prompt",className:"h-auto min-h-10 whitespace-normal leading-tight",children:"Storyboard Prompt"}),e.jsx(k,{value:"video-generation-prompt",className:"h-auto min-h-10 whitespace-normal leading-tight",children:"Video Generation Prompt"}),e.jsx(k,{value:"start-frame-prompt",className:"h-auto min-h-10 whitespace-normal leading-tight",children:"Starting Frame Prompt"})]})}),e.jsxs(S,{value:"users",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:Z,disabled:N,children:[N?e.jsx(g,{className:"w-4 h-4 mr-2 animate-spin"}):e.jsx(z,{className:"w-4 h-4 mr-2"}),"Clear stuck jobs"]}),e.jsx(A,{to:"/admin/templates",children:e.jsxs(h,{variant:"outline",size:"sm",children:[e.jsx(he,{className:"w-4 h-4 mr-2"}),"Templates"]})}),e.jsx(A,{to:"/admin/stripe",children:e.jsxs(h,{variant:"outline",size:"sm",children:[e.jsx(ne,{className:"w-4 h-4 mr-2"}),"Stripe"]})}),e.jsx(A,{to:"/admin/credits",children:e.jsxs(h,{variant:"outline",size:"sm",children:[e.jsx(pe,{className:"w-4 h-4 mr-2"}),"Credits"]})}),e.jsx(A,{to:"/admin/deploy",children:e.jsxs(h,{variant:"outline",size:"sm",children:[e.jsx(ue,{className:"w-4 h-4 mr-2"}),"Deploy"]})}),e.jsxs(h,{variant:"destructive",size:"sm",disabled:D,onClick:async()=>{H(!0);try{const{data:t,error:a}=await m.functions.invoke("admin-stats",{body:{action:"cancel_stale"}});if(a)throw a;d.success(`Cancelled ${t.cancelled} stale jobs (${t.images} images, ${t.videos} videos)`),await R()}catch(t){w(t)||d.error(t.message||"Failed to cancel stale jobs")}finally{H(!1)}},children:[D?e.jsx(g,{className:"w-4 h-4 mr-2 animate-spin"}):e.jsx(z,{className:"w-4 h-4 mr-2"}),"Cancel Stale"]}),e.jsxs(h,{variant:"outline",size:"sm",disabled:U,onClick:async()=>{$(!0);try{const{data:t,error:a}=await m.functions.invoke("dedup-reference-images");if(a)throw a;d.success(`Dedup complete: ${t.duplicates_found} duplicates found, ${t.deleted} deleted (from ${t.total_assets} total)`)}catch(t){w(t)||d.error(t.message||"Dedup failed")}finally{$(!1)}},children:[U?e.jsx(g,{className:"w-4 h-4 mr-2 animate-spin"}):e.jsx(V,{className:"w-4 h-4 mr-2"}),"Dedup Images"]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:R,disabled:f,children:[e.jsx(V,{className:`w-4 h-4 mr-2 ${f?"animate-spin":""}`}),"Refresh"]})]}),f?e.jsx("div",{className:"flex items-center justify-center py-20",children:e.jsx(g,{className:"w-6 h-6 animate-spin text-muted-foreground"})}):e.jsx("div",{className:"border border-border rounded-lg overflow-x-auto",children:e.jsxs(ie,{children:[e.jsx(oe,{children:e.jsxs(I,{children:[e.jsx(l,{children:"Email"}),e.jsx(l,{children:"Plan"}),e.jsx(l,{className:"text-right",children:"$/Credit"}),e.jsx(l,{className:"text-right",children:"Total Profit"}),e.jsx(l,{className:"text-right",children:"Img Profit"}),e.jsx(l,{className:"text-right",children:"Vid Profit"}),e.jsx(l,{className:"text-right",children:"Anim Profit"}),e.jsx(l,{className:"text-right",children:"Images"}),e.jsx(l,{className:"text-right",children:"Img User$"}),e.jsx(l,{className:"text-right",children:"Img Cost"}),e.jsx(l,{className:"text-right",children:"Videos"}),e.jsx(l,{className:"text-right",children:"Vid User$"}),e.jsx(l,{className:"text-right",children:"Vid Cost"}),e.jsx(l,{className:"text-right",children:"Anims"}),e.jsx(l,{className:"text-right",children:"Anim User$"}),e.jsx(l,{className:"text-right",children:"Anim Cost"}),e.jsx(l,{className:"text-right",children:"Total Cost"}),e.jsx(l,{className:"text-right",children:"Credits"}),e.jsx(l,{children:"Actions"})]})}),e.jsxs(ce,{children:[b.map(t=>e.jsxs(I,{children:[e.jsxs(p,{className:"font-medium text-sm whitespace-nowrap",children:[t.email,t.role==="admin"&&e.jsx("span",{className:"ml-2 text-xs bg-primary/10 text-primary px-1.5 py-0.5 rounded",children:"admin"})]}),e.jsx(p,{children:e.jsx(Ne,{plan:t.plan})}),e.jsxs(p,{className:"text-right font-mono text-sm",children:["$",t.credit_price.toFixed(4)]}),e.jsx(O,{value:t.total_profit}),e.jsx(O,{value:t.image_profit}),e.jsx(O,{value:t.video_profit}),e.jsx(O,{value:t.anim_profit??0}),e.jsx(p,{className:"text-right font-mono text-sm",children:t.image_count}),e.jsxs(p,{className:"text-right font-mono text-sm",children:["$",(t.user_image_cost??0).toFixed(2)]}),e.jsxs(p,{className:"text-right font-mono text-sm",children:["$",t.image_cost.toFixed(2)]}),e.jsx(p,{className:"text-right font-mono text-sm",children:t.video_count}),e.jsxs(p,{className:"text-right font-mono text-sm",children:["$",(t.user_video_cost??0).toFixed(2)]}),e.jsxs(p,{className:"text-right font-mono text-sm",children:["$",t.video_cost.toFixed(2)]}),e.jsx(p,{className:"text-right font-mono text-sm",children:t.anim_count}),e.jsxs(p,{className:"text-right font-mono text-sm",children:["$",(t.user_anim_cost??0).toFixed(2)]}),e.jsxs(p,{className:"text-right font-mono text-sm",children:["$",t.anim_cost.toFixed(2)]}),e.jsxs(p,{className:"text-right font-mono text-sm font-semibold",children:["$",t.total_cost.toFixed(2)]}),e.jsx(p,{className:"text-right font-mono text-sm",children:Number(t.credits_remaining??t.balance??0).toFixed(1)}),e.jsx(p,{children:e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(ae,{type:"number",step:"1",min:"1",defaultValue:"5",className:"w-20 h-7 text-xs",onChange:a=>T(a.target.value)}),e.jsxs(h,{size:"sm",variant:"outline",className:"h-7 text-xs gap-1",disabled:s===t.id,onClick:()=>J(t.id),children:[s===t.id?e.jsx(g,{className:"w-3 h-3 animate-spin"}):e.jsx(fe,{className:"w-3 h-3"}),"Add"]}),e.jsxs(h,{size:"sm",variant:"secondary",className:"h-7 text-xs gap-1",disabled:n===t.id,onClick:async()=>{v(t.id);try{const{data:a,error:j}=await m.functions.invoke("admin-stats",{body:{action:"impersonate",userId:t.id}});if(j)throw j;if(!(a!=null&&a.access_token))throw new Error("No session returned");await m.auth.setSession({access_token:a.access_token,refresh_token:a.refresh_token}),localStorage.removeItem("viib-active-brand"),x("/brands"),window.location.reload()}catch(a){w(a)||d.error(a.message||"Failed to login as user")}finally{v(null)}},children:[n===t.id?e.jsx(g,{className:"w-3 h-3 animate-spin"}):e.jsx(ge,{className:"w-3 h-3"}),"Login"]})]})})]},t.id)),b.length===0&&e.jsx(I,{children:e.jsx(p,{colSpan:19,className:"text-center text-muted-foreground py-8",children:"No users found"})})]})]})})]}),e.jsx(S,{value:"meta",className:"mt-4",children:e.jsx(me,{})}),e.jsx(S,{value:"video-script-prompt",className:"mt-4",children:e.jsx(xe,{})}),e.jsx(S,{value:"storyboard-prompt",className:"mt-4",children:e.jsx(ye,{})}),e.jsx(S,{value:"video-generation-prompt",className:"mt-4",children:e.jsx(we,{})}),e.jsx(S,{value:"start-frame-prompt",className:"mt-4",children:e.jsx(je,{})})]})]})})}export{tt 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.