@clickview/lite 0.82.1 → 0.82.2-rc.0
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.
- package/dist/bundles.json +1 -1
- package/dist/css/2074-lite-ac8da6c78b.chunk.css +4 -0
- package/dist/languages/en.json +1 -1
- package/dist/scripts/{1199-01cc084886-lite.chunk.js → 1199-da55d69853-lite.chunk.js} +1 -1
- package/dist/scripts/{1199-01cc084886-lite.chunk.js.map → 1199-da55d69853-lite.chunk.js.map} +1 -1
- package/dist/scripts/1202-d96ad80884-lite.chunk.js +2 -0
- package/dist/scripts/1202-d96ad80884-lite.chunk.js.map +1 -0
- package/dist/scripts/{4208-0706461da6-lite.chunk.js → 1336-1826f6e582-lite.chunk.js} +2 -2
- package/dist/scripts/1336-1826f6e582-lite.chunk.js.map +1 -0
- package/dist/scripts/2074-39b86b9a22-lite.chunk.js +2 -0
- package/dist/scripts/2074-39b86b9a22-lite.chunk.js.map +1 -0
- package/dist/scripts/{2664-907153c03b-lite.chunk.js → 2664-87c8cbfa7f-lite.chunk.js} +2 -2
- package/dist/scripts/2664-87c8cbfa7f-lite.chunk.js.map +1 -0
- package/dist/scripts/2888-2596e106a5-lite.chunk.js +2 -0
- package/dist/scripts/2888-2596e106a5-lite.chunk.js.map +1 -0
- package/dist/scripts/289-669c0c8222-lite.chunk.js +2 -0
- package/dist/scripts/289-669c0c8222-lite.chunk.js.map +1 -0
- package/dist/scripts/{9911-8892b6dbfe-lite.chunk.js → 3612-8c6423bd51-lite.chunk.js} +2 -2
- package/dist/scripts/{9911-8892b6dbfe-lite.chunk.js.map → 3612-8c6423bd51-lite.chunk.js.map} +1 -1
- package/dist/scripts/3840-98c79fc0d8-lite.chunk.js +2 -0
- package/dist/scripts/3840-98c79fc0d8-lite.chunk.js.map +1 -0
- package/dist/scripts/3893-2856933742-lite.chunk.js +2 -0
- package/dist/scripts/3893-2856933742-lite.chunk.js.map +1 -0
- package/dist/scripts/4006-9dfe9cec1b-lite.chunk.js +3 -0
- package/dist/scripts/4006-9dfe9cec1b-lite.chunk.js.map +1 -0
- package/dist/scripts/{4177-2d876c7b14-lite.chunk.js → 4177-285ddf9ae3-lite.chunk.js} +2 -2
- package/dist/scripts/4177-285ddf9ae3-lite.chunk.js.map +1 -0
- package/dist/scripts/{4578-27028d26eb-lite.chunk.js → 4578-7578bcf17a-lite.chunk.js} +2 -2
- package/dist/scripts/4578-7578bcf17a-lite.chunk.js.map +1 -0
- package/dist/scripts/{4621-7fb0a05bcb-lite.chunk.js → 4621-1f79d94416-lite.chunk.js} +2 -2
- package/dist/scripts/4621-1f79d94416-lite.chunk.js.map +1 -0
- package/dist/scripts/4806-f36469abb7-lite.chunk.js +2 -0
- package/dist/scripts/4806-f36469abb7-lite.chunk.js.map +1 -0
- package/dist/scripts/{4948-ba684e5f4f-lite.chunk.js → 4948-de1c75e7fb-lite.chunk.js} +1 -1
- package/dist/scripts/{4948-ba684e5f4f-lite.chunk.js.map → 4948-de1c75e7fb-lite.chunk.js.map} +1 -1
- package/dist/scripts/4985-bdfa839f8f-lite.chunk.js +2 -0
- package/dist/scripts/4985-bdfa839f8f-lite.chunk.js.map +1 -0
- package/dist/scripts/{5554-f1f3baf822-lite.chunk.js → 5554-17bb3b86fc-lite.chunk.js} +2 -2
- package/dist/scripts/5554-17bb3b86fc-lite.chunk.js.map +1 -0
- package/dist/scripts/5579-a9c152057f-lite.chunk.js +2 -0
- package/dist/scripts/5579-a9c152057f-lite.chunk.js.map +1 -0
- package/dist/scripts/5712-e784cfe89c-lite.chunk.js +2 -0
- package/dist/scripts/5712-e784cfe89c-lite.chunk.js.map +1 -0
- package/dist/scripts/6070-a390fdce21-lite.chunk.js +2 -0
- package/dist/scripts/6070-a390fdce21-lite.chunk.js.map +1 -0
- package/dist/scripts/{6909-ba75701156-lite.chunk.js → 6909-a9b8930e37-lite.chunk.js} +2 -2
- package/dist/scripts/6909-a9b8930e37-lite.chunk.js.map +1 -0
- package/dist/scripts/7401-98135f09e8-lite.chunk.js +2 -0
- package/dist/scripts/7401-98135f09e8-lite.chunk.js.map +1 -0
- package/dist/scripts/{7617-211f084b70-lite.chunk.js → 7617-9d34c841e6-lite.chunk.js} +2 -2
- package/dist/scripts/7617-9d34c841e6-lite.chunk.js.map +1 -0
- package/dist/scripts/7742-342db3ce4f-lite.chunk.js +2 -0
- package/dist/scripts/7742-342db3ce4f-lite.chunk.js.map +1 -0
- package/dist/scripts/7843-f6033528ce-lite.chunk.js +2 -0
- package/dist/scripts/7843-f6033528ce-lite.chunk.js.map +1 -0
- package/dist/scripts/787-dcb3a0a26c-lite.chunk.js +2 -0
- package/dist/scripts/787-dcb3a0a26c-lite.chunk.js.map +1 -0
- package/dist/scripts/8077-9fdb522d7e-lite.chunk.js +2 -0
- package/dist/scripts/8077-9fdb522d7e-lite.chunk.js.map +1 -0
- package/dist/scripts/{3392-f7f8cb65e5-lite.chunk.js → 8133-ffcff3b7fc-lite.chunk.js} +3 -3
- package/dist/scripts/8133-ffcff3b7fc-lite.chunk.js.map +1 -0
- package/dist/scripts/8364-ff63447d36-lite.chunk.js +3 -0
- package/dist/scripts/8364-ff63447d36-lite.chunk.js.map +1 -0
- package/dist/scripts/8672-6967ce8a23-lite.chunk.js +2 -0
- package/dist/scripts/8672-6967ce8a23-lite.chunk.js.map +1 -0
- package/dist/scripts/{9042-fd7e79b891-lite.chunk.js → 9042-fdc5ecb459-lite.chunk.js} +1 -1
- package/dist/scripts/{9042-fd7e79b891-lite.chunk.js.map → 9042-fdc5ecb459-lite.chunk.js.map} +1 -1
- package/dist/scripts/9295-4242401e60-lite.chunk.js +2 -0
- package/dist/scripts/9295-4242401e60-lite.chunk.js.map +1 -0
- package/dist/scripts/{9742-3f6b75484a-lite.chunk.js → 9742-5f99d74bb0-lite.chunk.js} +2 -2
- package/dist/scripts/9742-5f99d74bb0-lite.chunk.js.map +1 -0
- package/dist/scripts/979-4b893e5603-lite.chunk.js +2 -0
- package/dist/scripts/979-4b893e5603-lite.chunk.js.map +1 -0
- package/dist/scripts/9911-9272b96e46-lite.chunk.js +2 -0
- package/dist/scripts/9911-9272b96e46-lite.chunk.js.map +1 -0
- package/dist/scripts/bundle-9a3e49399a.min.js +3 -0
- package/dist/scripts/{bundle-1187cb1e9f.min.js.map → bundle-9a3e49399a.min.js.map} +1 -1
- package/package.json +1 -1
- package/dist/scripts/1074-fdce06d863-lite.chunk.js +0 -2
- package/dist/scripts/1074-fdce06d863-lite.chunk.js.map +0 -1
- package/dist/scripts/2664-907153c03b-lite.chunk.js.map +0 -1
- package/dist/scripts/2970-024b1dd55d-lite.chunk.js +0 -2
- package/dist/scripts/2970-024b1dd55d-lite.chunk.js.map +0 -1
- package/dist/scripts/3392-f7f8cb65e5-lite.chunk.js.map +0 -1
- package/dist/scripts/3840-59e5e53cda-lite.chunk.js +0 -2
- package/dist/scripts/3840-59e5e53cda-lite.chunk.js.map +0 -1
- package/dist/scripts/4177-2d876c7b14-lite.chunk.js.map +0 -1
- package/dist/scripts/4208-0706461da6-lite.chunk.js.map +0 -1
- package/dist/scripts/4578-27028d26eb-lite.chunk.js.map +0 -1
- package/dist/scripts/4598-8f5266e4c2-lite.chunk.js +0 -2
- package/dist/scripts/4598-8f5266e4c2-lite.chunk.js.map +0 -1
- package/dist/scripts/4621-7fb0a05bcb-lite.chunk.js.map +0 -1
- package/dist/scripts/4806-a6f31d703c-lite.chunk.js +0 -2
- package/dist/scripts/4806-a6f31d703c-lite.chunk.js.map +0 -1
- package/dist/scripts/4985-7e02d5df40-lite.chunk.js +0 -2
- package/dist/scripts/4985-7e02d5df40-lite.chunk.js.map +0 -1
- package/dist/scripts/5554-f1f3baf822-lite.chunk.js.map +0 -1
- package/dist/scripts/5712-7cee70c6b4-lite.chunk.js +0 -2
- package/dist/scripts/5712-7cee70c6b4-lite.chunk.js.map +0 -1
- package/dist/scripts/6550-d99e0ed75d-lite.chunk.js +0 -2
- package/dist/scripts/6550-d99e0ed75d-lite.chunk.js.map +0 -1
- package/dist/scripts/6909-ba75701156-lite.chunk.js.map +0 -1
- package/dist/scripts/7148-1ced1b5dce-lite.chunk.js +0 -2
- package/dist/scripts/7148-1ced1b5dce-lite.chunk.js.map +0 -1
- package/dist/scripts/7568-55e9b01367-lite.chunk.js +0 -3
- package/dist/scripts/7568-55e9b01367-lite.chunk.js.map +0 -1
- package/dist/scripts/7617-211f084b70-lite.chunk.js.map +0 -1
- package/dist/scripts/7742-514844bd1a-lite.chunk.js +0 -2
- package/dist/scripts/7742-514844bd1a-lite.chunk.js.map +0 -1
- package/dist/scripts/7843-cbebf1a786-lite.chunk.js +0 -2
- package/dist/scripts/7843-cbebf1a786-lite.chunk.js.map +0 -1
- package/dist/scripts/8077-dfd239131d-lite.chunk.js +0 -2
- package/dist/scripts/8077-dfd239131d-lite.chunk.js.map +0 -1
- package/dist/scripts/843-4dbc5df109-lite.chunk.js +0 -3
- package/dist/scripts/843-4dbc5df109-lite.chunk.js.map +0 -1
- package/dist/scripts/8735-e74a148502-lite.chunk.js +0 -2
- package/dist/scripts/8735-e74a148502-lite.chunk.js.map +0 -1
- package/dist/scripts/8856-2d332952ae-lite.chunk.js +0 -2
- package/dist/scripts/8856-2d332952ae-lite.chunk.js.map +0 -1
- package/dist/scripts/904-2784e45cfc-lite.chunk.js +0 -2
- package/dist/scripts/904-2784e45cfc-lite.chunk.js.map +0 -1
- package/dist/scripts/9295-eb130a0b17-lite.chunk.js +0 -2
- package/dist/scripts/9295-eb130a0b17-lite.chunk.js.map +0 -1
- package/dist/scripts/9528-4e954d9dff-lite.chunk.js +0 -2
- package/dist/scripts/9528-4e954d9dff-lite.chunk.js.map +0 -1
- package/dist/scripts/9742-3f6b75484a-lite.chunk.js.map +0 -1
- package/dist/scripts/979-6a70a0e616-lite.chunk.js +0 -2
- package/dist/scripts/979-6a70a0e616-lite.chunk.js.map +0 -1
- package/dist/scripts/bundle-1187cb1e9f.min.js +0 -3
- /package/dist/css/{9528-lite-4a892bdbf2.chunk.css → 1202-lite-4a892bdbf2.chunk.css} +0 -0
- /package/dist/css/{7148-lite-856c02f000.chunk.css → 2888-lite-856c02f000.chunk.css} +0 -0
- /package/dist/css/{904-lite-2435a34b13.chunk.css → 289-lite-2435a34b13.chunk.css} +0 -0
- /package/dist/css/{9911-lite-2b4142796a.chunk.css → 3612-lite-2b4142796a.chunk.css} +0 -0
- /package/dist/css/{8856-lite-f8e496136d.chunk.css → 5579-lite-f8e496136d.chunk.css} +0 -0
- /package/dist/css/{6550-lite-45dc286aab.chunk.css → 6070-lite-45dc286aab.chunk.css} +0 -0
- /package/dist/css/{2970-lite-5a317efacd.chunk.css → 787-lite-5a317efacd.chunk.css} +0 -0
- /package/dist/css/{843-lite-db31e36b79.chunk.css → 8364-lite-db31e36b79.chunk.css} +0 -0
- /package/dist/css/{8735-lite-856c02f000.chunk.css → 9911-lite-856c02f000.chunk.css} +0 -0
- /package/dist/scripts/{3392-f7f8cb65e5-lite.chunk.js.LICENSE.txt → 4006-9dfe9cec1b-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{7568-55e9b01367-lite.chunk.js.LICENSE.txt → 8133-ffcff3b7fc-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{843-4dbc5df109-lite.chunk.js.LICENSE.txt → 8364-ff63447d36-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{bundle-1187cb1e9f.min.js.LICENSE.txt → bundle-9a3e49399a.min.js.LICENSE.txt} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scripts/3840-59e5e53cda-lite.chunk.js","mappings":"+LACA,SAAgB,IAAM,QAAQ,QAAU,SCSxC,IAAMA,EAAY,qCAOZ,SAAUC,EAAcC,GAC5B,OACE,gBAACC,EAAA,EAAO,CAACC,MAAOC,EAAA,YAA0BL,EAAW,WAAYM,kBAAiB,kBAAa,WAAkBC,UAAQ,GACvH,uBAAKC,UAAS,8CAAyC,MAAU,YAAIN,EAAMM,YACzE,gBAACC,EAAA,EAAY,CAACC,QAAS,cACrBR,EAAMS,UAAYN,EAAA,YAA0BL,EAAW,eAIjE,C,6DCzBA,SAAgB,SAAW,QAAQ,MAAQ,QAAQ,KAAO,QAAQ,QAAU,QAAQ,UAAY,QAAQ,UAAY,QAAQ,MAAQ,SCyB9H,SAAUY,EAAoBV,G,UAYlC,OACE,gBAACW,EAAA,EAAO,CACNC,QAAyB,QAAhB,EAAAZ,EAAMa,kBAAU,uBACzBP,UAAS,8EAAoF,QAAX,EAAAN,EAAMc,aAAK,eAAEC,OAAM,0CAAkCf,EAAMM,WAC7IU,cAAehB,EAAMgB,cACrBC,iBAAkBjB,EAAMiB,kBAExB,uBAAKX,UAAS,4BAAuB,aACnC,uBAAKA,UAAS,UAAgB,QAAX,EAAAN,EAAMc,aAAK,eAAEI,WAAU,iBAAS,QAAY,sDAC5DlB,EAAMmB,MAAQnB,EAAMmB,MAAQ,sCAE/B,uBAAKb,UAAS,UAtBpB,WACE,OAAQN,EAAMoB,KAAKC,MACjB,IAAK,QACH,OAAO,YACT,IAAK,MACH,OAAO,UACT,IAAK,QACH,OAAO,YAEb,CAayBC,GAAc,YAAI,OAAW,UAC7CtB,EAAMoB,KAAKG,MAEd,uBAAKjB,UAAS,eAAU,UACrBN,EAAMwB,QAKjB,C,2DCrDaC,EAAiB,CAC5BC,WAAU,SAACC,GACT,OAAOA,aAAG,EAAHA,EAAKC,UAAW,YACzB,EAEAC,QAAO,SAACC,EAAoBC,G,MAC1B,SAAKA,IAAgBD,GAAY,YAAqBA,EAASE,cAGxDF,EAASE,WAAWC,GAAGC,cAA6B,QAAd,EAAAH,EAAYE,UAAE,eAAEC,WAC/D,EAEAC,cAAa,SAACL,G,UACZ,GAAKA,EAAL,CAGA,IAAIM,EAAQ,EAWZ,OATmB,QAAf,EAAAN,EAASO,cAAM,eAAED,SACnBA,GAASN,EAASO,OAAOD,QAET,QAAd,EAAAN,EAASQ,aAAK,eAAEF,SAClBA,GAASN,EAASQ,MAAMF,QAED,QAArB,EAAAN,EAASS,oBAAY,eAAEH,SACzBA,GAASN,EAASS,aAAaH,OAE1BA,CAbC,CAcV,E,2JCxBItC,EAAY,oBAkBZ,SAAU0C,EAAWxC,GACzB,MAA8D,eAC5DyC,YAAY,GACTzC,GAFG0C,EAAU,EAAVA,WAAY9B,EAAO,EAAPA,QAAS+B,EAAK,EAALA,MAAOC,EAAY,EAAZA,aAAcH,EAAU,EAAVA,WAK5CI,EAAaH,EACfvC,EAAA,YAA0BL,EAAW,SAAU,CAAE4C,WAAAA,IACjDvC,EAAA,YAA0BL,EAAW,QAEnCgD,EAAuB,UAAVH,EAAoB,GAAK,aACtCI,EAAkBN,EAAa,cAAgB,GAErD,OACE,gBAAC9B,EAAA,EAAO,CACNC,QAASA,EACTN,UAAS,mDAA8CsC,EAAY,YAAIE,EAAU,YAAIC,IAErF,gBAACxC,EAAA,EAAY,CAACC,QAAS,iBAA0BwC,KAAMzC,EAAA0C,EAAA,SACvD,wBAAM3C,UAAU,QAAQuC,GAG9B,CA3BAL,EAAWU,aAAe,CACxBP,MAAO,QACPC,aAAc,I,oGCvBhB,SAAgB,cAAgB,QAAQ,iBAAmB,QAAQ,sBAAwB,QAAQ,UAAY,QAAQ,cAAgB,QAAQ,kBAAoB,QAAQ,YAAc,QAAQ,sBAAwB,QAAQ,aAAe,QAAQ,QAAU,SCuBlQ,IAAMO,EAAQ,GAAH,OAAM,IAAmB,cAAmBC,MAAK,YAAI,IAAmB,cAAmBC,QAatG,SAASC,EAAaC,GACpB,OAAIA,EAAQC,OAAS,IACZ,KAEF,cACT,CAwBA,IAEaC,EAAe,OAAW,SAASzD,G,YACtCuD,EAAyFvD,EAAzFuD,QAASG,EAAgF1D,EAAhF0D,OAAQC,EAAwE3D,EAAxE2D,YAAaC,EAA2D5D,EAA3D4D,QAASC,EAAkD7D,EAAlD6D,cAAeC,EAAmC9D,EAAnC8D,iBAAkBC,EAAiB/D,EAAjB+D,aAE1EC,EAAyB,aAAiBC,EAAA,GAE1CC,GA5Cc,EAAAC,EAAA,KAEJC,IALS,KADL,KAkDdC,EAAsB,UAAc,WACxC,IAAKN,GAAgB/D,EAAMsE,eACzB,OAAO,EAET,IAAMC,EAAQC,EAAA,SAAkB,IAAIC,KAAQ,cAE5C,OAAKV,EAAaW,QAGXX,EAAaY,WAAaJ,GAASR,EAAaW,SAAWH,EAFzDR,EAAaY,YAAcJ,CAGtC,EAAG,CAACR,IAYEa,EAAe5E,EAAM4E,cAAgB,CACzCxB,MAAOc,EACPW,MAAO1B,EACP2B,WAAY,YAGRC,IAAQrB,KAAYC,GAAeqB,EAAA,kBAA4BtB,EAAQ,CAC3EuB,gBAAiBtB,EACjBuB,qBAAsB3B,EACtBlC,KAAM,cACLuD,GAEGO,EAAgG,CACpG7E,UAAW,wBAAF,OAA0BN,EAAMoF,iBACzCC,MAAON,EAAM,CAAEO,gBAAiB,QAAF,OAAUP,EAAG,OAAS,CAAC,IAGlDrB,GAAUI,WACNqB,EAAeE,MACtBF,EAAe7E,WAAa,IAAJ,OAAQwD,IAGlC,IAAMyB,EAAmBvF,EAAMwF,iBAEzBC,GAA0B,EAAAC,EAAA,GAAgB1F,EAAMuD,QAAS,KAE/D,OAAOoC,EAAA,yBAEL,0CAAYR,GACV,uBAAK7E,UAAS,oBAAe,YAAgB,oCAC1CN,EAAM4F,mBACL,uBAAKtF,UAAU,QACb,gBAACkC,EAAU,CACT5B,QAASZ,EAAM4F,kBACflD,WAAY1C,EAAM6F,eAClBjD,aAAc5C,EAAM8F,kBACpBnD,MAAM,WAKZ,uBAAKrC,UAAS,UAAKN,EAAM+F,cAAgB,iEAAmE,GAAH,OAAM,gBAAoB,kBAAmB,QAAV,EAAA/F,EAAMgG,YAAI,eAAEjB,KAAM,wBAA+B,QACxLhB,GACD,uBAAKzD,UAAS,4BAAuB,0BACnC,gBAACI,EAAA,EAAmB,CAClBU,KAAM,CACJC,KAAM0C,EAAaW,QAAU,QAAU,MACvCnD,KAAMwC,EAAaW,QAAO,UACnBF,EAAA,SAAkBT,EAAaY,UAAW,MAAK,YAAIH,EAAA,SAAkBT,EAAaW,QAAS,OAC9FF,EAAA,SAAkBT,EAAaY,UAAW,OAEhDnD,MA7Dd,SAAkCuC,GAChC,OAAKA,EAAaW,QAGdF,EAAA,SAAkBT,EAAaY,UAAWZ,EAAaW,QAAS,SAC3DF,EAAA,SAAkBT,EAAaY,UAAW,QAE5C,GAAP,OAAUH,EAAA,SAAkBT,EAAaY,UAAW,OAAM,cAAMH,EAAA,SAAkBT,EAAaW,QAAS,QAL/FF,EAAA,SAAkBT,EAAaY,UAAW,OAMrD,CAqDqBsB,CAAyBlC,GAChCjD,MAAOd,EAAMkG,iBAInB,2BACG7B,GACC,uBAAK/D,UAAU,kFACb,gBAAC6F,EAAA,EAAI,CAACrG,UA1FJ,sBA0F0BsG,OAAO,aAGtCpG,EAAMsE,gBACL,gBAACvE,EAAA,EAAa,CAACO,UAAU,yEAE3B,uBAAKA,UAAU,6BACZN,EAAM+F,gBAA2B,QAAV,EAAA/F,EAAMgG,YAAI,eAAEjB,MAClC,uBAAKzE,UAAS,UAAK,oBAAwB,kEAA0DmF,IACnG,gBAACY,EAAA,EAAS,CACRC,IAAKtB,EAAA,YAAgC,QAAV,EAAAhF,EAAMgG,YAAI,eAAEjB,IAAK,CAAE/B,KAAM,cACpDqC,MAAO,CAAEkB,gBAAiBvG,EAAMwG,iBAItC,sBAAIlG,UAAS,sDAAiD,UAAc,YAAIgD,EAAaC,GAAQ,YAAIvD,EAAM+F,cAAgB,OAAS,KACrIxC,EACAgC,GAAoB,gBAACA,EAAgB,WAIzC3B,GACD,uBAAKtD,UAAW,oBACd,gBAACmG,EAAA,EAAO,CACN7C,QAASA,EACTC,cAAeA,EACf6C,yBAA0B1G,EAAM0G,8BAKtC1G,EAAM+F,kBAA6B,QAAV,EAAA/F,EAAMgG,YAAI,eAAEjB,MACrC,uBAAKzE,UAAW,iBACd,uBACEgG,IAAKtB,EAAA,YAAsBhF,EAAMgG,KAAKjB,IAAK,CAAE/B,KAAM,cACnD1C,UAAU,sBAMpB0D,aAAsB,EAAtBA,EAAwB2C,UAE5B,EAAG,SAACC,EAAWC,G,QAAuB,OACpCD,EAAUhD,UAAYiD,EAAUjD,SAC7BgD,EAAUrD,UAAYsD,EAAUtD,UAClB,QAAd,EAAAqD,EAAUZ,YAAI,eAAEjB,QAAsB,QAAd,EAAA8B,EAAUb,YAAI,eAAEjB,I,GAGvC,SAAU+B,IACd,IAAM9C,EAAyB,aAAiBC,EAAA,GAEhD,OAAO0B,EAAA,yBACL,uBAAKrF,UAAS,oDAA+C,YAC7D0D,aAAsB,EAAtBA,EAAwB2C,UAE5B,C,yGCzLMI,EAA8B,CAClCC,SAAU,IACVC,UAAW,CACTC,OAAQ,IACRC,UAAW,IACXC,OAAQ,IACRC,QAAS,KAEXC,WAAY,IACZC,oBAAqB,KAGjB,SAAUC,EACdC,GAMkC,IALlCC,EAAA,uDAA+B,CAAC,EAKhCC,EAAA,uDAAgC,CAAC,EAEjC,GAAKF,EAAL,CAGA,IAAIG,EAGFA,EADmB,iBAAVH,EACIA,EAEAA,EAAKI,OAGpB,IAAMC,EAAW,OAAH,wBACTf,GACAW,GAGAE,GAGA,yBAAmCA,KAGpCA,IAAe,mBAMfA,IAAe,aAMfA,IAAe,cAUdD,EAAUL,YACb,aAAuB,IAAIQ,EAASR,YAN/BK,EAAUV,WACb,aAAuB,IAAIa,EAASb,UAAUI,SAX3CM,EAAUX,UACb,aAAuB,IAAIc,EAASd,UAPjCW,EAAUJ,qBACb,aAAuB,IAAI,KAvBvB,CA6CV,C,+vDCvFMQ,EAAa,GAkBb,SAAUC,EACdC,EACAC,GAEA,IAEMC,EAFS,UAA0BF,EAASF,GAE1BK,IAAI,SAAAC,GAAK,OAAIH,EAAW,SAAiBG,GAAO,GAElEC,EAAY,qBAA6BH,GAEzCI,EAAW,YAAoBD,EAAUE,MACzCC,EAAQH,EAAUE,KAAKhF,OACzB+E,EAASG,OAAO,SAACC,EAAKC,GAAI,OAAK,+BAAMD,GAAG,KAAGC,EAAK3G,GAAK2G,GAAI,EAAK,CAAC,GAC/D,KAEJ,MAAO,CACLL,SAAAA,EACAE,MAAAA,EACAI,WAAYP,EAAUO,WACtBC,aAAcR,EAAUQ,aAE5B,CAQM,SAAUC,EACdC,EACAd,EACAe,GAEA,IAAMC,EAASD,QAAAA,EAAY,SAACtH,GAC1B,MAAmB,WAAf,EAAOA,GACFA,EAAIM,GAENN,CACT,EAEM,EAA0BwH,EAA8C,CAAEjB,WAAAA,EAAYe,QAAAA,IAApFG,EAAU,EAAVA,WAAeZ,EAAI,IAArB,gBASN,OAPA,YAAgB,YACTQ,aAAI,EAAJA,EAAMxF,SAGX4F,EAAWJ,EACb,EAAG,CAACA,aAAI,EAAJA,EAAMZ,IAAIc,GAAQG,KAAK,OAEpBb,CACT,CAWM,SAAUW,EACdG,G,cAEMJ,EAAwB,QAAf,EAAAI,EAAQL,eAAO,QAAK,SAACtH,GAClC,MAAmB,WAAf,EAAOA,GACFA,EAAIM,GAENN,CACT,EAEM4H,EAAe,SAA0B,IAAIC,KACmB,G,EAApC,WAAiC,I,EAAG,E,unBAA9DrB,EAAQ,KAAEsB,EAAW,KAwBvBnB,EAAY,qBAAqCH,GACjDI,EAAW,YAAoBD,EAAUE,MACzCC,EAAQH,EAAUE,KAAKhF,OACzB+E,EAASG,OAAkC,SAACC,EAAKC,GAAI,OAAK,+BAAMD,GAAG,KAAGO,EAAON,GAAQA,GAAI,EAAK,CAAC,GAC/F,KAEJ,MAAO,CACLc,4BAAoD,QAAxB,EAAmB,QAAnB,EAAApB,EAAUA,iBAAS,eAAG,UAAE,eAAEQ,cACtDP,SAAAA,EACAE,MAAAA,EACAI,WAAYP,EAAUO,WACtBO,WAjCF,SAAoBJ,GAClB,GAAKA,aAAI,EAAJA,EAAMxF,OAAX,CAGA,IAAMmG,EAA6B,GAEnCX,EAAKY,QAAQ,SAAAjI,GACX,IAAMkI,EAAMX,EAAOvH,GAEf4H,EAAaO,QAAQC,IAAIF,KAG7BF,EAAeK,KAAKrI,GACpB4H,EAAaO,QAAQG,IAAIJ,GAC3B,GAEKF,EAAenG,QAGpBiG,EAAY,SAAAS,GAAC,kBAAUA,GAAC,EAAK,UAA4BP,EAAgB5B,GAAYK,IAAIkB,EAAQpB,aAAW,EAjBpG,CAkBV,EAeF,C,6DCjIA,SAASiC,EAAiBC,GACxB,OAAOA,EAAWhC,IAAI,SAAAzG,GAAG,OAAIA,EAAIiG,UAAU,GAAEyB,KAAK,IACpD,CAGM,SAAUgB,EACdC,EACAC,EACAC,GAEA,IAAMJ,EAAaK,MAAMC,QAAQJ,GAAeA,EAAc,CAACA,IAE/D,IAAAK,WAAU,WACRP,EAAWR,QAAQ,SAAAjI,IACjB,OAAgBA,EAAIiG,WAAY2C,EAAcC,EAChD,EACF,EAAG,CAAEL,EAAiBC,GAAaG,EAAcC,GACnD,C,wECnBMI,EAAmB,I,iHC2BnB,SAAUC,EACd3C,EACA4C,EACAC,EACAC,EACAC,EACAC,GAEA,I,ID1BgC5B,EAC1B6B,ECyB+C,G,GAAX,IAAAC,UAAS,G,EAAE,E,o4BAA7CC,EAAY,KAAEC,EAAe,KAE/BC,EAAcT,EAcdU,GAAW,OAZjB,SAAgBC,GACd,IAAKvD,EACH,OAAO,KAET,IAAMwD,EAAUxD,EAAWuD,GAE3B,OAAKC,EAGEA,EAAQ7B,IAFN,IAGX,EAIEmB,EACAC,GAwCF,ODrFgC3B,ECwDd,CAChBqC,cATF,WACE,GAAKb,GAAc5C,GAAesD,EAIlC,OADAF,EAAgB,SAAAM,GAAU,OAAIA,EAAa,CAAC,GACrCL,EAAYC,EAASK,WAC9B,EAIEC,WAAWN,aAAQ,EAARA,EAAUK,YACrBhD,WAAY2C,aAAQ,EAARA,EAAU3C,WACtBqC,gBAAAA,GD3DIC,EAAe,WACnB,IAAI7B,EAAQT,WAAZ,CAGA,GAAKS,EAAQ4B,gBAON,CACL,IAAQA,EAAoB5B,EAApB4B,gBAKR,GAJ4BA,EAAgBa,wBAAwB1I,OAAS6H,EAAgBc,UAEzEd,EAAgBe,aAAerB,EAGjD,MACH,MAVC,GAJ4BsB,OAAOC,YAAcC,SAASC,gBAAgBL,UAEtDI,SAASC,gBAAgBJ,aAAerB,EAG1D,OAWJtB,EAAQqC,eAnBA,CAoBV,GAEA,IAAAhB,WAAU,WACR,IAAM2B,EAAWC,EAAA,WAAwBpB,EAAc,KAEjDD,EAAkB5B,EAAQ4B,iBAAmBgB,OAKnD,OAHI5C,EAAQwC,SACVZ,EAAgBsB,iBAAiB,SAAUF,GAEtC,kBAAMpB,EAAgBuB,oBAAoB,SAAUH,EAAS,CACtE,EAAG,CAAEhD,EAAQwC,QAASxC,EAAQqC,cAAerC,EAAQ4B,mBC6BrD,IAAAP,WAAU,WACHa,GAGDA,EAASkB,oBAAsB5B,IACjCS,IACAD,EAAgB,SAAAM,GAAU,OAAIA,EAAa,CAAC,GAEhD,EAAG,CAAEJ,aAAQ,EAARA,EAAUkB,mBAAoB5B,KAEnC,IAAAH,WAAU,W,QACR,IAAKa,aAAQ,EAARA,EAAU5D,aAAe2E,EAAA,aAA0BxB,GAAxD,CAGA,IAAM4B,IAAoE,QAA/B,EAAmB,QAAnB,EAAAnB,EAAS5D,kBAAU,eAAE1F,kBAAU,eAAE0K,OAAO,EAAG,IAElFD,IAAoBE,EAAA,eAA+BF,IAAoBE,EAAA,eAG3E9B,EAAQM,EAAcG,EAAS5D,WAPvB,CAQV,EAAG,CAAC4D,aAAQ,EAARA,EAAU5D,aAEP,CACLa,MAAO+C,aAAQ,EAARA,EAAU/C,MACjBqD,WAAWN,aAAQ,EAARA,EAAUK,YACrBA,WAAYL,aAAQ,EAARA,EAAUK,WACtBhD,WAAY2C,aAAQ,EAARA,EAAU3C,WACtBiE,WAAYtB,aAAQ,EAARA,EAAUsB,WACtBC,sBAAuBvB,aAAQ,EAARA,EAAUuB,sBAErC,C,mbCrGM,SAAUC,EAAelD,GAC7B,I,IAAqF,G,EAAvD,UAAc,kBAAM,gBAA8B,EAAE,I,EAAG,E,unBAA7EmD,EAAK,KAEPC,GAAcC,EAFK,MAEMF,GAE/B,OAAKC,GAAgBpD,EAGd,GAAP,O,yWAAA,CAAYoD,GAAW,gCAAOpD,GAAO,CAAEsD,QAAQ,MAFtCF,CAGX,C,+jBCJMpN,EAAY,kCAEZuN,EAAY,SAAH,OAAM/M,EAAS,EAATA,UAAS,OAC5B,wBAAMA,UAAWA,GAAS,IAAe,EAE3C,SAASgN,EAAqBxL,GAC5B,IAAQE,EAAeF,EAAfE,WAER,GAAKA,EAGL,OAAIA,EAAWuL,MAAQvL,EAAWwL,QACzBC,EAAA,cAAuBzL,EAAWuL,KAAO,IAAMvL,EAAWwL,QAAQE,UAAU,EAAG,IAEpF1L,EAAWuL,KACNvL,EAAWuL,KAAKI,MAAM,KAAK,QADpC,CAEF,CA6BM,SAAUC,EAAsB5N,G,QAC9B6N,EAAqBpM,EAAA,UAAuBzB,EAAM8B,SAAU9B,EAAM+B,aAElE+L,EAAwC,QAAxB,EAAA9N,EAAM8B,SAASiM,iBAAS,eAAE3L,MAE1C4L,EAhCR,SAAwBlM,GACtB,IAAKA,EAASmM,oBACZ,MAAO,GAET,IAAMC,EAAM,IAAIzJ,KACVuJ,EAAcxJ,EAAA,oBAA6B1C,EAASmM,qBAG1D,OAAIzJ,EAAA,WAAoBwJ,EAAaxJ,EAAA,WAAoB0J,EAAK,EAAG,UACxD,GAEF1J,EAAA,UAAmBwJ,EAC5B,CAoBsBG,CAAenO,EAAM8B,UAEzC,OACE,uBAAKxB,UAAWN,EAAMoO,mBAEjBpO,EAAMqO,gBAAkBR,GACzB,iCACqC,QAAlC,EAAA7N,EAAM8B,SAASwM,2BAAmB,eAAEC,OACnC,gCACE,uBAAKjO,UAAWN,EAAMwO,0BACpB,gBAACC,EAAA,EAAe,OAElB,0CAGF,gBAACtI,EAAA,EAAI,CAACrG,UAAWA,EAAWsG,OAAO,YAAYkD,QAAS,CAAEoF,KAAMpB,EAAqBtN,EAAM8B,aAG7F,gBAACuL,EAAS,CAAC/M,UAAWN,EAAM2O,sBAKF,iBAAtB3O,EAAM4O,aACZ,gBAACzI,EAAA,EAAI,CAACrG,UAAWA,EAAWsG,OAAO,SAASkD,QAAS,CAAEuF,WAAY7O,EAAM4O,eAI1Ed,EAAgB,GACf,gCACE,gBAACT,EAAS,CAAC/M,UAAWN,EAAM2O,qBAC5B,gBAACxI,EAAA,EAAI,CAACrG,UAAWA,EAAWsG,OAAO,YAAYkD,QAAS,CAAEuF,WAAYf,QAKvEE,GACD,gCACE,gBAACX,EAAS,CAAC/M,UAAWN,EAAM2O,qBAC5B,gBAACxI,EAAA,EAAI,CAACrG,UAAWA,EAAWsG,OAAO,cAAckD,QAAS,CAAEwF,QAASd,MAK/E,C,qGCvGA,UAAgB,mBAAqB,SCK/B,SAAUe,KACd,OACE,gCACE,gBAAC,IAAmB,MACpB,uBAAKzO,UAAU,QACb,uBAAKA,UAAS,wDAAmD,0BAIzE,C,oDCIM0O,GAAY7O,EAAA,mBADA,4BAkBL8O,GAAsB,CACjCC,mBAAkB,SAACC,EAAkCC,G,gBAEjDC,EASED,EATFC,gBACAC,EAQEF,EARFE,SACAC,EAOEH,EAPFG,SACAC,EAMEJ,EANFI,eACAC,EAKEL,EALFK,YACAC,EAIEN,EAJFM,qBACAC,EAGEP,EAHFO,kBACAC,EAEER,EAFFQ,cACAC,EACET,EADFS,kBAGI7O,EAAgB,CACpBiB,GAAIkN,EAAYrN,SAASG,GACzBsL,KAAM4B,EAAYrN,SAASyL,KAC3BO,cAA6C,QAA9B,EAAAqB,EAAYrN,SAASiM,iBAAS,eAAE3L,MAC/C0N,WAAuC,QAA3B,EAAAX,EAAYrN,SAASO,cAAM,eAAED,MACzC2N,iBAAmD,QAAjC,EAAAZ,EAAYrN,SAASS,oBAAY,eAAEH,MACrD4N,UAAqC,QAA1B,EAAAb,EAAYrN,SAASQ,aAAK,eAAEF,MACvC6N,oBAA6D,QAAxC,EAAAd,EAAYrN,SAASwM,2BAAmB,eAAEC,OAG3DtN,EAAqC,CACzCiP,SAAU,YACVC,OAAQ,cACRC,cAAe,YAGXxM,EAA2B,GAEjC,IAAKyL,EACH,OAAOzL,EAET,GAAIwL,EAAKiB,QACP,OAAOzM,EAET,IAAM/B,EAAUJ,EAAA,UAAuB0N,EAAYrN,SAAUqN,EAAYpN,aACnEuO,EAAmBC,GAAA,iCAA4CpB,EAAYpN,aAC3EyO,EAAwBpB,EAAKqB,iBAAmBrB,EAAKsB,YAAcJ,EAqJzE,OAnJKhB,IACCH,EAAYwB,gBACd/M,EAAQoG,KAAK,CACX7I,MAAO6N,GAAU,WACjBpO,QAASuO,EAAYwB,eACrBnQ,QAAS,WACTF,UAAYiP,EAAyC,GAA9B,4BACvBqB,QAASrB,EACTvO,cAAAA,EACAC,iBAAkB,OAAF,wBACXA,GAAgB,CACnB4P,WAAY,cAKdL,GACF5M,EAAQoG,KAAK,CACX7I,MAAO6N,GAAU,UACjBpO,QAASkQ,GAAA,eAAiC,CACxCC,WAAY,WACZC,SAAU7B,EAAYrN,SAASG,KAEjCzB,QAAS,iBACTF,UAAYiP,EAAyC,GAA9B,4BACvBqB,QAASrB,EACTvO,cAAAA,EACAC,iBAAkB,OAAF,wBACXA,GAAgB,CACnB4P,WAAY,WACZV,OAAQ,gBAKVP,GACFhM,EAAQoG,KAAK,CACX7I,OAAO,UACP8P,KAAMpB,EACNqB,cAAc,IAGlBtN,EAAQoG,KAAK,CACX7I,OAAQqP,GAAyBxB,GAAU,SAC3CmC,QAASX,GAAyBxB,GAAU,SAC5CpO,QAAS,CACPwQ,YAAa,UACbC,OAAQ,gBACRjC,KAAM,CAACD,EAAYrN,SAASG,IAC5BqP,OAAQ,CAAEP,WAAY,aAExBvQ,QAAS4O,EAAKqB,eAAiB,WAAoB,YACnDnQ,UAAYiP,EAA4D,GAAjD,+CACvBqB,QAASrB,EACTvO,cAAAA,EACAC,iBAAkB,OAAF,wBACXA,GAAgB,CACnB4P,WAAY,WACZU,aAAc,aAKf1P,GACH+B,EAAQoG,KAAK,CACX7I,MAAO6N,GAAUS,EAAc,YAAc,UAC7C+B,QAAS,WACPhC,GAAgBC,GAChBC,GAAqB,GACrBP,EAAYsC,QACThC,EACD,WACEC,GAAqB,GACrBgC,GAAA,gBAA8B1Q,EAAe,OAAF,wBACtCC,GAAgB,CACnB4P,WAAY,YACZc,WAAYlC,EAAc,SAAuB,QACjDW,cAAe,gBAEnB,EACA,WACEV,GAAqB,GACrBF,EAAeC,EACjB,EAEJ,EACAjP,QAASiP,EAAc,iBAA0B,WACjDnP,UAAYiP,EAER,GAFgB,6BACME,EAAc,eAAiB,OAAM,SAE/DmB,QAASrB,EACTqC,YAAajC,IAIb9N,IACF+B,EAAQoG,KAAK,CACX7I,MAAO6N,GAAU,QACjBpO,QAAS,CACPwQ,YAAa,cACbC,OAAQ,4BACRjC,KAAM,CAACD,EAAYrN,SAASG,KAE9BzB,QAAS,WACToQ,QAAQ,EACR5P,cAAAA,EACAC,iBAAkB,OAAF,wBACXA,GAAgB,CACnB4P,WAAY,cAIhBjN,EAAQoG,KAAK,CACX7I,MAAO6N,GAAU,UACjBpO,QAAS,CACPwQ,YAAa,cACbC,OAAQ,8BACRjC,KAAM,CAACD,EAAYrN,SAASG,KAE9BzB,QAAS,aACTF,UAAW,cACXsQ,QAAQ,EACR5P,cAAAA,EACAC,iBAAkB,OAAF,wBACXA,GAAgB,CACnB4P,WAAY,kBAK0B,QAAxC,EAAA1B,EAAYrN,SAASwM,2BAAmB,eAAEC,QAC5C3K,EAAQoG,KAAK,CACX7I,MAAO6N,GAAU,QACjBpO,QAAS,CACPwQ,YAAa,cACbC,OAAQ,4BACRjC,KAAM,CAACD,EAAYrN,SAASG,KAE9B2O,QAAQ,EACR5P,cAAAA,EACAC,iBAAkB,OAAF,wBACXA,GAAgB,CACnB4P,WAAY,cAKXjN,CACT,GCjOF,UAAgB,gBAAkB,S,ogCC0C5B,SAAUiO,GAAe7R,GAC7B,IAAQsP,GAAa,EAAAwC,GAAA,KAAbxC,SACAyC,GAAmB,EAAAC,EAAA,KAAnBD,eACAtB,GAAmB,EAAAwB,EAAA,GAAY,MAA/BxB,eAGiE,KAAjC,WAAezQ,EAAMyP,aAAY,GAAjEA,EAAW,KAAED,EAAc,KACsC,KAArB,YAAe,GAAM,GAAjEG,EAAiB,KAAED,EAAoB,KAE/C,YAAgB,kBAAMF,EAAexP,EAAMyP,YAAY,EAAE,CAACzP,EAAMyP,cAEhE,IAAMF,GAAW,OAAc,QAE/B,GAAIvP,EAAMkS,mBACR,OAAO,gBAACnD,GAAqB,MAE/B,IAAMoD,EAAcnS,EAAM8B,SAASqQ,YAE7BvO,EAA2BqL,GAAoBC,mBAAmBlP,EAAO,CAC7EqP,gBAAiBrP,EAAM+B,YAAYsN,gBACnCC,SAAAA,EACAC,SAAAA,EACAC,eAAAA,EACAC,YAAAA,EACAC,qBAAAA,EACAC,kBAAAA,EACAC,cAAe5P,EAAM4P,cACrBC,kBAAmB7P,EAAM6P,kBACzBY,eAAAA,EACAC,UAAWqB,EAAeK,EAAA,qBAC1B/B,QAAS0B,EAAeK,EAAA,qBAGpBlF,EAAclN,EAAMqS,iBAE1B,OACE,gCACE,gBAAC5O,EAAA,EAAY,CACXF,QAASvD,EAAM8B,SAASyL,KACxB7J,OAAQ1D,EAAM8B,SAAS4B,OACvBC,YAAa3D,EAAM2D,YACnBC,QAASA,EAAQJ,QAAUI,EAC3B8C,yBAAyB,uBACzB5C,kBAAkB,EAAA4B,EAAA,GAAgB1F,EAAM8B,SAASyL,KAAM,KACvD/H,iBAAkB,WAAF,OACd,gBAACoI,EAAqB,CACpB9L,SAAU9B,EAAM8B,SAChBC,YAAa/B,EAAM+B,YACnBqM,iBAAiB,wCACjBI,yBAA0B,mBAC1BG,mBAAmB,OACnBC,YAAa5O,EAAM4O,aACnB,OAGFuD,MAAiBjF,aAAW,EAAXA,EAAa1J,UAChC,uBAAKlD,UAAU,uBAENN,EAAM8B,UAAa9B,EAAMsS,mBAAqBtS,EAAMuS,UAChD,gBAAC,KAAkB,MAG1B,uBAAKjS,UAAU,QACb,gBAACkS,EAAA,GAAW,CAACtF,YAAaA,OAI7BiF,GAAe,qBAAG7R,UAAU,QAAQ6R,IAKjD,C,sfC3FM,SAAUM,GAA2BzS,GACzC,I,IAAQ0S,EAAuE1S,EAAvE0S,eAAgBC,EAAuD3S,EAAvD2S,YAAaT,EAA0ClS,EAA1CkS,mBAAuBU,EAAc,GAAK5S,EAAzE,uDAE0E,G,EAAxB,a,EAAwB,E,s4BAAxE6S,EAAmB,KAAEC,EAAsB,KA2BnD,OAAIZ,EACK,gBAACa,GAAA,EAAgB,CAACC,eAAgBhT,EAAMiT,SAAWjT,EAAMkT,cAE7DlT,EAAMiT,QAIT,gBAAC,MAAiB,iBACZL,EAAc,CAClBC,oBAAqBA,EACrBF,YAnCuB,SAACQ,GAC1B,IAAMC,EAAQpT,EAAMqC,OAAOgR,UAAU,SAAAC,GAAC,OAAIA,EAAErR,GAAGC,aAAeiR,EAAM/F,OAAOnL,GAAGC,UAAU,GAExF4Q,EAAuBM,GAEnB7G,GAAA,aAA0BoG,IAC5BA,EAAYS,EAChB,EA6BIG,UA3Bc,SAACJ,GACjBL,EAAuB,MAEvB,IAAQ1F,EAAiB+F,EAAjB/F,OAAQoG,EAASL,EAATK,KAEVC,EAAWzT,EAAMqC,OAAOgR,UAAU,SAAAC,GAAC,OAAIA,EAAErR,GAAGC,aAAekL,EAAOnL,GAAGC,UAAU,GAC/EwR,EAAW1T,EAAMqC,OAAOgR,UAAU,SAAAC,GAAC,OAAIA,EAAErR,GAAGC,aAAesR,EAAKvR,GAAGC,UAAU,GAE9EqK,GAAA,aAA0BmG,GAK/BA,EAAee,EAAUC,GAJvB,aAAuB,IAAIC,GAAA,EAAS,oFAKxC,EAcIC,eAAgB,gBAChBC,mBAAoBtT,GAAA0C,EAAA,IACpB6Q,sBAAuB9T,EAAM8T,yBAVxB,gBAACC,GAAA,GAAS,iBAAKnB,GAa1B,C,4BChEM,GAAY,+BAEZ,SAAUoB,KACd,OACE,gBAAC,aAAiC,CAACzF,MAAO,IACxC,gBAAC0F,GAAA,EAAU,KACT,gBAACA,GAAA,QAAgB,CAAC3N,IAAK4N,GAAA,0CAEvB,gBAACD,GAAA,UAAkB,KAAC,gBAAC9N,EAAA,EAAI,CAACC,OAAO,aAEjC,gBAAC6N,GAAA,OAAe,KAAC,gBAAC9N,EAAA,EAAI,CAACC,OAAO,WAItC,C,uJCHA,IAAM,GAAYjG,EAAA,mBAAiC,sBAiE7C,SAAUgU,GAAcC,EAAoBC,EAAiBjE,GACjEsB,GAAA,gBAA8B,CAAEzP,GAAIoS,EAASD,WAAAA,GAAc,CACzDlE,SAAU,eACVC,OAAQ,WACRU,WAAY,UACZT,cAAAA,GAEJ,CAEO,IAAMkE,GAAiB,CAC5BtN,SAAU,KACVC,UAAW,CACTI,QAASkN,GAAA,I,uGC/Cb,IACM,GAAYpU,EAAA,mBADA,sBAWZ,SAAUqU,GAAaxU,G,kCACrByU,GAAW,UACXC,GAAS,SAETC,EAAS,kBAA6BC,EAAA,YACtC7S,EAAc,kBAAwC8S,EAAA,iBAC5D,IAAuD,EAAAC,EAAA,MAA/ClF,GAAa,GAAbA,cAAemF,GAA2B,GAA3BA,4BACfhD,IAAmB,EAAAC,EAAA,KAAnBD,eAEFiD,GAAa,mBACD,QAAhB,EAAAjT,EAAYyG,YAAI,eAAE6G,kBAAmB4F,EAAA,aAA4BlT,EAAYyG,KAAK0M,aAG9E3C,GAAY,kBAChBvS,EAAMsS,kBACN6C,EAAA,OAA4BnV,EAAMsS,mBAG9B8C,GAAiB,kBACrBpV,EAAMsS,kBACN6C,EAAA,iBAAsCnV,EAAMsS,iBAAkC,QAAhB,EAAAvQ,EAAYyG,YAAI,eAAEvG,KAG5EoT,GAA6B,kBACjCD,GAAetM,cACfqM,EAAA,mBAA2D,QAAnB,EAAAC,GAAe5M,YAAI,eAAE8M,iBAGzDC,IAAwC,QAAhB,EAAAxT,EAAYyG,YAAI,eAAE6G,kBAE3CrP,EAAMsS,kBAAoB+C,GAA2BvM,gBADrB,QAA/B,EAAAuM,GAA2B7M,YAAI,eAAEvG,IAGjCuT,GAAY,kBAChBD,IACAE,EAAA,wBAAsE,QAA/B,EAAAJ,GAA2B7M,YAAI,eAAEvG,KAGlEyT,IAAqB,EAAAC,EAAA,GAAoB,CAC/CC,gBAAiB,oBACjBC,IAAK7V,EAAM8V,YACXC,iBAAkB/V,EAAMgW,UAHlBN,iBAMFO,GAAkBjW,EAAMgW,QAC1BE,EAAA,oBAAmClW,EAAMoU,WAAYpU,EAAMgW,SAC3DE,EAAA,cAA6BlW,EAAMoU,YAEjC+B,GAA2BnW,EAAMgW,QACnCE,EAAA,+BAA8ClW,EAAMoU,WAAYpU,EAAMgW,SACtEE,EAAA,yBAAwClW,EAAMoU,YAE5CtS,GAAW,kBAA+BmU,IAC1CG,GAAqB,kBAA+BD,IAEpDE,GDhFF,SACJvU,EACAC,EACAiU,GAEA,IAAMM,GAAe,EAAAC,GAAA,GAAgB,CAAErG,SAAU,eAAgC8F,QAAAA,IAEjF,OAAKvU,EAAA,UAAuBK,EAAUC,GAqC/B,OAAP,wBACKuU,GAAY,CACfE,gBApCsB,SAACC,EAAmBnN,GAC1C,I,EAAQoN,EAAeC,EAAA,mBAA6BF,GAA5CC,WAEFE,EAA2B,CAC/BzV,MAAO,GAAU,sBACjByP,QAAQ,EACRpQ,QAAS,aACTI,QAAS,CACPwQ,YAAa,cACbC,OAAQ,yCACRjC,KAAM,CAAEqH,EAAMxU,GAAIH,EAASG,IAC3BqP,OAAQ,CAAE1P,OAAQ6U,EAAM7U,SAE1BtB,UAAW,cACXW,iBAAkB,CAChBkP,OAAQ,WACRU,WAAY,gBACZX,SAAU,mBACVE,cAAe,WACfuB,WAAY,eAEd3Q,cAAe,CACbiB,GAAIwU,EAAMxU,GACVmS,WAAYtS,EAASG,IAEvB4U,MAAO,UAGT,OAAKH,EAGE,GAAP,O,gDAAYJ,EAAaE,gBAAgBC,EAAOnN,K,ojBAAQ,CAAEsN,IAFjD,CAACA,EAGZ,IAlCSN,CAwCX,CCgC8BQ,CAA4BhV,GAAS0G,KAAMzG,EAAYyG,KAAMxI,EAAMgW,UAE/F,OAAqBlU,GAAUwS,IAE/B,IAAMyC,GAAmB,SAACtL,GACxB,OAAOzL,EAAMgW,QACTE,EAAA,0BAAyClW,EAAMoU,WAAYpU,EAAMgW,QAASvK,GAC1EyK,EAAA,oBAAmClW,EAAMoU,WAAY3I,EAC3D,EAEMuL,GAAY,mBACA,QAAhB,EAAAjV,EAAYyG,YAAI,eAAEvG,KAClBiU,EAAA,yBAAwClW,EAAMoU,WAA4B,QAAhB,EAAArS,EAAYyG,YAAI,eAAEvG,KAGxE6I,GAAY,SAACW,GACjB,aAAgBgJ,EAAhB,CAA0BsC,GAAiBtL,GAC7C,EAEA,IAA+C,OAA4BsL,GAAkBjM,IAA9EzI,GAAM,GAAboG,MAAeqD,GAAO,GAAPA,QAASjD,GAAU,GAAVA,YAEhC,EAAAoO,EAAA,GAAc5U,IAGd,IC9GAoG,GAE6D,GAArDyO,GAAgBC,G,MD4GiD,G,05BAAA,EC9GzE1O,GD8GkEpG,G,IC5GpB,IAAA+I,Y,GAAe,K,w4BAArD8L,GAAc,MAAEC,GAAiB,OAEzC,IAAAxM,WAAU,WACHuM,KAGDzO,GAAMjF,SAAW0T,GAAe1T,QA/BxC,SAAsB4T,EAAoBC,GACxC,IAAIC,GAAU,EAEd,GAAIF,EAAK5T,SAAW6T,EAAK7T,OACvB,OAAO,EAET,IAAK,IAAI+T,EAAI,EAAGA,EAAIH,EAAK5T,OAAQ+T,IAC/B,GAAIH,EAAKG,GAAGtV,KAAOoV,EAAKE,GAAGtV,GAAI,CAC7BqV,GAAU,EACV,KACD,CAGH,OAAOA,CACT,CAiBkDE,CAAa/O,GAAOyO,MAChEC,GAAkB,KACtB,EAAG,CAAC1O,KAEG,CAAEyO,GAAgBC,KDkGgD,GAAjEM,GAAe,MAAEC,GAAkB,OAE3C,EAAAC,EAAA,GAAa,CAAE1V,GAAIjC,EAAMoU,WAAYwD,IAAK,YAAa5B,QAAShW,EAAMgW,WACtE,EAAA6B,EAAA,GAAmBC,EAAA,uBAAuC,CACxDC,QAASjW,GAAS0G,KAClBwP,cAAe,CACbC,cAAe,GACfC,YAAa,YACbC,kBAAmB,mBAErBC,cAAeC,EAAA,mBAA2B,CAAEC,uBAAuB,IACnEC,eAAe,KAGjB,IAyCMC,KAAoBnW,IAA4B,IAAlBA,GAAOmB,OAErC,GAAkB,SACtBiT,EACAgC,GAEE,I,EADFnP,EAAA,uDAAkC,CAAC,EAEnC,OAAOoP,EAAA,aAA8BjC,EAAO,OAAF,wBACrCnN,GAAO,CACVqP,UAAW3Y,EAAMoU,WACjBwE,QAASC,EAAA,WACT7C,QAAShW,EAAMgW,QACfF,YAAa9V,EAAM8V,YACnB2C,SAAAA,EACAK,gBAAgC,QAAhB,EAAA/W,EAAYyG,YAAI,eAAE6G,oBAAqBrP,EAAMgW,UAEjE,EAEM+C,KAAuC,QAAhB,EAAAhX,EAAYyG,YAAI,eAAE6G,oBAAqB2H,GAAUlO,aAGxEkQ,GAAoB3W,cAAM,EAANA,GAAQ4W,KAAK,SAAA3F,GAAI,MAAC,OAA+B,QAA/B,EAAAqD,EAAA,mBAA6BrD,UAAE,eAAEoD,UAAU,GACjFzD,GAAUxR,EAAA,UAAuBK,GAAS0G,KAAMzG,EAAYyG,MAE5D0Q,GACJ7W,IAAUN,EAAYyG,MAAQmM,EAAOnM,KAcjC0E,IAAc,EAAAF,EAAA,GAAe,CAAEO,KAAmB,QAAb,EAAAzL,GAAS0G,YAAI,eAAE+E,OAE1D,OACE,gBAAC4L,EAAA,WAA4B,CAAC5K,OAAuB,QAAhB,EAAAxM,EAAYyG,YAAI,eAAE6G,kBAAmBgH,IACxE,uBAAK/V,UAAU,iBACb,gBAACuR,GAAc,CACb/P,SAAUA,GAAS0G,KACnBzG,YAAaA,EAAYyG,KACzBiH,YAA2B,QAAd,EAAAuH,GAAUxO,YAAI,eAAEiH,YAC7BgC,OA7DO,SAAC2H,EAAuBC,EAAuBtO,G,MACtDuO,EAAMF,EACRlD,EAAA,iBACAA,EAAA,mBAOJ,UAAazB,EAAU6E,EAAItZ,EAAMoU,WAA4B,QAAhB,EAAArS,EAAYyG,YAAI,eAAEvG,GAAIoX,EALrD,WACZtO,IACA2J,EAAO6E,MAAM,GAAUH,EAAe,cAAgB,iBACxD,GAGF,EAmDQzI,eAAgBqI,IAAqB,GAAgBA,IAAmB,GACxE9G,oBAAqBpQ,GAAS0G,OAAS0Q,KAAoBH,GAC3DpV,cAAegR,EAAOnM,MAAQmM,EAAOnM,KAAK7E,YAC1C0O,eAAgB,WAAF,OAAQrS,EAAMwZ,gBAAkB,KAAOtM,EAAW,EAChEqF,UAAWA,GAAU/J,KACrBsN,YAAa9V,EAAM8V,YACnBxD,iBAAkBtS,EAAMsS,iBACxB1C,cAAeA,GACfC,kBAAmBkF,GAAyC,QAAb,EAAAjT,GAAS0G,YAAI,eAAE5G,OAAqB,QAAb,EAAAE,GAAS0G,YAAI,eAAEvG,IACrF2M,YAAanN,EAAA,gBAA6B2U,GAAmB5N,QAE/D,uBAAKlI,UAAU,QACXkY,GAoBI,gBAACxE,GAAkB,MAlBrB,gBAACvB,GAA0B,CACzBpQ,OAAQoV,IAAmBpV,GAC3B2S,WAAYA,GAAWxM,KACvB4L,aAActS,GAAS0G,MAAQ1G,GAAS0G,KAAKvG,GAC7C0Q,YA5GM,SAACS,GACnB,IAAMqD,EAAQpU,GAAO+Q,GAEjBqD,GACFtC,GAAcnU,EAAMoU,WAAYqC,EAAMxU,GAAI,WAC9C,EAwGcyQ,eAtGS,SAAC+G,EAAgBC,GACtC,GAAID,IAAWC,EAAf,CAGA,IAAMjD,EAAQpU,GAAOoX,GAErB,GAAKhD,EAAL,CAGA,MAA2CkD,EAAA,UAAsBtX,GAAQoX,EAAQC,GAAzExC,EAAc,EAAdA,eAAgB0C,EAAc,EAAdA,eACxBlC,GAAmBR,GAEnB/C,GAAcnU,EAAMoU,WAAYqC,EAAMxU,GAAI,eAM1C,UAAawS,EAAUyB,EAAA,gBAA+BlW,EAAMoU,WAAYwF,EAAgB,KAJxE,WACdlC,GAAmB,KACrB,GATQ,CALA,CAiBV,EAoFczE,QAASA,GACTf,oBAAqBgH,GACrBW,gBAAiB,SAACvG,EAAGwG,GAAI,OAAK,GAAgBxG,GAAG,EAAOwG,EAAK,EAC7DC,aAA6B,QAAhB,EAAAhY,EAAYyG,YAAI,eAAE6G,iBAC/B2K,iBA7CW,SAACpZ,GACxB,IAAMqZ,EAAc,eAA2BrZ,GACzC0Q,EAAyB,MAAhB2I,EAAsB,CAAEA,YAAAA,GAAgB,CAAC,EAExD,MAAO,CACL7I,YAAa,YACbC,OAAQ,sBACRC,OAAAA,EAEJ,EAqCc4I,uBAAwBjH,GACxBa,sBAAuB9T,EAAM8V,YAAc,KAAON,GAAUhN,KAC5D0K,aAAa,EACbnB,eAAgBA,GAChBoI,2BAA4B,SAAAC,GAAW,OAAIC,EAAA,6BAA8CD,EAAY,EACrG1E,iBAAkBA,OAKxB5J,IAAWjD,KAAe,gBAACyR,EAAA,EAAoB,CAACzR,WAAYA,GAAYiC,UAAWA,MAI7F,C,+JEvPM,SAAU6K,EAAoBrM,G,UAClC,EAAkEA,GAAW,CAAC,EAAtEsM,EAAe,EAAfA,gBAAiBC,EAAG,EAAHA,IAAK0E,EAAe,EAAfA,gBAAiBxE,EAAc,EAAdA,eAE/C,GAA6B,SAArBzG,EAAQ,EAARA,SAAUgC,EAAM,EAANA,OAClB,GAAuC,IAAAkJ,GAAkB5E,EAAiB2E,GAAlEE,EAAY,EAAZA,aAAcC,EAAY,EAAZA,aACtB,GAAmD,OAAY,MAAvDC,EAAmB,EAAnBA,oBAAqBC,EAAiB,EAAjBA,kBAC7B,GAA2D,SAAnD7I,EAAc,EAAdA,eAA0B8I,EAAoB,EAA9BC,SAClBC,EAAuBhJ,EAAe,uBACtCiJ,EAAqBjJ,EAAe,qBAEpC4C,EAAS,kBAA6B,cACtC5S,EAAc,kBAAkC,mBAChDiT,EAAa,mBACD,QAAhB,EAAAjT,EAAYyG,YAAI,eAAE6G,kBAAmB,eAA4BtN,EAAYyG,KAAK0M,aA4BpF,MAAO,CACL+F,8BARCL,GACDC,GACAlG,EAAO7L,cACP/G,EAAY+G,iBACM,QAAhB,EAAA/G,EAAYyG,YAAI,eAAE6G,kBAAmB2F,EAAWlM,cAKlD4M,iBAAkB,CAChBwF,YAAa,SACbC,kBA7BJ,SAA2B1E,G,MACzB,MAAM,WAAYA,EAUdV,KAAmC,QAAhB,EAAAhU,EAAYyG,YAAI,eAAE6G,iBAChC,KAEF,qBAAqCoH,EAAM2E,OAAQ,CAAEvF,IAAAA,IAZnD,IAaX,EAeIvG,SAAAA,EACA+L,iBAAiB/J,aAAM,EAANA,EAAQgK,OACzBZ,aAAAA,EACAD,aAAAA,EACA9W,YAAwB,QAAX,EAAAgR,EAAOnM,YAAI,eAAE7E,YAC1BqR,WAAYA,EAAWxM,KACvB+S,yBAA0B,6BAC1BC,8BAA+B,kCAC/BC,2BAA4B,+BAC5BC,sBAAuBf,EACvBgB,uBAAwB,KACxBZ,qBAAAA,EACAC,mBAAAA,GAGN,C,+ECrFA,SAASY,EAAgBC,GACvB,OAAKA,EAGDpR,MAAMC,QAAQmR,GACTA,EAAQC,OAAO,SAAAC,GAAC,QAAMA,IAAM,YAAoBA,IAAM,WAAmBA,GAAG,GAEjF,SAAUF,EACLA,EAAQrT,KAAKsT,OAAO,SAAAC,GAAC,QAAMA,IAAM,YAAoBA,IAAM,WAAmBA,GAAG,GAEnF,GARE,EASX,CAUM,SAAU9E,EAAc4E,GAA+C,IAA/BvS,EAAA,uDAA6B,CAAC,EACpE0S,EAAWJ,EAAgBC,GAASzT,IAAI,SAAAkL,GAAC,OAAIA,EAAErR,EAAE,IAEvD,QACE+Z,EACA,SAAAC,GAAG,OAAI,qBAA+BA,EAAK3S,EAAQiR,gBAAgB,EACnE,KAEJ,CAEM,SAAU2B,IAAiD,IAA/B5S,EAAA,uDAA6B,CAAC,EAStDF,GAAe,QAAyB,CAAElB,WARlD,SAAoB+T,GAClB,OAAO,qBAA+BA,EAAK3S,EAAQiR,gBACrD,IAMQnR,WAER,MAAO,CAAE+S,aANT,SAAsB1T,GACpB,OAAOW,EAAWwS,EAAgBnT,GAAOL,IAAI,SAAAkL,GAAC,OAAIA,EAAErR,EAAE,GACxD,EAKF,C","sources":["file:///app/packages/libs/shared/src/apps/calendar/components/coming-soon-tag/coming-soon-tag.scss","file:///app/packages/libs/shared/src/apps/calendar/components/coming-soon-tag/ComingSoonTag.tsx","file:///app/packages/libs/shared/src/apps/calendar/components/generic-calendar-date/generic-calendar-date.scss","file:///app/packages/libs/shared/src/apps/calendar/components/generic-calendar-date/GenericCalendarDate.tsx","file:///app/packages/libs/shared/src/apps/playlists/utils/PlaylistHelper.ts","file:///app/packages/libs/shared/src/components/back-button/BackButton.tsx","file:///app/packages/libs/shared/src/components/banner-header/banner-header.scss","file:///app/packages/libs/shared/src/components/banner-header/BannerHeader.tsx","file:///app/packages/libs/shared/src/errors/handlers/HttpErrorHandlers.ts","file:///app/packages/libs/shared/src/hooks/UseBatchFetch.ts","file:///app/packages/libs/shared/src/hooks/UseHandleObjectError.ts","file:///app/packages/libs/shared/src/hooks/UseInfiniteScroll.ts","file:///app/packages/libs/shared/src/hooks/UseInfiniteList.ts","file:///app/packages/libs/shared/src/hooks/useBreadcrumbs.ts","file:///app/packages/libs/shared/src/apps/playlists/components/playlist-header-details/PlaylistHeaderDetails.tsx","file:///app/packages/projects/lite/src/apps/playlists/components/playlist-header/partial-loading/partial-playlist-header.scss","file:///app/packages/projects/lite/src/apps/playlists/components/playlist-header/partial-loading/PartialPlaylistHeader.tsx","file:///app/packages/projects/lite/src/apps/playlists/components/playlist-header/PlaylistHeaderUtils.ts","file:///app/packages/projects/lite/src/apps/playlists/components/playlist-header/playlist-header.scss","file:///app/packages/projects/lite/src/apps/playlists/components/playlist-header/PlaylistHeader.tsx","file:///app/packages/projects/lite/src/apps/playlists/components/video-list/SortableVideoListContainer.tsx","file:///app/packages/projects/lite/src/apps/playlists/views/playlist/empty-state/PlaylistEmptyState.tsx","file:///app/packages/projects/lite/src/apps/playlists/views/playlist/PlaylistViewUtils.ts","file:///app/packages/projects/lite/src/apps/playlists/views/playlist/PlaylistView.tsx","file:///app/packages/libs/shared/src/hooks/UseReorderedItems.ts","file:///app/packages/projects/lite/src/shared/hooks/useCommonVideoProps.ts","file:///app/packages/projects/lite/src/shared/hooks/useVideoMixin.ts"],"sourcesContent":["// extracted by mini-css-extract-plugin\nexport default {\"tag\":\"XRj8d\",\"tooltip\":\"X6mLk\"};","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { SvgContainer } from 'libs/shared/components/svg-container/SvgContainer';\nimport { Tooltip } from 'libs/shared/components/tooltip/Tooltip';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport styles from './coming-soon-tag.scss';\n\nconst namespace = 'specialEventCalendar.comingSoonTag';\n\ninterface ComingSoonProps {\n className?: string;\n onlyIcon?: boolean;\n}\n\nexport function ComingSoonTag(props: ComingSoonProps): JSX.Element {\n return (\n <Tooltip title={LanguageService.getPhrase(namespace, 'tooltip')} spanHackClassName={`d-block ${styles.tooltip}`} spanHack>\n <div className={`d-flex text-dark align-items-center ${styles.tag} ${props.className}`}>\n <SvgContainer svgName={cvSvgLibrary.Timer} />\n {!props.onlyIcon && LanguageService.getPhrase(namespace, 'comingSoon')}\n </div>\n </Tooltip>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"dateItem\":\"I3SBm\",\"label\":\"PRORs\",\"body\":\"RfiM_\",\"bodyDay\":\"ZOVny\",\"bodyRange\":\"vYhXN\",\"bodyMonth\":\"mYslO\",\"month\":\"EPkkQ\"};","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { HashObject } from 'libs/common/react/interfaces';\n\nimport { AnalyticsOptions } from 'libs/analytics/interfaces';\n\nimport { CalendarTheme } from 'libs/shared/apps/calendar/interfaces/CalendarTheme';\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\n\nimport styles from './generic-calendar-date.scss';\n\nexport interface GenericCalendarDateProps {\n label?: string;\n body: {\n type: 'month' | 'range' | 'day';\n text: string;\n };\n month?: string;\n getAppLink?: () => Core.AppLink;\n analyticsData?: HashObject;\n analyticsOptions?: AnalyticsOptions;\n className?: string;\n theme?: CalendarTheme;\n}\n\nexport function GenericCalendarDate(props: GenericCalendarDateProps): JSX.Element {\n function getBodyClass(): string {\n switch (props.body.type) {\n case 'range':\n return styles.bodyRange;\n case 'day':\n return styles.bodyDay;\n case 'month':\n return styles.bodyMonth;\n }\n }\n\n return (\n <AppLink\n appLink={props.getAppLink?.()}\n className={`text-decoration-none text-center bg-white text-dark border border-3 ${props.theme?.border} rounded-3 d-block fw-semibold ${props.className}`}\n analyticsData={props.analyticsData}\n analyticsOptions={props.analyticsOptions}\n >\n <div className={`position-relative ${styles.dateItem}`}>\n <div className={`${props.theme?.background} py-1 ${styles.label} d-flex align-items-center justify-content-center`}>\n {props.label ? props.label : <> </>}\n </div>\n <div className={`${getBodyClass()} ${styles.body} my-2`}>\n {props.body.text}\n </div>\n <div className={`mb-0 ${styles.month}`}>\n {props.month}\n </div>\n </div>\n </AppLink>\n );\n}","import { ObjectHelper } from 'libs/common/react/utils/ObjectHelper';\n\nimport { MasterType } from 'libs/shared/enums/MasterType';\nimport { BaseObject, CurrentUser, Playlist } from 'libs/shared/interfaces';\n\nexport const PlaylistHelper = {\n isPlaylist(obj: BaseObject): obj is Playlist {\n return obj?.typeId === MasterType.Playlist;\n },\n\n isOwner(playlist: Playlist, currentUser: CurrentUser): boolean {\n if (!currentUser || !playlist || ObjectHelper.isEmpty(playlist._liteOwner))\n return false;\n\n return playlist._liteOwner.id.toString() === currentUser.id?.toString();\n },\n\n getVideoCount(playlist: Playlist): number {\n if (!playlist)\n return;\n\n let count = 0;\n\n if (playlist.videos?.count)\n count += playlist.videos.count;\n\n if (playlist.clips?.count)\n count += playlist.clips.count;\n\n if (playlist.interactives?.count)\n count += playlist.interactives.count;\n\n return count;\n }\n};","import * as React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\n\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { SvgContainer, SvgContainerSize } from 'libs/shared/components/svg-container/SvgContainer';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nconst namespace = 'shared.backButton';\n\ninterface BackButtonProps {\n appLink: Core.AppLink;\n backToName?: string;\n color?: 'black' | 'white';\n extraClasses?: string;\n /**\n * Whether or not the button text has a text shadow. Defaults to true\n */\n textShadow?: boolean;\n}\n\nBackButton.defaultProps = {\n color: 'black',\n extraClasses: ''\n};\n\nexport function BackButton(props: BackButtonProps): React.ReactElement {\n const { backToName, appLink, color, extraClasses, textShadow } = {\n textShadow: true,\n ...props\n };\n\n const backPhrase = backToName\n ? LanguageService.getPhrase(namespace, 'backTo', { backToName })\n : LanguageService.getPhrase(namespace, 'back');\n\n const colorClass = color === 'black' ? '' : 'text-white';\n const textShadowClass = textShadow ? 'text-shadow' : '';\n\n return (\n <AppLink\n appLink={appLink}\n className={`d-inline-flex align-items-center h5 mb-0 ${extraClasses} ${colorClass} ${textShadowClass}`}\n >\n <SvgContainer svgName={cvSvgLibrary.ChevronLeft} size={SvgContainerSize.Medium} />\n <span className='ms-1'>{backPhrase}</span>\n </AppLink>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"bannerContent\":\"sSCTB\",\"actionsContainer\":\"Z5WI2\",\"bannerContentWithLogo\":\"rgs7Q\",\"container\":\"M51HJ\",\"logoContainer\":\"vkeJk\",\"logoContainerLeft\":\"M3U9B\",\"logoHeading\":\"EtRwC\",\"specialEventContainer\":\"rOxDc\",\"headingLarge\":\"_8pnV\",\"heading\":\"JXVBH\"};","import * as React from 'react';\n\nimport { Core } from 'libs/common/core';\nimport { DateHelper } from 'libs/common/react/utils/DateHelper';\nimport { PortalHelper } from 'libs/common/react/utils/PortalHelper';\n\nimport { ComingSoonTag } from 'libs/shared/apps/calendar/components/coming-soon-tag/ComingSoonTag';\nimport { GenericCalendarDate } from 'libs/shared/apps/calendar/components/generic-calendar-date/GenericCalendarDate';\nimport { CalendarTheme } from 'libs/shared/apps/calendar/interfaces/CalendarTheme';\nimport { ActionOptions, Actions } from 'libs/shared/components/actions/Actions';\nimport { BackButton } from 'libs/shared/components/back-button/BackButton';\nimport { LazyImage } from 'libs/shared/components/lazy-image/LazyImage';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { BG_COLOUR_CLASS_NAMES } from 'libs/shared/constants/ColourClassNames';\nimport { ImageMinDimensions } from 'libs/shared/constants/ImageSizes';\nimport { BannerPortalContext } from 'libs/shared/context/BannerPortalContext';\nimport { ImageSize, ImageType, ResizeType } from 'libs/shared/enums/Images';\nimport { useBreakpoints } from 'libs/shared/hooks/useBreakpoints';\nimport { Banner, CalendarEvent, Logo } from 'libs/shared/interfaces';\nimport { getBgColorClass } from 'libs/shared/utils/getBgColorClass';\nimport { ImageHelper, ImageOptions } from 'libs/shared/utils/ImageHelper';\n\nimport styles from './banner-header.scss';\n\nconst RATIO = `${ImageMinDimensions[ImageType.Banners].width}:${ImageMinDimensions[ImageType.Banners].height}`;\nconst DEFAULT_WIDTH = 1200; // This is ImageSize.Large for a Banner.\nconst LARGE_SCREEN_WIDTH = 1920;\n\nfunction useGetImageWidth(): number {\n const breakpoints = useBreakpoints();\n\n if (breakpoints.xxl)\n return LARGE_SCREEN_WIDTH;\n\n return DEFAULT_WIDTH;\n}\n\nfunction getSizeClass(heading: string): string {\n if (heading.length < 160)\n return 'h1';\n\n return styles.headingLarge;\n}\n\ninterface BannerHeaderProps {\n heading: string;\n banner?: Banner;\n bannerClassName?: string;\n imageCdnUrl?: string;\n logo?: Logo;\n logoBgColour?: string;\n actions?: ActionOptions[];\n specialEvent?: CalendarEvent;\n backButtonAppLink?: Core.AppLink;\n backButtonText?: string;\n backButtonClasses?: string;\n sortComponent?: JSX.Element;\n blockColourClass?: string;\n actionsDropdownClassName?: string;\n detailsComponent?: () => React.ReactElement;\n imageOptions?: ImageOptions;\n showComingSoon?: boolean;\n alignLogoLeft?: boolean;\n calendarTheme?: CalendarTheme;\n}\n\nconst namespace = 'shared.bannerHeader';\n\nexport const BannerHeader = React.memo(function(props: React.PropsWithChildren<BannerHeaderProps>): React.ReactElement {\n const { heading, banner, imageCdnUrl, actions, sortComponent, blockColourClass, specialEvent } = props;\n\n const portalContainerContext = React.useContext(BannerPortalContext);\n\n const imageWidth = useGetImageWidth();\n\n const specialEventIsToday = React.useMemo(() => {\n if (!specialEvent || props.showComingSoon)\n return false;\n\n const today = DateHelper.format(new Date(), 'YYYY-MM-DD');\n\n if (!specialEvent.endDate)\n return specialEvent.startDate === today;\n\n return specialEvent.startDate <= today && specialEvent.endDate >= today;\n }, [specialEvent]);\n\n function getSpecialEventMonthText(specialEvent: CalendarEvent): string {\n if (!specialEvent.endDate)\n return DateHelper.format(specialEvent.startDate, 'MMMM');\n\n if (DateHelper.isSame(specialEvent.startDate, specialEvent.endDate, 'month'))\n return DateHelper.format(specialEvent.startDate, 'MMMM');\n\n return `${DateHelper.format(specialEvent.startDate, 'MMM')} - ${DateHelper.format(specialEvent.endDate, 'MMM')}`;\n }\n\n const imageOptions = props.imageOptions || {\n width: imageWidth,\n ratio: RATIO,\n resizeType: ResizeType.Cover\n };\n\n const url = !!banner && !!imageCdnUrl && ImageHelper.createBannerUrl(banner, {\n fallbackBaseUrl: imageCdnUrl,\n fallbackCategoryName: heading,\n type: ImageType.Banners\n }, imageOptions);\n\n const containerProps: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> = {\n className: `banner banner-header ${props.bannerClassName}`,\n style: url ? { backgroundImage: `url('${url}')` } : {}\n };\n\n if (!banner && blockColourClass) {\n delete containerProps.style;\n containerProps.className += ` ${blockColourClass}`;\n }\n\n const DetailsComponent = props.detailsComponent;\n\n const logoFallbackBgClassName = getBgColorClass(props.heading, BG_COLOUR_CLASS_NAMES);\n\n return PortalHelper.renderInPortalIfExists(\n // \"banner\" is used in playlists in Online. banner-header is used by all other projects\n <header {...containerProps}>\n <div className={`container ${styles.container} position-relative inner-banner`}>\n {props.backButtonAppLink && (\n <div className='pt-3'>\n <BackButton\n appLink={props.backButtonAppLink}\n backToName={props.backButtonText}\n extraClasses={props.backButtonClasses}\n color='white'\n />\n </div>\n )}\n \n <div className={`${props.alignLogoLeft ? 'position-absolute top-50 start-0 translate-middle-y w-100 ps-4' : `${styles.bannerContent} px-2 ${props.logo?.url ? styles.bannerContentWithLogo : ''}`}`}>\n {!!specialEvent && (\n <div className={`position-relative ${styles.specialEventContainer}`}>\n <GenericCalendarDate\n body={{\n type: specialEvent.endDate ? 'range' : 'day',\n text: specialEvent.endDate\n ? `${DateHelper.format(specialEvent.startDate, 'DD')}-${DateHelper.format(specialEvent.endDate, 'DD')}`\n : DateHelper.format(specialEvent.startDate, 'DD')\n }}\n month={getSpecialEventMonthText(specialEvent)}\n theme={props.calendarTheme}\n />\n </div>\n )}\n <div>\n {specialEventIsToday && (\n <div className='rounded-pill py-1 px-2 my-1 me-1 fw-semibold bg-light-blue lh-1 d-inline-block'>\n <Text namespace={namespace} phrase='onToday' />\n </div>\n )}\n {props.showComingSoon && (\n <ComingSoonTag className='pe-2 fw-semibold mb-1 rounded-pill justify-content-start text-nowrap' />\n )}\n <div className='d-flex align-items-center'>\n {props.alignLogoLeft && props.logo?.url &&\n <div className={`${styles.logoContainerLeft} d-none d-md-block rounded-circle overflow-hidden me-3 ${logoFallbackBgClassName}`}>\n <LazyImage\n src={ImageHelper.createUrl(props.logo?.url, { size: ImageSize.Medium })}\n style={{ backgroundColor: props.logoBgColour }}\n />\n </div>\n }\n <h1 className={`text-white text-shadow pe-3 position-static ${styles.heading} ${getSizeClass(heading)} ${props.alignLogoLeft ? 'w-50' : ''}`}>\n {heading}\n {DetailsComponent && <DetailsComponent />}\n </h1>\n </div>\n </div>\n {!!actions && (\n <div className={styles.actionsContainer}>\n <Actions\n actions={actions}\n sortComponent={sortComponent}\n actionsDropdownClassName={props.actionsDropdownClassName}\n />\n </div>\n )}\n </div>\n {!props.alignLogoLeft && !!props.logo?.url &&\n <div className={styles.logoContainer}>\n <img\n src={ImageHelper.createUrl(props.logo.url, { size: ImageSize.Medium })}\n className='rounded-circle'\n />\n </div>\n }\n </div>\n </header>,\n portalContainerContext?.container\n );\n}, (prevProps, nextProps): boolean => (\n prevProps.actions === nextProps.actions\n && prevProps.heading === nextProps.heading\n && prevProps.logo?.url === nextProps.logo?.url\n));\n\nexport function PartialBannerHeader(): JSX.Element {\n const portalContainerContext = React.useContext(BannerPortalContext);\n\n return PortalHelper.renderInPortalIfExists(\n <div className={`partial-banner partial-loading-background ${styles.banner}`} />,\n portalContainerContext?.container\n );\n}","import { BaseError } from 'libs/common/backbone/core/BaseError';\nimport { HttpStatus } from 'libs/common/backbone/enums/HttpStatus';\nimport { Xhr } from 'libs/common/backbone/interfaces';\nimport { Core } from 'libs/common/core';\n\nimport { NotFoundError } from 'libs/shared/errors/general/not-found/NotFoundError';\nimport { PrivateResourceError } from 'libs/shared/errors/general/private-resource/PrivateResourceError';\nimport { RegionLockedResourceError } from 'libs/shared/errors/general/region-locked-resource/RegionLockedResourceError';\nimport { UnspecifiedError } from 'libs/shared/errors/general/unspecified-error/UnspecifiedError';\nimport { VideoTypes } from 'libs/shared/interfaces';\n\nexport interface HttpErrorMap {\n notFound?: new () => BaseError;\n forbidden?: {\n rating?: new (description: string) => BaseError;\n yearLevel?: new (description: string) => BaseError;\n region?: new () => BaseError;\n privacy?: new (video?: VideoTypes) => BaseError;\n };\n badRequest?: new () => BaseError;\n internalServerError?: new () => BaseError;\n}\n\nexport type IgnoreHttpErrorMap = {\n [key in keyof HttpErrorMap]: boolean;\n};\n\nconst defaultErrors: HttpErrorMap = {\n notFound: NotFoundError,\n forbidden: {\n rating: PrivateResourceError,\n yearLevel: PrivateResourceError,\n region: RegionLockedResourceError,\n privacy: PrivateResourceError\n },\n badRequest: UnspecifiedError,\n internalServerError: UnspecifiedError\n};\n\nexport function handleHttpError(\n info: HttpStatus | Xhr,\n customErrorMap: HttpErrorMap = {},\n /**\n * Prevent certain errors in the errorMap from being thrown\n * so that you may implement your own handler\n */\n ignoreMap: IgnoreHttpErrorMap = {}\n): void {\n if (!info)\n return;\n\n let statusCode: HttpStatus;\n\n if (typeof(info) === 'number') {\n statusCode = info;\n } else {\n statusCode = info.status;\n }\n\n const errorMap = {\n ...defaultErrors,\n ...customErrorMap\n };\n\n if (!statusCode)\n return;\n\n if (!Core.ErrorHelper.isStatusCodeError(statusCode))\n return;\n\n if (statusCode === HttpStatus.InternalServer) {\n if (!ignoreMap.internalServerError)\n Core.ErrorHelper.throw(new UnspecifiedError());\n return;\n }\n\n if (statusCode === HttpStatus.NotFound) {\n if (!ignoreMap.notFound)\n Core.ErrorHelper.throw(new errorMap.notFound());\n return;\n }\n\n if (statusCode === HttpStatus.Forbidden) {\n /**\n * TODO: Work out how to go about handling all forbidden errors, such as region locking, year levels,\n * ratings, and privacy.\n */\n if (!ignoreMap.forbidden)\n Core.ErrorHelper.throw(new errorMap.forbidden.privacy());\n return;\n }\n\n if (!ignoreMap.badRequest)\n Core.ErrorHelper.throw(new errorMap.badRequest());\n}\n\nexport function handleXhrError(xhr: Xhr, customErrorMap?: HttpErrorMap): void {\n handleHttpError(xhr.status, customErrorMap);\n}","import React from 'react';\n\nimport { Flight } from 'libs/common/flight';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { BaseObject } from 'libs/shared/interfaces';\n\nconst CHUNK_SIZE = 50;\n\nexport interface UseBatchFetchResult<T extends BaseObject> {\n itemsArr: T[];\n items: { [key: string]: T} | null;\n isFetching: boolean;\n hasCompleted: boolean;\n}\n\n/**\n * Used to fetch multiple items by id with Flight. Will fetch 25 items at a time firing off multiple\n * requests if there are more than 25 items.\n * This will return items as null until we have all our items. Items will be returned as an object with\n * their ids as they key for easy mapping\n * \n * @param itemIds \n * @param getRequest \n */\nexport function useBatchFetch<T extends BaseObject>(\n itemIds: string[],\n getRequest: (ids: string[]) => Flight.Request\n): UseBatchFetchResult<T> {\n const chunks = ArrayHelper.chunk<string>(itemIds, CHUNK_SIZE);\n\n const requests = chunks.map(chunk => getRequest(ArrayHelper.uniq(chunk)));\n\n const responses = Flight.useBasicFetchAll<T[]>(requests);\n\n const itemsArr = ArrayHelper.flatten(responses.data);\n const items = responses.data.length\n ? itemsArr.reduce((acc, item) => ({ ...acc, [item.id]: item }), {})\n : null;\n\n return {\n itemsArr,\n items,\n isFetching: responses.isFetching,\n hasCompleted: responses.hasCompleted\n };\n}\n\n/**\n * When you need the useBatchFetch() behavior, but your list of objects to hydrate\n * will grow, such as on a scrolling page. useGrowingBatchFetch() will use local state\n * to determine what we've already built a request for and what items are new\n * as to not re-fetch items - Sha\n */\nexport function useGrowingBatchFetch<TResponse, TObjects = string>(\n objs: TObjects[],\n getRequest: (items: TObjects[]) => Flight.Request,\n _getKey?: (obj: TObjects) => string\n) {\n const getKey = _getKey ?? ((obj: any) => {\n if (typeof obj === 'object')\n return obj.id;\n\n return obj;\n });\n\n const { fetchItems, ...data } = useGrowingBatchFetchFunc<TResponse, TObjects>({ getRequest, _getKey });\n\n React.useEffect(() => {\n if (!objs?.length)\n return;\n\n fetchItems(objs);\n }, [objs?.map(getKey).join(',')]);\n\n return data;\n}\n\ninterface UseGrowingBatchFetchFuncOptions<TObjects> {\n getRequest: (items: TObjects[]) => Flight.Request;\n _getKey?: (obj: TObjects) => string;\n}\n\n/**\n * When you need the useGrowingBatchFetch() behaviour, but need to trigger the\n * fetch manually and update the objects - Nish \n */\nexport function useGrowingBatchFetchFunc<TResponse, TObjects = string>(\n options: UseGrowingBatchFetchFuncOptions<TObjects>\n) {\n const getKey = options._getKey ?? ((obj: any) => {\n if (typeof obj === 'object')\n return obj.id;\n\n return obj;\n });\n\n const fetchedItems = React.useRef<Set<string>>(new Set<string>());\n const [ requests, setRequests ] = React.useState<Flight.Request[]>([]);\n\n function fetchItems(objs: TObjects[]) {\n if (!objs?.length)\n return;\n\n const unfetchedItems: TObjects[] = [];\n \n objs.forEach(obj => {\n const key = getKey(obj);\n\n if (fetchedItems.current.has(key))\n return;\n\n unfetchedItems.push(obj);\n fetchedItems.current.add(key);\n });\n \n if (!unfetchedItems.length)\n return;\n \n setRequests(r => ([ ...r, ...ArrayHelper.chunk<TObjects>(unfetchedItems, CHUNK_SIZE).map(options.getRequest) ]));\n }\n\n const responses = Flight.useBasicFetchAll<TResponse[]>(requests);\n const itemsArr = ArrayHelper.flatten(responses.data);\n const items = responses.data.length\n ? itemsArr.reduce<Record<string, TResponse>>((acc, item) => ({ ...acc, [getKey(item)]: item }), {})\n : null;\n\n return {\n hasFirstRequestCompleted: !!responses.responses?.[0]?.hasCompleted,\n itemsArr,\n items,\n isFetching: responses.isFetching,\n fetchItems\n };\n}\n","import { useEffect } from 'react';\n\nimport { Flight } from 'libs/common/flight';\n\nimport { handleHttpError, HttpErrorMap, IgnoreHttpErrorMap } from 'libs/shared/errors/handlers/HttpErrorHandlers';\n\nfunction generateCacheKey(flightObjs: Array<Flight.Response<any>>): string {\n return flightObjs.map(obj => obj.statusCode).join(':');\n}\n\n// TODO: Change this to just `useHandleHttpError` and only accept a status code.\nexport function useHandleObjectError(\n _flightObjs: Flight.Response<any> | Array<Flight.Response<any>>,\n customErrors?: HttpErrorMap,\n ignoreErrors?: IgnoreHttpErrorMap\n): void {\n const flightObjs = Array.isArray(_flightObjs) ? _flightObjs : [_flightObjs];\n\n useEffect(() => {\n flightObjs.forEach(obj => {\n handleHttpError(obj.statusCode, customErrors, ignoreErrors);\n });\n }, [ generateCacheKey(flightObjs), customErrors, ignoreErrors ]);\n}","import { useEffect } from 'react';\n\nimport { FunctionHelper } from 'libs/common/backbone/utils/FunctionHelper';\n\nconst SCROLL_TOLERANCE = 400; // value in px\n\ninterface UseInfiniteScrollOptions {\n fetchNextPage: () => void;\n hasMore: boolean;\n isFetching: boolean;\n scrollContainer?: HTMLElement;\n}\n\nexport function useInfiniteScroll(options: UseInfiniteScrollOptions): void {\n const handleScroll = (): void => {\n if (options.isFetching)\n return;\n\n if (!options.scrollContainer) {\n const currentScrollHeight = window.innerHeight + document.documentElement.scrollTop;\n \n const totalHeight = document.documentElement.scrollHeight - SCROLL_TOLERANCE;\n \n if (currentScrollHeight < totalHeight)\n return;\n } else {\n const { scrollContainer } = options;\n const currentScrollHeight = scrollContainer.getBoundingClientRect().height + scrollContainer.scrollTop;\n \n const totalHeight = scrollContainer.scrollHeight - SCROLL_TOLERANCE;\n \n if (currentScrollHeight < totalHeight)\n return;\n }\n\n options.fetchNextPage();\n };\n\n useEffect(() => {\n const onScroll = FunctionHelper.throttle(handleScroll, 200);\n\n const scrollContainer = options.scrollContainer || window;\n\n if (options.hasMore)\n scrollContainer.addEventListener('scroll', onScroll);\n\n return () => scrollContainer.removeEventListener('scroll', onScroll);\n }, [ options.hasMore, options.fetchNextPage, options.scrollContainer ]);\n}","import { useEffect, useState } from 'react';\n\nimport { HttpStatus, HttpStatusClass } from 'libs/common/backbone/enums/HttpStatus';\nimport { FunctionHelper } from 'libs/common/backbone/utils/FunctionHelper';\nimport { Flight } from 'libs/common/flight';\n\nimport { BaseObject, BasePaginatedCollection } from 'libs/shared/interfaces';\n\nimport { useInfiniteScroll } from './UseInfiniteScroll';\nimport { useSelectAllPages } from './UseSelectAllPages';\n\nexport interface UseInfiniteListResult<T extends BaseObject> {\n items: T[];\n hasMore: boolean;\n isFetching: boolean;\n nextCursor: string;\n totalItems?: number;\n hasFirstPageCompleted: boolean;\n}\n\n/**\n * Hook to extract an infinite list from the application state,\n * save it locally in state and only update when new data\n * is fetched.\n * \n * @param getRequest - callback function to get the request for each page.\n * Can be false if the request requires data that hasn't yet been fetched - e.g. user id.\n * \n * @param fetchNext - callback function to fetch a page.\n * Can be false if the request requires data that hasn't yet been fetched - e.g. user id.\n */\nexport function useInfiniteList<TObject = BaseObject, TResponse = BasePaginatedCollection<TObject>>(\n getRequest: ((cursor?: string) => Flight.Request) | false,\n fetchNext: ((cursor?: string) => void) | false,\n onError?: (pageNumber: number, statusCode: HttpStatus) => void,\n getItems?: (responseData: TResponse) => TObject[],\n getCursor?: (responseData: TResponse) => string,\n scrollContainer?: HTMLElement\n): UseInfiniteListResult<TObject> {\n const [ pagesFetched, setPagesFetched ] = useState(0);\n\n const fetchNextFn = fetchNext as (cursor?: string) => void;\n\n function getKey(cursor?: string): string {\n if (!getRequest)\n return null;\n\n const request = getRequest(cursor);\n\n if (!request)\n return null;\n\n return request.key;\n }\n\n const response = useSelectAllPages<TObject, TResponse>(\n getKey,\n getItems,\n getCursor\n );\n\n function fetchNextPage(): void {\n if (!fetchNext || !getRequest || !response)\n return;\n\n setPagesFetched(currentVal => currentVal + 1);\n return fetchNextFn(response.nextCursor);\n }\n\n useInfiniteScroll({\n fetchNextPage,\n hasMore: !!response?.nextCursor,\n isFetching: response?.isFetching,\n scrollContainer\n });\n\n useEffect(() => {\n if (!response)\n return;\n\n if (response.shouldInitialFetch && fetchNext) {\n fetchNextFn();\n setPagesFetched(currentVal => currentVal + 1);\n }\n }, [ response?.shouldInitialFetch, fetchNext ]);\n\n useEffect(() => {\n if (!response?.statusCode || !FunctionHelper.isFunction(onError))\n return;\n\n const httpStatusClass: HttpStatusClass = +(response.statusCode?.toString()?.substr(0, 1));\n\n if (httpStatusClass !== HttpStatusClass.ClientError && httpStatusClass !== HttpStatusClass.ServerError)\n return;\n\n onError(pagesFetched, response.statusCode);\n }, [response?.statusCode]);\n\n return {\n items: response?.items,\n hasMore: !!response?.nextCursor,\n nextCursor: response?.nextCursor,\n isFetching: response?.isFetching,\n totalItems: response?.totalItems,\n hasFirstPageCompleted: response?.hasFirstPageCompleted\n };\n}","import React from 'react';\n\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { BreadcrumbService } from 'libs/shared/services/BreadcrumbService';\n\nexport function useBreadcrumbs(current: Breadcrumb): Breadcrumb[] {\n const [ match, useBuilder ] = React.useMemo(() => BreadcrumbService.getBuilder(), []);\n\n const breadcrumbs = useBuilder(match);\n\n if (!breadcrumbs || !current)\n return breadcrumbs;\n\n return [ ...breadcrumbs, { ...current, active: true }];\n}\n\n","import React from 'react';\n\nimport { DateHelper } from 'libs/common/react/utils/DateHelper';\nimport { TextHelper } from 'libs/common/react/utils/TextHelper';\n\nimport { PlaylistHelper } from 'libs/shared/apps/playlists/utils/PlaylistHelper';\nimport { ClickViewAvatar } from 'libs/shared/components/clickview-avatar/ClickViewAvatar';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { CurrentUser, Playlist } from 'libs/shared/interfaces';\n\nconst namespace = 'playlists.playlistHeaderDetails';\n\nconst Separator = ({ className }: { className: string }) =>\n <span className={className}>•</span>;\n\nfunction getPlaylistOwnerName(playlist: Playlist): string {\n const { _liteOwner } = playlist;\n\n if (!_liteOwner)\n return;\n\n if (_liteOwner.name && _liteOwner.surname)\n return TextHelper.toTitleCase(_liteOwner.name + ' ' + _liteOwner.surname.substring(0, 1));\n\n if (_liteOwner.name)\n return _liteOwner.name.split(' ')[0];\n}\n\nfunction getLastUpdated(playlist: Playlist): string {\n if (!playlist.contentModifiedDate)\n return '';\n\n const now = new Date();\n const lastUpdated = DateHelper.convertUTCToLocal(playlist.contentModifiedDate);\n\n // Don't show if last updated over a month ago\n if (DateHelper.isBefore(lastUpdated, DateHelper.subtract(now, 1, 'month')))\n return '';\n\n return DateHelper.fromNow(lastUpdated);\n}\n\ninterface PlaylistHeaderDetailsProps {\n playlist: Playlist;\n currentUser: CurrentUser;\n totalVideos: number;\n \n hideOwnerName?: boolean;\n\n // Custom classes for everything as online and lite use different styles\n detailsClassName: string;\n clickViewAvatarClassName: string;\n separatorClassName: string;\n}\n\nexport function PlaylistHeaderDetails(props: PlaylistHeaderDetailsProps): React.ReactElement {\n const currentUserIsOwner = PlaylistHelper.isOwner(props.playlist, props.currentUser);\n\n const followerCount = props.playlist.followers?.count;\n\n const lastUpdated = getLastUpdated(props.playlist);\n\n return (\n <div className={props.detailsClassName}>\n {/* Owner name */}\n {(!props.hideOwnerName && !currentUserIsOwner) && (\n <>\n {props.playlist._isClickViewCurated?.value ? (\n <>\n <div className={props.clickViewAvatarClassName}>\n <ClickViewAvatar />\n </div>\n <span>ClickView</span>\n </>\n ) : (\n <Text namespace={namespace} phrase='createdBy' options={{ user: getPlaylistOwnerName(props.playlist) }} />\n )}\n\n <Separator className={props.separatorClassName} />\n </>\n )}\n\n {/* Video count */}\n {typeof props.totalVideos === 'number' && (\n <Text namespace={namespace} phrase='videos' options={{ smartCount: props.totalVideos }} />\n )}\n\n {/* Follower count */}\n {followerCount > 0 && (\n <>\n <Separator className={props.separatorClassName} />\n <Text namespace={namespace} phrase='followers' options={{ smartCount: followerCount }} />\n </>\n )}\n\n {/* Last updated */}\n {!!lastUpdated && (\n <>\n <Separator className={props.separatorClassName} />\n <Text namespace={namespace} phrase='lastUpdated' options={{ timeAgo: lastUpdated }} />\n </>\n )}\n </div>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"partialDescription\":\"vDX0m\"};","import React from 'react';\n\nimport { PartialBannerHeader } from 'libs/shared/components/banner-header/BannerHeader';\n\nimport styles from './partial-playlist-header.scss';\n\nexport function PartialPlaylistHeader(): JSX.Element {\n return (\n <>\n <PartialBannerHeader />\n <div className='mb-2'>\n <div className={`partial-loading-background my-2 border-bottom ${styles.partialDescription}`} />\n </div>\n </>\n );\n}","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { AnalyticsOptions, EntityType, EventVersion, LocationContext, ToggleDescriptor, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { PlaylistHelper } from 'libs/shared/apps/playlists/utils/PlaylistHelper';\nimport { ActionOptions } from 'libs/shared/components/actions/Actions';\nimport { getOpenInCurationStudioLabel } from 'libs/shared/hooks/useCurationStudio';\nimport { AssignHelper } from 'libs/shared/utils/AssignHelper';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nimport { AssignAppLinkHelper } from 'apps/assign/utils/AssignAppLinkHelper';\n\nimport { PlaylistHeaderProps } from './PlaylistHeader';\n\nconst namespace = 'playlists.playlistHeader';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface GetPlaylistActionsArgs {\n isAuthenticated: boolean;\n isPlugin: boolean;\n isMobile: boolean;\n setIsFollowing: (val: boolean) => void;\n isFollowing: boolean;\n setShowFollowSpinner: (val: boolean) => void;\n showFollowSpinner: boolean;\n isUserCurator: boolean;\n openInCuratorLink: string;\n hasShareFlowV2: boolean;\n isStudent: boolean;\n isGuest: boolean;\n}\n\nexport const PlaylistHeaderUtils = {\n getPlaylistActions(headerProps: PlaylistHeaderProps, args: GetPlaylistActionsArgs): ActionOptions[] {\n const {\n isAuthenticated,\n isPlugin,\n isMobile,\n setIsFollowing,\n isFollowing,\n setShowFollowSpinner,\n showFollowSpinner,\n isUserCurator,\n openInCuratorLink\n } = args;\n\n const analyticsData = {\n id: headerProps.playlist.id,\n name: headerProps.playlist.name,\n followerCount: headerProps.playlist.followers?.count,\n videoCount: headerProps.playlist.videos?.count,\n interactiveCount: headerProps.playlist.interactives?.count,\n clipCount: headerProps.playlist.clips?.count,\n isClickViewPlaylist: headerProps.playlist._isClickViewCurated?.value\n };\n\n const analyticsOptions: AnalyticsOptions = {\n location: LocationContext.Banner,\n entity: EntityType.Playlist,\n workflowPhase: WorkflowPhase.Start\n };\n\n const actions: ActionOptions[] = [];\n\n if (!isAuthenticated)\n return actions;\n\n if (args.isGuest)\n return actions;\n\n const isOwner = PlaylistHelper.isOwner(headerProps.playlist, headerProps.currentUser);\n const hideAssignButton = AssignHelper.hideAssignButtonOnVideoActions(headerProps.currentUser);\n const hasAssignActionButton = args.hasShareFlowV2 && !args.isStudent && !hideAssignButton;\n\n if (!isPlugin) {\n if (headerProps.playAllAppLink) {\n actions.push({\n label: getPhrase('playAll'),\n appLink: headerProps.playAllAppLink,\n svgName: cvSvgLibrary.Play,\n className: !isMobile ? 'btn btn-outline-dark me-2' : '',\n button: !isMobile,\n analyticsData,\n analyticsOptions: {\n ...analyticsOptions,\n actionType: UserAction.Play\n }\n });\n }\n\n if (hasAssignActionButton) {\n actions.push({\n label: getPhrase('assign'),\n appLink: AssignAppLinkHelper.flowSelector({\n entityType: 'playlist',\n objectId: headerProps.playlist.id\n }),\n svgName: cvSvgLibrary.Classrooms,\n className: !isMobile ? 'btn btn-outline-dark me-2' : '',\n button: !isMobile,\n analyticsData,\n analyticsOptions: {\n ...analyticsOptions,\n actionType: UserAction.Share,\n entity: EntityType.Assign\n }\n });\n }\n \n if (isUserCurator)\n actions.push({\n label: getOpenInCurationStudioLabel(),\n href: openInCuratorLink,\n openInNewTab: true\n });\n\n actions.push({\n label: !hasAssignActionButton && getPhrase('share'),\n tooltip: hasAssignActionButton && getPhrase('share'),\n appLink: {\n application: AppChannels.SHARE,\n action: Actions.Share.SHARE,\n args: [headerProps.playlist.id],\n params: { entityType: 'playlist' }\n },\n svgName: args.hasShareFlowV2 ? cvSvgLibrary.Link : cvSvgLibrary.Share,\n className: !isMobile ? 'btn btn-outline-dark me-2 align-self-stretch' : '',\n button: !isMobile,\n analyticsData,\n analyticsOptions: {\n ...analyticsOptions,\n actionType: UserAction.Share,\n eventVersion: EventVersion.V3\n }\n });\n }\n\n if (!isOwner) {\n actions.push({\n label: getPhrase(isFollowing ? 'following' : 'follow'),\n onClick: () => {\n setIsFollowing(!isFollowing);\n setShowFollowSpinner(true);\n headerProps.follow(\n !isFollowing,\n () => {\n setShowFollowSpinner(false);\n AnalyticsHelper.logUserAction(analyticsData, {\n ...analyticsOptions,\n actionType: UserAction.Follow,\n descriptor: isFollowing ? ToggleDescriptor.Off : ToggleDescriptor.On,\n workflowPhase: WorkflowPhase.Complete\n });\n },\n () => {\n setShowFollowSpinner(false);\n setIsFollowing(isFollowing);\n }\n );\n },\n svgName: isFollowing ? cvSvgLibrary.BellFilled : cvSvgLibrary.Bell,\n className: !isMobile\n ? `btn follow-btn btn-${isFollowing ? 'outline-dark' : 'dark'} me-2`\n : '',\n button: !isMobile,\n showSpinner: showFollowSpinner\n });\n }\n\n if (isOwner) {\n actions.push({\n label: getPhrase('edit'),\n appLink: {\n application: AppChannels.PLAYLISTS,\n action: Actions.Playlists.EDIT_PLAYLIST,\n args: [headerProps.playlist.id]\n },\n svgName: cvSvgLibrary.Edit,\n button: false,\n analyticsData,\n analyticsOptions: {\n ...analyticsOptions,\n actionType: UserAction.Edit\n }\n });\n\n actions.push({\n label: getPhrase('delete'),\n appLink: {\n application: AppChannels.PLAYLISTS,\n action: Actions.Playlists.DELETE_PLAYLIST,\n args: [headerProps.playlist.id]\n },\n svgName: cvSvgLibrary.Delete,\n className: 'text-danger',\n button: false,\n analyticsData,\n analyticsOptions: {\n ...analyticsOptions,\n actionType: UserAction.Delete\n }\n });\n }\n\n if (headerProps.playlist._isClickViewCurated?.value) {\n actions.push({\n label: getPhrase('copy'),\n appLink: {\n application: AppChannels.PLAYLISTS,\n action: Actions.Playlists.COPY_PLAYLIST,\n args: [headerProps.playlist.id]\n },\n button: false,\n analyticsData,\n analyticsOptions: {\n ...analyticsOptions,\n actionType: UserAction.Copy\n }\n });\n }\n\n return actions;\n }\n};\n","// extracted by mini-css-extract-plugin\nexport default {\"clickViewAvatar\":\"PHe9c\"};","import * as React from 'react';\n\nimport { Core } from 'libs/common/core';\n\nimport { PlaylistHeaderDetails } from 'libs/shared/apps/playlists/components/playlist-header-details/PlaylistHeaderDetails';\nimport { ActionOptions } from 'libs/shared/components/actions/Actions';\nimport { BannerHeader } from 'libs/shared/components/banner-header/BannerHeader';\nimport { Breadcrumb, Breadcrumbs, PartialBreadcrumbs } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { BG_COLOUR_CLASS_NAMES } from 'libs/shared/constants/ColourClassNames';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { PermissionName } from 'libs/shared/enums/PermissionName';\nimport { useMediaQuery } from 'libs/shared/hooks/UseMediaQuery';\nimport { usePermissions } from 'libs/shared/hooks/usePermissions';\nimport { useSettings } from 'libs/shared/hooks/useSettings';\nimport { Classification, CurrentUser, Playlist } from 'libs/shared/interfaces';\nimport { getBgColorClass } from 'libs/shared/utils/getBgColorClass';\n\nimport { usePluginHelper } from 'shared/hooks/use-plugin-helper/usePluginHelper';\n\nimport { PartialPlaylistHeader } from './partial-loading/PartialPlaylistHeader';\nimport { PlaylistHeaderUtils } from './PlaylistHeaderUtils';\n\nimport styles from './playlist-header.scss';\n\nexport interface PlaylistHeaderProps {\n playlist: Playlist;\n currentUser: CurrentUser;\n isFollowing: boolean;\n follow: (shouldFollow: boolean, onSuccess: () => void, onError: () => void) => void;\n imageCdnUrl: string;\n showPartialLoading: boolean;\n playAllAppLink: Core.AppLink;\n isUserCurator: boolean;\n openInCuratorLink: string;\n\n // For breadcrumbs\n getBreadcrumbs: () => Breadcrumb[];\n topicPath: Classification[];\n moviesAndTv: boolean;\n classificationId: string;\n totalVideos: number;\n}\n\nexport function PlaylistHeader(props: PlaylistHeaderProps): JSX.Element {\n const { isPlugin } = usePluginHelper();\n const { hasPermissions } = usePermissions();\n const { hasShareFlowV2 } = useSettings(null);\n\n // Store isFollowing in local state so that it updates immediately.\n const [ isFollowing, setIsFollowing ] = React.useState(props.isFollowing);\n const [ showFollowSpinner, setShowFollowSpinner ] = React.useState(false);\n\n React.useEffect(() => setIsFollowing(props.isFollowing), [props.isFollowing]);\n\n const isMobile = useMediaQuery(MediaQueryStrings.XS);\n\n if (props.showPartialLoading)\n return <PartialPlaylistHeader />;\n\n const description = props.playlist.description;\n\n const actions: ActionOptions[] = PlaylistHeaderUtils.getPlaylistActions(props, {\n isAuthenticated: props.currentUser.isAuthenticated,\n isPlugin,\n isMobile,\n setIsFollowing,\n isFollowing,\n setShowFollowSpinner,\n showFollowSpinner,\n isUserCurator: props.isUserCurator,\n openInCuratorLink: props.openInCuratorLink,\n hasShareFlowV2,\n isStudent: hasPermissions(PermissionName.StudentExperience),\n isGuest: hasPermissions(PermissionName.GuestExperience)\n });\n\n const breadcrumbs = props.getBreadcrumbs();\n\n return (\n <>\n <BannerHeader\n heading={props.playlist.name}\n banner={props.playlist.banner}\n imageCdnUrl={props.imageCdnUrl}\n actions={actions.length && actions}\n actionsDropdownClassName='btn btn-outline-dark'\n blockColourClass={getBgColorClass(props.playlist.name, BG_COLOUR_CLASS_NAMES)}\n detailsComponent={() => (\n <PlaylistHeaderDetails\n playlist={props.playlist}\n currentUser={props.currentUser}\n detailsClassName='mb-n1 font-size-normal fw-normal mt-1'\n clickViewAvatarClassName={styles.clickViewAvatar}\n separatorClassName='mx-1'\n totalVideos={props.totalVideos}\n />\n )}\n />\n {(!!description || !!breadcrumbs?.length) && (\n <div className='border-bottom py-3'>\n {(() => {\n if (!props.playlist || (props.classificationId && !props.topicPath))\n return <PartialBreadcrumbs />;\n\n return (\n <div className='pb-2'>\n <Breadcrumbs breadcrumbs={breadcrumbs} />\n </div>\n );\n })()}\n {!!description && <p className='mb-0'>{description}</p>}\n </div>\n )}\n </>\n );\n}\n","import * as React from 'react';\nimport { DragEndEvent, DragStartEvent } from '@dnd-kit/core';\n\nimport { DevError } from 'libs/common/backbone/errors/DevError';\nimport { FunctionHelper } from 'libs/common/backbone/utils/FunctionHelper';\nimport { Core } from 'libs/common/core';\n\nimport { SvgContainerSize } from 'libs/shared/components/svg-container/SvgContainer';\nimport { PartialVideoList } from 'libs/shared/components/video-list/partial-loading/PartialVideoList';\nimport { SortableVideoList, VideoList, VideoListProps } from 'libs/shared/components/video-list/VideoList';\nimport { YearGroup } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\ninterface SortableVideoListContainerProps extends VideoListProps {\n playlistId: string;\n yearGroups: YearGroup[];\n onSortComplete: (oldIdx: number, newIdx: number) => void;\n onSortStart?: (index: number) => void;\n canEdit?: boolean;\n showPartialLoading?: boolean;\n fetchRestrictions?: () => void;\n showSignIn?: boolean;\n}\n\nexport function SortableVideoListContainer(props: SortableVideoListContainerProps): React.ReactElement {\n const { onSortComplete, onSortStart, showPartialLoading, ...videoListProps } = props;\n\n const [ currentSortingIndex, setCurrentSortingIndex ] = React.useState<number>();\n\n const onSortStartHandler = (event: DragStartEvent) => {\n const index = props.videos.findIndex(v => v.id.toString() === event.active.id.toString());\n\n setCurrentSortingIndex(index);\n\n if (FunctionHelper.isFunction(onSortStart))\n onSortStart(index);\n };\n\n const onSortEnd = (event: DragEndEvent) => {\n setCurrentSortingIndex(null);\n\n const { active, over } = event;\n \n const oldIndex = props.videos.findIndex(v => v.id.toString() === active.id.toString());\n const newIndex = props.videos.findIndex(v => v.id.toString() === over.id.toString());\n\n if (!FunctionHelper.isFunction(onSortComplete)) {\n Core.ErrorHelper.throw(new DevError('An onSortComplete callback function must be passed to SortableVideoListComponent'));\n return;\n }\n \n onSortComplete(oldIndex, newIndex);\n };\n\n if (showPartialLoading)\n return <PartialVideoList withReordering={props.canEdit || props.showIndexes} />;\n\n if (!props.canEdit)\n return <VideoList {...videoListProps} />;\n\n return (\n <SortableVideoList\n {...videoListProps}\n currentSortingIndex={currentSortingIndex}\n onSortStart={onSortStartHandler}\n onSortEnd={onSortEnd}\n dragHandleIcon={cvSvgLibrary.Hamburger}\n dragHandleIconSize={SvgContainerSize.XXL}\n presentationAudiences={props.presentationAudiences}\n />\n );\n}","import React from 'react';\n\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\n\nimport { ImageUrls } from 'shared/constants/ImageUrls';\n\nconst namespace = 'playlists.playlistEmptyState';\n\nexport function PlaylistEmptyState(): JSX.Element {\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState>\n <EmptyState.Image src={ImageUrls.EmptyStates.Playlists.PLAYLIST_VIDEOS} />\n\n <EmptyState.Heading><Text phrase='heading' /></EmptyState.Heading>\n\n <EmptyState.Info><Text phrase='info' /></EmptyState.Info>\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { AssocDescriptor, EntityType, LocationContext, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { PlaylistHelper } from 'libs/shared/apps/playlists/utils/PlaylistHelper';\nimport { VideoActionsOptions } from 'libs/shared/context/VideoActionsContext';\nimport { CurrentUser, Playlist, Video, VideoTypes } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\nimport { VideoHelper } from 'libs/shared/utils/VideoHelper';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\nimport { PlaylistNotFoundError } from 'shared/errors/playlists/playlist-not-found/LitePlaylistNotFoundError';\nimport { PlaylistPrivateError } from 'shared/errors/playlists/playlist-private/PlaylistPrivateError';\nimport { useVideoActions, VideoActionsLocation } from 'shared/hooks/use-video-actions/useVideoActions';\n\nconst getPhrase = LanguageService.encloseNamespace('playlists.playlist');\n\n/**\n * NOTE:\n * This will be wrong if we increase the playlist limit from 100, or\n * stop fetching all 100 videos at once.\n */\nexport function getLastUpdatedDate(videos: Video[]): string {\n const videoLastUpdatedDates: string[] = videos && videos.length && videos.map(v => v.dateAssociated);\n\n return (videoLastUpdatedDates && videoLastUpdatedDates.length)\n ? ArrayHelper.max<string, number>(videoLastUpdatedDates, (date: string) => new Date(date).getTime())\n : null;\n}\n\nexport function usePlaylistViewVideoActions(\n playlist: Playlist,\n currentUser: CurrentUser,\n shareId: string\n) {\n const videoActions = useVideoActions({ location: VideoActionsLocation.VideoItem, shareId });\n\n if (!PlaylistHelper.isOwner(playlist, currentUser))\n return videoActions;\n\n const getVideoActions = (video: VideoTypes, options?: VideoActionsOptions) => {\n const { canConsume } = VideoHelper.getCanBeConsumed(video);\n\n const removeFromPlaylistAction = {\n label: getPhrase('removeFromPlaylist'),\n button: false,\n svgName: cvSvgLibrary.Delete,\n appLink: {\n application: AppChannels.PLAYLISTS,\n action: Actions.Playlists.REMOVE_VIDEO_FROM_PLAYLIST,\n args: [ video.id, playlist.id ],\n params: { typeId: video.typeId }\n },\n className: 'text-danger',\n analyticsOptions: {\n entity: EntityType.Video,\n actionType: UserAction.Dissociate,\n location: LocationContext.VideoListItem,\n workflowPhase: WorkflowPhase.Start,\n descriptor: AssocDescriptor.Playlist\n },\n analyticsData: {\n id: video.id,\n playlistId: playlist.id\n },\n group: 'delete'\n };\n\n if (!canConsume)\n return [removeFromPlaylistAction];\n\n return [ ...videoActions.getVideoActions(video, options), removeFromPlaylistAction ];\n };\n\n return {\n ...videoActions,\n getVideoActions\n };\n}\n\nexport function logSortAction(playlistId: string, videoId: string, workflowPhase: WorkflowPhase): void {\n AnalyticsHelper.logUserAction({ id: videoId, playlistId }, {\n location: LocationContext.VideoList,\n entity: EntityType.Video,\n actionType: UserAction.Move,\n workflowPhase\n });\n}\n\nexport const playlistErrors = {\n notFound: PlaylistNotFoundError,\n forbidden: {\n privacy: PlaylistPrivateError\n }\n};","import * as React from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\nimport { Flight } from 'libs/common/flight';\n\nimport { LocationContext, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { PlaylistHelper } from 'libs/shared/apps/playlists/utils/PlaylistHelper';\nimport { InfiniteScrollFooter } from 'libs/shared/components/infinite-scroll-footer/InfiniteScrollFooter';\nimport { VideoActionsContext } from 'libs/shared/context/VideoActionsContext';\nimport { RelatedVideosContext } from 'libs/shared/enums/RelatedVideosContext';\nimport { AudienceRequests } from 'libs/shared/flight-requests/AudienceRequests';\nimport { ClassificationRequests } from 'libs/shared/flight-requests/ClassificationRequests';\nimport { ConfigRequests } from 'libs/shared/flight-requests/ConfigRequests';\nimport { CustomerRequests } from 'libs/shared/flight-requests/CustomerRequests';\nimport { PlaylistRequests } from 'libs/shared/flight-requests/PlaylistRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { useAlerts } from 'libs/shared/hooks/UseAlerts';\nimport { useBreadcrumbs } from 'libs/shared/hooks/useBreadcrumbs';\nimport { useCurationStudio } from 'libs/shared/hooks/useCurationStudio';\nimport { useHandleObjectError } from 'libs/shared/hooks/UseHandleObjectError';\nimport { useInfiniteList } from 'libs/shared/hooks/UseInfiniteList';\nimport { usePermissions } from 'libs/shared/hooks/usePermissions';\nimport { useReorderedItems } from 'libs/shared/hooks/UseReorderedItems';\nimport { useSetPageMetadata } from 'libs/shared/hooks/useSetPageMetadata';\nimport { Classification, Config, Following, OnlineCurrentUser, Playlist, Presentation, PresentationAudience, VideoTypes, YearGroup } from 'libs/shared/interfaces';\nimport { GetVideoAppLinkOptions } from 'libs/shared/interfaces/VideoAppLinkOptions';\nimport { PageMetadataHelper } from 'libs/shared/utils/PageMetadataHelper';\nimport { ReorderHelper } from 'libs/shared/utils/ReorderHelper';\nimport { VideoHelper } from 'libs/shared/utils/VideoHelper';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\nimport { useCommonVideoProps } from 'shared/hooks/useCommonVideoProps';\nimport { useDeepLinks } from 'shared/hooks/useDeepLinks';\nimport { useVideoMixin } from 'shared/hooks/useVideoMixin';\nimport { InteractiveHelpers } from 'shared/utils/InteractiveHelper';\nimport { SeoHelper } from 'shared/utils/SeoHelper';\nimport { VideoAppLinkHelper } from 'shared/utils/VideoAppLinkHelper';\n\nimport { PlaylistHeader } from 'apps/playlists/components/playlist-header/PlaylistHeader';\nimport { SortableVideoListContainer } from 'apps/playlists/components/video-list/SortableVideoListContainer';\n\nimport { PlaylistEmptyState } from './empty-state/PlaylistEmptyState';\nimport { logSortAction, playlistErrors, usePlaylistViewVideoActions } from './PlaylistViewUtils';\n\nconst namespace = 'playlists.playlist';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface PlaylistViewProps {\n playlistId: string;\n shareId?: string;\n classificationId?: string;\n moviesAndTv?: boolean;\n hideBreadCrumbs?: boolean;\n}\n\nexport function PlaylistView(props: PlaylistViewProps): React.ReactElement {\n const dispatch = useDispatch();\n const alerts = useAlerts();\n\n const config = Flight.useBasicFetch<Config>(ConfigRequests.config());\n const currentUser = Flight.useBasicFetch<OnlineCurrentUser>(UserRequests.currentUser());\n const { isUserCurator, getOpenInCurationStudioLink } = useCurationStudio();\n const { hasPermissions } = usePermissions();\n\n const yearGroups = Flight.useBasicFetch<YearGroup[]>(\n currentUser.data?.isAuthenticated && CustomerRequests.yearGroups(currentUser.data.customerId)\n );\n\n const topicPath = Flight.useBasicFetch<Classification[]>(\n props.classificationId &&\n ClassificationRequests.path(props.classificationId)\n );\n\n const classification = Flight.useBasicFetch<Classification>(\n props.classificationId &&\n ClassificationRequests.classification(props.classificationId, currentUser.data?.id)\n );\n\n const classificationPresentation = Flight.useBasicFetch<Presentation>(\n classification.hasCompleted &&\n ClassificationRequests.presentationById(classification.data?.presentationId)\n );\n\n const shouldFetchAudiences = !currentUser.data?.isAuthenticated\n ? !!classificationPresentation.data?.id\n : !props.classificationId || classificationPresentation.hasCompleted;\n\n const audiences = Flight.useBasicFetch<PresentationAudience[]>(\n shouldFetchAudiences &&\n AudienceRequests.presentationAudiences(classificationPresentation.data?.id)\n );\n\n const { commonVideoProps } = useCommonVideoProps({\n locationContext: LocationContext.VideoThumbnail,\n mtv: props.moviesAndTv,\n sharedPlaylist: !!props.shareId\n });\n\n const playlistRequest = props.shareId\n ? PlaylistRequests.getSharedPlaylist(props.playlistId, props.shareId)\n : PlaylistRequests.getPlaylist(props.playlistId);\n\n const playlistItemCountRequest = props.shareId\n ? PlaylistRequests.getSharedPlaylistVideosCount(props.playlistId, props.shareId)\n : PlaylistRequests.getPlaylistVideosCount(props.playlistId);\n\n const playlist = Flight.useBasicFetch<Playlist>(playlistRequest);\n const playlistWithCounts = Flight.useBasicFetch<Playlist>(playlistItemCountRequest);\n\n const getVideoItemActions = usePlaylistViewVideoActions(playlist.data, currentUser.data, props.shareId);\n\n useHandleObjectError(playlist, playlistErrors);\n\n const getVideosRequest = (cursor?: string) => {\n return props.shareId\n ? PlaylistRequests.getSharedPlaylistVideos(props.playlistId, props.shareId, cursor)\n : PlaylistRequests.getPlaylistVideos(props.playlistId, cursor);\n };\n\n const following = Flight.useBasicFetch<Following>(\n currentUser.data?.id &&\n PlaylistRequests.getIsFollowingPlaylist(props.playlistId, currentUser.data?.id)\n );\n\n const fetchNext = (cursor?: string) => {\n Flight.getFetch(dispatch)(getVideosRequest(cursor));\n };\n\n const { items: videos, hasMore, isFetching } = useInfiniteList<VideoTypes>(getVideosRequest, fetchNext);\n\n useVideoMixin(videos);\n\n // Locally stored array of videos used to immediately reflect changes in order.\n const [ reorderedVideos, setReorderedVideos ] = useReorderedItems(videos);\n\n useDeepLinks({ id: props.playlistId, app: 'playlists', shareId: props.shareId });\n useSetPageMetadata(PageMetadataHelper.getPlaylistMetadata({\n content: playlist.data,\n phraseContext: {\n phraseHandler: getPhrase,\n titlePhrase: 'pageTitle',\n descriptionPhrase: 'pageDescription'\n },\n canonicalLink: SeoHelper.getCanonicalLink({ stripPresentationSlug: true }),\n allowIndexing: false\n }));\n\n const onSortStart = (index: number) => {\n const video = videos[index];\n\n if (video)\n logSortAction(props.playlistId, video.id, WorkflowPhase.Start);\n };\n\n const onSortComplete = (oldIdx: number, newIdx: number) => {\n if (oldIdx === newIdx)\n return;\n\n const video = videos[oldIdx];\n\n if (!video)\n return;\n\n const { reorderedItems, reorderRequest } = ReorderHelper.reorder(videos, oldIdx, newIdx);\n setReorderedVideos(reorderedItems);\n\n logSortAction(props.playlistId, video.id, WorkflowPhase.Complete);\n\n const onError = () => {\n setReorderedVideos(null);\n };\n\n Flight.fetch(dispatch, PlaylistRequests.reorderVideos(props.playlistId, reorderRequest, null, onError));\n };\n\n const follow = (shouldFollow: boolean, onSuccess: () => void, onError: () => void) => {\n const req = shouldFollow\n ? PlaylistRequests.followPlaylist\n : PlaylistRequests.unfollowPlaylist;\n\n const error = () => {\n onError();\n alerts.error(getPhrase(shouldFollow ? 'followError' : 'unfollowError'));\n };\n\n Flight.fetch(dispatch, req(props.playlistId, currentUser.data?.id, onSuccess, error));\n };\n\n const playlistIsEmpty = !!videos && videos.length === 0;\n\n const getVideoAppLink = (\n video: VideoTypes,\n playNext: boolean,\n options: GetVideoAppLinkOptions = {}\n ) => {\n return VideoAppLinkHelper.getAppLink(video, {\n ...options,\n contextId: props.playlistId,\n context: RelatedVideosContext.Playlist,\n shareId: props.shareId,\n moviesAndTv: props.moviesAndTv,\n playNext,\n includeContext: currentUser.data?.isAuthenticated || !!props.shareId\n });\n };\n\n const isFollowingComplete = !currentUser.data?.isAuthenticated || !!following.hasCompleted;\n\n // The play all applink should start from the first consumable video\n const firstPlayAllVideo = videos?.find(v => VideoHelper.getCanBeConsumed(v)?.canConsume);\n const canEdit = PlaylistHelper.isOwner(playlist.data, currentUser.data);\n\n const videoDataLoaded = (\n videos && currentUser.data && config.data\n );\n\n const getSignInAppLink = (appLink: Core.AppLink): Core.AppLink => {\n const redirectUrl = Core.AppLinkHelper.getHref(appLink);\n const params = redirectUrl !== '/' ? { redirectUrl } : {};\n \n return {\n application: AppChannels.DEFAULT,\n action: Actions.Default.CHALLENGE,\n params\n };\n };\n\n const breadcrumbs = useBreadcrumbs({ name: playlist.data?.name });\n\n return (\n <VideoActionsContext.Provider value={currentUser.data?.isAuthenticated && getVideoItemActions}>\n <div className='bg-white px-3'>\n <PlaylistHeader\n playlist={playlist.data}\n currentUser={currentUser.data}\n isFollowing={following.data?.isFollowing}\n follow={follow}\n playAllAppLink={firstPlayAllVideo && getVideoAppLink(firstPlayAllVideo, true)}\n showPartialLoading={!playlist.data || !videoDataLoaded || !isFollowingComplete}\n imageCdnUrl={!!config.data && config.data.imageCdnUrl}\n getBreadcrumbs={() => props.hideBreadCrumbs ? null : breadcrumbs}\n topicPath={topicPath.data}\n moviesAndTv={props.moviesAndTv}\n classificationId={props.classificationId}\n isUserCurator={isUserCurator}\n openInCuratorLink={getOpenInCurationStudioLink(playlist.data?.typeId, playlist.data?.id)}\n totalVideos={PlaylistHelper.getVideoCount(playlistWithCounts.data)}\n />\n <div className='mt-2'>\n {!playlistIsEmpty\n ? (\n <SortableVideoListContainer\n videos={reorderedVideos || videos}\n yearGroups={yearGroups.data}\n playlistId={!!playlist.data && playlist.data.id}\n onSortStart={onSortStart}\n onSortComplete={onSortComplete}\n canEdit={canEdit}\n showPartialLoading={!videoDataLoaded}\n getVideoAppLink={(v, opts) => getVideoAppLink(v, false, opts)}\n showSignIn={!currentUser.data?.isAuthenticated}\n getSignInAppLink={getSignInAppLink}\n canRemovePrivateVideos={canEdit}\n presentationAudiences={props.moviesAndTv ? null : audiences.data}\n showIndexes={true}\n hasPermissions={hasPermissions}\n getPreviewQuestionsAppLink={interactive => InteractiveHelpers.getPreviewQuestionsAppLink(interactive)}\n commonVideoProps={commonVideoProps}\n />\n ) : <PlaylistEmptyState />\n }\n </div>\n {(hasMore || isFetching) && <InfiniteScrollFooter isFetching={isFetching} fetchNext={fetchNext} />}\n </div>\n </VideoActionsContext.Provider>\n );\n}\n","import { useEffect, useState } from 'react';\n\nimport { BaseObject } from 'libs/shared/interfaces';\n\nfunction isOrderEqual(arr1: BaseObject[], arr2: BaseObject[]): boolean {\n let isEqual = true;\n\n if (arr1.length !== arr2.length)\n return false;\n\n for (let i = 0; i < arr1.length; i++) {\n if (arr1[i].id !== arr2[i].id) {\n isEqual = false;\n break;\n }\n }\n\n return isEqual;\n}\n\n/**\n * This function can be used to temporarily store an array of reordered objects\n * until the array obtained from the application store updates to the new order.\n * \n * @param items array of objects from application store.\n */\nexport function useReorderedItems<T extends BaseObject>(\n items: T[]\n): [ T[], React.Dispatch<React.SetStateAction<T[]>> ] {\n const [ reorderedItems, setReorderedItems ] = useState<T[]>();\n\n useEffect(() => {\n if (!reorderedItems)\n return;\n\n if (items.length !== reorderedItems.length || isOrderEqual(items, reorderedItems))\n setReorderedItems(null);\n }, [items]);\n\n return [ reorderedItems, setReorderedItems ];\n}","import { Core } from 'libs/common/backbone/index';\nimport { Flight } from 'libs/common/react/index';\n\nimport { LocationContext } from 'libs/analytics/interfaces';\n\nimport { PermissionName } from 'libs/shared/enums/PermissionName';\nimport { ConfigRequests } from 'libs/shared/flight-requests/ConfigRequests';\nimport { CustomerRequests } from 'libs/shared/flight-requests/CustomerRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { usePermissions } from 'libs/shared/hooks/usePermissions';\nimport { useSettings } from 'libs/shared/hooks/useSettings';\nimport { Config, CurrentUser, VideoTypes, YearGroup } from 'libs/shared/interfaces';\nimport { CommonVideoProps } from 'libs/shared/interfaces/CommonVideoProps';\n\nimport { VideoAppLinkHelper } from 'shared/utils/VideoAppLinkHelper';\n\nimport { SeriesAppLinkHelper } from 'apps/series/SeriesAppLinkHelper';\n\nimport { usePluginHelper } from './use-plugin-helper/usePluginHelper';\nimport { useLiteFavourites } from './useLiteFavourites';\n\ninterface UseCommonVideoPropsResult {\n hasCommonVideoPropsCompleted: boolean;\n commonVideoProps: CommonVideoProps;\n}\n\ninterface UseCommonVideoPropsOptions {\n locationContext: LocationContext,\n mtv?: boolean;\n flightNamespace?: string;\n sharedPlaylist?: boolean;\n}\n\nexport function useCommonVideoProps(options: UseCommonVideoPropsOptions): UseCommonVideoPropsResult {\n const { locationContext, mtv, flightNamespace, sharedPlaylist } = options || {};\n\n const { isPlugin, params } = usePluginHelper();\n const { setFavourite, canFavourite } = useLiteFavourites(locationContext, flightNamespace);\n const { hasTopicDirectories, isLoadingSettings } = useSettings(null);\n const { hasPermissions, isLoaded: hasLoadedPermissions } = usePermissions();\n const hasStudentExperience = hasPermissions(PermissionName.StudentExperience);\n const hasGuestExperience = hasPermissions(PermissionName.GuestExperience);\n\n const config = Flight.useBasicFetch<Config>(ConfigRequests.config());\n const currentUser = Flight.useBasicFetch<CurrentUser>(UserRequests.currentUser());\n const yearGroups = Flight.useBasicFetch<YearGroup[]>(\n currentUser.data?.isAuthenticated && CustomerRequests.yearGroups(currentUser.data.customerId)\n );\n\n function getSubTextAppLink(video: VideoTypes): Core.AppLink {\n if (!('series' in video))\n return null;\n\n /**\n * We do not allow navigating to series on shared playlists when the user is not signed in\n * because most series are customer created and will be empty for public users\n * \n * We do not have to do this for shared series, because all the series links are self referencing\n * - Sha\n */\n if (sharedPlaylist && !currentUser.data?.isAuthenticated)\n return null;\n \n return SeriesAppLinkHelper.getSeriesAppLink(video.series, { mtv });\n }\n\n const hasCommonVideoPropsCompleted = (\n !isLoadingSettings &&\n hasLoadedPermissions &&\n config.hasCompleted &&\n currentUser.hasCompleted &&\n (!currentUser.data?.isAuthenticated || yearGroups.hasCompleted)\n );\n\n return {\n hasCommonVideoPropsCompleted,\n commonVideoProps: {\n subTextType: 'series',\n getSubTextAppLink,\n isPlugin,\n isPluginPopup: !!params?.popup,\n canFavourite,\n setFavourite,\n imageCdnUrl: config.data?.imageCdnUrl,\n yearGroups: yearGroups.data,\n getClassroomGuideAppLink: VideoAppLinkHelper.getClassroomGuideAppLink,\n getInteractiveGuidanceAppLink: VideoAppLinkHelper.getInteractiveGuidanceAppLink,\n getResourceGuidanceAppLink: VideoAppLinkHelper.getResourceGuidanceAppLink,\n showNewVideoIndicator: hasTopicDirectories,\n companyLogoFallbackUrl: null,\n hasStudentExperience,\n hasGuestExperience\n }\n };\n}","import { Flight } from 'libs/common/react/index';\n\nimport { VideoRequests } from 'libs/shared/flight-requests/VideoRequests';\nimport { useGrowingBatchFetch, useGrowingBatchFetchFunc } from 'libs/shared/hooks/UseBatchFetch';\nimport { Clip, ClipCollection, Video, VideoCollection } from 'libs/shared/interfaces';\nimport { VideoHelper } from 'libs/shared/utils/VideoHelper';\n\ntype Types = Video[] | VideoCollection | Clip[] | ClipCollection;\n\nfunction getValidObjects(objects: Types): (Video | Clip)[] {\n if (!objects)\n return [];\n\n if (Array.isArray(objects))\n return objects.filter(o => !!o && (VideoHelper.isVideo(o) || VideoHelper.isClip(o)));\n\n if ('data' in objects)\n return objects.data.filter(o => !!o && (VideoHelper.isVideo(o) || VideoHelper.isClip(o)));\n\n return [];\n}\n\ninterface VideoMixinOptions {\n /**\n * If the videos that are having new data mixed into are sitting on an explicit Flight namespace,\n * providing that namespace here is required\n */\n flightNamespace?: string;\n}\n\nexport function useVideoMixin(objects: Types, options: VideoMixinOptions = {}) {\n const videoIds = getValidObjects(objects).map(v => v.id);\n\n useGrowingBatchFetch(\n videoIds,\n ids => VideoRequests.videoMixinAssocs(ids, options.flightNamespace),\n null\n );\n}\n\nexport function useVideoMixinFunc(options: VideoMixinOptions = {}) {\n function getRequest(ids: string[]): Flight.Request {\n return VideoRequests.videoMixinAssocs(ids, options.flightNamespace);\n }\n \n function fetchObjects(items: Types) {\n return fetchItems(getValidObjects(items).map(v => v.id));\n }\n\n const { fetchItems } = useGrowingBatchFetchFunc({ getRequest });\n\n return { fetchObjects };\n}"],"names":["namespace","ComingSoonTag","props","Tooltip","title","LanguageService","spanHackClassName","spanHack","className","SvgContainer","svgName","onlyIcon","GenericCalendarDate","AppLink","appLink","getAppLink","theme","border","analyticsData","analyticsOptions","background","label","body","type","getBodyClass","text","month","PlaylistHelper","isPlaylist","obj","typeId","isOwner","playlist","currentUser","_liteOwner","id","toString","getVideoCount","count","videos","clips","interactives","BackButton","textShadow","backToName","color","extraClasses","backPhrase","colorClass","textShadowClass","size","S","defaultProps","RATIO","width","height","getSizeClass","heading","length","BannerHeader","banner","imageCdnUrl","actions","sortComponent","blockColourClass","specialEvent","portalContainerContext","BannerPortalContext","imageWidth","useBreakpoints","xxl","specialEventIsToday","showComingSoon","today","DateHelper","Date","endDate","startDate","imageOptions","ratio","resizeType","url","ImageHelper","fallbackBaseUrl","fallbackCategoryName","containerProps","bannerClassName","style","backgroundImage","DetailsComponent","detailsComponent","logoFallbackBgClassName","getBgColorClass","PortalHelper","backButtonAppLink","backButtonText","backButtonClasses","alignLogoLeft","logo","getSpecialEventMonthText","calendarTheme","Text","phrase","LazyImage","src","backgroundColor","logoBgColour","Actions","actionsDropdownClassName","container","prevProps","nextProps","PartialBannerHeader","defaultErrors","notFound","forbidden","rating","yearLevel","region","privacy","badRequest","internalServerError","handleHttpError","info","customErrorMap","ignoreMap","statusCode","status","errorMap","CHUNK_SIZE","useBatchFetch","itemIds","getRequest","requests","map","chunk","responses","itemsArr","data","items","reduce","acc","item","isFetching","hasCompleted","useGrowingBatchFetch","objs","_getKey","getKey","useGrowingBatchFetchFunc","fetchItems","join","options","fetchedItems","Set","setRequests","hasFirstRequestCompleted","unfetchedItems","forEach","key","current","has","push","add","r","generateCacheKey","flightObjs","useHandleObjectError","_flightObjs","customErrors","ignoreErrors","Array","isArray","useEffect","SCROLL_TOLERANCE","useInfiniteList","fetchNext","onError","getItems","getCursor","scrollContainer","handleScroll","useState","pagesFetched","setPagesFetched","fetchNextFn","response","cursor","request","fetchNextPage","currentVal","nextCursor","hasMore","getBoundingClientRect","scrollTop","scrollHeight","window","innerHeight","document","documentElement","onScroll","FunctionHelper","addEventListener","removeEventListener","shouldInitialFetch","httpStatusClass","substr","HttpStatus","totalItems","hasFirstPageCompleted","useBreadcrumbs","match","breadcrumbs","useBuilder","active","Separator","getPlaylistOwnerName","name","surname","TextHelper","substring","split","PlaylistHeaderDetails","currentUserIsOwner","followerCount","followers","lastUpdated","contentModifiedDate","now","getLastUpdated","detailsClassName","hideOwnerName","_isClickViewCurated","value","clickViewAvatarClassName","ClickViewAvatar","user","separatorClassName","totalVideos","smartCount","timeAgo","PartialPlaylistHeader","getPhrase","PlaylistHeaderUtils","getPlaylistActions","headerProps","args","isAuthenticated","isPlugin","isMobile","setIsFollowing","isFollowing","setShowFollowSpinner","showFollowSpinner","isUserCurator","openInCuratorLink","videoCount","interactiveCount","clipCount","isClickViewPlaylist","location","entity","workflowPhase","isGuest","hideAssignButton","AssignHelper","hasAssignActionButton","hasShareFlowV2","isStudent","playAllAppLink","button","actionType","AssignAppLinkHelper","entityType","objectId","href","openInNewTab","tooltip","application","action","params","eventVersion","onClick","follow","AnalyticsHelper","descriptor","showSpinner","PlaylistHeader","usePluginHelper","hasPermissions","usePermissions","useSettings","showPartialLoading","description","PermissionName","getBreadcrumbs","classificationId","topicPath","Breadcrumbs","SortableVideoListContainer","onSortComplete","onSortStart","videoListProps","currentSortingIndex","setCurrentSortingIndex","PartialVideoList","withReordering","canEdit","showIndexes","event","index","findIndex","v","onSortEnd","over","oldIndex","newIndex","DevError","dragHandleIcon","dragHandleIconSize","presentationAudiences","VideoList","PlaylistEmptyState","EmptyState","ImageUrls","logSortAction","playlistId","videoId","playlistErrors","PlaylistPrivateError","PlaylistView","dispatch","alerts","config","ConfigRequests","UserRequests","useCurationStudio","getOpenInCurationStudioLink","yearGroups","CustomerRequests","customerId","ClassificationRequests","classification","classificationPresentation","presentationId","shouldFetchAudiences","audiences","AudienceRequests","commonVideoProps","useCommonVideoProps","locationContext","mtv","moviesAndTv","sharedPlaylist","shareId","playlistRequest","PlaylistRequests","playlistItemCountRequest","playlistWithCounts","getVideoItemActions","videoActions","useVideoActions","getVideoActions","video","canConsume","VideoHelper","removeFromPlaylistAction","group","usePlaylistViewVideoActions","getVideosRequest","following","useVideoMixin","reorderedItems","setReorderedItems","arr1","arr2","isEqual","i","isOrderEqual","reorderedVideos","setReorderedVideos","useDeepLinks","app","useSetPageMetadata","PageMetadataHelper","content","phraseContext","phraseHandler","titlePhrase","descriptionPhrase","canonicalLink","SeoHelper","stripPresentationSlug","allowIndexing","playlistIsEmpty","playNext","VideoAppLinkHelper","contextId","context","RelatedVideosContext","includeContext","isFollowingComplete","firstPlayAllVideo","find","videoDataLoaded","VideoActionsContext","shouldFollow","onSuccess","req","error","hideBreadCrumbs","oldIdx","newIdx","ReorderHelper","reorderRequest","getVideoAppLink","opts","showSignIn","getSignInAppLink","redirectUrl","canRemovePrivateVideos","getPreviewQuestionsAppLink","interactive","InteractiveHelper","InfiniteScrollFooter","flightNamespace","u","setFavourite","canFavourite","hasTopicDirectories","isLoadingSettings","hasLoadedPermissions","isLoaded","hasStudentExperience","hasGuestExperience","hasCommonVideoPropsCompleted","subTextType","getSubTextAppLink","series","isPluginPopup","popup","getClassroomGuideAppLink","getInteractiveGuidanceAppLink","getResourceGuidanceAppLink","showNewVideoIndicator","companyLogoFallbackUrl","getValidObjects","objects","filter","o","videoIds","ids","useVideoMixinFunc","fetchObjects"],"sourceRoot":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scripts/4177-2d876c7b14-lite.chunk.js","mappings":"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","sources":["file:///app/packages/libs/shared/src/components/rostering/rostering-alert/RosteringAlert.tsx","file:///app/packages/libs/shared/src/hooks/useBulkCheckboxManager.ts","file:///app/packages/libs/shared/src/utils/GroupHelper.ts","file:///app/packages/projects/lite/src/apps/classrooms/components/manage-classroom-students/partial-loading/partial-manage-classroom-students.scss","file:///app/packages/projects/lite/src/apps/classrooms/components/manage-classroom-students/partial-loading/PartialManageClassroomStudents.tsx","file:///app/packages/projects/lite/src/apps/classrooms/views/full-classrooms-experience/empty-state/ClassroomsNoStudentsState.tsx","file:///app/packages/projects/lite/src/apps/classrooms/components/manage-classroom-students/empty-state/ManageClassroomStudentsEmptyState.tsx","file:///app/packages/projects/lite/src/apps/classrooms/components/classroom-group-pill/classroom-group-pill.scss","file:///app/packages/projects/lite/src/apps/classrooms/components/classroom-group-pill/ClassroomGroupPill.tsx","file:///app/packages/projects/lite/src/apps/classrooms/components/classroom-group-dropdown/ClassroomGroupDropdown.tsx","file:///app/packages/projects/lite/src/apps/classrooms/components/manage-classroom-student-item/manage-classroom-student-item.scss","file:///app/packages/projects/lite/src/apps/classrooms/components/manage-classroom-student-item/ManageClassroomStudentItem.tsx","file:///app/packages/projects/lite/src/apps/classrooms/components/manage-classroom-students/ManageClassroomStudents.tsx","file:///app/packages/projects/lite/src/apps/classrooms/views/classroom-students/ClassroomStudentsView.tsx","file:///app/packages/projects/lite/src/shared/hooks/useClassroomExperience.ts"],"sourcesContent":["import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nconst namespace = 'rostering.alert';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface RosteringAlertProps {\n type?: 'classroom' | 'general';\n}\n\nexport function RosteringAlert(props: RosteringAlertProps) {\n const text = props.type === 'classroom' ? getPhrase('classroom') : getPhrase('hasRostering');\n\n return (\n <div className='alert text-info bg-light-blue px-2 rounded-3 fw-semibold py-2 d-flex flex-wrap'>\n {text} \n {/* todo add it back when KB article link is ready */}\n {/* <ExternalLink\n className='text-info text-underline'\n href={''}\n newTab\n >\n {LanguageService.getPhrase(namespace, 'learnMore')}\n </ExternalLink> */}\n </div>\n );\n}","import React from 'react';\n\nimport { HashObject } from 'libs/common/react/interfaces/HashObject';\n\nimport { useForceUpdate } from 'libs/shared/hooks/useForceUpdate';\nimport { usePrevious } from 'libs/shared/hooks/usePrevious';\n\ntype CheckboxItemsState = Map<string, boolean>;\n\nexport interface BulkCheckboxManager {\n onToggleBulk: () => void;\n onToggleItem: (id: string) => void;\n getSelected: () => string[];\n isChecked: (item: string | number | HashObject<string>) => boolean;\n bulkChecked: boolean;\n deselectAll: () => void;\n hasSomeSelections: () => boolean;\n setSelected: (ids: string[]) => void;\n getSelectedCount: () => number;\n reset: () => void;\n getMap: () => Map<string, boolean>;\n}\n\nexport interface BulkCheckboxManagerOptions {\n idField?: string; // For objects like `PresentationAudiences` that don't use `id` as their identifier field\n persistNamespace?: string;\n preselectedIds?: string[];\n initialState?: CheckboxItemsState;\n}\n\n/**\n * @param collection - The collection you are keeping track of with checkboxes\n * @param options - See interface above\n */\nexport const useBulkCheckboxManager = (collection: HashObject[], options: BulkCheckboxManagerOptions = {}) => {\n const { idField = 'id', persistNamespace } = options;\n\n const initial = options.initialState ? options.initialState : new Map<string, boolean>();\n\n const items = React.useRef<CheckboxItemsState>(initial);\n \n const forceUpdate = useForceUpdate();\n\n const prevCollection = usePrevious(collection);\n const prevNamespace = usePrevious(persistNamespace);\n\n /**\n * This hook will clear the state of this hook when a user navigates between pages\n * if a persistNamespace was not provided\n */\n React.useEffect(() => {\n /**\n * If we're being passed initial state, we don't want to clear the state\n */\n if (options.initialState)\n return;\n\n /**\n * If we've been given a persist namespace, we don't want to clear our\n * selections while the namespace stays the same\n */\n if (persistNamespace && prevNamespace === persistNamespace)\n return;\n\n /**\n * Don't reinitialize if the ids of the new and old collection\n * are identical\n */\n const prevIds = prevCollection?.map(i => i[idField]).join();\n const ids = collection?.map(i => i[idField]).join();\n\n if (prevIds === ids)\n return;\n\n reset();\n }, [ prevCollection, prevNamespace, collection, options.initialState ]);\n\n React.useEffect(() => {\n if (!options.preselectedIds?.length)\n return;\n\n setSelected(options.preselectedIds);\n }, []);\n\n function reset(): void {\n items.current.clear();\n forceUpdate();\n }\n\n // When toggled on, all checkbox items will be enabled. Vice versa if toggled off\n function onToggleBulk(): void {\n const setValue = !isBulkChecked();\n\n collection.forEach(item => {\n if (setValue)\n items.current.set(item[idField].toString(), true);\n else\n items.current.delete(item[idField].toString());\n });\n\n forceUpdate();\n }\n\n // Toggles a single item\n function onToggleItem(id: string): void {\n const nextItemState = !items.current.get(id.toString());\n\n if (nextItemState)\n items.current.set(id.toString(), nextItemState);\n else\n items.current.delete(id.toString());\n \n forceUpdate();\n }\n\n // Returns the state of the item passed in\n function isChecked(item: string | number | HashObject<string>): boolean {\n if (typeof item === 'number')\n item = item.toString();\n else if (typeof item !== 'string')\n item = item[idField].toString();\n\n return items.current.get(item);\n }\n\n function getSelected(): string[] {\n return Array.from(items.current.keys());\n }\n\n function deselectAll(): void {\n if (!collection?.length) return;\n\n collection.forEach(item => {\n items.current.delete(item[idField].toString());\n });\n forceUpdate();\n }\n\n // Returns true if at least 1 item is checked\n function hasSomeSelections(): boolean {\n if (!collection?.length)\n return false;\n\n return !!collection.find(item => isChecked(item));\n }\n\n function isBulkChecked(): boolean {\n if (!collection?.length)\n return false;\n\n return collection.every(isChecked);\n }\n\n function setSelected(ids: string[]): void {\n ids.forEach(id => {\n items.current.set(id, true);\n });\n forceUpdate();\n }\n\n function getSelectedCount(): number {\n return items.current.size;\n }\n\n function getMap(): Map<string, boolean> {\n return items.current;\n }\n\n return {\n onToggleBulk,\n onToggleItem,\n getSelected,\n isChecked,\n bulkChecked: isBulkChecked(),\n deselectAll,\n hasSomeSelections,\n setSelected,\n getSelectedCount,\n reset,\n getMap\n };\n};","import { ButtonProps } from 'react-bootstrap';\n\nimport { ClassroomGroupColour } from 'libs/shared/interfaces';\n\nexport function mapColourToBsVariant(groupColour: ClassroomGroupColour): ButtonProps['variant'] {\n switch (groupColour) {\n case ClassroomGroupColour.Pink:\n return 'pink';\n case ClassroomGroupColour.Orange:\n return 'orange';\n case ClassroomGroupColour.Green:\n return 'green';\n case ClassroomGroupColour.Blue:\n return 'blue';\n case ClassroomGroupColour.Purple:\n return 'purple';\n case ClassroomGroupColour.Indigo:\n return 'indigo';\n default:\n return 'pink';\n }\n}\n","// extracted by mini-css-extract-plugin\nexport default {\"heading\":\"YrP_G\",\"avatar\":\"droqZ\",\"checkbox\":\"pJf6R\",\"actionIcon\":\"MSvzY\",\"addStudents\":\"j62jt\",\"studentName\":\"gorcb\",\"group\":\"IFmvc\",\"sm\":\"pOcvk\",\"lg\":\"SdQ90\",\"moreActions\":\"S7p4K\"};","import React from 'react';\n\nimport { PartialBreadcrumbs } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { PartialPillTabSelector } from 'libs/shared/components/pill-tab-selector/partial-loading/PartialPillTabSelector';\n\nimport styles from './partial-manage-classroom-students.scss';\n\nexport const PartialManageClassroomStudents = React.memo(function(): JSX.Element {\n return (\n <div className='px-3'>\n {/* Heading */}\n <div className={`mb-1 partial-loading-background ${styles.heading}`} />\n\n {/* Breadcrumbs */}\n <div className='pb-3'>\n <PartialBreadcrumbs numItems={2} />\n </div>\n\n {/* Pill tab selector */}\n <div className='pb-2'>\n <PartialPillTabSelector />\n </div>\n\n <div className='d-flex align-items-center py-2'>\n {/* Checkbox */}\n <div className={`mx-4 partial-loading-background ${styles.checkbox}`} />\n {/* Group selector */}\n <div className={`me-2 partial-loading-background ${styles.actionIcon}`} />\n {/* Delete action */}\n <div className={`me-auto partial-loading-background ${styles.actionIcon}`} />\n\n {/* Add new students button */}\n <div className={`partial-loading-background ${styles.addStudents}`} />\n </div>\n\n {/* Students list */}\n <ul className='striped-list list-unstyled'>\n {Array(20).fill(null).map((student, i) => (\n <li key={i}>\n <div className='d-flex align-items-center py-1 px-4'>\n {/* Checkbox */}\n <div className={`me-2 partial-loading-background ${styles.checkbox}`} />\n\n {/* Avatar */}\n <div className={`me-2 partial-loading-background ${styles.avatar}`} />\n\n {/* Student name */}\n <div className='w-25'>\n <div className={`partial-loading-background ${styles.studentName}`} />\n </div>\n\n {/* Groups list. Randomly renders either 1 or 2 groups. Group widths are randomly generated */}\n <div className='me-auto d-flex'>\n {Math.random() > 0.5\n ? (\n <>\n <div className={`partial-loading-background rounded-pill me-1 ${styles.group} ${styles.lg}`} />\n <div className={`partial-loading-background rounded-pill ${styles.group} ${styles.sm}`} />\n </>\n ) : <div className={`partial-loading-background rounded-pill ${styles.group} ${styles.sm}`} />\n }\n </div>\n\n {/* Group selector */}\n <div className={`me-2 partial-loading-background ${styles.actionIcon}`} />\n {/* More actions */}\n <div className={`partial-loading-background ${styles.moreActions}`} />\n </div>\n </li>\n ))}\n </ul>\n </div>\n );\n});","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\n\nimport { ImageUrls } from 'shared/constants/ImageUrls';\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nconst namespace = 'classrooms.classroomsEmptyState';\n\ninterface ClassroomsNoStudentsStateProps {\n canManageUsers: boolean;\n isRostering?: boolean;\n}\n\nexport function ClassroomsNoStudentsState(props: ClassroomsNoStudentsStateProps): JSX.Element {\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState>\n <EmptyState.Image src={ImageUrls.EmptyStates.Classrooms.STUDENTS} />\n\n <EmptyState.Heading><Text phrase='noStudentsHeading' /></EmptyState.Heading>\n <EmptyState.Info className={`w-33 ${!props.canManageUsers ? 'mb-0' : ''}`}>\n <Text phrase='noStudentsInfo' />\n </EmptyState.Info>\n\n {props.canManageUsers && !props.isRostering && (\n <EmptyState.Cta\n text={LanguageService.getPhrase(namespace, 'noStudentsCta')}\n appLink={{\n application: AppChannels.USER_MANAGER,\n action: Actions.UserManager.STUDENTS\n }}\n />\n )}\n {!props.canManageUsers && !props.isRostering && (\n <EmptyState.Info><Text phrase='askAdmin' /></EmptyState.Info>\n )}\n {props.isRostering && (\n <a className='btn btn-link info-link font-semibold' href={''} target='_blank'>\n {LanguageService.getPhrase(namespace, 'rosteringCta')}\n </a>\n )}\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\nimport { Classroom } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport { ImageUrls } from 'shared/constants/ImageUrls';\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nimport { ClassroomsNoStudentsState } from 'apps/classrooms/views/full-classrooms-experience/empty-state/ClassroomsNoStudentsState';\n\nconst namespace = 'classrooms.manageClassroomStudentsEmptyState';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nconst STUDENT_ENGAGEMENT_IDEAS_LINK = 'https://static.clickview.com.au/Primary/Documents/Student-engagement-ideas.pdf';\nconst ROSTERING_KB_ARTICLE_URL = '';\n\ninterface ManageClassroomStudentsEmptyStateProps {\n classroom: Classroom;\n classroomIdeasText: string;\n schoolHasNoStudents: boolean;\n canManageUsers: boolean;\n}\n\nexport function RosteredClassroomStudentsEmptyState(): JSX.Element {\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState>\n <EmptyState.Image src={ImageUrls.EmptyStates.Classrooms.STUDENTS} />\n\n <EmptyState.Heading><Text phrase='emptyStateHeading' /></EmptyState.Heading>\n\n <EmptyState.Info className='mb-2' ><Text phrase='emptyStateInfo' /></EmptyState.Info>\n\n <a className='btn btn-link info-link font-semibold' href={ROSTERING_KB_ARTICLE_URL} target='_blank'>\n {getPhrase('rosteringCta')}\n </a>\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n\nexport function ManageClassroomStudentsEmptyState(props: ManageClassroomStudentsEmptyStateProps): JSX.Element {\n if (props.schoolHasNoStudents)\n return <ClassroomsNoStudentsState canManageUsers={props.canManageUsers} />;\n\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState>\n <EmptyState.Image src={ImageUrls.EmptyStates.Classrooms.STUDENTS} />\n\n <EmptyState.Heading><Text phrase='emptyStateHeading' /></EmptyState.Heading>\n\n <EmptyState.Info><Text phrase='emptyStateInfo' /></EmptyState.Info>\n <EmptyState.Cta\n text={LanguageService.getPhrase(namespace, 'addStudents')}\n icon={cvSvgLibrary.Plus}\n appLink={{\n application: AppChannels.CLASSROOMS,\n action: Actions.Classrooms.ADD_STUDENTS_CHOICES,\n args: [props.classroom.id]\n }}\n />\n\n <a className='btn btn-link info-link font-semibold' href={STUDENT_ENGAGEMENT_IDEAS_LINK} target='_blank'>\n {props.classroomIdeasText}\n </a>\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n","// extracted by mini-css-extract-plugin\nexport default {\"maxWidth\":\"A0VzW\"};","import React from 'react';\n\nimport { DivButton } from 'libs/shared/components/div-button/DivButton';\nimport { ClassroomGroup } from 'libs/shared/interfaces';\nimport { mapColourToBsVariant } from 'libs/shared/utils/GroupHelper';\n\nimport styles from './classroom-group-pill.scss';\n\ninterface ClassroomGroupProps {\n group: ClassroomGroup;\n}\n\nexport function ClassroomGroupPill(props: ClassroomGroupProps): JSX.Element {\n if (!props.group)\n return <></>;\n\n return (\n <div className={`classroom-pill ${styles.maxWidth} text-white text-truncate bg-${mapColourToBsVariant(props.group.metadata?.colour)}`}>\n <p className='text-truncate mb-0' title={props.group.name}>{props.group.name}</p>\n </div>\n );\n}\n\ninterface ClassroomGroupExpanderProps {\n count: number;\n onClick: () => void;\n}\n\nexport function ClassroomGroupExpander(props: ClassroomGroupExpanderProps): JSX.Element {\n if (!props.count)\n return <></>;\n\n return (\n <DivButton onClick={props.onClick} className={`classroom-pill bg-white border border-dark`}>\n +{props.count}\n </DivButton>\n );\n}","import React from 'react';\nimport { Dropdown } from 'react-bootstrap';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { HashObject } from 'libs/common/react/interfaces/HashObject';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { EntityType, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { Checkbox } from 'libs/shared/components/forms/form-checkbox/Checkbox';\nimport { SvgContainer } from 'libs/shared/components/svg-container/SvgContainer';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { useBulkCheckboxManager } from 'libs/shared/hooks/useBulkCheckboxManager';\nimport { PropsWithAnalyticsOptions, User } from 'libs/shared/interfaces';\nimport { Classroom, ClassroomGroup } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nimport { ClassroomGroupPill } from 'apps/classrooms/components/classroom-group-pill/ClassroomGroupPill';\n\nconst namespace = 'classrooms.classroomGroupDropdown';\n\nconst getNewGroupAppLink = (id: string, students: User[]) => ({\n application: AppChannels.CLASSROOMS,\n action: Actions.Classrooms.NEW_GROUP,\n args: [id],\n params: {\n addStudents: students.map(s => s.id)\n }\n});\n\nfunction checkStudentsAllInGroup(students: User[], group: ClassroomGroup) {\n const groupUserIds = new Set(group.users.data.map(u => u.id.toString()));\n return students.every(student => groupUserIds.has(student.id.toString()));\n}\n\nfunction checkStudentsNotInGroup(students: User[], group: ClassroomGroup) {\n const groupUserIds = new Set(group.users.data.map(u => u.id.toString()));\n return students.every(student => !groupUserIds.has(student.id.toString()));\n}\n\ntype ClassroomGroupDropdownProps = PropsWithAnalyticsOptions<{\n id: string;\n classroom: Classroom;\n selectedStudents: User[];\n groups: ClassroomGroup[];\n onSelectGroup: (group: ClassroomGroup, toggleOn?: boolean) => void;\n preselections?: ClassroomGroup[];\n isBulk?: boolean;\n\n alignRight?: boolean;\n disabled?: boolean;\n disabledTooltips?: string;\n}>;\n\nClassroomGroupDropdown.defaultProps = {\n preselections: []\n};\n\nexport function ClassroomGroupDropdown(props: ClassroomGroupDropdownProps): JSX.Element {\n const { onToggleItem, isChecked } = useBulkCheckboxManager(props.groups, {\n preselectedIds: props.preselections.map(s => s.id)\n });\n\n const studentsAllInGroupLookup = props.groups.reduce((acc, group) => {\n acc[group.id] = checkStudentsAllInGroup(props.selectedStudents, group);\n return acc;\n }, {} as Record<string, boolean>);\n\n function onChange(group: ClassroomGroup): void {\n const shouldAdd = !isChecked(group.id);\n props.onSelectGroup(group, shouldAdd);\n\n onToggleItem(group.id);\n }\n\n function onClickCreateNewGroup(): void {\n if (props.disabled)\n return;\n\n AnalyticsHelper.logUserAction({\n classroom: { id: props.classroom.id, name: props.classroom.name }\n }, AnalyticsHelper.mergeOptions(props.analyticsOptions, {\n actionType: UserAction.Create,\n workflowPhase: WorkflowPhase.Start,\n entity: EntityType.ClassroomGroup\n }));\n }\n\n React.useEffect(() => {\n // On each passthrough, validate that the checkbox states are valid\n // This is needed because the group/student state is managed in 2 separate places on the same page\n props.groups.forEach(g => {\n const totalCheckedForGroup = studentsAllInGroupLookup[g.id];\n // Validate if unchecked checkbox should be checked\n if (!!totalCheckedForGroup && !isChecked(g.id)) {\n onToggleItem(g.id);\n return;\n }\n\n // Validate if checked checkbox should be unchecked\n if (!totalCheckedForGroup && isChecked(g.id)) {\n onToggleItem(g.id);\n return;\n }\n });\n }, [\n Object.entries(studentsAllInGroupLookup).sort((a, b) => a[0].localeCompare(b[0])).join(',')\n ]);\n\n const buttonClasses = 'me-2 d-inline-block svg-container sm';\n\n const dropdownProps: HashObject = {\n align: props.alignRight ? 'end' : 'start'\n };\n\n /**\n * This prop is applied like this so that when `props.disabled` it false, the prop is omitted altogether.\n * This is because we want `react-bootstrap` to control the open state, and if we used the `show` prop\n * at all times we'd be preventing that.\n */\n if (props.disabled)\n dropdownProps.show = false;\n\n return (\n <Dropdown {...dropdownProps}>\n <Dropdown.Toggle\n as='div'\n id={props.id}\n className={`${props.disabled ? 'text-light' : 'cursor-pointer'} ${buttonClasses} no-caret`}\n >\n <SvgContainer\n svgName={cvSvgLibrary.Group}\n title={props.disabled ? props.disabledTooltips : LanguageService.getPhrase(namespace, 'addToGroupTooltip')}\n tooltipPlacement='top'\n tooltipSpanHack\n tooltipSpanHackClassName=''\n />\n </Dropdown.Toggle>\n <Dropdown.Menu>\n {!!props.groups?.length && (\n <div className='px-2 border-bottom mb-1'>\n <p className='mb-0'><Text namespace={namespace} phrase='addToGroup' /></p>\n <ul className='list-unstyled pe-3'>\n {props.groups.map(group => {\n const isEmptyChecked = checkStudentsNotInGroup(props.selectedStudents, group);\n const isIndeterminate = !props.isBulk\n ? false\n : !studentsAllInGroupLookup[group.id] && !isEmptyChecked;\n\n return (\n <li key={group.id} className='d-flex align-items-center bg-white my-1'>\n <Checkbox\n id={`${props.id}:${group.id}`}\n checked={isChecked(group.id)}\n onChange={() => onChange(group)}\n indeterminate={isIndeterminate }\n />\n <ClassroomGroupPill group={group} />\n </li>\n );\n })}\n </ul>\n </div>\n )}\n <AppLink\n onClick={onClickCreateNewGroup}\n appLink={getNewGroupAppLink(props.classroom.id, props.selectedStudents)}\n className={props.disabled ? 'disabled' : 'text-nowrap d-flex align-items-center px-2'}\n >\n <SvgContainer svgName={cvSvgLibrary.Plus} />\n <Text namespace={namespace} phrase='createNew' />\n </AppLink>\n </Dropdown.Menu>\n </Dropdown>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"avatarContainer\":\"rfVnC\",\"name\":\"RYLWZ\"};","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { FunctionHelper } from 'libs/common/backbone/utils/FunctionHelper';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { AssocDescriptor, EntityType, LocationContext, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { ActionOptions, Actions as MoreActions } from 'libs/shared/components/actions/Actions';\nimport { Avatar } from 'libs/shared/components/avatar/Avatar';\nimport { Checkbox } from 'libs/shared/components/forms/form-checkbox/Checkbox';\nimport { PermissionName } from 'libs/shared/enums/PermissionName';\nimport { UserGroup } from 'libs/shared/enums/UserGroup';\nimport { usePermissions } from 'libs/shared/hooks/usePermissions';\nimport { useResizeListener } from 'libs/shared/hooks/UseResizeListener';\nimport { ClassroomGroup, Config } from 'libs/shared/interfaces';\nimport { Classroom } from 'libs/shared/interfaces';\nimport { User } from 'libs/shared/interfaces';\nimport { UserHelper } from 'libs/shared/utils/UserHelper';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nimport { ClassroomGroupDropdown } from 'apps/classrooms/components/classroom-group-dropdown/ClassroomGroupDropdown';\nimport { ClassroomGroupExpander, ClassroomGroupPill } from 'apps/classrooms/components/classroom-group-pill/ClassroomGroupPill';\n\nimport styles from './manage-classroom-student-item.scss';\n\ntype GroupVisibilityMapping = { [id: string]: boolean };\n\nconst namespace = 'classrooms.manageClassroomStudentItem';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nconst getEditStudentAppLink = (id: string) => ({\n application: AppChannels.USER_MANAGER,\n action: Actions.UserManager.EDIT_USER,\n args: [id],\n params: { userType: UserGroup.Learner }\n});\n\nconst getRemoveStudentsAppLink = (studentId: string, classroomId: string) => ({\n application: AppChannels.CLASSROOMS,\n action: Actions.Classrooms.REMOVE_STUDENTS,\n args: [classroomId],\n params: {\n studentIds: [studentId]\n }\n});\n\ninterface ManageClassroomStudentItemProps {\n classroom: Classroom;\n student: User;\n classroomGroups: ClassroomGroup[];\n selectedGroups: ClassroomGroup[];\n config: Config;\n onToggleGroup: (student: User, group: ClassroomGroup, toggleOn: boolean) => void;\n onToggleCheckbox: () => void;\n checked: boolean;\n readOnly?: boolean;\n readOnlyTooltip?: string;\n}\n\nexport function ManageClassroomStudentItem(props: ManageClassroomStudentItemProps): JSX.Element {\n const [ isComputingTruncation, setIsComputingTruncation ] = React.useState(false);\n const [ hasExpandedGroups, setHasExpandedGroups ] = React.useState(false);\n\n // Maps a group to it's visibility state.\n const [ groupVisibilityMapping, setGroupVisibilityMapping ] = React.useState<GroupVisibilityMapping>({});\n\n const groupListRef = React.useRef<HTMLDivElement>(null);\n const expanderRef = React.useRef<HTMLDivElement>(null);\n const selectedGroupsRef = React.useRef<ClassroomGroup[]>(props.selectedGroups);\n\n const { hasPermissions } = usePermissions();\n\n // Every time the selected groups array changes, we want to re-compute which groups should be truncated\n React.useEffect(() => {\n selectedGroupsRef.current = props.selectedGroups;\n renderAllGroups();\n\n if (hasExpandedGroups) // Don't re-compute if the user has expanded all groups\n return;\n\n setIsComputingTruncation(true);\n }, [props.selectedGroups.length]);\n\n function onResize(): void {\n renderAllGroups();\n setIsComputingTruncation(true);\n }\n\n const throttledResizeListener = FunctionHelper.throttle(onResize, 300);\n\n useResizeListener(() => {\n if (hasExpandedGroups) // Don't re-compute if the user has expanded all groups\n return;\n\n throttledResizeListener();\n });\n\n /**\n * This iterates through each group element, and detects if any of them don't\n * fit on the first row of items. The elements that don't will be hidden.\n */\n React.useEffect(() => {\n if (!groupListRef.current || !expanderRef.current || !isComputingTruncation)\n return;\n\n const firstGroupPill = groupListRef.current.firstElementChild as HTMLDivElement;\n if (!firstGroupPill) return;\n\n const topRowHeight = firstGroupPill.getBoundingClientRect().y;\n\n const nextGroupVisibilityMapping: { [id: string]: boolean } = {};\n\n /**\n * Here we're checking if the y-coordinate of any groups\n * don't match the y-coordinate of the first group (which should\n * always be on the first row). This way we know if they should be\n * hidden or not.\n */\n let lastVisibleId: string;\n for (const child of groupListRef.current.children) {\n if (child.id) {\n nextGroupVisibilityMapping[child.id] = child.getBoundingClientRect().y === topRowHeight;\n lastVisibleId = nextGroupVisibilityMapping[child.id] ? child.id : lastVisibleId;\n }\n }\n\n // If the expander button has also wrapped, we hide the last element that we were going to make visible.\n if (expanderRef.current.getBoundingClientRect().y !== topRowHeight)\n nextGroupVisibilityMapping[lastVisibleId] = false;\n\n setGroupVisibilityMapping(nextGroupVisibilityMapping);\n setIsComputingTruncation(false);\n }, [isComputingTruncation]);\n\n function onClickShowAllGroups(): void {\n setHasExpandedGroups(true);\n renderAllGroups();\n }\n\n // Updates the group visibility mapping to display all groups\n function renderAllGroups(): void {\n setGroupVisibilityMapping(selectedGroupsRef.current.reduce((acc, group) => {\n acc[group.id] = true;\n return acc;\n }, {} as GroupVisibilityMapping));\n }\n\n // Returns the number of groups that are invisible\n function getInvisibleGroupCount(): number {\n return Object.keys(groupVisibilityMapping).reduce((count, groupId) => {\n if (!groupVisibilityMapping[groupId])\n count++;\n \n return count;\n }, 0);\n }\n\n function getActions(): ActionOptions[] {\n const actions: ActionOptions[] = [];\n\n if (hasPermissions(PermissionName.ManageUsers))\n actions.push({\n label: getPhrase('editStudent'),\n appLink: getEditStudentAppLink(props.student.id),\n disabled: props.readOnly,\n className: props.readOnly ? 'disabled' : '',\n tooltip: props.readOnly ? props.readOnlyTooltip : '',\n onClick: () => {\n AnalyticsHelper.logUserAction({ id: props.student.id }, {\n actionType: UserAction.Edit,\n entity: EntityType.User,\n workflowPhase: WorkflowPhase.Start,\n location: LocationContext.ManageClassroomStudentListItem\n });\n }\n });\n\n actions.push({\n label: getPhrase('removeStudent'),\n appLink: getRemoveStudentsAppLink(props.student.id, props.classroom.id),\n disabled: props.readOnly,\n className: props.readOnly ? 'disabled' : 'text-danger',\n tooltip: props.readOnly ? props.readOnlyTooltip : '',\n onClick: () => {\n AnalyticsHelper.logUserAction({\n id: props.classroom.id,\n name: props.classroom.name,\n userId: props.student.id\n }, {\n actionType: UserAction.Dissociate,\n entity: EntityType.Classroom,\n descriptor: AssocDescriptor.User,\n workflowPhase: WorkflowPhase.Start,\n location: LocationContext.ManageClassroomStudentListItem\n });\n }\n });\n\n return actions;\n }\n\n return (\n <div className='d-flex align-items-center py-1 px-4'>\n <Checkbox\n id={props.student.id}\n checked={props.checked}\n onChange={props.onToggleCheckbox}\n className='me-2'\n disabled={props.readOnly}\n />\n\n <div className={`${styles.avatarContainer} flex-shrink-0 me-2`}>\n <Avatar\n imageCdnUrl={props.config.imageCdnUrl}\n initials={UserHelper.getInitials(props.student.name, props.student.surname)}\n imageUrl={props.student.avatar?.url}\n />\n </div>\n\n <p className={`me-2 ${styles.name} text-truncate mb-0 text-nowrap`}>{props.student.name} {props.student.surname}</p>\n\n <div\n // When we are computing the truncation, we want all group elements to be rendered but invisible.\n className={`${isComputingTruncation ? 'invisible' : ''} me-auto d-flex flex-wrap mt-n1`}\n ref={groupListRef}\n >\n {props.selectedGroups.map(group => {\n if (!groupVisibilityMapping[group.id]) // Don't render any groups that are marked as hidden\n return <React.Fragment key={group.id}></React.Fragment>;\n\n return (\n <div key={group.id} className='me-1 mt-1' id={group.id}>\n <ClassroomGroupPill group={group} />\n </div>\n );\n })}\n <div ref={expanderRef} className='me-1 mt-1'>\n <ClassroomGroupExpander count={getInvisibleGroupCount()} onClick={onClickShowAllGroups} />\n </div>\n </div>\n\n <ClassroomGroupDropdown\n id={`add-group-${props.student.id}`}\n classroom={props.classroom}\n groups={props.classroomGroups}\n selectedStudents={[props.student]}\n preselections={props.selectedGroups}\n onSelectGroup={(group, toggleOn) => props.onToggleGroup(props.student, group, toggleOn)}\n analyticsOptions={{ location: LocationContext.ManageClassroomStudentListItem }}\n alignRight\n disabled={props.readOnly}\n disabledTooltips={props.readOnlyTooltip}\n />\n\n <MoreActions\n actions={getActions()}\n actionsDropdownClassName='btn'\n />\n </div>\n );\n}","import * as React from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\nimport { Flight } from 'libs/common/flight';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { AssocDescriptor, EntityType, LocationContext, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { DivButton } from 'libs/shared/components/div-button/DivButton';\nimport { Checkbox } from 'libs/shared/components/forms/form-checkbox/Checkbox';\nimport { IconButton } from 'libs/shared/components/icon-button/IconButton';\nimport { SvgContainer } from 'libs/shared/components/svg-container/SvgContainer';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { Tooltip } from 'libs/shared/components/tooltip/Tooltip';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { useAlerts } from 'libs/shared/hooks/UseAlerts';\nimport { useBulkCheckboxManager } from 'libs/shared/hooks/useBulkCheckboxManager';\nimport { useMediaQuery } from 'libs/shared/hooks/UseMediaQuery';\nimport { Classroom, Config } from 'libs/shared/interfaces';\nimport { ClassroomGroup, User, UserCollection } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nimport { ClassroomGroupDropdown } from 'apps/classrooms/components/classroom-group-dropdown/ClassroomGroupDropdown';\nimport { ManageClassroomStudentItem } from 'apps/classrooms/components/manage-classroom-student-item/ManageClassroomStudentItem';\nimport { ClassroomRequests } from 'apps/classrooms/flight-requests/ClassroomRequests';\n\nimport { ManageClassroomStudentsEmptyState } from './empty-state/ManageClassroomStudentsEmptyState';\n\nconst namespace = 'classrooms.manageClassroomStudents';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface ManageClassroomStudentsProps {\n classroom: Classroom;\n students: UserCollection;\n schoolHasNoStudents: boolean;\n canManageUsers: boolean;\n groups: ClassroomGroup[];\n config: Config;\n onToggleGroup: (student: User, group: ClassroomGroup, toggleOn: boolean) => void;\n onBulkSelectGroup: (students: User[], group: ClassroomGroup, shouldAdd: boolean) => void;\n readOnly?: boolean;\n}\n\nexport function ManageClassroomStudents(props: ManageClassroomStudentsProps): JSX.Element {\n const { classroom, students, groups } = props;\n\n const dispatch = useDispatch();\n const alerts = useAlerts();\n\n const CheckboxHelper = useBulkCheckboxManager(students.data);\n const selectionCount = CheckboxHelper.getSelected().length;\n\n const bulkPreselections = groups.filter(group => {\n if (!group.users?.data?.length)\n return false;\n\n let allStudentsFound = true;\n let index = 0;\n\n const studentIds = CheckboxHelper.getSelected();\n\n if (!studentIds.length)\n return;\n\n do {\n const id = studentIds[index];\n if (!group.users.data.find((stu: any) => stu.id.toString() === id.toString()))\n allStudentsFound = false;\n\n index++;\n } while (index < studentIds.length);\n\n return allStudentsFound;\n });\n\n function onClickAddStudents(): void {\n AnalyticsHelper.logUserAction({ id: classroom.id }, {\n entity: EntityType.Classroom,\n descriptor: AssocDescriptor.User,\n workflowPhase: WorkflowPhase.Start,\n actionType: UserAction.Associate,\n location: LocationContext.ManageClassroomStudents\n });\n\n Core.AppLinkHelper.trigger({\n application: AppChannels.CLASSROOMS,\n action: Actions.Classrooms.ADD_STUDENTS_CHOICES,\n args: [classroom.id]\n });\n }\n\n function onClickBulkRemoveStudents(): void {\n if (!selectionCount || props.readOnly)\n return;\n\n const studentIds = CheckboxHelper.getSelected();\n\n AnalyticsHelper.logUserAction({\n id: classroom.id,\n studentCount: studentIds.length\n }, {\n entity: EntityType.Classroom,\n descriptor: AssocDescriptor.User,\n workflowPhase: WorkflowPhase.Start,\n actionType: UserAction.Dissociate,\n location: LocationContext.ManageClassroomStudents\n });\n\n Core.AppLinkHelper.trigger({\n application: AppChannels.CLASSROOMS,\n action: Actions.Classrooms.REMOVE_STUDENTS,\n args: [classroom.id],\n params: {\n studentIds\n }\n });\n }\n\n function onSelectGroup(group: ClassroomGroup, shouldAdd: boolean): void {\n const selectedStudentIds = CheckboxHelper.getSelected();\n // optimistically update the UI on bulk add/remove\n props.onBulkSelectGroup(students.data.filter(s => selectedStudentIds.includes(s.id.toString())), group, shouldAdd);\n\n const request = shouldAdd ? ClassroomRequests.addStudentsToGroup : ClassroomRequests.removeStudentsFromGroup;\n\n Flight.fetch(\n dispatch,\n request(selectedStudentIds, group.id, classroom.id, () => {\n AnalyticsHelper.logUserAction({\n id: group.id,\n studentCount: selectedStudentIds.length\n }, {\n actionType: UserAction.Associate,\n entity: EntityType.ClassroomGroup,\n descriptor: AssocDescriptor.User,\n workflowPhase: WorkflowPhase.Complete,\n location: LocationContext.ManageClassroomStudents\n });\n\n alerts.success(getPhrase('addSuccess', { groupName: group.name, escapeText: true }));\n }, () => {\n alerts.error(getPhrase('addError', { groupName: group.name, escapeText: true }));\n })\n );\n }\n\n const edgeToEdge = useMediaQuery(MediaQueryStrings.XLDown);\n\n if (!students.data?.length) {\n return (\n <ManageClassroomStudentsEmptyState\n classroom={props.classroom}\n classroomIdeasText={getPhrase('classroomIdeasText')}\n schoolHasNoStudents={props.schoolHasNoStudents}\n canManageUsers={props.canManageUsers}\n />\n );\n }\n\n const selectedStudents = CheckboxHelper\n .getSelected()\n .map(id => {\n return props.students.data.find(s => s.id.toString() === id.toString());\n })\n .filter(s => !!s);\n\n return (\n <>\n <div className={`d-flex align-items-center py-2 ${edgeToEdge ? 'ps-2' : 'ps-4'}`}>\n <Checkbox\n id='manage-classroom-students-bulk'\n onChange={CheckboxHelper.onToggleBulk}\n checked={CheckboxHelper.bulkChecked}\n className='me-2'\n indeterminate={CheckboxHelper.hasSomeSelections()}\n disabled={props.readOnly}\n />\n\n <ClassroomGroupDropdown\n id='bulk-add-group'\n classroom={classroom}\n selectedStudents={selectedStudents}\n isBulk\n groups={groups}\n onSelectGroup={onSelectGroup}\n disabled={!selectionCount || props.readOnly}\n preselections={bulkPreselections}\n analyticsOptions={{ location: LocationContext.ManageClassroomStudents }}\n disabledTooltips={props.readOnly && LanguageService.getPhrase(namespace, 'disabledByRostering')}\n />\n <DivButton\n className={`me-auto ${!selectionCount || props.readOnly ? 'text-light cursor-default' : ''}`}\n onClick={onClickBulkRemoveStudents}\n >\n <Tooltip\n spanHack\n title={props.readOnly ? LanguageService.getPhrase(namespace, 'disabledByRostering') : ''}\n >\n <SvgContainer\n svgName={cvSvgLibrary.Delete}\n title={LanguageService.getPhrase(namespace, 'delete')}\n tooltipPlacement='top'\n tooltipSpanHack\n />\n </Tooltip>\n </DivButton>\n <Tooltip\n spanHack\n title={props.readOnly ? LanguageService.getPhrase(namespace, 'disabledByRostering') : ''}\n >\n <IconButton\n onClick={onClickAddStudents}\n svgName={cvSvgLibrary.Plus}\n className='btn btn-outline-dark'\n disabled={props.readOnly}\n >\n <Text namespace={namespace} phrase='addStudent' />\n </IconButton>\n </Tooltip>\n </div>\n\n <ul className='striped-list list-unstyled'>\n {students.data.map(student => (\n <li key={student.id}>\n <ManageClassroomStudentItem\n classroom={classroom}\n student={student}\n classroomGroups={props.groups}\n config={props.config}\n selectedGroups={props.groups.filter(g => g.users.data.find(u => u.id === student.id))}\n checked={CheckboxHelper.isChecked(student.id)}\n onToggleCheckbox={() => CheckboxHelper.onToggleItem(student.id)}\n onToggleGroup={props.onToggleGroup}\n readOnly={props.readOnly}\n readOnlyTooltip={props.readOnly ? getPhrase('disabledByRostering') : ''}\n />\n </li>\n ))}\n </ul>\n </>\n );\n}\n","import React from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { AssocDescriptor, EntityType, LocationContext, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { Pagination } from 'libs/shared/components/pagination/Pagination';\nimport { RosteringAlert } from 'libs/shared/components/rostering/rostering-alert/RosteringAlert';\nimport { PermissionName } from 'libs/shared/enums/PermissionName';\nimport { UserGroup } from 'libs/shared/enums/UserGroup';\nimport { ConfigRequests } from 'libs/shared/flight-requests/ConfigRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { usePermissions } from 'libs/shared/hooks/usePermissions';\nimport { useSetPageMetadata } from 'libs/shared/hooks/useSetPageMetadata';\nimport { useSettings } from 'libs/shared/hooks/useSettings';\nimport { Classroom, ClassroomGroup, ClassroomGroupCollection, Config, CurrentUser, User, UserCollection } from 'libs/shared/interfaces';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nimport { ManageClassroomStudentsEmptyState, RosteredClassroomStudentsEmptyState } from 'apps/classrooms/components/manage-classroom-students/empty-state/ManageClassroomStudentsEmptyState';\nimport { ManageClassroomStudents } from 'apps/classrooms/components/manage-classroom-students/ManageClassroomStudents';\nimport { PartialManageClassroomStudents } from 'apps/classrooms/components/manage-classroom-students/partial-loading/PartialManageClassroomStudents';\nimport { ClassroomRequests } from 'apps/classrooms/flight-requests/ClassroomRequests';\nimport { useHandleClassroomErrors } from 'apps/classrooms/hooks/useHandleClassroomErrors';\nimport { ClassroomLayout } from 'apps/classrooms/layouts/ClassroomLayout';\nimport { UserManagerRequests } from 'apps/user-manager/flight-requests/UserManagerRequests';\n\nconst namespace = 'classrooms.classroomStudents';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nconst baseAnalyticsOptions = {\n entity: EntityType.ClassroomGroup,\n descriptor: AssocDescriptor.User,\n workflowPhase: WorkflowPhase.Complete,\n location: LocationContext.ManageClassroomStudentListItem\n};\n\ninterface ClassroomStudentsViewProps {\n id: string;\n cursor: string;\n}\n\nexport function ClassroomStudentsView(props: ClassroomStudentsViewProps): JSX.Element {\n const { hasShareFlowV2 } = useSettings(null);\n const currentUser = Flight.useBasicFetch<CurrentUser>(UserRequests.currentUser());\n const classroom = Flight.useBasicFetch<Classroom>(currentUser.data &&\n ClassroomRequests.getClassroom(props.id, currentUser.data.id));\n const students = Flight.useBasicFetch<UserCollection>(ClassroomRequests.getClassroomStudents(props.id, props.cursor));\n const allStudents = Flight.useBasicFetch<UserCollection>(currentUser.data &&\n UserManagerRequests.getUsers(currentUser.data.customerId, UserGroup.Learner));\n const groups = Flight.useBasicFetch<ClassroomGroupCollection>(ClassroomRequests.getClassroomGroups(props.id));\n const config = Flight.useBasicFetch<Config>(ConfigRequests.config());\n\n // Maintain a localGroups to optimistically update the UI\n const [ localGroups, setLocalGroups ] = React.useState<ClassroomGroup[]>(groups.data?.data);\n React.useEffect(() => {\n if (groups.hasCompleted && !groups.isFetching)\n setLocalGroups(groups.data.data);\n }, [ groups.hasCompleted, groups.isFetching ]);\n\n const isRostered = classroom.data?._integrations?.rostered;\n\n const dispatch = useDispatch();\n const { hasPermissions } = usePermissions();\n\n useSetPageMetadata({\n title: getPhrase('pageTitle', { classroomName: classroom.data?.name })\n });\n useHandleClassroomErrors(classroom);\n\n function onToggleGroup(student: User, group: ClassroomGroup, toggleOn: boolean): void {\n const analyticsData = {\n id: group.id,\n studentCount: 1\n };\n\n // optimistically update the UI\n let updatedGroups = [...localGroups];\n if (!toggleOn) {\n updatedGroups = updatedGroups.map(g => {\n if (g.id === group.id) {\n return {\n ...g,\n users: {\n ...g.users,\n data: g.users.data.filter(s => s.id !== student.id)\n }\n };\n }\n return g;\n });\n } else {\n updatedGroups = updatedGroups.map(g => {\n if (g.id === group.id) {\n return {\n ...g,\n users: {\n ...g.users,\n data: ArrayHelper.uniq([ ...g.users.data, student ], 'id')\n }\n };\n }\n return g;\n });\n }\n setLocalGroups(updatedGroups);\n\n // send the request\n const request = toggleOn\n ? ClassroomRequests.addStudentsToGroup([student.id], group.id, props.id, () => {\n AnalyticsHelper.logUserAction(analyticsData, {\n ...baseAnalyticsOptions,\n actionType: UserAction.Associate\n });\n })\n : ClassroomRequests.removeStudentsFromGroup([student.id], group.id, props.id, () => {\n AnalyticsHelper.logUserAction(analyticsData, {\n ...baseAnalyticsOptions,\n actionType: UserAction.Dissociate\n });\n });\n\n Flight.fetch(dispatch, request);\n }\n // optimistically update the UI on bulk add/remove\n function onBulkSelectGroup(students: User[], group: ClassroomGroup, shouldAdd: boolean): void {\n let updatedGroups = [...localGroups];\n if (!shouldAdd) {\n updatedGroups = updatedGroups.map(g => {\n if (g.id !== group.id) {\n return g;\n }\n\n return {\n ...g,\n users: {\n ...g.users,\n data: g.users.data.filter(s => !students.some(stu => stu.id === s.id))\n }\n };\n });\n } else {\n updatedGroups = updatedGroups.map(g => {\n if (g.id !== group.id) {\n return g;\n }\n return {\n ...g,\n users: {\n ...g.users,\n data: ArrayHelper.uniq([ ...g.users.data, ...students ], 'id')\n }\n };\n });\n }\n setLocalGroups(updatedGroups);\n }\n\n function onTogglePin(shouldPin: boolean, onSuccess: () => void, onError: () => void): void {\n if (isRostered)\n return;\n const request = shouldPin\n ? ClassroomRequests.pinClassroom\n : ClassroomRequests.unpinClassroom;\n\n Flight.fetch(dispatch, request(classroom.data, onSuccess, onError));\n }\n\n if (\n !classroom.data\n || !students.data?.data\n || !groups.data?.data\n || !config.data\n || !allStudents.data\n || !localGroups\n )\n return <PartialManageClassroomStudents />;\n\n return (\n <ClassroomLayout\n classroom={classroom.data}\n currentUser={currentUser.data}\n onTogglePin={onTogglePin}\n activeTab='students'\n isRostered={isRostered}\n hasShareFlowV2={hasShareFlowV2}\n >\n {(() => {\n if (isRostered)\n return (\n <>\n <RosteringAlert type='classroom'/>\n {!students.data?.data?.length ? (\n <RosteredClassroomStudentsEmptyState />\n ) : (\n <ManageClassroomStudents\n classroom={classroom.data}\n students={students.data}\n groups={localGroups}\n onToggleGroup={onToggleGroup}\n onBulkSelectGroup={onBulkSelectGroup}\n config={config.data}\n schoolHasNoStudents={!allStudents.data?.data?.length}\n canManageUsers={hasPermissions(PermissionName.ManageUsers)}\n readOnly\n />\n )}\n </>\n );\n\n if (students.data?.data?.length) {\n return (\n <ManageClassroomStudents\n classroom={classroom.data}\n students={students.data}\n groups={localGroups}\n onToggleGroup={onToggleGroup}\n onBulkSelectGroup={onBulkSelectGroup}\n config={config.data}\n schoolHasNoStudents={!allStudents.data?.data?.length}\n canManageUsers={hasPermissions(PermissionName.ManageUsers)}\n />\n );\n }\n\n return (\n <ManageClassroomStudentsEmptyState\n classroom={classroom.data}\n classroomIdeasText={getPhrase('classroomIdeasText')}\n schoolHasNoStudents={!allStudents.data?.data?.length}\n canManageUsers={hasPermissions(PermissionName.ManageUsers)}\n />\n );\n })()}\n\n {!!students.data?.pagination?.cursors && (\n <Pagination\n appLink={{\n application: AppChannels.CLASSROOMS,\n action: Actions.Classrooms.CLASSROOM_STUDENTS,\n args: [props.id]\n }}\n cursors={students.data?.pagination?.cursors}\n buttonVariant='outline-dark'\n className='py-2 float-end'\n prevHack\n />\n )}\n </ClassroomLayout>\n );\n}\n","import { PermissionName } from 'libs/shared/enums/PermissionName';\nimport { usePermissions } from 'libs/shared/hooks/usePermissions';\nimport { useSettings } from 'libs/shared/hooks/useSettings';\n\ntype ClassroomExperience = 'none' | 'minimal' | 'full';\n\nexport function useClassroomExperience() {\n const { hasShareFlowV2, hasClassrooms, isLoadingSettings } = useSettings(null);\n const { hasPermissions, isLoaded } = usePermissions();\n\n function getExperience(): ClassroomExperience {\n if (!hasClassrooms)\n return 'none';\n\n if (hasPermissions(PermissionName.ViewClassrooms))\n return 'full';\n \n if (hasShareFlowV2)\n return 'minimal';\n }\n\n return {\n experience: getExperience(),\n loading: isLoadingSettings || !isLoaded\n };\n}"],"names":["getPhrase","RosteringAlert","props","text","type","className","useBulkCheckboxManager","collection","options","idField","persistNamespace","initial","initialState","Map","items","forceUpdate","prevCollection","prevNamespace","reset","current","clear","isChecked","item","toString","get","isBulkChecked","length","every","setSelected","ids","forEach","id","set","map","i","join","preselectedIds","onToggleBulk","setValue","onToggleItem","nextItemState","getSelected","Array","from","keys","bulkChecked","deselectAll","hasSomeSelections","find","getSelectedCount","size","getMap","mapColourToBsVariant","groupColour","PartialManageClassroomStudents","numItems","PartialPillTabSelector","fill","student","key","Math","random","namespace","ClassroomsNoStudentsState","value","EmptyState","src","ImageUrls","Text","phrase","canManageUsers","isRostering","LanguageService","appLink","application","action","href","target","STUDENT_ENGAGEMENT_IDEAS_LINK","ROSTERING_KB_ARTICLE_URL","RosteredClassroomStudentsEmptyState","ManageClassroomStudentsEmptyState","schoolHasNoStudents","icon","args","classroom","classroomIdeasText","ClassroomGroupPill","group","metadata","colour","title","name","ClassroomGroupExpander","count","DivButton","onClick","getNewGroupAppLink","students","params","addStudents","s","ClassroomGroupDropdown","groups","preselections","studentsAllInGroupLookup","reduce","acc","groupUserIds","Set","users","data","u","has","checkStudentsAllInGroup","selectedStudents","g","totalCheckedForGroup","Object","entries","sort","a","b","localeCompare","dropdownProps","align","alignRight","disabled","show","Dropdown","as","SvgContainer","svgName","disabledTooltips","tooltipPlacement","tooltipSpanHack","tooltipSpanHackClassName","isEmptyChecked","checkStudentsNotInGroup","isIndeterminate","isBulk","Checkbox","checked","onChange","shouldAdd","onSelectGroup","indeterminate","AppLink","AnalyticsHelper","analyticsOptions","actionType","workflowPhase","entity","defaultProps","getEditStudentAppLink","userType","UserGroup","getRemoveStudentsAppLink","studentId","classroomId","studentIds","ManageClassroomStudentItem","isComputingTruncation","setIsComputingTruncation","hasExpandedGroups","setHasExpandedGroups","groupVisibilityMapping","setGroupVisibilityMapping","groupListRef","expanderRef","selectedGroupsRef","selectedGroups","hasPermissions","usePermissions","renderAllGroups","actions","throttledResizeListener","FunctionHelper","firstGroupPill","firstElementChild","lastVisibleId","topRowHeight","getBoundingClientRect","y","nextGroupVisibilityMapping","children","child","onToggleCheckbox","readOnly","Avatar","imageCdnUrl","config","initials","UserHelper","surname","imageUrl","avatar","url","ref","groupId","classroomGroups","toggleOn","onToggleGroup","location","readOnlyTooltip","PermissionName","push","label","tooltip","userId","descriptor","actionsDropdownClassName","ManageClassroomStudents","dispatch","alerts","CheckboxHelper","selectionCount","bulkPreselections","filter","allStudentsFound","index","stu","edgeToEdge","selectedStudentIds","onBulkSelectGroup","includes","request","ClassroomRequests","studentCount","success","groupName","escapeText","error","Tooltip","spanHack","IconButton","baseAnalyticsOptions","ClassroomStudentsView","hasShareFlowV2","useSettings","currentUser","UserRequests","cursor","allStudents","UserManagerRequests","customerId","ConfigRequests","localGroups","setLocalGroups","hasCompleted","isFetching","isRostered","_integrations","rostered","analyticsData","updatedGroups","ArrayHelper","some","useSetPageMetadata","classroomName","useHandleClassroomErrors","ClassroomLayout","onTogglePin","shouldPin","onSuccess","onError","activeTab","pagination","cursors","Pagination","buttonVariant","prevHack","useClassroomExperience","hasClassrooms","isLoadingSettings","isLoaded","experience","loading"],"sourceRoot":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scripts/4208-0706461da6-lite.chunk.js","mappings":"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","sources":["file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/IllustrationResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/MissingWordResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/MultipleChoiceResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/TrueOrFalseResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/ShortAnswerResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/interaction-response-item.scss","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/InteractionResponseItem.tsx","file:///app/packages/libs/shared/src/utils/AnalyticsRequestUtils.ts","file:///app/packages/libs/shared/src/apps/analytics/flight-requests/InteractiveResultsRequests.ts","file:///app/packages/libs/shared/src/apps/analytics/hooks/UseMarkAnswers.ts","file:///app/packages/libs/shared/src/apps/analytics/utils/InteractiveUtils.ts"],"sourcesContent":["import React from 'react';\n\nimport { SvgContainer } from 'libs/shared/components/svg-container/SvgContainer';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { StudentAnswer } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\ninterface AnswerContainerProps extends React.PropsWithChildren {\n answer: StudentAnswer;\n textClassName?: string;\n customAnswer?: boolean;\n}\n\nexport function AnswerContainer(props: AnswerContainerProps) {\n const { answer } = props;\n\n function getBgColour(status: InteractiveAnswerStatus) {\n switch (status) {\n case InteractiveAnswerStatus.Correct: return 'bg-light-green';\n case InteractiveAnswerStatus.Incorrect: return 'bg-light-red';\n case InteractiveAnswerStatus.PendingReview: return 'bg-light-blue';\n }\n }\n\n return (\n <div key={answer.id} className={`${getBgColour(answer.status)} rounded p-2 mb-2`}>\n <div className='d-flex align-items-center gap-2'>\n {answer.status === InteractiveAnswerStatus.Correct && <SvgContainer svgName={cvSvgLibrary.Check} className='svg-container flex-shrink-0 text-success' />}\n {answer.status === InteractiveAnswerStatus.Incorrect && <SvgContainer svgName={cvSvgLibrary.Close} className='svg-container flex-shrink-0 text-danger' />}\n {!props.customAnswer && <span className={props.textClassName}>{answer.text}</span>}\n </div>\n {props.children}\n </div>\n );\n}","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\nconst namespace = 'shared.interactionResponses';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport function IllustrationResponse(props: ResponseItemComponentProps): JSX.Element {\n const answer = ArrayHelper.first(props.answers);\n\n if (!answer)\n return <></>;\n\n return (\n <AnswerContainer answer={answer} customAnswer>\n <div className='ratio ratio-16x9'>\n <img\n className='img-fluid bg-white border rounded h-100 w-100'\n src={answer.text}\n alt={`${getPhrase('illustrationAlt')}: ${props.interaction.name}`}\n />\n </div>\n {props.children}\n </AnswerContainer>\n );\n}","import React from 'react';\n\nimport { Interaction, InteractionTypeId, StudentAnswer, User } from 'libs/shared/interfaces';\n\nimport { IllustrationResponse } from './components/IllustrationResponse';\nimport { MissingWordResponse } from './components/MissingWordResponse';\nimport { MultipleChoiceResponse } from './components/MultipleChoiceResponse';\nimport { ShortAnswerResponse } from './components/ShortAnswerResponse';\nimport { TrueOrFalseResponse } from './components/TrueOrFalseResponse';\n\nexport interface ResponseItemComponentProps extends React.PropsWithChildren {\n interaction: Interaction;\n answers: StudentAnswer[];\n imageCdnUrl: string;\n user: User;\n showFeedback?: boolean;\n showAvatar?: boolean;\n anonymisedUserName?: string;\n}\nconst NoResponseRequired = () => <></>;\n\nexport const ResponseItemComponentLookup: {\n [typeId: number]: (props: ResponseItemComponentProps) => JSX.Element\n} = {\n [InteractionTypeId.Annotation]: NoResponseRequired,\n [InteractionTypeId.Image]: NoResponseRequired,\n [InteractionTypeId.MissingWord]: MissingWordResponse,\n [InteractionTypeId.MultipleChoice]: MultipleChoiceResponse,\n [InteractionTypeId.TrueOrFalse]: TrueOrFalseResponse,\n [InteractionTypeId.ShortAnswer]: ShortAnswerResponse,\n [InteractionTypeId.Illustration]: IllustrationResponse\n};","import React from 'react';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\n\nexport function MissingWordResponse(props: ResponseItemComponentProps) {\n if (!props.answers.length) return <></>;\n\n return (\n <ul className='list-unstyled'>\n {props.answers.map(answer => (\n <li key={answer.id}>\n <AnswerContainer\n answer={answer}\n textClassName='bg-white p-1 border border-gray-300 rounded'\n />\n </li>\n ))}\n </ul>\n );\n}","import React from 'react';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\nexport function MultipleChoiceResponse(props: ResponseItemComponentProps) {\n if (!props.answers.length) return <></>;\n\n return (\n <ul className='list-unstyled'>\n {props.answers.map(answer => (\n <li key={answer.id}>\n <AnswerContainer answer={answer} />\n </li>\n ))}\n </ul>\n );\n}","import React from 'react';\n\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\nexport function TrueOrFalseResponse(props: ResponseItemComponentProps) {\n const answer = ArrayHelper.first(props.answers);\n\n if (!answer)\n return <></>;\n\n return (\n <AnswerContainer answer={answer} />\n );\n}","import React from 'react';\n\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\nexport function ShortAnswerResponse(props: ResponseItemComponentProps): JSX.Element {\n const answer = ArrayHelper.first(props.answers);\n\n if (!answer)\n return <></>;\n\n return (\n <AnswerContainer answer={answer}>\n {props.children}\n </AnswerContainer>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"avatarContainer\":\"O7oaA\"};","import React from 'react';\n\nimport { ResponseItemComponentLookup } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\nimport { Avatar } from 'libs/shared/components/avatar/Avatar';\nimport { InteractionResponseCorrectness } from 'libs/shared/components/interaction-response/InteractionResponseCorrectness';\nimport { InteractionStudentDetailsHeader } from 'libs/shared/components/interaction-response/InteractionStudentDetailsHeader';\nimport { MarkResponse } from 'libs/shared/components/interaction-response/MarkResponse';\nimport { NoResponse } from 'libs/shared/components/interaction-response/response-types/NoResponse';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { Interaction, StudentAnswer, StudentResults } from 'libs/shared/interfaces';\nimport { InteractiveCorrectnessHelper } from 'libs/shared/utils/InteractiveCorrectnessHelper';\nimport { getStudentAttempt, getStudentResult } from 'libs/shared/utils/InteractiveHelper';\nimport { UserHelper } from 'libs/shared/utils/UserHelper';\n\nimport styles from './interaction-response-item.scss';\n\ninterface InteractionResponseProps {\n interaction: Interaction;\n studentResults: StudentResults;\n imageCdnUrl: string;\n markInteraction: (answers: StudentAnswer[], status: InteractiveAnswerStatus) => void;\n markedStatus?: InteractiveAnswerStatus;\n showStudentDetails?: boolean;\n className?: string;\n showFeedback?: boolean;\n showAvatar?: boolean;\n anonymisedUserName?: string;\n responseComponentClass?: string;\n}\n\nexport function InteractionResponseItem(props: InteractionResponseProps): JSX.Element {\n const ResponseItemComponent = ResponseItemComponentLookup[props.interaction.typeId];\n\n if (!ResponseItemComponent)\n return <></>;\n\n const result = getStudentResult(props.studentResults);\n\n const studentAttempt = getStudentAttempt(props.interaction.id, result);\n\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(props.interaction, result);\n\n return (\n <div className='position-relative'>\n <div className={`rounded ${props.className ?? ''}`}>\n <div className='d-flex'>\n {!!props.showStudentDetails &&\n <div className='me-2'>\n <div className={styles.avatarContainer}>\n <Avatar\n imageCdnUrl={props.imageCdnUrl}\n initials={props.anonymisedUserName\n ? UserHelper.getInitialsFromFullName(props.anonymisedUserName)\n : UserHelper.getInitials(props.studentResults.user?.name, props.studentResults.user?.surname)\n }\n imageUrl={props.anonymisedUserName ? null : props.studentResults.user?.avatar?.url}\n showAnonymousUser={!!props.studentResults?.user?.sessionId}\n />\n </div>\n \n </div>\n }\n <div className='flex-grow-1'>\n {!!props.showStudentDetails &&\n <InteractionStudentDetailsHeader\n studentResults={props.studentResults}\n correctness={correctness}\n anonymisedUserName={props.anonymisedUserName}\n />\n }\n <div className='d-flex justify-content-between'>\n <div className={`flex-grow-1 mb-2 ${props.responseComponentClass ? props.responseComponentClass : ''}`}>\n {studentAttempt\n ? <ResponseItemComponent\n interaction={props.interaction}\n answers={studentAttempt.answers}\n imageCdnUrl={props.imageCdnUrl}\n user={props.studentResults.user}\n showFeedback={props.showFeedback}\n showAvatar={props.showAvatar}\n >\n <MarkResponse\n studentAttempt={studentAttempt}\n correctness={correctness}\n markInteraction={props.markInteraction}\n markedStatus={props.markedStatus}\n />\n </ResponseItemComponent>\n : <NoResponse />\n }\n </div>\n {!props.showStudentDetails &&\n <InteractionResponseCorrectness correctness={correctness} />\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}","import { AnalyticsRequestFilter } from 'libs/shared/interfaces';\n\nexport function getAnalyticsRequestKey(baseKey: string, filter: AnalyticsRequestFilter, extra?: string): string {\n if (!filter)\n return baseKey;\n\n let key = `${baseKey}:${filter.start}:${filter.end}`;\n\n const userIdKey = Array.isArray(filter.userId) ? filter.userId.sort().join(':') : filter.userId;\n const groupIdKey = Array.isArray(filter.groupId) ? filter.groupId.sort().join(':') : filter.groupId;\n const customerIdKey = Array.isArray(filter.customerId) ? filter.customerId.sort().join(':') : filter.customerId;\n\n if (userIdKey)\n key += `:${userIdKey}`;\n\n if (groupIdKey)\n key += `:${groupIdKey}`;\n\n if (customerIdKey)\n key += `:${customerIdKey}`;\n\n if (extra)\n key += `:${extra}`;\n\n return key;\n}","import { HttpVerbs } from 'libs/common/backbone/enums/HttpVerbs';\nimport { Flight } from 'libs/common/react/index';\n\nimport { MarkInteractiveAnswer } from 'libs/shared/apps/analytics/interfaces/MarkInteractiveAnswer';\nimport { InteractiveResultsReport } from 'libs/shared/apps/analytics/interfaces/requests/InteractiveResultsReport';\nimport { InteractivesPendingReviewsRequest } from 'libs/shared/apps/analytics/interfaces/requests/InteractivesPendingReviewsRequest';\nimport { AnalyticsRequestFilter, CurrentUser, InteractiveResultSet } from 'libs/shared/interfaces';\nimport { getAnalyticsRequestKey } from 'libs/shared/utils/AnalyticsRequestUtils';\n\ninterface InteractiveResultFilters {\n currentUserId: string;\n currentCustomerId: string;\n dateRange?: { start: string, end: string }\n userIds?: string | string[];\n classroomsAndGroups?: string | string[];\n shareId?: string;\n}\n\nfunction getInteractiveResultFilters(\n currentUser: CurrentUser,\n filter: AnalyticsRequestFilter,\n shareId?: string\n): InteractiveResultFilters {\n return {\n currentUserId: currentUser.id,\n currentCustomerId: currentUser.customerId,\n dateRange: filter ? { start: filter.start, end: filter.end } : undefined,\n userIds: filter?.userId,\n classroomsAndGroups: filter?.groupId,\n shareId: shareId\n };\n}\n\nexport const InteractiveResultsRequests = {\n /** \n * This endpoint returns data with a lot of duplicated ids,\n * e.g. student answers to the same question will have the same id.\n * Because of that, we don't normalize.\n */\n interactiveResultSet(\n interactiveId: string,\n interactiveMetadataId: string,\n currentUser: CurrentUser,\n filter?: AnalyticsRequestFilter,\n shareId?: string,\n success?: (data: InteractiveResultSet) => void,\n error?: (data: any) => void,\n always?: () => void\n ): Flight.Request {\n return {\n url: shareId ?\n `/api/domain/v3/analytics/interactives/${interactiveId}/metadata/${interactiveMetadataId}` :\n `/api/domain/v2/analytics/interactives/${interactiveId}/metadata/${interactiveMetadataId}`,\n key: getAnalyticsRequestKey(`interactive:result:set:${interactiveId}:${interactiveMetadataId}:${shareId}`, filter),\n data: getInteractiveResultFilters(currentUser, filter, shareId),\n type: HttpVerbs.POST,\n normalize: false,\n success,\n error,\n always\n };\n },\n \n /**\n * As the response from `interactiveResultSet` isn't normalised, we need to invalidate the cache\n * to update the results data.\n */\n mark(\n interactiveId: string,\n interactiveMetadataId: string,\n answerId: string,\n data: MarkInteractiveAnswer,\n success?: () => void,\n error?: (data: any) => void,\n always?: () => void\n ): Flight.Request {\n return {\n url: `/api/domain/v1/analytics/answers/${answerId}`,\n key: `mark:answer:${answerId}:${data.resultId}`,\n type: HttpVerbs.PUT,\n data,\n normalize: false,\n invalidationKeys: `interactive:result:set:${interactiveId}:${interactiveMetadataId}`,\n success,\n error,\n always\n };\n },\n\n pendingReviews(data: InteractivesPendingReviewsRequest): Flight.Request {\n const key = data.interactives.map(interactive => `${interactive.interactiveId}:${interactive.metadataId}:${interactive.shareId}`).join(',');\n return {\n url: `/api/domain/v1/analytics/interactives/pending-reviews/summary`,\n key: `interactives:pending:reviews:${key}`,\n type: HttpVerbs.POST,\n data,\n normalize: false\n };\n },\n\n interactiveResultsReport(data: InteractiveResultsReport): Flight.Request {\n return {\n url: '/api/domain/v3/analytics/interactives/report',\n key: 'interactive:results:report',\n data,\n type: HttpVerbs.POST,\n normalize: false\n };\n }\n};","import { useState } from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\n\nimport { InteractiveResultsRequests } from 'libs/shared/apps/analytics/flight-requests/InteractiveResultsRequests';\nimport { getMarkedAnswerId } from 'libs/shared/apps/analytics/utils/InteractiveUtils';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { useAlerts } from 'libs/shared/hooks/UseAlerts';\nimport { StudentAnswer } from 'libs/shared/interfaces';\n\nconst getPhrase = LanguageService.encloseNamespace('reportsShared.dataHooks');\n\nexport type MarkedAnswerHash = { [id: string]: StudentAnswer };\n\n/**\n * This hook manages the storing of a marked answer hash in state and then the submitting\n * of those answers via an api call.\n */\nexport const useMarkAnswers = (interactiveId: string, interactiveMetadataId: string, onDone?: () => void) => {\n const [ markedAnswers, setMarkedAnswers ] = useState<MarkedAnswerHash>({});\n\n const dispatch = useDispatch();\n const alerts = useAlerts();\n\n function addMarkedAnswers(answers: StudentAnswer[], status: InteractiveAnswerStatus): void {\n answers.forEach(a => {\n setMarkedAnswers(m => ({ ...m, [getMarkedAnswerId(a)]: { ...a, status } }));\n });\n }\n\n function submitMarkedAnswers(): void {\n const answers = Object.keys(markedAnswers).map(key => markedAnswers[key]);\n\n if (!answers.length)\n return;\n\n let completeCount = 0;\n let successCount = 0;\n\n function onSuccess(): void {\n successCount++;\n }\n\n function onAlways(): void {\n completeCount++;\n\n if (completeCount === answers.length)\n onComplete();\n }\n\n function onComplete(): void {\n let alertMessage = '';\n let useErrorAlert = false;\n\n if (successCount === 0) {\n alertMessage = getPhrase('error', { smartCount: answers.length });\n useErrorAlert = true;\n }\n\n if (successCount < completeCount) {\n alertMessage = getPhrase('success', { smartCount: successCount })\n + ` ${getPhrase('partialError', { smartCount: completeCount - successCount })}`;\n }\n\n if (successCount === completeCount) {\n alertMessage = getPhrase('success', { smartCount: successCount });\n }\n\n useErrorAlert\n ? alerts.error(alertMessage)\n : alerts.success(alertMessage);\n\n setMarkedAnswers({});\n\n onDone && onDone();\n }\n\n answers.forEach(({ id, resultId, questionId, status }) => {\n Flight.fetch(dispatch, InteractiveResultsRequests.mark(\n interactiveId,\n interactiveMetadataId,\n id,\n { id, resultId, questionId, status },\n onSuccess,\n null,\n onAlways\n ));\n });\n }\n\n return {\n markedAnswers,\n addMarkedAnswers,\n submitMarkedAnswers\n };\n};","import { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { MarkedAnswerHash } from 'libs/shared/apps/analytics/hooks/UseMarkAnswers';\nimport { ResultsSummary } from 'libs/shared/apps/analytics/interfaces/ResultsSummary';\nimport { StudentResultsWithSummary } from 'libs/shared/apps/analytics/interfaces/StudentResultsWithSummary';\nimport { ScoreThresholdDefaults, ScoreThresholds } from 'libs/shared/constants/ScoreThresholds';\nimport { InteractionCorrectness } from 'libs/shared/enums/InteractionCorrectness';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { Interaction, StudentAnswer, StudentResults } from 'libs/shared/interfaces';\nimport { Interactive, InteractiveResultSet } from 'libs/shared/interfaces';\nimport { InteractiveCorrectnessHelper } from 'libs/shared/utils/InteractiveCorrectnessHelper';\nimport { flattenInteractions, getInteractions, getStudentAttempt, getStudentResult } from 'libs/shared/utils/InteractiveHelper';\n\ninterface StudentGroups {\n markingRequired: StudentResultsWithSummary[];\n lowScore: StudentResultsWithSummary[];\n highScore: StudentResultsWithSummary[];\n completed: StudentResultsWithSummary[];\n notCompleted: StudentResultsWithSummary[];\n}\n\nexport function groupStudents(\n interactive: Interactive,\n results: InteractiveResultSet,\n scoreThreshold?: ScoreThresholds\n): StudentGroups {\n const groups: StudentGroups = {\n markingRequired: [],\n lowScore: [],\n highScore: [],\n completed: [],\n notCompleted: []\n };\n\n const interactions = getInteractions(interactive);\n const interactionIds = new Set(interactions.map(i => i.id));\n \n results.students.forEach(s => {\n const withSummary = {\n ...s,\n summary: getStudentResultsSummary(interactive, s)\n };\n \n if (withSummary.summary.awaitingMarking) {\n groups.markingRequired.push(withSummary);\n return;\n }\n\n const result = ArrayHelper.last(s.results);\n const answeredInteractions = result.attempts.filter(a => !!interactionIds.has(a?.answers[0]?.questionId)).length;\n\n if (answeredInteractions === interactionIds.size) {\n groups.completed.push(withSummary);\n } else {\n groups.notCompleted.push(withSummary);\n return;\n }\n \n if (withSummary.summary.percentCorrect >= (scoreThreshold?.HIGH || ScoreThresholdDefaults.HIGH))\n groups.highScore.push(withSummary);\n \n if (withSummary.summary.percentCorrect < (scoreThreshold?.MODERATE || ScoreThresholdDefaults.MODERATE))\n groups.lowScore.push(withSummary);\n });\n \n const sortedLowScore = ArrayHelper.sortBy(groups.lowScore, s => s.summary.percentCorrect);\n const sortedHighScore = ArrayHelper.sortBy(groups.highScore, s => -s.summary.percentCorrect);\n \n return {\n ...groups,\n lowScore: sortedLowScore,\n highScore: sortedHighScore\n };\n}\n\nexport function getInteractionById(interactive: Interactive, interactionId: string): Interaction {\n const flattenedInteractions = flattenInteractions(interactive);\n return flattenedInteractions.find(i => i.id.toString() === interactionId.toString());\n}\n\n/**\n * We need to use the question and result ids as a list of one student's responses\n * to multiple questions will all have the same result id and a list of multiple\n * students responses to one question will all have the same questionId.\n */\nexport function getMarkedAnswerId(answer: StudentAnswer): string {\n return `${answer.questionId}:${answer.resultId}`;\n}\n\nexport function getMarkedStatus(\n interactionId: string,\n studentResults: StudentResults,\n markedAnswers: MarkedAnswerHash\n): InteractiveAnswerStatus {\n const result = getStudentResult(studentResults);\n const studentResponse = getStudentAttempt(interactionId, result);\n\n const isMarkedCorrect = studentResponse?.answers.every(a => {\n return markedAnswers[getMarkedAnswerId(a)]?.status === InteractiveAnswerStatus.Correct;\n });\n\n if (isMarkedCorrect)\n return InteractiveAnswerStatus.Correct;\n\n const isMarkedIncorrect = studentResponse?.answers.every(a => {\n return markedAnswers[getMarkedAnswerId(a)]?.status === InteractiveAnswerStatus.Incorrect;\n });\n\n if (isMarkedIncorrect)\n return InteractiveAnswerStatus.Incorrect;\n}\n\nexport function getInteractionResultsSummary(\n interaction: Interaction,\n results: InteractiveResultSet\n): ResultsSummary {\n const numStudents = results.students.length;\n let numCorrect = 0;\n let answered = 0;\n let unanswered = 0;\n let awaitingMarking = 0;\n let attempts = 0;\n\n results.students.forEach(s => {\n const result = getStudentResult(s);\n\n if (!result)\n return;\n\n attempts = attempts + s.results.length;\n\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(interaction, result);\n\n if (correctness === InteractionCorrectness.Correct)\n numCorrect++;\n\n if (correctness === InteractionCorrectness.UnAnswered)\n unanswered++;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n awaitingMarking++;\n\n if (correctness !== InteractionCorrectness.UnAnswered)\n answered++;\n });\n\n\n const percentCorrect = numStudents > 0\n ? numCorrect / numStudents\n : 0;\n\n return {\n percentCorrect,\n correct: numCorrect,\n answered,\n unanswered,\n awaitingMarking,\n attempts\n };\n}\n\nexport function getStudentResultsSummary(interactive: Interactive, studentResults: StudentResults): ResultsSummary {\n const result = getStudentResult(studentResults);\n\n const interactions = getInteractions(interactive);\n\n const numInteractions = interactions.length;\n\n let numCorrect = 0;\n let awaitingMarking = 0;\n\n interactions.forEach(i => {\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(i, result);\n\n if (correctness === InteractionCorrectness.Correct)\n numCorrect++;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n awaitingMarking++;\n });\n\n const percentCorrect = numInteractions > 0 ? numCorrect / numInteractions : 0;\n\n /**\n * Our interactions list has images and annotations filtered out.\n * We built a map of valid questions, so that we can calculate the unswered accurately.\n * We're doing this because of a bug that caused annotations and images to record answers in the player.\n * - Sha\n */\n const interactionIds = new Set(interactions.map(i => i.id));\n const answeredInteractions = result.attempts.filter(a => !!interactionIds.has(a?.answers[0]?.questionId)).length;\n\n return {\n answered: answeredInteractions,\n attempts: studentResults.results.length,\n unanswered: numInteractions - answeredInteractions,\n percentCorrect,\n correct: numCorrect,\n awaitingMarking\n };\n}"],"names":["AnswerContainer","props","answer","key","id","className","status","InteractiveAnswerStatus","getBgColour","SvgContainer","svgName","customAnswer","textClassName","text","children","getPhrase","LanguageService","NoResponseRequired","ResponseItemComponentLookup","answers","length","map","ArrayHelper","src","alt","interaction","name","InteractionResponseItem","ResponseItemComponent","typeId","result","studentResults","studentAttempt","correctness","InteractiveCorrectnessHelper","showStudentDetails","Avatar","imageCdnUrl","initials","anonymisedUserName","UserHelper","user","surname","imageUrl","avatar","url","showAnonymousUser","sessionId","InteractionStudentDetailsHeader","responseComponentClass","showFeedback","showAvatar","MarkResponse","markInteraction","markedStatus","NoResponse","InteractionResponseCorrectness","getAnalyticsRequestKey","baseKey","filter","extra","start","end","userIdKey","Array","isArray","userId","sort","join","groupIdKey","groupId","customerIdKey","customerId","getInteractiveResultFilters","currentUser","shareId","currentUserId","currentCustomerId","dateRange","undefined","userIds","classroomsAndGroups","InteractiveResultsRequests","interactiveResultSet","interactiveId","interactiveMetadataId","success","error","always","data","type","HttpVerbs","normalize","mark","answerId","resultId","invalidationKeys","pendingReviews","interactives","interactive","metadataId","interactiveResultsReport","useMarkAnswers","onDone","useState","markedAnswers","setMarkedAnswers","dispatch","alerts","addMarkedAnswers","forEach","a","m","submitMarkedAnswers","Object","keys","completeCount","successCount","questionId","I","onSuccess","onAlways","alertMessage","useErrorAlert","smartCount","groupStudents","results","scoreThreshold","groups","markingRequired","lowScore","highScore","completed","notCompleted","interactions","interactionIds","Set","i","students","s","withSummary","summary","getStudentResultsSummary","awaitingMarking","push","attempts","has","size","percentCorrect","HIGH","MODERATE","sortedLowScore","sortedHighScore","getInteractionById","interactionId","find","toString","getMarkedAnswerId","getMarkedStatus","studentResponse","every","getInteractionResultsSummary","numStudents","numCorrect","answered","unanswered","correct","numInteractions","answeredInteractions"],"sourceRoot":""}
|