@vue-skuilder/platform-ui 0.1.33 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/assets/{About-C1rcp0Ex.js → About-BpqIdlZQ.js} +2 -2
  2. package/dist/assets/{About-C1rcp0Ex.js.map → About-BpqIdlZQ.js.map} +1 -1
  3. package/dist/assets/{AdminDashboard-BOHgXD45.js → AdminDashboard-BObO6egG.js} +2 -2
  4. package/dist/assets/{AdminDashboard-BOHgXD45.js.map → AdminDashboard-BObO6egG.js.map} +1 -1
  5. package/dist/assets/{ClassroomCtrlPanel-ezMgP7A3.js → ClassroomCtrlPanel-lgN6cdTd.js} +2 -2
  6. package/dist/assets/{ClassroomCtrlPanel-ezMgP7A3.js.map → ClassroomCtrlPanel-lgN6cdTd.js.map} +1 -1
  7. package/dist/assets/{Classrooms-CdN-ogiI.js → Classrooms-BWoQ4i1_.js} +2 -2
  8. package/dist/assets/{Classrooms-CdN-ogiI.js.map → Classrooms-BWoQ4i1_.js.map} +1 -1
  9. package/dist/assets/{CourseRouter-BKHj3HHh.js → CourseRouter-CODD0Qm5.js} +2 -2
  10. package/dist/assets/{CourseRouter-BKHj3HHh.js.map → CourseRouter-CODD0Qm5.js.map} +1 -1
  11. package/dist/assets/{Courses-DTsQz202.js → Courses-ClDdLQUO.js} +2 -2
  12. package/dist/assets/{Courses-DTsQz202.js.map → Courses-ClDdLQUO.js.map} +1 -1
  13. package/dist/assets/{DataInputFormTester-BC2ZDakI.js → DataInputFormTester-ywHjm2yC.js} +2 -2
  14. package/dist/assets/{DataInputFormTester-BC2ZDakI.js.map → DataInputFormTester-ywHjm2yC.js.map} +1 -1
  15. package/dist/assets/{EloModeration-DqViuzI8.js → EloModeration-B6LM11G_.js} +2 -2
  16. package/dist/assets/{EloModeration-DqViuzI8.js.map → EloModeration-B6LM11G_.js.map} +1 -1
  17. package/dist/assets/{JoinCode-BjbhKTgK.js → JoinCode-DgPD_OFL.js} +2 -2
  18. package/dist/assets/{JoinCode-BjbhKTgK.js.map → JoinCode-DgPD_OFL.js.map} +1 -1
  19. package/dist/assets/{NewCourseDialog-4YsIKoUU.js → NewCourseDialog-DhwvBT3y.js} +2 -2
  20. package/dist/assets/{NewCourseDialog-4YsIKoUU.js.map → NewCourseDialog-DhwvBT3y.js.map} +1 -1
  21. package/dist/assets/{ReleaseNotes-BYXN8IZ4.js → ReleaseNotes-DtwDIIfH.js} +2 -2
  22. package/dist/assets/{ReleaseNotes-BYXN8IZ4.js.map → ReleaseNotes-DtwDIIfH.js.map} +1 -1
  23. package/dist/assets/{RequestPasswordReset-Zxt4oKHx.js → RequestPasswordReset-DBv0XCIk.js} +2 -2
  24. package/dist/assets/{RequestPasswordReset-Zxt4oKHx.js.map → RequestPasswordReset-DBv0XCIk.js.map} +1 -1
  25. package/dist/assets/{ResetPassword-rAc69I0Q.js → ResetPassword-BtBplqsQ.js} +2 -2
  26. package/dist/assets/{ResetPassword-rAc69I0Q.js.map → ResetPassword-BtBplqsQ.js.map} +1 -1
  27. package/dist/assets/{Study-DJlTc-ZH.js → Study-D9W1DKes.js} +2 -2
  28. package/dist/assets/{Study-DJlTc-ZH.js.map → Study-D9W1DKes.js.map} +1 -1
  29. package/dist/assets/{TagInformation-CSUtrZy7.js → TagInformation-DgUkKxoU.js} +2 -2
  30. package/dist/assets/{TagInformation-CSUtrZy7.js.map → TagInformation-DgUkKxoU.js.map} +1 -1
  31. package/dist/assets/{User-D2R6CphB.js → User-DorFkRx_.js} +2 -2
  32. package/dist/assets/{User-D2R6CphB.js.map → User-DorFkRx_.js.map} +1 -1
  33. package/dist/assets/{UserStats-BgnHXg6C.js → UserStats-ck9Oh4qt.js} +2 -2
  34. package/dist/assets/{UserStats-BgnHXg6C.js.map → UserStats-ck9Oh4qt.js.map} +1 -1
  35. package/dist/assets/{VerifyEmail-BLfciV-4.js → VerifyEmail-BYt5xfhm.js} +2 -2
  36. package/dist/assets/{VerifyEmail-BLfciV-4.js.map → VerifyEmail-BYt5xfhm.js.map} +1 -1
  37. package/dist/assets/{common-ui.es-I814CYyx.js → common-ui.es-BrXWBn7p.js} +6 -6
  38. package/dist/assets/common-ui.es-BrXWBn7p.js.map +1 -0
  39. package/dist/assets/common-ui.es-DKUQOgQx.js +1 -0
  40. package/dist/assets/dist-5cG6aSxW.js +1 -0
  41. package/dist/assets/{dist-DkeESCP4.js → dist-CzLl7g6t.js} +11 -10
  42. package/dist/assets/dist-CzLl7g6t.js.map +1 -0
  43. package/dist/assets/{dist-BwVFN4Xe.js → dist-D5-LrzD6.js} +3 -3
  44. package/dist/assets/{dist-BwVFN4Xe.js.map → dist-D5-LrzD6.js.map} +1 -1
  45. package/dist/assets/dist-y6_rrqhr.js +1 -0
  46. package/dist/assets/{edit-ui.es-Cs9EI-Ey.js → edit-ui.es-C9MhXwkt.js} +2 -2
  47. package/dist/assets/{edit-ui.es-Cs9EI-Ey.js.map → edit-ui.es-C9MhXwkt.js.map} +1 -1
  48. package/dist/assets/edit-ui.es-DT9CMaNG.js +1 -0
  49. package/dist/assets/{index-DotoyByQ.css → index-C8gy3Ea0.css} +1 -1
  50. package/dist/assets/{index-CF-NaZ2k.js → index-DUZItsH-.js} +4 -4
  51. package/dist/assets/{index-CF-NaZ2k.js.map → index-DUZItsH-.js.map} +1 -1
  52. package/dist/assets/{server-Cl1ZnRx7.js → server-Db_WegNj.js} +2 -2
  53. package/dist/assets/{server-Cl1ZnRx7.js.map → server-Db_WegNj.js.map} +1 -1
  54. package/dist/index.html +4 -4
  55. package/dist/sw.js +1 -1
  56. package/dist/sw.js.map +1 -1
  57. package/package.json +8 -8
  58. package/dist/assets/common-ui.es-B6tKmOxI.js +0 -1
  59. package/dist/assets/common-ui.es-I814CYyx.js.map +0 -1
  60. package/dist/assets/dist-BjDnRspm.js +0 -1
  61. package/dist/assets/dist-CFgc27Ho.js +0 -1
  62. package/dist/assets/dist-DkeESCP4.js.map +0 -1
  63. package/dist/assets/edit-ui.es-C_I54ckd.js +0 -1
