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,46 @@
|
||||
<x-filament-panels::page>
|
||||
<style>
|
||||
.bk-card { background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 24px; max-width: 720px; }
|
||||
.dark .bk-card { background: #1f2937; border-color: #374151; }
|
||||
.bk-h2 { font-size: 18px; font-weight: 600; margin-bottom: 8px; }
|
||||
.bk-p { font-size: 13px; color: #6b7280; line-height: 1.6; margin-bottom: 12px; }
|
||||
.bk-list { list-style: none; padding: 0; margin: 16px 0; }
|
||||
.bk-list li { padding: 6px 0; font-size: 13px; }
|
||||
.bk-list li::before { content: '✓'; color: #059669; font-weight: 700; margin-right: 8px; }
|
||||
.bk-btn {
|
||||
display: inline-block; padding: 12px 24px; background: #3b82f6; color: #fff;
|
||||
border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500;
|
||||
text-decoration: none;
|
||||
}
|
||||
.bk-btn:hover { background: #2563eb; }
|
||||
</style>
|
||||
|
||||
<div class="bk-card">
|
||||
<h2 class="bk-h2">📦 Export complet date tenant</h2>
|
||||
<p class="bk-p">
|
||||
Exportă toate datele companiei tale într-un fișier ZIP. Util pentru:
|
||||
</p>
|
||||
<ul class="bk-list">
|
||||
<li>Backup periodic (descarcă local sau sincronizează cu cloud)</li>
|
||||
<li>Migrare la alt sistem CRM</li>
|
||||
<li>Audit / verificări fiscale</li>
|
||||
<li>Conformitate GDPR (la cererea ștergerii datelor)</li>
|
||||
</ul>
|
||||
<p class="bk-p">
|
||||
<b>Conține:</b> clienți, mașini, lead-uri, deal-uri, programări, fișe de lucru cu manopere și piese,
|
||||
depozit, furnizori, achiziții, plăți, cheltuieli, salarii, useri, logo + favicon, manifest cu metadata.
|
||||
</p>
|
||||
<p class="bk-p">
|
||||
<b>Format:</b> ZIP cu fișiere JSON (1 per tabel) + media + manifest.json.
|
||||
</p>
|
||||
|
||||
<button type="button" class="bk-btn" wire:click="downloadBackup" wire:loading.attr="disabled">
|
||||
<span wire:loading.remove wire:target="downloadBackup">⬇ Descarcă backup acum</span>
|
||||
<span wire:loading wire:target="downloadBackup">Generez ZIP...</span>
|
||||
</button>
|
||||
|
||||
<p class="bk-p" style="margin-top:24px;font-size:11px;color:#9ca3af;">
|
||||
⚠ Backup-urile pot conține date sensibile (telefoane, emailuri, plăți). Stochează-le în siguranță.
|
||||
</p>
|
||||
</div>
|
||||
</x-filament-panels::page>
|
||||
@@ -0,0 +1,78 @@
|
||||
<x-filament-panels::page>
|
||||
<style>
|
||||
.ig-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); }
|
||||
.ig-card {
|
||||
background: #fff; border: 1px solid #e5e7eb; border-radius: 12px;
|
||||
padding: 20px; position: relative;
|
||||
}
|
||||
.dark .ig-card { background: #1f2937; border-color: #374151; }
|
||||
.ig-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
|
||||
.ig-icon {
|
||||
width: 40px; height: 40px; display: flex; align-items: center; justify-content: center;
|
||||
border-radius: 8px; font-size: 22px; color: #fff;
|
||||
}
|
||||
.ig-name { font-size: 15px; font-weight: 600; flex: 1; }
|
||||
.ig-desc { font-size: 12px; color: #6b7280; margin-bottom: 16px; line-height: 1.5; }
|
||||
|
||||
.ig-toggle { display: flex; align-items: center; gap: 8px; }
|
||||
.ig-toggle input[type=checkbox] { transform: scale(1.2); cursor: pointer; }
|
||||
.ig-status { font-size: 11px; color: #6b7280; }
|
||||
.ig-status.on { color: #059669; font-weight: 600; }
|
||||
|
||||
.ig-fields { margin-top: 12px; }
|
||||
.ig-fld { margin-bottom: 10px; }
|
||||
.ig-lbl { font-size: 11px; color: #6b7280; display: block; margin-bottom: 4px; }
|
||||
.ig-input {
|
||||
width: 100%; padding: 8px 10px; border: 1px solid #e5e7eb; border-radius: 6px;
|
||||
font-size: 12px; font-family: inherit;
|
||||
}
|
||||
.dark .ig-input { background: #111827; border-color: #374151; color: #f9fafb; }
|
||||
|
||||
.ig-save {
|
||||
margin-top: 8px; padding: 6px 16px; font-size: 12px;
|
||||
background: #3b82f6; color: #fff; border: none; border-radius: 6px; cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div style="background: #fef3c7; border-left: 4px solid #f59e0b; padding: 12px 16px; border-radius: 6px; margin-bottom: 16px; font-size: 13px;">
|
||||
ℹ️ <b>Status:</b> aceste integrări sunt placeholder UI — le configurezi aici, dar implementarea actuală a fiecărui canal e proiect separat.
|
||||
Pentru moment, valorile salvate sunt accesibile în cod via <code>$tenant->settings['integrations']</code>.
|
||||
</div>
|
||||
|
||||
<div class="ig-grid">
|
||||
@foreach ($this->integrations() as $key => $meta)
|
||||
@php
|
||||
$cfg = $config[$key] ?? [];
|
||||
$enabled = $cfg['enabled'] ?? false;
|
||||
@endphp
|
||||
<div class="ig-card">
|
||||
<div class="ig-head">
|
||||
<div class="ig-icon" style="background:{{ $meta['color'] }};">{{ $meta['icon'] }}</div>
|
||||
<div class="ig-name">{{ $meta['name'] }}</div>
|
||||
<label class="ig-toggle">
|
||||
<input type="checkbox" {{ $enabled ? 'checked' : '' }}
|
||||
wire:click="setStatus('{{ $key }}', {{ $enabled ? 'false' : 'true' }})">
|
||||
<span class="ig-status {{ $enabled ? 'on' : '' }}">{{ $enabled ? 'Activ' : 'Inactiv' }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="ig-desc">{{ $meta['description'] }}</div>
|
||||
|
||||
<div class="ig-fields">
|
||||
@foreach ($meta['fields'] as $fkey => $fmeta)
|
||||
<div class="ig-fld">
|
||||
<label class="ig-lbl">{{ $fmeta['label'] }}</label>
|
||||
<input
|
||||
type="{{ $fmeta['type'] }}"
|
||||
class="ig-input"
|
||||
placeholder="{{ $fmeta['placeholder'] ?? '' }}"
|
||||
wire:change="updateField('{{ $key }}', '{{ $fkey }}', $event.target.value)"
|
||||
value="{{ $cfg[$fkey] ?? '' }}"
|
||||
>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<button type="button" class="ig-save" wire:click="save">Salvează</button>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-filament-panels::page>
|
||||
Reference in New Issue
Block a user