222 lines
11 KiB
HTML
222 lines
11 KiB
HTML
<!-- Portal Dashboard -->
|
|
<div x-data="portalDashboard()" x-init="init()">
|
|
|
|
<!-- Saludo -->
|
|
<div class="mb-8">
|
|
<h1 class="text-2xl font-bold text-slate-800">
|
|
Hola, {{ if .portalUser }}{{ .portalUser.Nombre }}{{ end }} 👋
|
|
</h1>
|
|
<p class="text-slate-500 text-sm mt-1">
|
|
{{ if .isPartner }}
|
|
Estás viendo todos los proyectos de tus clientes.
|
|
{{ else }}
|
|
Aquí puedes ver el avance de tus proyectos.
|
|
{{ end }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Proyectos cards -->
|
|
{{ if .isPartner }}
|
|
<!-- Agrupado por cliente -->
|
|
{{ range .grupos }}
|
|
<div class="mb-8">
|
|
<h2 class="text-sm font-bold text-slate-500 uppercase tracking-wide mb-3">
|
|
{{ if .Cliente.Empresa }}{{ .Cliente.Empresa }}{{ else }}{{ .Cliente.Nombre }}{{ end }}
|
|
</h2>
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{{ range .Proyectos }}
|
|
<a href="/portal/proyecto/{{ .Slug }}" class="bg-white rounded-2xl border border-slate-200 shadow-sm hover:shadow-md transition-shadow p-5 block group">
|
|
<div class="flex items-center gap-3 mb-3">
|
|
<span class="w-3 h-3 rounded-full" style="background:{{ .Color }}"></span>
|
|
<span class="font-semibold text-slate-800 group-hover:text-[#8eb02f] transition-colors text-sm">{{ .Nombre }}</span>
|
|
</div>
|
|
<p class="text-xs text-slate-500 mb-3 line-clamp-2">{{ .Descripcion }}</p>
|
|
<div class="flex items-center justify-between mb-1">
|
|
<span class="text-xs font-medium text-slate-500">Progreso</span>
|
|
<span class="text-xs font-bold text-slate-700">{{ .Progreso }}%</span>
|
|
</div>
|
|
<div class="w-full bg-slate-100 rounded-full h-2">
|
|
<div class="h-2 rounded-full" style="background:{{ .Color }};width:{{ .Progreso }}%"></div>
|
|
</div>
|
|
<div class="mt-3 flex justify-between items-center">
|
|
<span class="text-xs px-2 py-0.5 rounded-full font-semibold" style="background:#f1f5f9;color:#475569">{{ .Estado }}</span>
|
|
<span class="text-xs text-slate-400">Ver detalle →</span>
|
|
</div>
|
|
</a>
|
|
{{ end }}
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
{{ else }}
|
|
<!-- Vista simple para cliente -->
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{{ range .proyectos }}
|
|
<a href="/portal/proyecto/{{ .Slug }}" class="bg-white rounded-2xl border border-slate-200 shadow-sm hover:shadow-md transition-shadow p-5 block group">
|
|
<div class="flex items-center gap-3 mb-3">
|
|
<span class="w-3 h-3 rounded-full" style="background:{{ .Color }}"></span>
|
|
<span class="font-semibold text-slate-800 group-hover:text-[#8eb02f] transition-colors text-sm">{{ .Nombre }}</span>
|
|
</div>
|
|
<p class="text-xs text-slate-500 mb-3 line-clamp-2">{{ .Descripcion }}</p>
|
|
<div class="flex items-center justify-between mb-1">
|
|
<span class="text-xs font-medium text-slate-500">Progreso</span>
|
|
<span class="text-xs font-bold text-slate-700">{{ .Progreso }}%</span>
|
|
</div>
|
|
<div class="w-full bg-slate-100 rounded-full h-2">
|
|
<div class="h-2 rounded-full" style="background:{{ .Color }};width:{{ .Progreso }}%"></div>
|
|
</div>
|
|
<div class="mt-3 flex justify-between items-center">
|
|
<span class="text-xs px-2 py-0.5 rounded-full font-semibold" style="background:#f1f5f9;color:#475569">{{ .Estado }}</span>
|
|
<span class="text-xs text-slate-400">Ver detalle →</span>
|
|
</div>
|
|
</a>
|
|
{{ end }}
|
|
</div>
|
|
{{ if not .proyectos }}
|
|
<div class="text-center py-20 text-slate-400">
|
|
<svg class="w-12 h-12 mx-auto mb-3 opacity-40" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z"/></svg>
|
|
<p>Aún no tienes proyectos asignados.</p>
|
|
</div>
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
</div>
|
|
|
|
{{ if .isPartner }}
|
|
<!-- ─── Sección Partner: Recursos y Comunicados ─────────────────────────────── -->
|
|
<div x-data="partnerHub()" x-init="init()" class="mt-10">
|
|
|
|
<div class="flex items-center gap-3 mb-5">
|
|
<span class="w-8 h-8 rounded-lg bg-[#8eb02f] text-white flex items-center justify-center text-sm font-bold">P</span>
|
|
<div>
|
|
<h2 class="text-base font-bold text-slate-800">Zona Partner</h2>
|
|
<p class="text-xs text-slate-400">Recursos y comunicados exclusivos para ti</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tabs -->
|
|
<div class="flex border-b border-slate-200 mb-5 gap-0">
|
|
<button @click="tab='comunicados'" class="px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors"
|
|
:class="tab==='comunicados' ? 'border-[#8eb02f] text-[#8eb02f]' : 'border-transparent text-slate-500 hover:text-slate-700'">
|
|
📢 Comunicados
|
|
<span x-show="comunicados.length > 0" class="ml-1 bg-slate-100 text-slate-500 text-xs px-1.5 py-0.5 rounded-full" x-text="comunicados.length"></span>
|
|
</button>
|
|
<button @click="tab='recursos'" class="px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors"
|
|
:class="tab==='recursos' ? 'border-[#8eb02f] text-[#8eb02f]' : 'border-transparent text-slate-500 hover:text-slate-700'">
|
|
📁 Recursos
|
|
<span x-show="recursos.length > 0" class="ml-1 bg-slate-100 text-slate-500 text-xs px-1.5 py-0.5 rounded-full" x-text="recursos.length"></span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Comunicados -->
|
|
<div x-show="tab==='comunicados'" x-cloak>
|
|
<div class="space-y-4">
|
|
<template x-for="com in comunicados" :key="com.ID">
|
|
<div class="bg-white border border-slate-200 rounded-xl p-5">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div class="flex-1">
|
|
<h3 class="font-semibold text-slate-800 text-sm mb-1" x-text="com.titulo"></h3>
|
|
<p class="text-sm text-slate-600 whitespace-pre-line leading-relaxed" x-text="com.contenido"></p>
|
|
<p class="text-xs text-slate-400 mt-2" x-text="formatDate(com.CreatedAt)"></p>
|
|
</div>
|
|
<template x-if="com.archivo">
|
|
<a :href="`/portal/partner-comunicados/${com.ID}/download`" target="_blank"
|
|
class="flex-shrink-0 inline-flex items-center gap-1.5 text-xs text-[#8eb02f] hover:text-[#6d8c24] border border-[#8eb02f] px-2.5 py-1.5 rounded-lg hover:bg-[#f6ffe0] transition-colors">
|
|
<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="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
|
|
Adjunto
|
|
</a>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<p x-show="comunicados.length === 0 && !loading" class="text-slate-400 text-sm text-center py-10">Sin comunicados por ahora.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recursos -->
|
|
<div x-show="tab==='recursos'" x-cloak>
|
|
<!-- Filtro por categoría -->
|
|
<div class="flex flex-wrap gap-2 mb-4">
|
|
<template x-for="cat in ['todos','general','tecnico','comercial','marketing']" :key="cat">
|
|
<button @click="filtro=cat" class="text-xs px-3 py-1 rounded-full border font-medium transition-colors capitalize"
|
|
:class="filtro===cat ? 'bg-[#8eb02f] text-white border-[#8eb02f]' : 'border-slate-200 text-slate-500 hover:border-slate-400'" x-text="cat">
|
|
</button>
|
|
</template>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
<template x-for="r in recursosFiltrados" :key="r.ID">
|
|
<div class="bg-white border border-slate-200 rounded-xl p-4 flex flex-col gap-2">
|
|
<div class="flex items-start justify-between gap-2">
|
|
<div class="flex-1">
|
|
<div class="flex items-center gap-2 mb-1">
|
|
<span class="text-xs px-2 py-0.5 rounded-full font-medium capitalize" :class="catClass(r.categoria)" x-text="r.categoria"></span>
|
|
</div>
|
|
<h4 class="font-semibold text-slate-800 text-sm" x-text="r.nombre"></h4>
|
|
<p class="text-xs text-slate-500 mt-0.5 line-clamp-2" x-text="r.descripcion"></p>
|
|
</div>
|
|
</div>
|
|
<template x-if="r.archivo">
|
|
<a :href="`/portal/partner-recursos/${r.ID}/download`" target="_blank"
|
|
class="mt-auto inline-flex items-center gap-2 text-xs font-medium text-white bg-[#8eb02f] hover:bg-[#6d8c24] px-3 py-1.5 rounded-lg transition-colors">
|
|
<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="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
|
|
Descargar
|
|
</a>
|
|
</template>
|
|
<template x-if="r.enlace">
|
|
<a :href="r.enlace" target="_blank" rel="noopener noreferrer"
|
|
class="inline-flex items-center gap-2 text-xs font-medium text-[#8eb02f] border border-[#8eb02f] hover:bg-[#f0f6e4] px-3 py-1.5 rounded-lg transition-colors">
|
|
<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="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>
|
|
Ver enlace
|
|
</a>
|
|
</template>
|
|
<template x-if="!r.archivo && !r.enlace">
|
|
<span class="text-xs text-slate-400 italic">Sin archivo adjunto</span>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
<p x-show="recursosFiltrados.length === 0 && !loading" class="sm:col-span-2 lg:col-span-3 text-slate-400 text-sm text-center py-10">Sin recursos disponibles.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
|
|
<script>
|
|
function partnerHub() {
|
|
return {
|
|
tab: 'comunicados',
|
|
filtro: 'todos',
|
|
recursos: [],
|
|
comunicados: [],
|
|
loading: false,
|
|
|
|
async init() {
|
|
this.loading = true;
|
|
try {
|
|
const r = await axios.get('/portal/partner-recursos');
|
|
this.recursos = r.data.recursos || [];
|
|
this.comunicados = r.data.comunicados || [];
|
|
} catch(e) {} finally { this.loading = false; }
|
|
},
|
|
|
|
get recursosFiltrados() {
|
|
if (this.filtro === 'todos') return this.recursos;
|
|
return this.recursos.filter(r => r.categoria === this.filtro);
|
|
},
|
|
|
|
catClass(cat) {
|
|
return {
|
|
general: 'bg-slate-100 text-slate-600',
|
|
tecnico: 'bg-blue-100 text-blue-700',
|
|
comercial: 'bg-yellow-100 text-yellow-700',
|
|
marketing: 'bg-pink-100 text-pink-700',
|
|
}[cat] || 'bg-slate-100 text-slate-600';
|
|
},
|
|
|
|
formatDate(d) {
|
|
if (!d) return '';
|
|
return new Date(d).toLocaleDateString('es-CO', { day:'2-digit', month:'short', year:'numeric' });
|
|
},
|
|
}
|
|
}
|
|
</script>
|