1import{j as e,r as o,B as N,c as be,t as Je,M as Ce,E as ue,u as Bt,d as Ft,S as Ze,x as bt,f as Tt,q as Rt,T as Dt,h as Ht,a as Ut,g as qt,e as Gt,z as lt,l as Kt,L as Yt,a5 as Vt,I as Wt}from"./index-_aijvlUq.js";import{u as Jt,P as Zt}from"./PageHeader-DCofr6qo.js";import{T as Xt}from"./Tabs-CGDUdv1I.js";import{M as H}from"./Menu-CATQC14B.js";import{p as q}from"./performances-duTJPchz.js";import{m as dt}from"./musicLibrary-DdhMEkq5.js";import{p as Ge,a as Qt,b as es,t as yt,l as ts,i as zt,A as tt,s as ss,P as ns,c as as,d as rs,C as ls,B as is}from"./FolderCheckoutSheet-D3PRcF2e.js";import{I as Ee}from"./Input-ysTyZFq5.js";import{I as os}from"./InstrumentsFromPhotoModal--KDh5F6z.js";import{C as ds}from"./ChipToggle-hmCaOMqs.js";import{E as $e}from"./EmptyState-CPGKooqj.js";import{m as cs}from"./members-I3UAoZ9P.js";import{b as Ot}from"./badges-sJrwZCWE.js";import{B as ms}from"./BottomSheet-BiQNSujt.js";import{C as ht}from"./ConfirmDialog-CODvETNM.js";import{g as pt,s as us,S as hs,a as jt,b as ct,c as Nt,d as ps,n as te,h as xs,f as gs,i as st,r as it,e as kt,j as vt,k as fs,l as bs,m as ys}from"./folderCustody-0jTNtNbN.js";import{F as xt,a as wt}from"./FolderHolder-a1wRvI5n.js";import{W as js}from"./WizardShell-BAf42hnX.js";import{b as Ns}from"./Table-Yng-lqpt.js";import{u as ks}from"./useDragReorder-BPTlhWx5.js";import{e as vs}from"./ensembles-WGlB365j.js";import"./Badge-DJIi163x.js";import"./PrintSheet-BwuplKw5.js";import"./CameraCaptureButton-B4WpiVvJ.js";import"./downscaleImage-qyGK-a3D.js";const V=Object.freeze({expandAll:"Open every piece to see its parts",collapseAll:"Close every piece",markPulled:"Tick this piece once its copies are out of the cabinet",pulled:"Pulled from the cabinet; tap again to untick it",markAllPulled:"Tick every piece as pulled from the cabinet",clearPulled:"Untick every piece",printPull:"Print the cabinet walk: what to pull and how many, in cabinet order",build:"Deal every piece into numbered folders from the seating chart",update:"Re-deal the folders for todayâs program and seating, then tap Print changes sheet on the Folders tab for what to add or take out",addFolders:"Add a folder for each instrument nobody is seated on",notPacked:"Show only folders with something still to pack",printChanges:"Print what changed since the last build, to work from at the shelf",acknowledge:"Clear this note once the shelf matches; folders no longer needed and back in the bin come off the board",state_built:"Show only folders in the bin",state_out:"Show only folders out with a player",state_returned:"Show only folders checked in after the concert",state_missing:"Show only folders that did not come back",packNext:"Open the next folder that still has something to pack",handOut:"Check every folder out to its assigned player in one go",printBuild:"Print every folder with its pieces to tick as you pack",printCheckout:"Print every folder with who has it, Out and Back boxes, and a by-name page for the music box",printLabels:"Print folder labels: new folders only, every folder, or a list of numbers",checkIn:"Take the roll call: tap the folders that are not back",share:"Let section leaders see and hand out their sectionâs folders in My Section",unshare:"Hide the folders from section leaders while you change them",chooseParts:"Say which printed part goes in each seatâs folder for this piece",count:"Record how many copies of each part you own: as printed, or count by hand",short:"Not enough copies for every folder: make copies, players share, or mark on order",scan:"Read the instrument list off a photo of the scoreâs first page",rescan:"Read the instrument list again; a part did not match an instrument",moreRow:"Other things you can do with this piece",auxDetails:"Show which instruments the program calls for with nobody seated",percDetails:"Show the percussion stations and instruments the program calls for"});function ws(t,{castByDefault:n=!1,canWrite:a=!1,laneFolders:m=null}={}){const d=Ge(t),g=Qt(t,m),k=es(d),p=t.readiness?.state||(d.length===0?"not_scanned":"ready"),l=d.filter(b=>b.uncounted).length,S=d.filter(b=>b.shortfall>0),w=S.filter(b=>!b.resolution).length,f=d.length>0,C=!!t.allAlreadyIn,c=!!t.pulledAt||C,u=p==="ready"&&f&&a,L=u&&(n||t.castSeats>0),G=p==="ready"&&f&&l===0&&w===0&&c;let I=null;p==="not_scanned"?I="not_scanned":p==="needs_attention"?I="needs_attention":w>0?I="short":l>0&&(I="uncounted");let T=null;p==="not_scanned"&&a?T="scan":p==="needs_attention"&&a?T="rescan":n&&u&&!t.castSeats&&!c&&I==null&&(T="choose");const v=[];
1L&&T!=="choose"&&v.push("choose"),l>0&&I!=="uncounted"&&a&&v.push("count");const j=[];if(d.length===0)j.push(p==="not_scanned"?"":"Nothing to pull");else if(C)j.push(`Already in the folders for ${t.alreadyInFrom||"another concert"}`);else{j.push(`Pull ${k.pull}${g.length?` (${g.length} percussion)`:""}`);const b=d.reduce(($,_)=>$+(Number(_.alreadyIn)||0),0);b>0&&j.push(`${b} already in the folders`),k.needMore>0?j.push(`${k.needMore} ${k.needMore===1?"copy":"copies"} short${w===0&&S.length>0?", decided":""}`):S.length>0&&w===0&&j.push("short copies decided")}const h=j.filter(Boolean).join(" · ");return{rows:d,perc:g,t:k,state:p,uncounted:l,shortRows:S,undecided:w,pullable:f,pulled:c,done:G,chip:I,next:T,more:v,summary:h,castOffered:L}}function Cs(t,{shortCount:n=0,uncounted:a=0,rowCount:m=0}={}){switch(t){case"not_scanned":return{text:"Not scanned",tone:"amber"};case"needs_attention":return{text:"Needs a look",tone:"amber"};case"short":return{text:`Short ${n}`,tone:"red"};case"uncounted":return{text:a===m?"Not counted":`${a} not counted`,tone:"gray"};default:return null}}const Ct={solo:"solo = first folder only",doubling:"+ instrument = doubling book, also goes in those folders",via:"for instrument = no part of its own, this one stands in",all:"everyone = no part number printed, one per player",wrap:"wraps = extra copies for folders with no part of their own",ladder:"chair n = trumpet ladder",shared:"one of these = players read one version, counts do not add"};function $s(t,n){const a=t.instrumentName;return(n||[]).some(m=>m!==t&&!m.hbLadder&&a&&m.instrumentName===a&&m.numbers?.length)}function Ss(t,n){const a=[],m=t.servesInstrumentName||t.instrumentName||"";return t.solo&&a.push({key:"solo",label:"solo",cls:"bg-gray-100 text-gray-700",hint:`Solo part: one copy, first ${m} folder only.`}),t.alsoServes?.length&&a.push({key:"doubling",label:`+ ${t.alsoServes.map(d=>d.instrumentName).join(", ")}`,cls:"bg-sky-100 text-sky-800",hint:`Doubling book: also goes in the ${t.alsoServes.map(d=>d.instrumentName).join(" and ")} folders.`}),t.viaEquivalent&&a.push({key:"via",label:`for ${t.viaEquivalent}`,cls:"bg-sky-100 text-sky-800",hint:`No ${t.viaEquivalent} part in this set: this goes in the ${t.viaEquivalent} folders.`}),t.assumed&&!t.solo&&!t.hbLadder&&(n===void 0||$s(t,n))&&a.push({key:"all",label:"everyone",cls:"bg-amber-100 text-amber-800",hint:`No part number printed: pull enough for everyone on ${m}.`}),t.wrapped&&a.push({key:"wrap",label:"wraps",cls:"bg-sky-100 text-sky-800",hint:"Includes extra copies for folders that have no part of their own."}),t.hbLadder&&a.push({key:"ladder",label:`chair ${(t.hbParts||[]).join(", ")||"none"}`,cls:"bg-violet-100 text-violet-800",hint:`Cornet and Trumpet share one set of chairs: this book goes to chair ${(t.hbParts||[]).join(", ")||"none (more books than chairs)"}.`}),t.sharedDemand&&a.push({key:"shared",label:"one of these",cls:"bg-gray-100 text-gray-600",hint:"Players use one of these versions: do not add the counts together."}),a}function Is(t){const n=new Set(t.flat().map(a=>a.key));return Object.keys(Ct).filter(a=>n.has(a)).map(a=>Ct[a]).join(" · ")}function nt({children:t,strong:n}){return e.jsx("span",{className:`tabular-nums ${n?"font-semibold text-gray-900":"text-gray-600"}`,children:t})}function $t({row:t}){return t.uncounted?e.jsxs("span",{className:"text-gray-400",title:"Never counted â not the same as zero",children:["â ",e.jsx("span",{className:"text-[10px] uppercase tracking-wide",children:"not counted"})]}):t.shortfall>0?e.jsx("span",{className:"text-red-700 font-semibold tabular-nums",title:`Need ${t.shortfall} more`,children:t.copiesOnHand}):e.jsx(nt,{children:t.copiesOnHand})}function St({row:t}){return t.uncounted?e.jsx("span",{className:"text-xs text-gray-400",children:"not counted"}):t.shortfall>0?e.jsxs("span",{className:"text-xs font-medium text-red-700 whitespace-nowrap",children:["have ",t.copiesOnHand," · short ",t.shortfall]}):e.jsxs("span",{className:"text-xs text-gray-500 whitespace-nowrap",children:["have ",t.copiesOnHand]})}function It({list:t,className:n=""}){return t.map(a=>e.jsx("span",{title:a.hint,className:`inline-flex items-center px-1.5 py-0.5 rounded-full text-xs font-medium ${a.cls} ${n}`,children:a.label},a.key))}const Ps={share:"Players share",ordered:"On order"};function Ls({piece:t,row:n,canWrite:a,busyKey:m,onResolve:d,onMadeCopies:g}
1){const[k,p]=o.useState(!1),[l,S]=o.useState(String(n.needed??""));if(!(n.shortfall>0))return null;const w=m===`res:${t.id}|${n.rawLabel}`,f="min-h-[2.75rem] md:min-h-[2.25rem]";if(n.resolution)return e.jsxs("span",{className:"flex flex-wrap items-center justify-end gap-2 text-sm","data-testid":`decided-${n.rawLabel}`,children:[e.jsxs("span",{className:"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 whitespace-nowrap",children:["â ",Ps[n.resolution]||n.resolution]}),a&&e.jsx(N,{type:"button",variant:"ghost",size:"sm",className:f,isLoading:w,onClick:()=>d?.(t.id,n.rawLabel,null),children:"Change"})]});if(!a)return e.jsxs("span",{className:"block text-sm text-red-700 whitespace-nowrap",children:["Short ",n.shortfall," â no decision yet"]});if(k){const C=parseInt(l,10);return e.jsxs("span",{className:"flex flex-wrap items-center justify-end gap-2",children:[e.jsx(Ee,{type:"number",min:0,max:999,step:1,inputMode:"numeric","aria-label":`Copies of ${n.rawLabel} on hand now`,value:l,onChange:c=>S(c.target.value),className:"!w-24 !text-base"}),e.jsx(N,{type:"button",size:"sm",variant:"primary",className:f,isLoading:w,disabled:!Number.isInteger(C)||C<0,onClick:()=>g?.(t.id,n.rawLabel,C),children:"Save count"}),e.jsx(N,{type:"button",size:"sm",variant:"ghost",className:f,onClick:()=>p(!1),children:"Cancel"})]})}return e.jsx("span",{className:"inline-flex","data-testid":`decide-${n.rawLabel}`,children:e.jsxs(H,{align:"right",menuId:`short-${t.id}-${n.rawLabel.replace(/[^a-z0-9]+/gi,"-")}`,trigger:e.jsxs(N,{type:"button",size:"sm",variant:"secondary",className:`${f} whitespace-nowrap`,isLoading:w,children:["Short ",n.shortfall]}),children:[e.jsx(H.Item,{onClick:()=>p(!0),children:"Made copiesâ¦"}),e.jsx(H.Item,{onClick:()=>d?.(t.id,n.rawLabel,"share"),children:"Players share"}),e.jsx(H.Item,{onClick:()=>d?.(t.id,n.rawLabel,"ordered"),children:"On order"})]})})}function As(t,n){const a=[];n.length===0&&t.readiness?.state==="not_scanned"&&a.push({key:"ns",cls:"text-gray-400",text:"Not scanned yet â Scan instruments⦠on the row lists the parts."}),n.length===0&&t.readiness?.state!=="not_scanned"&&a.push({key:"none",cls:"text-gray-500",text:"Nothing to pull â nobody is seated on the instruments this piece is written for."});const m=(t.parts||[]).filter(d=>d.alreadyIn>0);return m.length>0&&a.push({key:"in",cls:"text-gray-700",text:`Already in the folders for ${t.alreadyInFrom||"another concert"}, not pulled again: ${m.map(d=>d.alreadyIn<d.needed?`${d.rawLabel} (${d.alreadyIn} of ${d.needed} copies)`:d.rawLabel).join(", ")}`}),t.noFolderParts?.length>0&&a.push({key:"nf",cls:"text-gray-500",text:`Also in the set, not pulled (nobody seated): ${t.noFolderParts.map(d=>d.rawLabel).join(", ")}`}),t.separateParts?.length>0&&a.push({key:"sep",cls:"text-gray-500",text:`Available separately from the publisher, not in the box: ${t.separateParts.join(", ")}`}),a}function Ms({piece:t,rows:n,perc:a,totals:m,compact:d,canWrite:g=!1,busyKey:k=null,onResolve:p,onMadeCopies:l}){const S=u=>e.jsx(Ls,{piece:t,row:u,canWrite:g,busyKey:k,onResolve:p,onMadeCopies:l}),w=t.parts||[],f=w.map(u=>Ss(u,w)),C=Is(f),c=As(t,n);return d?e.jsxs("div",{id:`pull-piece-${t.id}`,"data-testid":`pull-parts-${t.id}`,children:[n.length>0&&e.jsxs("div",{className:"flex justify-between px-3 pt-1.5 pb-1 text-[11px] uppercase tracking-wide text-gray-400",children:[e.jsx("span",{children:"Part"}),e.jsx("span",{children:"Pull"})]}),e.jsxs("ul",{children:[w.map((u,L)=>e.jsxs("li",{className:"flex items-start justify-between gap-3 px-3 py-2 border-t border-gray-100",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-[15px] leading-snug text-gray-900",children:u.rawLabel}),f[L].length>0&&e.jsx("div",{className:"mt-1 flex flex-wrap gap-1",children:e.jsx(It,{list:f[L]})}),S(u)]}),e.jsxs("div",{className:"shrink-0 flex flex-col items-end",children:[e.jsx("span",{className:"text-base font-semibold tabular-nums text-gray-900",children:Math.max(0,(u.needed||0)-(u.alreadyIn||0))}),e.jsx(St,{row:u})]})]},u.rawLabel)),a.length>0&&e.jsx("li",{className:"px-3 py-1.5 border-t border-gray-200 bg-gray-50 text-xs font-semibold uppercase tracking-wide text-gray-500",children:"Percussion â one copy each"}),a.map(u=>e.jsxs("li",{className:"flex items-start justify-between gap-3 px-3 py-2 border-t border-gray-100",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-[15px] leading-snug text-gray-900",children:u.label}),u.folder&&e.jsxs("p",{className:"text-xs text-sky-800",children:["into ",u.folder]}),S(u)]}),e.jsxs("div",{className:"shrink-0 flex flex-col items-end",children:[e.jsx("span",{className:"text-base font-semibold tabular-nums text-gray-900",children:u.needed}),e.jsx(St,{row:u})]})]},`perc-${u.rawLabel}`)),c.map(u=>e.jsx("li",{className:`px-3 py-2 border-t border-gray-100 text-sm ${u.cls}`,children:u.text},u.key))]}),n.length>0&&e.jsxs("div",{className:"px-3 py-2 border-t border-gray-200 bg-gray-50 space-y-1",children:[C&&e.jsx("p",{className:"text-xs text-gray-500","data-testid":"badge-legend",children:C}),e.jsxs("p",{className:"text-sm font-semibold text-gray-700",children:["Total: ",yt(m)]})]})]}):e.jsxs("table",{id:`pull-piece-${t.id}`,"data-testid":`pull-parts-${t.id}`,className:"w-full text-base",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-[11px] uppercase tracking-wide text-gray-400",children:[e.jsx("th",{className:"text-left font-medium px-4 py-1.5",children:"Part"}),e.jsx("th",{className:"text-right font-medium px-3 py-1.5 whitespace-nowrap",children:"Folders needed"}),e.jsx("th",{className:"text-right font-medium px-3 py-1.5 whitespace-nowrap",children:"On hand"}),e.jsx("th",{className:"text-right font-medium px-3 py-1.5 whitespace-nowrap",children:"Set has"}),e.jsx("th",{className:"text-right font-medium px-4 py-1.5 whitespace-nowrap",children:"Short"})]})}),e.jsxs("tbody",{children:[w.map((u,L)=>e.jsxs("tr",{className:"border-t border-gray-100",children:[e.jsx("td",{className:"px-4 py-1",children:e.jsxs("span",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"text-base text-gray-900",children:u.rawLabel}),e.jsx(It,{list:f[L]})]})}),e.jsx("td",{className:"px-3 py-1 text-right",children:e.jsx(nt,{strong:!0,children:u.needed})}),e.jsx("td",{className:"px-3 py-1 text-right",children:e.jsx($t,{row:u})}),e.jsx("td",{className:"px-3 py-1 text-right",children:e.jsx(nt,{children:u.setCount??"â"})}),e.jsx("td",{className:"px-4 py-1 text-right whitespace-nowrap",children:S(u)})]},u.rawLabel)),a.length>0&&e.jsx("tr",{className:"border-t border-gray-200 bg-gray-50",children:e.jsx("td",{colSpan:5,className:"px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-gray-500",children:"Percussion â one copy of each, into its lane folder"})}),a.map(u=>e.jsxs("tr",{className:"border-t border-gray-100",children:[e.jsxs("td",{className:"px-4 py-1.5",children:[e.jsx("span",{className:"text-base text-gray-900",children:u.label}),u.label!==u.rawLabel&&e.jsx("span",{className:"ml-2 text-xs text-gray-400",children:u.rawLabel}),u.folder&&e.jsxs("span",{className:"ml-2 text-xs text-sky-800",children:["â ",u.folder]})]}),e.jsx("td",{className:"px-3 py-1 text-right",children:e.jsx(nt,{strong:!0,children:u.needed})}),e.jsx("td",{className:"px-3 py-1 text-right",children:e.jsx($t,{row:u})}),e.jsx("td",{className:"px-3 py-1 text-right",children:e.jsx(nt,{children:u.setCount??"â"})}),e.jsx("td",{className:"px-4 py-1 text-right whitespace-nowrap",children:S(u)})]},`perc-${u.rawLabel}`)),c.map(u=>e.jsx("tr",{children:e.jsx("td",{colSpan:5,className:`px-4 py-1.5 text-sm ${u.cls}`,children:u.text})},u.key))]}),n.length>0&&e.jsxs("tfoot",{children:[C&&e.jsx("tr",{className:"border-t border-gray-100",children:e.jsx("td",{colSpan:5,className:"px-4 py-1.5 text-xs text-gray-500","data-testid":"badge-legend",children:C})}),e.jsx("tr",{className:"border-t border-gray-200 bg-gray-50",children:e.jsxs("td",{colSpan:5,className:"px-4 py-1.5 text-sm font-semibold text-gray-700 text-right",children:["Total â ",yt(m)]})})]})]})}function Fs({isOpen:t,onClose:n,performanceId:a,musicId:m,pieceTitle:d=null,canWrite:g=!1,onChanged:k}){const{showError:p}=be(),[l,S]=o.useState(null),[w,f]=o.useState(!1),[C,c]=o.useState(null);o.useEffect(()=>{if(!t||!a||!m)return;let v=!1;return f(!0),q.getCasting(a,m).then(j=>{v||S(j)}).catch(()=>{v||p(Je("the parts for this piece"))}).finally(()=>{v||f(!1)}),()=>{v=!0}},[t,a,m]);async function u(v,j,h){const b=`${v.instrumentId}|${j.partNumber}|${j.copyIndex}`;c(b);try{const $=await q.setCasting(a,{musicId:m,instrumentId:v.instrumentId,partNumber:j.partNumber,copyIndex:j.copyIndex,rawLabels:h});S($),k?.($)}catch($){p($?.message||ue)}finally{c(null)}}const L=(v,j,h)=>{const $=j.labels.includes(h)?j.labels.filter(_=>_!==h):[...j.labels,h];return u(v,j,$)},G=(l?.sections||[]).flatMap(v=>v.coverage.filter(j=>j.folders===0).map(j=>`${v.instrumentName} ${j.partName}`)),I=v=>v===0?"nobody":v===1?"1 folder":`${v} folders`,T=`Choose parts â ${l?.piece?.title||d||""}`.replace(/ â $/,"");return e.jsx(Ce,{isOpen:t,onClose:n,title:T,size:"lg",footer:e.jsx("div",{className:"flex gap-2",children:e.jsx(N,{type:"button",variant:"ghost",onClick:n,children:"Close"})}),children:w||!l?e.jsx("p",{className:"text-sm text-gray-500",children:"Loadingâ¦"}):e.jsxs("div",{className:"space-y-5",children:[e.jsx("p",{className:"text-sm text-gray-600",children:"Tap a part to put it in that seat. Saves as you tap."}),e.jsx("p",{className:"text-sm","data-testid":"casting-coverage",children:G.length===0?e.jsx("span",{className:"text-gray-700",children:"Every part is in a folder."}):e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"font-medium text-red-700",children:"Nobody holds:"})," ",e.jsx("span",{className:"text-red-700",children:G.join(", ")})]})}),l.sections.length===0&&e.jsx($e,{size:"compact",title:"No seat matches a printed part of this piece."}),l.sections.map(v=>e.jsxs("section",{"aria-label":v.instrumentName,children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-500 uppercase tracking-wide mb-1",children:v.instrumentName}),e.jsx("p",{className:"text-xs text-gray-500 mb-2","data-testid":`coverage-${v.instrumentId}`,children:v.coverage.map((j,h)=>e.jsxs("span",{children:[h>0?" · ":"",j.partName,": ",e.jsx("span",{className:j.folders===0?"text-red-700 font-medium":"",children:I(j.folders)})]},j.rawLabel))}),e.jsx("ul",{className:"space-y-2",children:v.seats.map(j=>{const h=`${v.instrumentId}|${j.partNumber}|${j.copyIndex}`,b=C===h;return e.jsxs("li",{className:"flex flex-wrap items-center gap-2 rounded-lg border border-gray-200 px-3 py-2","data-testid":`seat-${h}`,"aria-busy":b||void 0,children:[e.jsxs("div",{className:"min-w-[10rem]",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900","data-testid":`seat-holder-${h}`,children:j.holderName||"Empty chair"}),e.jsxs("p",{className:"text-xs text-gray-500",children:[j.folderDisplay?`${j.folderDisplay} · `:"",j.label,j.cast?" · set by hand":""]}),g&&j.cast&&e.jsx(N,{type:"button",variant:"ghost",size:"sm",className:"-ml-3 mt-0.5",isLoading:b,onClick:()=>u(v,j,null),children:"Back to usual"})]}),e.jsxs("div",{className:"flex flex-wrap gap-1.5 flex-1",children:[v.o
1ptions.map($=>e.jsx(ds,{selected:j.labels.includes($.rawLabel),size:"md",disabled:!g||b,onClick:()=>L(v,j,$.rawLabel),children:$.partName},$.rawLabel)),j.labels.length===0&&e.jsx("span",{className:"text-xs text-gray-500 self-center",children:"nothing from this piece"})]})]},h)})})]},v.instrumentId)),e.jsx("p",{className:"text-xs text-gray-500",children:"Kept for the season and used each time folders are built. A seat can hold two parts; a part in two seats means two copies on the pull list."})]})})}function We({tone:t="gray",children:n,testId:a}){const m=t==="amber"?"bg-amber-100 text-amber-800":t==="red"?"bg-red-100 text-red-700":"bg-gray-100 text-gray-600";return e.jsx("span",{className:`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold whitespace-nowrap ${m}`,"data-testid":a,children:n})}function zs({data:t,performanceId:n,canWrite:a=!1,compact:m=!1,onChanged:d,primary:g=null,onPrimary:k,building:p=!1,aux:l=null,onAddAux:S,onPrint:w}){const{showSuccess:f,showError:C}=be(),c=Bt(),u=()=>d?.(),[L,G]=o.useState(null),I=t?.folderSettings?.folderDealing==="by_seat",[T,v]=o.useState(null);async function j(i){v(i);try{const z=await dt.countAsPrinted(i),B=z?.data?.data||z?.data||z;f(`${B?.counted??0} part${B?.counted===1?"":"s"} counted as printed${B?.skipped?.length?` â ${B.skipped.length} with no printed count left uncounted`:""}`),u()}catch(z){C(z?.message||"Could not record the counts")}finally{v(null)}}const[h,b]=o.useState(null);async function $(i,z,B){b(i);try{await z(),B&&f(B),u()}catch(X){C(X?.message||ue)}finally{b(null)}}const _=(i,z)=>$(`pulled:${i||"all"}`,()=>q.setPulled(n,i?{pulled:z,musicId:i}:{pulled:z}),i?null:z?"Every piece marked pulled.":"Pulled marks cleared."),U=(i,z,B)=>$(`res:${i}|${z}`,()=>q.setPartResolution(n,{musicId:i,rawLabel:z,kind:B})),Y=(i,z,B)=>$(`res:${i}|${z}`,()=>dt.setPartInventory(i,[{rawLabel:z,copiesOnHand:B}]),"Copies on hand updated."),ye=(i,z)=>$(`res:${i.id}|*`,async()=>{for(const B of Ge(i).filter(X=>X.shortfall>0&&!X.resolution))await q.setPartResolution(n,{musicId:i.id,rawLabel:B.rawLabel,kind:z})},z==="share"?"Players share the copies you have.":"Marked on order."),[Z,se]=o.useState(()=>new Set),ne=o.useRef(null);o.useEffect(()=>{ne.current!==n&&(ne.current=n,se(new Set))},[n]);const P=i=>se(z=>{const B=new Set(z);return B.has(i)?B.delete(i):B.add(i),B}),[A,K]=o.useState(!1),[D,he]=o.useState(!1),[Re,pe]=o.useState(null),[ie,Se]=o.useState(null),[Me,xe]=o.useState(!1);function Fe(i){const z=Ge(i).filter(B=>B.shortfall>0&&!B.resolution);Se({piece:i,rows:z,counts:Object.fromEntries(z.map(B=>[B.rawLabel,String(B.needed??(Number(B.copiesOnHand)||0)+B.shortfall)]))})}async function De(){if(!ie)return;const i=ie.rows.map(z=>({rawLabel:z.rawLabel,copiesOnHand:parseInt(ie.counts[z.rawLabel],10)}));if(i.some(z=>!Number.isInteger(z.copiesOnHand)||z.copiesOnHand<0)){C("Enter a count for each part");return}xe(!0);try{await dt.setPartInventory(ie.piece.id,i),f("Copies on hand updated."),Se(null),u()}catch(z){C(z?.message||ue)}finally{xe(!1)}}if(t===void 0)return e.jsx("p",{className:"text-sm text-gray-400 py-4",children:"Loadingâ¦"});if(t===null)return e.jsx("p",{className:"text-sm text-gray-400 py-4",children:"Couldnât load the pull list."});if(t.selfManaged)return e.jsx($e,{size:"compact",title:"This ensemble manages its own music.",description:"There is no librarian pull list for it."});const{pieces:ae,percussion:J,excluded:Q,needsAttention:ze}=t;if(!ae.length)return e.jsx($e,{size:"compact",title:"Nothing on the program yet.",description:"Add music to this concert, then come back to pull the parts."});const Ie=ae.filter(i=>Ge(i).length>0),Xe=Ie.filter(i=>i.pulledAt).length,ee=(l?.candidates||[]).filter(i=>!(l?.selected||[]).includes(i.instrumentId));return e.jsxs("div",{className:"space-y-3","data-testid":"prepare-tab",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap","data-testid":"pull-toolbar",children:[ae.length>1&&e.jsx(N,{variant:m?"secondary":"ghost",size:"sm",className:"min-h-[2.75rem]",title:Z.size===ae.length?V.collapseAll:V.expandAll,onClick:()=>se(Z.size===ae.length?new Set:new Set(ae.map(i=>i.id))),children:Z.size===ae.length?"Collapse all":"Expand all"}),a&&Ie.length>0&&(Xe<Ie.length?e.jsx(N,{variant:m?"secondary":"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:h==="pulled:all",title:V.markAllPulled,onClick:()=>_(null,!0),"data-testid":"all-pulled",children:"Mark all pulled"}):e.jsx(N,{variant:m?"secondary":"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:h==="pulled:all",title:V.clearPulled,onClick:()=>_(null,!1),children:"Clear pulled marks"})),w&&ae.length>0&&e.jsx(N,{variant:m?"secondary":"ghost",size:"sm",className:"min-h-[2.75rem]",title:V.printPull,onClick:w,children:"Print pull sheet"}),g&&e.jsx("span",{className:"ml-auto",children:e.jsx(N,{variant:"primary",size:"md",className:"min-h-[2.75rem]",isLoading:p,title:g.action==="update"?V.update:V.build,onClick:()=>k?.(g.action),"data-testid":"prepare-primary",children:g.label})})]}),ee.length>0&&e.jsxs("div",{className:"border border-gray-200 rounded-xl px-4 py-2 flex items-center gap-2 flex-wrap","data-testid":"aux-line",children:[e.jsxs("span",{className:"text-base text-gray-800 flex-1 min-w-0",children:[ee.length===1?`${ee[0].instrumentName} is on the program and nobody is seated on it.`:`${ee.length} instruments on the program have nobody seated.`,D&&ee.length>1&&e.jsx("span",{className:"block text-sm text-gray-500 mt-0.5",children:ee.map(i=>i.instrumentName).join(", ")})]}),e.jsxs("span",{className:"flex items-center gap-1.5 shrink-0",children:[ee.length>1&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",title:V.auxDetails,onClick:()=>he(i=>!i),children:D?"Hide":"Details"}),a&&S&&e.jsx(N,{variant:"secondary",size:"sm",className:"min-h-[2.75rem]",isLoading:p,title:V.addFolders,onClick:()=>S(ee.map(i=>i.instrumentId)),children:"Add folders"})]})]}),ae.map(i=>{const z=Z.has(i.id),B=ws(i,{castByDefault:I,canWrite:a,laneFolders:J?.folders}),{rows:X,perc:je,t:oe,state:_e,uncounted:Ke,shortRows:Be,undecided:ce,pullable:ge,pulled:re,done:me,chip:Pe,next:He,more:Le,summary:Oe}=B,Ye=Cs(Pe,{shortCount:Be.length,uncounted:Ke,rowCount:X.length}),Ve=e.jsxs(H,{align:"right",menuId:`short-${i.id}`,trigger:e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem] !px-2",isLoading:h===`res:${i.id}|*`,title:V.short,"data-testid":`chip-short-${i.id}`,children:e.jsxs(We,{tone:"red",children:["Short ",Be.length]})}),children:[e.jsx(H.Item,{onClick:()=>Fe(i),children:"Made copiesâ¦"}),e.jsx(H.Item,{onClick:()=>ye(i,"share"),children:"Players share"}),e.jsx(H.Item,{onClick:()=>ye(i,"ordered"),children:"On order"})]}),le=e.jsxs(e.Fragment,{children:[X.some(ve=>ve.uncounted&&ve.setCount!=null)?e.jsx(H.Item,{onClick:()=>j(i.id),children:"Count as printed"}):null,e.jsx(H.Item,{onClick:()=>c(`/music?highlight=${i.id}&inventory=1`),children:"Count by hand"})]}),de=e.jsx(H,{align:"right",menuId:`count-${i.id}`,trigger:e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem] !px-2",isLoading:T===i.id,title:V.count,"data-testid":`chip-count-${i.id}`,children:e.jsx(We,{children:Ye?.text})}),children:le});let Ne=null;Pe==="short"?Ne=a?Ve:e.jsxs(We,{tone:"red",testId:`chip-short-${i.id}`,children:["Short ",Be.length]}):Pe==="uncounted"?Ne=a?de:e.jsx(We,{testId:`chip-count-${i.id}`,children:Ye.text}):Pe==="not_scanned"?Ne=e.jsx(We,{tone:"amber",testId:`chip-unscanned-${i.id}`,children:"Not scanned"}):Pe==="needs_attention"?Ne=e.jsx(We,{tone:"amber",testId:`chip-attention-${i.id}`,children:"Needs a look"}):Be.length>0&&ce===0&&(Ne=e.jsxs(We,{testId:`chip-short-${i.id}`,children:["Short ",Be.length," · decided"]}));let ke=null;He==="scan"?ke=e.jsx(N,{variant:"secondary",size:"sm",className:"min-h-[2.75rem]",title:V.scan,onClick:()=>pe(i),children:"Scan instrumentsâ¦"}):He==="rescan"?ke=e.jsx(N,{variant:"secondary",size:"sm",className:"min-h-[2.75rem]",title:V.rescan,onClick:()=>pe(i),children:"Re-scan instrumentsâ¦"}
1):He==="choose"&&(ke=e.jsx(N,{variant:"secondary",size:"sm",className:"min-h-[2.75rem]",title:V.chooseParts,onClick:()=>G(i),"data-testid":`chip-cast-${i.id}`,children:"Choose partsâ¦"}));const Ue=[];Le.includes("choose")&&Ue.push(e.jsx(H.Item,{onClick:()=>G(i),children:i.castSeats>0?`Choose parts · ${i.castSeats} by handâ¦`:"Choose partsâ¦"},"choose")),Le.includes("count")&&Ue.push(e.jsx(H.Section,{label:"Count copies",children:le},"count"));const qe=Ue.length>0?e.jsx(H,{align:"right",menuId:`more-${i.id}`,trigger:e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem] min-w-[2.75rem]",title:V.moreRow,"aria-label":`More for ${i.title}`,"data-testid":`more-${i.id}`,children:"â¦"}),children:Ue}):null;return e.jsxs("div",{className:`border rounded-xl ${me?"border-green-300":"border-gray-200"}`,"data-testid":`piece-${i.id}`,"data-readiness":_e,"data-done":me?"true":"false","data-note":"no overflow-hidden: the Short / Count menus are positioned inside the card and were clipped (Greg 9/21)",children:[e.jsxs("div",{className:`flex items-center ${me?"bg-green-50":"bg-gray-50"} ${z?"rounded-t-xl":"rounded-xl"} ${m?"flex-wrap":""}`,children:[e.jsxs("button",{type:"button",onClick:()=>P(i.id),"aria-expanded":z,"aria-controls":`pull-piece-${i.id}`,className:"flex-1 min-w-0 px-4 py-2 flex items-start gap-2 text-left min-h-[2.75rem] focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-band-500",children:[me?e.jsx("svg",{className:"h-4 w-4 text-green-600 shrink-0 mt-1",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2.5,"aria-hidden":"true",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})}):e.jsx("svg",{className:`h-4 w-4 text-gray-400 shrink-0 mt-1 transition-transform ${z?"rotate-180":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})}),e.jsxs("span",{className:"min-w-0",children:[e.jsxs("span",{className:"flex items-baseline gap-2 flex-wrap",children:[e.jsx("span",{className:"text-base font-semibold text-gray-900",children:i.title}),i.folderNumber&&e.jsxs("span",{className:"text-xs text-gray-500",children:["cabinet #",i.folderNumber]}),i.composers&&e.jsx("span",{className:"text-xs text-gray-400",children:i.composers}),i.source==="master"&&e.jsx("span",{className:"text-[10px] uppercase tracking-wide text-gray-400",children:"parts from the shared catalog"})]}),(Oe||me)&&e.jsx("span",{className:`block text-sm tabular-nums ${me?"text-green-800":oe.needMore>0&&ce>0?"text-red-700":"text-gray-600"}`,"data-testid":`summary-${i.id}`,children:me?`Pulled · ${Oe}`:Oe})]})]}),e.jsxs("div",{className:`flex items-center justify-end gap-1.5 px-2 py-1 shrink-0 ${m?"w-full flex-wrap":""}`,"data-testid":`chips-${i.id}`,children:[Ne,ke,e.jsx("span",{className:"inline-flex justify-end min-w-[2.75rem]",children:qe}),e.jsx("span",{className:"inline-flex justify-end min-w-[7.5rem]",children:ge&&(a?e.jsx(N,{type:"button",variant:re?"ghost":"secondary",size:"sm",className:"min-h-[2.75rem]",isLoading:h===`pulled:${i.id}`,title:re?V.pulled:V.markPulled,"aria-pressed":re,onClick:()=>_(i.id,!re),"data-testid":`pulled-${i.id}`,children:re?"â Pulled":"Mark pulled"}):re?e.jsx("span",{className:"self-center px-3 text-sm text-green-700",children:"â Pulled"}):null)})]})]}),_e==="not_scanned"&&e.jsx("p",{className:"px-4 py-2 text-sm text-amber-900 bg-amber-50 border-t border-amber-100","data-testid":`unscanned-note-${i.id}`,children:"Goes in every folder until scanned."}),_e==="needs_attention"&&i.readiness?.attention?.length>0&&e.jsxs("p",{className:"px-4 py-2 text-sm text-amber-900 bg-amber-50 border-t border-amber-100","data-testid":`attention-${i.id}`,children:[i.readiness.attention.map(ve=>ve.rawLabel).join(", ")," â the label did not resolve to an instrument. Re-scan the page; if it still does not, tell us the label."]}),z&&e.jsxs(e.Fragment,{children:[e.jsx(Ms,{piece:i,rows:X,perc:je,totals:oe,compact:m,canWrite:a,busyKey:h,onRes
1olve:U,onMadeCopies:Y}),!I&&a&&_e==="ready"&&X.length>0&&!i.castSeats&&e.jsx("div",{className:"px-4 pb-3",children:e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",title:V.chooseParts,onClick:()=>G(i),"data-testid":`open-cast-${i.id}`,children:"Choose partsâ¦"})})]})]},i.id)}),J&&(J.performing>0||J.requirements?.stations?.length>0||J.requirements?.implements?.length>0)&&e.jsxs("div",{className:"border border-gray-200 rounded-xl",children:[e.jsxs("div",{className:`flex items-center px-4 py-2 gap-2 ${m?"flex-wrap":""}`,children:[e.jsxs("span",{className:"flex-1 min-w-0",children:[e.jsxs("span",{className:"block text-base font-semibold text-gray-900",children:["Percussion",J.folders?.length>0?` â ${J.folderCount} folder${J.folderCount===1?"":"s"} (${ts(J.folders)})`:""]}),e.jsx("span",{className:"block text-sm text-gray-600",children:J.folders?.length>0?"One copy of each part; the section hands them out.":"No percussion parts on this program."})]}),(J.requirements?.stations?.length>0||J.requirements?.implements?.length>0)&&e.jsx("span",{className:"inline-flex justify-end min-w-[7.5rem] shrink-0",children:e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",title:V.percDetails,onClick:()=>K(i=>!i),children:A?"Hide details":"Details"})})]}),A&&J.requirements?.stations?.length>0&&e.jsxs("p",{className:"text-sm text-gray-600 px-4 pb-2",children:[e.jsx("span",{className:"font-medium",children:"Stations across the program:"})," ",J.requirements.stations.map(i=>i.label+(i.optional?" (optional)":"")).join(", ")]}),A&&J.requirements?.implements?.length>0&&e.jsxs("p",{className:"text-sm text-gray-600 px-4 pb-3",children:[e.jsx("span",{className:"font-medium",children:"Instruments called for:"})," ",J.requirements.implements.map(i=>i.label).join(", ")]})]}),Q&&(Q.historicalOnly>0||Q.digital?.length>0||ze?.length>0)&&e.jsxs("div",{className:"text-xs text-gray-500 space-y-1",children:[Q.historicalOnly>0&&e.jsxs("p",{children:[Q.historicalOnly," historical program entr",Q.historicalOnly!==1?"ies":"y"," excluded â no music record to pull."]}),Q.digital?.length>0&&e.jsxs("p",{children:["Digital, nothing to pull: ",Q.digital.map(i=>i.title).join(", "),"."]}),ze?.length>0&&e.jsxs("p",{className:"text-amber-700",children:["Needs attention â parts with no matched instrument: ",ze.map(i=>`${i.pieceTitle}: ${i.rawLabel}`).join(" · ")]})]}),e.jsx(Ce,{isOpen:!!ie,onClose:()=>Se(null),title:ie?`Made copies â ${ie.piece.title}`:"",size:"sm",footer:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(N,{type:"button",onClick:De,isLoading:Me,title:"Record the copies you now have for each short part",children:"Save counts"}),e.jsx(N,{type:"button",variant:"ghost",onClick:()=>Se(null),title:"Close without changing any count",children:"Cancel"})]}),children:ie&&e.jsxs("div",{className:"space-y-3","data-testid":"made-copies-dialog",children:[e.jsx("p",{className:"text-sm text-gray-600",children:"For each short part, enter how many copies you have now that you have made more. The number of folders it needs is filled in."}),ie.rows.map(i=>e.jsx(Ee,{label:`${i.rawLabel} â needs ${i.needed}, had ${i.copiesOnHand??0}`,type:"number",min:0,inputMode:"numeric",value:ie.counts[i.rawLabel],onChange:z=>Se(B=>({...B,counts:{...B.counts,[i.rawLabel]:z.target.value}}))},i.rawLabel))]})}),e.jsx(Fs,{isOpen:!!L,onClose:()=>G(null),performanceId:n,musicId:L?.id||null,pieceTitle:L?.title||null,canWrite:a,onChanged:()=>d?.()}),Re&&e.jsx(os,{piece:Re,onClose:()=>pe(null),onSaved:()=>{pe(null),u()}})]})}function Os({folder:t,performanceId:n,canPack:a,onItemToggled:m,onFolderPacked:d}){const{showError:g}=be(),[k,p]=o.useState(null),[l,S]=o.useState(!1),w=t.items.filter(c=>!c.packedAt).length;async function f(){if(a){S(!0);try{const c=await q.packFolders(n,{packed:!0,folderIds:[t.id]});d(t.id,c?.packedAt||new Date().toISOString())}catch(c){g(c?.message||"Couldnât save.")}finally{S(!1)}}}async function C(c){if(!a)return;const u=!c.packedAt;p(c.id);try{await q.packFolderItem(c.id,{packed:u}),m(t.id,c.id,u)}catch(L){g(L?.message||"Couldnât save.")}finally{p(null)}}return e.jsxs("div",{className:"divide-y divide-gray-50","data-testid":`pack-checklist-${t.id}`,children:[a&&w>1&&e.jsx("div",{className:"py-2",children:e.jsxs(N,{type:"button",variant:"secondary",size:"sm",className:"min-h-[2.75rem]",isLoading:l,onClick:f,"data-testid":`pack-folder-${t.id}`,children:["Pack whole folder (",w," pieces)"]})}),t.items.map(c=>e.jsxs("label",{className:`flex items-center gap-3 text-base min-h-[2.75rem] py-1 ${a?"cursor-pointer":""}`,children:[e.jsx("input",{type:"checkbox",checked:!!c.packedAt,disabled:!a||k===c.id||!!c.alreadyIn,onChange:()=>C(c),className:"rounded border-gray-300 text-band-600 focus:ring-band-500 h-6 w-6 shrink-0"}),e.jsxs("span",{className:`min-w-0 ${c.packedAt&&!c.alreadyIn?"text-gray-400 line-through":"text-gray-900"}`,children:[c.title||"Untitled piece",c.unresolved?e.jsxs("span",{className:"ml-2 text-sm text-amber-800","data-testid":`unresolved-${c.id}`,children:["â ",zt(c)]}):e.jsx("span",{className:"ml-2 text-sm text-gray-400",children:c.rawLabel}),c.alreadyIn&&e.jsxs("span",{className:"block text-sm text-gray-600","data-testid":`already-in-${c.id}`,children:["Already in the folder for ",c.alreadyIn]})]})]},c.id)),t.items.length===0&&e.jsx($e,{size:"compact",title:"Nothing on the program for this folder."})]})}function gt(t,n){const a=(t||[]).filter(m=>m.instrumentId===n);return a.length?`#${Math.min(...a.map(m=>m.start))}â${Math.max(...a.map(m=>m.end))}`:null}function Es(t,n,a){const m=(t||[]).filter(d=>d.instrumentId===n&&(d.partNumber??null)===(a??null));return m.length?`#${Math.min(...m.map(d=>d.start))}â${Math.max(...m.map(d=>d.end))}`:null}function _s({open:t}){return e.jsx("svg",{className:`h-4 w-4 text-gray-400 shrink-0 transition-transform ${t?"rotate-180":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})}const Pt=t=>t.items.length>0&&t.items.every(n=>n.packedAt),ft=t=>t.aux?tt:t.instrumentName;function Lt(t){const n=t.lastEvent?.createdAt||t.custodyAt;return n?t.status==="missing"?`since ${bt(n)}`:bt(n):""}function Bs(t){return t.whenUnneeded==="retire"?"Not needed for this concert. It will be retired and unpacked when it comes back.":t.whenUnneeded==="keep"?"Not needed for this concert. Kept in the bin as it is, ready for the next concert.":"Not needed for this concert. It stays in the bin as it is unless you retire it."}const Ts={check_out:"Checked out",check_in:"Checked in",missing:"Marked missing",found:"Found",assign:"Assigned",unassign:"Holder cleared"};function Rs({data:t,setData:n,performanceId:a,canWrite:m=!1,isMobile:d=!1,musicGoesHome:g=null,onSaveGoesHome:k,savingGoesHome:p=!1,folderBasis:l="roster",holderDefault:S=null,primary:w=null,building:f=!1,onBuild:C,onChanged:c,onPrintChanges:u,onAck:L,onPrintBuild:G,onPrintCheckout:I,onPrintLabels:T,sharing:v=[],foldersSharedAt:j=null,foldersSharedByName:h=null,onShare:b,sharingBusy:$=!1}){const{showSuccess:_,showError:U}=be(),Y=o.useMemo(()=>t?.folders||[],[t]),ye=t?.candidates||{},[Z,se]=o.useState(""),[ne,P]=o.useState(!1),[A,K]=o.useState(null),[D,he]=o.useState(()=>new Set),Re=o.useMemo(()=>{const s=pt(Y,ft),x=s.find(([r])=>r===tt);return x?[...s.filter(([r])=>r!==tt),x]:s},[Y]),pe=o.useMemo(()=>Re.filter(([s])=>!Z||s===Z).map(([s,x])=>[s,x.filter(r=>(!ne||!Pt(r))&&(!A||!r.stale&&(r.status||"built")===A))]).filter(([,s])=>s.length>0),[Re,Z,ne,A]),ie=o.useMemo(()=>us(Y),[Y]),Se=o.useMemo(()=>pe.flatMap(([,s])=>s),[pe]),[Me,xe]=o.useState(null),Fe=Y.find(s=>
1s.id===Me)||null,[De,ae]=o.useState(null),J=o.useRef(null);o.useEffect(()=>()=>clearTimeout(J.current),[]);const Q=o.useRef(null);o.useEffect(()=>{if(!Q.current||Q.current!==Me)return;const s=Q.current;Q.current=null;const x=setTimeout(()=>{const r=typeof document<"u"?document.getElementById(`folder-${s}`):null;r?.scrollIntoView&&r.scrollIntoView({behavior:"smooth",block:"start"})},0);return()=>clearTimeout(x)},[Me,t]);const ze=s=>n(x=>x&&{...x,custodySummary:void 0,folders:x.folders.map(s)}),Ie=s=>n(x=>{if(!x)return x;const r=new Map((s?.folders||[]).map(F=>[F.id,F])),E={...x,custodySummary:s?.custodySummary,folders:x.folders.map(F=>r.get(F.id)||F)};for(const F of["candidates","numbering","changes"])s?.[F]!==void 0&&(E[F]=s[F]);return E});function Xe(s,x,r){ze(R=>R.id!==s?R:{...R,items:R.items.map(fe=>fe.id!==x?fe:{...fe,packedAt:r?new Date().toISOString():null})});const E=Y.find(R=>R.id===s);r&&E&&E.items.length>0&&E.items.every(R=>R.id===x||R.packedAt)&&i(s)}function ee(s,x){ze(r=>r.id!==s?r:{...r,items:r.items.map(E=>E.packedAt?E:{...E,packedAt:x})}),i(s)}function i(s){ae(s),clearTimeout(J.current),J.current=setTimeout(()=>{ae(null),n(x=>{const r=pt(x?.folders||[],ft).flatMap(([,fe])=>fe),E=r.findIndex(fe=>fe.id===s),R=[...r.slice(E+1),...r.slice(0,E)].find(fe=>fe.items.some(Qe=>!Qe.packedAt))||null;return Q.current=R?R.id:null,xe(R?R.id:null),x})},900)}function z(){const s=Se.find(x=>x.items.some(r=>!r.packedAt))||Y.find(x=>x.items.some(r=>!r.packedAt));s&&(Q.current=s.id,xe(s.id))}const[B,X]=o.useState(null);async function je(s,{optimistic:x=null,ok:r=null,key:E="custody"}={}){const F=t;x&&ze(x),X(E);try{const R=await q.folderCustody(a,s);return Ie(R),r&&_(typeof r=="function"?r(R):r),R}catch(R){return n(F),U(R?.message||ue),null}finally{X(null)}}const oe=()=>new Date().toISOString(),_e=s=>{const x=it(s);return je({action:"check_out",folderIds:[s.id],memberId:x.memberId,reassign:!1},{key:s.id,optimistic:r=>r.id!==s.id?r:{...r,status:"out",heldByMemberId:x.memberId,heldByName:x.name,custodyAt:oe(),lastEvent:{event:"check_out",createdAt:oe()}}})},Ke=s=>je({action:"missing",folderIds:[s.id]},{key:s.id,optimistic:x=>x.id!==s.id?x:{...x,status:"missing",custodyAt:oe(),lastEvent:{event:"missing",createdAt:oe()}}}),Be=s=>je({action:"found",folderIds:[s.id]},{key:s.id,optimistic:x=>x.id!==s.id?x:{...x,status:"built",heldByMemberId:null,heldByName:null,lastEvent:{event:"found",createdAt:oe()}},ok:`${te(s)} is back in the bin.`}),[ce,ge]=o.useState(null),[re,me]=o.useState(null),[Pe,He]=o.useState(null),[Le,Oe]=o.useState(null),[Ye,Ve]=o.useState(null),[le,de]=o.useState(null),[Ne,ke]=o.useState(!1),[Ue,qe]=o.useState(!1);async function ve(){await je({action:"check_out"},{key:"hand-out",ok:x=>{const r=(x?.folders||[]).length,E=(x?.skipped||[]).length;return`${r} ${r===1?"folder":"folders"} handed out${E?`; ${E} with nobody responsible stayed in the bin`:""}.`}})&&ke(!1)}function at(){w?.action==="hand-out"?ke(!0):w?.action==="check-in"&&qe(!0)}const ot=s=>m?st(s)?{label:"Check inâ¦",onClick:()=>me(s)}:it(s).kind==="player"?{label:"Check out",onClick:()=>_e(s)}:{label:"Assignâ¦",onClick:()=>ge(s)}:null;if(t===void 0)return e.jsx("p",{className:"text-sm text-gray-400 py-4",children:"Loadingâ¦"});if(Y.length===0)return e.jsx($e,{card:!0,title:"No folders built yet.",description:"Build creates one per seated chair, straight from the pull list.",action:m&&C?e.jsx(N,{variant:"primary",size:"md",isLoading:f,onClick:C,children:"Build folders"}):null});const we=t?.changes||[],rt=new Set(we.filter(s=>s.kind==="folder_removed"&&s.perfFolderId).map(s=>s.perfFolderId)),y=Y.filter(s=>rt.has(s.id));async function M(s,x){if(s?.length){X("unneeded");try{const r=await q.setFoldersUnneeded(a,s.map(R=>R.id),x);n(R=>R?{...R,...r}:r);const E=s.length===1,F=s.some(R=>st(R)||R.status==="missing");_(x==="keep"?E?`${te(s[0])} stays in the bin as it is.`:`${s.length} folders stay in the bin as they are.`:`${E?`${te(s[0])} is retired.`:`${s.length} folders are retired.`} File the music back in the cabinet.${F?" Folders that are out are retired when they come back.":""}`)}catch(r){U(r?.message||ue)}finally{X(null)}}}const O=ss(we,{folderBasis:l}),W=s=>e.jsxs("div",{className:d?"px-4":"pb-2 pl-2 md:pl-[4.5rem]",children:[De===s.id&&e.jsx("p",{className:"mb-1 rounded-lg bg-green-50 border border-green-200 text-green-800 text-base px-3 py-2","aria-live":"polite","data-testid":`packed-banner-${s.id}`,children:"â Packed. Moving to the next folderâ¦"}),e.jsx(Os,{folder:s,performanceId:a,canPack:m&&!f,onItemToggled:Xe,onFolderPacked:ee}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap pt-2 text-sm text-gray-600","data-testid":`custody-${s.id}`,children:[e.jsxs("span",{children:["Holder: ",e.jsx(xt,{folder:s})]}),e.jsx("span",{"aria-hidden":"true",children:"·"}),e.jsx("span",{children:ct(s)}),m&&e.jsxs("span",{className:"ml-auto flex items-center gap-1 flex-wrap",children:[e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",onClick:()=>ge(s),children:"Assignâ¦"}),it(s).kind==="player"&&!st(s)&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:B===s.id,onClick:()=>_e(s),children:"Check out"}),s.status!=="returned"&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",onClick:()=>me(s),children:"Check inâ¦"}),s.status!=="missing"&&s.status!=="returned"&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:B===s.id,onClick:()=>Ke(s),children:"Mark missing"}),s.status==="missing"&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:B===s.id,onClick:()=>Be(s),children:"Found"})]})]})]});return e.jsxs("div",{className:"space-y-3","data-testid":"folder-board",children:[e.jsx("p",{className:"flex items-center gap-2 flex-wrap text-base text-gray-700","data-testid":"share-line",children:j?e.jsxs(e.Fragment,{children:[e.jsxs("span",{children:["Shared with section leaders · ",Ft(j),h?` by ${h}`:"","."]}),m&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:$,title:V.unshare,onClick:()=>b?.(!1),children:"Unshare"})]}):e.jsxs(e.Fragment,{children:[e.jsx("span",{children:"Not yet shared with section leaders."}),m&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:$,title:V.share,onClick:()=>b?.(!0),children:"Share with section leaders"})]})}),g==null&&m&&e.jsxs("p",{className:"flex items-center gap-2 flex-wrap text-base text-gray-700","data-testid":"goes-home-prompt",children:[e.jsx("span",{children:"Do folders go home with players?"}),e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:p,onClick:()=>k?.(!0),children:"Yes"}),e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",isLoading:p,onClick:()=>k?.(!1),children:"No"})]}),O&&e.jsxs("div",{className:"rounded-xl border border-amber-200 bg-amber-50 p-4 space-y-2 text-base text-gray-800","aria-live":"polite","data-testid":"folder-changes",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"Since your last build."})," ",O.why]}),e.jsx("ul",{className:"space-y-2",children:O.groups.map(s=>e.jsxs("li",{"data-testid":`change-${s.kind}`,children:[e.jsx("span",{className:"font-medium",children:s.sentence}),s.byInstrument.length>0&&s.count>1&&e.jsx("span",{className:"block text-gray-700",children:s.byInstrument.map(x=>`${x.name} ${x.count}`).join(" · ")}),e.jsxs("span",{className:"block text-gray-700",children:["What to do: ",s.instruction]}),s.kind==="folder_removed"&&m&&y.length>0&&e.jsxs("span",{className:"flex flex-wrap gap-2 pt-1",children:[e.jsx(N,{variant:"secondary",size:"sm",className:"min-h-[2.75rem]",isLoading:B==="unneeded",onClick:()=>M(y,"keep"),children:y.length===1?"Keep in the bin":"Keep all in the bin"}),e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",onClick:()=>de(y),children:y.length===1?"Retire and unpack":"Retire and unpack all"})]}),s.count>1&&s.byInstrument.length>0&&e.jsxs("span",{className:"block",children:[e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]","aria-expanded":D.has(s.kind),onClick:()=>he(x=>{const r=new Set(x);return r.has(s.kind)?r.delete(s.kind):r.add(s.kind),r}),children:D.has(s.kind)?"Hide the list":`Show all ${s.count}`}),D.has(s.kind)&&e.jsx("span",{className:"block text-gray-700","data-testid":`change-${s.kind}-list`,children:s.names.join(", ")})]})]},s.kind))}),Y.some(s=>s.status==="out"||s.status==="missing")&&e.jsx("p",{className:"text-gray-700","data-testid":"change-folders-out",children:"Some folders are out, so these changes arenât in them yet. Tap Update folders on Prepare once theyâre back."}),O.groups.some(s=>s.kind.startsWith("folder_"))&&e.jsx("p",{className:"text-gray-700","data-testid":"change-not-what-you-meant",children:"Wrong number of folders? Change the counts under More, then Numbering."}),e.jsx("p",{className:"text-gray-700",children:"When the shelf matches, acknowledge the changes."}),e.jsxs("p",{className:"flex items-center gap-2 flex-wrap",children:[m&&e.jsx(N,{variant:"secondary",size:"md",onClick:L,title:V.acknowledge,children:"Acknowledge"}),e.jsx(N,{variant:"ghost",size:"md",onClick:u,title:V.printChanges,children:"Print changes sheet"})]})]}),(G||I||T)&&(d?e.jsx("div",{className:"flex items-center gap-2","data-testid":"folder-prints",children:e.jsxs(H,{menuId:"folder-prints-menu",trigger:e.jsx(N,{variant:"secondary",size:"sm",className:"min-h-[2.75rem]",children:"Printâ¦"}),children:[G&&e.jsx(H.Item,{onClick:G,children:"Print build sheet"}),I&&e.jsx(H.Item,{onClick:I,children:"Print check-out sheet"}),T&&e.jsx(H.Item,{onClick:T,children:"Print labelsâ¦"})]})}):e.jsxs("div",{className:"flex items-center gap-2 flex-wrap","data-testid":"folder-prints",children:[G&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",title:V.printBuild,onClick:G,children:"Print build sheet"}),I&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",title:V.printCheckout,onClick:I,children:"Print check-out sheet"}),T&&e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem]",title:V.printLabels,onClick:T,children:"Print labelsâ¦"})]})),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap","data-testid":"folder-filters",children:[e.jsx(Ze,{"aria-label":"Section",value:Z,active:!!Z,onChange:s=>se(s.target.value),className:"!w-auto !py-2 !text-base h-11 md:h-auto",options:[{value:"",label:"All sections"},...Re.map(([s])=>({value:s,label:s}))]}),e.jsx(N,{variant:"secondary",size:"sm",className:`min-h-[2.75rem] !rounded-full ${ne?"!bg
1-band-50 !border-band-400 !text-band-700":""}`,"aria-pressed":ne,title:V.notPacked,onClick:()=>P(s=>!s),children:"Not packed"}),e.jsx("span",{className:"flex items-center gap-2 flex-wrap",role:"group","aria-label":"Show folders by state","data-testid":"state-filters",children:hs.map(s=>{const x=ie[s.status],r=A===s.status,E=s.status==="missing"&&x>0;return e.jsxs(N,{variant:"secondary",size:"sm",className:`min-h-[2.75rem] !rounded-full gap-1.5 ${E?"!bg-red-500 !border-red-500 !text-white":""} ${r?"!ring-2 !ring-offset-1 !ring-band-500":""} ${x===0&&!r?"opacity-60":""}`,"aria-pressed":r,"aria-label":`${s.word}: ${x} ${x===1?"folder":"folders"}`,title:V[`state_${s.status}`],"data-testid":`state-filter-${s.status}`,onClick:()=>K(F=>F===s.status?null:s.status),children:[!E&&e.jsx("span",{className:`inline-block h-2.5 w-2.5 rounded-full ${s.dot}`,"aria-hidden":"true"}),e.jsx("span",{children:s.word}),e.jsx("span",{className:"tabular-nums font-semibold",children:x})]},s.status)})}),m&&e.jsx(N,{variant:d?"secondary":"ghost",size:"sm",className:"min-h-[2.75rem]",title:V.packNext,onClick:z,children:"Pack next"}),w&&e.jsx("span",{className:"ml-auto",children:e.jsx(N,{variant:"primary",size:"md",className:"min-h-[2.75rem]",isLoading:B==="hand-out",title:w.action==="hand-out"?V.handOut:V.checkIn,onClick:at,"data-testid":"folders-primary",children:w.label})})]}),Se.length===0&&e.jsx($e,{size:"compact",title:"No folders match these filters."}),Se.length>0&&e.jsxs("div",{className:"hidden md:grid md:grid-cols-[4rem_minmax(0,1fr)_5rem_minmax(0,1.2fr)_9rem_6.5rem_10rem] md:gap-3 px-3 pb-1 text-xs font-semibold uppercase tracking-wide text-gray-500 border-b border-gray-200","aria-hidden":"true",children:[e.jsx("span",{children:"#"}),e.jsx("span",{children:"Part"}),e.jsx("span",{children:"Packed"}),e.jsx("span",{children:"Holder"}),e.jsx("span",{children:"State"}),e.jsx("span",{children:"Last moved"}),e.jsx("span",{className:"text-right",children:"Actions"})]}),pe.map(([s,x])=>e.jsxs("div",{id:`folder-group-${s.toLowerCase().replace(/[^a-z0-9]+/g,"-")}`,className:"scroll-mt-4 rounded-xl border border-gray-200 bg-white",children:[e.jsxs("p",{className:"sticky top-0 z-10 rounded-t-xl bg-gray-50 border-b border-gray-200 px-3 py-2 flex items-center gap-2 flex-wrap text-base font-semibold text-gray-900","data-testid":"folder-group-header",children:[e.jsx("span",{children:s}),e.jsxs("span",{className:"text-sm font-normal text-gray-500",children:[x.length," ",x.length===1?"folder":"folders"]}),gt(t?.numbering?.blocks,s===tt?"extras":x[0]?.instrumentId)&&e.jsx("span",{className:"text-sm font-normal text-gray-500 tabular-nums",children:gt(t?.numbering?.blocks,s===tt?"extras":x[0]?.instrumentId)}),v.filter(r=>r.instrumentName===s).length>0&&e.jsx("span",{className:"text-sm font-normal text-amber-800","data-testid":"sharing-chip",children:v.filter(r=>r.instrumentName===s).map(r=>`${r.extra} share${r.extra===1?"s":""} ${r.instrumentName} ${r.partNumber}`).join(" · ")})]}),x.map(r=>{const E=Me===r.id,F=r.items.filter(_t=>_t.packedAt).length,R=Pt(r),fe=ot(r),Qe=r.folderNumber?r.folderDisplay||`#${r.folderNumber}`:null;return e.jsxs("div",{id:`folder-${r.id}`,className:"border-b border-gray-100 last:border-0 scroll-mt-10 px-3","data-testid":`folder-${r.id}`,"data-status":r.status||"built",children:[e.jsxs("div",{className:"flex flex-col gap-1 md:grid md:grid-cols-[4rem_minmax(0,1fr)_5rem_minmax(0,1.2fr)_9rem_6.5rem_10rem] md:gap-3 md:items-center",children:[e.jsxs("button",{type:"button",onClick:()=>xe(E?null:r.id),"aria-expanded":E,className:"flex-1 min-w-0 min-h-[2.75rem] py-1.5 text-left rounded-lg md:hover:bg-gray-50 md:col-span-6 md:grid md:grid-cols-subgrid md:gap-3 md:items-center","data-testid":`folder-row-${r.id}`,children:[e.jsxs("span",{className:"flex items-center gap-2 md:contents",children:[e.jsxs("span",{className:"flex items-center gap-1 shrink-0 md:contents",children:[e.jsx("span",{className:"md:hidden",children:e.jsx(_s,{open:E})}),e.jsx("span",{className:`text-base font-semibold tabular-nums ${Qe?"text-gray-900":"text-amber-800"}`,children:Qe||"no folder #"})]}),e.jsxs("span",{className:"text-base text-gray-900 truncate min-w-0 flex-1",children:[r.label,r.alsoInstruments?.length>0&&e.jsxs("span",{className:"text-sm text-gray-500","data-testid":`also-${r.id}
1`,children:[" + ",r.alsoInstruments.join(", ")]})]}),r.unresolvedCount>0&&e.jsxs("span",{className:"hidden md:inline text-xs font-medium text-amber-800 shrink-0","data-testid":`unresolved-count-${r.id}`,children:[r.unresolvedCount," part",r.unresolvedCount===1?"":"s"," not listed yet"]}),e.jsxs("span",{className:`inline-flex items-center px-2 py-0.5 rounded-full text-sm font-semibold tabular-nums shrink-0 justify-self-start ${R?"bg-green-100 text-green-700":F>0?"bg-amber-100 text-amber-700":"bg-gray-100 text-gray-500"}`,"data-testid":`packed-${r.id}`,children:[F,"/",r.items.length,R?" â":""]})]}),e.jsxs("span",{className:"block truncate text-sm text-gray-600 mt-0.5 md:contents md:mt-0",children:[e.jsx(xt,{folder:r,testId:`holder-${r.id}`,className:"md:text-base md:text-gray-900"}),r.unresolvedCount>0&&e.jsxs("span",{className:"md:hidden ml-2 text-xs font-medium text-amber-800","data-testid":`unresolved-count-mobile-${r.id}`,children:["· ",r.unresolvedCount," part",r.unresolvedCount===1?"":"s"," not listed yet"]}),e.jsx("span",{className:`hidden md:inline-flex ${jt} ${Nt(r)}`,"data-testid":`state-${r.id}`,children:ct(r)}),e.jsx("span",{className:"hidden md:inline text-gray-500 tabular-nums","data-testid":`moved-${r.id}`,children:Lt(r)})]}),(r.unneeded||r.stale)&&e.jsx("span",{className:"block text-sm text-amber-800 md:col-span-6","data-testid":`stale-${r.id}`,children:Bs(r)})]}),e.jsxs("span",{className:"flex items-center justify-between gap-2 pb-1 md:pb-0 md:py-1 md:justify-end","data-testid":`actions-${r.id}`,children:[e.jsxs("span",{className:"flex items-center gap-2 min-w-0 md:hidden","aria-hidden":"true",children:[e.jsx("span",{className:`${jt} ${Nt(r)}`,"data-testid":`state-${r.id}-phone`,children:ct(r)}),e.jsx("span",{className:"text-sm text-gray-500 tabular-nums whitespace-nowrap",children:Lt(r)})]}),e.jsxs("span",{className:"flex items-center gap-1 shrink-0",children:[fe&&e.jsx(N,{variant:ps(r),size:"sm",className:"min-h-[2.75rem]",isLoading:B===r.id,onClick:fe.onClick,children:fe.label}),m&&e.jsxs(H,{align:"right",menuId:`folder-menu-${r.id}`,trigger:e.jsx(N,{variant:"ghost",size:"sm",className:"min-h-[2.75rem] min-w-[2.75rem]","aria-label":`More for folder ${Qe||r.label}`,children:"â¦"}),children:[e.jsx(H.Item,{onClick:()=>Ve(r),children:"Change numberâ¦"}),!r.aux&&r.instrumentId&&e.jsx(H.Item,{onClick:()=>Oe(r),children:"Also put inâ¦"}),r.folderNumber?e.jsx(H.Item,{onClick:()=>
1Ot.openPdf(q.folderLabelsUrl(a,{which:"numbers",numbers:[r.folderNumber]})),children:"Print label"}):null,m&&(r.unneeded||r.stale)&&r.whenUnneeded!=="keep"&&e.jsx(H.Item,{onClick:()=>M([r],"keep"),children:"Keep in the bin"}),m&&(r.unneeded||r.stale)&&r.whenUnneeded!=="retire"&&e.jsx(H.Item,{onClick:()=>de([r]),children:"Retire and unpack"}),e.jsx(H.Item,{onClick:()=>He(r),children:"History"})]})]})]})]}),E&&!d&&W(r)]},r.id)})]},s)),e.jsx("p",{className:"text-sm text-gray-500",children:"Tap a folder to tick pieces in as you pack, or to record who has it."}),d&&e.jsx(ms,{isOpen:!!Fe,onClose:()=>xe(null),title:Fe?`${te(Fe)} · ${Fe.label}`:"",children:Fe&&W(Fe)}),e.jsx(ht,{isOpen:!!le,onClose:()=>de(null),onConfirm:async()=>{const s=le;de(null),await M(s,"retire")},isLoading:B==="unneeded",title:le?.length===1?`Retire and unpack ${te(le[0])}?`:`Retire and unpack ${le?.length||0} folders?`,message:"Take the music out and file it back in the cabinet. The folder number is freed for another folder, and its check-out history is kept. A folder that is out is retired when it comes back.",confirmLabel:"Retire and unpack",confirmVariant:"warning"}),e.jsx(ht,{isOpen:Ne,onClose:()=>ke(!1),onConfirm:ve,isLoading:B==="hand-out",title:"Hand out every folder?",message:`Each folder is checked out to ${xs(S)}. A folder with nobody responsible stays in the bin. After the concert, Check in⦠takes the roll call.`,confirmLabel:"Hand out all",confirmVariant:"primary"}),e.jsx(Ds,{isOpen:Ue,onClose:()=>qe(!1),folders:Y,busy:B==="roll-call",onDone:async({back:s,notBack:x})=>{X("roll-call");const r=t;try{s.length&&Ie(await q.folderCustody(a,{action:"check_in",folderIds:s})),x.length&&Ie(await q.folderCustody(a,{action:"missing",folderIds:x}));const E=x.map(F=>Y.find(R=>R.id===F)).filter(Boolean).map(F=>`${te(F)} (${F.label})`);_(`${s.length} of ${s.length+x.length} back${E.length?`; missing ${E.join(", ")}`:"."}`),qe(!1)}catch(E){n(r),U(E?.message||ue)}finally{X(null)}}}),re&&e.jsx(Hs,{folder:re,busy:B===re.id,onClose:()=>me(null),onConfirm:async s=>{const x=re;await je({action:"check_in",folderIds:[x.id],...s.length?{itemIds:s}:{}},{key:x.id,optimistic:E=>E.id!==x.id?E:{...E,status:"returned",heldByMemberId:null,heldByName:null,lastEvent:{event:"check_in",createdAt:oe()}},ok:`${te(x)} checked in${s.length?`; ${s.length} ${s.length===1?"piece":"pieces"} reported missing`:""}.`})&&me(null)}}),ce&&e.jsx(Us,{folder:ce,holderDefault:S,holdings:gs(Y),candidates:ye[`${ce.instrumentId}|${ce.partNumber}`]||ye[`${ce.instrumentId}|null`]||[],busy:B===ce.id,onClose:()=>ge(null),onPick:async s=>{const x=ce;(s?await je({action:"assign",folderIds:[x.id],memberId:s.id},{key:x.id,optimistic:E=>E.id!==x.id?E:{...E,memberId:s.id,memberName:s.name,responsible:{kind:"player",memberId:s.id,name:s.name,source:"holder"}},ok:`${te(x)} assigned to ${s.name}.`}):await je({action:"unassign",folderIds:[x.id]},{key:x.id,ok:E=>{const F=(E?.folders||[]).find(R=>R.id===x.id);return bs(te(x),F)}}))&&ge(null)}}),Pe&&e.jsx(qs,{folder:Pe,onClose:()=>He(null)}),Le&&e.jsx(Gs,{performanceId:a,folder:Le,onClose:()=>Oe(null),onSaved:(s,x)=>{Ie(s);const r=st(Le);_(x.length?`Saved. ${x.join(", ")} parts go in ${te(Le)} for every piece.${r?` ${te(Le)} is out now â add them when it comes back.`:""}`:`Saved. Nothing extra goes in ${te(Le)}.`),Oe(null)}}),Ye&&e.jsx(Ks,{folder:Ye,blocks:t?.numbering?.blocks,onClose:()=>Ve(null),onSaved:()=>{Ve(null),c?.()}})]})}function Ds({isOpen:t,onClose:n,folders:a,busy:m,onDone:d}){const[g,k]=o.useState(()=>new Set),p=o.useMemo(()=>a.filter(st),[a]);o.useEffect(()=>{t&&k(new Set(p.filter(f=>f.status==="missing").map(f=>f.id)))},[t]);const l=o.useMemo(()=>pt(p,ft),[p]),S=f=>k(C=>{const c=new Set(C);return c.has(f)?c.delete(f):c.add(f),c}),w=p.filter(f=>!g.has(f.id)).map(f=>f.id);return e.jsxs(Ce,{isOpen:t,onClose:n,title:"Roll call",size:"lg",footer:e.jsxs("div",{className:"flex gap-2 items-center",children:[e.jsx(N,{variant:"primary",size:"md",isLoading:m,onClick:()=>d({back:w,notBack:[...g]}),"data-testid":"roll-call-done",children:`Check in ${w.length} ${w.length===1?"folder":"folders"}`}),e.jsx(N,{variant:"secondary",size:"md",onClick:n,children:"Cancel"}),e.jsxs("span",{className:"ml-auto text-sm text-gray-600 tabular-nums",children:[w.length," of ",p.length," back"]})]}),children:[e.jsxs("p",{className:"text-base text-gray-700 mb-3",children:["Tap every folder that is ",e.jsx("strong",{children:"not"})," back. The rest are checked in."]}),p.length===0&&e.jsx($e,{size:"compact",title:"No folders are out."}),l.map(([f,C])=>e.jsxs("div",{className:"mb-3",children:[e.jsx("p",{className:"text-xs uppercase tracking-wide text-gray-500 mb-1",children:f}),e.jsx("div",{className:"flex flex-wrap gap-2",children:C.map(c=>{const u=g.has(c.id);return e.jsxs(N,{variant:u?"warning":"secondary",size:"md",className:"min-h-[2.75rem] min-w-[4.5rem] flex-col !py-1","aria-pressed":u,"aria-label":`${te(c)} ${c.label}${u?", not back":""}`,onClick:()=>S(c.id),"data-testid":`roll-${c.id}`,children:[e.jsx("span",{className:"text-base font-semibold tabular-nums",children:te(c)}),u&&e.jsx("span",{className:"text-xs",children:"Not back"})]},c.id)})})]},f))]})}function Hs({folder:t,busy:n,onClose:a,onConfirm:m}){const[d,g]=o.useState(()=>new Set),k=p=>g(l=>{const S=new Set(l);return S.has(p)?S.delete(p):S.add(p),S});return e.jsxs(Ce,{isOpen:!0,onClose:a,title:`Check in ${te(t)} · ${t.label}`,footer:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(N,{variant:"primary",size:"md",isLoading:n,onClick:()=>m([...d]),"data-testid":"check-in-confirm",children:"Check in folder"}),e.jsx(N,{variant:"secondary",size:"md",onClick:a,children:"Cancel"})]}),children:[e.jsx("p",{className:"text-base text-gray-700 mb-3",children:"Anything missing? Tick any piece that did not come back; leave the rest alone."}),e.jsxs("div",{className:"divide-y divide-gray-50",children:[t.items.map(p=>e.jsxs("label",{className:"flex items-center gap-3 text-base min-h-[2.75rem] py-1 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:d.has(p.id),onChange:()=>k(p.id),className:"rounded border-gray-300 text-band-600 focus:ring-band-500 h-6 w-6 shrink-0"}),e.jsxs("span",{className:"text-gray-900",children:[p.title||"Untitled piece"," ",e.jsx("span",{className:"text-sm text-gray-400",children:zt(p)})]})]}
1,p.id)),t.items.length===0&&e.jsx($e,{size:"compact",title:"Nothing on the program for this folder."})]})]})}function Us({folder:t,candidates:n,busy:a,onClose:m,onPick:d,holderDefault:g=null,holdings:k=new Map}){const{showError:p}=be(),[l,S]=o.useState(""),[w,f]=o.useState([]),[C,c]=o.useState(!1);o.useEffect(()=>{const I=l.trim();if(I.length<2){f([]);return}let T=!1;const v=setTimeout(()=>{c(!0),cs.list({search:I,limit:10,status:"active"}).then(j=>{T||f((j?.members||j||[]).map(h=>({id:h.id,name:Tt(h)})))}).catch(j=>{T||p(j?.message||Je("members"))}).finally(()=>{T||c(!1)})},250);return()=>{T=!0,clearTimeout(v)}},[l]);const u=new Set(n.map(I=>I.memberId)),L=it(t),G=!!t.memberId;return e.jsx(Ce,{isOpen:!0,onClose:m,title:`Assign ${te(t)} · ${t.label}`,size:"sm",footer:G?e.jsxs("div",{className:"space-y-2","data-testid":"assign-clear",children:[e.jsx("p",{className:"text-sm text-gray-600",children:fs(g)}),e.jsx(N,{variant:"ghost",size:"md",className:"min-h-[2.75rem]",isLoading:a,onClick:()=>d(null),children:"Clear holder"})]}):null,children:e.jsxs("div",{className:"space-y-3","data-testid":"assign-modal",children:[e.jsxs("p",{className:"text-sm text-gray-600","data-testid":"assign-responsible",children:["Responsible now: ",e.jsx(xt,{folder:t})]}),n.length>0&&e.jsxs("div",{children:[e.jsx("p",{className:"text-xs uppercase tracking-wide text-gray-500 mb-1",children:t.partNumber==null?"Playing this concert":"Seated on this chair"}),e.jsx("div",{className:"space-y-1",children:kt(n,k).map(I=>e.jsx(N,{variant:I.memberId===L.memberId?"secondary":"ghost",size:"md",className:"w-full justify-start min-h-[2.75rem] py-2",isLoading:a,onClick:()=>d({id:I.memberId,name:I.name}),"aria-pressed":I.memberId===L.memberId,...vt({name:I.name,memberId:I.memberId,holdings:k,folderId:t.id,responsibleNow:I.memberId===L.memberId}),children:e.jsx(wt,{name:I.name,memberId:I.memberId,holdings:k,folderId:t.id,responsibleNow:I.memberId===L.memberId,testId:`assign-candidate-${I.memberId}`})},I.memberId))})]}),e.jsxs("div",{children:[e.jsx(Ee,{"aria-label":"Search the roster",placeholder:"Search the roster by name",value:l,onChange:I=>S(I.target.value)}),C&&e.jsx("p",{className:"text-sm text-gray-400 mt-1",children:"Searchingâ¦"}),e.jsx("div",{className:"space-y-1 mt-1",children:kt(w.filter(I=>!u.has(I.id)),k).map(I=>e.jsx(N,{variant:"ghost",size:"md",className:"w-full justify-start min-h-[2.75rem] py-2",isLoading:a,onClick:()=>d(I),...vt({name:I.name,memberId:I.id,holdings:k,folderId:t.id}),children:e.jsx(wt,{name:I.name,memberId:I.id,holdings:k,folderId:t.id,testId:`assign-candidate-${I.id}`})},I.id))})]})]})})}function qs({folder:t,onClose:n}){const{showError:a}=be(),[m,d]=o.useState(void 0);return o.useEffect(()=>{let g=!1;return q.folderHistory(t.id).then(k=>{g||d(k?.events||[])}).catch(k=>{g||(d(null),a(k?.message||Je("the folder history")))}),()=>{g=!0}},[t.id]),e.jsxs(Ce,{isOpen:!0,onClose:n,title:`History · ${te(t)} ${t.label}`,children:[m===void 0&&e.jsx("p",{className:"text-sm text-gray-400",children:"Loadingâ¦"}),m===null&&e.jsx("p",{className:"text-sm text-gray-500",children:"Couldnât load the history. Close and try again."}),Array.isArray(m)&&m.length===0&&e.jsx($e,{size:"compact",title:"Nothing recorded yet.",description:"Only hand-outs, check-ins and missing folders are recorded; a normal night writes nothing."}),Array.isArray(m)&&m.length>0&&e.jsx("ul",{className:"divide-y divide-gray-100","data-testid":"folder-history",children:m.map(g=>e.jsxs("li",{className:"py-2 text-base text-gray-900",children:[e.jsx("span",{className:"font-medium",children:Ts[g.event]||g.event}),g.toMember?.name&&e.jsxs(e.Fragment,{children:[" â ",g.toMember.name]}),g.event==="check_in"&&g.fromMember?.name&&e.jsxs(e.Fragment,{children:[" from ",g.fromMember.name]}),g.itemTitle&&e.jsxs(e.Fragment,{children:[" · ",g.itemTitle]}),e.jsxs("span",{className:"block text-sm text-gray-500",children:[Rt(g.createdAt),g.byUser?.name?` · recorded by ${g.byUser.name}`:"",g.via==="section_leader"?" (section leader)":"",g.note?` · ${g.note}`:""]})]},g.id))})]})}function Gs({performanceId:t,folder:n,onClose:a,onSaved:m}){const{showError:d}=be(),[g,k]=o.useState(null),[p,l]=o.useState(()=>new Set),[S,w]=o.useState(!1);o.useEffect(()=>{let c=!1;return q.getFolderAlso(t,n.id).then(u=>{c||(k(u),l(new Set(u?.current||[])))}).catch(u=>{c||(k({choices:[],current:[]}
1),d(u?.message||Je("instruments")))}),()=>{c=!0}},[t,n.id]);const f=c=>l(u=>{const L=new Set(u);return L.has(c)?L.delete(c):L.add(c),L});async function C(){w(!0);try{const c=[...p],u=await q.setFolderAlso(t,n.id,c);m(u,c)}catch(c){d(c?.message||ue)}finally{w(!1)}}return e.jsxs(Ce,{isOpen:!0,onClose:a,title:`Also put in · ${te(n)} ${n.label}`,size:"sm",footer:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(N,{type:"button",variant:"primary",size:"md",isLoading:S,disabled:!g,onClick:C,children:"Save changes"}),e.jsx(N,{type:"button",variant:"secondary",size:"md",onClick:a,children:"Cancel"})]}),children:[e.jsx("p",{className:"text-base text-gray-700 mb-3",children:"Tick an instrument and its part goes in this folder too, for every piece, all season."}),g===null?e.jsx("p",{className:"text-sm text-gray-400",children:"Loadingâ¦"}):g.choices.length===0?e.jsx($e,{size:"compact",title:"No other parts on this program yet."}):e.jsx("div",{className:"divide-y divide-gray-100 border border-gray-200 rounded-lg",children:g.choices.map(c=>e.jsxs("label",{className:"flex items-center gap-3 px-3 min-h-[44px] text-base text-gray-800 cursor-pointer hover:bg-gray-50",children:[e.jsx("input",{type:"checkbox",checked:p.has(c),onChange:()=>f(c),className:"h-5 w-5 rounded border-gray-300 text-band-600 focus:ring-band-500"}),c]},c))})]})}function Ks({folder:t,blocks:n,onClose:a,onSaved:m}){const{showError:d,showSuccess:g}=be(),[k,p]=o.useState(t.folderNumber||""),[l,S]=o.useState(!1),w=String(k).trim(),f=w.toUpperCase()===String(t.folderNumber||"").toUpperCase();async function C(c){if(c?.preventDefault(),!(!w||f)){S(!0);try{await q.updatePerfFolder(t.id,{folderNumber:w}),g("Folder number saved."),m()}catch(u){d(u?.message||ue)}finally{S(!1)}}}return e.jsx(Ce,{isOpen:!0,onClose:a,title:`Change number · ${t.label}`,size:"sm",footer:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(N,{type:"submit",form:"change-number-form",variant:"primary",size:"md",isLoading:l,disabled:!w||f,children:"Save changes"}),e.jsx(N,{type:"button",variant:"secondary",size:"md",onClick:a,children:"Cancel"})]}),children:e.jsxs("form",{id:"change-number-form",onSubmit:C,children:[(()=>{const c=t.aux?"extras":t.instrumentId,u=gt(n,c),L=t.aux?null:Es(n,t.instrumentId,t.partNumber);if(!u)return null;const G=t.aux?"Extra folders":t.instrumentName,I=L&&L!==u?t.label.replace(/\s+[â-]\s+\d+$/,""):null;return e.jsxs("p",{className:"mb-3 rounded-lg bg-gray-50 border border-gray-200 px-3 py-2 text-sm text-gray-700","data-testid":"change-number-range",children:[e.jsxs("span",{className:"font-medium text-gray-900 tabular-nums",children:[G," folders are numbered ",u]}),I&&e.jsxs("span",{className:"tabular-nums",children:[" · ",I," ",L]}),e.jsx("span",{className:"block text-gray-500",children:"Any free number works; these keep the section together."})]})})(),e.jsx(Ee,{label:"Folder number",value:k,onChange:c=>p(c.target.value),placeholder:"26",className:"!text-base",autoFocus:!0}),e.jsx("p",{className:"text-sm text-gray-500 mt-2","data-testid":"change-number-help",children:"Renames this folder at every concert it is used at; whoever holds it keeps it. A number another folder already has canât be used."})]})})}const At=["Prefix","Labels","How many folders","Custody","Who is responsible","Who decides"],Ys=t=>t==null?null:t?"seated":"section_leader";function Ae({name:t,value:n,current:a,onChange:m,title:d,detail:g}){const k=a===n;return e.jsxs("label",{className:`flex items-start gap-3 rounded-xl border p-4 cursor-pointer min-h-[2.75rem] ${k?"border-band-400 bg-band-50 ring-2 ring-band-200":"border-gray-200 hover:border-gray-300"}`,children:[e.jsx("input",{type:"radio",name:t,value:String(n),checked:k,onChange:()=>m(n),className:"mt-1 h-4 w-4 text-band-600 focus:ring-band-500"}),e.jsxs("span",{children:[e.jsx("span",{className:"block text-base font-medium text-gray-900",children:d}),g&&e.jsx("span",{className:"block text-sm text-gray-600 mt-0.5",children:g})]})]})}function Vs({ensembleName:t,initial:n={},onSubmit:a,onCancel:m,isSubmitting:d=!1,submitLabel:g="Start using folders"}
1){const[k,p]=o.useState(0),[l,S]=o.useState(n.prefix||""),[w,f]=o.useState(n.newLabelsEachPerformance??null),[C,c]=o.useState(n.folderBasis||null),[u,L]=o.useState(n.musicGoesHome??null),[G,I]=o.useState(n.holderDefault??null),[T,v]=o.useState(n.folderDealing??null),j=G??Ys(u),h=[!0,w!=null,C!=null,u!=null,j!=null,T!=null],b=`${(l||"").toUpperCase()}${l?"-":""}01`,{showError:$}=be();function _(){if(!h.every(Boolean)){$("Pick an answer for each question first.");return}a({prefix:l.trim().toUpperCase(),newLabelsEachPerformance:w,folderBasis:C,musicGoesHome:u,holderDefault:j,folderDealing:T})}return e.jsxs("section",{"aria-labelledby":"folder-setup-heading",children:[e.jsxs("h3",{id:"folder-setup-heading",className:"text-sm font-semibold text-gray-500 uppercase tracking-wide mb-1",children:["Set up Music Folders",t?` â ${t}`:""]}),e.jsx("p",{className:"text-base text-gray-700 mb-6",children:"Six quick questions so the folders start the way your band already works. You can change any of these later under Folder settings."}),e.jsxs(js,{steps:At,currentStep:k,onNext:()=>p(U=>Math.min(U+1,At.length-1)),onBack:()=>p(U=>Math.max(U-1,0)),onCancel:m,onSubmit:_,nextDisabled:!h[k],isSubmitting:d,submitLabel:g,maxWidth:"max-w-2xl",children:[k===0&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-base font-medium text-gray-900",children:"Do you put a short prefix on your folder numbers?"}),e.jsxs("p",{className:"text-sm text-gray-600",children:["Up to two letters or digits, so a Concert Band folder reads ",e.jsx("span",{className:"font-mono",children:"CB-01"})," and a Jazz Band folder ",e.jsx("span",{className:"font-mono",children:"JB-01"}),". Leave it blank for plain numbers."]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(Ee,{value:l,onChange:U=>S(U.target.value.replace(/[^A-Za-z0-9]/g,"").slice(0,2).toUpperCase()),placeholder:"CB","aria-label":"Folder number prefix",className:"!w-24 uppercase",maxLength:2}),e.jsxs("span",{className:"text-sm text-gray-500",children:["Folders will print as ",e.jsx("span",{className:"font-mono font-semibold text-gray-900",children:b})]})]}),e.jsxs("p",{className:"text-sm text-gray-600 bg-gray-50 border border-gray-200 rounded-xl px-4 py-2",children:["Folders already numbered? Build assigns each folder a number; put its contents in the physical folder with that number and you are done. Only if your numbers are already tied to people (folders out with players, or names on the folders) use ",e.jsx("span",{className:"font-medium",children:"Match numbers from a listâ¦"})," under More after the first build, so Sarah keeps folder 12."]})]}),k===1&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-base font-medium text-gray-900",children:"Do you make new folder labels for every performance session?"}),e.jsx(Ae,{name:"labels",value:!0,current:w,onChange:f,title:"Yes â every concert is a fresh set",detail:"Each concert gets renumbered from your scheme and every folder gets a new label."}),e.jsx(Ae,{name:"labels",value:!1,current:w,onChange:f,title:"No â the folders carry over",detail:"A folder keeps its number from concert to concert; only folders new this concert get a label."})]}),k===2&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-base font-medium text-gray-900",children:"How do you decide how many folders to make?"}),e.jsx(Ae,{name:"basis",value:"fixed",current:C,onChange:c,title:"A set number for each instrument and chair",detail:"You make a set number of folders for each part, usually the copies you own. Four Clarinet 1 folders exist whether or not four are seated, and players beyond that number share a folder."}),C==="fixed"&&e.jsx("p",{className:"text-sm text-sky-900 bg-sky-50 border border-sky-200 rounded-xl px-4 py-2",children:"After the last question youâll set the number of folders for each chair â we start you from this concertâs seating, one folder per seated player, and you change any count to match the copies you own."}),e.jsx(Ae,{name:"basis",value:"roster",current:C,onChange:c,title:"One folder per performing member",detail:"Folders follow the seating chart for each concert: a folder for everyone seated, none for empty seats."})]}),k===3&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-base font-medium text-gray-900",children:"Do folders go home with players?"}),e.jsx(Ae,{name:"custody",value:!0,current:u,onChange:L,title:"Yes â folders go home with the players",detail
1:"Folders are handed out and collected back at the end of the season; the roll call by folder number tells you what's missing."}),e.jsx(Ae,{name:"custody",value:!1,current:u,onChange:L,title:"No â always collected at the end of rehearsal",detail:"Folders stay in the section bins; you record only the exceptions, one folder at a time."})]}),k===4&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-base font-medium text-gray-900",children:"Who is responsible for a folder before itâs checked out?"}),e.jsxs("p",{className:"text-sm text-gray-600",children:["This decides whose name a folder starts with. After that the name stays with the folder all season until you change it. ",G==null&&j?"Pre-selected from your last answer; change it if that is not how your band works.":""]}),e.jsx(Ae,{name:"holder",value:"seated",current:j,onChange:I,title:"The player seated on that chair",detail:"When a folder is first built, copy 1 of a chair goes to its first seated player, copy 2 to the second, and so on. After that the folder keeps its name when the seating changes. Percussion and extra folders have no chair, so they start with nobody."}),e.jsx(Ae,{name:"holder",value:"section_leader",current:j,onChange:I,title:"The section leader",detail:"The section's folders are the leader's until they hand each one to a player; the board shows the section and its leader."}),e.jsx(Ae,{name:"holder",value:"nobody",current:j,onChange:I,title:"Nobody until it's checked out",detail:"Every folder starts with no name; someone is recorded only when a folder is checked out or assigned. Hand out is not offered."})]}),k===5&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-base font-medium text-gray-900",children:"Who decides what goes in a folder?"}),e.jsx(Ae,{name:"dealing",value:"by_part",current:T,onChange:v,title:"The music does â a folder for each printed part",detail:"Four horn parts, four horn folders: each folder holds its part, and a chair whose part a piece does not print takes the next one up. You can still change any single seat with Choose parts inside a piece on the pull list."}),e.jsx(Ae,{name:"dealing",value:"by_seat",current:T,onChange:v,title:"The director does â a folder for each seat, parts cast piece by piece",detail:"Two horns and a piece with a 3rd part that matters: the director picks which printed part each seat's folder holds. You'll do it from the pull list, one piece at a time, and the choice is kept for the season."})]})]})]})}const Ws={ready:{label:"Ready",cls:"bg-green-100 text-green-800"},applied:{label:"Done",cls:"bg-green-100 text-green-800"},unmatched:{label:"No match â pick a member",cls:"bg-amber-100 text-amber-800"},duplicate:{label:"Number used twice",cls:"bg-red-100 text-red-800"},taken:{label:"Number on another folder",cls:"bg-red-100 text-red-800"},no_folder:{label:"No folder on this concert",cls:"bg-gray-100 text-gray-700"}
1,no_name:{label:"No name",cls:"bg-gray-100 text-gray-700"},no_number:{label:"No number",cls:"bg-gray-100 text-gray-700"}};function Js({isOpen:t,onClose:n,performanceId:a,onApplied:m}){const{showSuccess:d,showError:g}=be(),[k,p]=o.useState(""),[l,S]=o.useState(null),[w,f]=o.useState(null),C=o.useRef(null);o.useEffect(()=>{t||(p(""),S(null),f(null))},[t]);const c=()=>k.split(/\r?\n/).map((h,b)=>({line:b+1,raw:h})).filter(h=>h.raw.trim()).map(h=>{const b=h.raw.split(/\t|,|;/).map(U=>U.trim()).filter(Boolean),$=b.findIndex(U=>/^[A-Za-z]{0,3}-?\d{1,4}$/.test(U)),_=b.filter((U,Y)=>Y!==$);return{line:h.line,name:_[0]||"",number:$>=0?b[$].replace(/^[A-Za-z]*-?/,""):"",instrument:_[1]||null}});async function u(h){if(!h.some(b=>String(b.number||"").trim())){g("No folder numbers in this list. Starting fresh? Build folders and the numbers are assigned for you."),f(null);return}f("preview");try{const b=await q.importFolderNumbers(a,{rows:h,apply:!1});S(b),b.built||g("Build the folders first, then import the numbers.")}catch(b){g(b?.message||ue)}finally{f(null)}}async function L(h){const b=h.target.files?.[0];if(b){f("file");try{const{rows:$}=await q.parseFolderNumbersFile(a,b);p($.map(_=>
1[_.name,_.number,_.instrument].filter(Boolean).join(", ")).join(` 2`)),await u($)}catch($){g($?.message||"Could not read that file."),f(null)}finally{C.current&&(C.current.value="")}}}function G(h,b){S($=>{const _=$.rows.map((U,Y)=>Y===h?{...U,memberId:b||null}:U);return{...$,rows:_}})}async function I(){l&&await u(l.rows.map(h=>({line:h.line,name:h.name,number:h.number,instrument:h.instrument,memberId:h.memberId||h.member?.id||null})))}async function T(){if(l){f("apply");try{const h=l.rows.map(_=>({line:_.line,name:_.name,number:_.number,instrument:_.instrument,memberId:_.memberId||_.member?.id||null})),b=await q.importFolderNumbers(a,{rows:h,apply:!0});S(b);const $=b.rows.filter(_=>_.status!=="applied").length;d(`${b.summary.applied} folder number${b.summary.applied===1?"":"s"} recorded${$?`, ${$} to fix`:""}`),$||m?.()}catch(h){g(h?.message||ue)}finally{f(null)}}}const v=l?.rows?.filter(h=>h.status==="ready").length||0,j=(l?.members||[]).map(h=>({value:h.id,label:h.name}));return e.jsx(Ce,{isOpen:t,onClose:n,title:"Match numbers from a list",size:"lg",footer:e.jsxs("div",{className:"flex gap-2",children:[l?.built&&e.jsxs(N,{type:"button",onClick:T,isLoading:w==="apply",disabled:!!w||v===0,children:["Record ",v," number",v===1?"":"s"]}),e.jsx(N,{type:"button",variant:"ghost",onClick:n,children:l?.summary?.applied?"Done":"Cancel"})]}),children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-gray-600",children:"For numbers that are already tied to people: folders out with players when you joined, or names on the folders. Paste the rows from your sign-in sheet, one person per line: name, folder number, instrument. Or upload the sheet. Numbers are recorded exactly as you have them; a later Renumber would replace them. Starting fresh with numbered folders? Close this: Build assigned each folder a number already, and its contents go in the physical folder with that number."}),e.jsx(Dt,{label:"Rows",value:k,onChange:h=>p(h.target.value),rows:6,placeholder:`Helen Newman, 62, Clarinet 3Karen Steele, 69, Horn`,disabled:!!w}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(N,{type:"button",variant:"secondary",onClick:()=>u(c()),isLoading:w==="preview",disabled:!!w||!k.trim(),children:"Preview"}),e.jsxs("label",{className:"text-sm text-band-700 cursor-pointer",children:[e.jsx("span",{className:"underline",children:"Upload CSV or spreadsheet"}),e.jsx("input",{ref:C,type:"file",accept:".csv,.txt,.xlsx,.xls",className:"sr-only",onChange:L,disabled:!!w,"aria-label":"Upload CSV or spreadsheet"})]}),w==="file"&&e.jsx("span",{className:"text-xs text-gray-500",children:"Reading the fileâ¦"})]}),l?.built&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("p",{className:"text-sm text-gray-700","aria-live":"polite",children:[l.summary.total," row",l.summary.total===1?"":"s"," · ",v," ready",l.summary.counts.unmatched?` · ${l.summary.counts.unmatched} to match`:"",l.summary.counts.duplicate?` · ${l.summary.counts.duplicate} duplicate`:"",l.summary.counts.taken?` · ${l.summary.counts.taken} taken`:"",l.summary.counts.no_folder?` · ${l.summary.counts.no_folder} without a folder here`:"",l.summary.applied?` · ${l.summary.applied} recorded`:""]}),e.jsxs(Ns,{children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Name"}),e.jsx("th",{children:"Number"}),e.jsx("th",{children:"Folder"}),e.jsx("th",{children:"Status"})]})}),e.jsx("tbody",{children:l.rows.map((h,b)=>{const $=Ws[h.status]||{label:h.status,cls:"bg-gray-100 text-gray-700"};return e.jsxs("tr",{"data-testid":`import-row-${b}`,children:[e.jsxs("td",{className:"align-top",children:[e.jsx("div",{className:"text-sm text-gray-900",children:h.name||e.jsx("span",{className:"text-gray-400",children:"(blank)"})}),h.member&&e.jsxs("div",{className:"text-xs text-gray-500",children:["â ",h.member.name]}),h.status==="unmatched"&&e.jsx("div",{className:"mt-1 max-w-xs",children:e.jsx(Ze,{"aria-label":`Member for ${h.name}`,value:h.memberId||"",onChange:_=>G(b,_.target.value),options:j,placeholder:h.candidate?`Maybe ${h.candidate.name}?`:"Pick a member"})})]}),e.jsxs("td",{className:"align-top tabular-nums",children:[l.prefix?`${l.prefix}-`:"",h.number]}),e.jsx("td",{className:"align-top text-sm text-gray-600",children:h.folder?`${h.folder.label}${h.folder.currentNumber?` (now ${h.folder.currentNumber})`:""}`:""}),e.jsxs("td",{className:"align-top",children:[e.jsx("span",{className:`inline-flex px-2 py-0.5 rounded-full text-xs ${$.cls}`,children:$.label}),h.note&&e.jsx("div",{className:"text-xs text-gray-500 mt-0.5",children:h.note})]})]},`${h.line}-${b}`)})})]}),l.rows.some(h=>h.memberId)&&e.jsx(N,{type:"button",variant:"ghost",size:"sm",onClick:I,isLoading:w==="preview",disabled:!!w,children:"Check again"})]})]})})}const Te="extras",mt=t=>t.instrumentId===Te?Te:`${t.instrumentId}-${t.partNumber??"all"}`;function Zs({performanceId:t,onSaved:n,onClose:a,heading:m,intro:d}){const{showSuccess:g,showError:k}=be(),[p,l]=o.useState(void 0),[S,w]=o.useState(!1),[f,C]=o.useState(null),[c,u]=o.useState(null),[L,G]=o.useState(!1);function I({propose:P=!1}={}){return q.folderNumbering(t,{propose:P}).then(A=>{const K=(A.blocks||[]).map(D=>({instrumentId:D.instrumentId,instrumentName:D.instrumentName,partNumber:D.partNumber??null,size:String(D.size??(D.end!=null&&D.start!=null?D.end-D.start+1:1))}));l(D=>({blocks:Mt(K),isProposal:!!A.isProposal,prefix:A.prefix||D?.prefix||"",numberedFolders:A.numberedFolders||0}))})}o.useEffect(()=>{let P=!0;return I().catch(A=>{P&&(k(A?.message||"Couldnât load the numbering scheme."),a?.())}),()=>{P=!1}},[t]);const T=o.useMemo(()=>(p?.blocks||[]).filter(P=>P.instrumentId!==Te),[p]),v=o.useMemo(()=>(p?.blocks||[]).find(P=>P.instrumentId===Te)||null,[p]),j=o.useMemo(()=>{const P=new Map;let A=1;for(const K of[...T,...v?[v]:[]]){const D=Math.max(1,Math.floor(Number(K.size)||1));P.set(mt(K),{start:A,end:A+D-1}),A+=D}return P},[T,v]);function h(P){l(A=>({...A,blocks:Mt([...P,...v?[v]:[]])}))}const b=ks({items:T,onReorder:h});function $(P,A){const K=P+A;if(K<0||K>=T.length)return;const D=[...T];[D[P],D[K]]=[D[K],D[P]],h(D)}function _(P,A){l(K=>({...K,blocks:K.blocks.map(D=>mt(D)===P?{...D,size:A}:D)}))}async function U(){try{await I({propose:!0}),g("Proposed again from this concertâs chairs â nothing is saved until you save.")}catch(P){k(P?.message||"Couldnât propose a scheme.")}}async function Y(P){P.preventDefault(),w(!0);
3try{const A=await q.saveFolderNumbering(t,{blocks:[...T,...v?[v]:[]].map(K=>({instrumentId:K.instrumentId,instrumentName:K.instrumentName,partNumber:K.partNumber??null,size:Math.max(1,Math.floor(Number(K.size)||1))})),prefix:p.prefix.trim().toUpperCase()});g("Numbering saved."),p.numberedFolders>0?u(A.blocks||[]):n?.(A.blocks||[],{rebuilt:A.rebuilt??null})}catch(A){k(A?.message||"Couldnât save the numbering scheme.")}finally{w(!1)}}async function ye(){G(!0);try{const P=await q.renumberFolders(t);g(`Renumbered ${P.renumbered} folder${P.renumbered===1?"":"s"}. Print every label.`),n?.(c||[],{renumbered:P})}catch(P){k(P?.message||"Couldnât renumber the folders.")}finally{G(!1)}}if(p===void 0)return null;if(c){const P=p.numberedFolders;return e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-6 mb-4","data-testid":"folder-renumber-step",children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-500 uppercase tracking-wide mb-1",children:"Numbering saved â what about the folders you already have?"}),e.jsxs("p",{className:"text-base text-gray-700 mb-2",children:[P===1?"1 folder on this concert already carries a number.":`${P} folders on this concert already carry numbers.`," You can keep those, or start a new set from the new scheme."]}),e.jsxs("ul",{className:"text-base text-gray-700 list-disc pl-5 mb-4 space-y-1",children:[e.jsxs("li",{children:[e.jsx("strong",{children:"Keep existing numbers"})," â nothing on the folders changes. The new scheme is used for folders added from now on."]}),e.jsxs("li",{children:[e.jsxs("strong",{children:["Renumber all ",P]})," â every folder on this concert gets a fresh number in the new order, including any you typed by hand. ",e.jsx("strong",{children:"Every printed label is then out of date: print a full new set."})," The next concert inherits the new numbers."]})]}),e.jsxs("div",{className:"flex gap-2 pt-2",children:[e.jsx(N,{type:"button",variant:"primary",size:"md",onClick:()=>n?.(c),children:"Keep existing numbers"}),e.jsxs(N,{type:"button",variant:"secondary",size:"md",isLoading:L,onClick:ye,children:["Renumber all ",P," folders"]})]})]})}const Z=p.prefix,se=P=>Z?`${Z}-${String(P).padStart(2,"0")}`:String(P),ne=P=>{const A=j.get(P);return A?`${se(A.start)} â ${se(A.end)}`:""};return e.jsxs("form",{onSubmit:Y,className:"bg-white rounded-xl border border-gray-200 p-6 mb-4","data-testid":"folder-numbering-panel",children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-500 uppercase tracking-wide mb-1",children:m||"Folder numbering"}),e.jsx("p",{className:"text-base text-gray-700 mb-4",children:d||(p.isProposal?"Proposed from this concertâs chairs, in score order, one row per part with two spare folders each. Drag the rows into the order you want, set how many folders each part needs, and the numbers follow.":"One row per part. Drag the rows into the order you want and set how many folders each part needs â the numbers follow, so every part stays together and a missing number always names its part. It holds for every concert until you edit it again.")}),e.jsx("div",{className:"max-w-xs mb-4",children:e.jsx(Ee,{label:"Prefix (up to 2 letters, optional)",placeholder:"CB",maxLength:2,value:Z,onChange:P=>l(A=>({...A,prefix:P.target.value.replace(/[^A-Za-z0-9]/g,"").slice(0,2).toUpperCase()})),hint:Z?`Folders print as ${Z}-01, ${Z}-02 â¦`:"e.g. CB for Concert Band â folders then print as CB-01",className:"!text-base"})}),p.blocks.length===0?e.jsx("p",{className:"text-base text-gray-500 mb-4",children:"No seated chairs to number yet â seat the roster for this concert first."}):e.jsxs("div",{className:"mb-4",children:[e.jsxs("p",{className:"text-sm text-sky-900 bg-sky-50 border border-sky-200 rounded-xl px-4 py-2 mb-3","data-testid":"numbering-order-tip",children:[e.jsx("span",{className:"font-semibold",children:"The order of this list is the order of the folder numbers."})," ","Drag a row by its grip ",e.jsx("span",{"aria-hidden":"true",children:"â®â®"})," (or use the arrows at the right) to move an instrument up or down â the numbers re-lay from the top as you go. Set how many folders each part gets in the Folders box."]}),e.jsxs("div",{className:"hidden sm:grid grid-cols-[1.5rem_1fr_6rem_9rem_6.5rem] gap-3 text-xs uppercase tracking-wide text-gray-400 px-1 mb-1",children:[e.jsx("span",{}),e.jsx("span",{children:"Part"}),e.jsx("span",{children:"Folders"}),e.jsx("span",{children:"Numbers"}),e.jsx("span",{children:"Move"})]}),e.jsx("ul",{className:"space-y-1","aria-label":"Parts in numbering order",children:T.map((P,A)=>{const K=mt(P),D=P.instrumentName||P.instrumentId;return e.jsxs("li",{...b.tapMode?b.getRowProps(A):{}
3,draggable:f===A&&!b.tapMode,onDragStart:()=>b.handleDragStart(A),onDragOver:he=>b.handleDragOver(he,A),onDrop:he=>b.handleDrop(he,A),onDragEnd:()=>{C(null),b.handleDragEnd()},className:`grid ${b.tapMode?"grid-cols-[2.75rem_minmax(0,1fr)_4.5rem]":"grid-cols-[minmax(0,1fr)_4.5rem]"} sm:grid-cols-[1.5rem_1fr_6rem_9rem_6.5rem] gap-2 sm:gap-3 items-center rounded-lg border px-1 py-1 ${b.dragOverIndex===A?"border-band-400 bg-band-50":"border-transparent"}`,children:[e.jsx("span",{className:`sm:inline shrink-0 cursor-grab ${b.tapMode?`rounded-md border text-gray-500 ${b.picked===A?"border-band-500 bg-band-50 ring-2 ring-band-500":"border-gray-300 bg-white"}`:"hidden text-gray-300"}`,"aria-hidden":b.tapMode?void 0:"true",...b.tapMode?b.getHandleProps(A):{},"data-testid":`grip-${K}`,onMouseDown:()=>C(A),onMouseUp:()=>C(null),onMouseLeave:()=>{f===A&&b.dragOverIndex==null&&C(null)},children:e.jsxs("svg",{className:"h-4 w-4",fill:"currentColor",viewBox:"0 0 20 20",children:[e.jsx("circle",{cx:"7",cy:"5",r:"1.5"}),e.jsx("circle",{cx:"7",cy:"10",r:"1.5"}),e.jsx("circle",{cx:"7",cy:"15",r:"1.5"}),e.jsx("circle",{cx:"13",cy:"5",r:"1.5"}),e.jsx("circle",{cx:"13",cy:"10",r:"1.5"}),e.jsx("circle",{cx:"13",cy:"15",r:"1.5"})]})}),e.jsxs("span",{className:"text-base text-gray-900 min-w-0",children:[D,e.jsx("span",{className:"block sm:hidden text-sm text-gray-500 tabular-nums",children:ne(K)})]}),e.jsx(Ee,{type:"number",min:1,max:999,step:1,inputMode:"numeric","aria-label":`${D} folders`,value:P.size,onChange:he=>_(K,he.target.value),className:"!text-base"}),e.jsx("span",{className:"hidden sm:inline text-base text-gray-600 tabular-nums","data-testid":`range-${K}`,children:ne(K)}),e.jsxs("span",{className:`flex gap-1 justify-end sm:justify-start ${b.tapMode?"col-start-2 col-span-2":"col-span-2"} sm:col-start-auto sm:col-span-1`,children:[e.jsx(N,{type:"button",variant:"secondary",size:"sm",className:"!px-2 min-h-[2.75rem] min-w-[2.75rem] sm:min-h-0 sm:min-w-0",title:"Move up","aria-label":`Move ${D} up`,disabled:A===0,onClick:()=>$(A,-1),children:e.jsx("svg",{className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2.5,"aria-hidden":"true",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"})})}),e.jsx(N,{type:"button",variant:"secondary",size:"sm",className:"!px-2 min-h-[2.75rem] min-w-[2.75rem] sm:min-h-0 sm:min-w-0",title:"Move down","aria-label":`Move ${D} down`,disabled:A===T.length-1,onClick:()=>$(A,1),children:e.jsx("svg",{className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2.5,"aria-hidden":"true",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})})]})]},K)})}),v&&e.jsxs("div",{className:`grid ${b.tapMode?"grid-cols-[2.75rem_minmax(0,1fr)_4.5rem]":"grid-cols-[minmax(0,1fr)_4.5rem]"} sm:grid-cols-[1.5rem_1fr_6rem_9rem_6.5rem] gap-2 sm:gap-3 items-center px-1 py-1 mt-2 border-t border-gray-200 pt-3`,children:[e.jsx("span",{className:b.tapMode?"sm:inline":"hidden sm:inline"}),e.jsxs("span",{className:"text-base text-gray-900 min-w-0",children:[v.instrumentName||"Extra folders (no one seated)",e.jsx("span",{className:"block text-sm text-gray-500",children:"Always last. Grows on its own if a part runs out."})]}),e.jsx(Ee,{type:"number",min:1,max:999,step:1,inputMode:"numeric","aria-label":"Extra folders folders",value:v.size,onChange:P=>_(Te,P.target.value),className:"!text-base"}),e.jsx("span",{className:"hidden sm:inline text-base text-gray-600 tabular-nums","data-testid":"range-extras",children:ne(Te)}),e.jsx("span",{className:"sm:hidden col-span-full text-sm text-gray-500 tabular-nums",children:ne(Te)}),e.jsx("span",{className:"hidden sm:inline"})]})]}),e.jsxs("div",{className:"flex gap-2 pt-2 flex-wrap",children:[e.jsx(N,{type:"submit",variant:"primary",size:"md",isLoading:S,disabled:p.blocks.length===0&&!Z,children:"Save changes"}),e.jsx(N,{type:"button",variant:"secondary",size:"md",onClick:a,children:"Cancel"}),!p.isProposal&&e.jsx(N,{type:"button",variant:"ghost",size:"md",className:"ml-auto",onClick:U,children:"Start over from this concertâs chairs"})]})]})}function Mt(t){return[...t.filter(n=>n.instrumentId!==Te),...t.filter(n=>n.instrumentId===Te)]}const Xs=[{value:"new",label:"Only folders new this concert"},{value:"all",label:"Every folder"},{value:"numbers",label:"Just these numbersâ¦"},{value:"blank",label:"Blank labels (hand-write the number and instrument)"}],Qs=[{value:"part",label:"Instrument and chair"},{value:"holder",label:"Player's name, then instrument"}];function en({performanceId:t,defaultWhich:n="new",defaultStyle:a="part",onClose:m}
3){const[d,g]=o.useState(n),[k,p]=o.useState(a),[l,S]=o.useState(""),[w,f]=o.useState("4");return e.jsxs("div",{"data-testid":"folder-labels-chooser",children:[e.jsx("p",{className:"text-base text-gray-700 mb-3",children:"One 7Ã2â³ label per folder, four to a sheet: the folder number in the top corner, the instrument and chair across the label, property-of, and who to ask. A folder keeps its label from concert to concert, so you usually only need the new ones. Blank labels print the frame to hand-write."}),e.jsxs("div",{className:"flex flex-wrap items-end gap-3",children:[e.jsx(Ze,{label:"Which folders",value:d,onChange:C=>g(C.target.value),options:Xs,className:"!text-base"}),d!=="blank"&&e.jsx(Ze,{label:"Label shows",value:k,onChange:C=>p(C.target.value),options:Qs,className:"!text-base"}),d==="numbers"&&e.jsx(Ee,{label:"Folder numbers",placeholder:"26, 38",value:l,onChange:C=>S(C.target.value),className:"!text-base"}),d==="blank"&&e.jsx(Ee,{label:"How many",type:"number",min:1,max:200,step:1,inputMode:"numeric",value:w,onChange:C=>f(C.target.value),hint:"4 per sheet",className:"!text-base"})]}),e.jsxs("div",{className:"flex gap-2 pt-4",children:[e.jsx(N,{type:"button",variant:"primary",size:"md",disabled:d==="numbers"&&!l.trim()||d==="blank"&&!(Number(w)>=1),onClick:()=>Ot.openPdf(q.folderLabelsUrl(t,{which:d,style:k,numbers:l.split(/[,\s]+/).filter(Boolean),count:Math.max(1,Math.min(200,Number(w)||4))})),children:"Open labels PDF"}),e.jsx(N,{type:"button",variant:"secondary",size:"md",onClick:m,children:"Close"})]})]})}function tn({isOpen:t,performanceId:n,performanceTitle:a,building:m=!1,onClose:d,onRebuild:g}){const{showError:k}=be(),[p,l]=o.useState(void 0),[S,w]=o.useState([]);return o.useEffect(()=>{if(!t)return;let f=!1;return l(void 0),q.auxCandidates(n).then(C=>{if(!f){if(!C?.candidates?.length){l(null);return}l(C),w(C.selected||[])}}).catch(C=>{f||(l(null),k(C?.message||"Couldnât check the program for extra instruments."))}),()=>{f=!0}},[t,n]),e.jsx(Ce,{isOpen:t,onClose:d,title:`Rebuild from roster${a?` â ${a}`:""}`,footer:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(N,{type:"button",variant:"primary",size:"md",isLoading:m,disabled:p===void 0,onClick:()=>g(p?S:[]),"data-testid":"rebuild-confirm",children:"Rebuild from roster"}),e.jsx(N,{type:"button",variant:"secondary",size:"md",onClick:d,children:"Cancel"})]}),children:e.jsxs("div",{"data-testid":"rebuild-folders-dialog",children:[e.jsx("p",{className:"text-base text-gray-700 mb-3",children:"Every folder is dealt again from todayâs seating and program. Packing ticks carry over for any piece that stays in the same folder, and a folder someone is carrying is never rewritten."}),p===void 0&&e.jsx("p",{className:"text-sm text-gray-400",children:"Checking the program for extra instrumentsâ¦"}),p&&e.jsxs("div",{"data-testid":"aux-folders-dialog",children:[e.jsx("p",{className:"text-base text-gray-700 mb-3",children:"This program calls for instruments nobody in the band currently plays. Build a folder for them anyway, in case someone borrows or subs in?"}),e.jsx("div",{className:"space-y-2 mb-3",children:p.candidates.map(f=>{const C=S.includes(f.instrumentId);return e.jsxs("label",{className:"flex items-start gap-3 cursor-pointer min-h-[44px]",children:[e.jsx("input",{type:"checkbox",className:"mt-1 h-6 w-6 rounded border-gray-300 text-band-600 focus:ring-2 focus:ring-band-500",checked:C,onChange:c=>w(u=>c.target.checked?[...u,f.instrumentId]:u.filter(L=>L!==f.instrumentId))}),e.jsxs("span",{className:"text-base text-gray-900",children:[f.instrumentName,e.jsxs("span",{className:"block text-sm text-gray-500",children:[f.pieceCount===1?"1 piece":`${f.pieceCount} pieces`,": ",f.pieces.slice(0,3).join(", "),f.pieces.length>3?` +${f.pieces.length-3} more`:""]})]})]},f.instrumentId)})}),e.jsx("p",{className:"text-sm text-gray-500",children:"Remembered for next time â the plain Build uses whatever you tick here."})]})]})})}function Et(t,n,a){const m=t?.folders||[],d={setlistChanged:!1,countChanged:!1,anyPacked:!1,builtCount:m.filter(p=>!p.aux).length};if(!m.length)return d;const g=new Set(m.flatMap(p=>
3p.items.map(l=>l.musicId))),k=n?new Set(n):null;return d.setlistChanged=!!k&&([...k].some(p=>!g.has(p))||[...g].some(p=>!k.has(p))),d.countChanged=a!=null&&d.builtCount!==a,d.anyPacked=m.some(p=>p.items.some(l=>l.packedAt&&!l.alreadyIn)),d}const et=(t,n,a)=>t===1?n:a;function sn(t){return t.items.length>0&&t.items.every(n=>n.packedAt)}function nn(t=[],n){if(n)return n;const a=m=>t.filter(d=>d.status===m).length;return{total:t.length,out:a("out"),missing:a("missing"),returned:a("returned"),inBin:t.filter(m=>!m.status||m.status==="built").length,packed:t.filter(sn).length}}function an({pull:t,folders:n,musicGoesHome:a=null,holderDefault:m=null,canWrite:d=!0}={}){const g=t?.pieces||[],k=n?.folders||[],p=k.length>0,l=(n?.changes||[]).length,S=g.filter(U=>Ge(U).length>0),w=S.filter(U=>U.pulledAt).length,f=S.filter(U=>U.pulledAt&&(U.readiness?.state||"ready")==="ready"&&!Ge(U).some(Y=>Y.uncounted||Y.shortfall>0&&!Y.resolution)).length,C=t?.readinessRollup||{total:g.length,notScanned:0,needsAttention:0},c=C.notScanned??g.filter(U=>U.readiness?.state==="not_scanned").length,u=C.needsAttention??0,L=g.filter(U=>Ge(U).some(Y=>Y.uncounted)).length,G=t?.rollup?.shortfallParts??0,I=t?.rollup?.undecidedShortParts??0,T=p?Et(n,S.map(U=>U.id),t?.foldersNeeded??null):null,v=!!T&&(T.setlistChanged||T.countChanged),j=[];g.length===0?j.push("Nothing on the program yet"):(S.length>0&&j.push(`${f} of ${S.length} ready`),w>f&&j.push(`${w-f} pulled with something to settle`),c>0&&j.push(`${c} not scanned`),u>0&&j.push(`${u} ${et(u,"part has","parts have")} no instrument yet`),L>0&&j.push(`${L} ${et(L,"set","sets")} never counted`),G>0&&j.push(`${G} short${I>0&&I<G?` (${G-I} decided)`:I===0?" (decided)":""}`),p&&v?j.push("program changed since the build"):p&&l>0&&j.push(`${l} ${et(l,"change","changes")} to make on the shelf`));let h=null;d&&g.length>0&&(p?v&&(h={action:"update",label:"Update folders"}):h={action:"build",label:"Build folders"});const b=nn(k,n?.custodySummary),$=[];p?($.push(`${b.total} ${et(b.total,"folder","folders")}`),$.push(`${b.packed} packed`),b.out>0&&$.push(`${b.out} out`),b.missing>0&&$.push(`${b.missing} missing`),b.returned>0&&$.push(`${b.returned} checked in`),l>0&&$.push(`${l} ${et(l,"change","changes")} since the last build`),n?.foldersSharedAt||$.push("not yet shared")):$.push("No folders built yet");let _=null;return d&&p&&(b.out>0||b.missing>0?_={action:"check-in",label:"Check inâ¦"}:a===!0&&m!=="nobody"&&(_={action:"hand-out",label:"Hand out"})),{built:p,stale:v,defaultTab:p?"folders":"prepare",prepare:{statusLine:j.join(" · "),primary:h},folders:{statusLine:$.join(" · "),primary:_,counts:b}}}const rn="You keep a set number of folders per chair, usually the copies you own. This starts from this concert's seating with two spare per part: drag the rows into your order and set the count for each chair. Exactly that many folders get built and labelled, whether or not every seat is filled; more players seated than folders means they share. You can change the counts any time under Numberingâ¦.",ln=[{key:"prepare",label:"Prepare"},{key:"folders",label:"Folders"}],ut={folders:[],candidates:{},numbering:{blocks:[]},changes:[]};function Fn(){Jt();const{currentOrg:t}=Ht(),{showError:n,showSuccess:a}=be(),{canAny:m}=Ut(),d=m("music:update"),g=qt(),[k,p]=Gt(),l=k.get("perf")||"",S=o.useRef(l);S.current=l;const w=(y,M)=>p(O=>{const W=new URLSearchParams(O);return M?W.set(y,M):W.delete(y),W},{replace:!0}),f=y=>w("perf",y),C=k.get("tab"),[c,u]=o.useState(void 0),[L,G]=o.useState({count:0,ensembles:[]}),[I,T]=o.useState([]),[v,j]=o.useState(void 0),[h,b]=o.useState(void 0),[$,_]=o.useState(void 0),[U,Y]=o.useState(null),ye=o.useRef(null);o.useEffect(()=>{if(!t)return;let y=!1;return Promise.all([q.list(t.id),vs.list(t.id).catch(lt("folders concert picker: ensembles list only filters self-managed ones out"))]).then(([M,O])=>{if(y)return;const W=new Set((Array.isArray(O)?O:[]).filter(F=>F.libraryMode==="self_managed").map(F=>F.id)),s=Kt(),x=(Array.isArray(M)?M:[]).filter(F=>!F.cancelledAt&&!F.deletedAt&&F.performanceDate>=s),r=x.filter(F=>F.ensembleId&&W.has(F.ensembleId)),E=x.filter(F=>!F.ensembleId||!W.has(F.ensembleId)).sort((F,R)=>String(F.performanceDate).localeCompare(String(R.performanceDate)));T((Array.isArray(O)?O:[]).map(F=>({id:F.id,name:F.name,libraryMode:F.libraryMode,upcoming:x.filter(R=>R.ensembleId===F.id).length}))),G({count:r.length,ensembles:(Array.isArray(O)?O:[]).filter(F=>r.some(R=>R.ensembleId===F.id)).map(F=>({id:F.id,name:F.name}))}),u(E),E.length>0&&!E.some(F=>F.id===S.current)&&f(E[0].id)}).catch(()=>{y||(u([]),n(Je("performances")))}),()=>{y=!0}},[t]);const Z=o.useCallback(()=>
3{if(!S.current)return Promise.resolve();const y=S.current;return q.pullList(y).then(M=>{S.current===y&&b(M)}).catch(M=>{S.current===y&&(n(M?.message||Je("the pull list")),b(O=>O??null))})},[]),se=o.useCallback(()=>{if(!S.current)return Promise.resolve();const y=S.current;return q.folders(y).then(M=>{S.current===y&&_(M||ut)}).catch(M=>{S.current===y&&(n(M?.message||Je("the folders")),_(O=>O??ut))})},[]),ne=o.useCallback(()=>Promise.all([Z(),se()]),[Z,se]);o.useEffect(()=>{if(j(void 0),b(void 0),_(void 0),Y(null),ye.current=null,!l)return;let y=!1;return q.folderSettings(l).then(M=>{y||j(M||null)}).catch(lt("folder settings: a band with no answers runs on the defaults")).then(()=>{y||j(M=>M===void 0?null:M)}),Z(),se(),q.auxCandidates(l).then(M=>{y||Y(M||null)}).catch(lt("extra-folder candidates: the line is informational; Build uses the remembered preference")),()=>{y=!0}},[l]);const P=v?.settings||null,A=v?.effectiveHolderDefault||$?.holderDefault||ys(P),K=o.useMemo(()=>an({pull:h,folders:$,musicGoesHome:P?.musicGoesHome??null,holderDefault:A,canWrite:d}),[h,$,P,A,d]),D=h!==void 0&&$!==void 0,he=C==="prepare"||C==="folders"?C:K.defaultTab,Re=y=>w("tab",y),[pe,ie]=o.useState(!1),[Se,Me]=o.useState(!1);async function xe(y){ie(!0);try{const M=await q.buildFolders(l,{auxInstrumentIds:y});_(M),Me(!1);const O=M?.buildReport||{};if(M?.deltaOnly)a(O.newPieceItems>0?"Changes recorded â the new music is listed in each folder as not yet in. Print the changes sheet. Folders are out with players, so nothing else was moved.":"Changes recorded â print the changes sheet. Folders are out with players, so nothing was moved.");else{const W=[];O.assigned>0&&W.push(`${O.assigned} numbered${O.reused>0?` (${O.reused} kept from last concert)`:""}`),O.unresolved?.notScanned?.length&&W.push(`${O.unresolved.notScanned.length} ${O.unresolved.notScanned.length===1?"piece":"pieces"} not scanned â in every folder until scanned`),O.unresolved?.unmatched?.length&&W.push(`${O.unresolved.unmatched.length} ${O.unresolved.unmatched.length===1?"part":"parts"} with no instrument â hand out by hand`),O.unnumbered?.length&&W.push(`${O.unnumbered.length} with no folder #`),O.overflow?.length&&W.push(`${O.overflow.length} numbered from Extra folders â widen the range under Numberingâ¦`),a(`Folders built${W.length?`. ${W.join("; ")}.`:"."}`)}y&&q.auxCandidates(l).then(W=>Y(W||null)).catch(lt("extra-folder candidates refresh"))}catch(M){n(M?.message||"Couldnât build folders.")}finally{ie(!1)}}o.useEffect(()=>{if(!D||!d||pe||!l||ye.current===l)return;const y=$?.folders||[];if(!y.length||y.some(W=>W.status&&W.status!=="built"))return;const M=Et($,(h?.pieces||[]).filter(W=>Ge(W).length>0).map(W=>W.id),h?.foldersNeeded??null);if(!(M.setlistChanged||M.countChanged)||M.anyPacked)return;const O=setTimeout(()=>{ye.current!==l&&(ye.current=l,xe(void 0))},0);return()=>clearTimeout(O)},[D,$,h,d,l]);const[Fe,De]=o.useState(!1),[ae,J]=o.useState(!1),[Q,ze]=o.useState(!1);async function Ie(y,{silent:M=!1}={}){ze(!0);try{const O=await q.saveFolderSettings(l,y);j(O),De(!1),M||(J(y.folderBasis==="fixed"),a(y.folderBasis==="fixed"?"Folder settings saved. Now set how many folders each chair gets.":"Folder settings saved."),ne())}catch(O){n(O?.message||ue)}finally{ze(!1)}}const Xe=y=>Ie({prefix:v?.prefix||"",newLabelsEachPerformance:P?.newLabelsEachPerformance??!1,folderBasis:P?.folderBasis||"roster",musicGoesHome:y,holderDefault:P?.holderDefault??null},{silent:!0}),[ee,i]=o.useState(null);o.useEffect(()=>{if(!ee)return;const y=setTimeout(()=>{window.print(),i(null)},60);return()=>clearTimeout(y)},[ee]);const z=y=>{g?Wt(`/app/print/folders/${y}/${l}`,{isMobile:!0}):i(y)},[B,X]=o.useState(!1),[je,oe]=o.useState(!1),[_e,Ke]=o.useState(!1),[Be,ce]=o.useState(null),[ge,re]=o.useState(null),[me,Pe]=o.useState(!1);async function He(){const y=ge==="pack";Pe(!0);try{await q.packFolders(l,{packed:y}),a(y?"Every folder is marked packed.":"All packing ticks cleared."),re(null),se()}catch(M){n(M?.message||ue)}finally{Pe(!1)}}const[Le,Oe]=o.useState(!1);async function Ye(y){Oe(!0);try{const M=await q.shareFolders(l,y);M&&_(O=>({...O||ut,...M})),a(y?"Section leaders can see these folders now.":"Hidden from section leaders.")}catch(M){n(M?.message||ue)}finally{Oe(!1)}}async function Ve(){try{await q.ackFolderChanges(l),a("Note cleared. Nothing in the app changed."),se()}catch(y){n(y?.message||ue)}}const le=$?.folders||[],de=le.length>0,Ne=le.flatMap(y=>y.items),ke=Ne.filter(y=>y.packedAt).length,Ue=($?.changes||[]).length,qe=o.useMemo(()=>(c||[]).map(y=>({value:y.id,label:`${Ft(y.performanceDate)} â ${y.title}${y.ensembleName?` (${y.ensembleName})`:""}${y.publishedAt?"":" â not published yet"}`})),[c]),ve=h?.performance||(c||[]).find(y=>y.id===l)||null,at=l&&c?.length>0?e.jsxs(H,{align:"right",menuId:"folders-more",trigger:e.jsx(N,{variant:"ghost",size:"md",className:"min-h-[2.75rem]",children:"More"}),children:[e.jsxs(H.Section,{label:"Print",children:[e.jsx(H.Item,{onClick:()=>z("pull"),children:"Print pull sheet"}),de?e.jsx(H.Item,{onClick:()=>z("build"),children:"Print build sheet"}):null,de?e.jsx(H.Item,{onClick:()=>z("checkout"),children:"Print check-out sheet"}):null,de&&Ue>0?e.jsx(H.Item,{onClick:()=>z("changes"),children:"Print changes sheet"}):null,de?e.jsx(H.Item,{onClick:()=>{ce(null),oe(!0)},children:"Print labelsâ¦"}):null]}),e.jsxs(H.Section,{label:"Folders",children:[d?e.jsx(H.Item,{onClick:()=>X(!0),children:"Numberingâ¦"}):null,d&&de?e.jsx(H.Item,{onClick:()=>Ke(!0),children:"Match numbers from a listâ¦"}):null,d&&de?e.jsx(H.Item,{onClick:()=>Me(!0),children:"Rebuild from rosterâ¦"}):null,d&&de&&ke<Ne.length?e.jsx(H.Item,{onClick:()=>re("pack"),children:"Mark all packed"}):null,d&&ke>0?e.jsx(H.Item,{onClick:()=>re("clear"),children:"Clear packing ticks"}):null]}),e.jsx(H.Section,{label:"Settings",children:d&&v?.ensembleId?e.jsx(H.Item,{onClick:()=>De(!0),children:"Folder settingsâ¦"}):null})]}):null,ot=y=>{(y==="build"||y==="update")&&xe(void 0)};let we;if(c===void 0)we=e.jsx("p",{className:"text-sm text-gray-400 py-6",children:"Loadingâ¦"});
3else if(c.length===0&&L.count>0){const y=L.ensembles.map(s=>s.name).join(", "),M=L.ensembles.length===1?L.ensembles[0]:null,O=I.filter(s=>s.libraryMode!=="self_managed"&&s.upcoming===0),W=O.length?` ${O.map(s=>s.name).join(", ")} ${O.length===1?"is":"are"} librarian-managed but ${O.length===1?"has":"have"} no upcoming concert; folders are built per concert, so add one on Performances first.`:"";we=e.jsx($e,{card:!0,title:`${y||"This ensemble"} ${L.ensembles.length===1?"is":"are"} set to Self-managed: members hold their own parts.`,description:`Music Folders builds folders for a librarian-managed library, so ${L.count===1?"its upcoming concert is":`${L.count} upcoming concerts are`} not listed here. To build folders, change Library Management on the ensemble to Librarian-managed.${W}`,action:d?e.jsx(Yt,{to:M?`/ensembles?highlight=${M.id}`:"/ensembles",className:Vt({variant:"primary",size:"md"}),children:"Open ensemble settings"}):void 0})}else if(c.length===0)we=e.jsx($e,{card:!0,title:"No upcoming performances.",description:"Folders are built per concert, so thereâs nothing to pull yet."});else if(!l||!D||v===void 0)we=e.jsx("p",{className:"text-sm text-gray-400 py-6",children:"Loadingâ¦"});else if(B||ae)we=e.jsx(Zs,{performanceId:l,heading:ae?"How many folders for each chair":void 0,intro:ae?rn:void 0,onSaved:(y,{renumbered:M,rebuilt:O}={})=>{X(!1),J(!1),ne(),O!=null&&a(`Folders rebuilt to match your counts (${O}).`),M&&(a(`New set: ${M.renumbered||""} folders renumbered. Every printed label is now out of date â print every label before these folders go out.`),ce("all"),oe(!0))},onClose:()=>{X(!1),J(!1)}});else{const y=he==="prepare"?K.prepare.statusLine:K.folders.statusLine;we=e.jsxs("div",{children:[e.jsx(Xt,{tabs:ln.map(M=>
3M.key==="folders"&&de?{...M,count:le.length}:M),value:he,onChange:Re,ariaLabel:"Music Folders",className:g?"mb-2 [&>[role=tab]]:flex-1 [&>[role=tab]]:justify-center [&>[role=tab]]:text-center":"mb-2"}),e.jsx("p",{className:"text-base text-gray-700 mb-3","aria-live":"polite","data-testid":"folders-status",children:y}),ve&&!ve.publishedAt&&e.jsx("p",{className:"text-sm text-gray-500 -mt-2 mb-3","data-testid":"folders-unpublished-note",children:"This concert isnât published yet â members canât see it, and the program may still change."}),he==="prepare"?e.jsx(zs,{data:h,performanceId:l,canWrite:d,compact:g,onChanged:ne,primary:K.prepare.primary,onPrimary:ot,building:pe,aux:U,onAddAux:M=>xe([...U?.selected||[],...M]),onPrint:()=>z("pull")}):e.jsx(Rs,{data:$,setData:_,performanceId:l,canWrite:d,isMobile:g,musicGoesHome:P?.musicGoesHome??null,folderBasis:P?.folderBasis||"roster",holderDefault:A,onSaveGoesHome:Xe,savingGoesHome:Q,primary:K.folders.primary,building:pe,onBuild:()=>xe(void 0),onChanged:se,onPrintChanges:()=>z("changes"),onAck:Ve,sharing:h?.sharing||[],foldersSharedAt:$?.foldersSharedAt||null,foldersSharedByName:$?.foldersSharedByName||null,onShare:Ye,sharingBusy:Le,onPrintBuild:()=>z("build"),onPrintCheckout:()=>z("checkout"),onPrintLabels:()=>{ce(null),oe(!0)}})]})}const rt=l?e.jsxs(e.Fragment,{children:[e.jsx(Ce,{isOpen:Fe,onClose:()=>De(!1),title:"Folder settings",size:"lg",children:e.jsx(Vs,{ensembleName:v?.ensembleName,initial:{prefix:v?.prefix,...v?.settings?.completedAt?v.settings:{}},onSubmit:Ie,onCancel:()=>De(!1),isSubmitting:Q,submitLabel:v?.settings?.completedAt?"Save settings":"Start using folders"},`${l}-${v?.ensembleId||""}`)}),e.jsx(Js,{isOpen:_e,onClose:()=>Ke(!1),performanceId:l,onApplied:()=>{Ke(!1),se()}}),e.jsx(Ce,{isOpen:je,onClose:()=>oe(!1),title:"Print folder labels",size:"lg",children:je&&e.jsx(en,{performanceId:l,defaultWhich:Be||(P?.newLabelsEachPerformance?"all":"new"),defaultStyle:P?.folderDealing==="by_seat"?"holder":"part",onClose:()=>oe(!1)})}),e.jsx(tn,{isOpen:Se,performanceId:l,performanceTitle:ve?.title,building:pe,onClose:()=>Me(!1),onRebuild:y=>xe(y)}),e.jsx(ht,{isOpen:!!ge,onClose:()=>re(null),onConfirm:He,isLoading:me,title:ge==="clear"?"Clear all packing ticks?":"Mark every folder packed?",message:ge==="clear"?`Every piece in all ${le.length} folders goes back to unpacked. Use this to start packing over.`:`This ticks the ${Ne.length-ke} pieces still unpacked across ${le.length} folders. Only do this once the folders really are packed; you can untick any piece afterwards.`,confirmLabel:ge==="clear"?"Clear ticks":"Mark all packed",confirmVariant:ge==="clear"?"danger":"primary"}),ee==="pull"&&h&&e.jsx(ns,{performance:h.performance,printPieces:as(rs(h.pieces||[],h.percussion?.folders)),percussion:h.percussion,foldersNeeded:h.foldersNeeded}),ee==="checkout"&&$&&e.jsx(ls,{performance:ve,folders:le}),(ee==="build"||ee==="changes")&&$&&e.jsx(is,{performance:ve,folders:le,changes:$.changes||[],mode:ee==="changes"?"changes":"full"})]}):null;return g?e.jsxs("div",{className:"px-4 pt-3 pb-4","data-testid":"music-folders-mobile",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[(c||[]).length>0?e.jsx(Ze,{value:l,onChange:y=>f(y.target.value),"aria-label":"Concert",className:"w-full !text-base !py-2.5 h-11",options:qe}):e.jsx("h1",{className:"text-[22px] font-bold text-gray-900 leading-none flex-1",children:"Music Folders"}),e.jsx("span",{className:"shrink-0",children:at})]}),c?.length>0&&L.count>0&&e.jsxs("p",{className:"text-xs text-gray-500 mb-3",children:[L.ensembles.map(y=>y.name).join(", ")," ",L.ensembles.length===1?"is":"are"," set to Self-managed, so ",L.count===1?"its concert is":`${L.count} concerts are`," not in the picker."]}),we,rt]}):e.jsxs("div",{className:"px-4 md:px-0",children:[e.jsx(Zt,{title:"Music Folders",breadcrumbs:[{label:"Home",to:"/"},{label:"Music Folders"}],actions:(c||[]).length>0?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ze,{value:l,onChange:y=>f(y.target.value),"aria-label":"Concert",className:"w-72",options:qe}),at]}):null}),c?.length>0&&L.count>0&&e.jsxs("p",{className:"text-xs text-gray-500 -mt-2 mb-3","data-testid":"self-managed-note",children:[L.ensembles.map(y=>y.name).join(", ")," ",L.ensembles.length===1?"is":"are"," set to Self-managed, so ",L.count===1?"its concert is":`${L.count} concerts are`," not in the picker."]}),l&&D&&v!==void 0&&c?.length>0?e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 p-6",children:we}):we,rt]})}export{Fn as MusicFoldersPage};
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.