todo-webclient/client/index.ls

330 lines
8.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

maquette = require "maquette"
nmd = require "nano-markdown"
LoginForm = require "../lib/authd/client/login-form.ls"
todows = require "./todowebsocket.ls"
AuthWS = require "./authws.ls"
bulma = require "./bulma.ls"
Task = require "./task.ls"
Project = require "./project.ls"
Modal = require "./modal.ls"
Navbar = require "./navbar.ls"
# ValidationModal = require "./validation-modal.ls"
{create-projector, h} = maquette
projector = create-projector!
model = {
# view: login, project-list, project, network-error (TODO: other views, such as rights)
current-view: "login"
viewed-project: void
# 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 = AuthWS 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"
model.last-network-error := event
projector.schedule-render!
authd-on-websocket-close = (event) ->
if model.current-view == "network-error"
return
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
# HANDLED with the "on-login" callback in the LoginForm component
# 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"
model.last-network-error := event
projector.schedule-render!
on-websocket-close = (event) ->
if model.current-view == "network-error"
return
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 "Projects 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 && 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 model.viewed-project && 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-project-list = ->
h \div.cards-list model.project-list.map (project) ->
h \div.card.is-grey {
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
} [
h \div.card-content [
bulma.title 3 project.title
]
]
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
]
model.login-form = LoginForm {
authws-url: model.authd-url
on-login: (user, token) ->
# FIXME: May double-login if the user clicks the “login” button too much.
if model.current-view != "login"
return
model.current-view := "project-list"
model.authd-ws.token := token
model.todod-ws.token := token
model.todod-ws.list-lists!
model.authd-ws.list-users!
projector.schedule-render!
}
navbar = Navbar!
render-body = ->
h \div#body [
navbar.render model
h \div#main-section [
switch model.current-view
when "login"
h \div.columns [
h \div.column
h \div.column [
model.login-form.render!
]
h \div.column
]
when "project-list"
render-project-list!
when "project"
render-project model.viewed-project
when "network-error"
h \div.container [
h \div.notification.is-danger [
h \div.title.is-2 [ "Socket error!" ]
h \div.content [
h \p [ "Were very sorry, but something got very wrong between here and the backend." ]
h \p [ "Please check your network connection and refresh the page." ]
h \p.small [ "The error happened on " + model.last-network-error.explicit-original-target.url ]
]
]
]
else
h \div.notification.is-error [
"Wait, what? Internal error!"
]
]
if model.modal
model.modal.render!
]
document.add-event-listener 'DOMContentLoaded' ->
projector.append document.body, render-body