@extends('examples.modern-layout-v2') @section('title', __('messages.menu.settings')) @section('settings', 'bg-blue-50 text-blue-700') @section('content') @if(!$settings)
error_outline
{{__('messages.settings.settings_error')}}

{{__('messages.settings.unable_to_load_settings')}}

@else @php // Detect server type $isApiServer = \App\Helpers\ServerHelper::isApiServer(); $isLocal = \App\Helpers\ServerHelper::isLocalServer(); @endphp

{{__('messages.menu.settings')}}

{{__('messages.settings.general_settings')}}

@if(!$isApiServer)

{{__('messages.settings.company settings')}}

{{__('messages.settings.general_settings')}}

business
check_circle

{{__('messages.common.update_success')}}

@csrf @if($errors->any())
error_outline
{{__('messages.errors.validation_errors')}}
    @foreach($errors->all() as $error)
  • {{ $error }}
  • @endforeach
@endif
badge
@error('name')

error_outline {{ $message }}

@enderror
email
@error('email')

error_outline {{ $message }}

@enderror
@if(!$isApiServer)
@error('address')

error_outline {{ $message }}

@enderror
phone
@error('phone')

error_outline {{ $message }}

@enderror
place
@error('location')

error_outline {{ $message }}

@enderror
@endif @if(!$isApiServer)
@if($settings->city_id && $settings->city)
location_city
{{$settings->city->name}} ({{strtoupper($settings->city->code)}})

{{__('messages.settings.city_set_help')}}

@else @if($isSuperAdmin)
add_circle {{__('messages.settings.add_new_city')}}

{{__('messages.settings.city_help')}}

{{__('messages.settings.city_code_help')}}

@error('new_city_code')

{{ $message }}

@enderror
@error('new_city_name')

{{ $message }}

@enderror
@else

{{__('messages.settings.city_not_set')}}

@endif @endif
@endif @if(!$isApiServer)
schedule

info {{__('messages.settings.timezone_message')}}

@error('timezone')

error_outline {{ $message }}

@enderror
@if($settings->logo && Storage::disk('public')->exists($settings->logo))
{{__('messages.settings.logo')}}
@endif
@error('logo')

error_outline {{ $message }}

@enderror
@endif
@endif @if(!$isApiServer)

{{__('messages.settings.change_default_language')}}

{{__('messages.settings.select_language')}}

language
check_circle

{{__('messages.common.update_success')}}

@csrf
@php $availableLanguages = $languages && $languages->count() > 0 ? $languages : collect([ (object)['id' => 1, 'name' => __('messages.settings.language_english'), 'code' => 'en'], (object)['id' => 2, 'name' => __('messages.settings.language_arabic'), 'code' => 'iq'], (object)['id' => 3, 'name' => __('messages.settings.language_kurdish'), 'code' => 'ku'], ]); @endphp @foreach($availableLanguages as $language) @endforeach
@error('language')

error_outline {{ $message }}

@enderror
@endif @if(!$isApiServer)

{{__('messages.settings.display voice settings')}}

{{__('messages.settings.general_settings')}}

settings_voice
check_circle

{{__('messages.common.update_success')}}

@csrf
timer

{{__('messages.settings.missed_token_expiration_help')}}

remove_expired_tokens_after_minutes ?? null) === null ? 'disabled' : '' }} class="block w-32 px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors bg-white @if(\App::currentLocale() == 'iq' || \App::currentLocale() == 'ku') text-right @else text-left @endif disabled:bg-gray-100 disabled:cursor-not-allowed" > {{__('messages.settings.minutes')}}

{{__('messages.settings.remove_expired_tokens_after_minutes_help')}}

@endif @can('super-admin') @php $isLocal = preg_match('/\d+\.\d+\.\d+\.\d+/', config('app.url')) === 1; // Only show sync settings on local servers, not on API servers $showSyncSettings = !$isApiServer; @endphp @if($showSyncSettings)

{{__('messages.settings.sync_settings')}}

{{__('messages.settings.sync_settings_description')}}

sync
check_circle

{{__('messages.common.update_success')}}

error_outline

