Skip to content

Commit 6360058

Browse files
Add presence
1 parent 1a39036 commit 6360058

File tree

9 files changed

+106
-91
lines changed

9 files changed

+106
-91
lines changed

assets/js/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ import "phoenix_html"
1414
// Import local files
1515
//
1616
// Local files can be imported directly using relative paths, for example:
17-
// import socket from "./socket"
17+
import socket from "./socket"

assets/js/socket.js

Lines changed: 18 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,25 @@
1-
// NOTE: The contents of this file will only be executed if
2-
// you uncomment its entry in "assets/js/app.js".
1+
import {Socket, Presence} from 'phoenix'
32

4-
// To use Phoenix channels, the first step is to import Socket,
5-
// and connect at the socket path in "lib/web/endpoint.ex".
6-
//
7-
// Pass the token on params as below. Or remove it
8-
// from the params if you are not using authentication.
9-
import {Socket} from "phoenix"
3+
const socket = new Socket('/socket', {params: {username: window.pointingParty.username}})
4+
socket.connect()
105

11-
let socket = new Socket("/socket", {params: {token: window.userToken}})
6+
const channel = socket.channel('room:lobby', {})
7+
const presence = new Presence(channel)
128

13-
// When you connect, you'll often need to authenticate the client.
14-
// For example, imagine you have an authentication plug, `MyAuth`,
15-
// which authenticates the session and assigns a `:current_user`.
16-
// If the current user exists you can assign the user's token in
17-
// the connection for use in the layout.
18-
//
19-
// In your "lib/web/router.ex":
20-
//
21-
// pipeline :browser do
22-
// ...
23-
// plug MyAuth
24-
// plug :put_user_token
25-
// end
26-
//
27-
// defp put_user_token(conn, _) do
28-
// if current_user = conn.assigns[:current_user] do
29-
// token = Phoenix.Token.sign(conn, "user socket", current_user.id)
30-
// assign(conn, :user_token, token)
31-
// else
32-
// conn
33-
// end
34-
// end
35-
//
36-
// Now you need to pass this token to JavaScript. You can do so
37-
// inside a script tag in "lib/web/templates/layout/app.html.eex":
38-
//
39-
// <script>window.userToken = "<%= assigns[:user_token] %>";</script>
40-
//
41-
// You will need to verify the user token in the "connect/3" function
42-
// in "lib/web/channels/user_socket.ex":
43-
//
44-
// def connect(%{"token" => token}, socket, _connect_info) do
45-
// # max_age: 1209600 is equivalent to two weeks in seconds
46-
// case Phoenix.Token.verify(socket, "user socket", token, max_age: 1209600) do
47-
// {:ok, user_id} ->
48-
// {:ok, assign(socket, :user, user_id)}
49-
// {:error, reason} ->
50-
// :error
51-
// end
52-
// end
53-
//
54-
// Finally, connect to the socket:
55-
socket.connect()
9+
presence.onSync(() => {
10+
const users = document.querySelector('.users')
11+
users.innerHTML = ''
12+
13+
presence.list((id, _) => {
14+
const user = document.createElement('li')
15+
user.setAttribute('class', id)
16+
user.appendChild(document.createTextNode(id))
17+
users.appendChild(user)
18+
})
19+
})
5620

57-
// Now that you are connected, you can join channels with a topic:
58-
let channel = socket.channel("topic:subtopic", {})
5921
channel.join()
60-
.receive("ok", resp => { console.log("Joined successfully", resp) })
61-
.receive("error", resp => { console.log("Unable to join", resp) })
22+
.receive('ok', resp => { console.log('Joined successfully', resp) })
23+
.receive('error', resp => { console.log('Unable to join', resp) })
6224

6325
export default socket

lib/pointing_party/application.ex

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,10 @@ defmodule PointingParty.Application do
66
use Application
77

88
def start(_type, _args) do
9-
# List all child processes to be supervised
109
children = [
11-
# Start the Ecto repository
1210
PointingParty.Repo,
13-
# Start the endpoint when the application starts
14-
PointingPartyWeb.Endpoint
15-
# Starts a worker by calling: PointingParty.Worker.start_link(arg)
16-
# {PointingParty.Worker, arg},
11+
PointingPartyWeb.Endpoint,
12+
PointingPartyWeb.Presence
1713
]
1814

