Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
purescript-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Grégoire Locqueville
purescript-gargantext
Commits
64405219
Commit
64405219
authored
Sep 20, 2019
by
James Laver
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New login component
parent
e7f00a37
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
96 additions
and
126 deletions
+96
-126
Login.purs
src/Gargantext/Components/Login.purs
+93
-125
Types.purs
src/Gargantext/Components/Login/Types.purs
+3
-1
No files found.
src/Gargantext/Components/Login.purs
View file @
64405219
module Gargantext.Components.Login where
module Gargantext.Components.Login where
import Control.Monad.Cont.Trans (lift)
import Control.Monad.Except (runExcept)
import Data.Either (Either(..))
import Data.Int as Int
import Data.Int as Int
import Data.Lens (over)
import Data.Map (Map)
import Data.Map as Map
import Data.Maybe (Maybe(..))
import Data.Maybe (Maybe(..))
import Data.Traversable (traverse)
import Data.Tuple.Nested((/\))
import Data.Tuple.Nested((/\))
import DOM.Simple.Console (log2)
import Effect.Class (liftEffect)
import Effect.Class (liftEffect)
import Effect (Effect)
import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Aff (Aff, launchAff_)
import Foreign (MultipleErrors)
import Foreign.Generic (encodeJSON, decodeJSON)
import Reactix as R
import Reactix as R
import Reactix.DOM.HTML as H
import Reactix.DOM.HTML as H
import React.DOM (button, div, h5, span, text)
import React.DOM.Props (_data, _id, _type, aria, className, role)
import Thermite (PerformAction, Render, Spec, _render, modifyState_, simpleSpec)
import Web.HTML (window)
import Web.HTML (window)
import Web.HTML.Window (localStorage)
import Web.HTML.Window (localStorage)
import Web.Storage.Storage (getItem, setItem, removeItem)
import Web.Storage.Storage (getItem, setItem, removeItem)
------------------------------------------------------------------------
------------------------------------------------------------------------
import Gargantext.Prelude
import Gargantext.Prelude
import Gargantext.Config (
toUrl, endConfigStateful, Path(..), End(..)
)
import Gargantext.Config (
Ends, BackendRoute(..), backendKey, url
)
import Gargantext.Config.REST (post)
import Gargantext.Config.REST (post)
import Gargantext.Components.Modals.Modal (modalHide)
import Gargantext.Components.Modals.Modal (modalHide)
import Gargantext.Components.Login.Types
import Gargantext.Components.Login.Types
...
@@ -28,104 +31,40 @@ import Gargantext.Utils.Reactix as R2
...
@@ -28,104 +31,40 @@ import Gargantext.Utils.Reactix as R2
-- TODO: ask for login (modal) or account creation after 15 mn when user
-- TODO: ask for login (modal) or account creation after 15 mn when user
-- is not logged and has made one search at least
-- is not logged and has made one search at least
type State =
type Auths = Map String AuthData
{ username :: String
, password :: String
, authData :: Maybe AuthData
, errorMessage :: String
}
initialState :: Effect State
initialState = do
authData <- getAuthData
pure
{ authData
, username : ""
, password : ""
, errorMessage : ""
}
data Action
= PostAuth
| SetCredentials String String
modalSpec :: forall props. Boolean -> String -> Spec State props Action -> Spec State props Action
modalSpec sm t = over _render \render d p s c ->
[ div [ _id "loginModal", className $ "modal myModal" <> if sm then "" else " fade"
, role "dialog"
, _data {show : true}
]
[ div [ className "modal-dialog"
, role "document"
]
[ div [ className "modal-content"]
[ div [ className "modal-header"]
[ h5 [ className "modal-title" ]
[ -- text t
]
, button [ _type "button"
, className "close"
, _data { dismiss : "modal"}
]
[ span [ aria {hidden : true}] [ text "X"]
]
]
, div [ className "modal-body"] (render d p s c)
]
]
]
]
spec' :: Spec State {} Action
spec' = modalSpec true "Login" renderSpec
performAction :: PerformAction State {} Action
performAction (SetCredentials usr pwd) _ _ = do
modifyState_ $ _ { username = usr, password = pwd }
performAction PostAuth _ {username, password} = do
res <- lift $ postAuthRequest $ AuthRequest {username, password}
case res of
AuthResponse {inval: Just (AuthInvalid {message})} ->
modifyState_ $ _ { errorMessage = message }
AuthResponse {valid} -> do
liftEffect $ setAuthData valid
modifyState_ $ _ {authData = valid, errorMessage = ""}
liftEffect $ modalHide "loginModal"
renderSpec :: Spec State {} Action
renderSpec = simpleSpec performAction render
where
render :: Render State {} Action
render dispatch _ state _ =
[R2.scuff $ renderCpt dispatch state]
type Props = ( ends :: Ends, setVisible :: R2.Setter Boolean)
renderCpt :: (Action -> Effect Unit) -> State -> R.Element
type ModalProps = ( visible :: Boolean )
renderCpt d s = R.createElement el {} []
where
el = R.hooksComponent "RenderComponent" cpt
cpt {} _children = do
(state /\ setState) <- R.useState' s
R.useEffect $
modal :: Record ModalProps -> Array R.Element -> R.Element
if (state /= s) then do
modal = R.createElement modalCpt
_ <- d $ SetCredentials state.username state.password
pure $ d $ PostAuth
else
pure $ pure $ unit
pure $ renderLogin (state /\ setState)
modalCpt :: R.Component ModalProps
modalCpt = R.staticComponent "Modal" cpt
renderLogin :: R.State State -> R.Element
renderLogin (state /\ setState) = R.createElement el {} []
where
where
el = R.hooksComponent "RenderLogin" cpt
cpt {visible} children =
cpt {} _children = do
H.div { id: "loginModal", className: modalClass visible, role: "dialog", "data": {show: true}}
username <- R.useState' state.username
[ H.div { className: "modal-dialog", role: "document"}
password <- R.useState' state.password
[ H.div { className: "modal-content" }
[ H.div { className: "modal-header" }
[ H.h5 { className: "modal-title" } []
, H.button { "type": "button", className: "close", "data": { dismiss: "modal" } }
[ H.span { aria: { hidden: true } } [ H.text "X" ] ]
, H.div { className: "modal-body" } children ] ] ] ]
modalClass s = "modal myModal" <> if s then "" else " fade"
login :: Record Props -> R.Element
login props = R.createElement loginCpt props []
loginCpt :: R.Component Props
loginCpt = R.hooksComponent "Login" cpt
where
cpt {ends, setVisible} _children = do
(username /\ setUsername) <- R.useState' ""
(password /\ setPassword) <- R.useState' ""
(error /\ setError) <- R.useState' ""
(authData /\ setAuthData) <- R.useState' Nothing
pure $ H.div {className: "row"}
pure $ H.div {className: "row"}
[ gargLogo
[ gargLogo
, H.div {className: "card-group"}
, H.div {className: "card-group"}
...
@@ -141,7 +80,7 @@ renderLogin (state /\ setState) = R.createElement el {} []
...
@@ -141,7 +80,7 @@ renderLogin (state /\ setState) = R.createElement el {} []
H.a { target: "blank"
H.a { target: "blank"
, href: "https://iscpif.fr/services/applyforourservices/"
, href: "https://iscpif.fr/services/applyforourservices/"
}
}
[H.text "
ask to get an
access"]
[H.text "
request
access"]
]
]
]
]
, H.div {}
, H.div {}
...
@@ -152,11 +91,11 @@ renderLogin (state /\ setState) = R.createElement el {} []
...
@@ -152,11 +91,11 @@ renderLogin (state /\ setState) = R.createElement el {} []
}
}
, H.div {className: "form-group"}
, H.div {className: "form-group"}
[ H.p {} [H.text
state.errorMessage
]
[ H.p {} [H.text
error
]
, usernameInput username
, usernameInput username
setUsername
]
]
, H.div {className: "form-group"}
, H.div {className: "form-group"}
[ passwordInput password
[ passwordInput password
setPassword
, H.div {className: "clearfix"} []
, H.div {className: "clearfix"} []
]
]
, H.div {className: "center"}
, H.div {className: "center"}
...
@@ -167,7 +106,7 @@ renderLogin (state /\ setState) = R.createElement el {} []
...
@@ -167,7 +106,7 @@ renderLogin (state /\ setState) = R.createElement el {} []
, value: ""
, value: ""
, className: "checkbox"
, className: "checkbox"
}
}
, H.text "I accept the terms of use
s
"
, H.text "I accept the terms of use "
, H.a {href: "http://gitlab.iscpif.fr/humanities/tofu/tree/master"}
, H.a {href: "http://gitlab.iscpif.fr/humanities/tofu/tree/master"}
[ H.text " [ Read the terms of use ] "]
[ H.text " [ Read the terms of use ] "]
]
]
...
@@ -177,7 +116,7 @@ renderLogin (state /\ setState) = R.createElement el {} []
...
@@ -177,7 +116,7 @@ renderLogin (state /\ setState) = R.createElement el {} []
, type: "submit"
, type: "submit"
-- TODO
-- TODO
--, on: {click: \_ -> dispatch $ PostAuth}
--, on: {click: \_ -> dispatch $ PostAuth}
, on: {click: onClick username password}
, on: {click: onClick
ends setError setAuthData setVisible
username password}
}
}
[H.text "Login"]
[H.text "Login"]
]
]
...
@@ -190,13 +129,9 @@ renderLogin (state /\ setState) = R.createElement el {} []
...
@@ -190,13 +129,9 @@ renderLogin (state /\ setState) = R.createElement el {} []
gargLogo =
gargLogo =
H.div {className: "col-md-10 col-md-push-1"}
H.div {className: "col-md-10 col-md-push-1"}
[ H.h2 {className: "text-primary center m-a-2"}
[ H.h2 {className: "text-primary center m-a-2"}
[ H.i {className: "material-icons md-36"}
[ H.i {className: "material-icons md-36"} [ H.text "control_point" ]
[H.text "control_point"]
, H.span {className: "icon-text"} [ H.text "Gargantext" ] ] ]
, H.span {className: "icon-text"}
usernameInput username setUsername =
[H.text "Gargantext"]
]
]
usernameInput (username /\ setUsername) =
H.input { className: "form-control"
H.input { className: "form-control"
, id: "id_username"
, id: "id_username"
, maxLength: "254"
, maxLength: "254"
...
@@ -207,7 +142,8 @@ renderLogin (state /\ setState) = R.createElement el {} []
...
@@ -207,7 +142,8 @@ renderLogin (state /\ setState) = R.createElement el {} []
--, on: {input: \e -> dispatch (SetUserName $ R2.unsafeEventValue e)}
--, on: {input: \e -> dispatch (SetUserName $ R2.unsafeEventValue e)}
, on: {change: \e -> setUsername $ const $ R2.unsafeEventValue e}
, on: {change: \e -> setUsername $ const $ R2.unsafeEventValue e}
}
}
passwordInput (password /\ setPassword) =
passwordInput password setPassword =
H.input { className: "form-control"
H.input { className: "form-control"
, id: "id_password"
, id: "id_password"
, name: "password"
, name: "password"
...
@@ -217,14 +153,41 @@ renderLogin (state /\ setState) = R.createElement el {} []
...
@@ -217,14 +153,41 @@ renderLogin (state /\ setState) = R.createElement el {} []
--, on: {input: \e -> dispatch (SetPassword $ R2.unsafeEventValue e)}
--, on: {input: \e -> dispatch (SetPassword $ R2.unsafeEventValue e)}
, on: {change: \e -> setPassword $ const $ R2.unsafeEventValue e}
, on: {change: \e -> setPassword $ const $ R2.unsafeEventValue e}
}
}
onClick (username /\ _) (password /\ _) = \e -> do
onClick ends setError setAuthData setVisible username password = \e ->
setState $ \st -> st {username = username, password = password}
launchAff_ $ do
res <- postAuthRequest ends $ AuthRequest {username, password}
case res of
AuthResponse {inval: Just (AuthInvalid {message})} -> liftEffect $ do
setError (const message)
setAuthData (const Nothing)
AuthResponse {valid} -> liftEffect $ do
setAuthData (const valid)
setError (const "")
setVisible (const false)
-- getAuth :: Effect Auth
-- getAuth = do
-- window >>= localStorage >>= getItem
-- setAuth :: Auth -> Effect Unit
getAuths :: Effect (Maybe Auths)
getAuths = pure Nothing
-- getAuths = window >>= localStorage >>= getItem "auths" >>= traverse decode
-- where
-- decode :: String -> Effect (Maybe Auths)
-- decode = ret <<< runExcept <<< decodeJSON
-- ret (Right v) = pure $ Just v
-- ret (Left e) = log2 "Error reading serialised auths:" e *> pure Nothing
setAuths :: Auths -> Effect Unit
-- setAuths Map.empty = -- window >>= localStorage >>= removeItem "auths"
setAuths _ = pure unit -- auths = window >>= localStorage >>= setItem "auths" (encodeJSON auths)
getAuthData :: Effect (Maybe AuthData)
getAuthData :: Effect (Maybe AuthData)
getAuthData = do
getAuthData = do
w <- window
ls <- window >>= localStorage
ls <- localStorage w
mto <- getItem "token" ls
mto <- getItem "token" ls
mti <- getItem "tree_id" ls
mti <- getItem "tree_id" ls
pure do
pure do
...
@@ -234,15 +197,20 @@ getAuthData = do
...
@@ -234,15 +197,20 @@ getAuthData = do
setAuthData :: Maybe AuthData -> Effect Unit
setAuthData :: Maybe AuthData -> Effect Unit
setAuthData Nothing = do
setAuthData Nothing = do
w <- window
ls <- window >>= localStorage
ls <- localStorage w
removeItem "token" ls
removeItem "token" ls
removeItem "tree_id" ls
removeItem "tree_id" ls
setAuthData (Just (AuthData {tree_id, token})) = do
setAuthData (Just (AuthData {tree_id, token})) = do
w <- window
ls <- window >>= localStorage
ls <- localStorage w
setItem "token" token ls
setItem "token" token ls
setItem "tree_id" (show tree_id) ls
setItem "tree_id" (show tree_id) ls
postAuthRequest :: AuthRequest -> Aff AuthResponse
-- TODO
postAuthRequest = post $ toUrl endConfigStateful Back Auth Nothing
-- useLocalStorageAuths :: String -> R.Hooks (R.State Auths)
-- useLocalStorageAuths key = do
postAuthRequest :: Ends -> AuthRequest -> Aff AuthResponse
postAuthRequest ends = post $ url ends Auth
getCurrentAuth :: Ends -> Auths -> Maybe AuthData
getCurrentAuth ends = Map.lookup (backendKey ends.backend)
src/Gargantext/Components/Login/Types.purs
View file @
64405219
...
@@ -8,6 +8,7 @@ import Data.Generic.Rep (class Generic)
...
@@ -8,6 +8,7 @@ import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Eq (genericEq)
import Data.Generic.Rep.Eq (genericEq)
import Data.Lens (Iso', iso)
import Data.Lens (Iso', iso)
import Data.Maybe (Maybe)
import Data.Maybe (Maybe)
import Data.Newtype (class Newtype)
type Username = String
type Username = String
type Password = String
type Password = String
...
@@ -32,9 +33,10 @@ newtype AuthData = AuthData
...
@@ -32,9 +33,10 @@ newtype AuthData = AuthData
, tree_id :: TreeId
, tree_id :: TreeId
}
}
derive instance genericAuthData :: Generic AuthData _
derive instance genericAuthData :: Generic AuthData _
derive instance newtypeAuthData :: Newtype AuthData _
instance eqAuthData :: Eq AuthData where
instance eqAuthData :: Eq AuthData where
eq = genericEq
eq = genericEq
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment