File: /home/xedaptot/be.naniguide.com/app/Http/Controllers/Refactor/SearchController.php
<?php
namespace App\Http\Controllers\Refactor;
use App\Http\Controllers\Controller;
use App\Library\Cache\AppCache;
use Illuminate\Http\Request;
class SearchController extends Controller
{
/**
* Unified power search endpoint — returns JSON for all searchable entities.
*/
public function search(Request $request)
{
$customer = $request->user()->customer;
$keyword = trim($request->keyword ?? '');
$limit = 5;
$categories = [];
if ($keyword !== '') {
// Campaigns — rich info
$campaigns = $customer->local()->campaigns()
->search($keyword)
->orderBy('campaigns.updated_at', 'desc')
->paginate($limit);
if ($campaigns->total() > 0) {
$categories[] = [
'key' => 'campaigns',
'label' => trans('refactor/search.section.campaigns'),
'icon' => 'campaign',
'total' => $campaigns->total(),
'items' => $campaigns->map(function ($c) {
$statusColors = [
'new' => 'default', 'draft' => 'default', 'queuing' => 'blue',
'queued' => 'blue', 'sending' => 'orange', 'done' => 'green',
'paused' => 'orange', 'error' => 'red',
];
$statusLabel = $c->status === 'done' ? 'Sent' : ucfirst($c->status);
if ($c->isError()) {
$statusLabel = 'Error';
} elseif ($c->isPaused()) {
$statusLabel = 'Paused';
}
$openRate = AppCache::for($c)->read('UniqOpenRate', 0);
$clickRate = AppCache::for($c)->read('ClickedRate', 0);
$subCount = AppCache::for($c)->read('SubscriberCount', 0);
$deliveredCount = AppCache::for($c)->read('DeliveredCount', 0);
return [
'type' => 'campaign',
'title' => $c->name,
'subtitle' => $c->subject ?: '',
'url' => route('refactor.campaigns.overview', $c->uid),
'icon' => 'campaign',
'badge' => [
'label' => $statusLabel,
'color' => $statusColors[$c->status] ?? 'default',
],
'meta' => [
'recipients' => number_format($subCount),
'delivered' => number_format($deliveredCount),
'open_rate' => $openRate ? round($openRate * 100, 1) . '%' : '—',
'click_rate' => $clickRate ? round($clickRate * 100, 1) . '%' : '—',
'date' => $c->run_at ? $c->run_at->format('M j, Y') : ($c->created_at ? $c->created_at->format('M j, Y') : ''),
],
];
})->values()->toArray(),
];
}
// Mail Lists
$lists = $customer->local()->mailLists()
->search($keyword)
->orderBy('mail_lists.updated_at', 'desc')
->paginate($limit);
if ($lists->total() > 0) {
$categories[] = [
'key' => 'lists',
'label' => trans('refactor/search.section.lists'),
'icon' => 'list',
'total' => $lists->total(),
'items' => $lists->map(function ($l) {
return [
'type' => 'list',
'title' => $l->name,
'subtitle' => '',
'url' => route('refactor.lists.overview', $l->uid),
'icon' => 'list',
'meta' => [
'subscribers' => number_format(AppCache::for($l)->read('SubscriberCount', 0)),
'created' => $l->created_at ? $l->created_at->format('M j, Y') : '',
],
];
})->values()->toArray(),
];
}
// Subscribers (cross-list)
$subscribers = $customer->local()->subscribers()
->search($keyword)
->orderBy('subscribers.updated_at', 'desc')
->paginate($limit);
if ($subscribers->total() > 0) {
$categories[] = [
'key' => 'subscribers',
'label' => trans('refactor/search.section.subscribers'),
'icon' => 'person',
'total' => $subscribers->total(),
'items' => $subscribers->map(function ($s) {
$statusColors = [
'subscribed' => 'green', 'unsubscribed' => 'default',
'unconfirmed' => 'orange', 'spam-reported' => 'red',
'blacklisted' => 'red',
];
return [
'type' => 'subscriber',
'title' => $s->email,
'subtitle' => $s->getFullName() ?: '',
'url' => route('refactor.lists.subscriber_edit', [$s->mailList->uid, $s->id]),
'icon' => 'person',
'badge' => [
'label' => ucfirst($s->status),
'color' => $statusColors[$s->status] ?? 'default',
],
'avatar' => [
'initials' => strtoupper(substr($s->email, 0, 1)),
'color' => (ord(strtoupper(substr($s->email, 0, 1))) % 8) + 1,
],
'meta' => [
'list' => $s->mailList->name,
'date' => $s->created_at ? $s->created_at->format('M j, Y') : '',
],
];
})->values()->toArray(),
];
}
// Email Templates — with preview/edit actions
$templates = $customer->customerEmailTemplates()
->whereHas('template', function ($q) use ($keyword) {
$q->where('templates.name', 'like', '%' . $keyword . '%');
})
->with('template')
->orderBy('updated_at', 'desc')
->paginate($limit);
if ($templates->total() > 0) {
$categories[] = [
'key' => 'templates',
'label' => trans('refactor/search.section.templates'),
'icon' => 'web',
'total' => $templates->total(),
'items' => $templates->map(function ($cet) {
$t = $cet->template;
$categories = $t->categories ? $t->categories->pluck('name')->implode(', ') : '';
return [
'type' => 'template',
'title' => $t->name,
'subtitle' => '',
'url' => route('refactor.templates.preview', $t->uid),
'icon' => 'web',
'thumb' => $t->getThumbUrl(),
'meta' => [
'category' => $categories ?: '',
'created' => $t->created_at ? $t->created_at->format('M j, Y') : '',
'updated' => $t->updated_at ? $t->updated_at->format('M j, Y') : '',
],
'actions' => [
['label' => 'Preview', 'url' => route('refactor.templates.preview', $t->uid), 'icon' => 'visibility'],
],
];
})->values()->toArray(),
];
}
// Automations
$automations = $customer->local()->automation2s()
->search($keyword)
->orderBy('automation2s.updated_at', 'desc')
->paginate($limit);
if ($automations->total() > 0) {
$categories[] = [
'key' => 'automations',
'label' => trans('refactor/search.section.automations'),
'icon' => 'bolt',
'total' => $automations->total(),
'items' => $automations->map(function ($a) {
$statusColors = ['active' => 'green', 'inactive' => 'default'];
return [
'type' => 'automation',
'title' => $a->name,
'subtitle' => '',
'url' => route('refactor.automations.index'),
'icon' => 'bolt',
'badge' => [
'label' => ucfirst($a->status),
'color' => $statusColors[$a->status] ?? 'default',
],
'meta' => [
'created' => $a->created_at ? $a->created_at->format('M j, Y') : '',
],
];
})->values()->toArray(),
];
}
// Forms — with thumbnail from template
$forms = $customer->local()->forms()
->search($keyword)
->with('template', 'mailList')
->orderBy('forms.updated_at', 'desc')
->paginate($limit);
if ($forms->total() > 0) {
$categories[] = [
'key' => 'forms',
'label' => trans('refactor/search.section.forms'),
'icon' => 'dynamic_form',
'total' => $forms->total(),
'items' => $forms->map(function ($f) {
$statusColors = ['published' => 'green', 'draft' => 'default'];
$thumb = $f->template ? $f->template->getThumbUrl() : null;
return [
'type' => 'form',
'title' => $f->name,
'subtitle' => $f->mailList ? $f->mailList->name : '',
'url' => route('refactor.forms.index'),
'icon' => 'dynamic_form',
'badge' => [
'label' => ucfirst($f->status),
'color' => $statusColors[$f->status] ?? 'default',
],
'thumb' => $thumb,
'thumb_ratio' => 'landscape', // 5:3 for forms
'actions' => $f->status === 'published' ? [
['label' => 'Preview', 'url' => route('refactor.forms.preview', $f->uid), 'icon' => 'visibility'],
] : [],
];
})->values()->toArray(),
];
}
// Segments (cross-list search)
$segments = collect();
$customer->local()->mailLists()->each(function ($list) use ($keyword, &$segments) {
$list->segments()
->where('segments.name', 'like', '%' . $keyword . '%')
->take(5)
->get()
->each(function ($seg) use (&$segments, $list) {
$seg->_list = $list; // attach list for reference
$segments->push($seg);
});
});
$segments = $segments->take($limit);
if ($segments->count() > 0) {
$categories[] = [
'key' => 'segments',
'label' => trans('refactor/search.section.segments'),
'icon' => 'filter_alt',
'total' => $segments->count(),
'items' => $segments->map(function ($seg) {
$list = $seg->_list ?? $seg->mailList;
return [
'type' => 'segment',
'title' => $seg->name,
'subtitle' => $list ? $list->name : '',
'url' => route('refactor.lists.segment_edit', [$list->uid, $seg->uid]),
'icon' => 'filter_alt',
'meta' => [
'subscribers' => number_format(AppCache::for($seg)->read('SubscriberCount', 0)),
'match' => $seg->matching === 'all' ? 'Match ALL' : 'Match ANY',
],
];
})->values()->toArray(),
];
}
}
return response()->json([
'categories' => $categories,
]);
}
/**
* Get customer pages for client-side instant search.
*/
public static function getPages()
{
return [
// Core
['title' => trans('refactor/search.page.dashboard'), 'description' => trans('refactor/search.desc.dashboard'), 'url' => route('refactor.dashboard'), 'icon' => 'dashboard', 'keywords' => 'home overview statistics stats summary report chart'],
['title' => trans('refactor/search.page.campaigns'), 'description' => trans('refactor/search.desc.campaigns'), 'url' => route('refactor.campaigns.index'), 'icon' => 'campaign', 'keywords' => 'email send broadcast newsletter bulk ab test schedule'],
['title' => trans('refactor/search.page.lists'), 'description' => trans('refactor/search.desc.lists'), 'url' => route('refactor.lists.index'), 'icon' => 'list', 'keywords' => 'mailing audience contacts subscribers list manage import export segment field'],
['title' => trans('refactor/search.page.templates'), 'description' => trans('refactor/search.desc.templates'), 'url' => route('refactor.templates.index'), 'icon' => 'web', 'keywords' => 'email design layout builder html drag drop gallery'],
['title' => trans('refactor/search.page.automations'), 'description' => trans('refactor/search.desc.automations'), 'url' => route('refactor.automations.index'), 'icon' => 'bolt', 'keywords' => 'workflow trigger autoresponder drip sequence welcome series'],
['title' => trans('refactor/search.page.forms'), 'description' => trans('refactor/search.desc.forms'), 'url' => route('refactor.forms.index'), 'icon' => 'dynamic_form', 'keywords' => 'signup embed popup subscribe opt-in landing widget'],
['title' => trans('refactor/search.page.funnels'), 'description' => trans('refactor/search.desc.funnels'), 'url' => route('refactor.funnels.index'), 'icon' => 'filter_alt', 'keywords' => 'funnel conversion flow pipeline page builder'],
// Sending infrastructure
['title' => trans('refactor/search.page.sending_servers'), 'description' => trans('refactor/search.desc.sending_servers'), 'url' => route('refactor.sending.servers'), 'icon' => 'dns', 'keywords' => 'smtp server amazon ses sendgrid mailgun sparkpost elastic postmark gmail oauth'],
['title' => trans('refactor/search.page.sending_domains'), 'description' => trans('refactor/search.desc.sending_domains'), 'url' => route('refactor.sending.domains'), 'icon' => 'domain', 'keywords' => 'domain dkim spf authentication dns record mx'],
['title' => trans('refactor/search.page.tracking_domains'), 'description' => trans('refactor/search.desc.tracking_domains'), 'url' => route('refactor.sending.tracking_domains'), 'icon' => 'track_changes', 'keywords' => 'tracking click open custom domain cname https ssl'],
['title' => trans('refactor/search.page.verified_senders'), 'description' => trans('refactor/search.desc.verified_senders'), 'url' => route('refactor.sending.senders'), 'icon' => 'verified', 'keywords' => 'sender identity from address email verified verify'],
['title' => trans('refactor/search.page.blacklist'), 'description' => trans('refactor/search.desc.blacklist'), 'url' => route('refactor.sending.blacklist'), 'icon' => 'block', 'keywords' => 'block suppress unsubscribe exclude ban'],
['title' => trans('refactor/search.page.email_verification'), 'description' => trans('refactor/search.desc.email_verification'), 'url' => route('refactor.sending.verification_servers'), 'icon' => 'mark_email_read', 'keywords' => 'verify clean validate hygiene bounce list cleaning'],
// Integrations
['title' => trans('refactor/search.page.websites'), 'description' => trans('refactor/search.desc.websites'), 'url' => route('refactor.websites.index'), 'icon' => 'language', 'keywords' => 'integration site connect website embed tracking pixel'],
// Account settings (enriched keywords for discoverability)
['title' => trans('refactor/search.page.account') . ' > ' . trans('refactor/search.page.profile'), 'description' => trans('refactor/search.desc.profile'), 'url' => route('refactor.account.profile'), 'icon' => 'person', 'keywords' => 'name email password change avatar photo image upload timezone language locale first last profile settings account'],
['title' => trans('refactor/search.page.account') . ' > ' . trans('refactor/search.page.contact'), 'description' => trans('refactor/search.desc.contact'), 'url' => route('refactor.account.contact'), 'icon' => 'contact_mail', 'keywords' => 'contact information company address phone country city state zip'],
['title' => trans('refactor/search.page.account') . ' > ' . trans('refactor/search.page.billing'), 'description' => trans('refactor/search.desc.billing'), 'url' => route('refactor.account.billing'), 'icon' => 'receipt_long', 'keywords' => 'payment invoice billing address credit card receipt history tax vat'],
['title' => trans('refactor/search.page.account') . ' > ' . trans('refactor/search.page.subscription'), 'description' => trans('refactor/search.desc.subscription'), 'url' => route('refactor.account.subscription'), 'icon' => 'card_membership', 'keywords' => 'plan upgrade cancel renew downgrade pricing trial subscription quota limit usage'],
['title' => trans('refactor/search.page.account') . ' > ' . trans('refactor/search.page.quota'), 'description' => trans('refactor/search.desc.quota'), 'url' => route('refactor.account.quota'), 'icon' => 'data_usage', 'keywords' => 'quota usage limit sending credits subscribers remaining plan allocation'],
['title' => trans('refactor/search.page.account') . ' > ' . trans('refactor/search.page.users'), 'description' => trans('refactor/search.desc.users'), 'url' => route('refactor.account.users'), 'icon' => 'group', 'keywords' => 'team user member invite colleague share access multi-user'],
['title' => trans('refactor/search.page.account') . ' > ' . trans('refactor/search.page.2fa'), 'description' => trans('refactor/search.desc.2fa'), 'url' => route('refactor.account.2fa'), 'icon' => 'security', 'keywords' => 'two factor 2fa authentication google authenticator security otp totp'],
['title' => trans('refactor/search.page.account') . ' > ' . trans('refactor/search.page.api'), 'description' => trans('refactor/search.desc.api'), 'url' => route('refactor.account.api'), 'icon' => 'api', 'keywords' => 'api key token integration rest webhook developer renew regenerate'],
['title' => trans('refactor/search.page.activity_log'), 'description' => trans('refactor/search.desc.activity_log'), 'url' => route('refactor.account.logs'), 'icon' => 'history', 'keywords' => 'log activity recent audit trail history event'],
];
}
/**
* Get customer quick actions for client-side instant search.
*/
public static function getActions()
{
return [
['title' => trans('refactor/search.action.create_campaign'), 'description' => trans('refactor/search.action_desc.create_campaign'), 'url' => route('refactor.campaigns.select_type'), 'icon' => 'add_circle'],
['title' => trans('refactor/search.action.create_list'), 'description' => trans('refactor/search.action_desc.create_list'), 'url' => route('refactor.lists.create'), 'icon' => 'add_circle'],
['title' => trans('refactor/search.action.create_template'), 'description' => trans('refactor/search.action_desc.create_template'), 'url' => route('refactor.templates.gallery'), 'icon' => 'add_circle'],
['title' => trans('refactor/search.action.create_automation'), 'description' => trans('refactor/search.action_desc.create_automation'), 'url' => route('refactor.automations.create'), 'icon' => 'add_circle'],
['title' => trans('refactor/search.action.create_form'), 'description' => trans('refactor/search.action_desc.create_form'), 'url' => route('refactor.forms.create'), 'icon' => 'add_circle'],
['title' => trans('refactor/search.action.go_dashboard'), 'description' => trans('refactor/search.action_desc.go_dashboard'), 'url' => route('refactor.dashboard'), 'icon' => 'home'],
['title' => trans('refactor/search.action.account_settings'), 'description' => trans('refactor/search.action_desc.account_settings'), 'url' => route('refactor.account.profile'), 'icon' => 'settings'],
['title' => trans('refactor/search.action.toggle_theme'), 'description' => trans('refactor/search.action_desc.toggle_theme'), 'url' => '#toggle-theme', 'icon' => 'dark_mode'],
];
}
}