@@ -1,2 +1,2 @@
1
- import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,S as i,T as a,_ as o,v as s}from"./vue.runtime.esm-bundler-C3q8JS9f.js";import{t as c}from"./index-CF-NaZ2k.js";var l=a({name:`AboutView`,components:{},data(){return{type:`Viewable`}}});function _sfc_render(a,c,l,u,d,f){let p=r(`v-btn`),m=r(`v-col`),h=r(`v-row`),g=r(`v-container`);return n(),s(g,{class:`about`},{default:e(()=>[t(h,null,{default:e(()=>[t(m,null,{default:e(()=>[c[1]||(c[1]=o(`h1`,{class:`text-h2 mb-6`},`Todo.`,-1)),c[2]||(c[2]=o(`p`,{class:`text-body-1 mb-4`},` This is a placeholder for the about page. It will be filled in with more information later. `,-1)),t(p,{to:`./notes`,variant:`text`,color:`primary`},{default:e(()=>c[0]||(c[0]=[i(` Release Notes `)])),_:1})]),_:1})]),_:1})]),_:1})}var u=c(l,[[`render`,_sfc_render]]);export{u as default};
2
- //# sourceMappingURL=About-C1rcp0Ex.js.map
1
+ import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,S as i,T as a,_ as o,v as s}from"./vue.runtime.esm-bundler-C3q8JS9f.js";import{t as c}from"./index-DUZItsH-.js";var l=a({name:`AboutView`,components:{},data(){return{type:`Viewable`}}});function _sfc_render(a,c,l,u,d,f){let p=r(`v-btn`),m=r(`v-col`),h=r(`v-row`),g=r(`v-container`);return n(),s(g,{class:`about`},{default:e(()=>[t(h,null,{default:e(()=>[t(m,null,{default:e(()=>[c[1]||(c[1]=o(`h1`,{class:`text-h2 mb-6`},`Todo.`,-1)),c[2]||(c[2]=o(`p`,{class:`text-body-1 mb-4`},` This is a placeholder for the about page. It will be filled in with more information later. `,-1)),t(p,{to:`./notes`,variant:`text`,color:`primary`},{default:e(()=>c[0]||(c[0]=[i(` Release Notes `)])),_:1})]),_:1})]),_:1})]),_:1})}var u=c(l,[[`render`,_sfc_render]]);export{u as default};
2
+ //# sourceMappingURL=About-BpqIdlZQ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"About-C1rcp0Ex.js","names":[],"sources":["../../src/views/About.vue","../../src/views/About.vue"],"sourcesContent":["<template>\n <v-container class=\"about\">\n <v-row>\n <v-col>\n <h1 class=\"text-h2 mb-6\">Todo.</h1>\n\n <p class=\"text-body-1 mb-4\">\n This is a placeholder for the about page. It will be filled in with more information later.\n </p>\n\n <v-btn :to=\"'./notes'\" variant=\"text\" color=\"primary\"> Release Notes </v-btn>\n </v-col>\n </v-row>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'AboutView',\n components: {},\n data() {\n return {\n type: 'Viewable',\n };\n },\n});\n</script>\n","<template>\n <v-container class=\"about\">\n <v-row>\n <v-col>\n <h1 class=\"text-h2 mb-6\">Todo.</h1>\n\n <p class=\"text-body-1 mb-4\">\n This is a placeholder for the about page. It will be filled in with more information later.\n </p>\n\n <v-btn :to=\"'./notes'\" variant=\"text\" color=\"primary\"> Release Notes </v-btn>\n </v-col>\n </v-row>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'AboutView',\n components: {},\n data() {\n return {\n type: 'Viewable',\n };\n },\n});\n</script>\n"],"mappings":"+KCmBA,IAAA,EAAe,EAAgB,CAC7B,KAAM,YACN,WAAY,EAAE,CACd,MAAO,CACL,MAAO,CACL,KAAM,WACP,EAEJ,CAAC,4GA1BA,EAYc,EAAA,CAZD,MAAM,QAAO,CAAA,CAD5B,QAAA,MAYY,CAVR,EAUQ,EAAA,KAAA,CAZZ,QAAA,MAWc,CARR,EAQQ,EAAA,KAAA,CAXd,QAAA,MAI2C,aAAnC,EAAmC,KAAA,CAA/B,MAAM,eAAc,CAAC,QAAK,GAAA,cAE9B,EAEI,IAAA,CAFD,MAAM,mBAAkB,CAAC,gGAE5B,GAAA,EAEA,EAA6E,EAAA,CAArE,GAAI,UAAW,QAAQ,OAAO,MAAM,YAVpD,QAAA,MAU6E,EAAA,KAAA,EAAA,GAAA,CAV7E,EAU8D,kBAAe,CAAA,EAAA,CAV7E,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA"}
1
+ {"version":3,"file":"About-BpqIdlZQ.js","names":[],"sources":["../../src/views/About.vue","../../src/views/About.vue"],"sourcesContent":["<template>\n <v-container class=\"about\">\n <v-row>\n <v-col>\n <h1 class=\"text-h2 mb-6\">Todo.</h1>\n\n <p class=\"text-body-1 mb-4\">\n This is a placeholder for the about page. It will be filled in with more information later.\n </p>\n\n <v-btn :to=\"'./notes'\" variant=\"text\" color=\"primary\"> Release Notes </v-btn>\n </v-col>\n </v-row>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'AboutView',\n components: {},\n data() {\n return {\n type: 'Viewable',\n };\n },\n});\n</script>\n","<template>\n <v-container class=\"about\">\n <v-row>\n <v-col>\n <h1 class=\"text-h2 mb-6\">Todo.</h1>\n\n <p class=\"text-body-1 mb-4\">\n This is a placeholder for the about page. It will be filled in with more information later.\n </p>\n\n <v-btn :to=\"'./notes'\" variant=\"text\" color=\"primary\"> Release Notes </v-btn>\n </v-col>\n </v-row>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'AboutView',\n components: {},\n data() {\n return {\n type: 'Viewable',\n };\n },\n});\n</script>\n"],"mappings":"+KCmBA,IAAA,EAAe,EAAgB,CAC7B,KAAM,YACN,WAAY,EAAE,CACd,MAAO,CACL,MAAO,CACL,KAAM,WACP,EAEJ,CAAC,4GA1BA,EAYc,EAAA,CAZD,MAAM,QAAO,CAAA,CAD5B,QAAA,MAYY,CAVR,EAUQ,EAAA,KAAA,CAZZ,QAAA,MAWc,CARR,EAQQ,EAAA,KAAA,CAXd,QAAA,MAI2C,aAAnC,EAAmC,KAAA,CAA/B,MAAM,eAAc,CAAC,QAAK,GAAA,cAE9B,EAEI,IAAA,CAFD,MAAM,mBAAkB,CAAC,gGAE5B,GAAA,EAEA,EAA6E,EAAA,CAArE,GAAI,UAAW,QAAQ,OAAO,MAAM,YAVpD,QAAA,MAU6E,EAAA,KAAA,EAAA,GAAA,CAV7E,EAU8D,kBAAe,CAAA,EAAA,CAV7E,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA"}
@@ -1,2 +1,2 @@
1
- import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,S as i,T as a,Vt as o,_ as s,b as c,v as l,y as u}from"./vue.runtime.esm-bundler-C3q8JS9f.js";import{B as d,T as f,b as p,c as m,p as h}from"./common-ui.es-I814CYyx.js";import"./dist-CrcJCHFk.js";import"./MarkdownRenderer-DoVbFpA6-BIbDxYC4.js";import{k as g,n as _}from"./dist-DkeESCP4.js";import{t as v}from"./index-CF-NaZ2k.js";import{g as y}from"./dist-BwVFN4Xe.js";var b=a({name:`AdminDashboard`,components:{CardSearch:m,CardSearchResults:h,CardHistoryViewer:p,CardLoader:d},data(){return{query:``,selectedCard:null,userId:``,userDB:null,dataLayer:null,adminDB:null,selectedUserId:``,selectedUserReader:null,selectedCourseId:null,userOptions:[],courseOptions:[]}},async created(){this.userDB=await f(),this.userId=this.userDB.getUsername(),this.dataLayer=await g(),this.adminDB=this.dataLayer.getAdminDB(),await this.loadUsers(),await this.loadCourses()},methods:{async loadUsers(){try{this.userOptions=(await this.adminDB.getUsers()).filter(e=>e.name&&!e.name.startsWith(`Guest_`)).map(e=>({label:e.name||`Unknown User`,value:e.name||``})).filter(e=>e.value!==``)}catch(e){console.error(`Failed to load users:`,e)}},async onUserSelected(e){if(!e){this.selectedUserReader=null;return}try{this.selectedUserReader=await this.dataLayer.createUserReaderForUser(e)}catch(e){console.error(`Failed to create user reader:`,e),this.selectedUserReader=null}},onSearch(e){this.query=e},onCardSelected(e){this.selectedCard=e},async loadCourses(){try{this.courseOptions=(await _.allCourseWare()).filter(e=>e._id).map(e=>{let t=e.name&&e.name.trim(),n,r;return t&&t!==e._id&&t!==``?(n=t,r=t.toLowerCase()):(n=e._id,r=e._id.toLowerCase()),{label:`📚 ${n}`,value:e._id,sortKey:r}}).sort((e,t)=>e.sortKey.localeCompare(t.sortKey)),console.log(`Loaded ${this.courseOptions.length} courses for filtering (lightweight mode)`)}catch(e){console.error(`Failed to load courses (lightweight):`,e),await this.loadCoursesExpensive()}},async loadCoursesExpensive(){try{console.log(`Using expensive course loading (full configs)...`),this.courseOptions=(await this.dataLayer.getAdminDB().getCourses()).filter(e=>e.courseID).map(e=>{let t=e.name&&e.name.trim(),n=e.creator?` (${e.creator})`:``,r,i;return t&&t!==e.courseID?(r=t,i=t.toLowerCase()):(r=e.courseID,i=e.courseID.toLowerCase()),{label:`${e.public?`🌐`:`🔒`} ${r}${n}`,value:e.courseID,sortKey:i}}).sort((e,t)=>e.sortKey.localeCompare(t.sortKey)),console.log(`Loaded ${this.courseOptions.length} courses for filtering (expensive mode)`)}catch(e){console.error(`Failed to load courses (expensive):`,e),this.loadCoursesBasic()}},async loadCoursesBasic(){try{console.log(`Using fallback course loading (IDs only)`),this.courseOptions=[{label:`⚠️ Course names not available - using IDs only`,value:``}]}catch(e){console.error(`Failed to load basic courses:`,e)}},onCourseFilterChanged(){this.query},getCourseNameById(e){let t=this.courseOptions.find(t=>t.value===e);return t?t.label:e},getSelectedCourseDetails(){return this.selectedCourseId?`ID: ${this.selectedCourseId}`:``},viewLookup(e){return y.getView(e)}}}),x={class:`admin-dashboard`},S={key:0,class:`mt-2`},C={key:0,class:`text-caption text-grey-darken-1`};function _sfc_render(a,d,f,p,m,h){let g=r(`v-card-title`),_=r(`v-select`),v=r(`v-chip`),y=r(`v-card-text`),b=r(`v-card`),w=r(`card-search`),T=r(`card-search-results`),E=r(`v-col`),D=r(`card-loader`),O=r(`v-row`),k=r(`card-history-viewer`);return n(),c(`div`,x,[d[4]||(d[4]=s(`h1`,null,`Admin Dashboard`,-1)),t(b,{class:`mb-4`},{default:e(()=>[t(g,null,{default:e(()=>d[2]||(d[2]=[i(`User Selection`)])),_:1}),t(y,null,{default:e(()=>[t(_,{modelValue:a.selectedUserId,"onUpdate:modelValue":[d[0]||(d[0]=e=>a.selectedUserId=e),a.onUserSelected],items:a.userOptions,"item-title":`label`,"item-value":`value`,label:`Select User`},null,8,[`modelValue`,`items`,`onUpdate:modelValue`]),a.selectedUserId?(n(),l(v,{key:0,color:`primary`,class:`mt-2`},{default:e(()=>[i(` Viewing data for: `+o(a.selectedUserId),1)]),_:1})):u(``,!0)]),_:1})]),_:1}),t(b,{class:`mb-4`},{default:e(()=>[t(g,null,{default:e(()=>d[3]||(d[3]=[i(`Search Filters`)])),_:1}),t(y,null,{default:e(()=>[t(_,{modelValue:a.selectedCourseId,"onUpdate:modelValue":[d[1]||(d[1]=e=>a.selectedCourseId=e),a.onCourseFilterChanged],items:a.courseOptions,"item-title":`label`,"item-value":`value`,label:`Filter by Course (optional)`,clearable:``},null,8,[`modelValue`,`items`,`onUpdate:modelValue`]),a.selectedCourseId?(n(),c(`div`,S,[t(v,{color:`info`,class:`mb-1`},{default:e(()=>[i(` 🎯 `+o(a.getCourseNameById(a.selectedCourseId)),1)]),_:1}),a.getSelectedCourseDetails()?(n(),c(`div`,C,o(a.getSelectedCourseDetails()),1)):u(``,!0)])):(n(),l(v,{key:1,color:`warning`,class:`mt-2`},{default:e(()=>[i(` ⚠️ Searching ALL `+o(a.courseOptions.length)+` courses (may be slow) `,1)]),_:1}))]),_:1})]),_:1}),t(w,{onSearch:a.onSearch},null,8,[`onSearch`]),t(O,null,{default:e(()=>[t(E,{cols:`6`},{default:e(()=>[a.query?(n(),l(T,{key:0,query:a.query,"data-layer":a.dataLayer,"course-filter":a.selectedCourseId,onCardSelected:a.onCardSelected},null,8,[`query`,`data-layer`,`course-filter`,`onCardSelected`])):u(``,!0)]),_:1}),t(E,{cols:`6`},{default:e(()=>[a.selectedCard?(n(),l(D,{key:0,qualified_id:{courseID:a.selectedCard.courseId,cardID:a.selectedCard.cardId},"view-lookup":a.viewLookup},null,8,[`qualified_id`,`view-lookup`])):u(``,!0)]),_:1})]),_:1}),a.selectedCard&&a.selectedUserReader?(n(),l(k,{key:0,"card-id":a.selectedCard.cardId,"course-id":a.selectedCard.courseId,"user-id":a.selectedUserId,"user-d-b":a.selectedUserReader},null,8,[`card-id`,`course-id`,`user-id`,`user-d-b`])):u(``,!0)])}var w=v(b,[[`render`,_sfc_render],[`__scopeId`,`data-v-7409c94e`]]);export{w as default};
2
- //# sourceMappingURL=AdminDashboard-BOHgXD45.js.map
1
+ import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,S as i,T as a,Vt as o,_ as s,b as c,v as l,y as u}from"./vue.runtime.esm-bundler-C3q8JS9f.js";import{B as d,T as f,b as p,c as m,p as h}from"./common-ui.es-BrXWBn7p.js";import"./dist-CrcJCHFk.js";import"./MarkdownRenderer-DoVbFpA6-BIbDxYC4.js";import{k as g,n as _}from"./dist-CzLl7g6t.js";import{t as v}from"./index-DUZItsH-.js";import{g as y}from"./dist-D5-LrzD6.js";var b=a({name:`AdminDashboard`,components:{CardSearch:m,CardSearchResults:h,CardHistoryViewer:p,CardLoader:d},data(){return{query:``,selectedCard:null,userId:``,userDB:null,dataLayer:null,adminDB:null,selectedUserId:``,selectedUserReader:null,selectedCourseId:null,userOptions:[],courseOptions:[]}},async created(){this.userDB=await f(),this.userId=this.userDB.getUsername(),this.dataLayer=await g(),this.adminDB=this.dataLayer.getAdminDB(),await this.loadUsers(),await this.loadCourses()},methods:{async loadUsers(){try{this.userOptions=(await this.adminDB.getUsers()).filter(e=>e.name&&!e.name.startsWith(`Guest_`)).map(e=>({label:e.name||`Unknown User`,value:e.name||``})).filter(e=>e.value!==``)}catch(e){console.error(`Failed to load users:`,e)}},async onUserSelected(e){if(!e){this.selectedUserReader=null;return}try{this.selectedUserReader=await this.dataLayer.createUserReaderForUser(e)}catch(e){console.error(`Failed to create user reader:`,e),this.selectedUserReader=null}},onSearch(e){this.query=e},onCardSelected(e){this.selectedCard=e},async loadCourses(){try{this.courseOptions=(await _.allCourseWare()).filter(e=>e._id).map(e=>{let t=e.name&&e.name.trim(),n,r;return t&&t!==e._id&&t!==``?(n=t,r=t.toLowerCase()):(n=e._id,r=e._id.toLowerCase()),{label:`📚 ${n}`,value:e._id,sortKey:r}}).sort((e,t)=>e.sortKey.localeCompare(t.sortKey)),console.log(`Loaded ${this.courseOptions.length} courses for filtering (lightweight mode)`)}catch(e){console.error(`Failed to load courses (lightweight):`,e),await this.loadCoursesExpensive()}},async loadCoursesExpensive(){try{console.log(`Using expensive course loading (full configs)...`),this.courseOptions=(await this.dataLayer.getAdminDB().getCourses()).filter(e=>e.courseID).map(e=>{let t=e.name&&e.name.trim(),n=e.creator?` (${e.creator})`:``,r,i;return t&&t!==e.courseID?(r=t,i=t.toLowerCase()):(r=e.courseID,i=e.courseID.toLowerCase()),{label:`${e.public?`🌐`:`🔒`} ${r}${n}`,value:e.courseID,sortKey:i}}).sort((e,t)=>e.sortKey.localeCompare(t.sortKey)),console.log(`Loaded ${this.courseOptions.length} courses for filtering (expensive mode)`)}catch(e){console.error(`Failed to load courses (expensive):`,e),this.loadCoursesBasic()}},async loadCoursesBasic(){try{console.log(`Using fallback course loading (IDs only)`),this.courseOptions=[{label:`⚠️ Course names not available - using IDs only`,value:``}]}catch(e){console.error(`Failed to load basic courses:`,e)}},onCourseFilterChanged(){this.query},getCourseNameById(e){let t=this.courseOptions.find(t=>t.value===e);return t?t.label:e},getSelectedCourseDetails(){return this.selectedCourseId?`ID: ${this.selectedCourseId}`:``},viewLookup(e){return y.getView(e)}}}),x={class:`admin-dashboard`},S={key:0,class:`mt-2`},C={key:0,class:`text-caption text-grey-darken-1`};function _sfc_render(a,d,f,p,m,h){let g=r(`v-card-title`),_=r(`v-select`),v=r(`v-chip`),y=r(`v-card-text`),b=r(`v-card`),w=r(`card-search`),T=r(`card-search-results`),E=r(`v-col`),D=r(`card-loader`),O=r(`v-row`),k=r(`card-history-viewer`);return n(),c(`div`,x,[d[4]||(d[4]=s(`h1`,null,`Admin Dashboard`,-1)),t(b,{class:`mb-4`},{default:e(()=>[t(g,null,{default:e(()=>d[2]||(d[2]=[i(`User Selection`)])),_:1}),t(y,null,{default:e(()=>[t(_,{modelValue:a.selectedUserId,"onUpdate:modelValue":[d[0]||(d[0]=e=>a.selectedUserId=e),a.onUserSelected],items:a.userOptions,"item-title":`label`,"item-value":`value`,label:`Select User`},null,8,[`modelValue`,`items`,`onUpdate:modelValue`]),a.selectedUserId?(n(),l(v,{key:0,color:`primary`,class:`mt-2`},{default:e(()=>[i(` Viewing data for: `+o(a.selectedUserId),1)]),_:1})):u(``,!0)]),_:1})]),_:1}),t(b,{class:`mb-4`},{default:e(()=>[t(g,null,{default:e(()=>d[3]||(d[3]=[i(`Search Filters`)])),_:1}),t(y,null,{default:e(()=>[t(_,{modelValue:a.selectedCourseId,"onUpdate:modelValue":[d[1]||(d[1]=e=>a.selectedCourseId=e),a.onCourseFilterChanged],items:a.courseOptions,"item-title":`label`,"item-value":`value`,label:`Filter by Course (optional)`,clearable:``},null,8,[`modelValue`,`items`,`onUpdate:modelValue`]),a.selectedCourseId?(n(),c(`div`,S,[t(v,{color:`info`,class:`mb-1`},{default:e(()=>[i(` 🎯 `+o(a.getCourseNameById(a.selectedCourseId)),1)]),_:1}),a.getSelectedCourseDetails()?(n(),c(`div`,C,o(a.getSelectedCourseDetails()),1)):u(``,!0)])):(n(),l(v,{key:1,color:`warning`,class:`mt-2`},{default:e(()=>[i(` ⚠️ Searching ALL `+o(a.courseOptions.length)+` courses (may be slow) `,1)]),_:1}))]),_:1})]),_:1}),t(w,{onSearch:a.onSearch},null,8,[`onSearch`]),t(O,null,{default:e(()=>[t(E,{cols:`6`},{default:e(()=>[a.query?(n(),l(T,{key:0,query:a.query,"data-layer":a.dataLayer,"course-filter":a.selectedCourseId,onCardSelected:a.onCardSelected},null,8,[`query`,`data-layer`,`course-filter`,`onCardSelected`])):u(``,!0)]),_:1}),t(E,{cols:`6`},{default:e(()=>[a.selectedCard?(n(),l(D,{key:0,qualified_id:{courseID:a.selectedCard.courseId,cardID:a.selectedCard.cardId},"view-lookup":a.viewLookup},null,8,[`qualified_id`,`view-lookup`])):u(``,!0)]),_:1})]),_:1}),a.selectedCard&&a.selectedUserReader?(n(),l(k,{key:0,"card-id":a.selectedCard.cardId,"course-id":a.selectedCard.courseId,"user-id":a.selectedUserId,"user-d-b":a.selectedUserReader},null,8,[`card-id`,`course-id`,`user-id`,`user-d-b`])):u(``,!0)])}var w=v(b,[[`render`,_sfc_render],[`__scopeId`,`data-v-7409c94e`]]);export{w as default};
2
+ //# sourceMappingURL=AdminDashboard-BObO6egG.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminDashboard-BOHgXD45.js","names":[],"sources":["../../src/views/AdminDashboard.vue","../../src/views/AdminDashboard.vue"],"sourcesContent":["<template>\n <div class=\"admin-dashboard\">\n <h1>Admin Dashboard</h1>\n\n <!-- User Selection Section -->\n <v-card class=\"mb-4\">\n <v-card-title>User Selection</v-card-title>\n <v-card-text>\n <v-select\n v-model=\"selectedUserId\"\n :items=\"userOptions\"\n item-title=\"label\"\n item-value=\"value\"\n label=\"Select User\"\n @update:model-value=\"onUserSelected\"\n ></v-select>\n <v-chip v-if=\"selectedUserId\" color=\"primary\" class=\"mt-2\"> Viewing data for: {{ selectedUserId }} </v-chip>\n </v-card-text>\n </v-card>\n\n <!-- Course Filter Section -->\n <v-card class=\"mb-4\">\n <v-card-title>Search Filters</v-card-title>\n <v-card-text>\n <v-select\n v-model=\"selectedCourseId\"\n :items=\"courseOptions\"\n item-title=\"label\"\n item-value=\"value\"\n label=\"Filter by Course (optional)\"\n clearable\n @update:model-value=\"onCourseFilterChanged\"\n ></v-select>\n <div v-if=\"selectedCourseId\" class=\"mt-2\">\n <v-chip color=\"info\" class=\"mb-1\"> 🎯 {{ getCourseNameById(selectedCourseId) }} </v-chip>\n <div v-if=\"getSelectedCourseDetails()\" class=\"text-caption text-grey-darken-1\">\n {{ getSelectedCourseDetails() }}\n </div>\n </div>\n <v-chip v-else color=\"warning\" class=\"mt-2\">\n ⚠️ Searching ALL {{ courseOptions.length }} courses (may be slow)\n </v-chip>\n </v-card-text>\n </v-card>\n\n <!-- Card Search Section -->\n <card-search @search=\"onSearch\" />\n <v-row>\n <v-col cols=\"6\">\n <card-search-results\n v-if=\"query\"\n :query=\"query\"\n :data-layer=\"dataLayer\"\n :course-filter=\"selectedCourseId\"\n @card-selected=\"onCardSelected\"\n />\n </v-col>\n <v-col cols=\"6\">\n <card-loader\n v-if=\"selectedCard\"\n :qualified_id=\"{ courseID: selectedCard.courseId, cardID: selectedCard.cardId }\"\n :view-lookup=\"viewLookup\"\n />\n </v-col>\n </v-row>\n\n <!-- Card History Section -->\n <card-history-viewer\n v-if=\"selectedCard && selectedUserReader\"\n :card-id=\"selectedCard.cardId\"\n :course-id=\"selectedCard.courseId\"\n :user-id=\"selectedUserId\"\n :user-d-b=\"selectedUserReader\"\n />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { CardSearch, CardSearchResults, CardHistoryViewer, CardLoader, getCurrentUser } from '@vue-skuilder/common-ui';\nimport { getDataLayer, CourseLookup } from '@vue-skuilder/db';\nimport { allCourseWare } from '@vue-skuilder/courseware';\nimport { UserDBInterface, UserDBReader, DataLayerProvider, AdminDBInterface } from '@vue-skuilder/db';\n\ninterface UserOption {\n label: string;\n value: string;\n}\n\nexport default defineComponent({\n name: 'AdminDashboard',\n components: {\n CardSearch,\n CardSearchResults,\n CardHistoryViewer,\n CardLoader,\n },\n data() {\n return {\n query: '',\n selectedCard: null as { cardId: string; courseId: string } | null,\n userId: '',\n userDB: null as UserDBInterface | null,\n dataLayer: null as DataLayerProvider | null,\n adminDB: null as AdminDBInterface | null,\n selectedUserId: '',\n selectedUserReader: null as UserDBReader | null,\n selectedCourseId: null as string | null,\n userOptions: [] as UserOption[],\n courseOptions: [] as UserOption[],\n };\n },\n async created() {\n this.userDB = await getCurrentUser();\n this.userId = this.userDB.getUsername();\n this.dataLayer = await getDataLayer();\n this.adminDB = this.dataLayer.getAdminDB();\n\n // Load user list for selection\n await this.loadUsers();\n\n // Load available courses\n await this.loadCourses();\n },\n methods: {\n async loadUsers() {\n try {\n const users = await this.adminDB!.getUsers();\n this.userOptions = users\n .filter((user) => user.name && !user.name.startsWith('Guest_'))\n .map((user) => ({\n label: user.name || 'Unknown User',\n value: user.name || '',\n }))\n .filter((option) => option.value !== '');\n } catch (error) {\n console.error('Failed to load users:', error);\n }\n },\n\n async onUserSelected(userId: string) {\n if (!userId) {\n this.selectedUserReader = null;\n return;\n }\n\n try {\n this.selectedUserReader = await this.dataLayer!.createUserReaderForUser(userId);\n } catch (error) {\n console.error('Failed to create user reader:', error);\n this.selectedUserReader = null;\n }\n },\n\n onSearch(query: string) {\n this.query = query;\n },\n\n onCardSelected(card: { cardId: string; courseId: string }) {\n this.selectedCard = card;\n },\n\n async loadCourses() {\n try {\n // Try efficient lookup-only approach first\n // const coursesDB = this.dataLayer!.getCoursesDB();\n\n // Get basic course list from lookup DB (lightweight, just IDs and basic names)\n const lookupCourses = await CourseLookup.allCourseWare();\n\n this.courseOptions = lookupCourses\n .filter((course) => course._id)\n .map((course) => {\n const courseName = course.name && course.name.trim();\n let displayName: string;\n let sortKey: string;\n\n if (courseName && courseName !== course._id && courseName !== '') {\n // Has a real name different from ID\n displayName = courseName;\n sortKey = courseName.toLowerCase();\n } else {\n // No name or name is same as ID - use ID\n displayName = course._id;\n sortKey = course._id.toLowerCase();\n }\n\n // Simple display without expensive metadata lookups\n return {\n label: `📚 ${displayName}`,\n value: course._id,\n sortKey,\n };\n })\n .sort((a, b) => a.sortKey.localeCompare(b.sortKey));\n\n console.log(`Loaded ${this.courseOptions.length} courses for filtering (lightweight mode)`);\n } catch (error) {\n console.error('Failed to load courses (lightweight):', error);\n // Fallback to expensive approach\n await this.loadCoursesExpensive();\n }\n },\n\n async loadCoursesExpensive() {\n try {\n console.log('Using expensive course loading (full configs)...');\n const adminDB = this.dataLayer!.getAdminDB();\n const basicCourseList = await adminDB.getCourses(); // This fetches full configs\n\n this.courseOptions = basicCourseList\n .filter((course) => course.courseID)\n .map((course) => {\n const courseName = course.name && course.name.trim();\n const creator = course.creator ? ` (${course.creator})` : '';\n\n let displayName: string;\n let sortKey: string;\n\n if (courseName && courseName !== course.courseID) {\n // Has a real name different from ID\n displayName = courseName;\n sortKey = courseName.toLowerCase();\n } else {\n // No name or name is same as ID - use ID\n displayName = course.courseID!;\n sortKey = course.courseID!.toLowerCase();\n }\n\n const visibility = course.public ? '🌐' : '🔒';\n\n return {\n label: `${visibility} ${displayName}${creator}`,\n value: course.courseID!,\n sortKey,\n };\n })\n .sort((a, b) => a.sortKey.localeCompare(b.sortKey));\n\n console.log(`Loaded ${this.courseOptions.length} courses for filtering (expensive mode)`);\n } catch (error) {\n console.error('Failed to load courses (expensive):', error);\n // Final fallback\n this.loadCoursesBasic();\n }\n },\n\n async loadCoursesBasic() {\n try {\n // Fallback: just get course IDs from lookup DB (fast)\n console.log('Using fallback course loading (IDs only)');\n // This would need a new method that just gets the lookup docs without full configs\n // For now, we'll show a basic message\n this.courseOptions = [{ label: '⚠️ Course names not available - using IDs only', value: '' }];\n } catch (error) {\n console.error('Failed to load basic courses:', error);\n }\n },\n\n onCourseFilterChanged() {\n // If there's an active search, re-run it with the new filter\n if (this.query) {\n // The CardSearchResults component will automatically re-search with the new filter\n }\n },\n\n getCourseNameById(courseId: string): string {\n const course = this.courseOptions.find((c) => c.value === courseId);\n return course ? course.label : courseId;\n },\n\n getSelectedCourseDetails(): string {\n if (!this.selectedCourseId) return '';\n\n // For now, just return the ID as additional context\n return `ID: ${this.selectedCourseId}`;\n },\n\n viewLookup(viewDescriptor: unknown) {\n return allCourseWare.getView(viewDescriptor);\n },\n },\n});\n</script>\n\n<style scoped>\n.admin-dashboard {\n padding: 2rem;\n}\n</style>\n","<template>\n <div class=\"admin-dashboard\">\n <h1>Admin Dashboard</h1>\n\n <!-- User Selection Section -->\n <v-card class=\"mb-4\">\n <v-card-title>User Selection</v-card-title>\n <v-card-text>\n <v-select\n v-model=\"selectedUserId\"\n :items=\"userOptions\"\n item-title=\"label\"\n item-value=\"value\"\n label=\"Select User\"\n @update:model-value=\"onUserSelected\"\n ></v-select>\n <v-chip v-if=\"selectedUserId\" color=\"primary\" class=\"mt-2\"> Viewing data for: {{ selectedUserId }} </v-chip>\n </v-card-text>\n </v-card>\n\n <!-- Course Filter Section -->\n <v-card class=\"mb-4\">\n <v-card-title>Search Filters</v-card-title>\n <v-card-text>\n <v-select\n v-model=\"selectedCourseId\"\n :items=\"courseOptions\"\n item-title=\"label\"\n item-value=\"value\"\n label=\"Filter by Course (optional)\"\n clearable\n @update:model-value=\"onCourseFilterChanged\"\n ></v-select>\n <div v-if=\"selectedCourseId\" class=\"mt-2\">\n <v-chip color=\"info\" class=\"mb-1\"> 🎯 {{ getCourseNameById(selectedCourseId) }} </v-chip>\n <div v-if=\"getSelectedCourseDetails()\" class=\"text-caption text-grey-darken-1\">\n {{ getSelectedCourseDetails() }}\n </div>\n </div>\n <v-chip v-else color=\"warning\" class=\"mt-2\">\n ⚠️ Searching ALL {{ courseOptions.length }} courses (may be slow)\n </v-chip>\n </v-card-text>\n </v-card>\n\n <!-- Card Search Section -->\n <card-search @search=\"onSearch\" />\n <v-row>\n <v-col cols=\"6\">\n <card-search-results\n v-if=\"query\"\n :query=\"query\"\n :data-layer=\"dataLayer\"\n :course-filter=\"selectedCourseId\"\n @card-selected=\"onCardSelected\"\n />\n </v-col>\n <v-col cols=\"6\">\n <card-loader\n v-if=\"selectedCard\"\n :qualified_id=\"{ courseID: selectedCard.courseId, cardID: selectedCard.cardId }\"\n :view-lookup=\"viewLookup\"\n />\n </v-col>\n </v-row>\n\n <!-- Card History Section -->\n <card-history-viewer\n v-if=\"selectedCard && selectedUserReader\"\n :card-id=\"selectedCard.cardId\"\n :course-id=\"selectedCard.courseId\"\n :user-id=\"selectedUserId\"\n :user-d-b=\"selectedUserReader\"\n />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { CardSearch, CardSearchResults, CardHistoryViewer, CardLoader, getCurrentUser } from '@vue-skuilder/common-ui';\nimport { getDataLayer, CourseLookup } from '@vue-skuilder/db';\nimport { allCourseWare } from '@vue-skuilder/courseware';\nimport { UserDBInterface, UserDBReader, DataLayerProvider, AdminDBInterface } from '@vue-skuilder/db';\n\ninterface UserOption {\n label: string;\n value: string;\n}\n\nexport default defineComponent({\n name: 'AdminDashboard',\n components: {\n CardSearch,\n CardSearchResults,\n CardHistoryViewer,\n CardLoader,\n },\n data() {\n return {\n query: '',\n selectedCard: null as { cardId: string; courseId: string } | null,\n userId: '',\n userDB: null as UserDBInterface | null,\n dataLayer: null as DataLayerProvider | null,\n adminDB: null as AdminDBInterface | null,\n selectedUserId: '',\n selectedUserReader: null as UserDBReader | null,\n selectedCourseId: null as string | null,\n userOptions: [] as UserOption[],\n courseOptions: [] as UserOption[],\n };\n },\n async created() {\n this.userDB = await getCurrentUser();\n this.userId = this.userDB.getUsername();\n this.dataLayer = await getDataLayer();\n this.adminDB = this.dataLayer.getAdminDB();\n\n // Load user list for selection\n await this.loadUsers();\n\n // Load available courses\n await this.loadCourses();\n },\n methods: {\n async loadUsers() {\n try {\n const users = await this.adminDB!.getUsers();\n this.userOptions = users\n .filter((user) => user.name && !user.name.startsWith('Guest_'))\n .map((user) => ({\n label: user.name || 'Unknown User',\n value: user.name || '',\n }))\n .filter((option) => option.value !== '');\n } catch (error) {\n console.error('Failed to load users:', error);\n }\n },\n\n async onUserSelected(userId: string) {\n if (!userId) {\n this.selectedUserReader = null;\n return;\n }\n\n try {\n this.selectedUserReader = await this.dataLayer!.createUserReaderForUser(userId);\n } catch (error) {\n console.error('Failed to create user reader:', error);\n this.selectedUserReader = null;\n }\n },\n\n onSearch(query: string) {\n this.query = query;\n },\n\n onCardSelected(card: { cardId: string; courseId: string }) {\n this.selectedCard = card;\n },\n\n async loadCourses() {\n try {\n // Try efficient lookup-only approach first\n // const coursesDB = this.dataLayer!.getCoursesDB();\n\n // Get basic course list from lookup DB (lightweight, just IDs and basic names)\n const lookupCourses = await CourseLookup.allCourseWare();\n\n this.courseOptions = lookupCourses\n .filter((course) => course._id)\n .map((course) => {\n const courseName = course.name && course.name.trim();\n let displayName: string;\n let sortKey: string;\n\n if (courseName && courseName !== course._id && courseName !== '') {\n // Has a real name different from ID\n displayName = courseName;\n sortKey = courseName.toLowerCase();\n } else {\n // No name or name is same as ID - use ID\n displayName = course._id;\n sortKey = course._id.toLowerCase();\n }\n\n // Simple display without expensive metadata lookups\n return {\n label: `📚 ${displayName}`,\n value: course._id,\n sortKey,\n };\n })\n .sort((a, b) => a.sortKey.localeCompare(b.sortKey));\n\n console.log(`Loaded ${this.courseOptions.length} courses for filtering (lightweight mode)`);\n } catch (error) {\n console.error('Failed to load courses (lightweight):', error);\n // Fallback to expensive approach\n await this.loadCoursesExpensive();\n }\n },\n\n async loadCoursesExpensive() {\n try {\n console.log('Using expensive course loading (full configs)...');\n const adminDB = this.dataLayer!.getAdminDB();\n const basicCourseList = await adminDB.getCourses(); // This fetches full configs\n\n this.courseOptions = basicCourseList\n .filter((course) => course.courseID)\n .map((course) => {\n const courseName = course.name && course.name.trim();\n const creator = course.creator ? ` (${course.creator})` : '';\n\n let displayName: string;\n let sortKey: string;\n\n if (courseName && courseName !== course.courseID) {\n // Has a real name different from ID\n displayName = courseName;\n sortKey = courseName.toLowerCase();\n } else {\n // No name or name is same as ID - use ID\n displayName = course.courseID!;\n sortKey = course.courseID!.toLowerCase();\n }\n\n const visibility = course.public ? '🌐' : '🔒';\n\n return {\n label: `${visibility} ${displayName}${creator}`,\n value: course.courseID!,\n sortKey,\n };\n })\n .sort((a, b) => a.sortKey.localeCompare(b.sortKey));\n\n console.log(`Loaded ${this.courseOptions.length} courses for filtering (expensive mode)`);\n } catch (error) {\n console.error('Failed to load courses (expensive):', error);\n // Final fallback\n this.loadCoursesBasic();\n }\n },\n\n async loadCoursesBasic() {\n try {\n // Fallback: just get course IDs from lookup DB (fast)\n console.log('Using fallback course loading (IDs only)');\n // This would need a new method that just gets the lookup docs without full configs\n // For now, we'll show a basic message\n this.courseOptions = [{ label: '⚠️ Course names not available - using IDs only', value: '' }];\n } catch (error) {\n console.error('Failed to load basic courses:', error);\n }\n },\n\n onCourseFilterChanged() {\n // If there's an active search, re-run it with the new filter\n if (this.query) {\n // The CardSearchResults component will automatically re-search with the new filter\n }\n },\n\n getCourseNameById(courseId: string): string {\n const course = this.courseOptions.find((c) => c.value === courseId);\n return course ? course.label : courseId;\n },\n\n getSelectedCourseDetails(): string {\n if (!this.selectedCourseId) return '';\n\n // For now, just return the ID as additional context\n return `ID: ${this.selectedCourseId}`;\n },\n\n viewLookup(viewDescriptor: unknown) {\n return allCourseWare.getView(viewDescriptor);\n },\n },\n});\n</script>\n\n<style scoped>\n.admin-dashboard {\n padding: 2rem;\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdminDashboard-BObO6egG.js","names":[],"sources":["../../src/views/AdminDashboard.vue","../../src/views/AdminDashboard.vue"],"sourcesContent":["<template>\n <div class=\"admin-dashboard\">\n <h1>Admin Dashboard</h1>\n\n <!-- User Selection Section -->\n <v-card class=\"mb-4\">\n <v-card-title>User Selection</v-card-title>\n <v-card-text>\n <v-select\n v-model=\"selectedUserId\"\n :items=\"userOptions\"\n item-title=\"label\"\n item-value=\"value\"\n label=\"Select User\"\n @update:model-value=\"onUserSelected\"\n ></v-select>\n <v-chip v-if=\"selectedUserId\" color=\"primary\" class=\"mt-2\"> Viewing data for: {{ selectedUserId }} </v-chip>\n </v-card-text>\n </v-card>\n\n <!-- Course Filter Section -->\n <v-card class=\"mb-4\">\n <v-card-title>Search Filters</v-card-title>\n <v-card-text>\n <v-select\n v-model=\"selectedCourseId\"\n :items=\"courseOptions\"\n item-title=\"label\"\n item-value=\"value\"\n label=\"Filter by Course (optional)\"\n clearable\n @update:model-value=\"onCourseFilterChanged\"\n ></v-select>\n <div v-if=\"selectedCourseId\" class=\"mt-2\">\n <v-chip color=\"info\" class=\"mb-1\"> 🎯 {{ getCourseNameById(selectedCourseId) }} </v-chip>\n <div v-if=\"getSelectedCourseDetails()\" class=\"text-caption text-grey-darken-1\">\n {{ getSelectedCourseDetails() }}\n </div>\n </div>\n <v-chip v-else color=\"warning\" class=\"mt-2\">\n ⚠️ Searching ALL {{ courseOptions.length }} courses (may be slow)\n </v-chip>\n </v-card-text>\n </v-card>\n\n <!-- Card Search Section -->\n <card-search @search=\"onSearch\" />\n <v-row>\n <v-col cols=\"6\">\n <card-search-results\n v-if=\"query\"\n :query=\"query\"\n :data-layer=\"dataLayer\"\n :course-filter=\"selectedCourseId\"\n @card-selected=\"onCardSelected\"\n />\n </v-col>\n <v-col cols=\"6\">\n <card-loader\n v-if=\"selectedCard\"\n :qualified_id=\"{ courseID: selectedCard.courseId, cardID: selectedCard.cardId }\"\n :view-lookup=\"viewLookup\"\n />\n </v-col>\n </v-row>\n\n <!-- Card History Section -->\n <card-history-viewer\n v-if=\"selectedCard && selectedUserReader\"\n :card-id=\"selectedCard.cardId\"\n :course-id=\"selectedCard.courseId\"\n :user-id=\"selectedUserId\"\n :user-d-b=\"selectedUserReader\"\n />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { CardSearch, CardSearchResults, CardHistoryViewer, CardLoader, getCurrentUser } from '@vue-skuilder/common-ui';\nimport { getDataLayer, CourseLookup } from '@vue-skuilder/db';\nimport { allCourseWare } from '@vue-skuilder/courseware';\nimport { UserDBInterface, UserDBReader, DataLayerProvider, AdminDBInterface } from '@vue-skuilder/db';\n\ninterface UserOption {\n label: string;\n value: string;\n}\n\nexport default defineComponent({\n name: 'AdminDashboard',\n components: {\n CardSearch,\n CardSearchResults,\n CardHistoryViewer,\n CardLoader,\n },\n data() {\n return {\n query: '',\n selectedCard: null as { cardId: string; courseId: string } | null,\n userId: '',\n userDB: null as UserDBInterface | null,\n dataLayer: null as DataLayerProvider | null,\n adminDB: null as AdminDBInterface | null,\n selectedUserId: '',\n selectedUserReader: null as UserDBReader | null,\n selectedCourseId: null as string | null,\n userOptions: [] as UserOption[],\n courseOptions: [] as UserOption[],\n };\n },\n async created() {\n this.userDB = await getCurrentUser();\n this.userId = this.userDB.getUsername();\n this.dataLayer = await getDataLayer();\n this.adminDB = this.dataLayer.getAdminDB();\n\n // Load user list for selection\n await this.loadUsers();\n\n // Load available courses\n await this.loadCourses();\n },\n methods: {\n async loadUsers() {\n try {\n const users = await this.adminDB!.getUsers();\n this.userOptions = users\n .filter((user) => user.name && !user.name.startsWith('Guest_'))\n .map((user) => ({\n label: user.name || 'Unknown User',\n value: user.name || '',\n }))\n .filter((option) => option.value !== '');\n } catch (error) {\n console.error('Failed to load users:', error);\n }\n },\n\n async onUserSelected(userId: string) {\n if (!userId) {\n this.selectedUserReader = null;\n return;\n }\n\n try {\n this.selectedUserReader = await this.dataLayer!.createUserReaderForUser(userId);\n } catch (error) {\n console.error('Failed to create user reader:', error);\n this.selectedUserReader = null;\n }\n },\n\n onSearch(query: string) {\n this.query = query;\n },\n\n onCardSelected(card: { cardId: string; courseId: string }) {\n this.selectedCard = card;\n },\n\n async loadCourses() {\n try {\n // Try efficient lookup-only approach first\n // const coursesDB = this.dataLayer!.getCoursesDB();\n\n // Get basic course list from lookup DB (lightweight, just IDs and basic names)\n const lookupCourses = await CourseLookup.allCourseWare();\n\n this.courseOptions = lookupCourses\n .filter((course) => course._id)\n .map((course) => {\n const courseName = course.name && course.name.trim();\n let displayName: string;\n let sortKey: string;\n\n if (courseName && courseName !== course._id && courseName !== '') {\n // Has a real name different from ID\n displayName = courseName;\n sortKey = courseName.toLowerCase();\n } else {\n // No name or name is same as ID - use ID\n displayName = course._id;\n sortKey = course._id.toLowerCase();\n }\n\n // Simple display without expensive metadata lookups\n return {\n label: `📚 ${displayName}`,\n value: course._id,\n sortKey,\n };\n })\n .sort((a, b) => a.sortKey.localeCompare(b.sortKey));\n\n console.log(`Loaded ${this.courseOptions.length} courses for filtering (lightweight mode)`);\n } catch (error) {\n console.error('Failed to load courses (lightweight):', error);\n // Fallback to expensive approach\n await this.loadCoursesExpensive();\n }\n },\n\n async loadCoursesExpensive() {\n try {\n console.log('Using expensive course loading (full configs)...');\n const adminDB = this.dataLayer!.getAdminDB();\n const basicCourseList = await adminDB.getCourses(); // This fetches full configs\n\n this.courseOptions = basicCourseList\n .filter((course) => course.courseID)\n .map((course) => {\n const courseName = course.name && course.name.trim();\n const creator = course.creator ? ` (${course.creator})` : '';\n\n let displayName: string;\n let sortKey: string;\n\n if (courseName && courseName !== course.courseID) {\n // Has a real name different from ID\n displayName = courseName;\n sortKey = courseName.toLowerCase();\n } else {\n // No name or name is same as ID - use ID\n displayName = course.courseID!;\n sortKey = course.courseID!.toLowerCase();\n }\n\n const visibility = course.public ? '🌐' : '🔒';\n\n return {\n label: `${visibility} ${displayName}${creator}`,\n value: course.courseID!,\n sortKey,\n };\n })\n .sort((a, b) => a.sortKey.localeCompare(b.sortKey));\n\n console.log(`Loaded ${this.courseOptions.length} courses for filtering (expensive mode)`);\n } catch (error) {\n console.error('Failed to load courses (expensive):', error);\n // Final fallback\n this.loadCoursesBasic();\n }\n },\n\n async loadCoursesBasic() {\n try {\n // Fallback: just get course IDs from lookup DB (fast)\n console.log('Using fallback course loading (IDs only)');\n // This would need a new method that just gets the lookup docs without full configs\n // For now, we'll show a basic message\n this.courseOptions = [{ label: '⚠️ Course names not available - using IDs only', value: '' }];\n } catch (error) {\n console.error('Failed to load basic courses:', error);\n }\n },\n\n onCourseFilterChanged() {\n // If there's an active search, re-run it with the new filter\n if (this.query) {\n // The CardSearchResults component will automatically re-search with the new filter\n }\n },\n\n getCourseNameById(courseId: string): string {\n const course = this.courseOptions.find((c) => c.value === courseId);\n return course ? course.label : courseId;\n },\n\n getSelectedCourseDetails(): string {\n if (!this.selectedCourseId) return '';\n\n // For now, just return the ID as additional context\n return `ID: ${this.selectedCourseId}`;\n },\n\n viewLookup(viewDescriptor: unknown) {\n return allCourseWare.getView(viewDescriptor);\n },\n },\n});\n</script>\n\n<style scoped>\n.admin-dashboard {\n padding: 2rem;\n}\n</style>\n","<template>\n <div class=\"admin-dashboard\">\n <h1>Admin Dashboard</h1>\n\n <!-- User Selection Section -->\n <v-card class=\"mb-4\">\n <v-card-title>User Selection</v-card-title>\n <v-card-text>\n <v-select\n v-model=\"selectedUserId\"\n :items=\"userOptions\"\n item-title=\"label\"\n item-value=\"value\"\n label=\"Select User\"\n @update:model-value=\"onUserSelected\"\n ></v-select>\n <v-chip v-if=\"selectedUserId\" color=\"primary\" class=\"mt-2\"> Viewing data for: {{ selectedUserId }} </v-chip>\n </v-card-text>\n </v-card>\n\n <!-- Course Filter Section -->\n <v-card class=\"mb-4\">\n <v-card-title>Search Filters</v-card-title>\n <v-card-text>\n <v-select\n v-model=\"selectedCourseId\"\n :items=\"courseOptions\"\n item-title=\"label\"\n item-value=\"value\"\n label=\"Filter by Course (optional)\"\n clearable\n @update:model-value=\"onCourseFilterChanged\"\n ></v-select>\n <div v-if=\"selectedCourseId\" class=\"mt-2\">\n <v-chip color=\"info\" class=\"mb-1\"> 🎯 {{ getCourseNameById(selectedCourseId) }} </v-chip>\n <div v-if=\"getSelectedCourseDetails()\" class=\"text-caption text-grey-darken-1\">\n {{ getSelectedCourseDetails() }}\n </div>\n </div>\n <v-chip v-else color=\"warning\" class=\"mt-2\">\n ⚠️ Searching ALL {{ courseOptions.length }} courses (may be slow)\n </v-chip>\n </v-card-text>\n </v-card>\n\n <!-- Card Search Section -->\n <card-search @search=\"onSearch\" />\n <v-row>\n <v-col cols=\"6\">\n <card-search-results\n v-if=\"query\"\n :query=\"query\"\n :data-layer=\"dataLayer\"\n :course-filter=\"selectedCourseId\"\n @card-selected=\"onCardSelected\"\n />\n </v-col>\n <v-col cols=\"6\">\n <card-loader\n v-if=\"selectedCard\"\n :qualified_id=\"{ courseID: selectedCard.courseId, cardID: selectedCard.cardId }\"\n :view-lookup=\"viewLookup\"\n />\n </v-col>\n </v-row>\n\n <!-- Card History Section -->\n <card-history-viewer\n v-if=\"selectedCard && selectedUserReader\"\n :card-id=\"selectedCard.cardId\"\n :course-id=\"selectedCard.courseId\"\n :user-id=\"selectedUserId\"\n :user-d-b=\"selectedUserReader\"\n />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { CardSearch, CardSearchResults, CardHistoryViewer, CardLoader, getCurrentUser } from '@vue-skuilder/common-ui';\nimport { getDataLayer, CourseLookup } from '@vue-skuilder/db';\nimport { allCourseWare } from '@vue-skuilder/courseware';\nimport { UserDBInterface, UserDBReader, DataLayerProvider, AdminDBInterface } from '@vue-skuilder/db';\n\ninterface UserOption {\n label: string;\n value: string;\n}\n\nexport default defineComponent({\n name: 'AdminDashboard',\n components: {\n CardSearch,\n CardSearchResults,\n CardHistoryViewer,\n CardLoader,\n },\n data() {\n return {\n query: '',\n selectedCard: null as { cardId: string; courseId: string } | null,\n userId: '',\n userDB: null as UserDBInterface | null,\n dataLayer: null as DataLayerProvider | null,\n adminDB: null as AdminDBInterface | null,\n selectedUserId: '',\n selectedUserReader: null as UserDBReader | null,\n selectedCourseId: null as string | null,\n userOptions: [] as UserOption[],\n courseOptions: [] as UserOption[],\n };\n },\n async created() {\n this.userDB = await getCurrentUser();\n this.userId = this.userDB.getUsername();\n this.dataLayer = await getDataLayer();\n this.adminDB = this.dataLayer.getAdminDB();\n\n // Load user list for selection\n await this.loadUsers();\n\n // Load available courses\n await this.loadCourses();\n },\n methods: {\n async loadUsers() {\n try {\n const users = await this.adminDB!.getUsers();\n this.userOptions = users\n .filter((user) => user.name && !user.name.startsWith('Guest_'))\n .map((user) => ({\n label: user.name || 'Unknown User',\n value: user.name || '',\n }))\n .filter((option) => option.value !== '');\n } catch (error) {\n console.error('Failed to load users:', error);\n }\n },\n\n async onUserSelected(userId: string) {\n if (!userId) {\n this.selectedUserReader = null;\n return;\n }\n\n try {\n this.selectedUserReader = await this.dataLayer!.createUserReaderForUser(userId);\n } catch (error) {\n console.error('Failed to create user reader:', error);\n this.selectedUserReader = null;\n }\n },\n\n onSearch(query: string) {\n this.query = query;\n },\n\n onCardSelected(card: { cardId: string; courseId: string }) {\n this.selectedCard = card;\n },\n\n async loadCourses() {\n try {\n // Try efficient lookup-only approach first\n // const coursesDB = this.dataLayer!.getCoursesDB();\n\n // Get basic course list from lookup DB (lightweight, just IDs and basic names)\n const lookupCourses = await CourseLookup.allCourseWare();\n\n this.courseOptions = lookupCourses\n .filter((course) => course._id)\n .map((course) => {\n const courseName = course.name && course.name.trim();\n let displayName: string;\n let sortKey: string;\n\n if (courseName && courseName !== course._id && courseName !== '') {\n // Has a real name different from ID\n displayName = courseName;\n sortKey = courseName.toLowerCase();\n } else {\n // No name or name is same as ID - use ID\n displayName = course._id;\n sortKey = course._id.toLowerCase();\n }\n\n // Simple display without expensive metadata lookups\n return {\n label: `📚 ${displayName}`,\n value: course._id,\n sortKey,\n };\n })\n .sort((a, b) => a.sortKey.localeCompare(b.sortKey));\n\n console.log(`Loaded ${this.courseOptions.length} courses for filtering (lightweight mode)`);\n } catch (error) {\n console.error('Failed to load courses (lightweight):', error);\n // Fallback to expensive approach\n await this.loadCoursesExpensive();\n }\n },\n\n async loadCoursesExpensive() {\n try {\n console.log('Using expensive course loading (full configs)...');\n const adminDB = this.dataLayer!.getAdminDB();\n const basicCourseList = await adminDB.getCourses(); // This fetches full configs\n\n this.courseOptions = basicCourseList\n .filter((course) => course.courseID)\n .map((course) => {\n const courseName = course.name && course.name.trim();\n const creator = course.creator ? ` (${course.creator})` : '';\n\n let displayName: string;\n let sortKey: string;\n\n if (courseName && courseName !== course.courseID) {\n // Has a real name different from ID\n displayName = courseName;\n sortKey = courseName.toLowerCase();\n } else {\n // No name or name is same as ID - use ID\n displayName = course.courseID!;\n sortKey = course.courseID!.toLowerCase();\n }\n\n const visibility = course.public ? '🌐' : '🔒';\n\n return {\n label: `${visibility} ${displayName}${creator}`,\n value: course.courseID!,\n sortKey,\n };\n })\n .sort((a, b) => a.sortKey.localeCompare(b.sortKey));\n\n console.log(`Loaded ${this.courseOptions.length} courses for filtering (expensive mode)`);\n } catch (error) {\n console.error('Failed to load courses (expensive):', error);\n // Final fallback\n this.loadCoursesBasic();\n }\n },\n\n async loadCoursesBasic() {\n try {\n // Fallback: just get course IDs from lookup DB (fast)\n console.log('Using fallback course loading (IDs only)');\n // This would need a new method that just gets the lookup docs without full configs\n // For now, we'll show a basic message\n this.courseOptions = [{ label: '⚠️ Course names not available - using IDs only', value: '' }];\n } catch (error) {\n console.error('Failed to load basic courses:', error);\n }\n },\n\n onCourseFilterChanged() {\n // If there's an active search, re-run it with the new filter\n if (this.query) {\n // The CardSearchResults component will automatically re-search with the new filter\n }\n },\n\n getCourseNameById(courseId: string): string {\n const course = this.courseOptions.find((c) => c.value === courseId);\n return course ? course.label : courseId;\n },\n\n getSelectedCourseDetails(): string {\n if (!this.selectedCourseId) return '';\n\n // For now, just return the ID as additional context\n return `ID: ${this.selectedCourseId}`;\n },\n\n viewLookup(viewDescriptor: unknown) {\n return allCourseWare.getView(viewDescriptor);\n },\n },\n});\n</script>\n\n<style scoped>\n.admin-dashboard {\n padding: 2rem;\n}\n</style>\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,S as i,T as a,Vt as o,W as s,_ as c,b as l,f as u,v as d,y as f}from"./vue.runtime.esm-bundler-C3q8JS9f.js";import{T as p}from"./common-ui.es-I814CYyx.js";import{E as m}from"./dist-CrcJCHFk.js";import"./MarkdownRenderer-DoVbFpA6-BIbDxYC4.js";import{k as h}from"./dist-DkeESCP4.js";import{t as g}from"./index-CF-NaZ2k.js";var _=a({name:`ClassroomCtrlPanel`,props:{classroomId:{type:String,required:!0}},data(){return{classroomCfg:null,classroomDB:null,assignedContent:[],nameRules:[e=>e.length>30?`Course name must be 30 characters or less`:!0],updatePending:!0,addingContent:!1,availableCourses:[],selectedCourse:``,availableTags:[],selectedTags:[]}},computed:{_assignedCourses(){return this.assignedContent.filter(e=>e.type===`course`)},_assignedTags(){return this.assignedContent.filter(e=>e.type===`tag`)}},watch:{async selectedCourse(){this.selectedCourse?this.availableTags=(await h().getCourseDB(this.selectedCourse).getCourseTagStubs()).rows.map(e=>e.doc):this.availableTags=[]}},async created(){try{this.classroomDB=await h().getClassroomDB(this.classroomId,`teacher`),this.assignedContent=await this.classroomDB.getAssignedContent(),this.classroomCfg=this.classroomDB.getConfig(),console.log(`[ClassroomCtrlPanel] Route loaded w/ (prop) _id: ${this.classroomId}`),console.log(`[ClassroomCtrlPanel] Config: ${JSON.stringify(this.classroomCfg)}`),this.availableCourses=await h().getCoursesDB().getCourseList(),this.updatePending=!1}catch(e){console.error(`[ClassroomCtrlPanel] Error initializing:`,e)}},methods:{async assignContent(){if(!this.classroomDB)return;let e=await p();this.selectedTags.length===0?await this.classroomDB.assignContent?.({assignedOn:m(),activeOn:m(),type:`course`,courseID:this.selectedCourse,assignedBy:e.getUsername()}):await Promise.all(this.selectedTags.map(t=>this.classroomDB.assignContent?.({assignedOn:m(),activeOn:m(),type:`tag`,courseID:this.selectedCourse,tagID:t,assignedBy:e.getUsername()}))),this.assignedContent=await this.classroomDB.getAssignedContent(),this.addingContent=!1,this.selectedCourse=``,this.selectedTags=[],this.availableTags=[]},async removeContent(e){this.classroomDB&&this.classroomDB.removeContent&&(await this.classroomDB.removeContent(e),this.assignedContent=await this.classroomDB.getAssignedContent())},async submit(){this.updatePending=!0}}}),v={key:0},y=[`onClick`],b=[`onClick`];function _sfc_render(a,p,m,h,g,_){let x=r(`router-link`),S=r(`v-btn`),C=r(`v-checkbox`),w=r(`v-col`),T=r(`v-icon`),E=r(`v-fade-transition`),D=r(`v-toolbar-title`),O=r(`v-spacer`),k=r(`v-toolbar`),A=r(`v-select`),j=r(`v-card-text`),M=r(`v-card-actions`),N=r(`v-card`),P=r(`v-row`);return a.updatePending?f(``,!0):(n(),l(`div`,v,[c(`h1`,null,[t(x,{to:`/classrooms`},{default:e(()=>p[5]||(p[5]=[i(`My Classrooms`)])),_:1}),i(` / `+o(a.classroomCfg.name),1)]),c(`h3`,null,[i(` Join code: `+o(a.classroomCfg.joinCode)+` `,1),t(x,{to:`/classrooms/${a.classroomId}/code`},{default:e(()=>[t(S,{size:`x-small`,icon:`mdi-fullscreen`,color:`accent`,alt:`Make Fullscreen`})]),_:1},8,[`to`])]),t(P,null,{default:e(()=>[t(w,{cols:`12`,sm:`6`,md:`4`},{default:e(()=>[t(C,{modelValue:a.classroomCfg.peerAssist,"onUpdate:modelValue":p[0]||(p[0]=e=>a.classroomCfg.peerAssist=e),label:`Allow peer instruction`},null,8,[`modelValue`])]),_:1}),a.classroomDB?(n(),d(w,{key:0,cols:`12`},{default:e(()=>[p[10]||(p[10]=c(`h2`,null,`Assigned Content:`,-1)),p[11]||(p[11]=c(`h3`,null,`Quilts:`,-1)),p[12]||(p[12]=c(`ul`,null,null,-1)),c(`ul`,null,[(n(!0),l(u,null,s(a._assignedCourses,e=>(n(),l(`li`,{key:e.courseID},[i(o(e.courseID)+` `,1),c(`a`,{onClick:t=>a.removeContent(e)},`Remove`,8,y)]))),128))]),p[13]||(p[13]=c(`h3`,null,`Tags:`,-1)),c(`ul`,null,[(n(!0),l(u,null,s(a._assignedTags,(e,t)=>(n(),l(`li`,{key:t},[i(o(e.courseID)+` - `+o(e.tagID)+` `,1),c(`a`,{onClick:t=>a.removeContent(e)},`Remove`,8,b)]))),128))]),t(E,null,{default:e(()=>[a.addingContent?f(``,!0):(n(),d(S,{key:0,color:`primary`,onClick:p[1]||(p[1]=e=>a.addingContent=!0)},{default:e(()=>[p[7]||(p[7]=i(` Assign New Content `)),t(T,{end:``},{default:e(()=>p[6]||(p[6]=[i(`mdi-plus`)])),_:1})]),_:1}))]),_:1}),a.addingContent?(n(),d(N,{key:0},{default:e(()=>[t(k,null,{default:e(()=>[t(D,null,{default:e(()=>p[8]||(p[8]=[i(`Add Content`)])),_:1}),t(O),t(S,{icon:`mdi-close`,color:`error`,onClick:p[2]||(p[2]=e=>a.addingContent=!1)})]),_:1}),t(j,null,{default:e(()=>[t(A,{modelValue:a.selectedCourse,"onUpdate:modelValue":p[3]||(p[3]=e=>a.selectedCourse=e),label:`Select Quilt`,items:a.availableCourses,"item-title":`name`,"item-value":`_id`,title:`Select Quilt`},null,8,[`modelValue`,`items`]),t(A,{modelValue:a.selectedTags,"onUpdate:modelValue":p[4]||(p[4]=e=>a.selectedTags=e),label:`Select Tags`,items:a.availableTags,"item-title":`name`,"item-value":`name`,multiple:``,chips:``,hint:``,"persistent-hint":``},null,8,[`modelValue`,`items`])]),_:1}),t(M,null,{default:e(()=>[a.selectedCourse===``?f(``,!0):(n(),d(S,{key:0,color:`primary`,onClick:a.assignContent},{default:e(()=>[i(o(a.selectedTags.length==0?`Add Entire Quilt`:`Add Tags`)+` `,1),t(T,{end:``},{default:e(()=>p[9]||(p[9]=[i(`mdi-plus`)])),_:1})]),_:1},8,[`onClick`]))]),_:1})]),_:1})):f(``,!0)]),_:1})):f(``,!0)]),_:1})]))}var x=g(_,[[`render`,_sfc_render]]);export{x as default};
2
- //# sourceMappingURL=ClassroomCtrlPanel-ezMgP7A3.js.map
1
+ import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,S as i,T as a,Vt as o,W as s,_ as c,b as l,f as u,v as d,y as f}from"./vue.runtime.esm-bundler-C3q8JS9f.js";import{T as p}from"./common-ui.es-BrXWBn7p.js";import{E as m}from"./dist-CrcJCHFk.js";import"./MarkdownRenderer-DoVbFpA6-BIbDxYC4.js";import{k as h}from"./dist-CzLl7g6t.js";import{t as g}from"./index-DUZItsH-.js";var _=a({name:`ClassroomCtrlPanel`,props:{classroomId:{type:String,required:!0}},data(){return{classroomCfg:null,classroomDB:null,assignedContent:[],nameRules:[e=>e.length>30?`Course name must be 30 characters or less`:!0],updatePending:!0,addingContent:!1,availableCourses:[],selectedCourse:``,availableTags:[],selectedTags:[]}},computed:{_assignedCourses(){return this.assignedContent.filter(e=>e.type===`course`)},_assignedTags(){return this.assignedContent.filter(e=>e.type===`tag`)}},watch:{async selectedCourse(){this.selectedCourse?this.availableTags=(await h().getCourseDB(this.selectedCourse).getCourseTagStubs()).rows.map(e=>e.doc):this.availableTags=[]}},async created(){try{this.classroomDB=await h().getClassroomDB(this.classroomId,`teacher`),this.assignedContent=await this.classroomDB.getAssignedContent(),this.classroomCfg=this.classroomDB.getConfig(),console.log(`[ClassroomCtrlPanel] Route loaded w/ (prop) _id: ${this.classroomId}`),console.log(`[ClassroomCtrlPanel] Config: ${JSON.stringify(this.classroomCfg)}`),this.availableCourses=await h().getCoursesDB().getCourseList(),this.updatePending=!1}catch(e){console.error(`[ClassroomCtrlPanel] Error initializing:`,e)}},methods:{async assignContent(){if(!this.classroomDB)return;let e=await p();this.selectedTags.length===0?await this.classroomDB.assignContent?.({assignedOn:m(),activeOn:m(),type:`course`,courseID:this.selectedCourse,assignedBy:e.getUsername()}):await Promise.all(this.selectedTags.map(t=>this.classroomDB.assignContent?.({assignedOn:m(),activeOn:m(),type:`tag`,courseID:this.selectedCourse,tagID:t,assignedBy:e.getUsername()}))),this.assignedContent=await this.classroomDB.getAssignedContent(),this.addingContent=!1,this.selectedCourse=``,this.selectedTags=[],this.availableTags=[]},async removeContent(e){this.classroomDB&&this.classroomDB.removeContent&&(await this.classroomDB.removeContent(e),this.assignedContent=await this.classroomDB.getAssignedContent())},async submit(){this.updatePending=!0}}}),v={key:0},y=[`onClick`],b=[`onClick`];function _sfc_render(a,p,m,h,g,_){let x=r(`router-link`),S=r(`v-btn`),C=r(`v-checkbox`),w=r(`v-col`),T=r(`v-icon`),E=r(`v-fade-transition`),D=r(`v-toolbar-title`),O=r(`v-spacer`),k=r(`v-toolbar`),A=r(`v-select`),j=r(`v-card-text`),M=r(`v-card-actions`),N=r(`v-card`),P=r(`v-row`);return a.updatePending?f(``,!0):(n(),l(`div`,v,[c(`h1`,null,[t(x,{to:`/classrooms`},{default:e(()=>p[5]||(p[5]=[i(`My Classrooms`)])),_:1}),i(` / `+o(a.classroomCfg.name),1)]),c(`h3`,null,[i(` Join code: `+o(a.classroomCfg.joinCode)+` `,1),t(x,{to:`/classrooms/${a.classroomId}/code`},{default:e(()=>[t(S,{size:`x-small`,icon:`mdi-fullscreen`,color:`accent`,alt:`Make Fullscreen`})]),_:1},8,[`to`])]),t(P,null,{default:e(()=>[t(w,{cols:`12`,sm:`6`,md:`4`},{default:e(()=>[t(C,{modelValue:a.classroomCfg.peerAssist,"onUpdate:modelValue":p[0]||(p[0]=e=>a.classroomCfg.peerAssist=e),label:`Allow peer instruction`},null,8,[`modelValue`])]),_:1}),a.classroomDB?(n(),d(w,{key:0,cols:`12`},{default:e(()=>[p[10]||(p[10]=c(`h2`,null,`Assigned Content:`,-1)),p[11]||(p[11]=c(`h3`,null,`Quilts:`,-1)),p[12]||(p[12]=c(`ul`,null,null,-1)),c(`ul`,null,[(n(!0),l(u,null,s(a._assignedCourses,e=>(n(),l(`li`,{key:e.courseID},[i(o(e.courseID)+` `,1),c(`a`,{onClick:t=>a.removeContent(e)},`Remove`,8,y)]))),128))]),p[13]||(p[13]=c(`h3`,null,`Tags:`,-1)),c(`ul`,null,[(n(!0),l(u,null,s(a._assignedTags,(e,t)=>(n(),l(`li`,{key:t},[i(o(e.courseID)+` - `+o(e.tagID)+` `,1),c(`a`,{onClick:t=>a.removeContent(e)},`Remove`,8,b)]))),128))]),t(E,null,{default:e(()=>[a.addingContent?f(``,!0):(n(),d(S,{key:0,color:`primary`,onClick:p[1]||(p[1]=e=>a.addingContent=!0)},{default:e(()=>[p[7]||(p[7]=i(` Assign New Content `)),t(T,{end:``},{default:e(()=>p[6]||(p[6]=[i(`mdi-plus`)])),_:1})]),_:1}))]),_:1}),a.addingContent?(n(),d(N,{key:0},{default:e(()=>[t(k,null,{default:e(()=>[t(D,null,{default:e(()=>p[8]||(p[8]=[i(`Add Content`)])),_:1}),t(O),t(S,{icon:`mdi-close`,color:`error`,onClick:p[2]||(p[2]=e=>a.addingContent=!1)})]),_:1}),t(j,null,{default:e(()=>[t(A,{modelValue:a.selectedCourse,"onUpdate:modelValue":p[3]||(p[3]=e=>a.selectedCourse=e),label:`Select Quilt`,items:a.availableCourses,"item-title":`name`,"item-value":`_id`,title:`Select Quilt`},null,8,[`modelValue`,`items`]),t(A,{modelValue:a.selectedTags,"onUpdate:modelValue":p[4]||(p[4]=e=>a.selectedTags=e),label:`Select Tags`,items:a.availableTags,"item-title":`name`,"item-value":`name`,multiple:``,chips:``,hint:``,"persistent-hint":``},null,8,[`modelValue`,`items`])]),_:1}),t(M,null,{default:e(()=>[a.selectedCourse===``?f(``,!0):(n(),d(S,{key:0,color:`primary`,onClick:a.assignContent},{default:e(()=>[i(o(a.selectedTags.length==0?`Add Entire Quilt`:`Add Tags`)+` `,1),t(T,{end:``},{default:e(()=>p[9]||(p[9]=[i(`mdi-plus`)])),_:1})]),_:1},8,[`onClick`]))]),_:1})]),_:1})):f(``,!0)]),_:1})):f(``,!0)]),_:1})]))}var x=g(_,[[`render`,_sfc_render]]);export{x as default};
2
+ //# sourceMappingURL=ClassroomCtrlPanel-lgN6cdTd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ClassroomCtrlPanel-ezMgP7A3.js","names":[],"sources":["../../src/components/Classrooms/ClassroomCtrlPanel.vue","../../src/components/Classrooms/ClassroomCtrlPanel.vue"],"sourcesContent":["<template>\n <div v-if=\"!updatePending\">\n <h1><router-link to=\"/classrooms\">My Classrooms</router-link> / {{ classroomCfg!.name }}</h1>\n\n <h3>\n Join code: {{ classroomCfg!.joinCode }}\n <router-link :to=\"`/classrooms/${classroomId}/code`\">\n <v-btn size=\"x-small\" icon=\"mdi-fullscreen\" color=\"accent\" alt=\"Make Fullscreen\"> </v-btn>\n </router-link>\n </h3>\n <v-row>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-checkbox v-model=\"classroomCfg!.peerAssist\" label=\"Allow peer instruction\"></v-checkbox>\n </v-col>\n <v-col v-if=\"classroomDB\" cols=\"12\">\n <h2>Assigned Content:</h2>\n <h3>Quilts:</h3>\n <ul></ul>\n <ul>\n <li v-for=\"c in _assignedCourses\" :key=\"c.courseID\">\n {{ c.courseID }} <a @click=\"removeContent(c)\">Remove</a>\n </li>\n </ul>\n <h3>Tags:</h3>\n <ul>\n <li v-for=\"(c, i) in _assignedTags\" :key=\"i\">\n {{ c.courseID }} - {{ c.tagID }} <a @click=\"removeContent(c)\">Remove</a>\n </li>\n </ul>\n <v-fade-transition>\n <v-btn v-if=\"!addingContent\" color=\"primary\" @click=\"addingContent = true\">\n Assign New Content\n <v-icon end>mdi-plus</v-icon>\n </v-btn>\n </v-fade-transition>\n <v-card v-if=\"addingContent\">\n <v-toolbar>\n <v-toolbar-title>Add Content</v-toolbar-title>\n <v-spacer></v-spacer>\n <v-btn icon=\"mdi-close\" color=\"error\" @click=\"addingContent = false\"> </v-btn>\n </v-toolbar>\n <v-card-text>\n <v-select\n v-model=\"selectedCourse\"\n label=\"Select Quilt\"\n :items=\"availableCourses\"\n item-title=\"name\"\n item-value=\"_id\"\n title=\"Select Quilt\"\n ></v-select>\n\n <v-select\n v-model=\"selectedTags\"\n label=\"Select Tags\"\n :items=\"availableTags\"\n item-title=\"name\"\n item-value=\"name\"\n multiple\n chips\n hint=\"\"\n persistent-hint\n ></v-select>\n </v-card-text>\n\n <v-card-actions>\n <v-btn v-if=\"selectedCourse !== ''\" color=\"primary\" @click=\"assignContent\">\n {{ selectedTags.length == 0 ? 'Add Entire Quilt' : 'Add Tags' }}\n <v-icon end>mdi-plus</v-icon>\n </v-btn>\n </v-card-actions>\n </v-card>\n </v-col>\n </v-row>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport moment from 'moment';\nimport { TeacherClassroomDBInterface, AssignedContent, AssignedTag, Tag, getDataLayer } from '@vue-skuilder/db';\nimport { ClassroomConfig, CourseConfig } from '@vue-skuilder/common';\nimport { defineComponent } from 'vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'ClassroomCtrlPanel',\n\n props: {\n classroomId: {\n type: String,\n required: true,\n },\n },\n\n data() {\n return {\n classroomCfg: null as ClassroomConfig | null,\n classroomDB: null as TeacherClassroomDBInterface | null,\n assignedContent: [] as AssignedContent[],\n nameRules: [\n (value: string): string | boolean => {\n const max = 30;\n return value.length > max ? `Course name must be ${max} characters or less` : true;\n },\n ],\n updatePending: true,\n addingContent: false,\n availableCourses: [] as CourseConfig[],\n selectedCourse: '',\n availableTags: [] as Tag[],\n selectedTags: [] as string[],\n };\n },\n\n computed: {\n _assignedCourses(): AssignedContent[] {\n return this.assignedContent.filter((c) => c.type === 'course');\n },\n _assignedTags(): AssignedTag[] {\n return this.assignedContent.filter((c) => c.type === 'tag') as AssignedTag[];\n },\n },\n\n watch: {\n async selectedCourse() {\n if (this.selectedCourse) {\n // Get course DB from data layer\n const courseDB = getDataLayer().getCourseDB(this.selectedCourse);\n // Get tags from course DB\n const tagResponse = await courseDB.getCourseTagStubs();\n this.availableTags = tagResponse.rows.map((row) => row.doc!);\n } else {\n this.availableTags = [];\n }\n },\n },\n\n async created() {\n try {\n // Get classroom DB from data layer\n this.classroomDB = (await getDataLayer().getClassroomDB(\n this.classroomId,\n 'teacher'\n )) as TeacherClassroomDBInterface;\n this.assignedContent = await this.classroomDB.getAssignedContent();\n this.classroomCfg = this.classroomDB.getConfig();\n\n console.log(`[ClassroomCtrlPanel] Route loaded w/ (prop) _id: ${this.classroomId}`);\n console.log(`[ClassroomCtrlPanel] Config: ${JSON.stringify(this.classroomCfg)}`);\n\n // Get course list from data layer\n this.availableCourses = await getDataLayer().getCoursesDB().getCourseList();\n\n this.updatePending = false;\n } catch (error) {\n console.error('[ClassroomCtrlPanel] Error initializing:', error);\n }\n },\n\n methods: {\n async assignContent() {\n if (!this.classroomDB) return;\n const u = await getCurrentUser();\n\n if (this.selectedTags.length === 0) {\n await this.classroomDB.assignContent?.({\n assignedOn: moment(),\n activeOn: moment(),\n type: 'course',\n courseID: this.selectedCourse,\n assignedBy: u.getUsername(),\n });\n } else {\n await Promise.all(\n this.selectedTags.map((tag) =>\n this.classroomDB!.assignContent?.({\n assignedOn: moment(),\n activeOn: moment(),\n type: 'tag',\n courseID: this.selectedCourse,\n tagID: tag,\n assignedBy: u.getUsername(),\n })\n )\n );\n }\n\n this.assignedContent = await this.classroomDB.getAssignedContent();\n this.addingContent = false;\n this.selectedCourse = '';\n this.selectedTags = [];\n this.availableTags = [];\n },\n\n async removeContent(c: AssignedContent) {\n if (this.classroomDB && this.classroomDB.removeContent) {\n await this.classroomDB.removeContent(c);\n this.assignedContent = await this.classroomDB.getAssignedContent();\n }\n },\n\n async submit() {\n this.updatePending = true;\n },\n },\n});\n</script>\n","<template>\n <div v-if=\"!updatePending\">\n <h1><router-link to=\"/classrooms\">My Classrooms</router-link> / {{ classroomCfg!.name }}</h1>\n\n <h3>\n Join code: {{ classroomCfg!.joinCode }}\n <router-link :to=\"`/classrooms/${classroomId}/code`\">\n <v-btn size=\"x-small\" icon=\"mdi-fullscreen\" color=\"accent\" alt=\"Make Fullscreen\"> </v-btn>\n </router-link>\n </h3>\n <v-row>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-checkbox v-model=\"classroomCfg!.peerAssist\" label=\"Allow peer instruction\"></v-checkbox>\n </v-col>\n <v-col v-if=\"classroomDB\" cols=\"12\">\n <h2>Assigned Content:</h2>\n <h3>Quilts:</h3>\n <ul></ul>\n <ul>\n <li v-for=\"c in _assignedCourses\" :key=\"c.courseID\">\n {{ c.courseID }} <a @click=\"removeContent(c)\">Remove</a>\n </li>\n </ul>\n <h3>Tags:</h3>\n <ul>\n <li v-for=\"(c, i) in _assignedTags\" :key=\"i\">\n {{ c.courseID }} - {{ c.tagID }} <a @click=\"removeContent(c)\">Remove</a>\n </li>\n </ul>\n <v-fade-transition>\n <v-btn v-if=\"!addingContent\" color=\"primary\" @click=\"addingContent = true\">\n Assign New Content\n <v-icon end>mdi-plus</v-icon>\n </v-btn>\n </v-fade-transition>\n <v-card v-if=\"addingContent\">\n <v-toolbar>\n <v-toolbar-title>Add Content</v-toolbar-title>\n <v-spacer></v-spacer>\n <v-btn icon=\"mdi-close\" color=\"error\" @click=\"addingContent = false\"> </v-btn>\n </v-toolbar>\n <v-card-text>\n <v-select\n v-model=\"selectedCourse\"\n label=\"Select Quilt\"\n :items=\"availableCourses\"\n item-title=\"name\"\n item-value=\"_id\"\n title=\"Select Quilt\"\n ></v-select>\n\n <v-select\n v-model=\"selectedTags\"\n label=\"Select Tags\"\n :items=\"availableTags\"\n item-title=\"name\"\n item-value=\"name\"\n multiple\n chips\n hint=\"\"\n persistent-hint\n ></v-select>\n </v-card-text>\n\n <v-card-actions>\n <v-btn v-if=\"selectedCourse !== ''\" color=\"primary\" @click=\"assignContent\">\n {{ selectedTags.length == 0 ? 'Add Entire Quilt' : 'Add Tags' }}\n <v-icon end>mdi-plus</v-icon>\n </v-btn>\n </v-card-actions>\n </v-card>\n </v-col>\n </v-row>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport moment from 'moment';\nimport { TeacherClassroomDBInterface, AssignedContent, AssignedTag, Tag, getDataLayer } from '@vue-skuilder/db';\nimport { ClassroomConfig, CourseConfig } from '@vue-skuilder/common';\nimport { defineComponent } from 'vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'ClassroomCtrlPanel',\n\n props: {\n classroomId: {\n type: String,\n required: true,\n },\n },\n\n data() {\n return {\n classroomCfg: null as ClassroomConfig | null,\n classroomDB: null as TeacherClassroomDBInterface | null,\n assignedContent: [] as AssignedContent[],\n nameRules: [\n (value: string): string | boolean => {\n const max = 30;\n return value.length > max ? `Course name must be ${max} characters or less` : true;\n },\n ],\n updatePending: true,\n addingContent: false,\n availableCourses: [] as CourseConfig[],\n selectedCourse: '',\n availableTags: [] as Tag[],\n selectedTags: [] as string[],\n };\n },\n\n computed: {\n _assignedCourses(): AssignedContent[] {\n return this.assignedContent.filter((c) => c.type === 'course');\n },\n _assignedTags(): AssignedTag[] {\n return this.assignedContent.filter((c) => c.type === 'tag') as AssignedTag[];\n },\n },\n\n watch: {\n async selectedCourse() {\n if (this.selectedCourse) {\n // Get course DB from data layer\n const courseDB = getDataLayer().getCourseDB(this.selectedCourse);\n // Get tags from course DB\n const tagResponse = await courseDB.getCourseTagStubs();\n this.availableTags = tagResponse.rows.map((row) => row.doc!);\n } else {\n this.availableTags = [];\n }\n },\n },\n\n async created() {\n try {\n // Get classroom DB from data layer\n this.classroomDB = (await getDataLayer().getClassroomDB(\n this.classroomId,\n 'teacher'\n )) as TeacherClassroomDBInterface;\n this.assignedContent = await this.classroomDB.getAssignedContent();\n this.classroomCfg = this.classroomDB.getConfig();\n\n console.log(`[ClassroomCtrlPanel] Route loaded w/ (prop) _id: ${this.classroomId}`);\n console.log(`[ClassroomCtrlPanel] Config: ${JSON.stringify(this.classroomCfg)}`);\n\n // Get course list from data layer\n this.availableCourses = await getDataLayer().getCoursesDB().getCourseList();\n\n this.updatePending = false;\n } catch (error) {\n console.error('[ClassroomCtrlPanel] Error initializing:', error);\n }\n },\n\n methods: {\n async assignContent() {\n if (!this.classroomDB) return;\n const u = await getCurrentUser();\n\n if (this.selectedTags.length === 0) {\n await this.classroomDB.assignContent?.({\n assignedOn: moment(),\n activeOn: moment(),\n type: 'course',\n courseID: this.selectedCourse,\n assignedBy: u.getUsername(),\n });\n } else {\n await Promise.all(\n this.selectedTags.map((tag) =>\n this.classroomDB!.assignContent?.({\n assignedOn: moment(),\n activeOn: moment(),\n type: 'tag',\n courseID: this.selectedCourse,\n tagID: tag,\n assignedBy: u.getUsername(),\n })\n )\n );\n }\n\n this.assignedContent = await this.classroomDB.getAssignedContent();\n this.addingContent = false;\n this.selectedCourse = '';\n this.selectedTags = [];\n this.availableTags = [];\n },\n\n async removeContent(c: AssignedContent) {\n if (this.classroomDB && this.classroomDB.removeContent) {\n await this.classroomDB.removeContent(c);\n this.assignedContent = await this.classroomDB.getAssignedContent();\n }\n },\n\n async submit() {\n this.updatePending = true;\n },\n },\n});\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"ClassroomCtrlPanel-lgN6cdTd.js","names":[],"sources":["../../src/components/Classrooms/ClassroomCtrlPanel.vue","../../src/components/Classrooms/ClassroomCtrlPanel.vue"],"sourcesContent":["<template>\n <div v-if=\"!updatePending\">\n <h1><router-link to=\"/classrooms\">My Classrooms</router-link> / {{ classroomCfg!.name }}</h1>\n\n <h3>\n Join code: {{ classroomCfg!.joinCode }}\n <router-link :to=\"`/classrooms/${classroomId}/code`\">\n <v-btn size=\"x-small\" icon=\"mdi-fullscreen\" color=\"accent\" alt=\"Make Fullscreen\"> </v-btn>\n </router-link>\n </h3>\n <v-row>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-checkbox v-model=\"classroomCfg!.peerAssist\" label=\"Allow peer instruction\"></v-checkbox>\n </v-col>\n <v-col v-if=\"classroomDB\" cols=\"12\">\n <h2>Assigned Content:</h2>\n <h3>Quilts:</h3>\n <ul></ul>\n <ul>\n <li v-for=\"c in _assignedCourses\" :key=\"c.courseID\">\n {{ c.courseID }} <a @click=\"removeContent(c)\">Remove</a>\n </li>\n </ul>\n <h3>Tags:</h3>\n <ul>\n <li v-for=\"(c, i) in _assignedTags\" :key=\"i\">\n {{ c.courseID }} - {{ c.tagID }} <a @click=\"removeContent(c)\">Remove</a>\n </li>\n </ul>\n <v-fade-transition>\n <v-btn v-if=\"!addingContent\" color=\"primary\" @click=\"addingContent = true\">\n Assign New Content\n <v-icon end>mdi-plus</v-icon>\n </v-btn>\n </v-fade-transition>\n <v-card v-if=\"addingContent\">\n <v-toolbar>\n <v-toolbar-title>Add Content</v-toolbar-title>\n <v-spacer></v-spacer>\n <v-btn icon=\"mdi-close\" color=\"error\" @click=\"addingContent = false\"> </v-btn>\n </v-toolbar>\n <v-card-text>\n <v-select\n v-model=\"selectedCourse\"\n label=\"Select Quilt\"\n :items=\"availableCourses\"\n item-title=\"name\"\n item-value=\"_id\"\n title=\"Select Quilt\"\n ></v-select>\n\n <v-select\n v-model=\"selectedTags\"\n label=\"Select Tags\"\n :items=\"availableTags\"\n item-title=\"name\"\n item-value=\"name\"\n multiple\n chips\n hint=\"\"\n persistent-hint\n ></v-select>\n </v-card-text>\n\n <v-card-actions>\n <v-btn v-if=\"selectedCourse !== ''\" color=\"primary\" @click=\"assignContent\">\n {{ selectedTags.length == 0 ? 'Add Entire Quilt' : 'Add Tags' }}\n <v-icon end>mdi-plus</v-icon>\n </v-btn>\n </v-card-actions>\n </v-card>\n </v-col>\n </v-row>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport moment from 'moment';\nimport { TeacherClassroomDBInterface, AssignedContent, AssignedTag, Tag, getDataLayer } from '@vue-skuilder/db';\nimport { ClassroomConfig, CourseConfig } from '@vue-skuilder/common';\nimport { defineComponent } from 'vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'ClassroomCtrlPanel',\n\n props: {\n classroomId: {\n type: String,\n required: true,\n },\n },\n\n data() {\n return {\n classroomCfg: null as ClassroomConfig | null,\n classroomDB: null as TeacherClassroomDBInterface | null,\n assignedContent: [] as AssignedContent[],\n nameRules: [\n (value: string): string | boolean => {\n const max = 30;\n return value.length > max ? `Course name must be ${max} characters or less` : true;\n },\n ],\n updatePending: true,\n addingContent: false,\n availableCourses: [] as CourseConfig[],\n selectedCourse: '',\n availableTags: [] as Tag[],\n selectedTags: [] as string[],\n };\n },\n\n computed: {\n _assignedCourses(): AssignedContent[] {\n return this.assignedContent.filter((c) => c.type === 'course');\n },\n _assignedTags(): AssignedTag[] {\n return this.assignedContent.filter((c) => c.type === 'tag') as AssignedTag[];\n },\n },\n\n watch: {\n async selectedCourse() {\n if (this.selectedCourse) {\n // Get course DB from data layer\n const courseDB = getDataLayer().getCourseDB(this.selectedCourse);\n // Get tags from course DB\n const tagResponse = await courseDB.getCourseTagStubs();\n this.availableTags = tagResponse.rows.map((row) => row.doc!);\n } else {\n this.availableTags = [];\n }\n },\n },\n\n async created() {\n try {\n // Get classroom DB from data layer\n this.classroomDB = (await getDataLayer().getClassroomDB(\n this.classroomId,\n 'teacher'\n )) as TeacherClassroomDBInterface;\n this.assignedContent = await this.classroomDB.getAssignedContent();\n this.classroomCfg = this.classroomDB.getConfig();\n\n console.log(`[ClassroomCtrlPanel] Route loaded w/ (prop) _id: ${this.classroomId}`);\n console.log(`[ClassroomCtrlPanel] Config: ${JSON.stringify(this.classroomCfg)}`);\n\n // Get course list from data layer\n this.availableCourses = await getDataLayer().getCoursesDB().getCourseList();\n\n this.updatePending = false;\n } catch (error) {\n console.error('[ClassroomCtrlPanel] Error initializing:', error);\n }\n },\n\n methods: {\n async assignContent() {\n if (!this.classroomDB) return;\n const u = await getCurrentUser();\n\n if (this.selectedTags.length === 0) {\n await this.classroomDB.assignContent?.({\n assignedOn: moment(),\n activeOn: moment(),\n type: 'course',\n courseID: this.selectedCourse,\n assignedBy: u.getUsername(),\n });\n } else {\n await Promise.all(\n this.selectedTags.map((tag) =>\n this.classroomDB!.assignContent?.({\n assignedOn: moment(),\n activeOn: moment(),\n type: 'tag',\n courseID: this.selectedCourse,\n tagID: tag,\n assignedBy: u.getUsername(),\n })\n )\n );\n }\n\n this.assignedContent = await this.classroomDB.getAssignedContent();\n this.addingContent = false;\n this.selectedCourse = '';\n this.selectedTags = [];\n this.availableTags = [];\n },\n\n async removeContent(c: AssignedContent) {\n if (this.classroomDB && this.classroomDB.removeContent) {\n await this.classroomDB.removeContent(c);\n this.assignedContent = await this.classroomDB.getAssignedContent();\n }\n },\n\n async submit() {\n this.updatePending = true;\n },\n },\n});\n</script>\n","<template>\n <div v-if=\"!updatePending\">\n <h1><router-link to=\"/classrooms\">My Classrooms</router-link> / {{ classroomCfg!.name }}</h1>\n\n <h3>\n Join code: {{ classroomCfg!.joinCode }}\n <router-link :to=\"`/classrooms/${classroomId}/code`\">\n <v-btn size=\"x-small\" icon=\"mdi-fullscreen\" color=\"accent\" alt=\"Make Fullscreen\"> </v-btn>\n </router-link>\n </h3>\n <v-row>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-checkbox v-model=\"classroomCfg!.peerAssist\" label=\"Allow peer instruction\"></v-checkbox>\n </v-col>\n <v-col v-if=\"classroomDB\" cols=\"12\">\n <h2>Assigned Content:</h2>\n <h3>Quilts:</h3>\n <ul></ul>\n <ul>\n <li v-for=\"c in _assignedCourses\" :key=\"c.courseID\">\n {{ c.courseID }} <a @click=\"removeContent(c)\">Remove</a>\n </li>\n </ul>\n <h3>Tags:</h3>\n <ul>\n <li v-for=\"(c, i) in _assignedTags\" :key=\"i\">\n {{ c.courseID }} - {{ c.tagID }} <a @click=\"removeContent(c)\">Remove</a>\n </li>\n </ul>\n <v-fade-transition>\n <v-btn v-if=\"!addingContent\" color=\"primary\" @click=\"addingContent = true\">\n Assign New Content\n <v-icon end>mdi-plus</v-icon>\n </v-btn>\n </v-fade-transition>\n <v-card v-if=\"addingContent\">\n <v-toolbar>\n <v-toolbar-title>Add Content</v-toolbar-title>\n <v-spacer></v-spacer>\n <v-btn icon=\"mdi-close\" color=\"error\" @click=\"addingContent = false\"> </v-btn>\n </v-toolbar>\n <v-card-text>\n <v-select\n v-model=\"selectedCourse\"\n label=\"Select Quilt\"\n :items=\"availableCourses\"\n item-title=\"name\"\n item-value=\"_id\"\n title=\"Select Quilt\"\n ></v-select>\n\n <v-select\n v-model=\"selectedTags\"\n label=\"Select Tags\"\n :items=\"availableTags\"\n item-title=\"name\"\n item-value=\"name\"\n multiple\n chips\n hint=\"\"\n persistent-hint\n ></v-select>\n </v-card-text>\n\n <v-card-actions>\n <v-btn v-if=\"selectedCourse !== ''\" color=\"primary\" @click=\"assignContent\">\n {{ selectedTags.length == 0 ? 'Add Entire Quilt' : 'Add Tags' }}\n <v-icon end>mdi-plus</v-icon>\n </v-btn>\n </v-card-actions>\n </v-card>\n </v-col>\n </v-row>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport moment from 'moment';\nimport { TeacherClassroomDBInterface, AssignedContent, AssignedTag, Tag, getDataLayer } from '@vue-skuilder/db';\nimport { ClassroomConfig, CourseConfig } from '@vue-skuilder/common';\nimport { defineComponent } from 'vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'ClassroomCtrlPanel',\n\n props: {\n classroomId: {\n type: String,\n required: true,\n },\n },\n\n data() {\n return {\n classroomCfg: null as ClassroomConfig | null,\n classroomDB: null as TeacherClassroomDBInterface | null,\n assignedContent: [] as AssignedContent[],\n nameRules: [\n (value: string): string | boolean => {\n const max = 30;\n return value.length > max ? `Course name must be ${max} characters or less` : true;\n },\n ],\n updatePending: true,\n addingContent: false,\n availableCourses: [] as CourseConfig[],\n selectedCourse: '',\n availableTags: [] as Tag[],\n selectedTags: [] as string[],\n };\n },\n\n computed: {\n _assignedCourses(): AssignedContent[] {\n return this.assignedContent.filter((c) => c.type === 'course');\n },\n _assignedTags(): AssignedTag[] {\n return this.assignedContent.filter((c) => c.type === 'tag') as AssignedTag[];\n },\n },\n\n watch: {\n async selectedCourse() {\n if (this.selectedCourse) {\n // Get course DB from data layer\n const courseDB = getDataLayer().getCourseDB(this.selectedCourse);\n // Get tags from course DB\n const tagResponse = await courseDB.getCourseTagStubs();\n this.availableTags = tagResponse.rows.map((row) => row.doc!);\n } else {\n this.availableTags = [];\n }\n },\n },\n\n async created() {\n try {\n // Get classroom DB from data layer\n this.classroomDB = (await getDataLayer().getClassroomDB(\n this.classroomId,\n 'teacher'\n )) as TeacherClassroomDBInterface;\n this.assignedContent = await this.classroomDB.getAssignedContent();\n this.classroomCfg = this.classroomDB.getConfig();\n\n console.log(`[ClassroomCtrlPanel] Route loaded w/ (prop) _id: ${this.classroomId}`);\n console.log(`[ClassroomCtrlPanel] Config: ${JSON.stringify(this.classroomCfg)}`);\n\n // Get course list from data layer\n this.availableCourses = await getDataLayer().getCoursesDB().getCourseList();\n\n this.updatePending = false;\n } catch (error) {\n console.error('[ClassroomCtrlPanel] Error initializing:', error);\n }\n },\n\n methods: {\n async assignContent() {\n if (!this.classroomDB) return;\n const u = await getCurrentUser();\n\n if (this.selectedTags.length === 0) {\n await this.classroomDB.assignContent?.({\n assignedOn: moment(),\n activeOn: moment(),\n type: 'course',\n courseID: this.selectedCourse,\n assignedBy: u.getUsername(),\n });\n } else {\n await Promise.all(\n this.selectedTags.map((tag) =>\n this.classroomDB!.assignContent?.({\n assignedOn: moment(),\n activeOn: moment(),\n type: 'tag',\n courseID: this.selectedCourse,\n tagID: tag,\n assignedBy: u.getUsername(),\n })\n )\n );\n }\n\n this.assignedContent = await this.classroomDB.getAssignedContent();\n this.addingContent = false;\n this.selectedCourse = '';\n this.selectedTags = [];\n this.availableTags = [];\n },\n\n async removeContent(c: AssignedContent) {\n if (this.classroomDB && this.classroomDB.removeContent) {\n await this.classroomDB.removeContent(c);\n this.assignedContent = await this.classroomDB.getAssignedContent();\n }\n },\n\n async submit() {\n this.updatePending = true;\n },\n },\n});\n</script>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import{i as e,s as t}from"./chunk-D6hFPZc3.js";import{$ as n,C as r,H as i,K as a,M as o,S as s,T as c,Vt as l,W as u,b as d,f,n as p,v as m,y as h}from"./vue.runtime.esm-bundler-C3q8JS9f.js";import{T as g,v as _}from"./common-ui.es-I814CYyx.js";import{E as v,T as y,f as b,w as x}from"./dist-CrcJCHFk.js";import"./MarkdownRenderer-DoVbFpA6-BIbDxYC4.js";import{k as S}from"./dist-DkeESCP4.js";import{t as C}from"./index-CF-NaZ2k.js";import{n as w,t as T}from"./server-Cl1ZnRx7.js";var E=t(w()),D=c({emits:[`ClassroomEditingComplete`],data(){return{mousetrap:new E.default(this.$el),peerAssist:!0,name:``,birthYear:void 0,id:``,nameRules:[e=>e.length>30?`Course name must be 30 characters or less`:!0],description:``,banner:void 0,thumb:void 0,updatePending:!1,birthYears:[]}},created(){this.mousetrap.bind(`esc`,this.clearFormAndDismiss);let e=v().year();this.birthYears.push({text:`< ${e-17} (Adult Students)`,value:0});for(let t=17;t>=6;t--)this.birthYears.push({text:`${e-t} (Grade ${t-5})`,value:e-t});this.birthYears.push({text:`>${e-6} (K or younger)`,value:e-5})},methods:{async submit(){this.updatePending=!0;let e=await g(),t={name:this.name,teachers:[e.getUsername()],students:[],birthYear:this.birthYear,classMeetingSchedule:``,peerAssist:this.peerAssist,joinCode:``};b(`Class Config:
1
+ import{i as e,s as t}from"./chunk-D6hFPZc3.js";import{$ as n,C as r,H as i,K as a,M as o,S as s,T as c,Vt as l,W as u,b as d,f,n as p,v as m,y as h}from"./vue.runtime.esm-bundler-C3q8JS9f.js";import{T as g,v as _}from"./common-ui.es-BrXWBn7p.js";import{E as v,T as y,f as b,w as x}from"./dist-CrcJCHFk.js";import"./MarkdownRenderer-DoVbFpA6-BIbDxYC4.js";import{k as S}from"./dist-CzLl7g6t.js";import{t as C}from"./index-DUZItsH-.js";import{n as w,t as T}from"./server-Db_WegNj.js";var E=t(w()),D=c({emits:[`ClassroomEditingComplete`],data(){return{mousetrap:new E.default(this.$el),peerAssist:!0,name:``,birthYear:void 0,id:``,nameRules:[e=>e.length>30?`Course name must be 30 characters or less`:!0],description:``,banner:void 0,thumb:void 0,updatePending:!1,birthYears:[]}},created(){this.mousetrap.bind(`esc`,this.clearFormAndDismiss);let e=v().year();this.birthYears.push({text:`< ${e-17} (Adult Students)`,value:0});for(let t=17;t>=6;t--)this.birthYears.push({text:`${e-t} (Grade ${t-5})`,value:e-t});this.birthYears.push({text:`>${e-6} (K or younger)`,value:e-5})},methods:{async submit(){this.updatePending=!0;let e=await g(),t={name:this.name,teachers:[e.getUsername()],students:[],birthYear:this.birthYear,classMeetingSchedule:``,peerAssist:this.peerAssist,joinCode:``};b(`Class Config:
2
2
  ${JSON.stringify(t)}`);let n=await T({data:t,type:x.CREATE_CLASSROOM,response:null,user:e.getUsername()});n.response&&n.response.ok?(_({text:`Class created successfully. Join code: ${n.response.joincode}`,status:y.ok}),e.registerForClassroom(n.response.uuid,`teacher`)):_({text:`Failed to create class. Please try again.`,status:y.error}),this.clearFormAndDismiss(),this.updatePending=!1},clearFormAndDismiss(){this.name=``,this.description=``,this.$emit(`ClassroomEditingComplete`)}}});function _sfc_render$1(e,t,o,c,l,u){let d=a(`v-card-title`),f=a(`v-spacer`),p=a(`v-icon`),h=a(`v-btn`),g=a(`v-toolbar`),_=a(`v-text-field`),v=a(`v-col`),y=a(`v-checkbox`),b=a(`v-select`),x=a(`v-row`),S=a(`v-container`),C=a(`v-form`),w=a(`v-card`);return i(),m(w,null,{default:n(()=>[r(g,{color:`primary`},{default:n(()=>[r(d,{class:`text-h6 font-weight-regular`},{default:n(()=>t[3]||(t[3]=[s(`Start a New Class`)])),_:1}),r(f),r(h,{icon:``,onClick:e.clearFormAndDismiss},{default:n(()=>[r(p,null,{default:n(()=>t[4]||(t[4]=[s(`mdi-close`)])),_:1})]),_:1},8,[`onClick`])]),_:1}),r(C,null,{default:n(()=>[r(S,null,{default:n(()=>[r(x,null,{default:n(()=>[r(v,{cols:`12`,sm:`6`,md:`4`},{default:n(()=>[r(_,{modelValue:e.name,"onUpdate:modelValue":t[0]||(t[0]=t=>e.name=t),counter:`30`,rules:e.nameRules,label:`Class Name`,required:``,hint:`Eg: Smith, Chemistry, Period 3`},null,8,[`modelValue`,`rules`])]),_:1}),r(v,{cols:`12`,sm:`6`,md:`4`},{default:n(()=>[r(y,{modelValue:e.peerAssist,"onUpdate:modelValue":t[1]||(t[1]=t=>e.peerAssist=t),label:`Allow peer instruction`},null,8,[`modelValue`])]),_:1}),r(v,{cols:`12`,sm:`6`,md:`4`},{default:n(()=>[r(b,{modelValue:e.birthYear,"onUpdate:modelValue":t[2]||(t[2]=t=>e.birthYear=t),items:e.birthYears,label:`Approximate Birth Year of Students`,"item-title":`text`,"item-value":`value`},null,8,[`modelValue`,`items`])]),_:1}),r(v,{cols:`12`,sm:`6`,md:`4`},{default:n(()=>[r(h,{loading:e.updatePending,color:`primary`,onClick:e.submit},{default:n(()=>t[5]||(t[5]=[s(`Create This Class`)])),_:1},8,[`loading`,`onClick`])]),_:1})]),_:1})]),_:1})]),_:1})]),_:1})}e(_sfc_render$1,`_sfc_render`);var O=c({name:`ClassroomsView`,components:{ClassroomEditor:C(D,[[`render`,_sfc_render$1]])},beforeRouteEnter(e,t,n){n()},data(){return{classes:[],joinCode:``,studentClasses:[],teacherClasses:[],spinnerMap:{},newClassDialog:!1,user:null}},created(){this.refreshData()},methods:{async refreshData(){this.$data.user=await g();let e=(await this.user.getUserClassrooms()).registrations,t=[],n=[];e.forEach(async e=>{let r=(await S().getClassroomDB(e.classID,e.registeredAs==`teacher`||e.registeredAs==`student`?e.registeredAs:`student`)).getConfig();console.log(`Registered class: ${JSON.stringify(r)}`);let i={_id:e.classID,name:r.name};e.registeredAs===`student`?t.push(i):e.registeredAs===`teacher`&&n.push(i)}),this.studentClasses=t,this.teacherClasses=n},async deleteClass(e){let t=await T({type:x.DELETE_CLASSROOM,user:this.user?.getUsername()||``,classID:e,response:null});t.response&&t.response.ok?_({text:`Class deleted successfully.`,status:y.ok}):_({text:`Failed to delete class. Please try again.`,status:y.error})},async leaveClass(e){this.spinnerMap[e]=!0,console.log(`Attempting to drop class: ${e}`);let t=await T({type:x.LEAVE_CLASSROOM,data:{classID:e},user:this.user?.getUsername()||``,response:null});t.response&&t.response.ok&&this.user&&await this.user.dropFromClassroom(e),delete this.spinnerMap[e],this.refreshData()},async joinClass(){let e=await T({type:x.JOIN_CLASSROOM,data:{joinCode:this.joinCode,registerAs:`student`,user:this.user?.getUsername()||``},user:this.user?.getUsername()||``,response:null});e.response&&e.response.ok?(console.log(`Adding registration to userDB...`),this.user?(await registerUserForClassroom(this.user.getUsername(),e.response.id_course,`student`),_({text:`Successfully joined class: ${e.response.course_name}.`,status:y.ok})):_({text:`Failed to join class. [Unknown current user.]`,status:y.error})):e.response&&_({text:e.response.errorText,status:y.error}),this.refreshData()},async processResponse(){this.newClassDialog=!this.newClassDialog}}});function _sfc_render(e,t,c,g,_,v){let y=a(`v-toolbar-title`),b=a(`v-toolbar`),x=a(`v-list-item-title`),S=a(`v-btn`),C=a(`v-list-item`),w=a(`v-list`),T=a(`v-card`),E=a(`v-col`),D=a(`v-row`),O=a(`v-divider`),k=a(`v-text-field`),A=a(`v-card-text`),j=a(`classroom-editor`),M=a(`v-dialog`),N=a(`v-container`);return i(),m(N,{fluid:``},{default:n(()=>[r(D,{class:`pa-4`,justify:`space-around`},{default:n(()=>[e.studentClasses.length>0?(i(),m(E,{key:0,cols:`12`,sm:`12`,md:`4`},{default:n(()=>[r(T,null,{default:n(()=>[r(b,{color:`primary`},{default:n(()=>[r(y,null,{default:n(()=>t[2]||(t[2]=[s(`My Classes`)])),_:1})]),_:1}),r(w,null,{default:n(()=>[r(p,{name:`component-fade`,mode:`out-in`},{default:n(()=>[(i(!0),d(f,null,u(e.studentClasses,a=>(i(),m(C,{key:a._id,value:a},{append:n(()=>[r(S,{size:`small`,color:`secondary`,loading:e.spinnerMap[a._id]!==void 0,onClick:t=>e.leaveClass(a._id)},{default:n(()=>t[3]||(t[3]=[s(` Leave this class `)])),_:2},1032,[`loading`,`onClick`])]),default:n(()=>[r(x,null,{default:n(()=>[s(l(a.name),1)]),_:2},1024)]),_:2},1032,[`value`]))),128))]),_:1})]),_:1})]),_:1})]),_:1})):h(``,!0),e.teacherClasses.length>0?(i(),m(E,{key:1,cols:`12`,sm:`12`,md:`4`},{default:n(()=>[r(T,null,{default:n(()=>[r(b,{color:`primary`},{default:n(()=>[r(y,null,{default:n(()=>t[4]||(t[4]=[s(`Classes I Manage`)])),_:1})]),_:1}),r(w,null,{default:n(()=>[r(p,{name:`component-fade`,mode:`out-in`},{default:n(()=>[(i(!0),d(f,null,u(e.teacherClasses,a=>(i(),m(C,{key:a._id,value:a},{append:n(()=>[r(S,{size:`small`,color:`secondary`,loading:e.spinnerMap[a._id]!==void 0,to:`/classrooms/${a._id}`},{default:n(()=>t[5]||(t[5]=[s(` Open `)])),_:2},1032,[`loading`,`to`])]),default:n(()=>[r(x,null,{default:n(()=>[s(l(a.name),1)]),_:2},1024)]),_:2},1032,[`value`]))),128))]),_:1})]),_:1})]),_:1})]),_:1})):h(``,!0),e.studentClasses.length===0&&e.teacherClasses.length===0?(i(),m(E,{key:2,class:`text-h5 text-center`},{default:n(()=>t[6]||(t[6]=[s(` You are not in any classes! Join your class below if someone has given you a joincode. Or else, start your own! `)])),_:1})):h(``,!0)]),_:1}),r(O,{class:`my-4`}),r(D,{class:`pa-4`},{default:n(()=>[r(E,{cols:`12`,sm:`12`,md:`8`,lg:`6`,xl:`6`},{default:n(()=>[r(T,null,{default:n(()=>[r(b,{color:`primary`},{default:n(()=>[r(y,null,{default:n(()=>t[7]||(t[7]=[s(`Join a class`)])),_:1})]),_:1}),r(A,null,{default:n(()=>[r(k,{modelValue:e.joinCode,"onUpdate:modelValue":t[0]||(t[0]=t=>e.joinCode=t),label:`Class Code`,variant:`outlined`},null,8,[`modelValue`]),r(S,{color:`primary`,onClick:e.joinClass},{default:n(()=>t[8]||(t[8]=[s(`Join`)])),_:1},8,[`onClick`])]),_:1})]),_:1})]),_:1})]),_:1}),r(M,{modelValue:e.newClassDialog,"onUpdate:modelValue":t[1]||(t[1]=t=>e.newClassDialog=t),fullscreen:``,transition:`dialog-bottom-transition`,scrim:!1},{activator:n(({props:e})=>[r(S,o({color:`primary`},e),{default:n(()=>t[9]||(t[9]=[s(`Start a new Class`)])),_:2},1040)]),default:n(()=>[r(j,{onClassroomEditingComplete:e.processResponse},null,8,[`onClassroomEditingComplete`])]),_:1},8,[`modelValue`])]),_:1})}var k=C(O,[[`render`,_sfc_render]]);export{k as default};