@php $isLocal = preg_match('/\d+\.\d+\.\d+\.\d+/', config('app.url')) === 1; // Only local servers can control sync settings // API servers (stage/prod) can only view city sync status $canControlSync = $isLocal && !$isApiServer; // Always fetch fresh settings to avoid cache issues - refresh to get latest sync_last_at \Cache::forget('settings'); // Clear cache first $settings = \App\Models\Setting::first(); if ($settings) { $settings->refresh(); // Force refresh to get latest sync_last_at and sync_interval_minutes } $syncEnabled = $settings && $settings->sync_enabled == 1; // Use old() only if form validation failed, otherwise use fresh database value $syncInterval = old('sync_interval_minutes'); if ($syncInterval === null) { $syncInterval = $settings ? (int)$settings->sync_interval_minutes : 5; } $lastSyncAt = $settings ? $settings->sync_last_at : null; $syncStatus = $settings ? $settings->sync_status : 'pending'; $liveUrl = old('sync_live_url', $settings ? $settings->sync_live_url : 'https://qflow.prod.api.alho.cloud'); // For prod/staging: determine if sync is active based on recent sync data $syncActive = false; if (!$isLocal && $lastSyncAt) { $lastSync = \Carbon\Carbon::parse($lastSyncAt); $syncActive = $lastSync->isAfter(now()->subDay()); // Active if synced within last 24 hours } @endphp @if($canControlSync)
@csrf
sync

{{__('messages.settings.enable_sync')}}

{{__('messages.settings.enable_sync_description')}}

{{__('messages.settings.sync_interval_help')}}

{{__('messages.settings.last_sync')}}

@if($lastSyncAt) @php $lastSync = \Carbon\Carbon::parse($lastSyncAt); $lastSync->setTimezone(config('app.timezone')); @endphp {{ $lastSync->diffForHumans() }} @else {{__('messages.settings.never')}} @endif

{{__('messages.settings.sync_status_label')}}

{{ ucfirst($syncStatus) }}
@else @php // Get all cities and their detailed sync status $cities = \App\Models\City::withCount([ 'queues' => function($query) { $query->whereNotNull('city_id'); }, 'calls' => function($query) { $query->whereNotNull('city_id'); }, 'messages' => function($query) { $query->whereNotNull('city_id'); }, 'locations' => function($query) { $query->whereNotNull('city_id'); } ])->get(); // Get detailed sync information per city $citySyncDetails = []; foreach ($cities as $city) { // Sync run observability (latest success/failure) $lastSuccessRun = null; $lastFailedRun = null; try { if (\Schema::hasTable('city_sync_runs')) { $lastSuccessRun = \DB::table('city_sync_runs') ->where('city_id', $city->id) ->where('status', 'success') ->orderByDesc('finished_at') ->first(); $lastFailedRun = \DB::table('city_sync_runs') ->where('city_id', $city->id) ->where('status', 'failed') ->orderByDesc('finished_at') ->first(); } } catch (\Throwable $e) { // ignore } // Get last update times for each data type $lastQueue = \App\Models\Queue::where('city_id', $city->id)->latest('updated_at')->first(); $lastCall = \App\Models\Call::where('city_id', $city->id)->latest('updated_at')->first(); $lastMessage = \App\Models\Message::where('city_id', $city->id)->latest('updated_at')->first(); $lastLocation = \App\Models\Location::where('city_id', $city->id)->latest('updated_at')->first(); // Get counters, services, and users counts through location relationship $countersCount = \App\Models\Counter::whereHas('location', function($q) use ($city) { $q->where('city_id', $city->id); })->count(); $servicesCount = \App\Models\Service::whereHas('location', function($q) use ($city) { $q->where('city_id', $city->id); })->count(); $usersCount = \App\Models\User::whereHas('location', function($q) use ($city) { $q->where('city_id', $city->id); })->count(); // Get last update times $lastCounter = \App\Models\Counter::whereHas('location', function($q) use ($city) { $q->where('city_id', $city->id); })->latest('updated_at')->first(); $lastService = \App\Models\Service::whereHas('location', function($q) use ($city) { $q->where('city_id', $city->id); })->latest('updated_at')->first(); $lastUser = \App\Models\User::whereHas('location', function($q) use ($city) { $q->where('city_id', $city->id); })->latest('updated_at')->first(); // Get overall last sync (most recent update) $lastSync = collect([ $lastQueue?->updated_at, $lastCall?->updated_at, $lastMessage?->updated_at, $lastLocation?->updated_at, $lastCounter?->updated_at, $lastService?->updated_at, $lastUser?->updated_at ])->filter()->max(); $citySyncDetails[$city->id] = [ 'last_queue' => $lastQueue?->updated_at, 'last_call' => $lastCall?->updated_at, 'last_message' => $lastMessage?->updated_at, 'last_location' => $lastLocation?->updated_at, 'last_counter' => $lastCounter?->updated_at, 'last_service' => $lastService?->updated_at, 'last_user' => $lastUser?->updated_at, 'last_sync' => $lastSync, 'counters_count' => $countersCount, 'services_count' => $servicesCount, 'users_count' => $usersCount, 'last_success_run' => $lastSuccessRun, 'last_failed_run' => $lastFailedRun, ]; } @endphp
info

