Creating a real-time Trello board with Phoenix LiveView-Part-1

Search for a command to run...

Wow nice
Had the folder misplacement of file didn't run the code? I'll check and update it ASAP. Sorry for the confusion.
You mentioned: "We are going to place both functions in a separate module organization.ex under trello_app/lib/trello_app folder." I suppose it to be in trello_app/lib folder because:
Motivation Recently, I tried to learn some low-level system programming stuff. I am a Mac user, and I thought that everything that works on Linux should also work on Mac. After all, Mac is a Unix-based system 😊. I guess we all heard this. Oh boy! I ...

Problem Statement While working on a Nestjs project, I encountered a weird problem related to the database column. I was trying to insert a record into a MySQL table using TypeORM. The error I was experiencing stated that a specific column “cannot be...

Recently, I was exploring design patterns courses on my LinkedIn Learning subscription. I came across a course, Node.js: Design Patterns by Alex Banks. It is a wonderful, easy-to-understand course. I started with the Builder Pattern, and the explanat...

Suppose you are working on a table in a LiveView project. This table has limited static data of not more than one page (you can avoid questions about pagination in the comment section 😊). From a user's point of view, it becomes hard to look into the...

Recently, while working on one of my personal Elixir projects. I came across a scenario where I needed to make some changes to the database schema.The changes mainly revolve around adding and removing indexes due to changes in the business requiremen...

Trello cards help you to collaborate, manage projects, and reach new productivity peaks(As per their official Website 😊). You may have used it earlier or some similar board like Jira to manage projects and tasks. When I joined one of my previous organizations, my training was tracked using the Trello board which helped me and other new joiners in learning and track our progress. In this Blog, we are about to create a similar board with a real-time update feature.
We are going to build a Trello look-alike board. It will have different cards belonging to different sections. We can drag and drop cards to different sections with a smooth transition. Along with the drag-and-drop transition of cards to different sections, the whole experience will be real-time. If any user makes any change in the card section then any other user watching the application screen doesn't have to explicitly refresh the browser to see the effect. Refer to the gif below to get an idea.

This is a 3 part blog series.
iex shell (This is Part 1)Let's start building 👷
Elixir -v.mix phx.new trello_app --live** (Mix) The task "phx.new" could not be found
Note no mix.exs was found in the current directory
Then run mix archive.install hex phx_newcd trello_app and run mix phx.server. Once, the project starts running navigate to localhost:4000 to see the welcome phoenix screen.card and the user to which this card belongs. We will call these cards Task.User table and the Task table. User table run mix ecto.gen.migration create_user and for Task table run mix ecto.gen.migration create_taskNow open trello_app/priv/repo/migrations/{{some_time_stamp}}_create_user.exs migration file at and the add following fields in the migration file.
defmodule TrelloApp.Repo.Migrations.CreateUser do
use Ecto.Migration
def change do
create table(:users) do
add :first_name, :string, null: false
add :last_name, :string, null: false
timestamps()
end
end
end
Similarly for task table open trello_app/priv/repo/migrations/{{some_time_stamp}}_create_task.exs migration file and the following fields
defmodule TrelloApp.Repo.Migrations.CreateTask do
use Ecto.Migration
def change do
create table(:tasks) do
add :title, :string, null: false
add :description, :text
add :user_id, references(:users)
add :state, :string, null: false
timestamps()
end
end
end
mix ecto.migrate. This will create tables User and Task in the database.User and Task tables now we are going to add User and Task structs so that we can use Ecto queries effectively.Task struct. For that we will create a file trello_app/lib/trello_app/organization/task.ex.Add the following code to the file.
defmodule TrelloApp.Organization.Task do
use Ecto.Schema
import Ecto.Changeset
alias TrelloApp.Organization.{ Task, User }
schema "tasks" do
field :title, :string
field :description, :string
field :state, :string
belongs_to :user, User
timestamps()
end
def changeset(%Task{} = task, attrs) do
task
|> cast(attrs, [:title, :description, :state, :user_id])
end
end
User struct in the same organization directory with a file name user.ex.We will add a similar code here as well.
defmodule TrelloApp.Organization.User do
use Ecto.Schema
import Ecto.Changeset
alias TrelloApp.Organization.{ Task, User }
schema "users" do
field :first_name
field :last_name
has_many :task, Task
timestamps()
end
def changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:first_name, :last_name])
end
end
User and Task has fields defined in the schema macro similar to the migration files. one-to-many relationship between User and Task which means User can have many Task. We've also defined the changeset functions for manipulating the data.iex shell.iex shell by typing iex -S mix.Repo to avoid typing long struct names.alias TrelloApp.Organization.{ Task, User }
First, we will insert the User record for that we will run the following code.
User.changeset(%User{}, %{first_name: "Michael", last_name: "Jordan"})
|> Repo.insert
User.changeset(%User{}, %{first_name: "Andrew", last_name: "Flintoff"})
|> Repo.insert
User's records with id of 1 and 2.Similarly, we will add a few Task records for both users but with different states. For testing purposes, we will add four tasks with the states "planning", "progress", and "completed".
%Task{}
|> Task.changeset(%{title: "Designing API", description: "designing api", state: "planning", user_id: 1})
|> Repo.insert
%Task{}
|> Task.changeset(%{title: "Take Backup", description: "take backup", state: "progress", user_id: 2})
|> Repo.insert
%Task{}
|> Task.changeset(%{title: "Add Migrations", description: "write migrations", state: "progress", user_id: 1})
|> Repo.insert
%Task{}
|> Task.changeset(%{title: "Write Script", description: "write script", state: "completed", user_id: 2})
|> Repo.insert
User record and three Task records.get_grouped_tasks and change_task_state.get_grouped_tasks will do?Task struct we have a state field. We've added three tasks records with state planning, progress, and completed.state mentioned in the task) and placed in the respective states column.

