Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Browse all series

Build a Voting App

In this workshop, we’ll build a voting app, similar to UserVoice, that allows you to create ideas, vote and comment on them, sort and filter the results, and even administer the site. We’ll start from scratch and work through the entire process, including implementing the design, working on all of the features, testing our code, and more.

We’ll be making use of the TALL (Tailwind, Alpine, Livewire, Laravel) stack in this particular series.

Progress

Series Info

Episodes
67
Run Time
18h 19m
Difficulty
Intermediate
Last Updated
Jun 29, 2021
Version
Laravel 8, Tailwind 2, Livewire 2

Series Episodes

  1. Introduction (1)
    1. Introduction and Demo

      Let's begin with a demo of the final voting app you'll building in this series, as well as a quick overview of its potential future features.
  2. Implement the Design (7)
    1. Initial Setup and Design

      We'll start by installing Laravel Breeze to handle the authentication layer. We'll also, in the process, install Tailwind and Alpine, and then set up our layouts and basic navigation.
    2. Idea Cards

      Let's work on implementing the design of the idea cards on the main page of the app.
    3. The "Add Idea" Form

      We'll next work on the design of the form that allows users to create and submit new ideas.
    4. The Idea Page

      Next, we can implement the design of the single idea page, which includes a section for comments.
    5. Set Status Dialog

      Let's now work on the design for the "set status" and "post comment" dialogs.
    6. Toggle Visibility with Alpine

      In this lesson, I'll show you how to toggle the visibility of a menus using Alpine.js. It's really simple!
    7. Make it Responsive

      Let's now finish up the design section of this series by making our layout responsive.
  3. Viewing Ideas (6)
    1. Idea Model and Migrations

      Let's begin this new chapter by setting up our Idea model and database migrations. After that, we'll make the index and show pages dynamic by pulling the relevant data from the database.
    2. Testing: Showing Ideas

      Let’s be sure to prepare a series of tests that ensure that showing ideas works on our index and show pages.
    3. Clicking the Idea Box

      Let's work on the ability to click the entire idea box and make it function like a link. Sure, it's a small feature, but you'll often find yourself working on little things like this.
    4. Gravatar Images

      In this episode, we add Gravatar images for our users with defaults - similar to what you'll find on the Laracasts forum. Of course, we'll also write a series of tests for this new functionality.
    5. Add Categories

      We'll now add categories and a corresponding relationship for each idea. We make sure it works in the browser, and then update our current tests.
    6. Add Statuses

      Next up, let's add statuses and a corresponding relationship for each idea. We'll also take a look at a few approaches for adding the corresponding classes with each status.
  4. Creating Ideas (2)
    1. Creating Ideas

      Let's make a Livewire component that handles the process of submitting new ideas. We'll also ensure that success and validation messages are displayed in response.
    2. Testing: Creating Ideas

      With the initial code implemented, let's fill it in with a test to prove that it works the way we expect.
  5. Voting for Ideas (6)
    1. Voting Database Structure

      We can finally work on the core functionality of voting for ideas. In this episode, we'll set up our database table to store votes on ideas, set up the relationship between our models, and display the votes count on both the index and show pages.
    2. Testing: Votes Count

      Again, let's be sure to write tests for this new votes count functionality.
    3. Did the Current User Vote for the Idea

      Let's continue the voting functionality and add some logic to check if a given idea was voted for by the logged-in user. We'll reach for subqueries to ensure that our queries are optimized and not at risk of the "n+1" issue.
    4. Voting for Ideas

      We can now tackle the actual voting functionality that allows a user to vote for any idea.
    5. The Back Button Bug When Voting

      In this episode, we discover and fix a bug that throws off our state in Livewire when using the back button in the browser.
    6. Alternative Implementations for Voting

      Next up, we'll discuss a few alternative ways of implementing the voting feature in our application.
  6. Filtering Ideas (9)
    1. Make a Livewire Component to Fetch Ideas

      Before we work on filtering, let's do some refactoring and move the logic for fetching ideas into a dedicated Livewire component.
    2. Status Filters

      Let's now work on the status filters to allow users the ability to filter all submitted ideas based on their associated status.
    3. Status Filters Count

      In this video, we'll add the ability to count our ideas based on their status.
    4. Status Filters Tests

      Let's be sure to write a few tests which ensure that the status filters are working as expected.
    5. Category Filters

      Let's work on the category filters and do some refactoring in order to manage the query string within one component.
    6. Testing Category Filters

      Before moving on, let's be sure to properly test our category filters component.
    7. Other Filters

      In this lesson, we'll work on some other filters: one for showing the top-voted ideas, and another for showing the ideas specifically for the logged-in user. As always, we'll include a set of tests,
    8. Search Filter

      Let's now work and test a filter that searches for ideas based on the title.
    9. In-App Back Button

      Next up, we'll add a minor, but useful and convenient UX addition to the site: an in-app back button.
  7. Admin Set Status (4)
    1. Set the Idea Status

      In this next section, we'll add the ability for users administers to set the status of an idea.
    2. Set Status Test

      As always, we should write some tests to prove that this new feature works as expected.
    3. Notify All Voters

      Next, we should add the ability to notify all voters (via email) when the status for an idea has changed.
    4. Notify All Voters Test

      In this lesson, we will test the "notify all voters" feature - and also make use of Horizon for our queues.
  8. Refactoring Tests (1)
    1. Refactoring Tests

      Let's go back and clean up our tests to utilize factories and factory states more efficiently.
  9. Editing Ideas (9)
    1. Modal CSS

      Let's begin this new chapter by working to allow users to edit an idea. We'll use Tailwind to make this as quick and easy as possible.
    2. Modal Toggle and Transitions

      In this episode, we'll leverage Alpine.js to toggle the modal and add the necessary transitions.
    3. Edit Policies

      In this episode, we'll work on actually editing the idea using Livewire. We can also take care of policy-based authorization.
    4. Edit Idea Tests

      As always, we can't forget to write a series of tests to ensure that editing works as expected.
    5. Delete an Idea

      Next, we'll add the ability to delete ideas, while making use of Tailwind UI’s modal component in the process.
    6. Delete an Idea Tests

      As always, we'll take some time ensure that our "Delete Idea" feature is working as expected.
    7. Manage Spam

      Next up we'll add some spam management features, such as marking an idea as spam, a spam filter, a spam counter for admins, and resetting spam counts for ideas.
    8. Manage Spam Tests

      Once again, we'll write some tests for our spam management features.
    9. Refactoring Modals

      Let's take some time to refactor our modals into a Blade component. This should help remove all of our repeated code.
  10. Success Message Notifications (2)
    1. Success Message CSS

      Let’s work on the success message notifications - specifically, their styling and transitions using Tailwind and Alpine.
    2. Success Message Notification

      Let's now wire up our notification with the actions in our application.
  11. Comments (11)
    1. Comment Model and Migration

      We get started on the comments feature that allows users to discuss an idea. We create our models and migrations and render the comments on the idea page.
    2. Add Comments

      Continuing on, we work on allowing the user to add comments to the idea.
    3. Comments UX

      Let's add a few small UX features, such as scrolling to a comment after it was added and giving it a subtle background color.
    4. Comments Pagination

      Next up, we'll work on allowing comments to be paginated in order to optimize any potential performance issues.
    5. Showing and Adding Comments Tests

      As we've done several times before, in this episode we'll take some time to write tests for showing and adding comments.
    6. Edit Comments

      Moving on, we add the ability to allow users to edit their comments.
    7. Delete Comments

      Okay, next we should ensure that a user can delete their own comments.
    8. Edit and Delete Comments Test

      Now that we've implemented the functionality to delete a comment, let's write a set of tests to ensure that it works as expected.
    9. Comment Spam Management

      In this episode, we'll add the ability to mark a comment as spam and reset the spam counter if we are logged in as an administrator.
    10. Admin Set Status Comment Part 1

      Let's revisit the "Set Status" component and allow admins to add a comment when setting a status on the idea. In this first part, we integrate the CSS and make changes to our models and migrations.
    11. Admin Set Status Comment Part 2

      In this second part, we'll implement the ability to add a comment. We'll also update our tests.
  12. Notifications (6)
    1. Notification Styling

      Let's change gears and get started on a feature that displays a user notifications if anyone has commented on their ideas. For this episode, we'll take care of the general styling.
    2. View Notifications

      In this lesson, we'll make use of notifications in Laravel. We'll reach for the database driver to store them in a dedicated notifications table. Finally, we'll finish by populating our dialog with the logged-in user's notifications.
    3. Badge Count

      Next, we'll add a badge count and skeleton loader for when notifications are being loaded.
    4. Mark Notifications as Read

      Let's allow the user to mark their notifications as "read." We'll additionally add a feature that visits the correct idea page and highlights the comment that was selected from our notifications dialog.
    5. Notification Polling

      Let's leverage Livewire's polling ability to automatically refresh our component to check for new notifications.
    6. Notification Tests

      Now we can finish up this particular feature by writing a series of tests to confirm it works properly.
  13. Wrapping Up (3)
    1. Auth Redirects

      Let's now work on redirecting newly signed in users to the page that they were on previously.
    2. Small Fixes

      As we near the end of this series, let's work through a list of minor fixes and updates, including making use of Tailwind’s JIT compiler and updating our database schema to includes cascades.
    3. Conclusion

      In this final episode, we wrap up the series with some discussion of potential features for the app that you're to explore on your own. Thanks so much for watching!

Continue Learning