diff --git a/ucp/assets/ucp.js b/ucp/assets/ucp.js
index 548d784..b05cbf7 100644
--- a/ucp/assets/ucp.js
+++ b/ucp/assets/ucp.js
@@ -607,7 +607,8 @@ function debounceLoadCdr() {
async function loadPersonalCdr() {
const tbody = document.getElementById('ucp-cdr-tbody');
- if (!tbody) return;
+ const mobileBox = document.getElementById('ucp-cdr-mobile-list');
+ if (!tbody && !mobileBox) return;
try {
const res = await ucpApiCall('get_personal_cdr', 'GET', {
@@ -625,46 +626,83 @@ async function loadPersonalCdr() {
document.getElementById('ucp-cdr-missed').textContent = String(stats.missed);
if (!calls.length) {
- tbody.innerHTML = `
| Aucun appel correspondant. |
`;
+ if (tbody) tbody.innerHTML = `| Aucun appel correspondant. |
`;
+ if (mobileBox) mobileBox.innerHTML = `Aucun appel correspondant.
`;
return;
}
- tbody.innerHTML = calls.map(c => {
- const dirMap = {
- inbound: '↘ Entrant',
- outbound: '↗ Sortant',
- internal: '⇄ Interne',
- };
+ const dirMap = {
+ inbound: '↘ Entrant',
+ outbound: '↗ Sortant',
+ internal: '⇄ Interne',
+ };
+
+ const formatParty = (name, num) => {
+ if (name && num && name !== num) {
+ return `${escapeHtml(name)}
${escapeHtml(num)}
`;
+ }
+ return `${escapeHtml(num || name || '—')}`;
+ };
+
+ const formatInlineParty = (name, num) => {
+ if (name && num && name !== num) {
+ return `${escapeHtml(name)} (${escapeHtml(num)})`;
+ }
+ return `${escapeHtml(num || name || '—')}`;
+ };
+
+ const rowsHtml = [];
+ const cardsHtml = [];
+
+ calls.forEach(c => {
const ok = c.disposition === 'ANSWERED';
const stBadge = ok
? `${escapeHtml(c.status_label || 'Répondu')}`
: `${escapeHtml(c.status_label || 'Manqué')}`;
- const srcNum = String(c.caller_number ?? c.src ?? '');
- const srcName = String(c.caller_name ?? '');
- const dstNum = String(c.callee_number ?? c.dst ?? '');
- const dstName = String(c.callee_name ?? '');
+ const dirBadge = dirMap[c.direction] || escapeHtml(c.direction_label || c.direction);
+ const srcNum = String(c.caller_number ?? c.src ?? '');
+ const srcName = String(c.caller_name ?? '');
+ const dstNum = String(c.callee_number ?? c.dst ?? '');
+ const dstName = String(c.callee_name ?? '');
+ const durText = escapeHtml(c.billsec_formatted || formatDuration(c.billsec || c.duration || 0));
+ const dtText = escapeHtml(c.datetime_formatted || c.datetime || '');
- const formatParty = (name, num) => {
- if (name && num && name !== num) {
- return `${escapeHtml(name)}
${escapeHtml(num)}
`;
- }
- return `${escapeHtml(num || name || '—')}`;
- };
-
- return `
+ rowsHtml.push(`
- | ${escapeHtml(c.datetime_formatted || c.datetime || '')} |
- ${dirMap[c.direction] || escapeHtml(c.direction_label || c.direction)} |
+ ${dtText} |
+ ${dirBadge} |
${formatParty(srcName, srcNum)} |
${formatParty(dstName, dstNum)} |
- ${escapeHtml(c.billsec_formatted || formatDuration(c.billsec || c.duration || 0))} |
+ ${durText} |
${stBadge} |
- `;
- }).join('');
+ `);
+
+ cardsHtml.push(`
+
+
+
+ ${dirBadge}
+ ${stBadge}
+
+
⏱ ${durText}
+
+
+ ${formatInlineParty(srcName, srcNum)}
+ →
+ ${formatInlineParty(dstName, dstNum)}
+
+
${dtText}
+
+ `);
+ });
+
+ if (tbody) tbody.innerHTML = rowsHtml.join('');
+ if (mobileBox) mobileBox.innerHTML = cardsHtml.join('');
} catch (err) {
- tbody.innerHTML = `| ${escapeHtml(err.message)} |
`;
+ if (tbody) tbody.innerHTML = `| ${escapeHtml(err.message)} |
`;
+ if (mobileBox) mobileBox.innerHTML = `${escapeHtml(err.message)}
`;
}
}
diff --git a/ucp/index.php b/ucp/index.php
index d9667d2..d01281a 100644
--- a/ucp/index.php
+++ b/ucp/index.php
@@ -350,7 +350,13 @@ $csrfToken = UcpAuth::getCsrfToken();
class="px-3 py-2 rounded-xl bg-slate-50 border border-slate-300 text-xs text-slate-900 focus:bg-white focus:outline-none focus:border-indigo-500">
-
+
+
+
+
+
diff --git a/version.json b/version.json
index e14e429..2e8d610 100644
--- a/version.json
+++ b/version.json
@@ -1,9 +1,10 @@
{
- "version": "2.5.6",
+ "version": "2.5.7",
"codename": "Pulsar UCP",
"release_date": "2026-11-11",
"min_php_version": "8.2",
"changelog": [
+ "UI v2.5.7 : journal d'appels UCP en cartes style iOS sur mobile (<768px) tout en conservant le tableau 6 colonnes sur ordinateur",
"Correctif v2.5.6 : ergonomie mobile iPhone (en-tête compact + dégradé latéral discret sur la barre d'onglets UCP sans scrollbar visible)",
"Correctif v2.5.5 : suppression du zoom automatique iOS/iPhone sur les champs (<16px) et blocage du débordement horizontal mobile dans l'UCP",
"Correctif v2.5.4 : correction du journal personnel UCP « Mes Appels » (correspondance caller_number/callee_number/canaux PJSIP et filtres Répondus/Manqués)",