added not subscribed page, added premium inbox

This commit is contained in:
Gitea
2025-05-06 07:21:39 +05:30
parent 86e452deac
commit 671cb6212d
12 changed files with 603 additions and 22 deletions

View File

@@ -49,6 +49,14 @@ class AppController extends Controller
} }
} }
public function switchP($email) {
Premium::setEmailP($email);
if (json_decode(config('app.settings.configuration_settings'))->disable_mailbox_slug) {
return redirect()->route('dashboard');
}
return redirect()->route('dashboard.premium');
}
public function deleteP($email = null) { public function deleteP($email = null) {
if ($email) { if ($email) {
$emails = Premium::getEmails(); $emails = Premium::getEmails();

View File

@@ -2,12 +2,14 @@
namespace App\Livewire\Dashboard; namespace App\Livewire\Dashboard;
use App\Models\UsageLog;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Livewire\Component; use Livewire\Component;
class Dashboard extends Component class Dashboard extends Component
{ {
public $message; public $message;
public $usageLog;
public $subscription; public $subscription;
public $plans; public $plans;
@@ -61,7 +63,11 @@ class Dashboard extends Component
} }
} }
$usageLog = UsageLog::where('user_id', auth()->user()->id)->first();
$this->usageLog = [
'emails_created_count' => $usageLog->emails_created_count ?? 0,
'emails_received_count' => $usageLog->emails_received_count ?? 0,
];
} }
public function render() public function render()

View File

