Initial commit: standalone quiz-testing system

Full-stack F# (Domain/Server/Client via Fable+Elmish+Feliz), PostgreSQL
persistence via Dapper, Docker Compose deployment. Student quiz-taking flow
with time-limit enforcement and focus-loss tracking, Teacher question bank
and quiz builder with results analytics, Admin user management.
This commit is contained in:
danamir
2026-08-06 12:36:16 +03:00
commit 942dfc9c1a
134 changed files with 10712 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
module Client.Features.Teacher.Home.State
open Elmish
open Domain
open Client.Features
open Client.Features.Teacher.Home.Types
/// `role` decides whether the Admin-only "Пользователи" tab is shown/loaded
/// Teacher and Admin otherwise share this exact same page (see DESIGN.md §2:
/// Admin = Teacher + user management).
let init (role: Role) : Model * Cmd<Msg> =
let questionsModel, questionsCmd = Teacher.Questions.State.init ()
let testsModel, testsCmd = Teacher.Tests.State.init ()
let usersCmd =
match role with
| Admin -> Cmd.map UsersMsg (Cmd.ofMsg Admin.Users.Types.LoadUsers)
| Teacher
| Student -> Cmd.none
{ Tab = QuestionsTab
Role = role
Questions = questionsModel
Tests = testsModel
Users = Admin.Users.Types.empty },
Cmd.batch [ Cmd.map QuestionsMsg questionsCmd; Cmd.map TestsMsg testsCmd; usersCmd ]
let update (token: string option) (msg: Msg) (model: Model) : Model * Cmd<Msg> =
match msg with
| SwitchTab tab -> { model with Tab = tab }, Cmd.none
| QuestionsMsg(Teacher.Questions.Types.TopicCreated topic as subMsg) ->
let m, cmd = Teacher.Questions.State.update token subMsg model.Questions
{ model with
Questions = m
// Questions and Tests keep independent `Topics` lists (own VSA
// slices, own `LoadTopics` on init) a topic created in one
// must be mirrored into the other, or the quiz question-picker
// never sees topics added after the page first loaded.
Tests = { model.Tests with Topics = model.Tests.Topics @ [ topic ] } },
Cmd.map QuestionsMsg cmd
| QuestionsMsg subMsg ->
let m, cmd = Teacher.Questions.State.update token subMsg model.Questions
{ model with Questions = m }, Cmd.map QuestionsMsg cmd
| TestsMsg subMsg ->
let m, cmd = Teacher.Tests.State.update token subMsg model.Tests
{ model with Tests = m }, Cmd.map TestsMsg cmd
| UsersMsg subMsg ->
let m, cmd = Admin.Users.State.update token subMsg model.Users
{ model with Users = m }, Cmd.map UsersMsg cmd