- Created a new Blade view for managing brand contracts with forms for adding and editing contracts, including client and category selection. - Implemented success message notifications for contract actions. - Added a new Blade view for invoice settings, allowing customization of invoice number format, header branding, and default values for new invoices. - Introduced a new PDF view for generating rate cards with customizable styles based on user profile settings. - Developed a profile management page for rate cards, enabling users to update their identity, appearance, and visibility settings.
284 lines
18 KiB
PHP
284 lines
18 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('title', 'Notification Settings')
|
||
@section('page-title', '🔔 Notifications')
|
||
@section('page-subtitle', 'Configure Email, Telegram & WhatsApp alerts')
|
||
|
||
@section('content')
|
||
|
||
<div class="max-w-3xl mx-auto space-y-6">
|
||
|
||
{{-- ── How it works ─────────────────────────────────────── --}}
|
||
<div class="cat-card p-4 flex gap-3 items-start bg-blue-50/50 border-blue-100">
|
||
<span class="text-2xl shrink-0">💡</span>
|
||
<div class="text-sm text-gray-600 space-y-1">
|
||
<p class="font-semibold text-gray-700">How notifications work</p>
|
||
<p>Add one or more channels below. Notifications fire automatically every hour via the scheduler.</p>
|
||
<p class="text-xs text-gray-400">To enable the scheduler on your server: add <code class="bg-white px-1 rounded text-xs">* * * * * php /path/to/artisan schedule:run</code> to crontab.</p>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── Existing channels ────────────────────────────────── --}}
|
||
@if($settings->isNotEmpty())
|
||
<div class="space-y-3">
|
||
@foreach($settings as $setting)
|
||
<div class="cat-card p-4" x-data="{ editing: false }">
|
||
<div class="flex items-center gap-3">
|
||
<span class="text-2xl shrink-0">{{ $setting->channelIcon }}</span>
|
||
<div class="flex-1 min-w-0">
|
||
<div class="flex items-center gap-2 flex-wrap">
|
||
<span class="font-semibold text-gray-800 text-sm">{{ $setting->name }}</span>
|
||
<span class="badge badge-ghost text-xs">{{ $setting->channelLabel }}</span>
|
||
@if(! $setting->is_enabled)
|
||
<span class="badge badge-error text-xs">Disabled</span>
|
||
@endif
|
||
</div>
|
||
<div class="text-xs text-gray-400 mt-0.5 flex flex-wrap gap-2">
|
||
@foreach($setting->triggers ?? [] as $trigger)
|
||
<span>{{ \App\Models\NotificationSetting::$triggerMeta[$trigger]['icon'] ?? '🔔' }}
|
||
{{ \App\Models\NotificationSetting::$triggerMeta[$trigger]['label'] ?? $trigger }}</span>
|
||
@endforeach
|
||
<span>⏰ {{ $setting->notify_before_hours }}h before</span>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center gap-1 shrink-0 flex-wrap justify-end">
|
||
{{-- Test --}}
|
||
<form action="{{ route('settings.notifications.test', $setting) }}" method="POST">
|
||
@csrf
|
||
<button type="submit" class="text-xs px-3 py-1.5 rounded-full border border-blue-200 text-blue-500 hover:bg-blue-50">
|
||
Test
|
||
</button>
|
||
</form>
|
||
{{-- Toggle --}}
|
||
<form action="{{ route('settings.notifications.toggle', $setting) }}" method="POST">
|
||
@csrf
|
||
<button type="submit"
|
||
class="text-xs px-3 py-1.5 rounded-full border {{ $setting->is_enabled ? 'border-amber-200 text-amber-500 hover:bg-amber-50' : 'border-green-200 text-green-500 hover:bg-green-50' }}">
|
||
{{ $setting->is_enabled ? 'Disable' : 'Enable' }}
|
||
</button>
|
||
</form>
|
||
{{-- Edit --}}
|
||
<button @click="editing = !editing"
|
||
class="text-xs px-3 py-1.5 rounded-full border border-pink-200 text-pink-500 hover:bg-pink-50">
|
||
Edit
|
||
</button>
|
||
{{-- Delete --}}
|
||
<form action="{{ route('settings.notifications.destroy', $setting) }}" method="POST"
|
||
onsubmit="return confirm('Remove this channel?')">
|
||
@csrf @method('DELETE')
|
||
<button type="submit"
|
||
class="text-xs px-3 py-1.5 rounded-full border border-red-100 text-red-400 hover:bg-red-50">
|
||
Del
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Inline edit form --}}
|
||
<div x-show="editing" x-transition class="mt-4 pt-4 border-t border-pink-50">
|
||
<form action="{{ route('settings.notifications.update', $setting) }}" method="POST"
|
||
class="space-y-3">
|
||
@csrf @method('PUT')
|
||
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Name</label>
|
||
<input type="text" name="name" value="{{ $setting->name }}"
|
||
class="input-soft text-sm" required>
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Notify before (hours)</label>
|
||
<input type="number" name="notify_before_hours"
|
||
value="{{ $setting->notify_before_hours }}"
|
||
min="1" max="720" class="input-soft text-sm">
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Triggers --}}
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-2">Triggers</label>
|
||
<div class="flex flex-wrap gap-3">
|
||
@foreach(\App\Models\NotificationSetting::$triggerMeta as $key => $meta)
|
||
<label class="flex items-center gap-1.5 cursor-pointer text-sm">
|
||
<input type="checkbox" name="triggers[]" value="{{ $key }}"
|
||
class="accent-pink-400"
|
||
{{ in_array($key, $setting->triggers ?? []) ? 'checked' : '' }}>
|
||
{{ $meta['icon'] }} {{ $meta['label'] }}
|
||
</label>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Channel-specific config --}}
|
||
@if($setting->channel === 'email')
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">To Email</label>
|
||
<input type="email" name="config[to_email]"
|
||
value="{{ $setting->config['to_email'] ?? '' }}"
|
||
class="input-soft text-sm" placeholder="you@example.com">
|
||
</div>
|
||
@elseif($setting->channel === 'telegram')
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Bot Token</label>
|
||
<input type="text" name="config[bot_token]"
|
||
value="{{ $setting->config['bot_token'] ?? '' }}"
|
||
class="input-soft text-sm" placeholder="123456:ABC-DEF...">
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Chat ID</label>
|
||
<input type="text" name="config[chat_id]"
|
||
value="{{ $setting->config['chat_id'] ?? '' }}"
|
||
class="input-soft text-sm" placeholder="-100123456789">
|
||
</div>
|
||
</div>
|
||
@elseif($setting->channel === 'whatsapp')
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||
<div class="sm:col-span-2">
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">WAHA Endpoint</label>
|
||
<input type="url" name="config[waha_endpoint]"
|
||
value="{{ $setting->config['waha_endpoint'] ?? '' }}"
|
||
class="input-soft text-sm" placeholder="http://localhost:3000/api/sendText">
|
||
<p class="text-xs text-gray-400 mt-1">Full URL to the sendText endpoint</p>
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Session Name</label>
|
||
<input type="text" name="config[waha_session]"
|
||
value="{{ $setting->config['waha_session'] ?? 'default' }}"
|
||
class="input-soft text-sm" placeholder="default">
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">API Key
|
||
<span class="font-normal text-gray-400">(if required)</span>
|
||
</label>
|
||
<input type="text" name="config[api_key]"
|
||
value="{{ $setting->config['api_key'] ?? '' }}"
|
||
class="input-soft text-sm" placeholder="your-waha-api-key">
|
||
<p class="text-xs text-gray-400 mt-1">Sent as <code>X-Api-Key</code> header. Leave blank if WAHA has no auth.</p>
|
||
</div>
|
||
<div class="sm:col-span-2">
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Chat ID</label>
|
||
<input type="text" name="config[chat_id]"
|
||
value="{{ $setting->config['chat_id'] ?? '' }}"
|
||
class="input-soft text-sm" placeholder="628123456789@c.us or 120363xxx@g.us">
|
||
<p class="text-xs text-gray-400 mt-1">Individual: <code>628xxx@c.us</code> · Group: <code>120363xxx@g.us</code></p>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
<button type="submit" class="btn-sakura text-sm px-6 py-2">💾 Save</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
@else
|
||
<div class="cat-card p-8 text-center text-gray-400">
|
||
<span class="text-4xl block mb-2">🔕</span>
|
||
<p class="text-sm font-medium">No notification channels yet</p>
|
||
<p class="text-xs mt-1">Add one below to get started</p>
|
||
</div>
|
||
@endif
|
||
|
||
{{-- ── Add new channel ─────────────────────────────────── --}}
|
||
<div class="cat-card p-5" x-data="{ channel: 'email' }">
|
||
<h2 class="font-bold text-gray-700 mb-4 flex items-center gap-2">
|
||
<span>➕</span> Add Notification Channel
|
||
</h2>
|
||
|
||
<form action="{{ route('settings.notifications.store') }}" method="POST" class="space-y-4">
|
||
@csrf
|
||
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Name <span class="text-pink-400">*</span></label>
|
||
<input type="text" name="name" class="input-soft text-sm"
|
||
placeholder="My Telegram Bot" required>
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Channel <span class="text-pink-400">*</span></label>
|
||
<select name="channel" class="input-soft text-sm" x-model="channel">
|
||
<option value="email">✉️ Email</option>
|
||
<option value="telegram">✈️ Telegram</option>
|
||
<option value="whatsapp">💬 WhatsApp (WAHA)</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Notify before (hours)</label>
|
||
<input type="number" name="notify_before_hours" value="24"
|
||
min="1" max="720" class="input-soft text-sm">
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Triggers --}}
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-2">Send when…</label>
|
||
<div class="flex flex-wrap gap-4">
|
||
@foreach(\App\Models\NotificationSetting::$triggerMeta as $key => $meta)
|
||
<label class="flex items-center gap-1.5 cursor-pointer text-sm">
|
||
<input type="checkbox" name="triggers[]" value="{{ $key }}"
|
||
class="accent-pink-400" checked>
|
||
{{ $meta['icon'] }} {{ $meta['label'] }}
|
||
</label>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Email --}}
|
||
<div x-show="channel === 'email'" x-transition>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">To Email <span class="text-pink-400">*</span></label>
|
||
<input type="email" name="config[to_email]" class="input-soft text-sm"
|
||
placeholder="you@example.com">
|
||
</div>
|
||
|
||
{{-- Telegram --}}
|
||
<div x-show="channel === 'telegram'" x-transition class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Bot Token <span class="text-pink-400">*</span></label>
|
||
<input type="text" name="config[bot_token]" class="input-soft text-sm"
|
||
placeholder="123456:ABC-DEF...">
|
||
<p class="text-xs text-gray-400 mt-1">Get from <a href="https://t.me/BotFather" target="_blank" class="text-pink-500">@BotFather</a></p>
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Chat ID <span class="text-pink-400">*</span></label>
|
||
<input type="text" name="config[chat_id]" class="input-soft text-sm"
|
||
placeholder="-100123456789 or @username">
|
||
<p class="text-xs text-gray-400 mt-1">Use <a href="https://t.me/userinfobot" target="_blank" class="text-pink-500">@userinfobot</a> to find your ID</p>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- WhatsApp / WAHA --}}
|
||
<div x-show="channel === 'whatsapp'" x-transition class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||
<div class="sm:col-span-2">
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">WAHA Endpoint <span class="text-pink-400">*</span></label>
|
||
<input type="url" name="config[waha_endpoint]" class="input-soft text-sm"
|
||
placeholder="http://localhost:3000/api/sendText">
|
||
<p class="text-xs text-gray-400 mt-1">Full URL to the sendText endpoint of your WAHA instance</p>
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Session Name</label>
|
||
<input type="text" name="config[waha_session]" value="default" class="input-soft text-sm">
|
||
</div>
|
||
<div>
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">API Key
|
||
<span class="font-normal text-gray-400">(if required)</span>
|
||
</label>
|
||
<input type="text" name="config[api_key]" class="input-soft text-sm"
|
||
placeholder="your-waha-api-key">
|
||
<p class="text-xs text-gray-400 mt-1">Sent as <code class="bg-gray-100 px-1 rounded">X-Api-Key</code> header. Leave blank if WAHA has no auth.</p>
|
||
</div>
|
||
<div class="sm:col-span-2">
|
||
<label class="text-xs font-semibold text-gray-600 block mb-1">Chat ID <span class="text-pink-400">*</span></label>
|
||
<input type="text" name="config[chat_id]" class="input-soft text-sm"
|
||
placeholder="628123456789@c.us or 120363xxx@g.us">
|
||
<p class="text-xs text-gray-400 mt-1">Individual: <code class="bg-gray-100 px-1 rounded">628xxx@c.us</code> · Group: <code class="bg-gray-100 px-1 rounded">120363xxx@g.us</code></p>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="btn-sakura">🔔 Add Channel</button>
|
||
</form>
|
||
</div>
|
||
|
||
</div>
|
||
@endsection
|