1"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[56901],{1651:(e,i,r)=>{r.d(i,{GP:()=>a,eC:()=>o,fV:()=>t});let t=[{questType:"interval",label:"Intervals",icon:"âï¸",practicePath:"/practice/intervals",description:"Two notes - name the distance"},{questType:"chord",label:"Chords",icon:"\uD83C\uDFB9",practicePath:"/practice/chords",description:"One chord: quality, or inversion"},{questType:"scale",label:"Scales",icon:"\uD83C\uDFBC",practicePath:"/practice/scales",description:"One scale up - name the type"},{questType:"voicing",label:"Jazz Voicings",icon:"\uD83C\uDFB5",practicePath:"/practice/jazz-voicings",description:"Hear a voicing, rebuild every note"},{questType:"harmonic-quest",label:"Harmonic Quest",icon:"\uD83C\uDFB6",practicePath:"/practice/harmonic-quest",description:"Hear each chord, play it back"},{questType:"guido",label:"Guido",icon:"\uD83D\uDC46",practicePath:"/practice/guido",description:"Hear one guide tone, find the other"},{questType:"slashmaster",label:"Slashmaster",icon:"/",practicePath:"/practice/slashmaster",description:"Which chord tone is in the bass?"},{questType:"functioneer",label:"Functioneer",icon:"\uD83D\uDCCA",practicePath:"/practice/functioneer",description:"Hear the key, then the chord in it"},{questType:"hybrid-lab",label:"Hybrid Lab",icon:"\uD83E\uDDEA",practicePath:"/practice/hybrid-lab",description:"Triad over a bass: distance, quality"},{questType:"polychordist",label:"Polychordist",icon:"\uD83D\uDD2E",practicePath:"/practice/polychordist",description:"Two triads: how far apart, what kind"}];function a(e){return t.find(i=>i.questType===e)}let n=new Set(["interval","chord","scale","voicing"]),s=new Set(["intervals","chords","scales","jazz-voicings"]);function o(e){return"string"==typeof e&&(n.has(e)||s.has(e))}},56901:(e,i,r)=>{r.d(i,{R:()=>c});var t=r(1651),a=r(12115),n=r(2615),s=r(35906),o=r(39556);function c(){var e;let{data:i,status:r,update:c}=(0,n.useSession)(),l=(0,s.jE)(),u=null==i?void 0:null===(e=i.user)||void 0===e?void 0:e.id,d=(0,a.useMemo)(()=>{var e;return(null==i?void 0:null===(e=i.user)||void 0===e?void 0:e.subscription)||null},[null==i?void 0:i.user]),h="loading"===r,{data:p,isLoading:v,error:f}=(0,o.I)({queryKey:["subscription",u],queryFn:async()=>{let e=await fetch("/api/subscription/info");if(!e.ok)throw Error("Failed to fetch subscription info");return e.json()},enabled:"authenticated"===r&&!!(null==i?void 0:i.user)&&!!u,staleTime:3e5,refetchOnMount:!0,refetchOnWindowFocus:!0,refetchOnReconnect:!0,refetchInterval:!1,retry:1}),y=(0,a.useMemo)(()=>(null==p?void 0:p.subscription)||d||null,[null==p?void 0:p.subscription,d]),m=(0,a.useMemo)(()=>(null==p?void 0:p.exerciseAccess)||null,[null==p?void 0:p.exerciseAccess]),b=(0,a.useMemo)(()=>(null==p?void 0:p.availableExercises)||null,[null==p?void 0:p.availableExercises]),w=(0,a.useMemo)(()=>h||v&&!p,[h,v,p]),[g,P]=(0,a.useState)(!1),q=(0,a.useCallback)(async()=>{await l.invalidateQueries({queryKey:["subscription"],exact:!1})},[l]),T=(0,a.useCallback)(async e=>{try{var r,t;let a=await fetch("/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({planName:e})}),s=await a.json();if(!a.ok)throw Error(s.error||"Failed to create subscription");if(await l.invalidateQueries({queryKey:["subscription"],exact:!1}),await l.invalidateQueries({queryKey:["user"]}),"Free Plan"===e){await new Promise(e=>setTimeout(e,100));let e=0;for(;e<3;)try{await (0,n.signIn)("credentials",{redirect:!1,email:null==i?void 0:null===(r=i.user)||void 0===r?void 0:r.email}),await new Promise(e=>setTimeout(e,200)),await c(),await q(),await new Promise(e=>setTimeout(e,100));break}catch(i){++e>=3?console.error("â All session refresh attempts failed"):await new Promise(e=>setTimeout(e,300))}}else await (0,n.signIn)("credentials",{redirect:!1,email:null==i?void 0:null===(t=i.user)||void 0===t?void 0:t.email}),await c(),await q();return s}catch(e){throw console.error("Error creating subscription:",e),e}},[q,c,i,l]),k=(0,a.useCallback)(async()=>{if(!(null==y?void 0:y.isAdmin))throw Error("Admin access required");try{if(!(await fetch("/api/subscription/dev-mode",{method:"POST"})).ok)throw Error("Failed to toggle dev mode");
1await l.invalidateQueries({queryKey:["subscription"],exact:!1}),await q()}catch(e){throw console.error("Error toggling dev mode:",e),e}},[null==y?void 0:y.isAdmin,q,l]),E=(0,a.useCallback)(e=>{var i,r;return"undefined"!=typeof navigator&&!navigator.onLine||!!y&&(!!(y.isAdmin||(null===(i=y.planName)||void 0===i?void 0:i.includes("Pro")))||(null===(r=y.features)||void 0===r?void 0:r.includes(e))||!1)},[y]),C=(0,a.useCallback)(e=>{var i,r;if("undefined"!=typeof navigator&&!navigator.onLine)return(0,t.eC)(e)||!!(null==y?void 0:y.isAdmin)||!!(null==y?void 0:null===(r=y.planName)||void 0===r?void 0:r.includes("Pro"));if(!y)return!1;if(y.isAdmin||y.devMode||(null===(i=y.planName)||void 0===i?void 0:i.includes("Pro")))return!0;if(!b)return!1;switch(e){case"intervals":return b.intervals.length>0;case"chords":return b.chords.length>0;case"scales":return b.scales.length>0;case"jazz-voicings":return!0;case"chord-progressions":return b.hasChordProgressions;case"harmonic-quest":return b.hasHarmonicQuest;default:return!1}},[y,b]),A=(0,a.useCallback)(async()=>{var e,i;if("undefined"!=typeof navigator&&!navigator.onLine)return!0;let r=y,t=m;if(d&&(r=d,d.isAdmin||(null===(i=d.planName)||void 0===i?void 0:i.includes("Pro"))))return!0;if(!d&&(w||!r))try{let e=await l.ensureQueryData({queryKey:["subscription",u],queryFn:async()=>{let e=await fetch("/api/subscription/info");if(!e.ok)throw Error("Failed to fetch subscription info");return e.json()}});r=e.subscription,t=e.exerciseAccess}catch(e){return console.error("â Error fetching subscription data:",e),!1}if(!r)return!1;if(r.isAdmin||(null==t?void 0:t.remaining)===-1||(null===(e=r.planName)||void 0===e?void 0:e.includes("Pro")))return!0;if((null==t?void 0:t.remaining)!==void 0&&t.remaining<=0)return P(!0),!1;try{let e=await fetch("/api/exercises/start",{method:"POST"});if(!e.ok){if(429===e.status)return P(!0),!1;throw Error("Failed to start exercise")}return!0}catch(e){return console.error("â Error starting exercise:",e),!1}},[d,w,y,m,l,P,v]),x=(0,a.useCallback)(async()=>{m&&y&&!y.isAdmin&&-1!==m.remaining&&(m.remaining<=0&&m.limit&&m.limit>0?P(!0):m.remaining>0&&g&&P(!1))},[m,y,g]);return{subscription:y,exerciseAccess:m,availableExercises:b,isLoading:w,error:f,showLimitOverlay:g,setShowLimitOverlay:P,refreshSubscription:q,createSubscription:T,toggleDevMode:k,hasFeature:E,canAccessExercise:C,startExercise:A,checkDailyLimit:x}}}}]);
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.