diff --git a/priv/repo/migrations/20170815184450_add_vote_table.exs b/priv/repo/migrations/20170815184450_add_vote_table.exs new file mode 100644 index 000000000..060f42f00 --- /dev/null +++ b/priv/repo/migrations/20170815184450_add_vote_table.exs @@ -0,0 +1,18 @@ +defmodule RemoteRetro.Repo.Migrations.AddVoteTable do + use Ecto.Migration + + def change do + create table(:votes) do + add :user_id, references(:users, [ + column: :id, + on_delete: :nothing + ]) + add :idea_id, references(:ideas, [ + column: :id, + on_delete: :nothing + ]) + + timestamps() + end + end +end diff --git a/web/channels/retro_channel.ex b/web/channels/retro_channel.ex index 6e655beda..5f33a8e00 100644 --- a/web/channels/retro_channel.ex +++ b/web/channels/retro_channel.ex @@ -1,7 +1,7 @@ defmodule RemoteRetro.RetroChannel do use RemoteRetro.Web, :channel - alias RemoteRetro.{Presence, PresenceUtils, Idea, Emails, Mailer, Retro} + alias RemoteRetro.{Presence, PresenceUtils, Idea, Emails, Mailer, Retro, Vote} def join("retro:" <> retro_id, _, socket) do socket = assign(socket, :retro_id, retro_id) @@ -76,11 +76,16 @@ defmodule RemoteRetro.RetroChannel do {:noreply, socket} end - def handle_in("submit_vote", %{"id" => id}, socket) do - query = from i in Idea, where: i.id == ^id - {_row_count, [updated_idea]} = Repo.update_all(query, [inc: [vote_count: 1]], returning: true) + def handle_in("submit_vote", %{"ideaId" => idea_id, "userId" => user_id}, socket) do + vote = + %Vote{ + idea_id: idea_id, + user_id: user_id + } + |> Vote.changeset + |> Repo.insert! - broadcast! socket, "vote_submitted", updated_idea + broadcast! socket, "vote_submitted", vote {:noreply, socket} end diff --git a/web/models/idea.ex b/web/models/idea.ex index 57455ace2..327297892 100644 --- a/web/models/idea.ex +++ b/web/models/idea.ex @@ -9,6 +9,7 @@ defmodule RemoteRetro.Idea do belongs_to :retro, RemoteRetro.Retro, type: Ecto.UUID belongs_to :user, RemoteRetro.User + has_many :vote, RemoteRetro.Vote timestamps(type: :utc_datetime) end diff --git a/web/models/user.ex b/web/models/user.ex index 4d1d1d5a7..6d0fbd795 100644 --- a/web/models/user.ex +++ b/web/models/user.ex @@ -25,6 +25,7 @@ defmodule RemoteRetro.User do field :last_login, Ecto.DateTime has_many :participations, RemoteRetro.Participation + has_many :votes, RemoteRetro.Vote timestamps(type: :utc_datetime) end diff --git a/web/models/vote.ex b/web/models/vote.ex new file mode 100644 index 000000000..9d9890e15 --- /dev/null +++ b/web/models/vote.ex @@ -0,0 +1,19 @@ +defmodule RemoteRetro.Vote do + use RemoteRetro.Web, :model + + @derive {Poison.Encoder, except: [:__meta__]} + schema "votes" do + belongs_to :user, RemoteRetro.User + belongs_to :idea, RemoteRetro.Idea + + timestamps(type: :utc_datetime) + end + + @required_fields [:user_id, :idea_id] + + def changeset(struct, params \\ %{}) do + struct + |> cast(params, @required_fields) + |> validate_required(@required_fields) + end +end diff --git a/web/static/js/components/idea_controls.jsx b/web/static/js/components/idea_controls.jsx index a4e08d70c..c195d93f0 100644 --- a/web/static/js/components/idea_controls.jsx +++ b/web/static/js/components/idea_controls.jsx @@ -24,7 +24,11 @@ const IdeaControls = props => { function renderIcons() { if (stage !== "idea-generation" && category !== "action-item") { return ( - + ) } if (currentUser.is_facilitator) { diff --git a/web/static/js/components/vote_counter.jsx b/web/static/js/components/vote_counter.jsx index add049014..10f798262 100644 --- a/web/static/js/components/vote_counter.jsx +++ b/web/static/js/components/vote_counter.jsx @@ -9,8 +9,8 @@ class VoteCounter extends React.Component { } handleClick() { - const { idea, retroChannel } = this.props - retroChannel.push("submit_vote", { id: idea.id }) + const { idea, retroChannel, currentUser } = this.props + retroChannel.push("submit_vote", { ideaId: idea.id, userId: currentUser.id }) } render() { @@ -32,6 +32,7 @@ class VoteCounter extends React.Component { VoteCounter.propTypes = { retroChannel: AppPropTypes.retroChannel.isRequired, idea: AppPropTypes.idea.isRequired, + currentUser: AppPropTypes.user.isRequired, } export default VoteCounter diff --git a/web/static/js/reducers/ideas.js b/web/static/js/reducers/ideas.js index 20a6de6f7..2d4eb07a4 100644 --- a/web/static/js/reducers/ideas.js +++ b/web/static/js/reducers/ideas.js @@ -1,3 +1,5 @@ +// const updateIdea = state + const ideas = (state = [], action) => { switch (action.type) { case "SET_INITIAL_STATE": diff --git a/web/static/js/services/retro_channel.js b/web/static/js/services/retro_channel.js index 358732d87..54b19b732 100644 --- a/web/static/js/services/retro_channel.js +++ b/web/static/js/services/retro_channel.js @@ -47,8 +47,9 @@ const applyListenerCallbacks = (retroChannel, store, actions) => { actions.deleteIdea(deletedIdea.id) }) - retroChannel.on("vote_submitted", votedOnIdea => { - actions.updateIdea(votedOnIdea.id, { vote_count: votedOnIdea.vote_count }) + retroChannel.on("vote_submitted", ideaId => { + // actions.updateIdea(votedOnIdea.id, { vote_count: votedOnIdea.vote_count }) + console.log("in vote submitted", ideaId) }) retroChannel.on("idea_highlighted", highlightedIdea => {