@@ -5,15 +5,18 @@ namespace App\Livewire\Dashboard\Mailbox;
use App\ColorPicker; use App\ColorPicker;
use App\Models\Log; use App\Models\Log;
use App\Models\Premium; use App\Models\Premium;
use App\Models\PremiumEmail;
use App\Models\UsageLog;
use Artisan;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cookie; use Illuminate\Support\Facades\Cookie;
use Livewire\Component; use Livewire\Component;
use Session;
class Inbox extends Component class Inbox extends Component
{ {
use ColorPicker; use ColorPicker;
public $messages = []; public $messages = [];
public $deleted = []; public $deleted = [];
public $error = ''; public $error = '';
@@ -24,8 +27,11 @@ class Inbox extends Component
public $messageId; public $messageId;
public $list = false; public $list = false;
public $emails; public $emails;
public $mailboxHistory;
public $emailsHistory;
public $username, $domain, $domains, $action; public $username, $domain, $domains, $action;
public $email_limit = 20; public $email_limit = 20;
private $isSubscribed;
protected $listeners = ['updateEmail' => 'syncEmail', 'getEmail' => 'generateEmail', 'fetchMessages' => 'fetch', 'setMessageId' => 'setMessageId']; protected $listeners = ['updateEmail' => 'syncEmail', 'getEmail' => 'generateEmail', 'fetchMessages' => 'fetch', 'setMessageId' => 'setMessageId'];
@@ -38,8 +44,11 @@ class Inbox extends Component
$this->initial = false; $this->initial = false;
$this->checkMultipleEmails(); $this->checkMultipleEmails();
$this->validateDomainInEmail(); $this->validateDomainInEmail();
$this->emailsHistory = array_reverse(PremiumEmail::parseEmail(\auth()->user()->id)['data']) ?? [];
if(auth()->user()->subscribedToProduct(config('app.plans')[0]['product_id'])) { $subscriptionCheck = auth()->user()->subscribedToProduct(config('app.plans')[0]['product_id']);
Session::put('isSubscribed', $subscriptionCheck);
if($subscriptionCheck) {
try { try {
$result = auth()->user()->subscriptions()->where(['stripe_status' => 'active'])->orderByDesc('updated_at')->first(); $result = auth()->user()->subscriptions()->where(['stripe_status' => 'active'])->orderByDesc('updated_at')->first();
$userPriceID = $result['items'][0]['stripe_price']; $userPriceID = $result['items'][0]['stripe_price'];
@@ -57,6 +66,9 @@ class Inbox extends Component
\Log::error($e->getMessage()); \Log::error($e->getMessage());
} }
} }
$mailboxHistory = UsageLog::where(['user_id' => auth()->user()->id])->first();
$this->mailboxHistory = $mailboxHistory->emails_created_history ?? [];
} }
private function checkMultipleEmails(): void private function checkMultipleEmails(): void
@@ -73,7 +85,22 @@ class Inbox extends Component
public function switchEmail($email) public function switchEmail($email)
{ {
return redirect()->route('switch', ['email' => $email]); try {
if ($email != null) {
$data = explode('@', $email);
if (isset($data[1])) {
$domain = $data[1];
$domains = json_decode(config('app.settings.configuration_settings'))->premium_domains ?? [];
if (!in_array($domain, $domains)) {
return $this->showAlert('error', __('This mailbox can not be recovered.'));
}
}
}
} catch (\Exception $exception) {
\Log::error($exception->getMessage());
}
return redirect()->route('switchP', ['email' => $email]);
} }
public function syncEmail(): void public function syncEmail(): void
@@ -183,19 +210,25 @@ class Inbox extends Component
private function validateDomainInEmail(): void private function validateDomainInEmail(): void
{ {
$data = explode('@', $this->email); try {
if (isset($data[1])) { if ($this->email != null) {
$domain = $data[1]; $data = explode('@', $this->email);
$domains = json_decode(config('app.settings.configuration_settings'))->premium_domains ?? []; if (isset($data[1])) {
if (!in_array($domain, $domains)) { $domain = $data[1];
$key = array_search($this->email, $this->emails); $domains = json_decode(config('app.settings.configuration_settings'))->premium_domains ?? [];
Premium::removeEmail($this->email); if (!in_array($domain, $domains)) {
if ($key == 0 && count($this->emails) == 1 && json_decode(config('app.settings.configuration_settings'))->after_last_email_delete == 'redirect_to_homepage') { $key = array_search($this->email, $this->emails);
redirect()->route('dashboard.premium'); Premium::removeEmail($this->email);
} else { if ($key == 0 && count($this->emails) == 1 && json_decode(config('app.settings.configuration_settings'))->after_last_email_delete == 'redirect_to_homepage') {
redirect()->route('dashboard.premium'); redirect()->route('dashboard.premium');
} else {
redirect()->route('dashboard.premium');
}
}
} }
} }
} catch (\Exception $exception) {
\Log::error($exception->getMessage());
} }
} }
@@ -241,6 +274,15 @@ class Inbox extends Component
$this->dispatch('showNewMailNotification', $notification); $this->dispatch('showNewMailNotification', $notification);
} }
Premium::incrementMessagesStats(count($notifications)); Premium::incrementMessagesStats(count($notifications));
if ($this->email != null && count($this->messages) > 0) {
foreach ($this->messages as $message) {
PremiumEmail::createEmail($message, $this->email);
}
}
$this->emailsHistory = array_reverse(PremiumEmail::parseEmail(\auth()->user()->id)['data']) ?? [];
} catch (\Exception $e) { } catch (\Exception $e) {
if (Auth::check() && Auth::user()->level == 9) { if (Auth::check() && Auth::user()->level == 9) {
$this->error = $e->getMessage(); $this->error = $e->getMessage();
@@ -252,6 +294,17 @@ class Inbox extends Component
$this->initial = true; $this->initial = true;
} }
public function processQueue(): void
{
try {
Artisan::call('queue:work', [
'--once' => true,
]);
} catch (\Exception $exception) {
\Log::error($exception->getMessage());
}
}
public function delete($messageId) { public function delete($messageId) {
try { try {
@@ -274,7 +327,11 @@ class Inbox extends Component
public function render() public function render()
{ {
return view('livewire.dashboard.mailbox.inbox')->layout('components.layouts.dashboard'); if (Session::get('isSubscribed')) {
return view('livewire.dashboard.mailbox.inbox')->layout('components.layouts.dashboard');
} else {
return view('livewire.dashboard.not-subscribed')->layout('components.layouts.dashboard');
}
} }
private function rrmdir($dir): void private function rrmdir($dir): void

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Livewire\Dashboard;
use Livewire\Component;
class NotSubscribed extends Component
{
public function render()
{
return view('livewire.dashboard.not-subscribed')->layout('components.layouts.dashboard');
}
}

View File

@@ -35,6 +35,12 @@ class Premium extends Model
public static function fetchMessages($email, $type = 'to', $deleted = []): array public static function fetchMessages($email, $type = 'to', $deleted = []): array
{ {
if ($email == null) {
return [
"data" => [],
"notifications" => []
];
}
$allowed = explode(',', 'doc,docx,xls,xlsx,ppt,pptx,xps,pdf,dxf,ai,psd,eps,ps,svg,ttf,zip,rar,tar,gzip,mp3,mpeg,wav,ogg,jpeg,jpg,png,gif,bmp,tif,webm,mpeg4,3gpp,mov,avi,mpegs,wmv,flx,txt'); $allowed = explode(',', 'doc,docx,xls,xlsx,ppt,pptx,xps,pdf,dxf,ai,psd,eps,ps,svg,ttf,zip,rar,tar,gzip,mp3,mpeg,wav,ogg,jpeg,jpg,png,gif,bmp,tif,webm,mpeg4,3gpp,mov,avi,mpegs,wmv,flx,txt');
$connection = self::connectMailBox(); $connection = self::connectMailBox();
@@ -91,6 +97,7 @@ class Premium extends Model
$obj['date'] = $date->format(json_decode(config('app.settings.configuration_settings'))->date_format ?? 'd M Y h:i A'); $obj['date'] = $date->format(json_decode(config('app.settings.configuration_settings'))->date_format ?? 'd M Y h:i A');
$obj['datediff'] = $datediff->diffForHumans(); $obj['datediff'] = $datediff->diffForHumans();
$obj['id'] = $message->getNumber(); $obj['id'] = $message->getNumber();
$obj['size'] = $message->getSize();
$obj['content'] = $content; $obj['content'] = $content;
$obj['contentText'] = $contentText; $obj['contentText'] = $contentText;
$obj['attachments'] = []; $obj['attachments'] = [];
@@ -191,6 +198,15 @@ class Premium extends Model
Cookie::queue('email', $email, 43800); Cookie::queue('email', $email, 43800);
} }
} }
public static function setEmailP($email): void
{
$usageLogs = UsageLog::where(['user_id' => auth()->user()->id])->first();
$emails = $usageLogs->emails_created_history;
if (is_array($emails) && in_array($email, $emails)) {
Cookie::queue('email', $email, 43800);
}
}
public static function removeEmail($email): void public static function removeEmail($email): void
{ {
$emails = self::getEmails(); $emails = self::getEmails();
@@ -287,14 +303,14 @@ class Premium extends Model
if ($domain == "gmail.com") { if ($domain == "gmail.com") {
$rd = mt_rand(0,1); $rd = mt_rand(0,1);
if ($rd == 0) { if ($rd == 0) {
$email = $zemail->generateRandomGmail(); $email = $zemail->generateRandomGmail(false);
} else { } else {
$email = $zemail->getRandomGmailUser().'+'.$zemail->generateRandomUsername().'@gmail.com'; $email = $zemail->getRandomGmailUser().'+'.$zemail->generateRandomUsername().'@gmail.com';
} }
} elseif ($domain == "googlemail.com") { } elseif ($domain == "googlemail.com") {
$rd = mt_rand(0,1); $rd = mt_rand(0,1);
if ($rd == 0) { if ($rd == 0) {
$email = $zemail->generateRandomGmail(); $email = $zemail->generateRandomGmail(false);
} else { } else {
$email = $zemail->getRandomGmailUser().'+'.$zemail->generateRandomUsername().'@googlemail.com'; $email = $zemail->getRandomGmailUser().'+'.$zemail->generateRandomUsername().'@googlemail.com';
} }

160
app/Models/PremiumEmail.php Normal file
View File

@@ -0,0 +1,160 @@
<?php
namespace App\Models;
use App\ColorPicker;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Validator;
class PremiumEmail extends Model
{
use ColorPicker;
protected $fillable = [
'user_id',
'message_id',
'subject',
'from_name',
'from_email',
'to',
'cc',
'bcc',
'timestamp',
'body_text',
'body_html',
'is_seen',
'is_flagged',
'size',
'mailbox',
'raw_headers',
'raw_body',
'attachments',
];
protected $casts = [
'to' => 'array',
'cc' => 'array',
'bcc' => 'array',
'attachments' => 'array',
'timestamp' => 'datetime'
];
public static function createEmail($message, $email): void
{
$initialData = $message;
$utcTime = CarbonImmutable::instance($message['timestamp'])->setTimezone('UTC')->toDateTimeString();
$messageId = Carbon::parse($utcTime)->format('Ymd').$initialData['id'];
$userId = \auth()->user()->id;
$exists = PremiumEmail::where('user_id', $userId)->where('message_id', $messageId)->exists();
$data = [
'user_id' => $userId,
'message_id' => $messageId,
'subject' => $initialData['subject'],
'from_name' => $initialData['sender_name'],
'from_email' => $initialData['sender_email'],
'to' => ["$email"],
'cc' => [],
'bcc' => [],
'timestamp' => $utcTime,
'body_text' => $initialData['contentText'],
'body_html' => $initialData['content'],
'is_seen' => true,
'is_flagged' => false,
'size' => $initialData['size'],
'mailbox' => 'INBOX',
'raw_headers' => null,
'raw_body' => null,
'attachments' => $initialData['attachments'],
];
if (!$exists) {
PremiumEmail::create($data);
}
}
public static function fetchEmailFromDB($userId) {
$validator = Validator::make(['user_id' => $userId], [
'user_id' => 'required|integer'
]);
if ($validator->fails()) {
return [];
}
return self::whereJsonContains('user_id', $userId)->orderBy('timestamp', 'desc')->get();
}
public static function parseEmail($userId, $deleted = []): array
{
$messages = self::fetchEmailFromDB($userId);
$limit = 50;
$count = 1;
$response = [
'data' => [],
'notifications' => []
];
foreach ($messages as $message) {
if (in_array($message['message_id'], $deleted)) {
// If it exists, delete the matching record from the 'emails' table
Email::where('message_id', $message['message_id'])->delete();
continue;
}
$blocked = false;
$timestamp = $message['timestamp'];
$carbonTimestamp = Carbon::parse($timestamp, 'UTC');
$obj = [];
$obj['subject'] = $message['subject'];
$obj['to'] = $message['to'];
$obj['sender_name'] = $message['from_name'];
$obj['sender_email'] = $message['from_email'];
$obj['timestamp'] = $message['timestamp'];
$obj['date'] = $carbonTimestamp->format('d M Y h:i A');
$obj['datediff'] = $carbonTimestamp->diffForHumans(Carbon::now('UTC'));
$obj['id'] = $message['message_id'];
$obj['content'] = $message['body_html'];
$obj['contentText'] = $message['body_text'];
$obj['attachments'] = [];
$obj['is_seen'] = $message['is_seen'];
$obj['sender_photo'] = self::chooseColor(strtoupper(substr($message['from_name'] ?: $message['from_email'], 0, 1) ));
$domain = explode('@', $obj['sender_email'])[1];
$blocked = in_array($domain, json_decode(config('app.settings.configuration_settings'))->blocked_domains);
if ($blocked) {
$obj['subject'] = __('Blocked');
$obj['content'] = __('Emails from') . ' ' . $domain . ' ' . __('are blocked by Admin');
$obj['contentText'] = __('Emails from') . ' ' . $domain . ' ' . __('are blocked by Admin');
}
if (count($message['attachments']) > 0 && !$blocked) {
$obj['attachments'] = $message['attachments'];
}
$response['data'][] = $obj;
if (!$message['is_seen']) {
$response['notifications'][] = [
'subject' => $obj['subject'],
'sender_name' => $obj['sender_name'],
'sender_email' => $obj['sender_email']
];
if (config('app.zemail_log')) {
file_put_contents(storage_path('logs/zemail.csv'), request()->ip() . "," . date("Y-m-d h:i:s a") . "," . $obj['sender_email'] . "," . $email . PHP_EOL, FILE_APPEND);
}
}
PremiumEmail::where('message_id', $message['message_id'])->update(['is_seen' => true]);
if (++$count > $limit) {
break;
}
}
return $response;
}
}

View File

@@ -0,0 +1,47 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('premium_emails', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('message_id')->unique()->index();
$table->string('subject')->nullable();
$table->string('from_name')->nullable();
$table->string('from_email');
$table->text('to');
$table->text('cc')->nullable();
$table->text('bcc')->nullable();
$table->dateTime('timestamp')->nullable();
$table->longText('body_text')->nullable();
$table->longText('body_html')->nullable();
$table->boolean('is_seen')->default(false);
$table->boolean('is_flagged')->default(false);
$table->unsignedBigInteger('size')->nullable();
$table->string('mailbox')->default('INBOX');
$table->longText('raw_headers')->nullable();
$table->longText('raw_body')->nullable();
$table->json('attachments')->nullable();
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('premium_emails');
}
};

View File

@@ -0,0 +1,43 @@
{{-- Credit: Lucide (https://lucide.dev) --}}
@props([
'variant' => 'outline',
])
@php
if ($variant === 'solid') {
throw new \Exception('The "solid" variant is not supported in Lucide.');
}
$classes = Flux::classes('shrink-0')
->add(match($variant) {
'outline' => '[:where(&)]:size-6',
'solid' => '[:where(&)]:size-6',
'mini' => '[:where(&)]:size-5',
'micro' => '[:where(&)]:size-4',
});
$strokeWidth = match ($variant) {
'outline' => 2,
'mini' => 2.25,
'micro' => 2.5,
};
@endphp
<svg
{{ $attributes->class($classes) }}
data-flux-icon
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="{{ $strokeWidth }}"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
data-slot="icon"
>
<circle cx="12" cy="16" r="1" />
<rect x="3" y="10" width="18" height="12" rx="2" />
<path d="M7 10V7a5 5 0 0 1 10 0v3" />
</svg>

View File

@@ -9,7 +9,7 @@
<flux:icon.at-sign /> <flux:icon.at-sign />
</span> </span>
<div> <div>
<p class="text-2xl font-medium text-gray-900 dark:text-white">0</p> <p class="text-2xl font-medium text-gray-900 dark:text-white">{{ $usageLog['emails_created_count'] }}</p>
<p class="text-sm text-gray-500 dark:text-gray-400">Mailbox Created</p> <p class="text-sm text-gray-500 dark:text-gray-400">Mailbox Created</p>
</div> </div>
</article> </article>
@@ -19,7 +19,7 @@
<flux:icon.mails /> <flux:icon.mails />
</span> </span>
<div> <div>
<p class="text-2xl font-medium text-gray-900 dark:text-white">0</p> <p class="text-2xl font-medium text-gray-900 dark:text-white">{{ $usageLog['emails_received_count'] }}</p>
<p class="text-sm text-gray-500 dark:text-gray-400">Emails Received</p> <p class="text-sm text-gray-500 dark:text-gray-400">Emails Received</p>
</div> </div>
</article> </article>

View File

@@ -55,8 +55,25 @@
</div> </div>
</div> </div>
<div x-data="{ currentTab: 0 }">
<div class="m-auto my-4 px-1 max-w-full max-lg:min-w-fit lg:max-w-96 flex justify-center">
<div class="w-full lg:px-12">
<ui-tabs class="block inline-flex p-1 rounded-lg bg-zinc-800/5 dark:bg-white/10 h-10 p-1 w-full" data-flux-tabs="" role="tablist">
<button type="button" x-on:click="currentTab = 0;" class="flex cursor-pointer whitespace-nowrap flex-1 justify-center items-center gap-2 rounded-md data-selected:shadow-xs text-sm font-medium text-zinc-600 hover:text-zinc-800 dark:hover:text-white dark:text-white/70 data-selected:text-zinc-800 dark:data-selected:text-white data-selected:bg-white dark:data-selected:bg-white/20 px-4" data-flux-tab="data-flux-tab" :data-selected="currentTab === 0 ? '' : null" role="tab">
Inbox
</button>
<button type="button" x-on:click="currentTab = 1;" class="flex cursor-pointer whitespace-nowrap flex-1 justify-center items-center gap-2 rounded-md data-selected:shadow-xs text-sm font-medium text-zinc-600 hover:text-zinc-800 dark:hover:text-white dark:text-white/70 data-selected:text-zinc-800 dark:data-selected:text-white data-selected:bg-white dark:data-selected:bg-white/20 px-4" data-flux-tab="data-flux-tab" :data-selected="currentTab === 1 ? '' : null" role="tab">
Mailbox
</button>
<button type="button" x-on:click="currentTab = 2;" class="flex cursor-pointer whitespace-nowrap flex-1 justify-center items-center gap-2 rounded-md data-selected:shadow-xs text-sm font-medium text-zinc-600 hover:text-zinc-800 dark:hover:text-white dark:text-white/70 data-selected:text-zinc-800 dark:data-selected:text-white data-selected:bg-white dark:data-selected:bg-white/20 px-4" data-flux-tab="data-flux-tab" :data-selected="currentTab === 2 ? '' : null" role="tab">
Email
</button>
</ui-tabs>
</div>
</div>
@if($email !== null) @if($email !== null)
<div class="mt-8 rounded-xl border dark:border-white/[0.1] border-black/[0.3]"> <div class="rounded-xl border dark:border-white/[0.1] border-black/[0.3]" x-show="currentTab === 0">
<div class="mt-4 w-full text-center"> <div class="mt-4 w-full text-center">
<div class="flex flex-full flex-row"> <div class="flex flex-full flex-row">
<div class="w-1/3"><flux:button class="w-3/4 cursor-pointer" x-on:click="$dispatch('copyEmail')">Copy</flux:button></div> <div class="w-1/3"><flux:button class="w-3/4 cursor-pointer" x-on:click="$dispatch('copyEmail')">Copy</flux:button></div>
@@ -241,5 +258,195 @@
</div> </div>
</div> </div>
@endif @endif
</div>
<div class="rounded-xl border dark:border-white/[0.1] border-black/[0.3]" x-show="currentTab === 1">
<div class="w-full text-center">
<div class="p-2 block rounded-xl items-center">
<h2 class="pt-3 text-lg font-semibold mb-4 text-center text-black dark:text-white">Generated Mailbox Addresses</h2>
<!-- Responsive Email List -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-left px-2">
@foreach(array_reverse($mailboxHistory) as $email)
<div wire:click="switchEmail('{{ $email }}')" class="cursor-pointer bg-gray-200 dark:bg-zinc-700 rounded-lg p-4 text-sm text-black dark:text-white flex items-center justify-between">
<span class="truncate">{{ $email }}</span>
<span class="text-gray-500 dark:text-gray-300 text-base"><flux:icon.arrow-right-circle /></span>
</div>
@endforeach
</div>
</div>
</div>
</div>
<div class="rounded-xl border dark:border-white/[0.1] border-black/[0.3]" x-show="currentTab === 2">
<div class="w-full text-center">
<div class="p-2 block rounded-xl items-center">
<h2 class="pt-6 text-lg font-semibold mb-4 text-center text-black dark:text-white">Email History</h2>
<!-- Responsive Email List -->
<div class="w-full mt-4">
<div x-data="{ show: false, id: 0 }" class="mx-3">
@if($emailsHistory)
<div class="mailbox">
<div x-show="!show" class="list">
<div class="mb-3"></div>
@foreach(array_reverse($emailsHistory) as $i => $message)
<div class="inbox-list cursor-pointer" x-on:click="show = true; id = {{ $message['id'] }};" data-id="{{ $message['id'] }}">
<div class="block rounded-lg bg-white shadow-md dark:bg-zinc-700 text-left">
<div class="flex items-center px-4 py-4 sm:px-6">
<div class="flex flex-1 items-center min-w-0">
<div class="flex-shrink-0">
<span class="relative inline-block">
{{-- <img src="{{ asset('images/user.webp') }}" class="size-12" alt="inbox-logo" />--}}
<span class="{{ $message['sender_photo']['dark'] }} {{ $message['sender_photo']['light'] }} inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle size-11 text-[22px] transition">
<span id="sender-logo" class="font-medium leading-none text-gray-100 dark:text-gray-300 dark:group-hover:text-gray-200 group-hover:text-gray-700 truncate">{{ strtoupper(substr($message['sender_name'] ?: $message['sender_email'], 0, 1) ) }}</span>
</span>
@if(!$message['is_seen'])
<span class="shadow-solid absolute bottom-0 right-0 block w-3 h-3 dark:text-gray-500 text-white bg-amber-300 dark:bg-amber-400 rounded-full"></span>
@endif
</span>
</div>
<div class="flex-1 px-4 min-w-0 md:grid md:gap-4 md:grid-cols-2">
<div>
<div class="dark:text-accent text-accent-content text-sm font-medium leading-5 truncate">
{{ $message['sender_name'] }}
</div>
<div class="flex items-center mt-2 dark:text-gray-400 text-gray-500 text-sm leading-5">
<svg fill="currentColor" viewBox="0 0 20 20"
class="flex-shrink-0 mr-1.5 w-5 h-5 text-gray-400">
<path fill-rule="evenodd"
d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884zM18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"
clip-rule="evenodd"></path>
</svg>
<span class="truncate">{{ $message['sender_email'] }}</span></div>
</div>
<div class="hidden md:block">
<div>
<div class="dark:text-gray-300 text-gray-900 text-sm leading-5 truncate">
{{ $message['subject'] }}
</div>
<div
class="flex items-center mt-2 text-gray-400 dark:text-gray-400 text-sm leading-5 truncate">
{{ Str::limit($message['contentText'], 100) }}
</div>
</div>
</div>
</div>
</div>
<div>
<svg fill="currentColor" viewBox="0 0 20 20" class="w-5 h-5 text-gray-400">
<path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"></path>
</svg>
</div>
</div>
</div>
</div>
@endforeach
</div>
<div x-show="show" class="message mx-2 mb-2 ">
@foreach(array_reverse($emailsHistory) as $message)
<div x-show="id === {{ $message['id'] }}" id="message-{{ $message['id'] }}">
<textarea class="hidden">To: {{ $this->email ?? "" }}&#13;From: "{{ $message['sender_name'] }}" <{{ $message['sender_email'] }}>&#13;Subject: {{ $message['subject'] }}&#13;Date: {{ $message['date'] }}&#13;Content-Type: text/html&#13;&#13;{{ $message['content'] }}</textarea>
<span>
<div class="-mx-2">
<nav class="flex items-center cursor-pointer" x-on:click="show = false">
<flux:icon.chevron-left variant="mini"/>
<flux:text>{{ __('Get back to MailBox') }}</flux:text>
</nav>
<div class="mt-2 md:flex md:items-center md:justify-between">
<div class="flex-1 min-w-0">
<h2 class="dark:text-gray-300 text-gray-900 text-2xl font-bold leading-7 sm:truncate">
{{ $message['subject'] }}
</h2>
</div>
<div class="flex flex-shrink-0 mt-4 overflow-y-auto md:ml-4 md:mt-0 gap-2">
<flux:button iconVariant="mini" iconLeading="download" x-on:click="$dispatch('downloadFile', { download_id: {{ $message['id'] }} })" class="cursor-pointer">Download</flux:button>
{{-- <flux:button iconVariant="mini" iconLeading="file">Source</flux:button>--}}
<flux:button iconVariant="mini" iconLeading="printer" x-on:click="$dispatch('printFile', { print_id: {{ $message['id'] }} })" class="cursor-pointer">Print</flux:button>
<flux:button iconVariant="mini" iconLeading="trash" x-on:click="show = false; id = 0; document.querySelector(`[data-id='{{ $message['id'] }}']`).remove()" wire:click="delete({{ $message['id'] }})" class="cursor-pointer" style="color: #F14743;">{{ __('Delete') }}</flux:button>
</div>
</div>
<div class="mt-4 px-4 py-5 bg-white border-b border-gray-200 dark:border-gray-900 shadow overflow-hidden sm:px-6 sm:rounded-md">
<div class="flex flex-wrap items-center justify-between -ml-4 -mt-4 sm:flex-nowrap">
<div class="ml-4 mt-4">
<div class="flex items-center">
<div class="flex-shrink-0">
<span class="{{ $message['sender_photo']['dark'] }} {{ $message['sender_photo']['light'] }} inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle size-11 text-[22px] transition">
<span id="sender-logo" class="font-medium leading-none text-gray-100 dark:text-gray-300 dark:group-hover:text-gray-200 group-hover:text-gray-700 truncate">{{ strtoupper(substr($message['sender_name'] ?: $message['sender_email'], 0, 1) ) }}</span>
</span>
</div>
<div class="ml-4">
<div class="text-gray-700 text-lg font-medium leading-6">
{{ $message['sender_name'] }}
<span class="text-gray-700 text-sm font-normal leading-5">{{ $message['sender_email'] }}</span>
</div>
<div class="flex items-center mt-2 text-gray-500 text-sm leading-5">
<svg fill="currentColor" viewBox="0 0 20 20" class="flex-shrink-0 mr-1.5 w-5 h-5 text-gray-400">
<path fill-rule="evenodd" d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884zM18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" clip-rule="evenodd"></path>
</svg>
<span class="truncate"><a href="mailto:{{ $message['sender_email'] }}"
class="ml-1">{{ $message['to'][0] ?? "" }};</a></span></div>
</div>
</div>
</div>
<div class="flex flex-shrink-0 ml-4 mt-4">
<time datetime="2025-04-24T10:11:55+00:00" class="text-gray-500 truncate">
{{ $message['datediff'] }}
</time>
</div>
</div>
<div class="px-4 py-5 sm:px-6">
<iframe srcdoc="{{ $message['content'] }}" class="w-full iframe-min-height">
</iframe>
</div>
@if (count($message['attachments']) > 0)
<div class="grid grid-cols-1 mt-2 text-sm leading-5 text-gray-900 lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2">
@foreach ($message['attachments'] as $attachment)
<button class="mb-2 mr-2 border border-gray-200 rounded-md text-sm leading-5 hover:text-gray-500 cursor-pointer" onclick="window.open('{{ $attachment['url'] }}', '_blank')">
<div class="py-3 pl-3 pr-4">
<div class="flex flex-1 items-center">
<svg class="h-5 w-5 flex-shrink-0 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M8 4a3 3 0 00-3 3v4a5 5 0 0010 0V7a1 1 0 112 0v4a7 7 0 11-14 0V7a5 5 0 0110 0v4a3 3 0 11-6 0V7a1 1 0 012 0v4a1 1 0 102 0V7a3 3 0 00-3-3z" clip-rule="evenodd"></path>
</svg>
<span class="ml-2 flex-1 truncate">{{ $attachment['file'] }}</span>
</div>
</div>
</button>
@endforeach
</div>
@endif
</div>
</div>
</span>
</div>
@endforeach
</div>
</div>
@else
<div class="mb-3"></div>
<div class="mb-3 block rounded-b-lg bg-white shadow-md dark:bg-zinc-700 items-center">
<div class="flex mailbox-min-height w-full items-center justify-center px-4 py-4 sm:px-6">
<div class="waitingBox flex flex-col items-center relative -space-y-4">
<div class="absolute -mt-4 inset-0 flex justify-center items-center animate-spin duration-2000">
<flux:icon.refresh-cw variant="mini" style="color: #ffffdf" />
</div>
<svg width="120" height="124" viewBox="0 0 92 87" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M26 54.37V38.9C26.003 37.125 26.9469 35.4846 28.48 34.59L43.48 25.84C45.027 24.9468 46.933 24.9468 48.48 25.84L63.48 34.59C65.0285 35.4745 65.9887 37.1167 66 38.9V54.37C66 57.1314 63.7614 59.37 61 59.37H31C28.2386 59.37 26 57.1314 26 54.37Z" fill="#8C92A5"></path>
<path d="M46 47.7L26.68 36.39C26.2325 37.1579 25.9978 38.0312 26 38.92V54.37C26 57.1314 28.2386 59.37 31 59.37H61C63.7614 59.37 66 57.1314 66 54.37V38.9C66.0022 38.0112 65.7675 37.1379 65.32 36.37L46 47.7Z" fill="#CDCDD8"></path>
<path d="M27.8999 58.27C28.7796 58.9758 29.8721 59.3634 30.9999 59.37H60.9999C63.7613 59.37 65.9999 57.1314 65.9999 54.37V38.9C65.9992 38.0287 65.768 37.1731 65.3299 36.42L27.8999 58.27Z" fill="#E5E5F0"></path>
</svg>
<flux:text>{{ __('No email history') }}</flux:text>
</div>
</div>
</div>
@endif
</div>
</div>
</div>
</div>
</div>
</div>
</div> <!-- Top Div -->
</span> </span>

View File

@@ -0,0 +1,23 @@
<span>
<div class="flex-1 overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700 dark:bg-white/[0.03] sm:px-8 sm:py-8 lg:p-12">
<div class="text-center p-2">
<!-- Message -->
<div class="w-full flex justify-center mb-6">
{{-- <img class="w-20" src="{{ asset('images/logo.webp') }}" alt="logo" />--}}
<flux:icon.lock-keyhole class="size-20" />
</div>
<h2 class="text-xl sm:text-2xl font-semibold text-gray-800 dark:text-white">
You don't have permission to access this page
</h2>
<p class="text-sm sm:text-base py-2 text-gray-600 dark:text-gray-300">
To continue, you need to subscribe to a plan that grants access.
</p>
<!-- Call to Action Button -->
<a href="{{ route('dashboard') }}"
class="inline-block mt-6 mb-2 px-6 py-3 inbox-btn text-white font-medium text-sm sm:text-base rounded-lg shadow-md transition-colors duration-200">
Subscribe now
</a>
</div>
</div>
</span>

View File

@@ -21,6 +21,7 @@ Route::get('/mailbox', Mailbox::class)->name('mailbox');
Route::get('/mailbox/{email?}', [AppController::class, 'mailbox'])->name('mailboxFromURL'); Route::get('/mailbox/{email?}', [AppController::class, 'mailbox'])->name('mailboxFromURL');
Route::get('/switch/{email}', [AppController::class, 'switch'])->name('switch'); Route::get('/switch/{email}', [AppController::class, 'switch'])->name('switch');
Route::get('/switchP/{email}', [AppController::class, 'switchP'])->name('switchP');
Route::get('/delete/{email?}', [AppController::class, 'delete'])->name('delete'); Route::get('/delete/{email?}', [AppController::class, 'delete'])->name('delete');
Route::get('/deleteP/{email?}', [AppController::class, 'deleteP'])->name('deleteP'); Route::get('/deleteP/{email?}', [AppController::class, 'deleteP'])->name('deleteP');