def get_grouped_tasks() do
Task
|> Repo.all()
|> Repo.preload(:user)
|> Enum.group_by(fn %{state: state} -> state end)
end
change_task_state.change_task_state will do?
Progress to Completed, we want to change the state field of the task from progress to completed.task_id and transition_state i.e the column we want our task should be moved.task by task_id parameterstate of the task as per provided transition_state using changeset function in Task structTaskdef change_task_state(task_id, transition_state) do
Task
|> Repo.get(task_id)
|> Task.changeset(%{state: transition_state})
|> Repo.update
end
organization.ex under trello_app/lib/trello_app folder.This module will be the provider of the two functions, which we will use in the LiveView module later.
defmodule TrelloApp.Organization do
alias TrelloApp.Repo
alias TrelloApp.Organization.Task
def get_grouped_tasks() do
Task
|> Repo.all()
|> Repo.preload(:user)
|> Enum.group_by(fn %{state: state} -> state end)
end
def change_task_state(task_id, transition_state) do
Task
|> Repo.get(task_id)
|> Task.changeset(%{state: transition_state})
|> Repo.update
end
end
iex shelltask and user.get_grouped_tasks/0 and change_task_state/2. First, we will test get_grouped_tasks/0,Organization module alias TrelloApp.Organization
Organization.get_grouped_tasks(), this will return grouped tasks as per their states%{
"planning" => [
%TrelloApp.Organization.Task{
__meta__: #Ecto.Schema.Metadata<:loaded, "tasks">,
description: "designing api",
id: 2,
inserted_at: ~N[2022-08-25 09:30:08],
state: "planning",
title: "Designing API",
updated_at: ~N[2022-08-25 09:30:08],
user: %TrelloApp.Organization.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
first_name: "Michael",
id: 1,
inserted_at: ~N[2022-08-25 08:45:25],
last_name: "holding",
tasks: #Ecto.Association.NotLoaded<association :tasks is not loaded>,
updated_at: ~N[2022-08-25 08:45:25]
},
user_id: 1
}
],
"progress" => [
// two tasks under progress
%TrelloApp.Organization.Task{ id: 2 },
%TrelloApp.Organization.Task{ id: 3 }
],
"completed" => [
// one task under completed
%TrelloApp.Organization.Task{id: 4}
]
}
planning, one task for completed, and two for progress. This is exactly as per the tasks we added with different states.change_task_state for first task i.e id=1.change_task_state/2 expects two parameters task_id and transtion_state.id=1 to the completed state. So, we will run Organization.change_task_state(1, 'completed') in our shell.id=1 to the completed column. We can test this by again running the get_grouped_task. It will not return the planning group since there is no task left with the planning state.This completes the first blog of this series. In the next part as per our planning, we will build the board, add tasks UI along with drag and drop functionality and will integrate the board with our API layer. I hope you like this blog. If you have any questions then please comment below. Thanks for reading 😊.