1915
# See https://hexdocs.pm/elixir/Supervisor.html
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
defmodule PointingPartyWeb.Presence do
2+
use Phoenix.Presence, otp_app: :pointing_party,
3+
pubsub_server: PointingParty.PubSub
4+
end
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
defmodule PointingPartyWeb.RoomChannel do
2+
use PointingPartyWeb, :channel
3+
4+
alias PointingPartyWeb.Presence
5+
6+
def join("room:lobby", _payload, socket) do
7+
send(self(), :after_join)
8+
9+
{:ok, socket}
10+
end
11+
12+
def handle_info(:after_join, socket) do
13+
push(socket, "presence_state", Presence.list(socket))
14+
{:ok, _} = Presence.track(socket, socket.assigns.username, %{})
15+
16+
{:noreply, socket}
17+
end
18+
end

lib/pointing_party_web/channels/user_socket.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ defmodule PointingPartyWeb.UserSocket do
22
use Phoenix.Socket
33

44
## Channels
5-
# channel "room:*", PointingPartyWeb.RoomChannel
5+
channel "room:lobby", PointingPartyWeb.RoomChannel
66

77
# Socket params are passed from the client and can
88
# be used to verify and authenticate a user. After
@@ -15,8 +15,8 @@ defmodule PointingPartyWeb.UserSocket do
1515
#
1616
# See `Phoenix.Token` documentation for examples in
1717
# performing token verification on connect.
18-
def connect(_params, socket, _connect_info) do
19-
{:ok, socket}
18+
def connect(%{"username" => username}, socket, _connect_info) do
19+
{:ok, assign(socket, :username, username)}
2020
end
2121

2222
# Socket id's are topics that allow you to identify all sockets for a given user:
Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,39 @@
1+
<div class="row">
2+
<div class="col-md-10">
3+
<div class="card text-left">
4+
<div class="card-header">
5+
<h2><%= @card.title %></h2>
6+
</div>
7+
<div class="card-body">
8+
<p class="card-text"><%= @card.description %></p>
9+
<div class="form-group text-left">
10+
<div class="form-row align-items-center">
11+
<div class="col-2">
12+
<label for="storyPoints">Story Points</label>
13+
<select class="form-control" id="storyPoints">
14+
<%= Enum.map(@points, fn point -> %>
15+
<%= if @card.points == point do %>
16+
<option selected="selected'"><%= point %></option>
17+
<% else %>
18+
<option><%= point %></option>
19+
<% end %>
20+
<% end) %>
21+
</select>
22+
</div>
23+
</div>
24+
</div>
25+
<a href="#" class="btn btn-primary">Calculate Points</a>
26+
</div>
127

2-
<div class="card text-left">
3-
<div class="card-header">
4-
<h2><%= @card.title %></h2>
5-
</div>
6-
<div class="card-body">
7-
<p class="card-text"><%= @card.description %></p>
8-
<div class="form-group text-left">
9-
<div class="form-row align-items-center">
10-
<div class="col-2">
11-
<label for="storyPoints">Story Points</label>
12-
<select class="form-control" id="storyPoints">
13-
<%= Enum.map(@points, fn point -> %>
14-
<%= if @card.points == point do %>
15-
<option selected="selected'"><%= point %></option>
16-
<% else %>
17-
<option><%= point %></option>
18-
<% end %>
19-
<% end) %>
20-
</select>
21-
</div>
28+
<div class="card-footer text-muted">
29+
created at: <%= @card.inserted_at %>
2230
</div>
31+
</div>
2332
</div>
24-
<a href="#" class="btn btn-primary">Calculate Points</a>
25-
</div>
26-
<div class="card-footer text-muted">
27-
created at: <%= @card.inserted_at %>
33+
34+
<div class="col-md-2">
35+
<h2>Users</h2>
36+
<ul class="users">
37+
</ul>
2838
</div>
2939
</div>

lib/pointing_party_web/templates/layout/app.html.eex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<title>PointingParty</title>
88
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
99
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
10+
<script>window.pointingParty = window.pointingParty || {}</script>
1011
</head>
1112
<body>
1213
<header>
@@ -31,6 +32,7 @@
3132
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
3233
<%= render @view_module, @view_template, assigns %>
3334
</main>
35+
<script type="text/javascript">window.pointingParty.username = "<%= Map.get(@conn.assigns, :username) %>"</script>
3436
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
3537
</body>
3638
</html>

priv/static/js/app.js

Lines changed: 24 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)