# first: # connection to authd # display the authd widget # # second: # connection to todod # rewrite the whole body component # page 1: (TODO) list of lists (or todos) # display: # navbar # # "element 1" button # "element 2" button # ... # "element x" button # # "new list" button # widgets: # navbar: [return to list button] [logout] # element button: # [project list name] # or # [project list name] [RIGTHS] [DELETE] # # page 2: # display: # (TODO) list of tasks (this client has a kanban display of tasks, with columns) # (TODO) task widget # widgets: # task widget: # TODO # # page 3: (TODO) pages about maquette = require "maquette" nmd = require "nano-markdown" authd = require "./authd.ls" todows = require "./todowebsocket.ls" bulma = require "./bulma.ls" Task = require "./task.ls" Project = require "./project.ls" Modal = require "./modal.ls" # ValidationModal = require "./validation-modal.ls" UUID = require "uuid/v4" {create-projector, h} = maquette projector = create-projector! model = { # view: login, project-list, project, network-error (TODO: other views, such as rights) # XXX FIXME TODO: TESTING THINGS current-view: "login" viewed-project: void # current-view: "testing-modals" # list of Project objects project-list: [] port: 9999 authd-url: undefined todod-url: undefined authd-ws: undefined todod-ws: undefined previous-error: undefined error: undefined # { uid => user data } users: {} } model.authd-url = (if location.protocol == 'https' then 'wss' else 'ws') + '://' + location.hostname + \: + model.port + "/auth.JSON" model.todod-url = (if location.protocol == 'https' then 'wss' else 'ws') + '://' + location.hostname + \: + model.port + "/todo.JSON" console.log "authd url: " + model.authd-url console.log "todod url: " + model.todod-url # # network configuration # model.authd-ws = authd.create-socket model.authd-url model.todod-ws = todows.create-socket model.todod-url # # authd messages management # # authd socket errors authd-on-websocket-error = (event) -> console.log "WebSocket error.", event model.current-view := "network-error" projector.schedule-render! authd-on-websocket-close = (event) -> model.current-view := "login" console.log "WebSocket has been closed.", event # model.todod-ws.reopen! projector.schedule-render! # record changes that need to happen on a network event model.authd-ws.user-on-socket-error ++= [ authd-on-websocket-error ] model.authd-ws.user-on-socket-close ++= [ authd-on-websocket-close ] # authd message handlers model.authd-ws.add-event-listener \token, (message) -> model.current-view := "project-list" model.authd-ws.token := message.token model.todod-ws.token := message.token model.todod-ws.list-lists! model.authd-ws.list-users! projector.schedule-render! model.authd-ws.add-event-listener \error, (message) -> console.log "authd error", message projector.schedule-render! model.authd-ws.add-event-listener \user, (message) -> model.users[message.user.uid] := message.user projector.schedule-render! model.authd-ws.add-event-listener \users-list, (message) -> console.log "Received users: ", message message.users.map (user) -> model.users[user.uid] := user projector.schedule-render! # TODO: user-added, user-edited # # todod messages management # # todod socket errors on-websocket-error = (event) -> console.log "WebSocket error.", event model.current-view := "network-error" projector.schedule-render! on-websocket-close = (event) -> model.current-view := "login" console.log "WebSocket has been closed.", event # model.todod-ws.reopen! projector.schedule-render! # record changes that need to happen on a network event model.todod-ws.user-on-socket-error ++= [ on-websocket-error ] model.todod-ws.user-on-socket-close ++= [ on-websocket-close ] model.todod-ws.add-event-listener \lists-list, (message) -> console.log "Project list received", message model.project-list := message.lists.map (x) -> old-project = model.project-list.find((.id == x.id)) new-project = Project x, model.todod-ws, model.users if old-project && new-project.id == old-project.id new-project.tasks = old-project.tasks new-project projector.schedule-render! model.todod-ws.add-event-listener \new-list, (message) -> console.log "New project", message model.project-list := model.project-list ++ [ (Project message.list, model.todod-ws, model.users) ] projector.schedule-render! model.todod-ws.add-event-listener \list-updated, (message) -> console.log "Project updated", message new-project = Project message.list, model.todod-ws, model.users model.project-list := model.project-list.map (project) -> if project.id == message.list.id new-project else project if model.viewed-project && model.viewed-project.id == message.list.id # create tasks in order to have the updated project properties new-project.tasks = model.viewed-project.tasks.map (task) -> Task task, new-project, model.todod-ws model.viewed-project = new-project projector.schedule-render! model.todod-ws.add-event-listener \list-removed, (message) -> console.log "A list has been removed", message if model.current-view == "project" && model.viewed-project.id == message.list model.current-view := "project-list" model.viewed-project := void projector.schedule-render! model.project-list := model.project-list.filter((.id != message.list)) # tasks model.todod-ws.add-event-listener \tasks, (message) -> console.log "Tasks received", message project = model.project-list.find((.id == message.list)) project.tasks := message.tasks.map (e) -> Task e, project, model.todod-ws if model.viewed-project.id == project.id model.viewed-project := project projector.schedule-render! model.todod-ws.add-event-listener \task-created, (message) -> console.log "A task has been created", message task = message.task list = model.project-list.find((.id == task.list)) if list.id == model.viewed-project.id model.viewed-project := list if list list.tasks ++= [ Task task, list, model.todod-ws ] projector.schedule-render! model.todod-ws.add-event-listener \task-updated, (message) -> console.log "A task has been updated", message task = message.task list = model.project-list.find((.id == task.list)) if list list.tasks = list.tasks.map (e) -> if e.id == task.id Task task, list, model.todod-ws else e projector.schedule-render! model.todod-ws.add-event-listener \task-removed, (message) -> console.log "A task has been removed", message task = message.task for project in model.project-list if project.tasks.find((.id == task)) project.tasks := project.tasks.filter((.id != task)) projector.schedule-render! render-navbar = -> h \div.navbar [ h \div.navbar-start [ h \a.navbar-item.is-size-2 { onclick: -> model.todod-ws.unsubscribe model.viewed-project.id model.todod-ws.list-lists! model.viewed-project := void model.current-view := "project-list" } [ "⌂" ] ] if model.viewed-project model.viewed-project.inner-nav-render! h \div.navbar-end [ if model.viewed-project model.viewed-project.right-nav-render! h \a.navbar-item { onclick: -> model.current-view := "login" # TODO: remove anything related to the old session on the client model.todod-ws.reopen! } [ "Logout" ] ] ] render-project-list = -> h \div.section model.project-list.map (project) -> h \div.box { key: project.id onclick: -> model.current-view := "project" model.viewed-project := project model.todod-ws.subscribe project.id model.todod-ws.get-list project.id model.todod-ws.get-tasks project.id } [ bulma.title 4 project.title ] Column = (title) -> { title: title id: UUID! # TODO FIXME XXX } render-new-project-button = -> h \div.button.is-primary.is-large.is-fullwidth { onclick: -> model.todod-ws.add-list "New project", { extra_properties: { columns: [ Column "Unassigned" Column "Work in progress" Column "To be checked" Column "Being checked" Column "Done" ] } } } [ "New project!" ] render-project = (project) -> if project project.render! else h \div.notification.is-error [ bulma.title 3 "Error, we did not get the project id " + project.id ] render-body = -> h \div.section [ switch model.current-view when "login" authd.login-page model when "project-list" h \div#project-list [ render-navbar! render-project-list! render-new-project-button! ] when "project" h \div [ render-navbar! render-project model.viewed-project ] else h \div.notification.is-error [ "Wait, what? Internal error!" ] if model.modal model.modal.render! ] renderer = -> render-navbar! render-body! document.add-event-listener 'DOMContentLoaded' -> projector.append document.body, renderer