-
Notifications
You must be signed in to change notification settings - Fork 17
/
Login.purs
102 lines (83 loc) · 2.78 KB
/
Login.purs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
module Test.Login where
import Prelude hiding (div)
import Concur.Core (Widget)
-- import Concur.Core.Patterns (loopState)
import Concur.React (HTML)
import Concur.React.DOM as D
import Concur.React.Props as P
import Concur.React.Widgets (textInputWithButton)
import Control.Monad.State (StateT, evalStateT, get)
import Data.Either (Either(..))
import Data.Map (Map, fromFoldable)
import Data.Map as M
import Data.Maybe (Maybe(..), maybe)
import Data.Tuple (Tuple(..))
type UserLogin = String
type User =
{ name :: String
, login :: UserLogin
}
userMap :: Map UserLogin User
userMap = fromFoldable
[ mkUser "admin" "Admin"
, mkUser "demo" "demo"
]
where
mkUser ulogin name = Tuple ulogin {name : name, login: ulogin}
------------------------------------------------------------
login :: Widget HTML User
login = loopState {msg: "", uname: ""} \s -> do
uname <- D.div'
[ D.div' [D.text "Try logging in as 'demo' or 'admin'"]
, D.div [P.style { color: "red"}] [D.text s.msg]
, D.div' [ textInputWithButton s.uname "Login" [P.placeholder "Enter Username"] [] ]
]
-- The following could be an effectful ajax call, instead of a pure lookup
pure $ case M.lookup uname userMap of
Nothing -> Left (s {msg = "Login Failed for user '" <> uname <> "'"})
Just u -> Right u
logout :: User -> Widget HTML Unit
logout u = D.div'
[ D.text ("Logged in as " <> u.login <> " ")
, unit <$ D.button [P.onClick] [D.text "Logout"]
]
-- PAGES ---------------------------------------------------
centerPage :: forall a. String -> Widget HTML a -> Widget HTML a
centerPage title contents = D.div'
[ D.h1' [D.text title]
, D.div'[ contents ]
]
loggedInPage :: forall a. String -> User -> Widget HTML a -> Widget HTML (Maybe a)
loggedInPage title user contents = D.div'
[ D.h1' [D.text title]
, D.div'[ Nothing <$ logout user ]
, D.div'[ Just <$> contents ]
]
------------------------------------------------------------
type St = User
type Task v a = StateT St (Widget v) a
currentUser :: forall v. Task v User
currentUser = get
runTask :: forall a. Task HTML a -> Widget HTML a
runTask task = do
u <- centerPage "Login" login
ma <- loggedInPage "Task" u (evalStateT task u)
maybe (runTask task) pure ma
------------------------------------------------------------
loginWidget :: forall a. Widget HTML a
loginWidget = runTask do
u <- currentUser
D.div'
[ D.text "HELLO!"
]
------------------------------------------------------------
-- Util: A very useful combinator for widgets with localised state
loopState ::
forall m a s.
Monad m =>
s ->
(s -> m (Either s a)) ->
m a
loopState s f = f s >>= case _ of
Left s' -> loopState s' f
Right a -> pure a