1import{j as e}from"./markdown-DtjUNGiI.js";import{r as g}from"./vendor-BwYRWotU.js";import{D as $,w as I,m as R,l as k}from"./firebase-CwtiMJt_.js";import{u as G,d as w,G as v,f as V}from"./index-DSU2RxiB.js";import{G as U}from"./GovBadge-C6PcdeKU.js";import{G as B}from"./GovLoadingState-B0F3SoJt.js";import{G as H}from"./GovEmptyState-CZY4zPhp.js";import{aK as _,ap as q,bp as Y,bq as F}from"./icons-Ck4WJybW.js";import"./geo-D5jDzFjM.js";const b={regularNoticeDays:7,specialNoticeDays:1,minutesDueDays:30,warningLeadDays:3,isConfirmed:!1,citation:""},a={POSTED_ON_TIME:"posted_on_time",POSTED_LATE:"posted_late",DUE_SOON:"due_soon",OVERDUE:"overdue",SCHEDULED:"scheduled",PAST:"past"},d={PUBLISHED:"published",DUE_SOON:"due_soon",OVERDUE:"overdue",NOT_DUE:"not_due"},z=1440*60*1e3,j=t=>{if(!t)return null;const s=new Date(`${String(t).slice(0,10)}T12:00:00`);return Number.isNaN(s.getTime())?null:s},M=(t,s)=>{if(!t||!s)return null;const n=new Date(t.getFullYear(),t.getMonth(),t.getDate()),l=new Date(s.getFullYear(),s.getMonth(),s.getDate());return Math.round((l-n)/z)},K=t=>{const s=(t?.agendaPdfUrl||"").trim(),n=(t?.agendaTopics||"").trim();return!!(s&&s!=="#"||n)},P=t=>{const s=(t?.minutesPdfUrl||"").trim();return!!(s&&s!=="#")},J=t=>{const s=`${t?.title||""} ${t?.bodyType||""} ${t?.meetingType||""}`.toLowerCase();return s.includes("special")||s.includes("called")||s.includes("emergency")},Q=(t,s={},n=new Date)=>{const l={...b,...s},i=j(t?.date),E=j(t?.agendaPostedAt),y=J(t),D=y?l.specialNoticeDays:l.regularNoticeDays,m=M(n,i),N=K(t);let c,h=null;i?N?(h=E?M(E,i):null,h===null?c=a.POSTED_ON_TIME:c=h>=D?a.POSTED_ON_TIME:a.POSTED_LATE):m<0?c=a.PAST:m<D?c=a.OVERDUE:m<=D+l.warningLeadDays?c=a.DUE_SOON:c=a.SCHEDULED:c=a.SCHEDULED;let p=d.NOT_DUE,o=null;if(i&&m<=0)if(P(t))p=d.PUBLISHED;else{const r=Math.abs(m);o=l.minutesDueDays-r,o<0?p=d.OVERDUE:o<=l.warningLeadDays?p=d.DUE_SOON:p=d.NOT_DUE}else i&&P(t)&&(p=d.PUBLISHED);return{meetingDate:i,daysUntil:m,requiredNoticeDays:D,noticeStatus:c,noticeLeadDays:h,minutesStatus:p,minutesDaysRemaining:o,isSpecialMeeting:y,policyConfirmed:!!l.isConfirmed}},W=(t=[])=>{const s={total:t.length,overdue:0,dueSoon:0,postedLate:0,onTime:0,minutesOverdue:0};for(const n of t)n.noticeStatus===a.OVERDUE||n.noticeStatus===a.PAST?s.overdue++:n.noticeStatus===a.DUE_SOON?s.dueSoon++:n.noticeStatus===a.POSTED_LATE?s.postedLate++:n.noticeStatus===a.POSTED_ON_TIME&&s.onTime++,n.minutesStatus===d.OVERDUE&&s.minutesOverdue++;return s},L={[a.POSTED_ON_TIME]:{label:"Notice posted",severity:"good"},[a.POSTED_LATE]:{label:"Posted late",severity:"warn"},[a.DUE_SOON]:{label:"Agenda due soon",severity:"warn"},[a.OVERDUE]:{label:"Notice window missed",severity:"crit"},[a.SCHEDULED]:{label:"Scheduled",severity:"idle"},[a.PAST]:{label:"Held without agenda on file",severity:"crit"}},A={[d.PUBLISHED]:{label:"Minutes published",severity:"good"},[d.DUE_SOON]:{label:"Minutes due soon",severity:"warn"},[d.OVERDUE]:{label:"Minutes overdue",severity:"crit"},[d.NOT_DUE]:{label:"â",severity:"idle"}},C={good:"active",warn:"warning",crit:"critical",idle:"neutral"},f=({label:t,value:s,tone:n="neutral",icon:l})=>{const i={critical:"text-rose-700",warning:"text-amber-700",active:"text-emerald-700",neutral:"text-slate-700"};return e.jsxs("div",{className:"bg-white border border-slate-300 rounded-lg p-4 flex items-start gap-3",children:[l&&e.jsx(l,{className:`w-5 h-5 mt-0.5 shrink-0 ${i[n]}`,"aria-hidden":"true"}),e.jsxs("div",{children:[e.jsx("div",{className:`text-2xl font-black tabular-nums leading-none ${i[n]}`,children:s}),e.jsx("div",{className:"text-[11px] font-bold uppercase tracking-wider text-slate-500 mt-1.5",children:t})]})]})},X=t=>t?t.toLocaleDateString("en-US",{weekday:"short",month:"short",day:"numeric",year:"numeric"}):"â",Z=t=>{const{noticeStatus:s,daysUntil:n,requiredNoticeDays:l,noticeLeadDays:i}=t;switch(s){case a.POSTED_ON_TIME:return i===null?"Agenda is published. Posting date was not recorded, so lead time cannot be shown.":`Agenda published ${i} days ahead (${l} required).`;case a.POSTED_LATE:return`Agenda published only ${i} days ahead; ${l} required.`;case a.DUE_SOON:return`Meeting is in ${n} days. Publish the agenda within ${n-l} day(s) to stay inside the notice window.`;case a.OVERDUE:return`Meeting is in ${n} days and no agenda is published. The ${l}-day notice window has already passed.`;case a.PAST:return"This meeting was held with no agenda on file.";default:return n===null?"No date set.":`Meeting is in ${n} days.`}},ce=()=>{const{tenantId:t,tenantConfig:s}=G(),[n,l]=g.useState([]),[i,E]=g.useState(b),[y,D]=g.useState(!0),[m,N]=g.useState(null);g.useEffect(()=>{if(!t)return;const o=$(w,"tenants",t,"cms","meetings","items");return I(o,u=>{l(u.docs.map(x=>({id:x.id,...x.data()}))),D(!1)},u=>{N(u.message),D(!1)})},[t]),g.useEffect(()=>{if(!t)return;let o=!0;return R(k(w,"sys_tenants",t)).then(r=>{if(!o||!r.exists())return;const u=r.data()?.noticePolicy;u&&E({...b,...u})}).catch(()=>{}),()=>{o=!1}},[t]);const c=g.useMemo(()=>{const o=new Date;return n.map(r=>({meeting:r,evaluation:Q(r,i,o)})).sort((r,u)=>{const x=S=>S.noticeStatus===a.OVERDUE||S.noticeStatus===a.PAST?0:S.minutesStatus===d.OVERDUE?1:S.noticeStatus===a.DUE_SOON?2
1:3,O=x(r.evaluation),T=x(u.evaluation);return O!==T?O-T:(r.evaluation.daysUntil??9999)-(u.evaluation.daysUntil??9999)})},[n,i]),h=g.useMemo(()=>W(c.map(o=>o.evaluation)),[c]),p=s?.name||"This municipality";return y?e.jsx(B,{label:"Loading meeting notice record"}):e.jsxs("div",{className:"p-6 sm:p-8 max-w-7xl mx-auto space-y-6",children:[e.jsxs("header",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest text-slate-500",children:[e.jsx(_,{className:"w-3.5 h-3.5","aria-hidden":"true"}),e.jsx("span",{children:"GovStax Shield"})]}),e.jsx("h1",{className:"text-2xl font-black tracking-tight text-slate-900",children:"Open Meetings Notice Tracker"}),e.jsxs("p",{className:"text-sm text-slate-600 max-w-2xl",children:["Every scheduled meeting for ",p,", checked against the advance-notice window and the deadline for publishing minutes."]})]}),!i.isConfirmed&&e.jsx(v,{severity:"warning",title:"Notice periods are not yet confirmed for this jurisdiction",message:`These statuses use placeholder windows of ${i.regularNoticeDays} days for regular meetings, ${i.specialNoticeDays} day for special or called meetings, and ${i.minutesDueDays} days to publish minutes. Notice requirements vary by state and by type of body. Have ${p}'s attorney confirm the correct periods, then record them on the tenant so this page reflects the law that actually applies. Until then treat it as a scheduling aid, not a compliance determination.`}),m&&e.jsx(v,{severity:"critical",title:"Could not load meetings",message:m}),e.jsxs("div",{className:"grid grid-cols-2 lg:grid-cols-4 gap-4",children:[e.jsx(f,{label:"Notice window missed",value:h.overdue,tone:"critical",icon:q}),e.jsx(f,{label:"Agenda due soon",value:h.dueSoon,tone:"warning",icon:Y}),e.jsx(f,{label:"Minutes overdue",value:h.minutesOverdue,tone:"warning",icon:F}),e.jsx(f,{label:"Noticed on time",value:h.onTime,tone:"active",icon:_})]}),e.jsx(V,{title:"Meeting record",subtitle:`${c.length} meeting${c.length===1?"":"s"} on file`,children:c.length===0?e.jsx(H,{title:"No meetings on file",description:"Add meetings in Civic Content â Meetings and they will appear here with their notice status."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm min-w-[52rem]",children:[e.jsx("caption",{className:"sr-only",children:"Scheduled meetings with agenda notice status and minutes publication status"}),e.jsx("thead",{children:e.jsx("tr",{className:"text-left",children:["Meeting","Date","Notice","Minutes"].map(o=>e.jsx("th",{scope:"col",className:"pb-2 pr-4 text-[11px] font-bold uppercase tracking-wider text-slate-500 border-b border-slate-300",children:o},o))})}),e.jsx("tbody",{children:c.map(({meeting:o,evaluation:r})=>{const u=L[r.noticeStatus]||L[a.SCHEDULED],x=A[r.minutesStatus]||A[d.NOT_DUE];return e.jsxs("tr",{className:"border-b border-slate-200 align-top",children:[e.jsxs("td",{className:"py-3 pr-4",children:[e.jsx("div",{className:"font-bold text-slate-900",children:o.title||"Untitled meeting"}),e.jsxs("div",{className:"text-xs text-slate-500 mt-0.5",children:[o.bodyType||"Public body",r.isSpecialMeeting&&" · Special / called"]})]}),e.jsxs("td",{className:"py-3 pr-4 whitespace-nowrap text-slate-700 tabular-nums",children:[X(r.meetingDate),o.time&&e.jsx("div",{className:"text-xs text-slate-500",children:o.time})]}),e.jsxs("td",{className:"py-3 pr-4",children:[e.jsx(U,{variant:C[u.severity],children:u.label}),e.jsx("p",{className:"text-xs text-slate-600 mt-1.5 max-w-sm",children:Z(r)})]}),e.jsxs("td",{className:"py-3 pr-4",children:[e.jsx(U,{variant:C[x.severity],children:x.label}),r.minutesStatus===d.OVERDUE&&e.jsxs("p",{className:"text-xs text-slate-600 mt-1.5",children:[Math.abs(r.minutesDaysRemaining)," days past the ",i.minutesDueDays,"-day target."]})]})]},o.id)})})]})})}),i.citation&&e.jsxs("p",{className:"text-xs text-slate-500",children:["Governing authority: ",i.citation]})]})};export{ce as OpenMeetingsTracker,ce as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.