City Sync Status

This page shows the sync status for each city. Sync is managed from local servers only.

@if($cities->count() > 0)
@foreach($cities as $city) @php $details = $citySyncDetails[$city->id] ?? []; $lastSync = $details['last_sync'] ?? null; $isHealthy = $lastSync && $lastSync->isAfter(now()->subDay()); $hasData = $city->queues_count > 0 || $city->calls_count > 0 || $city->messages_count > 0 || $city->locations_count > 0; // Determine status color if ($isHealthy && $hasData) { $statusColor = 'green'; $statusText = 'Healthy'; $statusIcon = 'check_circle'; } elseif ($hasData) { $statusColor = 'yellow'; $statusText = 'Stale'; $statusIcon = 'warning'; } else { $statusColor = 'gray'; $statusText = 'No Data'; $statusIcon = 'info'; } @endphp
location_city

{{ $city->name }}

Code: {{ strtoupper($city->code) }}

Last Sync

@if($lastSync) {{ $lastSync->diffForHumans() }} @else Never @endif

@if(isset($details['last_success_run']) && $details['last_success_run'])

Last success: {{ \Carbon\Carbon::parse($details['last_success_run']->finished_at)->diffForHumans() }} @if(!empty($details['last_success_run']->duration_ms)) ({{ (int)$details['last_success_run']->duration_ms }}ms) @endif

@endif @if(isset($details['last_failed_run']) && $details['last_failed_run'])

Last failure: {{ \Carbon\Carbon::parse($details['last_failed_run']->finished_at)->diffForHumans() }}

@endif
{{ $statusIcon }} {{ $statusText }}
{{ number_format($city->queues_count) }}
Queues
{{ number_format($city->calls_count) }}
Calls
{{ number_format($city->messages_count) }}
Messages
{{ number_format($city->locations_count) }}
Locations
{{ number_format($details['counters_count']) }}
Counters
{{ number_format($details['services_count']) }}
Services
{{ number_format($details['users_count']) }}
Users
data_usage Data Sync Details
queue Queues
{{ number_format($city->queues_count) }}
@if($details['last_queue']) Updated {{ $details['last_queue']->diffForHumans() }} @else Never @endif
phone Calls
{{ number_format($city->calls_count) }}
@if($details['last_call']) Updated {{ $details['last_call']->diffForHumans() }} @else Never @endif
message Messages
{{ number_format($city->messages_count) }}
@if($details['last_message']) Updated {{ $details['last_message']->diffForHumans() }} @else Never @endif
place Locations
{{ number_format($city->locations_count) }}
@if($details['last_location']) Updated {{ $details['last_location']->diffForHumans() }} @else Never @endif
info Additional Information
desktop_windows Counters
{{ number_format($details['counters_count']) }}
@if($details['last_counter']) Updated {{ $details['last_counter']->diffForHumans() }} @else Never @endif
business_center Services
{{ number_format($details['services_count']) }}
@if($details['last_service']) Updated {{ $details['last_service']->diffForHumans() }} @else Never @endif
people Users
{{ number_format($details['users_count']) }}
@if($details['last_user']) Updated {{ $details['last_user']->diffForHumans() }} @else Never @endif
Overall Status
Sync Health {{ $statusText }}
@if($lastSync)
Last synchronized: {{ $lastSync->format('M d, Y H:i:s') }}
@endif
@endforeach
@else
location_city

