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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
module Gargantext.Components.Forest.Tree.Node.Action.Share where
import Data.Array (filter, nub)
import Data.Either (Either(..))
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..))
import Data.Show.Generic (genericShow)
import Data.String (Pattern(..), contains)
import Data.Tuple.Nested ((/\))
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (Elevation(Level1))
import Gargantext.Components.Forest.Tree.Node.Action.Types as Action
import Gargantext.Components.Forest.Tree.Node.Tools as Tools
import Gargantext.Components.Forest.Tree.Node.Tools.SubTree (subTreeView, SubTreeParamsIn)
import Gargantext.Components.InputWithAutocomplete (inputWithAutocomplete)
import Gargantext.Config.REST (AffRESTError)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Prelude
import Gargantext.Routes as GR
import Gargantext.Sessions (Session, get, post)
import Gargantext.Types (ID, NodeID, NodeType)
import Gargantext.Types as GT
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.SimpleJSON as GUSJ
import Reactix as R
import Reactix.DOM.HTML as H
import Simple.JSON as JSON
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree.Node.Action.Share"
------------------------------------------------------------------------
shareReq :: Session -> ID -> ShareNodeParams -> AffRESTError ID
shareReq session nodeId =
post session $ GR.NodeAPI GT.Node (Just nodeId) "share"
getCompletionsReq :: { session :: Session } -> AffRESTError (Array String)
getCompletionsReq { session } =
get session GR.Members
------------------------------------------------------------------------
data ShareNodeParams =
ShareTeamParams { username :: String }
| SharePublicParams { node_id :: Int }
derive instance Eq ShareNodeParams
derive instance Generic ShareNodeParams _
instance JSON.ReadForeign ShareNodeParams where readImpl = GUSJ.taggedSumRep
instance JSON.WriteForeign ShareNodeParams where
writeImpl (ShareTeamParams { username }) = JSON.writeImpl { "type": "ShareTeamParams"
, username }
writeImpl (SharePublicParams { node_id }) = JSON.writeImpl { "type": "SharePublicParams"
, node_id }
instance Show ShareNodeParams where show = genericShow
------------------------------------------------------------------------
type ShareNode =
( id :: ID
, session :: Session )
shareNode :: R2.Component ShareNode
shareNode = R.createElement shareNodeCpt
shareNodeCpt :: R.Component ShareNode
shareNodeCpt = R2.hereComponent here "shareNode" hCpt where
hCpt hp { id, session } _ = do
useLoader { errorHandler: Nothing
, herePrefix: hp
, loader: getCompletionsReq
, path: { session }
, render: \completions -> shareNodeInner { completions, id, session } []
}
type ShareNodeInner =
( completions :: Array String
| ShareNode
)
shareNodeInner :: R2.Component ShareNodeInner
shareNodeInner = R.createElement shareNodeInnerCpt
shareNodeInnerCpt :: R.Component ShareNodeInner
shareNodeInnerCpt = here.component "shareNodeInner" cpt
where
cpt { completions, id, session } _ = do
state' /\ state <- R2.useBox' ""
text' /\ text <- R2.useBox' ""
mError' /\ mError <- R2.useBox' Nothing
pure $ Tools.panel { mError: mError' }
[ inputWithAutocomplete { autoFocus: true
, autocompleteSearch
, classes: "share-users-completions d-flex align-items-center"
, onAutocompleteClick
, onEnterPress: onEnterPress text mError
, pattern: "^\\S+$" -- pattern doesn't allow space characters
, placeholder: "username or email"
, state
, title }
[ B.iconButton { callback: \_ -> onEnterPress text mError state'
, elevation: Level1
, name: "send"
, title: "Submit" } ]
-- footer
, H.div {} [ H.text text' ] ]
where
autocompleteSearch input = pure $ nub $ filter (contains (Pattern input)) completions
onAutocompleteClick _ = pure unit
onEnterPress text mError val = do
T.write_ Nothing mError
launchAff_ do
eRes <- shareReq session id $ ShareTeamParams { username: val }
liftEffect $ case eRes of
Left err -> do
T.write_ (Just $ show err) mError
Right _ -> do
T.write_ ("Invited " <> val <> " to the team") text
T.write_ Nothing mError
title = "Enter a username or an email address (space characters are not allowed)"
------------------------------------------------------------------------
publishNode :: R2.Component SubTreeParamsIn
publishNode = R.createElement publishNodeCpt
publishNodeCpt :: R.Component SubTreeParamsIn
publishNodeCpt = here.component "publishNode" cpt
where
cpt { dispatch, id, nodeType, session, subTreeParams } _ = do
action <- T.useBox (Action.SharePublic { params: Nothing })
action' <- T.useLive T.unequal action
let button = case action' of
Action.SharePublic { params } ->
R2.fromMaybe params $
\val -> Tools.submitButton { action: Action.SharePublic {params: Just val}
, dispatch }
_ -> H.div {} []
pure $ Tools.panel { mError: Nothing }
[ subTreeView { action
, dispatch
, id
, nodeType
, session
, subTreeParams
} []
-- footer
, button ]
------------------------------------------------------------------------
type ShareURL =
( nodeType :: NodeType
, id :: ID
, session :: Session)
shareURL :: R2.Component ShareURL
shareURL = R.createElement shareURLcpt
shareURLcpt :: R.Component ShareURL
shareURLcpt = R2.hereComponent here "shareURL" hCpt
where
hCpt hp {nodeType, id, session} _ = do
useLoader { errorHandler: Just errorHandler
, herePrefix: hp
, loader: loadUrl
, path: {nodeType, id, session}
, render: \url -> shareURLInner {url} [] }
errorHandler err = here.warn2 "[ShareURL] RESTError" err
shareURLInner :: R2.Component ( url :: String )
shareURLInner = R.createElement shareURLInnercpt
shareURLInnercpt :: R.Component ( url :: String )
shareURLInnercpt = here.component "shareURLInner" cpt
where
cpt { url } _ = do
pure $ Tools.panel { mError: Nothing } [ H.div {} [ H.text url ] ]
loadUrl :: { session :: Session, id :: NodeID, nodeType :: NodeType } -> AffRESTError String
loadUrl { session, id, nodeType } = get session $ GR.ShareURL id nodeType