Skip to content

Commit

Permalink
📝 Add a Livewire example
Browse files Browse the repository at this point in the history
  • Loading branch information
Log1x committed Feb 9, 2024
1 parent a897ee0 commit d369d20
Show file tree
Hide file tree
Showing 2 changed files with 261 additions and 0 deletions.
261 changes: 261 additions & 0 deletions content/docs/livewire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
---
slug: livewire
title: 'Livewire'
description: "Laracord's HTTP server includes support for Laravel Livewire making simple web admin interfaces for your bot a breeze."
priority: 1
group: Examples
---

Laracord's HTTP server while implementing Laravel's routing also brings in the necessary requirements for Livewire.

While Laracord has not been thoroughly tested with everything Livewire has to offer, it has been tested with full page components and can be a very quick and powerful way to create a basic web interface to interact with your bot instance in real-time without Javascript.

> #### Note
>
> While this provides a great way to easily manage a personal bot, it is **strongly discouraged** to use the Laracord HTTP server to host any kind of user-facing application.
In this example, we will install Livewire and create a simple **Message component** that is capable of showing every user visible to the bot in a select dropdown and firing off a message using the bot instance when clicking send.

## Install Livewire

Start by installing Livewire using Composer:

```sh
$ composer require livewire/livewire
```

Once installed, you will need to generate an application key (`APP_KEY`) using the `laracord` binary:

```sh
$ php laracord key:generate
```

The final step is to add the Livewire service provider to `providers` in `config/app.php`:

```php
'providers' => [
App\Providers\BotServiceProvider::class,
Livewire\LivewireServiceProvider::class,
],
```

## Creating a Layout

Before creating a component, you will need to create an `app.blade.php` layout for Livewire to use. You can create this using `livewire:layout`:

```sh
$ php laracord livewire:layout
```

Once `app.blade.php` has been created, you will need to add the `@livewireStyles` and `@livewireScripts` Blade directives to the layout.

Here is a full example including Tailwind's CDN since Laracord does not use node out of the box:

```php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title ?? 'Laracord' }}</title>

<script src="https://cdn.tailwindcss.com"></script>
@livewireStyles
</head>
<body>
{{ $slot }}
@livewireScripts
</body>
</html>
```

## Message Component

For this example, we will create a simple full page component. We can start by using the `make:livewire` console command:

```sh
$ php laracord make:livewire Message
```

### Creating a Route

After the component is created, we can create a route for it in `app/Bot.php`:

```php
<?php

namespace App;

use App\Livewire\Message;
use Illuminate\Support\Facades\Route;
use Laracord\Laracord;

class Bot extends Laracord
{
/**
* The HTTP routes.
*/
public function routes(): void
{
Route::middleware('auth')->group(function () {
Route::get('/message', Message::class);
});
}
}
```

> #### Note
>
> It is strongly recommended to put routes behind the **auth** middleware if the bot is publicly accessible. See [HTTP Server Security](/docs/http-server#content-security) to learn more.
### Creating the Component

Once our route is configured, we can switch over to the Message component that was generated by `make:livewire` and add in the logic for the component:

```php
<?php

namespace App\Livewire;

use Laracord\HasLaracord;
use Livewire\Attributes\Locked;
use Livewire\Component;

class Message extends Component
{
use HasLaracord;

/**
* The selected user.
*
* @var string
*/
public $user;

/**
* The message to send.
*
* @var string
*/
public $message;

/**
* The Discord users.
*
* @var array
*/
#[Locked]
public $members;

/**
* Render the component.
*
* @return \Illuminate\View\View
*/
public function render()
{
$this->members = collect($this->discord()->users->map(fn ($user) => [
'id' => $user->id,
'username' => $user->username,
]))->keyBy('id');

return view('livewire.message');
}

/**
* Send a message to the selected user.
*
* @return void
*/
public function sendMessage()
{
$this->validate([
'user' => 'required',
'message' => 'required|min:3|max:150',
]);

if (! $this->members->has($this->user)) {
$this->addError('user', 'The selected user does not exist.');

return;
}

$this
->message($this->message)
->sendTo($this->user);

$this->reset('message');

session()->flash('success', 'The message has been sent.');
}
}
```

Thanks to the `WithLaracord` trait, the methods we are used to using when writing commands are available in the Livewire component such as `bot()`, `discord()`, `console()`, and `message()`.

Let's break down the above component. To start, we create our properties:

- A **$user** property to wire to our **user** select.
- A **$message** property to wire to our **message** textarea.
- A [locked](https://livewire.laravel.com/docs/locked) **$members** property to hold the array of user's in the bot repository.

In the `render()` method, we set our `members` property by mapping the Discord users by `id` and `username` and then keying them by `id`. Keying them by `id` will be convenient for validation.

In the `sendMessage()` method, we start by using basic Laravel validation to check that the `user` and `message` are filled out and the `message` meets a generic minimum/maximum length.

Once `validate()` passes, we do our own quick validation to ensure that the user attempting to be messaged is in the users list and hasn't been tampered with.

Once validation is complete, we can send the message using the `message()` method similar to how we would in a command, reset the `message` textarea, and flash a `success` message.

### Creating a View

The component view is located in `resources/views/livewire/message.blade.php` and will be composed of a simple select dropdown, a textarea, and a send message button. I won't go into specifics for this one:

```php
<div class="max-w-2xl p-8 mx-auto">
<h1 class="mb-6 text-3xl">Send a Message</h1>

<div class="grid gap-8">
<div>
<select wire:model="user" class="w-full px-3 py-2 border">
<option value="">Select a member...</option>
@foreach ($members as $member)
<option value="{{ $member['id'] }}">{{ $member['username'] }}</option>
@endforeach
</select>

@error('user')
<div class="mt-1 text-red-500">{{ $message }}</div>
@enderror
</div>

<div>
<textarea
class="w-full px-3 py-2 border"
wire:model="message"
rows="5"
placeholder="Enter a message..."
></textarea>

@error('message')
<div class="mt-1 text-red-500">{{ $message }}</div>
@enderror
</div>

<button class="px-4 py-2 text-white bg-blue-500" wire:click="sendMessage">
Send Message
</button>

@session('success')
<div class="px-4 py-3 text-green-700 bg-green-100 rounded">
<b>Success</b>
<p>{{ session('success') }}</p>
</div>
@endsession
</div>
</div>
```

Once your component is created, it should be ready and accessible at `localhost:8080/messages` by default once booting your bot.

![Screenshot](/images/livewire-example.png)
Binary file added public/images/livewire-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d369d20

Please sign in to comment.