Revert "telegram"

This reverts commit 46daf3d4aa.
This commit is contained in:
Lizandro Guarnizo
2026-05-25 12:50:53 -05:00
parent 7b1c260af5
commit 58d98f23aa
6 changed files with 101 additions and 80 deletions
+26 -3
View File
@@ -75,8 +75,12 @@
<p class="text-sm text-slate-600 mt-1" x-text="av.contenido"></p>
</div>
<div class="flex gap-1 ml-4">
<button @click="toggleAvanceVisible(av)" :title="av.visible ? 'Ocultar' : 'Publicar'" class="btn-icon" :class="av.visible ? 'text-green-500' : 'text-slate-400'">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg>
<button @click="toggleAvanceVisible(av)"
:title="av.visible ? 'Visible en portal · clic para ocultar' : 'Oculto en portal · clic para publicar'"
class="btn-icon flex items-center gap-1 px-2 py-1 rounded-lg text-xs font-medium border transition-colors"
:class="av.visible ? 'text-green-600 border-green-200 bg-green-50 hover:bg-green-100' : 'text-slate-400 border-slate-200 bg-slate-50 hover:bg-slate-100'">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg>
<span x-text="av.visible ? 'Visible' : 'Oculto'"></span>
</button>
<button @click="deleteAvance(av.ID)" class="btn-icon text-red-400"><svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg></button>
</div>
@@ -306,6 +310,17 @@
</div>
</div>
<!-- Toast -->
<div x-show="toast.show" x-cloak x-transition
class="fixed bottom-6 right-6 z-50 px-5 py-3 rounded-xl shadow-lg text-white text-sm font-medium flex items-center gap-2"
:class="toast.type === 'error' ? 'bg-red-500' : 'bg-[#8eb02f]'">
<svg class="w-4 h-4 shrink-0" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<path x-show="toast.type !== 'error'" stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path x-show="toast.type === 'error'" stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
<span x-text="toast.msg"></span>
</div>
</div>
<script>
@@ -325,6 +340,7 @@ function proyectoDetalle(proyectoId, slug) {
showDocumentoModal: false,
documentoForm: { tipo:'contrato', nombre:'', descripcion:'' },
documentoFile: null, documentoError:'',
toast: { show: false, msg: '', type: 'ok' },
async init() {
await Promise.all([this.loadFases(), this.loadAvances(), this.loadEntregables(), this.loadTickets(), this.loadDocumentos()]);
@@ -390,8 +406,10 @@ function proyectoDetalle(proyectoId, slug) {
await this.loadAvances();
},
async toggleAvanceVisible(av) {
await axios.put(`/app/proyectos/${this.proyectoId}/avances/${av.ID}`, {...av, visible:!av.visible});
const nuevoEstado = !av.visible;
await axios.put(`/app/proyectos/${this.proyectoId}/avances/${av.ID}`, {...av, visible:nuevoEstado});
await this.loadAvances();
this.showToast(nuevoEstado ? 'Avance visible en el portal del cliente' : 'Avance oculto en el portal del cliente');
},
// ─── Entregables ───
@@ -462,6 +480,11 @@ function proyectoDetalle(proyectoId, slug) {
t._reply='';
},
showToast(msg, type = 'ok') {
this.toast = { show: true, msg, type };
setTimeout(() => { this.toast.show = false; }, 3000);
},
// ─── Helpers ───
faseBadgeClass(e) { return {pendiente:'badge-slate',en_progreso:'badge-yellow',completado:'badge-green',bloqueado:'badge-red'}[e]||'badge-slate'; },
avanceBadgeClass(t) { return {update:'badge-blue',milestone:'badge-green',nota:'badge-slate',alerta:'badge-yellow'}[t]||'badge-slate'; },
-33
View File
@@ -55,12 +55,6 @@
<span x-show="!webhookLoading[cfg.ID]">🔗 Webhook portal</span>
<span x-show="webhookLoading[cfg.ID]">Registrando…</span>
</button>
<button @click="checkWebhook(cfg)" :disabled="webhookInfoLoading[cfg.ID]"
class="flex-1 text-xs border border-slate-300 text-slate-600 px-3 py-1.5 rounded hover:bg-slate-50 transition-colors disabled:opacity-50"
title="Consulta getWebhookInfo en Telegram para este bot">
<span x-show="!webhookInfoLoading[cfg.ID]">📡 Estado webhook</span>
<span x-show="webhookInfoLoading[cfg.ID]">Consultando…</span>
</button>
<button @click="openEdit(cfg)"
class="text-xs border border-blue-400 text-blue-500 px-3 py-1.5 rounded hover:bg-blue-50">Editar</button>
<button @click="confirmDelete(cfg.ID)"
@@ -234,7 +228,6 @@ function telegramApp() {
form: { nombre: '', bot_token: '', chat_id: '', notas: '', activo: true },
testLoading: {}, testResult: {}, testOk: {},
webhookLoading: {}, webhookResult: {}, webhookOk: {},
webhookInfoLoading: {},
sendForm: { config_ids: [], titulo: '', mensaje: '' },
sendLoading: false, sendResult: '', sendOk: true,
logs: [], logPage: 1, logTotalPages: 1, logTotal: 0,
@@ -319,32 +312,6 @@ function telegramApp() {
this.webhookLoading[cfg.ID] = false;
}
},
async checkWebhook(cfg) {
this.webhookInfoLoading[cfg.ID] = true;
this.webhookResult[cfg.ID] = '';
try {
const res = await fetch(`/app/telegram/${cfg.ID}/webhook-info`);
const d = await res.json();
const info = d.result || {};
const hasPortalURL = (info.url || '').includes('/webhooks/telegram-portal');
const hasError = !!(info.last_error_message || info.last_synchronization_error_date);
this.webhookOk[cfg.ID] = !!d.ok && hasPortalURL && !hasError;
const parts = [];
if (info.url) parts.push(`URL: ${info.url}`);
if (typeof info.pending_update_count !== 'undefined') parts.push(`Pendientes: ${info.pending_update_count}`);
if (info.last_error_message) parts.push(`Último error: ${info.last_error_message}`);
if (!parts.length) parts.push(d.description || 'Sin datos de webhook');
this.webhookResult[cfg.ID] = (this.webhookOk[cfg.ID] ? '✅ ' : '⚠️ ') + parts.join(' | ');
} catch (e) {
this.webhookOk[cfg.ID] = false;
this.webhookResult[cfg.ID] = '❌ Error consultando webhook: ' + e.message;
} finally {
this.webhookInfoLoading[cfg.ID] = false;
}
},
async sendMessage() {
this.sendResult = '';