Deploy: 2026-05-22 03:37:23

This commit is contained in:
Hamza-Ayed
2026-05-22 03:37:23 +03:00
parent 479aedcbcf
commit 8448f13dfc
5 changed files with 761 additions and 2 deletions

View File

@@ -774,13 +774,26 @@
<button class="nav-item" :class="{ 'active': activeDashboardTab === 'chatbot' }" @click="activeDashboardTab = 'chatbot'; fetchChatbotSettings()" id="nav-chatbot-btn">
<span>🤖</span> <span x-text="lang === 'ar' ? 'روبوت الذكاء الاصطناعي' : 'AI Chatbot Settings'"></span>
</button>
<button class="nav-item" :class="{ 'active': activeDashboardTab === 'integrations' }" @click="activeDashboardTab = 'integrations'; fetchEndpoints()" id="nav-integrations-btn">
<span>🔌</span> <span>ربط تطبيق نبيه بمشروعك (API Integrations)</span>
<button class="nav-item" :class="{ 'active': activeDashboardTab === 'integrations' }" @click="activeDashboardTab = 'integrations'; fetchEndpoints(); fetchSallaStatus()" id="nav-integrations-btn">
<span>🔌</span> <span x-text="lang === 'ar' ? 'الربط البرمجي والمنصات (Integrations)' : 'API & Platform Integrations'"></span>
</button>
</div>
<!-- Right Dashboard Panels -->
<div style="flex: 1;">
<!-- Global Dashboard Banner -->
<template x-if="dashboardSuccess">
<div class="banner banner-success" style="margin-bottom: 1.5rem;" id="dashboard-success-banner">
<span x-text="dashboardSuccess"></span>
<button @click="dashboardSuccess = ''" style="background: none; border: none; color: inherit; font-size: 1.2rem; cursor: pointer; margin-left: auto; margin-right: 0;" id="dashboard-success-close-btn">&times;</button>
</div>
</template>
<template x-if="dashboardError">
<div class="banner banner-danger" style="margin-bottom: 1.5rem;" id="dashboard-error-banner">
<span x-text="dashboardError"></span>
<button @click="dashboardError = ''" style="background: none; border: none; color: inherit; font-size: 1.2rem; cursor: pointer; margin-left: auto; margin-right: 0;" id="dashboard-error-close-btn">&times;</button>
</div>
</template>
<!-- Panel: WhatsApp Connection -->
<div class="panel" x-show="activeDashboardTab === 'whatsapp'" id="panel-whatsapp">
@@ -1113,6 +1126,50 @@
<p class="text-muted" style="margin-bottom: 1.5rem; font-size: 0.9rem;" x-text="lang === 'ar' ? 'قم بتهيئة واجهات برمجة التطبيقات الخارجية (Web APIs) للربط البرمجي بمشروعك. يمكن للروبوت جلب الملفات التعريفية للمستخدمين أو التحقق من تفاصيل الدفع ديناميكيًا.' : 'Configure external web APIs for multi-tenant integrations. The chatbot can fetch user profiles or verify payment details dynamically.'">
</p>
<!-- Salla Integration Section -->
<div style="background: rgba(0, 178, 137, 0.05); border: 1px solid rgba(0, 178, 137, 0.15); border-radius: 12px; padding: 1.5rem; margin-bottom: 2rem; box-shadow: 0 4px 20px rgba(0, 178, 137, 0.05);">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem;" :style="lang === 'ar' ? 'flex-direction: row-reverse' : ''">
<div style="display: flex; align-items: center; gap: 1rem;" :style="lang === 'ar' ? 'flex-direction: row-reverse; text-align: right;' : ''">
<div style="background: #00b289; width: 48px; height: 48px; border-radius: 10px; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 15px rgba(0, 178, 137, 0.4);">
<span style="font-size: 1.5rem;">🛍️</span>
</div>
<div>
<h3 style="font-size: 1.2rem; margin: 0; display: flex; align-items: center; gap: 0.5rem;" :style="lang === 'ar' ? 'flex-direction: row-reverse' : ''">
<span x-text="lang === 'ar' ? 'ربط متجر سلة (Salla)' : 'Salla Store Integration'"></span>
<template x-if="sallaStatus && sallaStatus.connected">
<span class="status-badge badge-connected" style="margin: 0; padding: 0.15rem 0.5rem; font-size: 0.7rem;" x-text="lang === 'ar' ? 'متصل' : 'Connected'"></span>
</template>
<template x-if="!sallaStatus || !sallaStatus.connected">
<span class="status-badge badge-disconnected" style="margin: 0; padding: 0.15rem 0.5rem; font-size: 0.7rem;" x-text="lang === 'ar' ? 'غير متصل' : 'Disconnected'"></span>
</template>
</h3>
<p class="text-muted" style="margin: 0.25rem 0 0 0; font-size: 0.85rem;" x-text="lang === 'ar' ? 'قم بربط متجر سلة الخاص بك لتفعيل الاستعلام التلقائي عن الطلبات وتتبع الشحنات وإرسال تنبيهات التحديثات للعملاء عبر الواتساب.' : 'Connect your Salla store to enable automatic order tracking and send customer updates via WhatsApp using Gemini AI.'"></p>
</div>
</div>
<div style="display: flex; gap: 0.75rem; align-items: center;">
<template x-if="sallaLoading">
<span class="spinner"></span>
</template>
<template x-if="!sallaLoading && (!sallaStatus || !sallaStatus.connected)">
<button @click="connectSalla()" class="btn" style="background: linear-gradient(135deg, #00b289 0%, #009673 100%); color: #fff; width: auto; font-size: 0.9rem; padding: 0.6rem 1.2rem; box-shadow: 0 4px 12px rgba(0, 178, 137, 0.3);" id="connect-salla-btn">
<span x-text="lang === 'ar' ? 'ربط المتجر الآن' : 'Connect Store'"></span>
</button>
</template>
<template x-if="!sallaLoading && sallaStatus && sallaStatus.connected">
<div style="display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;" :style="lang === 'ar' ? 'flex-direction: row-reverse' : ''">
<div style="text-align: right;" :style="lang === 'ar' ? 'text-align: right;' : 'text-align: left;'">
<span style="font-size: 0.8rem; color: var(--text-secondary);" x-text="lang === 'ar' ? 'المتجر المرتبط:' : 'Connected Store:'"></span>
<strong style="display: block; font-size: 0.95rem; color: #fff;" x-text="sallaStatus.store_name"></strong>
</div>
<button @click="disconnectSalla()" class="btn btn-danger" style="width: auto; font-size: 0.9rem; padding: 0.6rem 1.2rem;" id="disconnect-salla-btn">
<span x-text="lang === 'ar' ? 'إلغاء الربط' : 'Disconnect'"></span>
</button>
</div>
</template>
</div>
</div>
</div>
<div class="data-table-container">
<table class="data-table">
<thead>
@@ -1390,6 +1447,12 @@
},
endpoints: [],
// Salla Integration States
sallaStatus: null,
sallaLoading: false,
dashboardSuccess: '',
dashboardError: '',
// Forms
contactName: '',
contactPhone: '',
@@ -1522,12 +1585,25 @@
this.templates = [];
this.campaigns = [];
this.endpoints = [];
this.sallaStatus = null;
this.dashboardSuccess = '';
this.dashboardError = '';
},
initializeDashboard() {
this.fetchWhatsappStatus();
this.fetchSallaStatus();
// Set up persistent background status check
this.startPolling();
// Detect Salla success connect
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('salla_connect') === 'success') {
this.dashboardSuccess = this.lang === 'ar'
? 'تم ربط متجر سلة بنجاح!'
: 'Salla store connected successfully!';
window.history.replaceState({}, document.title, window.location.pathname);
}
},
async fetchWhatsappStatus() {
@@ -1716,6 +1792,65 @@
}
},
// Salla Integration Methods
async fetchSallaStatus() {
if (!this.token) return;
this.sallaLoading = true;
try {
const response = await fetch('/api/integrations/salla/status', {
headers: { 'Authorization': `Bearer ${this.token}` }
});
const data = await response.json();
if (response.ok && data.status === 'success') {
this.sallaStatus = data;
} else {
this.sallaStatus = { connected: false };
}
} catch (err) {
console.error('Error fetching Salla status:', err);
this.sallaStatus = { connected: false };
} finally {
this.sallaLoading = false;
}
},
connectSalla() {
if (!this.token) return;
window.location.href = `/api/integrations/salla/auth?token=${encodeURIComponent(this.token)}`;
},
async disconnectSalla() {
const confirmMsg = this.lang === 'ar'
? 'هل أنت متأكد من رغبتك في إلغاء ربط متجر سلة؟'
: 'Are you sure you want to disconnect your Salla store?';
if (!confirm(confirmMsg)) return;
this.sallaLoading = true;
try {
const response = await fetch('/api/integrations/salla/disconnect', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
}
});
const data = await response.json();
if (response.ok && data.status === 'success') {
this.dashboardSuccess = this.lang === 'ar'
? 'تم إلغاء ربط متجر سلة بنجاح.'
: 'Salla store disconnected successfully.';
await this.fetchSallaStatus();
} else {
this.dashboardError = data.message || 'Failed to disconnect Salla integration.';
}
} catch (err) {
console.error('Error disconnecting Salla:', err);
this.dashboardError = 'Failed to disconnect Salla integration.';
} finally {
this.sallaLoading = false;
}
},
// CRM List Fetchers
async fetchContacts() {
this.selectedContactIds = [];

View File

@@ -73,6 +73,14 @@ $router->get('/api/endpoints', [\App\Controllers\EndpointController::class,
$router->post('/api/endpoints', [\App\Controllers\EndpointController::class, 'store'], [\App\Middlewares\AuthMiddleware::class]);
$router->delete('/api/endpoints', [\App\Controllers\EndpointController::class, 'delete'], [\App\Middlewares\AuthMiddleware::class]);
// Salla Platform Integration Routes (Phase 6+)
$router->get('/api/integrations/salla/auth', [\App\Controllers\SallaController::class, 'auth']);
$router->get('/api/integrations/salla/callback', [\App\Controllers\SallaController::class, 'callback']);
$router->get('/api/integrations/salla/status', [\App\Controllers\SallaController::class, 'status'], [\App\Middlewares\AuthMiddleware::class]);
$router->post('/api/integrations/salla/disconnect',[\App\Controllers\SallaController::class, 'disconnect'], [\App\Middlewares\AuthMiddleware::class]);
$router->post('/api/webhooks/salla', [\App\Controllers\SallaController::class, 'webhook']);
// Mock External API for Entaleq Driver Info (Used to fetch real-time driver data)
$router->post('/api/external/driver-info', function ($request, $response) {
$body = $request->getBody();