PageSourceSearch

https://app.laurenvestal.com/assets/_authenticated.coach.strength.templates-1H-RzGAm.js

js laurenvestal.com collected 2026-10-05 00:41:49 UTC 8,910 bytes, 1 lines download raw bytes

1import{r,j as e,t as d}from"./index-C4omiYqX.js";import{u as E}from"./useQuery-B6SrqyHC.js";import{u as o}from"./auth-middleware--nUBr2fg.js";import{e as J,f as M,h as X,i as Y,j as Z,k as ee,m as se}from"./strength.functions-CBjQIFC0.js";import{C as V,c as z,a as te,b as ae}from"./card-CJ6v28i6.js";import{B as l}from"./button-TrljJ5s5.js";import{I as i}from"./input-C0JNkts8.js";import{L as n}from"./label-CZ4oxKpO.js";import{T as k}from"./textarea-KvQo3VR8.js";import{D as u,b as h,c as j,d as g,f as b}from"./dialog-CcJe2LNk.js";import{B as re}from"./badge-CWkA7KXd.js";import{d as ne}from"./csv-download-BAiM10AP.js";import{U as le}from"./upload-BuEe_myq.js";import{P as oe}from"./plus-Cocdt-EX.js";import{D as ie}from"./download-CqiypLkL.js";import{P as ce}from"./pencil-0bLtVatm.js";import{T as de}from"./trash-2-DAG9djwc.js";import"./utils-C4zmdnH3.js";import"./index-DViK8mMC.js";import"./index-BB7I2wRt.js";import"./index-YUTg012B.js";import"./index-BgAjSVG2.js";import"./index-CFOV8CDV.js";import"./index-Cf_woGl9.js";import"./x-BT-IK6ww.js";import"./createLucideIcon-BgoXvqI6.js";function Ee(){const O=o(ee),B=o(X),U=o(Z),R=o(M),H=o(se),K=o(J),Q=o(Y),{data:S,isLoading:T,refetch:x}=E({queryKey:["strength-templates"],queryFn:()=>O()}),[A,v]=r.useState(!1),[f,_]=r.useState(""),[F,D]=r.useState(""),[I,$]=r.useState(""),[a,c]=r.useState(null),[p,L]=r.useState(null),[G,y]=r.useState(!1),[w,P]=r.useState(""),[W,q]=r.useState(""),[C,N]=r.useState(""),m=E({queryKey:["strength-template",p],queryFn:()=>H({data:{id:p}}),enabled:!!p});return e.jsxs("div",{className:"max-w-4xl mx-auto p-4 md:p-6 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-2",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-semibold",children:"Strength templates"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Reusable workouts you can drop into any client's plan. Save one from any workout's ⋯ menu, or start fresh here and then add blocks in the client editor."})]}),e.jsxs("div",{className:"flex gap-2 flex-wrap",children:[e.jsxs(l,{variant:"outline",onClick:()=>{P(""),q(""),N(""),y(!0)},children:[e.jsx(le,{className:"h-4 w-4 mr-1"})," Upload CSV"]}),e.jsxs(l,{onClick:()=>{_(""),D(""),$(""),v(!0)},children:[e.jsx(oe,{className:"h-4 w-4 mr-1"})," New template"]})]})]}),T?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"}):null,!T&&(S??[]).length===0?e.jsx(V,{children:e.jsx(z,{className:"py-8 text-center text-sm text-muted-foreground",children:"No templates yet."})}):null,e.jsx("div",{className:"grid gap-3 md:grid-cols-2",children:(S??[]).map(s=>e.jsxs(V,{children:[e.jsxs(te,{className:"flex flex-row items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(ae,{className:"text-base",children:s.name}),e.jsxs("div",{className:"text-xs text-muted-foreground mt-1",children:[s.category?e.jsx(re,{variant:"secondary",className:"mr-2",children:s.category}):null,s.block_count," blocks · ",s.exercise_count," exercises"]})]}),e.jsxs("div",{className:"flex gap-1",children:[e.jsx(l,{size:"sm",variant:"ghost",onClick:()=>L(s.id),children:"Preview"}),e.jsx(l,{size:"sm",variant:"ghost",title:"Download CSV",onClick:async()=>{const t=await K({data:{templateId:s.id}});ne(`${s.name.replace(/[^a-z0-9]+/gi,"_")}.csv`,t)},children:e.jsx(ie,{className:"h-4 w-4"})}),e.jsx(l,{size:"sm",variant:"ghost",onClick:()=>c({id:s.id,name:s.name,category:s.category??"",notes:s.notes??""}),children:e.jsx(ce,{className:"h-4 w-4"})}),e.jsx(l,{size:"sm",variant:"ghost",className:"text-destructive",onClick:async()=>{confirm(`Delete template "${s.name}"?`)&&(await R({data:{id:s.id}}),d.success("Template deleted"),x())},children:e.jsx(de,{className:"h-4 w-4"})})]})]}),s.notes?e.jsx(z,{children:e.jsx("p",{className:"text-sm text-muted-foreground whitespace-pre-line",children:s.notes})}):null]},s.id))}),e.jsx(u,{open:A,onOpenChange:v,children:e.jsxs(h,{children:[e.jsx(j,{children:e.jsx(g,{children:"New template"})}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx(n,{children:"Name"}),e.jsx(i,{value:f,onChange:s=>_(s.target.value),placeholder:"e.g., Warm-up + Foam roll"})]}),e.jsxs("div",{children:[e.jsx(n,{children:"Category (optional)"}),e.jsx(i,{value:F,onChange:s=>D(s.target.value),placeholder:"Warm-up, Cool-down, Full session…"})]}),e.jsxs("div",{children:[e.jsx(n,{children:"Notes (optional)"}),e.jsx(k,{rows:3,value:I,onChange:s=>$(s.target.value)})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:`Tip: the fastest way to build a template is to author it once in a client's plan, then use "Save as template…" from the workout's ⋯ menu.`})]}),e.jsx(b,{children:e.jsx(l,{disabled:!f.trim(),onClick:async()=>{await B({data:{name:f.trim(),category:F.trim()||null,notes:I.trim()||null}}),v(!1),x(),d.success("Template created")},children:"Create"})})]})}),e.jsx(u,{open:G,onOpenChange:y,children:e.jsxs(h,{className:"max-w-2xl",children:[e.jsx(j,{children:e.jsx(g,{children:"Upload CSV to new template"})}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx(n,{children:"Template name"}),e.jsx(i,{value:w,onChange:s=>P(s.target.value),placeholder:"e.g., Standard warm-up"})]}),e.jsxs("div",{children:[e.jsx(n,{children:"Category (optional)"}),e.jsx(i,{value:W,onChange:s=>q(s.target.value)})]}),e.jsxs("div",{children:[e.jsx(n,{children:"CSV file"}),e.jsx(i,{type:"file",accept:".csv,text/csv",onChange:async s=>{const t=s.target.files?.[0];t&&N(await t.text())}})]}),e.jsxs("div",{children:[e.jsx(n,{children:"Or paste CSV"}),e.jsx(k,{rows:6,value:C,onChange:s=>
1N(s.target.value),placeholder:"block_order,block_title,structure,rounds,block_notes,exercise_order,exercise_name,library_slug,sets,reps,rest_seconds,tempo,target_load,equipment,exercise_notes"})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Tip: download an existing workout or template as CSV first to see the expected columns. Equipment can be a semicolon-separated list. Rows sharing a ",e.jsx("code",{children:"block_order"})," become one block; structure/rounds/title/notes come from the first row of each group."]})]}),e.jsx(b,{children:e.jsx(l,{disabled:!w.trim()||!C.trim(),onClick:async()=>{try{const s=await Q({data:{name:w.trim(),category:W.trim()||null,csv:C}});d.success(`Imported ${s.blocks} blocks, ${s.exercises} exercises`),s.warnings?.length&&d.warning(s.warnings.slice(0,3).join(" · ")),y(!1),x()}catch(s){d.error(s?.message??"Import failed")}},children:"Import"})})]})}),e.jsx(u,{open:!!a,onOpenChange:s=>!s&&c(null),children:e.jsxs(h,{children:[e.jsx(j,{children:e.jsx(g,{children:"Edit template"})}),a?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx(n,{children:"Name"}),e.jsx(i,{value:a.name,onChange:s=>c({...a,name:s.target.value})})]}),e.jsxs("div",{children:[e.jsx(n,{children:"Category"}),e.jsx(i,{value:a.category,onChange:s=>c({...a,category:s.target.value})})]}),e.jsxs("div",{children:[e.jsx(n,{children:"Notes"}),e.jsx(k,{rows:3,value:a.notes,onChange:s=>c({...a,notes:s.target.value})})]})]}),e.jsx(b,{children:e.jsx(l,{disabled:!a.name.trim(),onClick:async()=>{await U({data:{id:a.id,name:a.name.trim(),category:a.category.trim()||null,notes:a.notes.trim()||null}}),c(null),x(),d.success("Saved")},children:"Save"})})]}):null]})}),e.jsx(u,{open:!!p,onOpenChange:s=>!s&&L(null),children:e.jsxs(h,{className:"max-w-2xl",children:[e.jsx(j,{children:e.jsx(g,{children:m.data?.name??"Template"})}),e.jsxs("div",{className:"max-h-[65vh] overflow-y-auto space-y-3",children:[m.isLoading?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"}):null,(m.data?.blocks??[]).map(s=>e.jsxs("div",{className:"rounded-md border p-3",children:[e.jsxs("div",{className:"text-sm font-medium",children:[s.title||s.structure.replace("_"," "),e.jsxs("span",{className:"text-xs text-muted-foreground ml-2",children:[s.structure," · ",s.rounds," round",s.rounds>1?"s":""]})]}),s.notes?e.jsx("p",{className:"text-xs text-muted-foreground whitespace-pre-line mt-1",children:s.notes}):null,e.jsx("ul",{className:"mt-2 space-y-1 text-sm",children:s.exercises.map(t=>e.jsxs("li",{children:[e.jsx("span",{className:"font-medium",children:t.name_override||t.library_title||"Exercise"}),e.jsxs("span",{className:"text-muted-foreground",children:[t.sets?` · ${t.sets}x${t.reps??""}`:t.reps?` · ${t.reps}`:"",t.target_load?` · ${t.target_load}`:"",t.rest_seconds?` · rest ${t.rest_seconds}s`:"",t.tempo?` · tempo ${t.tempo}`:""]})]},t.id))})]},s.id)),!m.isLoading&&(m.data?.blocks??[]).length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"This template has no blocks yet. The easiest way to add blocks is to instantiate it into a client's week, edit there, then re-save as a new template."}):null]})]})})]})}export{Ee as component};

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.