1"use strict";(self.webpackChunknaums_web=self.webpackChunknaums_web||[]).push([[6204],{42638:(e,a,t)=>{t.r(a),t.d(a,{computeUserActivityCounts:()=>L,default:()=>z});var s=t(89379),n=t(65043),r=t(18799),l=t(87890),o=t(91281),i=t(17869),c=t(80379),d=t(82291),h=t(87734),m=t(52185),u=t(6026),x=t(10023),p=t(75748),g=t(53913),f=t(29066),v=t(53862),b=t(5101),y=t(32513),j=t(67700),N=t(1858),S=t(46892),k=t(97700),w=t(66335),A=t(64233),F=t(5060),D=t(81895),C=t(42343),T=t(70579);const E=["#FFAB4D","#3B82F6","#0F9D58","#FF4713","#8C88A3","#FFC266","#DC2626","#6366F1","#F97316","#14B8A6"];function L(e){const a=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:new Date).getTime(),t=a-6048e5,s=a-2592e6,n=e.filter(e=>!e.isArchived),r=n.map(e=>function(e){if(e instanceof Date)return isNaN(e.getTime())?null:e;if("function"===typeof(null===e||void 0===e?void 0:e.toDate))try{const a=e.toDate();return a instanceof Date&&!isNaN(a.getTime())?a:null}catch(a){return null}return null}(e.lastLogin));return{nonArchivedAccounts:n.length,activated:n.filter(e=>Boolean(e.firstLoginAt)||!0===e.hasSignedIn||Boolean(e.lastLogin)).length,active7d:r.filter(e=>e&&e.getTime()<=a&&e.getTime()>=t).length,active30d:r.filter(e=>e&&e.getTime()<=a&&e.getTime()>=s).length}}const P=[{key:"schools-by-state",label:"Schools by State",modes:["bar","donut"]},{key:"funding-types",label:"Funding Types",modes:["donut","bar"]},{key:"membership-status",label:"Membership Status",modes:["donut","bar"]},{key:"enrollment-trend",label:"Enrollment Trend",modes:["line","bar"],needsSnaps:!0},{key:"enrollment-by-grade",label:"Enrollment by Grade",modes:["bar","donut"],needsSnaps:!0},{key:"user-roles",label:"User Roles",modes:["donut","bar"]},{key:"staff-overview",label:"Staff Breakdown",modes:["bar"],needsSnaps:!0},{key:"invoice-status",label:"Invoice Status",modes:["donut","bar"]},{key:"revenue-trend",label:"Revenue Over Time",modes:["line","bar"]},{key:"accreditation-status",label:"Accreditation Status",modes:["donut","bar"]}],U=new Map(P.map(e=>[e.key,e])),B=[{metric:"schools-by-state",mode:"bar"},{metric:"funding-types",mode:"donut"},{metric:"enrollment-trend",mode:"line"},{metric:"enrollment-by-grade",mode:"bar"},{metric:"user-roles",mode:"donut"},{metric:"invoice-status",mode:"donut"},{metric:"revenue-trend",mode:"line"},{metric:"accreditation-status",mode:"donut"}],R="naums_analytics_slots";function M(){try{const e=localStorage.getItem(R);if(e)return JSON.parse(e)}catch(e){}return B}function O(e){try{localStorage.setItem(R,JSON.stringify(e))}catch(a){}}function Y(e,a,t){return"donut"===a?function(e,a){if(!e.length)return(0,T.jsx)("div",{className:"ax-empty",children:"No data"});const t=e.reduce((e,a)=>e+a.value,0);return(0,T.jsxs)("div",{className:"ax-donut-wrap",children:[(0,T.jsxs)("div",{className:"ax-donut-chart",children:[(0,T.jsx)(r.u,{width:"100%",height:a,children:(0,T.jsxs)(l.r,{children:[(0,T.jsx)(o.Fq,{data:e,cx:"50%",cy:"50%",innerRadius:"55%",outerRadius:"80%",dataKey:"value",paddingAngle:2,stroke:"none",children:e.map((e,a)=>(0,T.jsx)(i.f,{fill:e.color||E[a%E.length]},a))}),(0,T.jsx)(c.m,{contentStyle:{fontFamily:"Poppins",fontSize:12,borderRadius:8,border:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.1)"},formatter:e=>[e.toLocaleString(),""]})]})}),(0,T.jsxs)("div",{className:"ax-donut-center",children:[(0,T.jsx)("span",{className:"ax-donut-total",children:t.toLocaleString()}),(0,T.jsx)("span",{className:"ax-donut-label",children:"Total"})]})]}),(0,T.jsx)("div",{className:"ax-donut-legend",children:e.map((e,a)=>(0,T.jsxs)("div",{className:"ax-legend-item",children:[(0,T.jsx)("span",{className:"ax-legend-dot",style:{background:e.color||E[a%E.length]}}),(0,T.jsx)("span",{className:"ax-legend-name",children:e.name}),(0,T.jsx)("span",{className:"ax-legend-val",children:e.value.toLocaleString()})]},e.name))})]})}(e,t):"line"===a?function(e,a){return e.length?(0,T.jsx)(r.u,{width:"100%",height:a,children:(0,T.jsxs)(p.b,{data:e,margin:{top:8,right:16,left:0,bottom:0},children:[(0,T.jsx)(h.d,{strokeDasharray:"3 3",stroke:"var(--border-light, #e5e7eb)"}),(0,T.jsx)(m.W,{dataKey:"name",tick:{fontFamily:"Poppins",fontSize:11,fill:"var(--text-secondary)"}}),(0,T.jsx)(u.h,{tick:{fontFamily:"Poppins",fontSize:11,fill:"var(--text-secondary)"}}),(0,T.jsx)(c.m,{contentStyle:{fontFamily:"Poppins",fontSize:12,borderRadius:8,border:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.1)"}}),(0,T.jsx)(g.N1,{type:"monotone",dataKey:"value",stroke:"#FFAB4D",strokeWidth:2.5,dot:{r:4,fill:"#FFAB4D",strokeWidth:2,stroke:"#fff"},activeDot:{r:6}})]})}):(0,T.jsx)("div",{className:"ax-empty",children:"No data"})}(e,t):function(e,a){return e.length?(0,T.jsx)(r.u,{width:"100%",height:a,children:(0,T.jsxs)(d.E,{data:e,margin:{top:8,right:16,left:0,bottom:0},children:[(0,T.jsx)(h.d,{strokeDasharray:"3 3",stroke:"var(--border-light, #e5e7eb)",vertical:!1}),(0,T.jsx)(m.W,{dataKey:"name",interval:0,angle:-40,textAnchor:"end",height:68,tickMargin:8,tick:{fontFamily:"Poppins",fontSize:10,fill:"var(--text-secondary)"}}),(0,T.jsx)(u.h,{tick:{fontFamily:"Poppins",fontSize:11,fill:"var(--text-secondary)"}}),(0,T.jsx)(c.m,{contentStyle:{fontFamily:"Poppins",fontSize:12,borderRadius:8,border:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.1)"}}),(0,T.jsx)(x.yP,{dataKey:"value",radius:[3,3,0,0],children:e.map((e,a)=>(0,T.jsx)(i.f,{fill:E[a%E.length]},a))})]})}):(0,T.jsx)("div",{className:"ax-empty",children:"No data"})}(e,t)}const I=n.memo(function(e){let{slot:a,index:t,height:s,className:n,snapsLoading:r,onUpdate:l,getData:o}=e;if(!a)return null;const i=U.get(a.metric),c=!(null===i||void 0===i||!i.needsSnaps)&&r,d=o(a.metric);return(0,T.jsxs)("div",{className:"ax-card ".concat(n||""),children:[(0,T.jsxs)("div",{className:"ax-card-toolbar",children:[(0,T.jsx)("select",{className:"ax-card-select",value:a.metric,onChange:e=>l(t,{metric:e.target.value}),children:P.map(e=>(0,T.jsx)("option",{value:e.key,children:e.label},e.key))}),i&&i.modes.length>1&&(0,T.jsx)("div",{className:"ax-card-toggle",children:i.modes.map(e=>(0,T.jsx)("button",{className:"ax-card-toggle-btn".concat(a.mode===e?" ax-card-toggle-btn--on":""),onClick:()=>l(t,{mode:e}),children:"bar"===e?"Bar":"line"===e?"Line":"Donut"},e))})]}),c?(0,T.jsx)("div",{className:"ax-empty",children:"Loading..."}):Y(d,a.mode,s)]})}),z=()=>{const{user:e,isAdmin:a}
1=(0,f.A)(),t=(0,A.n)(),r=(0,F.N)(D.o,t),[l,o]=(0,n.useState)(!0),[i,c]=(0,n.useState)(!0),[d,h]=(0,n.useState)([]),[m,u]=(0,n.useState)([]),[x,p]=(0,n.useState)([]),[g,E]=(0,n.useState)({total:0,pending:0,paid:0,overdue:0,totalRevenue:0,pendingRevenue:0}),[P,R]=(0,n.useState)({total:0,active:0,expiringSoon:0,expired:0,pendingSiteVisits:0}),[Y,z]=(0,n.useState)([]),[K,V]=(0,n.useState)("all"),[W,H]=(0,n.useState)(M),_=(0,n.useCallback)((e,a)=>{H(t=>{const n=t.map((t,n)=>n===e?(0,s.A)((0,s.A)({},t),a):t);if(a.metric){const t=U.get(a.metric);t&&(n[e].mode=t.modes[0])}return O(n),n})},[]),G=(0,n.useCallback)(()=>{H(B),O(B)},[]);(0,n.useEffect)(()=>{let e=!1;return(async()=>{const[a,t,s,n]=await Promise.all([v.A.getActiveSchools().catch(()=>[]),b.default.getAllUsers().catch(()=>[]),y.A.getAllInvoices().catch(()=>[]),j.A.getAccreditationStats().catch(()=>({total:0,active:0,expiringSoon:0,expired:0,pendingSiteVisits:0}))]);if(e)return{sc:[]};const r=s.filter(e=>"PAID"===e.status),l=s.filter(e=>"PENDING"===e.status),i=s.filter(e=>"OVERDUE"===e.status);return h(a),u(t),p(s),E({total:s.length,paid:r.length,pending:l.length,overdue:i.length,totalRevenue:r.reduce((e,a)=>e+(a.paidAmount||a.amount||0),0),pendingRevenue:l.reduce((e,a)=>e+(a.amount||0),0)}),R(n),o(!1),{sc:a}})().then(a=>{let{sc:t}=a;t.length>0?(async a=>{const t=await Promise.all(a.slice(0,50).map(e=>N.A.getSnapshotsForSchool(e.id).catch(()=>[])));e||(z(t.flat()),c(!1))})(t):c(!1)}).catch(()=>{o(!1),c(!1)}),()=>{e=!0}},[]);const q=(0,n.useMemo)(()=>{const e=new Set;return Y.forEach(a=>e.add(a.academicYear)),Array.from(e).sort().reverse()},[Y]),J=(0,n.useMemo)(()=>d.reduce((e,a)=>e+(a.studentCount||0),0),[d]),$=(0,n.useMemo)(()=>L(m),[m]),Q=(0,n.useMemo)(()=>new Set(d.map(e=>{var a;return null===(a=e.address)||void 0===a?void 0:a.state}).filter(Boolean)).size,[d]),X=(0,n.useCallback)(e=>{switch(e){case"schools-by-state":{const e={};return d.forEach(a=>{var t;const s=null===(t=a.address)||void 0===t?void 0:t.state;s&&(e[s]=(e[s]||0)+1)}),Object.entries(e).map(e=>{let[a,t]=e;return{name:a,value:t}}).sort((e,a)=>a.value-e.value).slice(0,12)}case"membership-status":{const e={};return d.forEach(a=>{e[a.membershipStatus]=(e[a.membershipStatus]||0)+1}),Object.entries(e).map(e=>{let[a,t]=e;return{name:a,value:t}})}case"funding-types":{const e={};return d.forEach(a=>{const t=(a.fundingType||"").trim(),s=t?t.charAt(0).toUpperCase()+t.slice(1).toLowerCase():"Unknown";e[s]=(e[s]||0)+1}),Object.entries(e).map(e=>{let[a,t]=e;return{name:a,value:t}})}case"user-roles":{const e={};return m.filter(e=>!e.isArchived).forEach(a=>{const t=C.B[a.role]||"Other";e[t]=(e[t]||0)+1}),Object.entries(e).map(e=>{let[a,t]=e;return{name:a,value:t}})}case"invoice-status":return[{name:"Paid",value:g.paid,color:"#0F9D58"},{name:"Pending",value:g.pending,color:"#FFAB4D"},{name:"Overdue",value:g.overdue,color:"#DC2626"}].filter(e=>e.value>0);case"accreditation-status":return[{name:"Active",value:P.active,color:"#0F9D58"},{name:"Expiring",value:P.expiringSoon,color:"#FFAB4D"},{name:"Expired",value:P.expired,color:"#DC2626"}].filter(e=>e.value>0);case"enrollment-trend":{const e={};return Y.forEach(a=>{e[a.academicYear]=(e[a.academicYear]||0)+a.totalEnrollment}),Object.entries(e).sort((e,a)=>{let[t]=e,[s]=a;return t.localeCompare(s)}).map(e=>{let[a,t]=e;return{name:a.split("-")[0],value:t}})}case"enrollment-by-grade":{const e="all"!==K?Y.filter(e=>e.academicYear===K):Y,a={};e.forEach(e=>e.enrollment.forEach(e=>{a[e.grade]=(a[e.grade]||0)+e.count}));return["Pre-K","T-K","K","1st","2nd","3rd","4th","5th","6th","7th","8th","9th","10th","11th","12th"].filter(e=>a[e]).map(e=>({name:e,value:a[e]}))}case"revenue-trend":{const e={};return x.filter(e=>e.paidDate&&e.paidAmount).forEach(a=>{const t=new Date(a.paidDate),s="".concat(t.getFullYear(),"-").concat(String(t.getMonth()+1).padStart(2,"0"));e[s]=(e[s]||0)+(a.paidAmount||0)}),Object.entries(e).sort((e,a)=>{let[t]=e,[s]=a;return t.localeCompare(s)}).map(e=>{let[a,t]=e;return{name:a,value:t}})}case"staff-overview":{const e="all"!==K?Y.filter(e=>e.academicYear===K):Y;let a=0,t=0,s=0,n=0;
1return e.forEach(e=>{a+=e.staff.teachersFullTime,t+=e.staff.teachersPartTime,s+=e.staff.staffFullTime,n+=e.staff.staffPartTime}),[{name:"Teachers FT",value:a},{name:"Teachers PT",value:t},{name:"Staff FT",value:s},{name:"Staff PT",value:n}]}default:return[]}},[d,m,x,g,P,Y,K]),Z=(0,n.useMemo)(()=>{const e=new Map;return a=>{let t=e.get(a);return t||(t=X(a),e.set(a,t)),t}},[X]),ee=(e,a,t)=>(0,T.jsxs)("div",{className:"ax-stat",style:{"--ax-accent":t},children:[(0,T.jsx)("span",{className:"ax-stat-val",children:a}),(0,T.jsx)("span",{className:"ax-stat-lbl",children:e})]});if(!a)return null;const ae=e=>"$".concat(e>999?"".concat((e/1e3).toFixed(0),"k"):e);return(0,T.jsxs)("div",{className:"ax-page",children:[(0,T.jsx)(k.A,{actions:(0,T.jsx)(w.A,{modalTitle:"Analytics Guide",faqSections:D.b,tourSteps:r,buttonTitle:"Help & guide for analytics"}),children:(0,T.jsxs)("div",{className:"ax-topbar-controls",children:[(0,T.jsx)("h1",{className:"page-title",children:"Analytics"}),q.length>0&&(0,T.jsxs)("select",{className:"ax-year-pick",value:K,onChange:e=>V(e.target.value),children:[(0,T.jsx)("option",{value:"all",children:"All Years"}),q.map(e=>(0,T.jsx)("option",{value:e,children:e},e))]}),(0,T.jsx)("button",{className:"ax-reset-btn",onClick:G,children:"Reset Layout"})]})}),(0,T.jsxs)("div",{className:"ax-body",children:[(0,T.jsxs)("div",{className:"ax-rail",children:[(0,T.jsxs)("div",{className:"ax-rail-stat",children:[(0,T.jsx)("span",{className:"ax-rail-val",children:l?"\u2014":d.length}),(0,T.jsx)("span",{className:"ax-rail-lbl",children:"schools"})]}),(0,T.jsxs)("div",{className:"ax-rail-stat",children:[(0,T.jsx)("span",{className:"ax-rail-val",children:l?"\u2014":(te=J,te>999?"".concat((te/1e3).toFixed(1),"k"):te.toString())}),(0,T.jsx)("span",{className:"ax-rail-lbl",children:"students"})]}),(0,T.jsxs)("div",{className:"ax-rail-stat",children:[(0,T.jsx)("span",{className:"ax-rail-val",children:l?"\u2014":ae(g.totalRevenue)}),(0,T.jsx)("span",{className:"ax-rail-lbl",children:"revenue"})]}),(0,T.jsxs)("div",{className:"ax-rail-stat",children:[(0,T.jsx)("span",{className:"ax-rail-val",children:l?"\u2014":$.nonArchivedAccounts}),(0,T.jsx)("span",{className:"ax-rail-lbl",children:"non-archived accounts"})]}),(0,T.jsxs)("div",{className:"ax-rail-stat",children:[(0,T.jsx)("span",{className:"ax-rail-val",children:l?"\u2014":P.active}),(0,T.jsx)("span",{className:"ax-rail-lbl",children:"accredited"})]}),(0,T.jsxs)("div",{className:"ax-rail-stat",children:[(0,T.jsx)("span",{className:"ax-rail-val ax-rail-val--warn",children:l?"\u2014":g.overdue}),(0,T.jsx)("span",{className:"ax-rail-lbl",children:"overdue"})]})]}),(0,T.jsx)("div",{className:"ax-main",children:l?(0,T.jsx)("div",{className:"ax-loading",children:"Loading analytics data..."}):(0,T.jsxs)(T.Fragment,{children:[(0,T.jsxs)("div",{className:"ax-row",children:[(0,T.jsx)(I,{slot:W[0],index:0,height:260,className:"ax-card--wide",snapsLoading:i,onUpdate:_,getData:Z}),(0,T.jsx)(I,{slot:W[1],index:1,height:260,className:"ax-card--narrow",snapsLoading:i,onUpdate:_,getData:Z})]}),(0,T.jsxs)("div",{className:"ax-row",children:[(0,T.jsx)(I,{slot:W[2],index:2,height:240,className:"ax-card--half",snapsLoading:i,onUpdate:_,getData:Z}),(0,T.jsx)(I,{slot:W[3],index:3,height:240,className:"ax-card--half",snapsLoading:i,onUpdate:_,getData:Z})]}),(0,T.jsxs)("div",{className:"ax-row",children:[(0,T.jsx)(I,{slot:W[4],index:4,height:240,className:"ax-card--narrow",snapsLoading:i,onUpdate:_,getData:Z}),(0,T.jsx)("div",{className:"ax-card ax-card--wide",children:(0,T.jsxs)("div",{className:"ax-stats-row",children:[ee("Non-archived accounts",$.nonArchivedAccounts.toString(),"#3B82F6"),ee("Activated",$.activated.toString(),"#6366F1"),ee("Active (7d)",$.active7d.toString(),"#14B8A6"),ee("Active (30d)",$.active30d.toString(),"#0F9D58"),ee("Pending",m.filter(e=>e.status===S._O.PENDING).length.toString(),"#DC2626"),ee("Schools",d.length.toString(),"#FFAB4D"),ee("States",Q.toString(),"#0F9D58")]})})]}),(0,T.jsxs)("div",{className:"ax-row",children:[(0,T.jsx)(I,{slot:W[5],index:5,height:220,className:"ax-card--narrow",snapsLoading:i,onUpdate:_,getData:Z}),(0,T.jsx)(I,{slot:W[6],index:6,height:220,className:"ax-card--wide",snapsLoading:i,onUpdate:_,getData:Z})]}),(0,T.jsxs)("div",{className:"ax-row",children:[(0,T.jsx)(I,{slot:W[7],index:7,height:220,className:"ax-card--narrow",snapsLoading:i,onUpdate:_,getData:Z}),(0,T.jsx)("div",{className:"ax-card ax-card--wide",children:(0,T.jsxs)("div",{className:"ax-stats-row",children:[ee("Total Revenue",ae(g.totalRevenue),"#0F9D58"),ee("Accreditations",P.total.toString(),"#8C88A3"),ee("Expiring Soon",P.expiringSoon.toString(),"#FFAB4D"),ee("Overdue Invoices",g.overdue.toString(),"#DC2626")]})})]})]})})]})]});var te}},81895:(e,a,t)=>{t.d(a,{b:()=>s,o:()=>n});const s=[{key:"overview",title:"What is the Analytics page?",lines:["Analytics aggregates data across the entire NAUMS network \u2014 total enrollment, school growth, accreditation rates, staff demographics, budget trends, and more.","Charts auto-update as schools submit annual data and as new schools join.","Useful for board reports, association-wide planning, and identifying trends."]}
1,{key:"data-sources",title:"Where does the data come from?",lines:["Annual snapshots \u2014 each school submits enrollment, staff counts, families, and budget once a year. Those snapshots feed the trend charts.","School profiles \u2014 type, accreditation, founding year, and other static info come from the school's profile.","Test/legacy data \u2014 for schools that haven't yet migrated to annual snapshots, the charts fall back to the imported CSV records."]},{key:"time-range",title:"How do I change the time range?",lines:["Use the year selector at the top to focus on a specific academic year.","Multi-year charts (like enrollment trend) show all available years by default.","If a school is missing data for a year, the chart skips that data point rather than showing zero."]},{key:"export",title:"Can I export the data?",lines:["Yes \u2014 most charts have a download/export option that emits a CSV of the underlying data.","You can also right-click any chart to save it as an image for slides or reports."]},{key:"click-to-drill",title:"Are charts interactive?",lines:["Yes \u2014 most charts are clickable.","Click a school in a list to jump to its profile.","Click a state on the map (if available) to filter charts to that state.","Hover over data points to see exact values."]}],n=[{id:"welcome",title:"Network Analytics",content:"A bird's-eye view of the NAUMS network \u2014 enrollment, growth, staff, accreditation, and budget data aggregated across all member schools.",fallbackCenter:!0},{id:"summary-cards",title:"Headline Numbers",content:"The top cards show the most important totals: schools, students, staff, and total budget. They auto-update whenever schools submit new annual data.",fallbackCenter:!0},{id:"time-filter",title:"Year Selector",content:'Use the year selector to focus on a specific academic year, or leave it on "All Years" to see multi-year trends.',fallbackCenter:!0},{id:"charts",title:"Trend Charts",content:"Each chart breaks down a different dimension \u2014 enrollment by year, schools by state, accreditation status, etc. Hover for tooltips with exact values.",fallbackCenter:!0},{id:"drilldown",title:"Drill Into Details",content:"Most charts are clickable \u2014 click a school name to jump to its profile, click a state to filter the rest of the page, or click a data point for context.",fallbackCenter:!0},{id:"export",title:"Export & Share",content:"Look for the download icon on individual charts to export as CSV. You can also screenshot any chart for slides or reports.",fallbackCenter:!0},{id:"done",title:"You're Set",content:"Analytics auto-refreshes as schools submit annual data \u2014 so your numbers stay current. Re-launch this tour anytime from the help icon.",fallbackCenter:!0}]}}]); 2//# sourceMappingURL=6204.516be796.chunk.js.map
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.