3
- //# sourceMappingURL=Classrooms-CdN-ogiI.js.map
3
+ //# sourceMappingURL=Classrooms-BWoQ4i1_.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Classrooms-CdN-ogiI.js","names":[],"sources":["../../src/components/Classrooms/CreateClassroom.vue","../../src/components/Classrooms/CreateClassroom.vue","../../src/views/Classrooms.vue","../../src/views/Classrooms.vue"],"sourcesContent":["<template>\n <v-card>\n <v-toolbar color=\"primary\">\n <v-card-title class=\"text-h6 font-weight-regular\">Start a New Class</v-card-title>\n <v-spacer></v-spacer>\n <v-btn icon @click=\"clearFormAndDismiss\">\n <v-icon>mdi-close</v-icon>\n </v-btn>\n </v-toolbar>\n <v-form>\n <v-container>\n <v-row>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-text-field\n v-model=\"name\"\n counter=\"30\"\n :rules=\"nameRules\"\n label=\"Class Name\"\n required\n hint=\"Eg: Smith, Chemistry, Period 3\"\n ></v-text-field>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-checkbox v-model=\"peerAssist\" label=\"Allow peer instruction\"></v-checkbox>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-select\n v-model=\"birthYear\"\n :items=\"birthYears\"\n label=\"Approximate Birth Year of Students\"\n item-title=\"text\"\n item-value=\"value\"\n ></v-select>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-btn :loading=\"updatePending\" color=\"primary\" @click=\"submit\">Create This Class</v-btn>\n </v-col>\n </v-row>\n </v-container>\n </v-form>\n </v-card>\n</template>\n\n<script lang=\"ts\">\nimport moment from 'moment';\nimport Mousetrap from 'mousetrap';\nimport { log } from '@vue-skuilder/common';\nimport { Status, ClassroomConfig, CreateClassroom, ServerRequestType } from '@vue-skuilder/common';\nimport serverRequest from '../../server';\nimport { alertUser } from '@vue-skuilder/common-ui';\nimport { defineComponent } from 'vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n emits: ['ClassroomEditingComplete'],\n\n data() {\n return {\n mousetrap: new Mousetrap(this.$el),\n peerAssist: true,\n name: '',\n birthYear: undefined as number | undefined,\n id: '',\n nameRules: [\n (value: string): string | boolean => {\n const max = 30;\n if (value.length > max) {\n return `Course name must be ${max} characters or less`;\n } else {\n return true;\n }\n },\n ],\n description: '',\n banner: undefined as Blob | undefined,\n thumb: undefined as Blob | undefined,\n updatePending: false,\n birthYears: [] as Array<{\n text: string;\n value: number;\n }>,\n };\n },\n\n created() {\n this.mousetrap.bind('esc', this.clearFormAndDismiss);\n\n const year: number = moment().year();\n\n this.birthYears.push({\n text: `< ${year - 17} (Adult Students)`,\n value: 0,\n });\n\n for (let age = 17; age >= 6; age--) {\n this.birthYears.push({\n text: `${year - age} (Grade ${age - 5})`,\n value: year - age,\n });\n }\n\n this.birthYears.push({\n text: `>${year - 6} (K or younger)`,\n value: year - 5,\n });\n },\n\n methods: {\n async submit() {\n this.updatePending = true;\n const u = await getCurrentUser();\n\n const config: ClassroomConfig = {\n name: this.name,\n teachers: [u.getUsername()],\n students: [],\n birthYear: this.birthYear,\n classMeetingSchedule: '',\n peerAssist: this.peerAssist,\n joinCode: '',\n };\n\n log(`Class Config:\n ${JSON.stringify(config)}`);\n\n const result = await serverRequest<CreateClassroom>({\n data: config,\n type: ServerRequestType.CREATE_CLASSROOM,\n response: null,\n user: u.getUsername(),\n });\n\n if (result.response && result.response.ok) {\n alertUser({\n text: `Class created successfully. Join code: ${result.response.joincode}`,\n status: Status.ok,\n });\n\n u.registerForClassroom(result.response.uuid, 'teacher');\n } else {\n alertUser({\n text: `Failed to create class. Please try again.`,\n status: Status.error,\n });\n }\n\n this.clearFormAndDismiss();\n this.updatePending = false;\n },\n\n clearFormAndDismiss() {\n this.name = '';\n this.description = '';\n\n this.$emit('ClassroomEditingComplete');\n },\n },\n});\n</script>\n","<template>\n <v-card>\n <v-toolbar color=\"primary\">\n <v-card-title class=\"text-h6 font-weight-regular\">Start a New Class</v-card-title>\n <v-spacer></v-spacer>\n <v-btn icon @click=\"clearFormAndDismiss\">\n <v-icon>mdi-close</v-icon>\n </v-btn>\n </v-toolbar>\n <v-form>\n <v-container>\n <v-row>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-text-field\n v-model=\"name\"\n counter=\"30\"\n :rules=\"nameRules\"\n label=\"Class Name\"\n required\n hint=\"Eg: Smith, Chemistry, Period 3\"\n ></v-text-field>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-checkbox v-model=\"peerAssist\" label=\"Allow peer instruction\"></v-checkbox>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-select\n v-model=\"birthYear\"\n :items=\"birthYears\"\n label=\"Approximate Birth Year of Students\"\n item-title=\"text\"\n item-value=\"value\"\n ></v-select>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-btn :loading=\"updatePending\" color=\"primary\" @click=\"submit\">Create This Class</v-btn>\n </v-col>\n </v-row>\n </v-container>\n </v-form>\n </v-card>\n</template>\n\n<script lang=\"ts\">\nimport moment from 'moment';\nimport Mousetrap from 'mousetrap';\nimport { log } from '@vue-skuilder/common';\nimport { Status, ClassroomConfig, CreateClassroom, ServerRequestType } from '@vue-skuilder/common';\nimport serverRequest from '../../server';\nimport { alertUser } from '@vue-skuilder/common-ui';\nimport { defineComponent } from 'vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n emits: ['ClassroomEditingComplete'],\n\n data() {\n return {\n mousetrap: new Mousetrap(this.$el),\n peerAssist: true,\n name: '',\n birthYear: undefined as number | undefined,\n id: '',\n nameRules: [\n (value: string): string | boolean => {\n const max = 30;\n if (value.length > max) {\n return `Course name must be ${max} characters or less`;\n } else {\n return true;\n }\n },\n ],\n description: '',\n banner: undefined as Blob | undefined,\n thumb: undefined as Blob | undefined,\n updatePending: false,\n birthYears: [] as Array<{\n text: string;\n value: number;\n }>,\n };\n },\n\n created() {\n this.mousetrap.bind('esc', this.clearFormAndDismiss);\n\n const year: number = moment().year();\n\n this.birthYears.push({\n text: `< ${year - 17} (Adult Students)`,\n value: 0,\n });\n\n for (let age = 17; age >= 6; age--) {\n this.birthYears.push({\n text: `${year - age} (Grade ${age - 5})`,\n value: year - age,\n });\n }\n\n this.birthYears.push({\n text: `>${year - 6} (K or younger)`,\n value: year - 5,\n });\n },\n\n methods: {\n async submit() {\n this.updatePending = true;\n const u = await getCurrentUser();\n\n const config: ClassroomConfig = {\n name: this.name,\n teachers: [u.getUsername()],\n students: [],\n birthYear: this.birthYear,\n classMeetingSchedule: '',\n peerAssist: this.peerAssist,\n joinCode: '',\n };\n\n log(`Class Config:\n ${JSON.stringify(config)}`);\n\n const result = await serverRequest<CreateClassroom>({\n data: config,\n type: ServerRequestType.CREATE_CLASSROOM,\n response: null,\n user: u.getUsername(),\n });\n\n if (result.response && result.response.ok) {\n alertUser({\n text: `Class created successfully. Join code: ${result.response.joincode}`,\n status: Status.ok,\n });\n\n u.registerForClassroom(result.response.uuid, 'teacher');\n } else {\n alertUser({\n text: `Failed to create class. Please try again.`,\n status: Status.error,\n });\n }\n\n this.clearFormAndDismiss();\n this.updatePending = false;\n },\n\n clearFormAndDismiss() {\n this.name = '';\n this.description = '';\n\n this.$emit('ClassroomEditingComplete');\n },\n },\n});\n</script>\n","<template>\n <v-container fluid>\n <v-row class=\"pa-4\" justify=\"space-around\">\n <!-- Student Classes -->\n <v-col v-if=\"studentClasses.length > 0\" cols=\"12\" sm=\"12\" md=\"4\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>My Classes</v-toolbar-title>\n </v-toolbar>\n\n <v-list>\n <transition-group name=\"component-fade\" mode=\"out-in\">\n <v-list-item v-for=\"classroom in studentClasses\" :key=\"classroom._id\" :value=\"classroom\">\n <v-list-item-title>\n {{ classroom.name }}\n </v-list-item-title>\n\n <template #append>\n <v-btn\n size=\"small\"\n color=\"secondary\"\n :loading=\"spinnerMap[classroom._id] !== undefined\"\n @click=\"leaveClass(classroom._id)\"\n >\n Leave this class\n </v-btn>\n </template>\n </v-list-item>\n </transition-group>\n </v-list>\n </v-card>\n </v-col>\n\n <!-- Teacher Classes -->\n <v-col v-if=\"teacherClasses.length > 0\" cols=\"12\" sm=\"12\" md=\"4\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>Classes I Manage</v-toolbar-title>\n </v-toolbar>\n\n <v-list>\n <transition-group name=\"component-fade\" mode=\"out-in\">\n <v-list-item v-for=\"classroom in teacherClasses\" :key=\"classroom._id\" :value=\"classroom\">\n <v-list-item-title>\n {{ classroom.name }}\n </v-list-item-title>\n\n <template #append>\n <v-btn\n size=\"small\"\n color=\"secondary\"\n :loading=\"spinnerMap[classroom._id] !== undefined\"\n :to=\"`/classrooms/${classroom._id}`\"\n >\n Open\n </v-btn>\n </template>\n </v-list-item>\n </transition-group>\n </v-list>\n </v-card>\n </v-col>\n\n <!-- Empty State Message -->\n <v-col v-if=\"studentClasses.length === 0 && teacherClasses.length === 0\" class=\"text-h5 text-center\">\n You are not in any classes! Join your class below if someone has given you a joincode. Or else, start your own!\n </v-col>\n </v-row>\n\n <v-divider class=\"my-4\"></v-divider>\n\n <!-- Join Class Form -->\n <v-row class=\"pa-4\">\n <v-col cols=\"12\" sm=\"12\" md=\"8\" lg=\"6\" xl=\"6\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>Join a class</v-toolbar-title>\n </v-toolbar>\n <v-card-text>\n <v-text-field v-model=\"joinCode\" label=\"Class Code\" variant=\"outlined\"></v-text-field>\n <v-btn color=\"primary\" @click=\"joinClass\">Join</v-btn>\n </v-card-text>\n </v-card>\n </v-col>\n </v-row>\n\n <!-- New Class Dialog -->\n <v-dialog v-model=\"newClassDialog\" fullscreen transition=\"dialog-bottom-transition\" :scrim=\"false\">\n <template #activator=\"{ props }\">\n <v-btn color=\"primary\" v-bind=\"props\">Start a new Class</v-btn>\n </template>\n <classroom-editor @classroom-editing-complete=\"processResponse\" />\n </v-dialog>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { Status, ServerRequestType, JoinClassroom, LeaveClassroom, DeleteClassroom } from '@vue-skuilder/common';\nimport { getDataLayer, UserDBInterface } from '@vue-skuilder/db';\nimport serverRequest from '@pui/server/index';\nimport { alertUser } from '@vue-skuilder/common-ui';\nimport ClassroomEditor from '@pui/components/Classrooms/CreateClassroom.vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\ninterface CourseReg {\n _id: string;\n name: string;\n}\n\nexport default defineComponent({\n name: 'ClassroomsView',\n\n components: {\n ClassroomEditor,\n },\n\n beforeRouteEnter(to, from, next) {\n // todo ?\n // See https://router.vuejs.org/guide/advanced/data-fetching.html#fetching-before-navigation\n // this.refreshData().then(() => {\n // next();\n // });\n next();\n },\n\n data() {\n return {\n classes: [] as string[],\n joinCode: '',\n studentClasses: [] as CourseReg[],\n teacherClasses: [] as CourseReg[],\n spinnerMap: {} as { [index: string]: boolean },\n newClassDialog: false,\n user: null as UserDBInterface | null,\n };\n },\n\n created() {\n this.refreshData();\n },\n\n methods: {\n async refreshData() {\n this.$data.user = await getCurrentUser();\n const registrations = (await this.user!.getUserClassrooms()).registrations;\n const studentClasses: CourseReg[] = [];\n const teacherClasses: CourseReg[] = [];\n\n registrations.forEach(async (reg) => {\n const cfg = (\n await getDataLayer().getClassroomDB(\n reg.classID,\n reg.registeredAs == 'teacher' || reg.registeredAs == 'student' ? reg.registeredAs : 'student'\n )\n ).getConfig();\n console.log(`Registered class: ${JSON.stringify(cfg)}`);\n const regItem = {\n _id: reg.classID,\n name: cfg.name,\n };\n\n if (reg.registeredAs === 'student') {\n studentClasses.push(regItem);\n } else if (reg.registeredAs === 'teacher') {\n teacherClasses.push(regItem);\n }\n });\n\n this.studentClasses = studentClasses;\n this.teacherClasses = teacherClasses;\n },\n\n async deleteClass(classId: string) {\n const result = await serverRequest<DeleteClassroom>({\n type: ServerRequestType.DELETE_CLASSROOM,\n user: this.user?.getUsername() || '',\n classID: classId,\n response: null,\n });\n if (result.response && result.response.ok) {\n alertUser({\n text: `Class deleted successfully.`,\n status: Status.ok,\n });\n } else {\n alertUser({\n text: `Failed to delete class. Please try again.`,\n status: Status.error,\n });\n }\n },\n\n async leaveClass(classID: string) {\n this.spinnerMap[classID] = true;\n console.log(`Attempting to drop class: ${classID}`);\n\n const result = await serverRequest<LeaveClassroom>({\n type: ServerRequestType.LEAVE_CLASSROOM,\n data: {\n classID: classID,\n },\n user: this.user?.getUsername() || '',\n response: null,\n });\n if (result.response && result.response.ok) {\n if (this.user) {\n await this.user!.dropFromClassroom(classID);\n }\n }\n\n delete this.spinnerMap[classID];\n this.refreshData();\n },\n\n async joinClass() {\n const result = await serverRequest<JoinClassroom>({\n type: ServerRequestType.JOIN_CLASSROOM,\n data: {\n joinCode: this.joinCode,\n registerAs: 'student',\n user: this.user?.getUsername() || '',\n },\n user: this.user?.getUsername() || '',\n response: null,\n });\n\n if (result.response && result.response.ok) {\n console.log(`Adding registration to userDB...`);\n if (this.user) {\n await registerUserForClassroom(this.user.getUsername(), result.response!.id_course, 'student');\n alertUser({\n text: `Successfully joined class: ${result.response.course_name}.`,\n status: Status.ok,\n });\n } else {\n alertUser({\n text: `Failed to join class. [Unknown current user.]`,\n status: Status.error,\n });\n }\n } else {\n if (result.response) {\n alertUser({\n text: result.response.errorText!,\n status: Status.error,\n });\n }\n }\n this.refreshData();\n },\n\n async processResponse() {\n this.newClassDialog = !this.newClassDialog;\n },\n },\n});\n</script>\n","<template>\n <v-container fluid>\n <v-row class=\"pa-4\" justify=\"space-around\">\n <!-- Student Classes -->\n <v-col v-if=\"studentClasses.length > 0\" cols=\"12\" sm=\"12\" md=\"4\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>My Classes</v-toolbar-title>\n </v-toolbar>\n\n <v-list>\n <transition-group name=\"component-fade\" mode=\"out-in\">\n <v-list-item v-for=\"classroom in studentClasses\" :key=\"classroom._id\" :value=\"classroom\">\n <v-list-item-title>\n {{ classroom.name }}\n </v-list-item-title>\n\n <template #append>\n <v-btn\n size=\"small\"\n color=\"secondary\"\n :loading=\"spinnerMap[classroom._id] !== undefined\"\n @click=\"leaveClass(classroom._id)\"\n >\n Leave this class\n </v-btn>\n </template>\n </v-list-item>\n </transition-group>\n </v-list>\n </v-card>\n </v-col>\n\n <!-- Teacher Classes -->\n <v-col v-if=\"teacherClasses.length > 0\" cols=\"12\" sm=\"12\" md=\"4\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>Classes I Manage</v-toolbar-title>\n </v-toolbar>\n\n <v-list>\n <transition-group name=\"component-fade\" mode=\"out-in\">\n <v-list-item v-for=\"classroom in teacherClasses\" :key=\"classroom._id\" :value=\"classroom\">\n <v-list-item-title>\n {{ classroom.name }}\n </v-list-item-title>\n\n <template #append>\n <v-btn\n size=\"small\"\n color=\"secondary\"\n :loading=\"spinnerMap[classroom._id] !== undefined\"\n :to=\"`/classrooms/${classroom._id}`\"\n >\n Open\n </v-btn>\n </template>\n </v-list-item>\n </transition-group>\n </v-list>\n </v-card>\n </v-col>\n\n <!-- Empty State Message -->\n <v-col v-if=\"studentClasses.length === 0 && teacherClasses.length === 0\" class=\"text-h5 text-center\">\n You are not in any classes! Join your class below if someone has given you a joincode. Or else, start your own!\n </v-col>\n </v-row>\n\n <v-divider class=\"my-4\"></v-divider>\n\n <!-- Join Class Form -->\n <v-row class=\"pa-4\">\n <v-col cols=\"12\" sm=\"12\" md=\"8\" lg=\"6\" xl=\"6\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>Join a class</v-toolbar-title>\n </v-toolbar>\n <v-card-text>\n <v-text-field v-model=\"joinCode\" label=\"Class Code\" variant=\"outlined\"></v-text-field>\n <v-btn color=\"primary\" @click=\"joinClass\">Join</v-btn>\n </v-card-text>\n </v-card>\n </v-col>\n </v-row>\n\n <!-- New Class Dialog -->\n <v-dialog v-model=\"newClassDialog\" fullscreen transition=\"dialog-bottom-transition\" :scrim=\"false\">\n <template #activator=\"{ props }\">\n <v-btn color=\"primary\" v-bind=\"props\">Start a new Class</v-btn>\n </template>\n <classroom-editor @classroom-editing-complete=\"processResponse\" />\n </v-dialog>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { Status, ServerRequestType, JoinClassroom, LeaveClassroom, DeleteClassroom } from '@vue-skuilder/common';\nimport { getDataLayer, UserDBInterface } from '@vue-skuilder/db';\nimport serverRequest from '@pui/server/index';\nimport { alertUser } from '@vue-skuilder/common-ui';\nimport ClassroomEditor from '@pui/components/Classrooms/CreateClassroom.vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\ninterface CourseReg {\n _id: string;\n name: string;\n}\n\nexport default defineComponent({\n name: 'ClassroomsView',\n\n components: {\n ClassroomEditor,\n },\n\n beforeRouteEnter(to, from, next) {\n // todo ?\n // See https://router.vuejs.org/guide/advanced/data-fetching.html#fetching-before-navigation\n // this.refreshData().then(() => {\n // next();\n // });\n next();\n },\n\n data() {\n return {\n classes: [] as string[],\n joinCode: '',\n studentClasses: [] as CourseReg[],\n teacherClasses: [] as CourseReg[],\n spinnerMap: {} as { [index: string]: boolean },\n newClassDialog: false,\n user: null as UserDBInterface | null,\n };\n },\n\n created() {\n this.refreshData();\n },\n\n methods: {\n async refreshData() {\n this.$data.user = await getCurrentUser();\n const registrations = (await this.user!.getUserClassrooms()).registrations;\n const studentClasses: CourseReg[] = [];\n const teacherClasses: CourseReg[] = [];\n\n registrations.forEach(async (reg) => {\n const cfg = (\n await getDataLayer().getClassroomDB(\n reg.classID,\n reg.registeredAs == 'teacher' || reg.registeredAs == 'student' ? reg.registeredAs : 'student'\n )\n ).getConfig();\n console.log(`Registered class: ${JSON.stringify(cfg)}`);\n const regItem = {\n _id: reg.classID,\n name: cfg.name,\n };\n\n if (reg.registeredAs === 'student') {\n studentClasses.push(regItem);\n } else if (reg.registeredAs === 'teacher') {\n teacherClasses.push(regItem);\n }\n });\n\n this.studentClasses = studentClasses;\n this.teacherClasses = teacherClasses;\n },\n\n async deleteClass(classId: string) {\n const result = await serverRequest<DeleteClassroom>({\n type: ServerRequestType.DELETE_CLASSROOM,\n user: this.user?.getUsername() || '',\n classID: classId,\n response: null,\n });\n if (result.response && result.response.ok) {\n alertUser({\n text: `Class deleted successfully.`,\n status: Status.ok,\n });\n } else {\n alertUser({\n text: `Failed to delete class. Please try again.`,\n status: Status.error,\n });\n }\n },\n\n async leaveClass(classID: string) {\n this.spinnerMap[classID] = true;\n console.log(`Attempting to drop class: ${classID}`);\n\n const result = await serverRequest<LeaveClassroom>({\n type: ServerRequestType.LEAVE_CLASSROOM,\n data: {\n classID: classID,\n },\n user: this.user?.getUsername() || '',\n response: null,\n });\n if (result.response && result.response.ok) {\n if (this.user) {\n await this.user!.dropFromClassroom(classID);\n }\n }\n\n delete this.spinnerMap[classID];\n this.refreshData();\n },\n\n async joinClass() {\n const result = await serverRequest<JoinClassroom>({\n type: ServerRequestType.JOIN_CLASSROOM,\n data: {\n joinCode: this.joinCode,\n registerAs: 'student',\n user: this.user?.getUsername() || '',\n },\n user: this.user?.getUsername() || '',\n response: null,\n });\n\n if (result.response && result.response.ok) {\n console.log(`Adding registration to userDB...`);\n if (this.user) {\n await registerUserForClassroom(this.user.getUsername(), result.response!.id_course, 'student');\n alertUser({\n text: `Successfully joined class: ${result.response.course_name}.`,\n status: Status.ok,\n });\n } else {\n alertUser({\n text: `Failed to join class. [Unknown current user.]`,\n status: Status.error,\n });\n }\n } else {\n if (result.response) {\n alertUser({\n text: result.response.errorText!,\n status: Status.error,\n });\n }\n }\n this.refreshData();\n },\n\n async processResponse() {\n this.newClassDialog = !this.newClassDialog;\n },\n },\n});\n</script>\n"],"mappings":"8eCqDA,EAAe,EAAgB,CAC7B,MAAO,CAAC,2BAA2B,CAEnC,MAAO,CACL,MAAO,CACL,UAAW,IAAI,EAAA,QAAU,KAAK,IAAI,CAClC,WAAY,GACZ,KAAM,GACN,UAAW,IAAA,GACX,GAAI,GACJ,UAAW,CACR,GAEK,EAAM,OAAS,GACV,4CAEA,GAGZ,CACD,YAAa,GACb,OAAQ,IAAA,GACR,MAAO,IAAA,GACP,cAAe,GACf,WAAY,EAAC,CAId,EAGH,SAAU,CACR,KAAK,UAAU,KAAK,MAAO,KAAK,oBAAoB,CAEpD,IAAM,EAAe,GAAQ,CAAC,MAAM,CAEpC,KAAK,WAAW,KAAK,CACnB,KAAM,KAAK,EAAO,GAAE,mBACpB,MAAO,EACR,CAAC,CAEF,IAAK,IAAI,EAAM,GAAI,GAAO,EAAG,IAC3B,KAAK,WAAW,KAAK,CACnB,KAAM,GAAG,EAAO,EAAG,UAAW,EAAM,EAAE,GACtC,MAAO,EAAO,EACf,CAAC,CAGJ,KAAK,WAAW,KAAK,CACnB,KAAM,IAAI,EAAO,EAAC,iBAClB,MAAO,EAAO,EACf,CAAC,EAGJ,QAAS,CACP,MAAM,QAAS,CACb,KAAK,cAAgB,GACrB,IAAM,EAAI,MAAM,GAAgB,CAE1B,EAA0B,CAC9B,KAAM,KAAK,KACX,SAAU,CAAC,EAAE,aAAa,CAAC,CAC3B,SAAU,EAAE,CACZ,UAAW,KAAK,UAChB,qBAAsB,GACtB,WAAY,KAAK,WACjB,SAAU,GACX,CAED,EAAI;QACF,KAAK,UAAU,EAAO,GAAG,CAE3B,IAAM,EAAS,MAAM,EAA+B,CAClD,KAAM,EACN,KAAM,EAAkB,iBACxB,SAAU,KACV,KAAM,EAAE,aAAa,CACtB,CAAC,CAEE,EAAO,UAAY,EAAO,SAAS,IACrC,EAAU,CACR,KAAM,0CAA0C,EAAO,SAAS,WAChE,OAAQ,EAAO,GAChB,CAAC,CAEF,EAAE,qBAAqB,EAAO,SAAS,KAAM,UAAU,EAEvD,EAAU,CACR,KAAM,4CACN,OAAQ,EAAO,MAChB,CAAC,CAGJ,KAAK,qBAAqB,CAC1B,KAAK,cAAgB,IAGvB,qBAAsB,CACpB,KAAK,KAAO,GACZ,KAAK,YAAc,GAEnB,KAAK,MAAM,2BAA2B,EAEzC,CACF,CAAC,mQA5JA,EAuCS,EAAA,KAAA,CAxCX,QAAA,MAQgB,CANZ,EAMY,EAAA,CAND,MAAM,UAAS,CAAA,CAF9B,QAAA,MAGwF,CAAlF,EAAkF,EAAA,CAApE,MAAM,8BAA6B,CAAA,CAHvD,QAAA,MAGyE,EAAA,KAAA,EAAA,GAAA,CAHzE,EAGwD,oBAAiB,CAAA,EAAA,CAHzE,EAAA,IAIM,EAAqB,EAAA,CACrB,EAEQ,EAAA,CAFD,KAAA,GAAM,QAAO,EAAA,sBAL1B,QAAA,MAMkC,CAA1B,EAA0B,EAAA,KAAA,CANlC,QAAA,MAMyB,EAAA,KAAA,EAAA,GAAA,CANzB,EAMgB,YAAS,CAAA,EAAA,CANzB,EAAA,MAAA,EAAA,oBAAA,EAAA,IASI,EA8BS,EAAA,KAAA,CAvCb,QAAA,MAsCoB,CA5Bd,EA4Bc,EAAA,KAAA,CAtCpB,QAAA,MAqCgB,CA1BR,EA0BQ,EAAA,KAAA,CArChB,QAAA,MAqBkB,CATR,EASQ,EAAA,CATD,KAAK,KAAK,GAAG,IAAI,GAAG,MAZrC,QAAA,MAoB4B,CAPhB,EAOgB,EAAA,CApB5B,WAcuB,EAAA,KAdvB,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EAcuB,KAAI,GACb,QAAQ,KACP,MAAO,EAAA,UACR,MAAM,aACN,SAAA,GACA,KAAK,mEAnBnB,EAAA,IAsBU,EAEQ,EAAA,CAFD,KAAK,KAAK,GAAG,IAAI,GAAG,MAtBrC,QAAA,MAuByF,CAA7E,EAA6E,EAAA,CAvBzF,WAuBiC,EAAA,WAvBjC,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EAuBiC,WAAU,GAAE,MAAM,mDAvBnD,EAAA,IAyBU,EAQQ,EAAA,CARD,KAAK,KAAK,GAAG,IAAI,GAAG,MAzBrC,QAAA,MAgCwB,CANZ,EAMY,EAAA,CAhCxB,WA2BuB,EAAA,UA3BvB,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EA2BuB,UAAS,GACjB,MAAO,EAAA,WACR,MAAM,qCACN,aAAW,OACX,aAAW,0CA/BzB,EAAA,IAkCU,EAEQ,EAAA,CAFD,KAAK,KAAK,GAAG,IAAI,GAAG,MAlCrC,QAAA,MAmCqG,CAAzF,EAAyF,EAAA,CAAjF,QAAS,EAAA,cAAe,MAAM,UAAW,QAAO,EAAA,SAnCpE,QAAA,MAmC6F,EAAA,KAAA,EAAA,GAAA,CAnC7F,EAmC4E,oBAAiB,CAAA,EAAA,CAnC7F,EAAA,8BAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,mCE8GA,IAAA,EAAe,EAAgB,CAC7B,KAAM,iBAEN,WAAY,CACV,gDACD,CAED,iBAAiB,EAAI,EAAM,EAAM,CAM/B,GAAM,EAGR,MAAO,CACL,MAAO,CACL,QAAS,EAAC,CACV,SAAU,GACV,eAAgB,EAAC,CACjB,eAAgB,EAAC,CACjB,WAAY,EAAC,CACb,eAAgB,GAChB,KAAM,KACP,EAGH,SAAU,CACR,KAAK,aAAa,EAGpB,QAAS,CACP,MAAM,aAAc,CAClB,KAAK,MAAM,KAAO,MAAM,GAAgB,CACxC,IAAM,GAAiB,MAAM,KAAK,KAAM,mBAAmB,EAAE,cACvD,EAA8B,EAAE,CAChC,EAA8B,EAAE,CAEtC,EAAc,QAAQ,KAAO,IAAQ,CACnC,IAAM,GACJ,MAAM,GAAc,CAAC,eACnB,EAAI,QACJ,EAAI,cAAgB,WAAa,EAAI,cAAgB,UAAY,EAAI,aAAe,UACtF,EACA,WAAW,CACb,QAAQ,IAAI,qBAAqB,KAAK,UAAU,EAAI,GAAG,CACvD,IAAM,EAAU,CACd,IAAK,EAAI,QACT,KAAM,EAAI,KACX,CAEG,EAAI,eAAiB,UACvB,EAAe,KAAK,EAAQ,CACnB,EAAI,eAAiB,WAC9B,EAAe,KAAK,EAAQ,EAE9B,CAEF,KAAK,eAAiB,EACtB,KAAK,eAAiB,GAGxB,MAAM,YAAY,EAAiB,CACjC,IAAM,EAAS,MAAM,EAA+B,CAClD,KAAM,EAAkB,iBACxB,KAAM,KAAK,MAAM,aAAY,EAAK,GAClC,QAAS,EACT,SAAU,KACX,CAAC,CACE,EAAO,UAAY,EAAO,SAAS,GACrC,EAAU,CACR,KAAM,8BACN,OAAQ,EAAO,GAChB,CAAC,CAEF,EAAU,CACR,KAAM,4CACN,OAAQ,EAAO,MAChB,CAAC,EAIN,MAAM,WAAW,EAAiB,CAChC,KAAK,WAAW,GAAW,GAC3B,QAAQ,IAAI,6BAA6B,IAAU,CAEnD,IAAM,EAAS,MAAM,EAA8B,CACjD,KAAM,EAAkB,gBACxB,KAAM,CACK,UACV,CACD,KAAM,KAAK,MAAM,aAAY,EAAK,GAClC,SAAU,KACX,CAAC,CACE,EAAO,UAAY,EAAO,SAAS,IACjC,KAAK,MACP,MAAM,KAAK,KAAM,kBAAkB,EAAQ,CAI/C,OAAO,KAAK,WAAW,GACvB,KAAK,aAAa,EAGpB,MAAM,WAAY,CAChB,IAAM,EAAS,MAAM,EAA6B,CAChD,KAAM,EAAkB,eACxB,KAAM,CACJ,SAAU,KAAK,SACf,WAAY,UACZ,KAAM,KAAK,MAAM,aAAY,EAAK,GACnC,CACD,KAAM,KAAK,MAAM,aAAY,EAAK,GAClC,SAAU,KACX,CAAC,CAEE,EAAO,UAAY,EAAO,SAAS,IACrC,QAAQ,IAAI,mCAAmC,CAC3C,KAAK,MACP,MAAM,yBAAyB,KAAK,KAAK,aAAa,CAAE,EAAO,SAAU,UAAW,UAAU,CAC9F,EAAU,CACR,KAAM,8BAA8B,EAAO,SAAS,YAAY,GAChE,OAAQ,EAAO,GAChB,CAAC,EAEF,EAAU,CACR,KAAM,gDACN,OAAQ,EAAO,MAChB,CAAC,EAGA,EAAO,UACT,EAAU,CACR,KAAM,EAAO,SAAS,UACtB,OAAQ,EAAO,MAChB,CAAC,CAGN,KAAK,aAAa,EAGpB,MAAM,iBAAkB,CACtB,KAAK,eAAiB,CAAC,KAAK,gBAE/B,CACF,CAAC,4TA/PA,EA4Fc,EAAA,CA5FD,MAAA,GAAK,CAAA,CADpB,QAAA,MAmEY,CAjER,EAiEQ,EAAA,CAjED,MAAM,OAAO,QAAQ,iBAFhC,QAAA,MA+Bc,CA3BK,EAAA,eAAe,OAAM,GAAA,GAAA,CAAlC,EA2BQ,EAAA,CA/Bd,IAAA,EAI8C,KAAK,KAAK,GAAG,KAAK,GAAG,MAJnE,QAAA,MA8BiB,CAzBT,EAyBS,EAAA,KAAA,CA9BjB,QAAA,MAQsB,CAFZ,EAEY,EAAA,CAFD,MAAM,UAAS,CAAA,CANpC,QAAA,MAOyD,CAA7C,EAA6C,EAAA,KAAA,CAPzD,QAAA,MAOuC,EAAA,KAAA,EAAA,GAAA,CAPvC,EAO6B,aAAU,CAAA,EAAA,CAPvC,EAAA,MAAA,EAAA,IAUU,EAmBS,EAAA,KAAA,CA7BnB,QAAA,MA4B+B,CAjBnB,EAiBmB,EAAA,CAjBD,KAAK,iBAAiB,KAAK,WAXzD,QAAA,MAY8D,EAAA,EAAA,GAAA,CAAhD,EAec,EAAA,KA3B5B,EAY+C,EAAA,eAAb,QAApB,EAec,EAAA,CAfoC,IAAK,EAAU,IAAM,MAAO,IAKjE,OAAM,MAQP,CAPR,EAOQ,EAAA,CANN,KAAK,QACL,MAAM,YACL,QAAS,EAAA,WAAW,EAAU,OAAS,IAAA,GACvC,QAAK,GAAE,EAAA,WAAW,EAAU,IAAG,GAtBpD,QAAA,MAyBkB,EAAA,KAAA,EAAA,GAAA,CAzBlB,EAuBmB,qBAED,CAAA,EAAA,CAzBlB,EAAA,iCAAA,QAAA,MAeoC,CAFpB,EAEoB,EAAA,KAAA,CAfpC,QAAA,MAcsC,CAdtC,EAAA,EAcqB,EAAU,KAAI,CAAA,EAAA,CAAA,CAAA,CAdnC,EAAA,WAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,GAAA,CAkCmB,EAAA,eAAe,OAAM,GAAA,GAAA,CAAlC,EA2BQ,EAAA,CA7Dd,IAAA,EAkC8C,KAAK,KAAK,GAAG,KAAK,GAAG,MAlCnE,QAAA,MA4DiB,CAzBT,EAyBS,EAAA,KAAA,CA5DjB,QAAA,MAsCsB,CAFZ,EAEY,EAAA,CAFD,MAAM,UAAS,CAAA,CApCpC,QAAA,MAqC+D,CAAnD,EAAmD,EAAA,KAAA,CArC/D,QAAA,MAqC6C,EAAA,KAAA,EAAA,GAAA,CArC7C,EAqC6B,mBAAgB,CAAA,EAAA,CArC7C,EAAA,MAAA,EAAA,IAwCU,EAmBS,EAAA,KAAA,CA3DnB,QAAA,MA0D+B,CAjBnB,EAiBmB,EAAA,CAjBD,KAAK,iBAAiB,KAAK,WAzCzD,QAAA,MA0C8D,EAAA,EAAA,GAAA,CAAhD,EAec,EAAA,KAzD5B,EA0C+C,EAAA,eAAb,QAApB,EAec,EAAA,CAfoC,IAAK,EAAU,IAAM,MAAO,IAKjE,OAAM,MAQP,CAPR,EAOQ,EAAA,CANN,KAAK,QACL,MAAM,YACL,QAAS,EAAA,WAAW,EAAU,OAAS,IAAA,GACvC,GAAE,eAAiB,EAAU,QApDlD,QAAA,MAuDkB,EAAA,KAAA,EAAA,GAAA,CAvDlB,EAqDmB,SAED,CAAA,EAAA,CAvDlB,EAAA,4BAAA,QAAA,MA6CoC,CAFpB,EAEoB,EAAA,KAAA,CA7CpC,QAAA,MA4CsC,CA5CtC,EAAA,EA4CqB,EAAU,KAAI,CAAA,EAAA,CAAA,CAAA,CA5CnC,EAAA,WAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,GAAA,CAgEmB,EAAA,eAAe,SAAM,GAAU,EAAA,eAAe,SAAM,GAAA,GAAA,CAAjE,EAEQ,EAAA,CAlEd,IAAA,EAgE+E,MAAM,wBAhErF,QAAA,MAkEM,EAAA,KAAA,EAAA,GAAA,CAlEN,EAgE2G,oHAErG,CAAA,EAAA,CAlEN,EAAA,KAAA,EAAA,GAAA,GAAA,GAAA,EAAA,IAqEI,EAAoC,EAAA,CAAzB,MAAM,OAAM,CAAA,CAGvB,EAYQ,EAAA,CAZD,MAAM,OAAM,CAAA,CAxEvB,QAAA,MAmFc,CAVR,EAUQ,EAAA,CAVD,KAAK,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,MAzEhD,QAAA,MAkFiB,CART,EAQS,EAAA,KAAA,CAlFjB,QAAA,MA6EsB,CAFZ,EAEY,EAAA,CAFD,MAAM,UAAS,CAAA,CA3EpC,QAAA,MA4E2D,CAA/C,EAA+C,EAAA,KAAA,CA5E3D,QAAA,MA4EyC,EAAA,KAAA,EAAA,GAAA,CA5EzC,EA4E6B,eAAY,CAAA,EAAA,CA5EzC,EAAA,MAAA,EAAA,IA8EU,EAGc,EAAA,KAAA,CAjFxB,QAAA,MA+EkG,CAAtF,EAAsF,EAAA,CA/ElG,WA+EmC,EAAA,SA/EnC,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EA+EmC,SAAQ,GAAE,MAAM,aAAa,QAAQ,mCAC5D,EAAsD,EAAA,CAA/C,MAAM,UAAW,QAAO,EAAA,YAhF3C,QAAA,MAgF0D,EAAA,KAAA,EAAA,GAAA,CAhF1D,EAgFsD,OAAI,CAAA,EAAA,CAhF1D,EAAA,oBAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,IAuFI,EAKW,EAAA,CA5Ff,WAuFuB,EAAA,eAvFvB,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EAuFuB,eAAc,GAAE,WAAA,GAAW,WAAW,2BAA4B,MAAO,KAC/E,UAAS,GAC6C,CADzC,WAAK,CAC3B,EAA+D,EAA/D,EAA+D,CAAxD,MAAM,UAAS,CAAS,EAAK,CAAA,CAzF5C,QAAA,MAyF+D,EAAA,KAAA,EAAA,GAAA,CAzF/D,EAyF8C,oBAAiB,CAAA,EAAA,CAzF/D,EAAA,WAAA,QAAA,MA2FwE,CAAlE,EAAkE,EAAA,CAA/C,2BAA4B,EAAA,gBAAe,CAAA,KAAA,EAAA,CAAA,6BAAA,CAAA,CAAA,CAAA,CA3FpE,EAAA,uBAAA,EAAA"}
1
+ {"version":3,"file":"Classrooms-BWoQ4i1_.js","names":[],"sources":["../../src/components/Classrooms/CreateClassroom.vue","../../src/components/Classrooms/CreateClassroom.vue","../../src/views/Classrooms.vue","../../src/views/Classrooms.vue"],"sourcesContent":["<template>\n <v-card>\n <v-toolbar color=\"primary\">\n <v-card-title class=\"text-h6 font-weight-regular\">Start a New Class</v-card-title>\n <v-spacer></v-spacer>\n <v-btn icon @click=\"clearFormAndDismiss\">\n <v-icon>mdi-close</v-icon>\n </v-btn>\n </v-toolbar>\n <v-form>\n <v-container>\n <v-row>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-text-field\n v-model=\"name\"\n counter=\"30\"\n :rules=\"nameRules\"\n label=\"Class Name\"\n required\n hint=\"Eg: Smith, Chemistry, Period 3\"\n ></v-text-field>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-checkbox v-model=\"peerAssist\" label=\"Allow peer instruction\"></v-checkbox>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-select\n v-model=\"birthYear\"\n :items=\"birthYears\"\n label=\"Approximate Birth Year of Students\"\n item-title=\"text\"\n item-value=\"value\"\n ></v-select>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-btn :loading=\"updatePending\" color=\"primary\" @click=\"submit\">Create This Class</v-btn>\n </v-col>\n </v-row>\n </v-container>\n </v-form>\n </v-card>\n</template>\n\n<script lang=\"ts\">\nimport moment from 'moment';\nimport Mousetrap from 'mousetrap';\nimport { log } from '@vue-skuilder/common';\nimport { Status, ClassroomConfig, CreateClassroom, ServerRequestType } from '@vue-skuilder/common';\nimport serverRequest from '../../server';\nimport { alertUser } from '@vue-skuilder/common-ui';\nimport { defineComponent } from 'vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n emits: ['ClassroomEditingComplete'],\n\n data() {\n return {\n mousetrap: new Mousetrap(this.$el),\n peerAssist: true,\n name: '',\n birthYear: undefined as number | undefined,\n id: '',\n nameRules: [\n (value: string): string | boolean => {\n const max = 30;\n if (value.length > max) {\n return `Course name must be ${max} characters or less`;\n } else {\n return true;\n }\n },\n ],\n description: '',\n banner: undefined as Blob | undefined,\n thumb: undefined as Blob | undefined,\n updatePending: false,\n birthYears: [] as Array<{\n text: string;\n value: number;\n }>,\n };\n },\n\n created() {\n this.mousetrap.bind('esc', this.clearFormAndDismiss);\n\n const year: number = moment().year();\n\n this.birthYears.push({\n text: `< ${year - 17} (Adult Students)`,\n value: 0,\n });\n\n for (let age = 17; age >= 6; age--) {\n this.birthYears.push({\n text: `${year - age} (Grade ${age - 5})`,\n value: year - age,\n });\n }\n\n this.birthYears.push({\n text: `>${year - 6} (K or younger)`,\n value: year - 5,\n });\n },\n\n methods: {\n async submit() {\n this.updatePending = true;\n const u = await getCurrentUser();\n\n const config: ClassroomConfig = {\n name: this.name,\n teachers: [u.getUsername()],\n students: [],\n birthYear: this.birthYear,\n classMeetingSchedule: '',\n peerAssist: this.peerAssist,\n joinCode: '',\n };\n\n log(`Class Config:\n ${JSON.stringify(config)}`);\n\n const result = await serverRequest<CreateClassroom>({\n data: config,\n type: ServerRequestType.CREATE_CLASSROOM,\n response: null,\n user: u.getUsername(),\n });\n\n if (result.response && result.response.ok) {\n alertUser({\n text: `Class created successfully. Join code: ${result.response.joincode}`,\n status: Status.ok,\n });\n\n u.registerForClassroom(result.response.uuid, 'teacher');\n } else {\n alertUser({\n text: `Failed to create class. Please try again.`,\n status: Status.error,\n });\n }\n\n this.clearFormAndDismiss();\n this.updatePending = false;\n },\n\n clearFormAndDismiss() {\n this.name = '';\n this.description = '';\n\n this.$emit('ClassroomEditingComplete');\n },\n },\n});\n</script>\n","<template>\n <v-card>\n <v-toolbar color=\"primary\">\n <v-card-title class=\"text-h6 font-weight-regular\">Start a New Class</v-card-title>\n <v-spacer></v-spacer>\n <v-btn icon @click=\"clearFormAndDismiss\">\n <v-icon>mdi-close</v-icon>\n </v-btn>\n </v-toolbar>\n <v-form>\n <v-container>\n <v-row>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-text-field\n v-model=\"name\"\n counter=\"30\"\n :rules=\"nameRules\"\n label=\"Class Name\"\n required\n hint=\"Eg: Smith, Chemistry, Period 3\"\n ></v-text-field>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-checkbox v-model=\"peerAssist\" label=\"Allow peer instruction\"></v-checkbox>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-select\n v-model=\"birthYear\"\n :items=\"birthYears\"\n label=\"Approximate Birth Year of Students\"\n item-title=\"text\"\n item-value=\"value\"\n ></v-select>\n </v-col>\n <v-col cols=\"12\" sm=\"6\" md=\"4\">\n <v-btn :loading=\"updatePending\" color=\"primary\" @click=\"submit\">Create This Class</v-btn>\n </v-col>\n </v-row>\n </v-container>\n </v-form>\n </v-card>\n</template>\n\n<script lang=\"ts\">\nimport moment from 'moment';\nimport Mousetrap from 'mousetrap';\nimport { log } from '@vue-skuilder/common';\nimport { Status, ClassroomConfig, CreateClassroom, ServerRequestType } from '@vue-skuilder/common';\nimport serverRequest from '../../server';\nimport { alertUser } from '@vue-skuilder/common-ui';\nimport { defineComponent } from 'vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n emits: ['ClassroomEditingComplete'],\n\n data() {\n return {\n mousetrap: new Mousetrap(this.$el),\n peerAssist: true,\n name: '',\n birthYear: undefined as number | undefined,\n id: '',\n nameRules: [\n (value: string): string | boolean => {\n const max = 30;\n if (value.length > max) {\n return `Course name must be ${max} characters or less`;\n } else {\n return true;\n }\n },\n ],\n description: '',\n banner: undefined as Blob | undefined,\n thumb: undefined as Blob | undefined,\n updatePending: false,\n birthYears: [] as Array<{\n text: string;\n value: number;\n }>,\n };\n },\n\n created() {\n this.mousetrap.bind('esc', this.clearFormAndDismiss);\n\n const year: number = moment().year();\n\n this.birthYears.push({\n text: `< ${year - 17} (Adult Students)`,\n value: 0,\n });\n\n for (let age = 17; age >= 6; age--) {\n this.birthYears.push({\n text: `${year - age} (Grade ${age - 5})`,\n value: year - age,\n });\n }\n\n this.birthYears.push({\n text: `>${year - 6} (K or younger)`,\n value: year - 5,\n });\n },\n\n methods: {\n async submit() {\n this.updatePending = true;\n const u = await getCurrentUser();\n\n const config: ClassroomConfig = {\n name: this.name,\n teachers: [u.getUsername()],\n students: [],\n birthYear: this.birthYear,\n classMeetingSchedule: '',\n peerAssist: this.peerAssist,\n joinCode: '',\n };\n\n log(`Class Config:\n ${JSON.stringify(config)}`);\n\n const result = await serverRequest<CreateClassroom>({\n data: config,\n type: ServerRequestType.CREATE_CLASSROOM,\n response: null,\n user: u.getUsername(),\n });\n\n if (result.response && result.response.ok) {\n alertUser({\n text: `Class created successfully. Join code: ${result.response.joincode}`,\n status: Status.ok,\n });\n\n u.registerForClassroom(result.response.uuid, 'teacher');\n } else {\n alertUser({\n text: `Failed to create class. Please try again.`,\n status: Status.error,\n });\n }\n\n this.clearFormAndDismiss();\n this.updatePending = false;\n },\n\n clearFormAndDismiss() {\n this.name = '';\n this.description = '';\n\n this.$emit('ClassroomEditingComplete');\n },\n },\n});\n</script>\n","<template>\n <v-container fluid>\n <v-row class=\"pa-4\" justify=\"space-around\">\n <!-- Student Classes -->\n <v-col v-if=\"studentClasses.length > 0\" cols=\"12\" sm=\"12\" md=\"4\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>My Classes</v-toolbar-title>\n </v-toolbar>\n\n <v-list>\n <transition-group name=\"component-fade\" mode=\"out-in\">\n <v-list-item v-for=\"classroom in studentClasses\" :key=\"classroom._id\" :value=\"classroom\">\n <v-list-item-title>\n {{ classroom.name }}\n </v-list-item-title>\n\n <template #append>\n <v-btn\n size=\"small\"\n color=\"secondary\"\n :loading=\"spinnerMap[classroom._id] !== undefined\"\n @click=\"leaveClass(classroom._id)\"\n >\n Leave this class\n </v-btn>\n </template>\n </v-list-item>\n </transition-group>\n </v-list>\n </v-card>\n </v-col>\n\n <!-- Teacher Classes -->\n <v-col v-if=\"teacherClasses.length > 0\" cols=\"12\" sm=\"12\" md=\"4\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>Classes I Manage</v-toolbar-title>\n </v-toolbar>\n\n <v-list>\n <transition-group name=\"component-fade\" mode=\"out-in\">\n <v-list-item v-for=\"classroom in teacherClasses\" :key=\"classroom._id\" :value=\"classroom\">\n <v-list-item-title>\n {{ classroom.name }}\n </v-list-item-title>\n\n <template #append>\n <v-btn\n size=\"small\"\n color=\"secondary\"\n :loading=\"spinnerMap[classroom._id] !== undefined\"\n :to=\"`/classrooms/${classroom._id}`\"\n >\n Open\n </v-btn>\n </template>\n </v-list-item>\n </transition-group>\n </v-list>\n </v-card>\n </v-col>\n\n <!-- Empty State Message -->\n <v-col v-if=\"studentClasses.length === 0 && teacherClasses.length === 0\" class=\"text-h5 text-center\">\n You are not in any classes! Join your class below if someone has given you a joincode. Or else, start your own!\n </v-col>\n </v-row>\n\n <v-divider class=\"my-4\"></v-divider>\n\n <!-- Join Class Form -->\n <v-row class=\"pa-4\">\n <v-col cols=\"12\" sm=\"12\" md=\"8\" lg=\"6\" xl=\"6\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>Join a class</v-toolbar-title>\n </v-toolbar>\n <v-card-text>\n <v-text-field v-model=\"joinCode\" label=\"Class Code\" variant=\"outlined\"></v-text-field>\n <v-btn color=\"primary\" @click=\"joinClass\">Join</v-btn>\n </v-card-text>\n </v-card>\n </v-col>\n </v-row>\n\n <!-- New Class Dialog -->\n <v-dialog v-model=\"newClassDialog\" fullscreen transition=\"dialog-bottom-transition\" :scrim=\"false\">\n <template #activator=\"{ props }\">\n <v-btn color=\"primary\" v-bind=\"props\">Start a new Class</v-btn>\n </template>\n <classroom-editor @classroom-editing-complete=\"processResponse\" />\n </v-dialog>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { Status, ServerRequestType, JoinClassroom, LeaveClassroom, DeleteClassroom } from '@vue-skuilder/common';\nimport { getDataLayer, UserDBInterface } from '@vue-skuilder/db';\nimport serverRequest from '@pui/server/index';\nimport { alertUser } from '@vue-skuilder/common-ui';\nimport ClassroomEditor from '@pui/components/Classrooms/CreateClassroom.vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\ninterface CourseReg {\n _id: string;\n name: string;\n}\n\nexport default defineComponent({\n name: 'ClassroomsView',\n\n components: {\n ClassroomEditor,\n },\n\n beforeRouteEnter(to, from, next) {\n // todo ?\n // See https://router.vuejs.org/guide/advanced/data-fetching.html#fetching-before-navigation\n // this.refreshData().then(() => {\n // next();\n // });\n next();\n },\n\n data() {\n return {\n classes: [] as string[],\n joinCode: '',\n studentClasses: [] as CourseReg[],\n teacherClasses: [] as CourseReg[],\n spinnerMap: {} as { [index: string]: boolean },\n newClassDialog: false,\n user: null as UserDBInterface | null,\n };\n },\n\n created() {\n this.refreshData();\n },\n\n methods: {\n async refreshData() {\n this.$data.user = await getCurrentUser();\n const registrations = (await this.user!.getUserClassrooms()).registrations;\n const studentClasses: CourseReg[] = [];\n const teacherClasses: CourseReg[] = [];\n\n registrations.forEach(async (reg) => {\n const cfg = (\n await getDataLayer().getClassroomDB(\n reg.classID,\n reg.registeredAs == 'teacher' || reg.registeredAs == 'student' ? reg.registeredAs : 'student'\n )\n ).getConfig();\n console.log(`Registered class: ${JSON.stringify(cfg)}`);\n const regItem = {\n _id: reg.classID,\n name: cfg.name,\n };\n\n if (reg.registeredAs === 'student') {\n studentClasses.push(regItem);\n } else if (reg.registeredAs === 'teacher') {\n teacherClasses.push(regItem);\n }\n });\n\n this.studentClasses = studentClasses;\n this.teacherClasses = teacherClasses;\n },\n\n async deleteClass(classId: string) {\n const result = await serverRequest<DeleteClassroom>({\n type: ServerRequestType.DELETE_CLASSROOM,\n user: this.user?.getUsername() || '',\n classID: classId,\n response: null,\n });\n if (result.response && result.response.ok) {\n alertUser({\n text: `Class deleted successfully.`,\n status: Status.ok,\n });\n } else {\n alertUser({\n text: `Failed to delete class. Please try again.`,\n status: Status.error,\n });\n }\n },\n\n async leaveClass(classID: string) {\n this.spinnerMap[classID] = true;\n console.log(`Attempting to drop class: ${classID}`);\n\n const result = await serverRequest<LeaveClassroom>({\n type: ServerRequestType.LEAVE_CLASSROOM,\n data: {\n classID: classID,\n },\n user: this.user?.getUsername() || '',\n response: null,\n });\n if (result.response && result.response.ok) {\n if (this.user) {\n await this.user!.dropFromClassroom(classID);\n }\n }\n\n delete this.spinnerMap[classID];\n this.refreshData();\n },\n\n async joinClass() {\n const result = await serverRequest<JoinClassroom>({\n type: ServerRequestType.JOIN_CLASSROOM,\n data: {\n joinCode: this.joinCode,\n registerAs: 'student',\n user: this.user?.getUsername() || '',\n },\n user: this.user?.getUsername() || '',\n response: null,\n });\n\n if (result.response && result.response.ok) {\n console.log(`Adding registration to userDB...`);\n if (this.user) {\n await registerUserForClassroom(this.user.getUsername(), result.response!.id_course, 'student');\n alertUser({\n text: `Successfully joined class: ${result.response.course_name}.`,\n status: Status.ok,\n });\n } else {\n alertUser({\n text: `Failed to join class. [Unknown current user.]`,\n status: Status.error,\n });\n }\n } else {\n if (result.response) {\n alertUser({\n text: result.response.errorText!,\n status: Status.error,\n });\n }\n }\n this.refreshData();\n },\n\n async processResponse() {\n this.newClassDialog = !this.newClassDialog;\n },\n },\n});\n</script>\n","<template>\n <v-container fluid>\n <v-row class=\"pa-4\" justify=\"space-around\">\n <!-- Student Classes -->\n <v-col v-if=\"studentClasses.length > 0\" cols=\"12\" sm=\"12\" md=\"4\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>My Classes</v-toolbar-title>\n </v-toolbar>\n\n <v-list>\n <transition-group name=\"component-fade\" mode=\"out-in\">\n <v-list-item v-for=\"classroom in studentClasses\" :key=\"classroom._id\" :value=\"classroom\">\n <v-list-item-title>\n {{ classroom.name }}\n </v-list-item-title>\n\n <template #append>\n <v-btn\n size=\"small\"\n color=\"secondary\"\n :loading=\"spinnerMap[classroom._id] !== undefined\"\n @click=\"leaveClass(classroom._id)\"\n >\n Leave this class\n </v-btn>\n </template>\n </v-list-item>\n </transition-group>\n </v-list>\n </v-card>\n </v-col>\n\n <!-- Teacher Classes -->\n <v-col v-if=\"teacherClasses.length > 0\" cols=\"12\" sm=\"12\" md=\"4\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>Classes I Manage</v-toolbar-title>\n </v-toolbar>\n\n <v-list>\n <transition-group name=\"component-fade\" mode=\"out-in\">\n <v-list-item v-for=\"classroom in teacherClasses\" :key=\"classroom._id\" :value=\"classroom\">\n <v-list-item-title>\n {{ classroom.name }}\n </v-list-item-title>\n\n <template #append>\n <v-btn\n size=\"small\"\n color=\"secondary\"\n :loading=\"spinnerMap[classroom._id] !== undefined\"\n :to=\"`/classrooms/${classroom._id}`\"\n >\n Open\n </v-btn>\n </template>\n </v-list-item>\n </transition-group>\n </v-list>\n </v-card>\n </v-col>\n\n <!-- Empty State Message -->\n <v-col v-if=\"studentClasses.length === 0 && teacherClasses.length === 0\" class=\"text-h5 text-center\">\n You are not in any classes! Join your class below if someone has given you a joincode. Or else, start your own!\n </v-col>\n </v-row>\n\n <v-divider class=\"my-4\"></v-divider>\n\n <!-- Join Class Form -->\n <v-row class=\"pa-4\">\n <v-col cols=\"12\" sm=\"12\" md=\"8\" lg=\"6\" xl=\"6\">\n <v-card>\n <v-toolbar color=\"primary\">\n <v-toolbar-title>Join a class</v-toolbar-title>\n </v-toolbar>\n <v-card-text>\n <v-text-field v-model=\"joinCode\" label=\"Class Code\" variant=\"outlined\"></v-text-field>\n <v-btn color=\"primary\" @click=\"joinClass\">Join</v-btn>\n </v-card-text>\n </v-card>\n </v-col>\n </v-row>\n\n <!-- New Class Dialog -->\n <v-dialog v-model=\"newClassDialog\" fullscreen transition=\"dialog-bottom-transition\" :scrim=\"false\">\n <template #activator=\"{ props }\">\n <v-btn color=\"primary\" v-bind=\"props\">Start a new Class</v-btn>\n </template>\n <classroom-editor @classroom-editing-complete=\"processResponse\" />\n </v-dialog>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { Status, ServerRequestType, JoinClassroom, LeaveClassroom, DeleteClassroom } from '@vue-skuilder/common';\nimport { getDataLayer, UserDBInterface } from '@vue-skuilder/db';\nimport serverRequest from '@pui/server/index';\nimport { alertUser } from '@vue-skuilder/common-ui';\nimport ClassroomEditor from '@pui/components/Classrooms/CreateClassroom.vue';\nimport { getCurrentUser } from '@vue-skuilder/common-ui';\n\ninterface CourseReg {\n _id: string;\n name: string;\n}\n\nexport default defineComponent({\n name: 'ClassroomsView',\n\n components: {\n ClassroomEditor,\n },\n\n beforeRouteEnter(to, from, next) {\n // todo ?\n // See https://router.vuejs.org/guide/advanced/data-fetching.html#fetching-before-navigation\n // this.refreshData().then(() => {\n // next();\n // });\n next();\n },\n\n data() {\n return {\n classes: [] as string[],\n joinCode: '',\n studentClasses: [] as CourseReg[],\n teacherClasses: [] as CourseReg[],\n spinnerMap: {} as { [index: string]: boolean },\n newClassDialog: false,\n user: null as UserDBInterface | null,\n };\n },\n\n created() {\n this.refreshData();\n },\n\n methods: {\n async refreshData() {\n this.$data.user = await getCurrentUser();\n const registrations = (await this.user!.getUserClassrooms()).registrations;\n const studentClasses: CourseReg[] = [];\n const teacherClasses: CourseReg[] = [];\n\n registrations.forEach(async (reg) => {\n const cfg = (\n await getDataLayer().getClassroomDB(\n reg.classID,\n reg.registeredAs == 'teacher' || reg.registeredAs == 'student' ? reg.registeredAs : 'student'\n )\n ).getConfig();\n console.log(`Registered class: ${JSON.stringify(cfg)}`);\n const regItem = {\n _id: reg.classID,\n name: cfg.name,\n };\n\n if (reg.registeredAs === 'student') {\n studentClasses.push(regItem);\n } else if (reg.registeredAs === 'teacher') {\n teacherClasses.push(regItem);\n }\n });\n\n this.studentClasses = studentClasses;\n this.teacherClasses = teacherClasses;\n },\n\n async deleteClass(classId: string) {\n const result = await serverRequest<DeleteClassroom>({\n type: ServerRequestType.DELETE_CLASSROOM,\n user: this.user?.getUsername() || '',\n classID: classId,\n response: null,\n });\n if (result.response && result.response.ok) {\n alertUser({\n text: `Class deleted successfully.`,\n status: Status.ok,\n });\n } else {\n alertUser({\n text: `Failed to delete class. Please try again.`,\n status: Status.error,\n });\n }\n },\n\n async leaveClass(classID: string) {\n this.spinnerMap[classID] = true;\n console.log(`Attempting to drop class: ${classID}`);\n\n const result = await serverRequest<LeaveClassroom>({\n type: ServerRequestType.LEAVE_CLASSROOM,\n data: {\n classID: classID,\n },\n user: this.user?.getUsername() || '',\n response: null,\n });\n if (result.response && result.response.ok) {\n if (this.user) {\n await this.user!.dropFromClassroom(classID);\n }\n }\n\n delete this.spinnerMap[classID];\n this.refreshData();\n },\n\n async joinClass() {\n const result = await serverRequest<JoinClassroom>({\n type: ServerRequestType.JOIN_CLASSROOM,\n data: {\n joinCode: this.joinCode,\n registerAs: 'student',\n user: this.user?.getUsername() || '',\n },\n user: this.user?.getUsername() || '',\n response: null,\n });\n\n if (result.response && result.response.ok) {\n console.log(`Adding registration to userDB...`);\n if (this.user) {\n await registerUserForClassroom(this.user.getUsername(), result.response!.id_course, 'student');\n alertUser({\n text: `Successfully joined class: ${result.response.course_name}.`,\n status: Status.ok,\n });\n } else {\n alertUser({\n text: `Failed to join class. [Unknown current user.]`,\n status: Status.error,\n });\n }\n } else {\n if (result.response) {\n alertUser({\n text: result.response.errorText!,\n status: Status.error,\n });\n }\n }\n this.refreshData();\n },\n\n async processResponse() {\n this.newClassDialog = !this.newClassDialog;\n },\n },\n});\n</script>\n"],"mappings":"8eCqDA,EAAe,EAAgB,CAC7B,MAAO,CAAC,2BAA2B,CAEnC,MAAO,CACL,MAAO,CACL,UAAW,IAAI,EAAA,QAAU,KAAK,IAAI,CAClC,WAAY,GACZ,KAAM,GACN,UAAW,IAAA,GACX,GAAI,GACJ,UAAW,CACR,GAEK,EAAM,OAAS,GACV,4CAEA,GAGZ,CACD,YAAa,GACb,OAAQ,IAAA,GACR,MAAO,IAAA,GACP,cAAe,GACf,WAAY,EAAC,CAId,EAGH,SAAU,CACR,KAAK,UAAU,KAAK,MAAO,KAAK,oBAAoB,CAEpD,IAAM,EAAe,GAAQ,CAAC,MAAM,CAEpC,KAAK,WAAW,KAAK,CACnB,KAAM,KAAK,EAAO,GAAE,mBACpB,MAAO,EACR,CAAC,CAEF,IAAK,IAAI,EAAM,GAAI,GAAO,EAAG,IAC3B,KAAK,WAAW,KAAK,CACnB,KAAM,GAAG,EAAO,EAAG,UAAW,EAAM,EAAE,GACtC,MAAO,EAAO,EACf,CAAC,CAGJ,KAAK,WAAW,KAAK,CACnB,KAAM,IAAI,EAAO,EAAC,iBAClB,MAAO,EAAO,EACf,CAAC,EAGJ,QAAS,CACP,MAAM,QAAS,CACb,KAAK,cAAgB,GACrB,IAAM,EAAI,MAAM,GAAgB,CAE1B,EAA0B,CAC9B,KAAM,KAAK,KACX,SAAU,CAAC,EAAE,aAAa,CAAC,CAC3B,SAAU,EAAE,CACZ,UAAW,KAAK,UAChB,qBAAsB,GACtB,WAAY,KAAK,WACjB,SAAU,GACX,CAED,EAAI;QACF,KAAK,UAAU,EAAO,GAAG,CAE3B,IAAM,EAAS,MAAM,EAA+B,CAClD,KAAM,EACN,KAAM,EAAkB,iBACxB,SAAU,KACV,KAAM,EAAE,aAAa,CACtB,CAAC,CAEE,EAAO,UAAY,EAAO,SAAS,IACrC,EAAU,CACR,KAAM,0CAA0C,EAAO,SAAS,WAChE,OAAQ,EAAO,GAChB,CAAC,CAEF,EAAE,qBAAqB,EAAO,SAAS,KAAM,UAAU,EAEvD,EAAU,CACR,KAAM,4CACN,OAAQ,EAAO,MAChB,CAAC,CAGJ,KAAK,qBAAqB,CAC1B,KAAK,cAAgB,IAGvB,qBAAsB,CACpB,KAAK,KAAO,GACZ,KAAK,YAAc,GAEnB,KAAK,MAAM,2BAA2B,EAEzC,CACF,CAAC,mQA5JA,EAuCS,EAAA,KAAA,CAxCX,QAAA,MAQgB,CANZ,EAMY,EAAA,CAND,MAAM,UAAS,CAAA,CAF9B,QAAA,MAGwF,CAAlF,EAAkF,EAAA,CAApE,MAAM,8BAA6B,CAAA,CAHvD,QAAA,MAGyE,EAAA,KAAA,EAAA,GAAA,CAHzE,EAGwD,oBAAiB,CAAA,EAAA,CAHzE,EAAA,IAIM,EAAqB,EAAA,CACrB,EAEQ,EAAA,CAFD,KAAA,GAAM,QAAO,EAAA,sBAL1B,QAAA,MAMkC,CAA1B,EAA0B,EAAA,KAAA,CANlC,QAAA,MAMyB,EAAA,KAAA,EAAA,GAAA,CANzB,EAMgB,YAAS,CAAA,EAAA,CANzB,EAAA,MAAA,EAAA,oBAAA,EAAA,IASI,EA8BS,EAAA,KAAA,CAvCb,QAAA,MAsCoB,CA5Bd,EA4Bc,EAAA,KAAA,CAtCpB,QAAA,MAqCgB,CA1BR,EA0BQ,EAAA,KAAA,CArChB,QAAA,MAqBkB,CATR,EASQ,EAAA,CATD,KAAK,KAAK,GAAG,IAAI,GAAG,MAZrC,QAAA,MAoB4B,CAPhB,EAOgB,EAAA,CApB5B,WAcuB,EAAA,KAdvB,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EAcuB,KAAI,GACb,QAAQ,KACP,MAAO,EAAA,UACR,MAAM,aACN,SAAA,GACA,KAAK,mEAnBnB,EAAA,IAsBU,EAEQ,EAAA,CAFD,KAAK,KAAK,GAAG,IAAI,GAAG,MAtBrC,QAAA,MAuByF,CAA7E,EAA6E,EAAA,CAvBzF,WAuBiC,EAAA,WAvBjC,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EAuBiC,WAAU,GAAE,MAAM,mDAvBnD,EAAA,IAyBU,EAQQ,EAAA,CARD,KAAK,KAAK,GAAG,IAAI,GAAG,MAzBrC,QAAA,MAgCwB,CANZ,EAMY,EAAA,CAhCxB,WA2BuB,EAAA,UA3BvB,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EA2BuB,UAAS,GACjB,MAAO,EAAA,WACR,MAAM,qCACN,aAAW,OACX,aAAW,0CA/BzB,EAAA,IAkCU,EAEQ,EAAA,CAFD,KAAK,KAAK,GAAG,IAAI,GAAG,MAlCrC,QAAA,MAmCqG,CAAzF,EAAyF,EAAA,CAAjF,QAAS,EAAA,cAAe,MAAM,UAAW,QAAO,EAAA,SAnCpE,QAAA,MAmC6F,EAAA,KAAA,EAAA,GAAA,CAnC7F,EAmC4E,oBAAiB,CAAA,EAAA,CAnC7F,EAAA,8BAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,mCE8GA,IAAA,EAAe,EAAgB,CAC7B,KAAM,iBAEN,WAAY,CACV,gDACD,CAED,iBAAiB,EAAI,EAAM,EAAM,CAM/B,GAAM,EAGR,MAAO,CACL,MAAO,CACL,QAAS,EAAC,CACV,SAAU,GACV,eAAgB,EAAC,CACjB,eAAgB,EAAC,CACjB,WAAY,EAAC,CACb,eAAgB,GAChB,KAAM,KACP,EAGH,SAAU,CACR,KAAK,aAAa,EAGpB,QAAS,CACP,MAAM,aAAc,CAClB,KAAK,MAAM,KAAO,MAAM,GAAgB,CACxC,IAAM,GAAiB,MAAM,KAAK,KAAM,mBAAmB,EAAE,cACvD,EAA8B,EAAE,CAChC,EAA8B,EAAE,CAEtC,EAAc,QAAQ,KAAO,IAAQ,CACnC,IAAM,GACJ,MAAM,GAAc,CAAC,eACnB,EAAI,QACJ,EAAI,cAAgB,WAAa,EAAI,cAAgB,UAAY,EAAI,aAAe,UACtF,EACA,WAAW,CACb,QAAQ,IAAI,qBAAqB,KAAK,UAAU,EAAI,GAAG,CACvD,IAAM,EAAU,CACd,IAAK,EAAI,QACT,KAAM,EAAI,KACX,CAEG,EAAI,eAAiB,UACvB,EAAe,KAAK,EAAQ,CACnB,EAAI,eAAiB,WAC9B,EAAe,KAAK,EAAQ,EAE9B,CAEF,KAAK,eAAiB,EACtB,KAAK,eAAiB,GAGxB,MAAM,YAAY,EAAiB,CACjC,IAAM,EAAS,MAAM,EAA+B,CAClD,KAAM,EAAkB,iBACxB,KAAM,KAAK,MAAM,aAAY,EAAK,GAClC,QAAS,EACT,SAAU,KACX,CAAC,CACE,EAAO,UAAY,EAAO,SAAS,GACrC,EAAU,CACR,KAAM,8BACN,OAAQ,EAAO,GAChB,CAAC,CAEF,EAAU,CACR,KAAM,4CACN,OAAQ,EAAO,MAChB,CAAC,EAIN,MAAM,WAAW,EAAiB,CAChC,KAAK,WAAW,GAAW,GAC3B,QAAQ,IAAI,6BAA6B,IAAU,CAEnD,IAAM,EAAS,MAAM,EAA8B,CACjD,KAAM,EAAkB,gBACxB,KAAM,CACK,UACV,CACD,KAAM,KAAK,MAAM,aAAY,EAAK,GAClC,SAAU,KACX,CAAC,CACE,EAAO,UAAY,EAAO,SAAS,IACjC,KAAK,MACP,MAAM,KAAK,KAAM,kBAAkB,EAAQ,CAI/C,OAAO,KAAK,WAAW,GACvB,KAAK,aAAa,EAGpB,MAAM,WAAY,CAChB,IAAM,EAAS,MAAM,EAA6B,CAChD,KAAM,EAAkB,eACxB,KAAM,CACJ,SAAU,KAAK,SACf,WAAY,UACZ,KAAM,KAAK,MAAM,aAAY,EAAK,GACnC,CACD,KAAM,KAAK,MAAM,aAAY,EAAK,GAClC,SAAU,KACX,CAAC,CAEE,EAAO,UAAY,EAAO,SAAS,IACrC,QAAQ,IAAI,mCAAmC,CAC3C,KAAK,MACP,MAAM,yBAAyB,KAAK,KAAK,aAAa,CAAE,EAAO,SAAU,UAAW,UAAU,CAC9F,EAAU,CACR,KAAM,8BAA8B,EAAO,SAAS,YAAY,GAChE,OAAQ,EAAO,GAChB,CAAC,EAEF,EAAU,CACR,KAAM,gDACN,OAAQ,EAAO,MAChB,CAAC,EAGA,EAAO,UACT,EAAU,CACR,KAAM,EAAO,SAAS,UACtB,OAAQ,EAAO,MAChB,CAAC,CAGN,KAAK,aAAa,EAGpB,MAAM,iBAAkB,CACtB,KAAK,eAAiB,CAAC,KAAK,gBAE/B,CACF,CAAC,4TA/PA,EA4Fc,EAAA,CA5FD,MAAA,GAAK,CAAA,CADpB,QAAA,MAmEY,CAjER,EAiEQ,EAAA,CAjED,MAAM,OAAO,QAAQ,iBAFhC,QAAA,MA+Bc,CA3BK,EAAA,eAAe,OAAM,GAAA,GAAA,CAAlC,EA2BQ,EAAA,CA/Bd,IAAA,EAI8C,KAAK,KAAK,GAAG,KAAK,GAAG,MAJnE,QAAA,MA8BiB,CAzBT,EAyBS,EAAA,KAAA,CA9BjB,QAAA,MAQsB,CAFZ,EAEY,EAAA,CAFD,MAAM,UAAS,CAAA,CANpC,QAAA,MAOyD,CAA7C,EAA6C,EAAA,KAAA,CAPzD,QAAA,MAOuC,EAAA,KAAA,EAAA,GAAA,CAPvC,EAO6B,aAAU,CAAA,EAAA,CAPvC,EAAA,MAAA,EAAA,IAUU,EAmBS,EAAA,KAAA,CA7BnB,QAAA,MA4B+B,CAjBnB,EAiBmB,EAAA,CAjBD,KAAK,iBAAiB,KAAK,WAXzD,QAAA,MAY8D,EAAA,EAAA,GAAA,CAAhD,EAec,EAAA,KA3B5B,EAY+C,EAAA,eAAb,QAApB,EAec,EAAA,CAfoC,IAAK,EAAU,IAAM,MAAO,IAKjE,OAAM,MAQP,CAPR,EAOQ,EAAA,CANN,KAAK,QACL,MAAM,YACL,QAAS,EAAA,WAAW,EAAU,OAAS,IAAA,GACvC,QAAK,GAAE,EAAA,WAAW,EAAU,IAAG,GAtBpD,QAAA,MAyBkB,EAAA,KAAA,EAAA,GAAA,CAzBlB,EAuBmB,qBAED,CAAA,EAAA,CAzBlB,EAAA,iCAAA,QAAA,MAeoC,CAFpB,EAEoB,EAAA,KAAA,CAfpC,QAAA,MAcsC,CAdtC,EAAA,EAcqB,EAAU,KAAI,CAAA,EAAA,CAAA,CAAA,CAdnC,EAAA,WAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,GAAA,CAkCmB,EAAA,eAAe,OAAM,GAAA,GAAA,CAAlC,EA2BQ,EAAA,CA7Dd,IAAA,EAkC8C,KAAK,KAAK,GAAG,KAAK,GAAG,MAlCnE,QAAA,MA4DiB,CAzBT,EAyBS,EAAA,KAAA,CA5DjB,QAAA,MAsCsB,CAFZ,EAEY,EAAA,CAFD,MAAM,UAAS,CAAA,CApCpC,QAAA,MAqC+D,CAAnD,EAAmD,EAAA,KAAA,CArC/D,QAAA,MAqC6C,EAAA,KAAA,EAAA,GAAA,CArC7C,EAqC6B,mBAAgB,CAAA,EAAA,CArC7C,EAAA,MAAA,EAAA,IAwCU,EAmBS,EAAA,KAAA,CA3DnB,QAAA,MA0D+B,CAjBnB,EAiBmB,EAAA,CAjBD,KAAK,iBAAiB,KAAK,WAzCzD,QAAA,MA0C8D,EAAA,EAAA,GAAA,CAAhD,EAec,EAAA,KAzD5B,EA0C+C,EAAA,eAAb,QAApB,EAec,EAAA,CAfoC,IAAK,EAAU,IAAM,MAAO,IAKjE,OAAM,MAQP,CAPR,EAOQ,EAAA,CANN,KAAK,QACL,MAAM,YACL,QAAS,EAAA,WAAW,EAAU,OAAS,IAAA,GACvC,GAAE,eAAiB,EAAU,QApDlD,QAAA,MAuDkB,EAAA,KAAA,EAAA,GAAA,CAvDlB,EAqDmB,SAED,CAAA,EAAA,CAvDlB,EAAA,4BAAA,QAAA,MA6CoC,CAFpB,EAEoB,EAAA,KAAA,CA7CpC,QAAA,MA4CsC,CA5CtC,EAAA,EA4CqB,EAAU,KAAI,CAAA,EAAA,CAAA,CAAA,CA5CnC,EAAA,WAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,GAAA,CAgEmB,EAAA,eAAe,SAAM,GAAU,EAAA,eAAe,SAAM,GAAA,GAAA,CAAjE,EAEQ,EAAA,CAlEd,IAAA,EAgE+E,MAAM,wBAhErF,QAAA,MAkEM,EAAA,KAAA,EAAA,GAAA,CAlEN,EAgE2G,oHAErG,CAAA,EAAA,CAlEN,EAAA,KAAA,EAAA,GAAA,GAAA,GAAA,EAAA,IAqEI,EAAoC,EAAA,CAAzB,MAAM,OAAM,CAAA,CAGvB,EAYQ,EAAA,CAZD,MAAM,OAAM,CAAA,CAxEvB,QAAA,MAmFc,CAVR,EAUQ,EAAA,CAVD,KAAK,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,MAzEhD,QAAA,MAkFiB,CART,EAQS,EAAA,KAAA,CAlFjB,QAAA,MA6EsB,CAFZ,EAEY,EAAA,CAFD,MAAM,UAAS,CAAA,CA3EpC,QAAA,MA4E2D,CAA/C,EAA+C,EAAA,KAAA,CA5E3D,QAAA,MA4EyC,EAAA,KAAA,EAAA,GAAA,CA5EzC,EA4E6B,eAAY,CAAA,EAAA,CA5EzC,EAAA,MAAA,EAAA,IA8EU,EAGc,EAAA,KAAA,CAjFxB,QAAA,MA+EkG,CAAtF,EAAsF,EAAA,CA/ElG,WA+EmC,EAAA,SA/EnC,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EA+EmC,SAAQ,GAAE,MAAM,aAAa,QAAQ,mCAC5D,EAAsD,EAAA,CAA/C,MAAM,UAAW,QAAO,EAAA,YAhF3C,QAAA,MAgF0D,EAAA,KAAA,EAAA,GAAA,CAhF1D,EAgFsD,OAAI,CAAA,EAAA,CAhF1D,EAAA,oBAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,IAuFI,EAKW,EAAA,CA5Ff,WAuFuB,EAAA,eAvFvB,sBAAA,EAAA,KAAA,EAAA,GAAA,GAAA,EAuFuB,eAAc,GAAE,WAAA,GAAW,WAAW,2BAA4B,MAAO,KAC/E,UAAS,GAC6C,CADzC,WAAK,CAC3B,EAA+D,EAA/D,EAA+D,CAAxD,MAAM,UAAS,CAAS,EAAK,CAAA,CAzF5C,QAAA,MAyF+D,EAAA,KAAA,EAAA,GAAA,CAzF/D,EAyF8C,oBAAiB,CAAA,EAAA,CAzF/D,EAAA,WAAA,QAAA,MA2FwE,CAAlE,EAAkE,EAAA,CAA/C,2BAA4B,EAAA,gBAAe,CAAA,KAAA,EAAA,CAAA,6BAAA,CAAA,CAAA,CAAA,CA3FpE,EAAA,uBAAA,EAAA"}