No cities found. Cities will appear here once they start syncing data.

@endif
@endif
@endif @if($isApiServer)

{{__('messages.settings.backup_settings')}}

{{__('messages.settings.backup_settings_description')}}

backup
check_circle

{{__('messages.common.update_success')}}

error_outline

@csrf @if($settings->city_id) @endif
backup

{{__('messages.settings.enable_automatic_backups')}}

{{__('messages.settings.enable_backup_description')}}

{{__('messages.settings.backup_interval_help')}}

{{__('messages.settings.backup_retention_help')}}

{{__('messages.settings.backup_path_help')}}

@php $activeCities = $cities->where('status', 1); @endphp @if($activeCities->count() > 0)

location_city {{__('messages.settings.cities_receiving_backups')}}

@foreach($activeCities as $city) @php // Get the city-specific settings to check if backup is enabled $citySettings = \App\Models\Setting::where('city_code', $city->code)->first(); $backupEnabled = $citySettings && $citySettings->backup_enabled; @endphp
{{ $backupEnabled ? 'backup' : 'backup_table' }}
{{ $city->name }}

{{ $city->code }}

{{ $backupEnabled ? 'check_circle' : 'cancel' }} {{ $backupEnabled ? 'Backup ON' : 'Backup OFF' }}
folder {{ $settings->backup_path ?: 'backup' }}/{{ $city->code }}/
schedule @if($settings->backup_interval_hours == 1) {{__('messages.settings.every_hour')}} @elseif($settings->backup_interval_hours == 6) {{__('messages.settings.every_6_hours')}} @elseif($settings->backup_interval_hours == 24) {{__('messages.settings.daily_24_hours')}} @else Every {{ $settings->backup_interval_hours }}h @endif
event Retain {{ $settings->backup_retention_days ?? 30 }} days
@if(!$backupEnabled)

info Backup is disabled on this local server

@endif
@endforeach
@else
warning

{{__('messages.settings.no_cities_configured')}}

{{__('messages.settings.no_cities_configured_description')}}

@endif
info

{{__('messages.settings.backup_info')}}

  • {{__('messages.settings.backup_location')}}: {{ $settings->backup_path ?: 'backup' }}
  • {{__('messages.settings.backup_format')}}: {{__('messages.settings.compressed_sql_gz')}}
@else

{{__('messages.settings.backup_settings')}}

{{__('messages.settings.backup_managed_on_api')}}

backup
check_circle

{{__('messages.success.backup_settings_updated')}}

@csrf @if($settings->city_id) @endif
backup

{{__('messages.settings.enable_automatic_backups')}}

{{__('messages.settings.backup_configuration_from_api')}}

info

{{__('messages.settings.backup_settings_managed_centrally')}}

{{__('messages.settings.backup_interval_retention_managed_on_api')}}

@if($settings->backup_enabled)
settings {{__('messages.settings.current_backup_configuration')}}

{{__('messages.settings.interval')}}

@if($settings->backup_interval_hours == 1) {{__('messages.settings.every_hour')}} @elseif($settings->backup_interval_hours == 24) {{__('messages.settings.daily')}} @else {{$settings->backup_interval_hours}}h @endif

{{__('messages.settings.retention')}}

{{$settings->backup_retention_days}} {{__('messages.settings.days')}}

{{__('messages.settings.path')}}

{{$settings->backup_path ?: 'backup'}}

@endif
@endif @endcan @if($isApiServer)

telegram {{__('messages.settings.telegram_settings')}}

{{__('messages.settings.telegram_description')}}

check_circle

{{__('messages.common.updated_successfully')}}

@csrf
notifications_active

{{__('messages.settings.enable_telegram')}}

{{__('messages.settings.enable_telegram_description')}}

{{__('messages.settings.telegram_bot_token_help')}}

{{__('messages.settings.telegram_chat_id_help')}}

cloud_upload

{{__('messages.settings.notify_deployments')}}

{{__('messages.settings.notify_deployments_description')}}

info

{{__('messages.settings.test_telegram_connection')}}

{{__('messages.settings.test_telegram_help')}}

@endif
@endif @push('scripts') @endpush @endsection