-
Notifications
You must be signed in to change notification settings - Fork 31
/
Chat.elm
223 lines (176 loc) · 5.04 KB
/
Chat.elm
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
module Chat exposing (..) --where
import Html exposing (Html, h3, div, text, ul, li, input, form, button, br, table, tbody, tr, td)
import Html.Attributes exposing (type', value)
import Html.Events exposing (onInput, onSubmit, onClick)
import Html.App
import Platform.Cmd
import Phoenix.Socket
import Phoenix.Channel
import Phoenix.Push
import Json.Encode as JE
import Json.Decode as JD exposing ((:=))
import Dict
-- MAIN
main : Program Never
main =
Html.App.program
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
-- CONSTANTS
socketServer : String
socketServer = "ws://phoenixchat.herokuapp.com/ws"
-- MODEL
type Msg
= ReceiveMessage String
| SendMessage
| SetNewMessage String
| PhoenixMsg (Phoenix.Socket.Msg Msg)
| ReceiveChatMessage JE.Value
| JoinChannel
| LeaveChannel
| ShowJoinedMessage String
| ShowLeftMessage String
| NoOp
type alias Model =
{ newMessage : String
, messages : List String
, phxSocket : Phoenix.Socket.Socket Msg
}
initPhxSocket : Phoenix.Socket.Socket Msg
initPhxSocket =
Phoenix.Socket.init socketServer
|> Phoenix.Socket.withDebug
|> Phoenix.Socket.on "new:msg" "rooms:lobby" ReceiveChatMessage
initModel : Model
initModel =
Model "" [] initPhxSocket
init : ( Model, Cmd Msg )
init =
( initModel, Cmd.none )
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Phoenix.Socket.listen model.phxSocket PhoenixMsg
-- COMMANDS
-- PHOENIX STUFF
type alias ChatMessage =
{ user : String
, body : String
}
chatMessageDecoder : JD.Decoder ChatMessage
chatMessageDecoder =
JD.object2 ChatMessage
("user" := JD.string)
("body" := JD.string)
-- UPDATE
userParams : JE.Value
userParams =
JE.object [ ("user_id", JE.string "123") ]
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ReceiveMessage str ->
( { model | messages = str :: model.messages }
, Cmd.none
)
PhoenixMsg msg ->
let
( phxSocket, phxCmd ) = Phoenix.Socket.update msg model.phxSocket
in
( { model | phxSocket = phxSocket }
, Cmd.map PhoenixMsg phxCmd
)
SendMessage ->
let
payload = (JE.object [ ("user", JE.string "user"), ("body", JE.string model.newMessage) ])
push' =
Phoenix.Push.init "new:msg" "rooms:lobby"
|> Phoenix.Push.withPayload payload
(phxSocket, phxCmd) = Phoenix.Socket.push push' model.phxSocket
in
( { model
| newMessage = ""
, phxSocket = phxSocket
}
, Cmd.map PhoenixMsg phxCmd
)
SetNewMessage str ->
( { model | newMessage = str }
, Cmd.none
)
ReceiveChatMessage raw ->
case JD.decodeValue chatMessageDecoder raw of
Ok chatMessage ->
( { model | messages = (chatMessage.user ++ ": " ++ chatMessage.body) :: model.messages }
, Cmd.none
)
Err error ->
( model, Cmd.none )
JoinChannel ->
let
channel =
Phoenix.Channel.init "rooms:lobby"
|> Phoenix.Channel.withPayload userParams
|> Phoenix.Channel.onJoin (always (ShowJoinedMessage "rooms:lobby"))
|> Phoenix.Channel.onClose (always (ShowLeftMessage "rooms:lobby"))
(phxSocket, phxCmd) = Phoenix.Socket.join channel model.phxSocket
in
({ model | phxSocket = phxSocket }
, Cmd.map PhoenixMsg phxCmd
)
LeaveChannel ->
let
(phxSocket, phxCmd) = Phoenix.Socket.leave "rooms:lobby" model.phxSocket
in
({ model | phxSocket = phxSocket }
, Cmd.map PhoenixMsg phxCmd
)
ShowJoinedMessage channelName ->
( { model | messages = ("Joined channel " ++ channelName) :: model.messages }
, Cmd.none
)
ShowLeftMessage channelName ->
( { model | messages = ("Left channel " ++ channelName) :: model.messages }
, Cmd.none
)
NoOp ->
( model, Cmd.none )
-- VIEW
view : Model -> Html Msg
view model =
div []
[ h3 [] [ text "Channels:" ]
, div
[]
[ button [ onClick JoinChannel ] [ text "Join channel" ]
, button [ onClick LeaveChannel ] [ text "Leave channel" ]
]
, channelsTable (Dict.values model.phxSocket.channels)
, br [] []
, h3 [] [ text "Messages:" ]
, newMessageForm model
, ul [] ((List.reverse << List.map renderMessage) model.messages)
]
channelsTable : List (Phoenix.Channel.Channel Msg) -> Html Msg
channelsTable channels =
table []
[ tbody [] (List.map channelRow channels)
]
channelRow : (Phoenix.Channel.Channel Msg) -> Html Msg
channelRow channel =
tr []
[ td [] [ text channel.name ]
, td [] [ (text << toString) channel.payload ]
, td [] [ (text << toString) channel.state ]
]
newMessageForm : Model -> Html Msg
newMessageForm model =
form [ onSubmit SendMessage ]
[ input [ type' "text", value model.newMessage, onInput SetNewMessage ] []
]
renderMessage : String -> Html Msg
renderMessage str =
li [] [ text str ]