mailwolt/app/Livewire/Ui/Webmail/Inbox.php

247 lines
7.6 KiB
PHP

<?php
namespace App\Livewire\Ui\Webmail;
use App\Services\ImapService;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
#[Layout('layouts.webmail')]
#[Title('Posteingang · Webmail')]
class Inbox extends Component
{
#[Url(as: 'folder')]
public string $folder = 'INBOX';
#[Url(as: 'page')]
public int $page = 1;
#[Url(as: 'tab')]
public string $tab = 'all';
public array $messages = [];
public array $categories = [];
public int $total = 0;
public array $folders = [];
public int $perPage = 25;
public string $search = '';
public array $searchResults = [];
public bool $searching = false;
public function mount(): void
{
if (! session('webmail_email')) {
$this->redirect(route('ui.webmail.login'));
return;
}
$this->load();
}
public function load(): void
{
try {
$imap = app(ImapService::class);
$client = $imap->client(
session('webmail_email'),
session('webmail_password'),
);
$this->folders = $imap->folders($client);
if ($this->folder === '_starred') {
$result = $imap->starredMessages($client, $this->page, $this->perPage);
} else {
$result = $imap->messages($client, $this->folder, $this->page, $this->perPage);
}
$this->total = $result['total'];
$this->messages = in_array($this->folder, ['INBOX', '_starred'])
? array_map(fn($m) => array_merge($m, ['category' => $this->getCategory($m)]), $result['messages'])
: $result['messages'];
$this->categories = [];
$client->disconnect();
} catch (\Throwable) {
session()->forget(['webmail_email', 'webmail_password']);
$this->redirect(route('ui.webmail.login'));
}
}
private function getCategory(array $msg): string
{
$from = strtolower($msg['from'] ?? '');
foreach (['facebook','twitter','instagram','linkedin','tiktok','youtube','pinterest','reddit','snapchat','xing','mastodon'] as $kw) {
if (str_contains($from, $kw)) return 'social';
}
foreach (['newsletter','noreply','no-reply','no_reply','marketing','mailer','mailchimp','sendgrid','campaign','promo','offers','deals'] as $kw) {
if (str_contains($from, $kw)) return 'promo';
}
return 'general';
}
public function updatedSearch(string $value): void
{
if (mb_strlen(trim($value)) < 2) {
$this->searchResults = [];
$this->searching = false;
return;
}
$this->searching = true;
try {
$imap = app(ImapService::class);
$client = $imap->client(session('webmail_email'), session('webmail_password'));
$searchFolder = $this->folder === '_starred' ? 'INBOX' : $this->folder;
$this->searchResults = $imap->searchMessages($client, $searchFolder, trim($value));
$client->disconnect();
} catch (\Throwable) {
$this->searchResults = [];
}
$this->searching = false;
}
public function clearSearch(): void
{
$this->search = '';
$this->searchResults = [];
}
public function switchTab(string $tab): void
{
$allowed = ['all', 'general', 'promo', 'social'];
$this->tab = in_array($tab, $allowed, true) ? $tab : 'all';
}
public function switchFolder(string $folder): void
{
$this->folder = $folder;
$this->page = 1;
$this->tab = 'all';
$this->load();
}
public function nextPage(): void
{
if ($this->page * $this->perPage < $this->total) {
$this->page++;
$this->load();
}
}
public function prevPage(): void
{
if ($this->page > 1) {
$this->page--;
$this->load();
}
}
public function toggleFlag(int $uid): void
{
try {
$imap = app(ImapService::class);
$client = $imap->client(session('webmail_email'), session('webmail_password'));
$imap->toggleFlag($client, $this->folder, $uid);
$client->disconnect();
} catch (\Throwable) {}
$this->load();
}
public function deleteDraft(int $uid): void
{
try {
$imap = app(ImapService::class);
$client = $imap->client(session('webmail_email'), session('webmail_password'));
$imap->deleteMessage($client, 'Drafts', $uid);
$client->disconnect();
} catch (\Throwable) {}
$this->load();
}
public function bulkMarkUnseen(array $uids): void
{
try {
$imap = app(ImapService::class);
$client = $imap->client(session('webmail_email'), session('webmail_password'));
foreach ($uids as $uid) {
$imap->markUnseen($client, $this->folder, (int) $uid);
}
$client->disconnect();
} catch (\Throwable) {}
$this->load();
}
public function bulkMarkSeen(array $uids): void
{
try {
$imap = app(ImapService::class);
$client = $imap->client(session('webmail_email'), session('webmail_password'));
foreach ($uids as $uid) {
$imap->markSeen($client, $this->folder, (int) $uid);
}
$client->disconnect();
} catch (\Throwable) {}
$this->load();
}
public function bulkMoveTo(array $uids, string $target): void
{
$allowed = ['INBOX', 'Sent', 'Archive', 'Junk', 'Trash'];
if (! in_array($target, $allowed, true) || $target === $this->folder) return;
try {
$imap = app(ImapService::class);
$client = $imap->client(session('webmail_email'), session('webmail_password'));
foreach ($uids as $uid) {
$imap->moveMessage($client, $this->folder, (int) $uid, $target);
}
$client->disconnect();
} catch (\Throwable) {}
$this->load();
}
public function bulkDelete(array $uids): void
{
try {
$imap = app(ImapService::class);
$client = $imap->client(session('webmail_email'), session('webmail_password'));
foreach ($uids as $uid) {
if ($this->folder === 'Trash') {
$imap->deleteMessage($client, $this->folder, (int) $uid);
} else {
$imap->moveMessage($client, $this->folder, (int) $uid, 'Trash');
}
}
$client->disconnect();
} catch (\Throwable) {}
$this->load();
}
public function emptyTrash(): void
{
try {
$imap = app(ImapService::class);
$client = $imap->client(session('webmail_email'), session('webmail_password'));
$folder = $client->getFolder('Trash');
foreach ($folder->query()->all()->get() as $msg) {
$msg->delete(false);
}
$folder->expunge();
$client->disconnect();
} catch (\Throwable) {}
$this->load();
}
public function logout(): void
{
session()->forget(['webmail_email', 'webmail_password']);
$this->redirect(route('ui.webmail.login'));
}
public function render()
{
return view('livewire.ui.webmail.inbox');
}
}