Batch 3: Integrări placeholder + Backup tenant
═══ Integrări (Marketing → Integrări) ═══ - /app/integrations Page cu 6 carduri (Telegram/WhatsApp/Google Ads/FB/SMS/Webhook) - Toggle on/off per integrare; salvare în settings.integrations JSON - Câmpuri specifice per integrare (token/key/id/secret) - Banner explicativ: 'placeholder UI — implementare separată' ═══ Backup tenant ═══ - TenantBackupService::export($company) → ZIP cu: • data/ (1 JSON per tabel: clients/vehicles/leads/deals/work_orders cu sub-relații/...) • media/ (logo + favicon) • manifest.json (metadata + counts) - /app/backup Page cu buton 'Descarcă backup acum' - Streaming download cu deleteFileAfterSend - Util pentru: backup local, migrare, audit, GDPR right-to-erasure Total tenant routes: 104. Toate cele ~26 module din prototip implementate (sau echivalent funcțional).
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Tenant\Pages;
|
||||
|
||||
use App\Models\Central\Company;
|
||||
use App\Services\TenantBackupService;
|
||||
use App\Tenancy\TenantManager;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
|
||||
class Backup extends Page
|
||||
{
|
||||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-archive-box-arrow-down';
|
||||
|
||||
protected static ?string $navigationLabel = 'Backup';
|
||||
|
||||
protected static string|\UnitEnum|null $navigationGroup = 'Admin';
|
||||
|
||||
protected static ?int $navigationSort = 96;
|
||||
|
||||
protected static ?string $title = 'Backup & Export date';
|
||||
|
||||
protected string $view = 'filament.tenant.pages.backup';
|
||||
|
||||
public function downloadBackup()
|
||||
{
|
||||
$tenant = app(TenantManager::class)->current();
|
||||
if (! $tenant) abort(404);
|
||||
|
||||
// Re-fetch via central scope to avoid issues.
|
||||
$company = Company::withoutGlobalScopes()->find($tenant->id);
|
||||
if (! $company) abort(404);
|
||||
|
||||
$svc = app(TenantBackupService::class);
|
||||
$file = $svc->export($company);
|
||||
$filename = $svc->filename($company);
|
||||
|
||||
return response()->download($file, $filename, [
|
||||
'Content-Type' => 'application/zip',
|
||||
])->deleteFileAfterSend();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Tenant\Pages;
|
||||
|
||||
use App\Tenancy\TenantManager;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
|
||||
class Integrations extends Page
|
||||
{
|
||||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-puzzle-piece';
|
||||
|
||||
protected static ?string $navigationLabel = 'Integrări';
|
||||
|
||||
protected static string|\UnitEnum|null $navigationGroup = 'Marketing';
|
||||
|
||||
protected static ?int $navigationSort = 63;
|
||||
|
||||
protected static ?string $title = 'Integrări externe';
|
||||
|
||||
protected string $view = 'filament.tenant.pages.integrations';
|
||||
|
||||
public array $config = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$tenant = app(TenantManager::class)->current();
|
||||
$this->config = (array) ($tenant?->settings['integrations'] ?? []);
|
||||
}
|
||||
|
||||
public function setStatus(string $key, bool $enabled): void
|
||||
{
|
||||
$this->config[$key]['enabled'] = $enabled;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function updateField(string $key, string $field, ?string $value): void
|
||||
{
|
||||
$this->config[$key][$field] = $value;
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$tenant = app(TenantManager::class)->current();
|
||||
if (! $tenant) return;
|
||||
$tenant->update([
|
||||
'settings' => array_merge((array) $tenant->settings, [
|
||||
'integrations' => $this->config,
|
||||
]),
|
||||
]);
|
||||
Notification::make()->title('Integrări salvate')->success()->send();
|
||||
}
|
||||
|
||||
public function integrations(): array
|
||||
{
|
||||
return [
|
||||
'telegram_bot' => [
|
||||
'name' => 'Telegram Bot',
|
||||
'icon' => '✈️',
|
||||
'color' => '#229ED9',
|
||||
'description' => 'Primește cereri din canalul Telegram + trimite confirmări automate.',
|
||||
'fields' => [
|
||||
'bot_token' => ['label' => 'Bot Token', 'type' => 'password', 'placeholder' => 'din @BotFather'],
|
||||
'chat_id' => ['label' => 'Channel/Chat ID', 'type' => 'text', 'placeholder' => '@psauto_md'],
|
||||
],
|
||||
],
|
||||
'whatsapp_business' => [
|
||||
'name' => 'WhatsApp Business',
|
||||
'icon' => '💬',
|
||||
'color' => '#25D366',
|
||||
'description' => 'Trimite mesaje template către clienți (programări, confirmări).',
|
||||
'fields' => [
|
||||
'phone_id' => ['label' => 'Phone Number ID', 'type' => 'text'],
|
||||
'token' => ['label' => 'Permanent Access Token', 'type' => 'password'],
|
||||
],
|
||||
],
|
||||
'google_ads' => [
|
||||
'name' => 'Google Ads',
|
||||
'icon' => '🔍',
|
||||
'color' => '#EA4335',
|
||||
'description' => 'Tracking conversii — leadurile generate de campanii Google.',
|
||||
'fields' => [
|
||||
'customer_id' => ['label' => 'Customer ID', 'type' => 'text', 'placeholder' => '123-456-7890'],
|
||||
'conversion_id' => ['label' => 'Conversion ID', 'type' => 'text'],
|
||||
],
|
||||
],
|
||||
'facebook' => [
|
||||
'name' => 'Facebook / Instagram Lead Ads',
|
||||
'icon' => '📘',
|
||||
'color' => '#1877F2',
|
||||
'description' => 'Importă lead-uri direct din Lead Ads forms.',
|
||||
'fields' => [
|
||||
'page_id' => ['label' => 'Page ID', 'type' => 'text'],
|
||||
'access_token' => ['label' => 'Access Token', 'type' => 'password'],
|
||||
],
|
||||
],
|
||||
'sms_gateway' => [
|
||||
'name' => 'SMS Gateway',
|
||||
'icon' => '📱',
|
||||
'color' => '#6366F1',
|
||||
'description' => 'Trimite SMS-uri prin gateway local (Moldcell/Orange API).',
|
||||
'fields' => [
|
||||
'provider' => ['label' => 'Provider', 'type' => 'text', 'placeholder' => 'moldcell / orange / twilio'],
|
||||
'api_key' => ['label' => 'API Key', 'type' => 'password'],
|
||||
'sender_id' => ['label' => 'Sender ID', 'type' => 'text'],
|
||||
],
|
||||
],
|
||||
'webhook_in' => [
|
||||
'name' => 'Webhook intrări (formulare site)',
|
||||
'icon' => '🪝',
|
||||
'color' => '#8B5CF6',
|
||||
'description' => 'URL secret pentru POST direct cu lead-uri din site-ul tău.',
|
||||
'fields' => [
|
||||
'secret' => ['label' => 'Secret token', 'type' => 'text', 'placeholder' => 'random string'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user