1import{v as C,c as L,r as p,t as k,j as t,B as g,L as B,J as R,F as I,d as N,l as D}from"./index-_aijvlUq.js";import{P}from"./PageHeader-DCofr6qo.js";import{I as v}from"./Input-ysTyZFq5.js";import{E as w}from"./EmptyState-CPGKooqj.js";import{W}from"./WhoList-DOo2DXJ4.js";import{d as F}from"./exportCsv-CZAUSrIW.js";import{h as $,a as _}from"./helpWanted-C0itiuLN.js";const z={getReport({start:l,end:a}={}){const i={};return l&&(i.start=l),a&&(i.end=a),C.get("/reports/volunteer-hours",{params:i})}},A={signed_up:"Signed up and did not withdraw",leader:"Set by a leader"};function h(l){const a=String(l??"");return/^[=+\-@]/.test(a)?`'${a}`:a}function H({label:l,value:a,sub:i}){return t.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-4 text-center",children:[t.jsx("p",{className:"text-xs text-gray-500 uppercase tracking-wide",children:l}),t.jsx("p",{className:"text-2xl font-bold text-gray-900 mt-1",children:a}),i&&t.jsx("p",{className:"text-xs text-gray-500 mt-0.5",children:i})]})}function K(){const l=L(e=>e.showError),[a,i]=p.useState(""),[m,b]=p.useState(""),[s,S]=p.useState(null),[f,j]=p.useState(!0),[u,y]=p.useState(!0),x=p.useCallback(e=>z.getReport(e).then(o=>{S(o),i(o.period.start),b(o.period.end)}).catch(o=>l(o?.message||k("volunteer hours"))).finally(()=>j(!1)),[l]);p.useEffect(()=>{x({})},[x]);function E(e){j(!0),x(e)}function O(){const e=s.totals,o=s.entries.map(n=>[n.date,h(n.name),n.notInBand?"No":"Yes",h(n.service),h(n.forTitle||""),h(n.location||""),n.hours??"",n.plannedHours??"",A[n.method]||"",h(n.role||"")]);o.push([]),o.push([`TOTAL ${s.period.start} to ${s.period.countedThrough}`,`${e.people} people`,"",`${e.jobs} jobs`,"","",e.hours]),s.leftOut.noHours&&o.push([`${s.leftOut.noHours} jobs have no hours set and add nothing to the total`]),s.leftOut.paidEntries&&o.push([`Left out: ${s.leftOut.paidEntries} paid (${s.leftOut.paidHours} hours)`]),s.leftOut.didNotCome&&o.push([`Left out: ${s.leftOut.didNotCome} marked as not having come`]),o.push([s.method]),o.push(["Playing time (rehearsals and concerts) is not included."]),F(`volunteer-hours_${s.period.start}_${s.period.countedThrough}_${D()}.csv`,["Date","Name","In the band","Job","For","Location","Hours","Estimated hours","How recorded","Band role"],o)}const c=s?.totals,d=s?.capacity,r=s?.leftOut,T=r?[r.paidEntries?`${r.paidEntries} paid ${r.paidEntries===1?"spot":"spots"} (${$(r.paidHours)}) left out`:null,r.didNotCome?`${r.didNotCome} marked as not having come, left out`:null,r.noHours?`${r.noHours} with no hours set: counted as people who helped, adding no hours`:null].filter(Boolean):[];return t.jsxs("div",{className:"px-4 md:px-0",children:[t.jsx(P,{title:"Volunteer Hours",breadcrumbs:[{label:"Reports",to:"/reports"},{label:"Volunteer Hours"}],subtitle:"Who helped and for how long, the spots still open on jobs coming up, and the total for a grant application.",actions:t.jsx(g,{variant:"secondary",size:"md",onClick:O,disabled:!s||s.entries.length===0,children:"Export CSV"})}),t.jsxs("form",{className:"bg-white rounded-xl border border-gray-200 p-4 mb-4 flex flex-wrap items-end gap-3",onSubmit:e=>{e.preventDefault(),E({start:a,end:m})},children:[t.jsx("div",{children:t.jsx(v,{label:"From",type:"date",value:a,onChange:e=>i(e.target.value)})}),t.jsx("div",{children:t.jsx(v,{label:"To",type:"date",value:m,onChange:e=>b(e.target.value)})}),t.jsx(g,{type:"submit",variant:"primary",size:"md",isLoading:f,disabled:!a||!m,children:"Show"})]}),s?t.jsxs(t.Fragment,{children:[t.jsxs("section",{className:"bg-white rounded-xl border border-gray-200 p-4 sm:p-6 mb-4","aria-labelledby":"vh-coming",children:[t.jsx("h3",{id:"vh-coming",className:"text-sm font-semibold text-gray-500 uppercase tracking-wide mb-2",children:"Jobs coming up"}),d.jobs.length===0?t.jsx(w,{size:"compact",title:"No jobs coming up."}):t.jsxs(t.Fragment,{children:[t.jsxs("p",{className:"text-base text-gray-900 mb-2",children:[d.filled," of ",d.spots," spots filled on ",d.jobs.length," ",d.jobs.length===1?"job":"jobs",d.open>0?` · ${d.open} still open`:" · all filled"]}),t.jsx("ul",{className:"divide-y divide-gray-100 border-t border-gray-100",children:d.jobs.map(e=>t.jsxs("li",{className:"py-2 flex flex-wrap items-baseline gap-x-3 gap-y-1","data-testid":"capacity-row",children:[t.jsxs("span",{className:"flex-1 min-w-[12rem] text-base text-gray-900",children:[e.performanceId?t.jsx(B,{to:_(e.performanceId),className:"hover:text-brand-primary hover:underline",children:e.title}):e.title,e.forTitle&&t.jsxs("span",{className:"text-sm text-gray-600",children:[", ",e.forTitle]}),e.paid&&t.jsx("span",{className:"text-sm text-gray-600",children:" · paid"})]}),t.jsx("span",{className:"text-sm text-gray-600 whitespace-nowrap",children:[R(e.neededOn),e.startTime?I(e.startTime):null].filter(
1Boolean).join(" · ")}),t.jsx("span",{className:`text-sm font-medium whitespace-nowrap ${e.open===0?"text-green-800":"text-amber-800"}`,children:e.open===0?`All ${e.spots} filled`:`${e.filled} of ${e.spots} filled`})]},e.id))})]})]}),t.jsxs("h3",{className:"text-sm font-semibold text-gray-500 uppercase tracking-wide mb-2",children:["Hours given, ",N(s.period.start)," to ",N(s.period.countedThrough)]}),c.entries===0?t.jsx(w,{card:!0,title:"No volunteer hours in these dates yet.",description:"Hours appear here the day after a Help wanted job, for everyone still signed up."}):t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3 mb-2",children:[t.jsx(H,{label:"Hours",value:Math.round(Number(c.hours)*100)/100,sub:r.noHours?`plus ${r.noHours} with no hours set`:"paid jobs left out"}),t.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-4 text-center",children:[t.jsx("p",{className:"text-xs text-gray-500 uppercase tracking-wide",children:"People who helped"}),t.jsx(g,{variant:"ghost",size:"md",className:"mt-1","aria-expanded":u,"aria-label":`${c.people} ${c.people===1?"person":"people"} helped. ${u?"Hide":"Show"} who`,onClick:()=>y(e=>!e),children:t.jsx("span",{className:"text-2xl font-bold text-gray-900",children:c.people})}),t.jsx("p",{className:"text-xs text-gray-500 mt-0.5",children:u?"listed below":"tap to see who"})]}),t.jsx(H,{label:"Jobs",value:c.jobs})]}),u&&t.jsx(W,{title:"People who helped",onClose:()=>y(!1),people:s.people.map(e=>({id:e.memberId,name:e.name,detail:[e.hours>0?$(e.hours):null,`${e.jobs} ${e.jobs===1?"job":"jobs"}`,e.jobsWithNoHours?`${e.jobsWithNoHours} with no hours set`:null,e.notInBand?e.addedByName?`not in the band, signed up by ${e.addedByName}`:"not in the band":null].filter(Boolean).join(" · ")}))}),t.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-4 mt-4 text-sm text-gray-600 space-y-1","data-testid":"vh-method",children:[t.jsx("p",{className:"font-medium text-gray-800",children:"How these hours are counted"}),t.jsx("p",{children:s.method}),t.jsx("p",{children:"Playing time at rehearsals and concerts is not included."}),T.map(e=>t.jsxs("p",{children:[e,"."]},e))]})]})]}):f?t.jsx("p",{className:"text-sm text-gray-400 py-8 text-center",children:"Loadingâ¦"}):null]})}export{K as VolunteerHoursReportPage};
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.