From 435930a8277529b387cf798a48bacdb59e00405f Mon Sep 17 00:00:00 2001 From: Yamen Ahmad Date: Sun, 19 Apr 2026 03:13:23 +0400 Subject: [PATCH] feat: institutional + support + training admin sections (backend + frontend) Ship three fully-wired admin areas end-to-end with APIs, seeds, tests and docs. Backend (new `encoach_lms_api` addon + existing addons): - Institutional: academic years/terms, departments, admission registers & admissions, courses/batches, lessons, fees (terms + student fees + invoicing with income-account auto-wiring), gradebook (assignments/grades), library, facilities (encoach.asset), student leave, result templates + marksheets (incl. delete-with-cascade). - Support: `encoach.ticket` model + CRUD/assignee routes; payment records derived from `op.student.fees.details` and `account.move`; platform settings backed by `encoach.code` and `ir.config_parameter` (packages + grading config). - Training: `encoach.vocab.item` + `encoach.grammar.rule` (plus progress models) with CRUD, pagination, search/level filters, and upsert-style progress endpoints. Odoo 19 compatibility: `_sql_constraints` replaced with `@api.constrains`; `ValidationError`/`UserError` mapped to HTTP 400. Frontend: - Rewire institutional admin pages (Academic Year Manager, Admissions, Courses, Lessons, Fees, Gradebook, Library, Facilities, Student Leave, Marksheets, Taxonomy, Resources) to real APIs with React Query invalidation and dialogs. - New typed services: `payments.service.ts`, `platformSettings.service.ts`, `training.service.ts`. Updated `fees/gradebook/lms/courseware/taxonomy/ resources/student-progress/generation` services + related types. - Rewrite `VocabularyPage`, `GrammarPage`, `PaymentRecordPage`, `SettingsPage`, `TicketsPage` to consume live data with search/filter/progress/CRUD flows. - New shared components: `TaxonomyCascade`, `MaterialViewer`, `teacher/TeacherLibrary`. - Favicons/branding assets and misc. UX polish across teacher/student pages. Tooling & QA: - Seeders: `seed_demo.py`, `seed_demo_data.py`, `seed_institutional.py` (idempotent, covers institutional + support + training fixtures incl. income-account wiring). - API write-flow test suites: `test_write_flows.py` (institutional), `test_support_flows.py` (support), `test_training_flows.py` (training), `test_ai_full.py`. All suites pass end-to-end. - Docs: add `docs/PROJECT_SUMMARY.md` with per-section scope, artifacts and QA. - `.gitignore`: ignore `pgdata_bak_*/`, `frontend/.vite/`, `frontend/dist/`, `frontend/node_modules/`. Made-with: Cursor --- index.html | 6 + public/apple-touch-icon.png | Bin 0 -> 4406 bytes public/favicon-16x16.png | Bin 0 -> 532 bytes public/favicon-32x32.png | Bin 0 -> 888 bytes public/favicon.ico | Bin 20373 -> 554 bytes public/logo-icon.png | Bin 0 -> 14880 bytes src/App.tsx | 10 +- src/components/MaterialViewer.tsx | 235 +++++++ src/components/TaxonomyCascade.tsx | 143 ++++ src/components/TeacherLayout.tsx | 3 +- src/components/ui/dialog.tsx | 1 + src/hooks/queries/keys.ts | 3 + src/hooks/queries/useAcademic.ts | 5 +- src/hooks/queries/useCourseware.ts | 28 +- src/hooks/queries/useFees.ts | 6 +- src/hooks/queries/useGradebook.ts | 3 +- src/hooks/queries/useLms.ts | 34 +- src/hooks/queries/useStudentProgress.ts | 13 +- src/pages/AssignmentsPage.tsx | 48 +- src/pages/ClassroomsPage.tsx | 370 ++++++++++- src/pages/EntitiesPage.tsx | 285 ++++++-- src/pages/GenerationPage.tsx | 114 +++- src/pages/GrammarPage.tsx | 349 ++++++++-- src/pages/Login.tsx | 2 +- src/pages/PaymentRecordPage.tsx | 230 +++++-- src/pages/SettingsPage.tsx | 405 +++++++++++- src/pages/TicketsPage.tsx | 2 +- src/pages/UsersPage.tsx | 577 +++++++++------- src/pages/VocabularyPage.tsx | 377 +++++++++-- src/pages/admin/AcademicYearManager.tsx | 7 +- src/pages/admin/AdminActivities.tsx | 5 +- src/pages/admin/AdminCourses.tsx | 761 ++++++++++++++++++++-- src/pages/admin/AdminFacilities.tsx | 104 ++- src/pages/admin/AdminFees.tsx | 334 +++++++--- src/pages/admin/AdminGradebook.tsx | 51 +- src/pages/admin/AdminLessons.tsx | 28 +- src/pages/admin/AdminLibrary.tsx | 51 +- src/pages/admin/AdminStudentLeave.tsx | 1 + src/pages/admin/AdminStudentProgress.tsx | 182 +++++- src/pages/admin/AdmissionRegisterPage.tsx | 2 +- src/pages/admin/MarksheetManager.tsx | 6 +- src/pages/admin/ResourceManager.tsx | 660 +++++++++++++++---- src/pages/admin/TaxonomyManager.tsx | 353 +++++++--- src/pages/student/StudentAssignments.tsx | 48 +- src/pages/student/StudentChapterView.tsx | 48 +- src/pages/student/StudentCourseDetail.tsx | 173 ++--- src/pages/student/StudentCourses.tsx | 82 ++- src/pages/student/StudentDashboard.tsx | 64 +- src/pages/teacher/ChapterDetail.tsx | 220 +++++-- src/pages/teacher/CourseChapters.tsx | 160 ++++- src/pages/teacher/TeacherAssignments.tsx | 84 ++- src/pages/teacher/TeacherCourses.tsx | 124 +++- src/pages/teacher/TeacherLibrary.tsx | 515 +++++++++++++++ src/services/courseware.service.ts | 40 ++ src/services/fees.service.ts | 41 +- src/services/generation.service.ts | 50 +- src/services/gradebook.service.ts | 2 +- src/services/lms.service.ts | 99 ++- src/services/payments.service.ts | 63 ++ src/services/platformSettings.service.ts | 59 ++ src/services/resources.service.ts | 26 +- src/services/student-progress.service.ts | 13 +- src/services/taxonomy.service.ts | 18 +- src/services/training.service.ts | 116 +++- src/types/adaptive.ts | 24 + src/types/courseware.ts | 5 + src/types/fees.ts | 25 +- src/types/lesson.ts | 7 + src/types/lms.ts | 48 ++ src/types/student-progress.ts | 34 + src/types/taxonomy.ts | 4 + 71 files changed, 6677 insertions(+), 1309 deletions(-) create mode 100644 public/apple-touch-icon.png create mode 100644 public/favicon-16x16.png create mode 100644 public/favicon-32x32.png create mode 100644 public/logo-icon.png create mode 100644 src/components/MaterialViewer.tsx create mode 100644 src/components/TaxonomyCascade.tsx create mode 100644 src/pages/teacher/TeacherLibrary.tsx create mode 100644 src/services/payments.service.ts create mode 100644 src/services/platformSettings.service.ts diff --git a/index.html b/index.html index c54f102..ea5a338 100644 --- a/index.html +++ b/index.html @@ -6,8 +6,14 @@ EnCoach — IELTS & English Learning Platform + + + + + + diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..398952a92aa732f858af7bd64cc93704107c7291 GIT binary patch literal 4406 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 NP*>JQR6el|`5(fdcP;<` literal 0 HcmV?d00001 diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..9943934bf0bffe52af72e21a224daa02c96961e5 GIT binary patch literal 532 zcmV+v0_**WP)Dh-5S-b6+p!}YL}7sdAzF~AkSRk=LxBth5=azKQ6Wn7`jVQC4(LcjO+`iRCZeJM z3j{&L4oHrj|GPnVjL+YJVeeaHBlu|U|CDjmyO3yKT;A&s!HJd!#l44Tp+kB$mW@xM?!)E zJi)r4ZUNj(ja0jRzj@_MaqmZ2UX(Bbu%d~$c#`l9)4(7XQ}P3vovdN+RC;Uu_DU}) zpZ9iob!X2?4;T>C&eQ|2p=r>nx%d0?giD9gl#W&#XKl>3!GAI07y-Y~9HS6d3$a?I zMgo#4Ls~i-i2^`f!K%Nzy(BA2Lp1gP%7bGG-|+99(a*(vx|r}fbcC=47cAU=75EJ> z9k8Cvzn(ua2sH)NC=uicG>ZVCIU(Q#y!&b6!iS2beqB21UazGZII|-ZPM}hLjR2uI zfIRzTJ8uUzsu&oSIi;0kq7|KP^%1&HzD3gPZiD%YVLFz%Dm^}rSbh-wTB@+t$)+QC zK!_HkH;#{+*E*f;&8>4}o)4o3UcLpO=D;Fl_$V`jW-DL+x!0000CPRy=5(>sZXm=A`b=e?@$tLl37YJmSc zIBtXao-7-?uNLy$Sh=hT%QATOuioIyK#eL=eEQN&=~7$?faR0xI;X-ID_ymzrZ zQh*Io-dbJdOHa+8HPcrC%n~$%XYk+{+7h=3d@*-?^FuU0Q;^u3;w&TcT$i7mKL@jO zB&SK1fGL4E$)~a7w*{>l%-3}nb8|0XZeTWSd8K1a@j z8Hh}p&1T5+Jf2#9>*XHwV>jwXTB$NssOP?(06*V_*>txj^G6QZwHdLEks=02TCJ9z zJb88wv3wUm55Ojg!*rSSoS`-XSUTxOAxn)zacdm8!)w6O*gIz662NUUrjs5wKf)xm zR7~}h4X=kf0#HWG04A7__;2A-2DLF(fKcl9=bA9<2S4sL2>xZrLjm|l;0>?ux>gZB zcz6qcScLx(0m-OEe|b7di>hp>fJLtaZ?U^q%R%tTem;h0W>H6t%LIGTj9>l!pEuu2}qwm!VjKX=zSMK2`YZ8io%uvye6<8 z7q7QheGb_xfUt%b*Y2>muol|wf>CNr&v%3DzqyM)PknXk+m)-k*Vo@U^Euc_*lI=Z z5qkuXU`J`6{1pCJFQ|*D$w9*R(bvD0=gUVvZ8pQ@#YK6x-5y@c{L5JGV($^4Mvq>u zZKLQYY&J0#6W)_s3iT+nEVJV)D?!h zEOr#s`MWfl+9#1xqiojM-ETy~6ZgeADh-5S-b6+p!}YL}7sdAzF~AkSRk=LxBth5=azKQ6Wn7`jVQC4(Lcj zO+`iRCZeJM3j{&L4oHrj|GPnVjBnw_j+ z?^Jqg{q{;PDWCUtd39&cN)H$i)Xvlcu%T(tf2z6n`}2fLhtiaeRvTw+%(lUQG2$2j zzt9|`5LXMaTBSw;k|{%4IvR-rKwZJAzq`F8D@sE&_5jL*V+r5z@14=l#eBM$@H%va zumu+^+z#?V%C^Lg*D_{bu-}kP6 iePhFggpfxse*x4D%mIWIakl^f002ov22Mn-LSTX*d+aU% literal 20373 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 diff --git a/public/logo-icon.png b/public/logo-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..05c1870e785e956064c33281116f32b0fa1545f8 GIT binary patch literal 14880 zcmdtJXIPX=(=OTr2oe+&34(~C1d${e6o;h*kqm?6Bsq?fGviW}AR;1?1wnF>BsoaV zIcHEZ3^~m(Gy6f;+TZtn=bY4Qh4 z5dkvhB@3;eaz5$h8f9g#8g@Iw)AgK`&WZ;u9OmX>e1o1<-Yhq+)OW=%Ni5xyCxJBj zzxAgMlcEI&q+vl^Gdh4zFdG9SJ-0bFh0FH_HM$l-pCc+J-v%oCPzqB3KX2I1==%92?*B*4SIyXWSI3q`aAyEc4%zZR2y zt4bUS2gamg91R@uPo|d=w^GI6-w>_#Le*Q?oC5eKyYF#6UWw|FC#xPWn^UMU18-6y zX7FDWTdwLjze{@Do~DI@@}I|mK|M1YmlpQXC^oKl{zy^qejI1 zbabkQj%mu6hr{)_jFPntd&krTf~CaBL3b;lbz|B142Dg!{p7`)Ptt$Rja;&% zeWHqYyk6ohdUUefuBBkE8IH`1uKB zf@Iv=`)2bmQh7@z;iW>lm5%1+l~Z)|q(|Q~_0bDkC86Rfd>@Y<1_G3zl!0lnKv=oJ zd+$5UAu`QXt=8_EzW32bJ+iv^B}#33J;u9HzK&RZzn{BdRK!A+ZggGO&k;< zIe2(8=cQrkw^>)W???KTH_DT@-N}+w@c9D;zw`}aHy`!0F+^CXcPV)b`LwKGt*f9T z-BY_Ja4VkLv@R6$h%+Q;e8rrd@K*Mqb|?Egp=p@aW9?-FBZ-GI>!&VX`7m3?qo&OG zU6Fo^khlm_#Cq&Zu|s+UJ}0k_iMNl)I{;J+|q&iD?%Hb=U7_S+Y79S1*OR z;joMGF&Ul0^>WKEjOk}X{p!XHv1ZkC=#xCT8#SW$_ocR-4mRfZR@Bj@f$dcc=g#@C zk@|v%PcCmQ-HmhDQE}EfEZ_r3#uW8GGFWM4%>z2HDNo z_bOv@X$_5@oOfTh#z#ed6O%?tUh+zz8k`2u6y#Q>?>akW?27PWQpe3*__Ux1#U2Dd zbCr#D{H2c=*lc3DWk8Th#^doZ(St(*&4|A{AG8odF+1_0 zAEVb=Q38zhBYo$qSCqA@t@9^Ek7wtF;@iq%HiMl_iztn)z>!x>K)Kdbd|t2zt1NmU z0*S3vIoF<>PDMp5xC?h#i_7y`7%iW137=S@Fn(p`OLYRCT~ML&a8A>6ewwR#DFu#= zH}-77vg*1T<}+R+wcIlHkx%wZ_f(c0ITT|Dd)N876+GN==1&MgODE$+rvY6}tS2b%SodRd}CT+WQde$m9t_s@sKG+_8kZ{}mI^}P-F zPWATKFmwD^S>QdNOlmOu{OcUcXtI4nE9=Zj+W<1oFx{8vELeLsOPGMd!MkUO`li)H zsjbml#a|l3SXhz)2h&o-jiQbyN8Cb(|FT~CFjED6C z`*Shm#4)oc4A7}5d~#Rud+zygLqxk49rbBM^Q_694w=`|p%rzRx7@*y`*i6ZYxB|* zBc_sFt&n=&YJh6D-dwEn@N7A%Zt5-=*}&CIFz_MlQhV;8_R34*GA&)6$hb{c9xWD> z4|g=oZeBitC3y{JH!RYoKgoN`YFoRj_{QJ9xb&e3i_$kN9%eC0Mi{f<)V|k~;Mdb) ztgf$sbPWiNqb$`?$C9CHOso6-!&QdyInm?W%oC~|S)IbUiML^$Y}m2&V#+8?yw4%$ zXJe!VvcFz5`n4aP3J-d<5uNdJ3b%2kg78C3iOP%6Eu*Q@%@GpReWOF_mjrKP0>&<- z3B6{3=2Q}i-(9jJ1-Q15Aoh-_DF3}s_(^i_joGcal^Wk3^aL5R zm3dRPLO)j%H8S|JbT#&iU;uyFuBBi=$Dx5%-eJ+V_9UX`-ZPW$XXQ&%srMahp6cw2 zz7u8&Hz@iTkJorEpogCR$dkUr)2}zwLkc`xY&9;GSl^sM5SCXP8&%QOsc=o9-%XfN)(g`m)swjzuK1G~g3;^TwZ{hkPAru|TQyr{FxWr>^Hs|T{s`CAuXMyii zOG~+ib;5E2XX3)n)A6_~+Tj=S4$h$V+ZyK|nBU@F&%{$M8D(|Vc82+Q8P6bG$boNC zpLLmK(Fy_c%&epFV0(Kx7+Ojr5I#oMjIQ)=u(h%>^TFvoUHGKJP;tRE;} zyu4~iuyk646Mnr~xSbz5(XtqBu3maO{d69~uo$C@#C$H8gtn9k} z&T8N(vJI8f;VfKUe;BvcaZJsbeVm-RHzaof)QPFcUgURbuadGldC_FGyl#J;Q}sy= z0}80^uh)(VW1-wNF**wC3i%pXQ+1sN2rwc#Wo13w!;H$DTEfsD?w$`wMLljYA&sRl zw5BT9`I$eaE7L~Sg>8C&Dcg?^)HPYLeW9*v9-yz@Z4X2Hy_uZqY>-hK(Ifl#jzT)1 zewHxH5?XNZ>xlZ%T!R?Qm>MvuG2xfGM2Ge(yld?&R5zRCHtUlf3(O*Z)f@Iz!o8h% zY+Q}axI@@9j$>&cQlO2ga8@Yw=spM)%9e+%K>w=0rw0N-ORJ+2QO73@#x*3+fIkxvM!PNX8_fGp%7))KG$Fddr2vG zt<9zs`P;grCcT-xZz|&OCBdHg_RS|^${@ry!# zGXg3~Azn7#=I&fa33m?P1AMcge|{J94kZKmr+r4Mdvq&<5n>_Mr6c432q5AEG4C02RBDc@ zfJpkxV)vqIocPeVjln)8XsD!`9pqS?_=)LVbr()!E-BYtXnujdF^2^K(#L@ zofqpE=c0YmOZkc8>e$UZDtn@wBv|j?i}~V&JHW&vGwV`~zWt1FRMa&2Ckp8{zwMIz zgu$Wp^6GtmP}f^%WF~DGS~*t4DmmacKOVAh?i>l~L$$RwE?}|PaNik#EUS65=ja^8 zNg=|)><<|&2~u%uzMM6K!oCfcxqenrD7p4(x|&|NHc?!H&!rtvwy%1o<#RbP4yYv? zWw$iBu*wqvco8E(+h#9P`Q7jPvI7YZB`itiOEInME|QW}3&#Uc_}K&u#!1q1Ea=HH zsm}QM=S0#H^?^u#{3lk=zio5~{K!x;&^secbwQ?JXE(75ESj3PiNHLp+7PL2>LjhF2 zdD^ti{re*ozuGwMQbRj~h_j{0dE-x3x9%D>)|Rq=Dwcco4fL|VP(a~SY(Wj7+Z zL<7Bz_6O35*C0^>ug*gMQe8jYnLZ3uwh5a$4vDL8?s_fCv}Ek?x|YsHG|nha`5gfU zFch#^W~Oy37cWdkclXr;J8i6ycu8NeCF2plb#Np1hvOBlAWO=0y+DO84<25dE!biU zr@cji-SLhtY@2qHOe1%2*~S{l;lG#BzP=8>Tt+?P)X_LWxSx21g=KU2<^;M6 zDcljlb+wO;e?3#v%~k4qTN9fN?iYGEjHA1`^9l@jP{}12J9@`l2{CW$L})dz#Cct( zp&|V?9sLN6C@m8nhi}`xQF*<+bnc`opTQWm3qmR}C-dOK#?RLN3W|5nT<*jP>!W$yS{dorfdmwu*zARSNrBKQ+o!2koY*dk}6?0b>@}?1h*3 zz7%;^N5@3bIMZ1MWMXWdZ;L}jWpndt-`At`>64kto@g3un($*c*{q%l_co0S4xF|z zv9f87LshlfUq?3b57THf%ifc)(T2pYzx}9!sxuQwtUw0Ge@(CKi{LXzOIxkf465Z9 z%VqDD{MpSPn?Y$>r_{juS3QIx5@1udmUs8ENL<%?{cV1aAH3S{qNO&@!PjcauhOaR z#yA)j9!=0o`bns_b=HTSOg|dZWnABQfaP%J5Zq}!_VvJ>+*RRHub8$^J@HpCNs_U( zIV$=k{Avp-sAZ;Bg#8MGAM?m|jQsjh)r)y#-|n(xQWSosmj%VB&Xe~m@s-?(>s>dP`C*Dl)-X6+0sj;v3Ypf zopJpIo^F_ESX6c8Sm1q3T(qi%*-=oZInOO~SGMillyIagCCj-rvN^tkti&r^6KZEr zFGpCE&QCdW#U&&tCmvRfpjFI&(be3ZS!pyfPiDDrnIV$Q`(f2%T*t%efWz~0ekLrh zUpzDDt?$zpvhyy@yy3`Q>f@rDT6yOn{i4-|k*xIK1rh`QE(+G_c6K5SRO(AYXP8NR~GDxpCs;|mcxS1E7wQzVhUG|A}wR;&2 zqX{uHU<$<*wC>{_;O?4k106`up=~YCp|MZ?v9#rrjVi(Ig#j-J;n6F^4GbiW9kz36 z^}{dNLZ52wPpmaDG?4#2jbZ%@5Zlu9d|j(qk;@&cx*K&ve$u^mYcYoG$p*aC*;6b1 zy+XRvywBF<(JkWHHNC67I_x2X>Dd7j{q3$3neQqEgM2vMJ_Vdr+jk}kd-E4FiFX1m zTr7K~$FHYr1{bcmGr$+2sBA9m<}@ioON(tO@&gYy>+ipyA*pZKcu*Q|-=ck&bL?F# z;laq-qsAIQ75#!73=9nPO-{zYdxwAYakLAL%PiW#Wff{7dL#H-X&(*skQ-1D7n1ZoD=I2#nsT2>uu~Uy&M$RyNziHLzvo#9nRnwM%YweU3mB|GGC_ub9XnM>O# z+j@c~^Nam}lV?7%p;U0Y)cPasKFT{`O6*QCPmfn(++bJ{WG9 zMnyhw?@ZsGrXlj0AbR0yZO8``W;%CR3%@6J!-(2z2K#dX4>NaO)0=-|>w*7Ts*X|`8d}JZwaiHtV8(^7Q8(dmj+qk3y zpD8fiDqUHTbGR3S4YS>8c)DscMVZ9Sfq8aT=h0NE-F2V?A8xpa3RbGLy1)BjyuE)V zQDbPjGjXaEVAx2+*Z3A3-A8?^ByQEa&a3N0e>J7SOi5+{rOHQEA-v3z@Gk*XMx8#J z)AzwLvE^!f5!wlTz+>Kbl~Y4pJ`C)^M>aQn%@TP1_Q|HVs&p1as@07n;W_}*(Qy6R zxU;CUxA+ zD{m@wcUM~NQo&tKFRW4#cwG8)VfMQb)=}#bR`{&1%ke4Nnn&`d>_7(v1PrN#=rTiQ0j@H`4-u?tC`Wf z-czm|AqN;Wa)42qAwj()+kAwssf?*TNG+`zjl%^>UKV+51%}-#XS;3Z++GQo6!ZU; z_#9WbM(F)QePp#>Yq3a)$`>iCxp4zSjE3jKSr7Y7?3quTodO(9g@&&$xka%8qNMcJ->3deIoq;(h1c z)Q%YMysXe5+w|2XB2>utOV>VprxaVTJ+3w#*W4F^MQVfkb;8zqj+kBJMjjTw(3$6) zMTw(P0<-gIviJ6Up?Sh7aknrpv%L=T+1zF;RnbPvqt0wY6#-g8fKfW(foSZ0o*3C{ zG4M*}UZp73UGw=#^@h^tOxsR8j4J0DT>5J>3ycvB1O}{MU9u-L+L@iEb?|#mDNx!l=beBJ1Jh=9ck3rskiHsOfLkwRvO`?5>e6^VXq)u*HMz*WVjw_|YB z7j?!>cgA`^BTAU^J)H6!J#k+k^?f|YtCd@G{Q~%CntS2B9JO1rU4sTlCsK>-Co_ti zUWAu#H!nyT8+=%jQPJ+?A`mm)e_X1G$k=<~?uD_=KR5i<&X_lipMt?sVH3JVpbAqX zZLM~ixb>O?yec9Dl&&n3M_>?}xw6Nsb-m;x#K9cYu2Vx__(2EAc+keI{-8v0;d0MZ zg}0rd(JVsWl72gv+JsSJLHt^l=IVN7U-U{OA%AT4Gh^m`RjntlC;;lZ+*xU@$1FZ^ zU1^8@-U2Z>6GfCovMC$`5Dw$WTUK2pF-B<{sX0Exx@5%PGpb_Y|Qh zrwB|;p7+!Fn?gThO+IGt?O<1i#8ueFm?fVEKjY;<&7sL@B-$vDJORlr?0y5fI%^*o z4EeNU%9nxz4r+4<#L^i6fumx)&wjqnmhkgj=}?p)_Pmh)6NCho+9V@0aKXrS$*EMC z#huthfLJl{L`0J15A!!f~hC2r&*xtz)7rB?9cXU1_c=d{EG;exjtIa$3FLgv}zd zE4iO0Pyy6hl0y)@=|7PzjpYmA$m>}V^8`E7mmcl+9Z zP8rsLsRF${Rk|Moa~u^;qN>VuhRPVvrgAx4yYHTdu82{7jRO|GDnN&t4u!B^x4&w* zIygXeHuaV(2RhzqQv~=}oRLly(b_%Kgh|J6H4#fU(V-??d}^2t=_Ptf>bTCq0N~C8 zjkdX&UT!@6#d2qW#dQFrjS=8O$9$kB;G%{`V3LW{uH3Ft%m7I|5a=?hs8Mfw(jEEJ zff@&72ZRAEBQwu2ldeVL3`+0<07(zH=Y^0dls3gJnd&fU8)(m?#;z5b;3C?Hzm9}t zq@K!%?936!&Hq&~6wuKR&3yB8<_}qNY%3o2ltx3)d%CCZxt@{cb!4dc5#z}XxD*Y> zt%$&hW){<9LeTDp(HRIHNmme%#K-i3yJ-an_tS__PBhSGet~WIavdUo;LQTbzo_teSJZ#WnGj4wL^l z@^RK`WB>MO;)1C3?@6@;h4??XP)yBs-h*^y=i3m1ff}zf((L&XwX5E&kU1nWPF>4G z6BRdHe0T>M^b*p=w=VN2D-qTZz<%n0*OzN!f<4vgJ^?j)ZUB186hX|0B;+63-~NFh zaQx_(_9#i9pgIho?u(O_#jbI@gC#4Sn(KryDfMSiV)_M|b{WVD+%dXn3v>36?*kN! z7Hp8{rYIP@$^`R8|Nc0q%QTN4LSwS>iA9+WJFkquQV^$8ycY|38adRZ@O&~3vTpyW zb>}Ih9VPulLl5P;tq_n}r>Hi9ef$6O0R@CoEy$F;V&34b)E^r{j=0H|9cQKjosL7& zmS5fnOFM!00T&%)U`#Tt$@Bg=$OFHFV&4!n8v-uYKc-jXVF@WeN3(FcjL6Q;kek`% zj!u@JA%99 z3cJv4rM27T6LPmr{-Dd4^isA9hnaWle>d}iXhpO{94)O;92J6pPG9*K z|Jpz!V*7Y-BbDe6Q9yRj8IH|jXrag_|1a=64QwAfI_X}~ef(c^RA}b;MdTl>W0HuT z{q~jMKM%6*pGo>1R`Zvjs6KVMD$IlVZd`@pzl=1mf`S6HITk*r{BPiWh*{vc0fq4o z$OE*e9{8FSuIGNQP-v1g@HdO?On}tyddnPEi>c!dLX$EJz_e2WB>~s($n0Z*O?Q6*7uuve#gfB8D+kZ8;YlfI0bbGh4lYO7s(xL zR{!#sRw9v_jq=b5E}rNQ)9l{@NHeRVWeq4Oen&Axdg2a9rIVMC+}|uaNiHCES-0CY zUGp>~8y9@JL7jH(xn4=y0{DjVQ!Pjtjo-$Oi4n^!*|DZ9h4|n%@n@Mf_QMbJQd)m()-m>fhXaN5DsMbd*+(eD|HeL=c(%Cu&Nel~ z;Q!`^NptgC&Xw^@r?Fdk3cU%CD-?6d`7}425;OPz(-o^Sh2gFI&{;zLRfzac`KYav zqDXvSa`C|(6a{#E%1BvXnLgosb3Toaw?NubK>q3_s|tt&N%wpjU{L1hJksK=VvQp| z&DV;MGgH+Lv`xuDYRah}S&7Y|JS`6yy+)kW+O7rIoO$~@E>!-S9 z+UE3sPJ$c+RU3f2hKg%fwBn;|WjsX`?91=8i;*-LI!G&W6}b@s$bx0eYxR`VXtyin@u0@wu)-)biUg z6+}tDp$dKemn!1k^|+^Wuq_GwJM;f%#oDUz&yfFFvOE8qo8W2b7HxC zaKp_OGSF|IDQKB-CbW$v&hvqPs-L3z;+hX@PaKJ5en-i^1Bz`$$9$T=8vAmPnmRt<#E<#Sw+PNQ37CP^CFx%|IbB^DJ z91Az7{;SaLQ+4#z**NefI?KJABf_Cl zkvZyA-2NTufhzO~MGJWIalak6-S%YfIN^r(T?=15DAW+XRBB&OvmZBTXsf^YzAYnu z?Mfdp8O53d%;V%a6x&&OAj6g8>D`~QY~0|X+>r2L-|Fyok$!&gl6QWZky6WJ%t(AX;OS2RMu$Yt=W~hyib%wB!EzAtZW@x zq(70jWIc*>wqSu#{Vpfc^}bq~S!udwYO05aV z&YhbXTRQ_4b^`V+fRZ)ek>&0XezB`#E;S}5roRS%D)4v7{l6jA@US71I{n6TF@i^7 zVLv6%n2$<4WrY7I!UgVC1xkd6YliIfDLPJ6s4ZgrrB7KX1Kf;i3Qt9V*Fj#JH^+Ea zT4Z9U9~%&;A(eX>=ul81HH3U^eaY5OkXd=UsKR?-d-}FemqzWuKbrgt%hzvWJVK|I z+vv)zdcsscpUaQLMRG#y5byvZ?}`d`zIV+01{uzIu!Mvj6L=3J)8ulsvODDic4f51}R$ zXN@-GA4;*-l&K>g8CBW!D0d0DJ@wB~?#lLn>g^g!H@~D!-2Mqhy-OFFcTwJySF?EQ z=|0zqXD-I(#s2jiLRPEw+`eEa?y^XzV&!>97PasPh^pX#><^k3T%UeOFqU`k*5}Bw zIXa`#xIa9Ab@7~#aiSYT)4G=xIjjo3Nl(9FbCoX(<3$U$N~n&ix2w>d`_q}pH081y z{5#V61F=G-?`;Y+0%zhMxgaM3M$W?OM(RS?gI4QHn0M~xtNE%Wml!_Pf@{}45@G77 zemj!DlXt0)y*nr2W})lXG|lO1$ytuggf$SeDmSB7hIyN?2CrslvT|1%vNpz8wrePGX;kbSSS2@kTXs7wQH2 zxXD(ggs-%{yF?j)F%$`cf6qziYdyW06J`p=i{yWI@t4G--{3J~(}w%B`>D849kku;D zb5ZQll|H$dktS)v78AWrlkWd3FBbEP<@38=(n7By+iAeoGX*%+Nl>s#<3)B`ug$Eq z7>2v!{lbS&6OrY@JSu)q75d+w^%_Dwd#!-5eadt`)D&WbU$SJJ7y#=kk&tr~;XHvAOZYNglDeALn%g)bf9^%574 z=if7q-WVAaKIhB?!n&crJ4}bFs$jdgq7^*uod3X=ha@O|N)e|aOCh8%Q=Ypay7O(j zh`g4i?7Q`e^axJXRo6KNd?WviJO0q;-brn_F*dwXFQqLqj$xq7ipQ_N`NHvHMx3u5 zPsOileVJ09!rBwLy2U{j%y!5a3UP08HssfzMoBI|m?rtcB!9^FH!8*o&}`rMflsP!cd zYNRd6$51{Lt4@*EI@r*Z@YL9s_y4)ecG0hueE=?s*+zEpA9C(w_Y6j)BbmaCG~gre zoFhMFxM_*_-8-O&ejVyB$(}~Y-u=qEIk{c9SiTjn6^|u6h8jLKUmd>=bbQRC*Ij&6 zr0KXotC$xTHx~4co;Tmm%-*qcUvzNqHRkEY#79plR83k}n*XnvH!ltX11tSDmd5q1 z7BT{_RO1dxeN4P=Vw3n5X1*$uZ}xbCxAE}3?aXEu z<+v^c2Ea@LN%317;xRgd-9vnJ5#tQ{##%Zhl@hsES~cvi*gXUq$Mc$_IZTy0IdI^s@HG#U8@vX^kbZcBMg2 zV{@~%X7pk>+;CD2evy=57h4pwM^03SqBQeh?B%=>BB)8ogVy|0G0#~r^64#Y_=T9b zz!A4~(icr%ah_jr z8Dhg>vSDBLkWY3C^tWl-D)S__z7M#y{P^mrS%kDCK%%4rVtk^fpl<5}?+BqxF^Q;5 z)=*v^VlHAh$~3)NrE@8YtmX;{9*=XcT1fv~aZ}7zud2<$Peb;Ta&7ar;48|_8_szN zDuaHNB~}y0I%fVkVl1oKKa4RYhHN#@s{{NtM7H~=w)G6 zKDw=-+V90&>zAPWgfwG=$?sphtqekp3!U0t-`x%OFk8Mo$~?&$;KeUHZ+p9v6JEHX zJK?wK9;U$ERe4)#lhAV=x>AhQXP)(671~~b!*g>3TpWg3N&T9A!O{5NsA(6jIQtrB zG_AHFKCyp$nZbv*yJV}x{}#!s#9Q;$U#ra;F4SWC6T@%JTUo}M(*9*!gDWHvxVCo^ zRvRC6P`Q{qT&T^OZL{1)2R6 z-l;HMs70B6eByGiw||MMQN_>YX~i1cZ2#xB+TvJBePUKm_JWwzj9>T{)SEtA-|fzK z?&Z0lM`8$Pp!x1d)sFESbPgQl#KE=8*fa(Lb;tmNmXOPJ1MF64`n1;?^)SO-vCLBS z6~mpM@)XYL({V%oC*J2zM%XT$H)pv9avm;4Se#Au>Pgm@@@dcgB`dx&!m4dVRF_mJ zFrtl15JFZqB^OPxI?bn3I8#?=GuO@yAqlzu%NwlAyO0u{bR#RXtbCitan6qWVXEbk z$uy?J)F5@A=6x<4XY6+YNcKL50PyvFzHp z-h*yIXA7=_z4G3n9>fNc{wqs6o<*}~mKrK=pvFUP93u7ektLr1|z}lez){a3>5nv zM1tx={ai3GU_gZcm}djV;^Rw=Yu-x+Ynr#mrzGkjnPp`eU@u0Xbt&!Oi>HmhlWyh2 z8hr^RDb(fFBzq>Q$L%CcZt?2!qk|UCsrHLd+{`|I0G4me*x5)3D=#a#RmkN675cN=av;OwpjIz~&?;f` zCjXTcbYTK*R+HFFzlJpyYX$m`tdxmdxNL=oon8b@8|00f3Gx5qqpsLM37Gkt)0wO;0Cfh9%Y45P10@#SyQ78cZwv z7!iEp@BXwsIV1y!zhN0fLBTxc@fc!&cmve_IwqLQ z?+`X~?C!Qi`U8|L4R}oNcEV~n>~hbNzzUKip$@y4tc2yqXo(|g0M!{u=B^^Rt*3+P z_zq&g-6()aR@)^!P#owB+<~;$gU($uTesi+nrk+Ck;?v&*$9ob`N5cmF{XaX`pa=hFk0UiT z>5TU^P0CIWF*R&0>0O;K=VBBD3{JOpmnjJhBR33B@~RJlw%QLiz{E+038H+ zi5P{qWaD!h_WK#S-L`dzJ=nMbOuiA-r70UC*>1C?{ki|@9BjLlh`?Q83i^eoL9s#SVPvo={c-)L&F!US%W#`-0wh5wEY%3Z+MPYE1?GKE=>8y@L+->b*_TN-Fj&&pn5zU(W57 zk)f8*$hSUQud4ckQq$rgv`qVPP4aQ}RVR>+Bp% zpFjpQFgi;w+*=|GzIQM%V(6}U#V7-lDPVB*5cJ}^b7$DtZgW7l^s`m12)*QkAKxy| z2H&QS#-+G~ttH))l47A#F}f^i_{tdteTk1D`PJdHOjk`tf3Gk0;10G0TKCx4SiOX2 z7KJhjn1lxC)iOlf*u>P`ovHM%6@N!CO(H_YtWX+z>TJZDF z)Ng}O-28(qUlXnKv10tTZ}H&SXR)!J_Km69d&azHNN)hBLujO`GG^weYNYn&MfcQO zGqd1Znmb*rVX3nJ$*M6XzvJ-=>&rqC8aLb<xCso_q)I|JeRAw9m_z=0gt`OLYl zx@wo;C-@P#n{`b&;EMROy3AnZ+Vs&x@3A5MH6rjz>><)JqG$YisnPTaG9fFGtjrpA ztrKr$WmS#q=Dn+lERAi;fWE^42aImhO14>UOCg*)@C=M8DufA~zamakaWbZeue`!t zWstq9IgTfiR<+)}iyk ( {/* Teacher routes */} - }> + }> }> } /> } /> + } /> } /> } /> } /> @@ -233,9 +235,9 @@ const App = () => ( } /> } /> } /> - } /> - } /> - } /> + } /> + } /> + } /> } /> } /> } /> diff --git a/src/components/MaterialViewer.tsx b/src/components/MaterialViewer.tsx new file mode 100644 index 0000000..b8b7ee6 --- /dev/null +++ b/src/components/MaterialViewer.tsx @@ -0,0 +1,235 @@ +import { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { ExternalLink, Download, FileText, Video, Music, Image, Link2 } from "lucide-react"; +import { API_BASE_URL } from "@/lib/api-client"; +import type { ChapterMaterial, MaterialType } from "@/types/courseware"; + +interface MaterialViewerProps { + material: ChapterMaterial | null; + open: boolean; + onOpenChange: (open: boolean) => void; + onDownload?: (materialId: number, name: string) => void; +} + +const typeLabels: Record = { + pdf: "PDF Document", + document: "Document", + video: "Video", + audio: "Audio", + image: "Image", + link: "External Link", + article: "Article", +}; + +const typeIcons: Record = { + pdf: , + document: , + video: