@extends('layouts.admin') @section('title', 'Platform Settings') @push('styles') @endpush @section('content') @if(session('success'))
{{ session('success') }}
@endif {{-- Tabs --}}
{{-- ============ GENERAL TAB ============ --}}
@csrf @method('PUT')
Platform Information
Fee Configuration
Applied to escrow transactions
Maintenance
Maintenance Mode
When enabled, non-admin users see a maintenance page. Admins can bypass via /tenseal-admin-bypass.
{{-- ============ INTEGRATIONS TAB ============ --}}
@csrf @method('PUT') {{-- Paystack --}}
Paystack
{{ ($settings['paystack_enabled'] ?? 'false') === 'true' ? 'Enabled' : 'Disabled' }}
Leave blank to keep current value
Leave blank to keep current value
Used to verify webhook payloads from Paystack. Leave blank to keep current value.
{{-- Copy-paste URLs for the Paystack dashboard. Generated live from url() so they reflect the actual host (works in dev, staging, prod without hardcoding). Two-column grid so the panel doesn't dominate the page vertically on desktop. Collapses to one column on narrow viewports. --}}
URLs to paste into Paystack dashboard
Webhook URL
{{ url('/api/v1/webhooks/paystack') }}
Callback URL (subscription payments)
https://inventory.tenseal.co/subscription/verify
{{-- Flutterwave --}}
Flutterwave
{{ ($settings['flutterwave_enabled'] ?? 'false') === 'true' ? 'Enabled' : 'Disabled' }}
Leave blank to keep current value
Leave blank to keep current value
Used to verify webhook payloads from Flutterwave. Leave blank to keep current value.
URLs to paste into Flutterwave dashboard
Webhook URL
{{ url('/api/v1/webhooks/flutterwave') }}
Redirect URL (subscription return)
https://inventory.tenseal.co/subscription/verify
{{-- Stripe --}}
Stripe
{{ ($settings['stripe_enabled'] ?? 'false') === 'true' ? 'Enabled' : 'Disabled' }}
Leave blank to keep current value
Leave blank to keep current value
Used to verify webhook payloads from Stripe. Leave blank to keep current value.
URLs to paste into Stripe dashboard
Webhook endpoint
{{ url('/api/v1/webhooks/stripe') }}
Subscribe to events: payment_intent.succeeded, payment_intent.payment_failed
Success URL (subscription return)
https://inventory.tenseal.co/subscription/verify
{{-- Google OAuth moved to its own tab --}}
Google Sign-In

Google Single Sign-On is now configured under the Single Sign-On tab.

{{-- ============ SINGLE SIGN-ON TAB ============ --}}
@csrf @method('PUT') @php $googleSecretSet = \App\Support\GoogleSso::secretConfigured(); @endphp
Google Single Sign-On

When enabled, a “Continue with Google” button appears on the user, marketplace, and inventory sign-in pages. One Google account maps to one Tenseal account across every module — sign in once and you're recognised everywhere. A user who signs into inventory for the first time is guided through business setup automatically.

Leave blank to keep the current secret.
Google Cloud Console setup

In your OAuth client, add every one of these as an Authorized redirect URI:

@foreach(\App\Support\GoogleSso::redirectUris() as $u)
{{ $u }}
@endforeach

And these as Authorized JavaScript origins:

@foreach(\App\Support\GoogleSso::origins() as $o)
{{ $o }}
@endforeach
{{-- ============ ESCROW FEES TAB ============ --}}
@csrf @method('PUT')
Escrow Transaction Fee Bands

Set how the escrow fee is charged by transaction amount. Each band applies to amounts in its range — choose a flat fee or a percentage, with an optional cap. Leave the highest band's “Max amount” empty for “and above”. Who pays the fee (buyer / seller / split) is chosen by the parties at transaction time; this only sets the amount.

@foreach($escrowFeeTiers as $i => $tier) @endforeach
Min amount (₦) Max amount (₦) Fee type Value Cap (₦)
VAT
{{-- ============ FEE SETTINGS TAB ============ --}}
@csrf @method('PUT')
Withdrawal Fee

Charged when a user withdraws from their wallet to their bank. The fee is deducted from the withdrawal — the user is debited the full amount and receives (amount − fee) at their bank.

Deposit Fee

Off by default — deposits are free and the user only pays their payment processor's own charge. Turn this on to also charge a platform fee on funding; it is deducted from the credited amount (the user pays the gross at the gateway and the wallet is credited amount − fee).

{{-- ============ EMAIL TAB ============ --}}
@csrf @method('PUT')
SMTP Configuration

Email credentials are saved to the server environment file. Leave fields blank to keep their current values.

{{-- Send test email --}}
@csrf
Send Test Email

After saving your SMTP settings above, send a test email to verify delivery works.

{{-- ============ MARKETPLACE TAB ============ --}}
@csrf @method('PUT')
Escrow Protection Mode
@foreach(['required' => ['Required', 'All marketplace purchases must go through escrow (recommended)'], 'optional' => ['Optional', 'Buyers can choose to use escrow or pay directly'], 'disabled' => ['Disabled', 'No escrow for marketplace (direct payment only)']] as $val => [$label, $desc]) @endforeach
Marketplace Configuration
Funds auto-release to seller after this period if no dispute
Platform takes this % from each sale
Seller Verification Required
Require KYC verification before a user can sell on the marketplace.
Listing Approval
Admin must approve listings before they go live.
{{-- ============ NOTIFICATIONS TAB ============ --}}
@csrf @method('PUT') {{-- SMS (Termii) --}}
SMS (Termii)
{{ ($settings['sms_enabled'] ?? 'false') === 'true' ? 'Enabled' : 'Disabled' }}
Leave blank to keep current value
The name recipients see (max 11 chars, must be approved by Termii)
Get your keys from accounts.termii.com
{{-- WhatsApp (Meta Cloud API) --}}
WhatsApp (Meta Cloud API)
{{ ($settings['whatsapp_enabled'] ?? 'false') === 'true' ? 'Enabled' : 'Disabled' }}
From Meta Business → WhatsApp → API Setup
Use a permanent system-user token for production
Webhook URL: {{ url('/whatsapp/webhook') }}
{{-- ============ SECURITY TAB ============ --}}
@include('auth.partials.two-factor-panel', [ 'twofaEnabled' => auth()->user()->hasTwoFactorEnabled(), 'pending2fa' => $pending2fa ?? null, 'confirmRoute' => route('admin.security.2fa.confirm'), 'disableRoute' => route('admin.security.2fa.disable'), 'recoveryRoute'=> route('admin.security.2fa.recovery'), ])
{{-- ============ DEPLOY TAB ============ --}}
@php $deployKey = $deployKey ?? ''; $deployBase = $deployKey ? '/deploy/?key=' . $deployKey : ''; $deployActions = [ ['path' => '', 'label' => 'Open Deploy Panel', 'desc' => 'Full dashboard with every action.', 'icon' => 'fa-rocket', 'variant' => 'primary'], ['path' => 'cache-clear', 'label' => 'Clear Cache', 'desc' => 'Flush config, route, view, and app caches.', 'icon' => 'fa-broom', 'variant' => 'secondary'], ['path' => 'cache-build', 'label' => 'Rebuild Cache', 'desc' => 'Re-cache config, routes, and views.', 'icon' => 'fa-bolt', 'variant' => 'secondary'], ['path' => 'optimize', 'label' => 'Optimize', 'desc' => 'One-shot clear + rebuild all caches.', 'icon' => 'fa-gauge-high', 'variant' => 'secondary'], ['path' => 'migrate', 'label' => 'Run Migrations', 'desc' => 'Apply pending database migrations.', 'icon' => 'fa-database', 'variant' => 'secondary'], ['path' => 'seed', 'label' => 'Run Seeders', 'desc' => 'Re-seed reference data (plans, roles).', 'icon' => 'fa-seedling', 'variant' => 'secondary'], ['path' => 'storage-link', 'label' => 'Storage Link', 'desc' => 'Create public/storage symlink.', 'icon' => 'fa-link', 'variant' => 'secondary'], ['path' => 'status', 'label' => 'Deploy Status', 'desc' => 'View current app, env, and git status.', 'icon' => 'fa-circle-info', 'variant' => 'secondary'], ]; @endphp
Master Deploy
@if(empty($deployKey))
DEPLOY_KEY not set.

Add DEPLOY_KEY=... to your .env file to enable the deploy panel.

@else

One-click shortcuts to the shared-hosting deploy runner. The key is pulled from .env — if you rotate it there, this page updates automatically.

@foreach($deployActions as $action) @php $deployHref = $action['path'] ? '/deploy/' . $action['path'] . '?key=' . $deployKey : '/deploy/?key=' . $deployKey; @endphp
{{ $action['label'] }}
{{ $action['desc'] }}
@endforeach
@endif
@if(!empty($deployKey))
Security
Deploy links carry the secret key in the URL — don't share them. If a key leaks, rotate DEPLOY_KEY in .env, then hit Clear Cache.
Key ending in …{{ substr($deployKey, -8) }}
@endif
@endsection @push('scripts') @endpush