BCards/src/BCards.Web/Views/UserPage/Display.cshtml
2025-08-17 15:45:59 -03:00

340 lines
16 KiB
Plaintext

@model BCards.Web.Models.IPageDisplay
@{
var seo = ViewBag.SeoSettings as BCards.Web.Models.SeoSettings;
var category = ViewBag.Category as BCards.Web.Models.Category;
var isPreview = ViewBag.IsPreview as bool? ?? false;
var isLivePage = ViewBag.IsLivePage as bool? ?? false;
ViewData["Title"] = seo?.Title ?? $"{Model.DisplayName} - {category?.Name}";
Layout = isPreview ? "_Layout" : "_UserPageLayout";
}
@section Head {
@if (isPreview)
{
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet">
}
else if (isLivePage)
{
<meta name="robots" content="index, follow">
@if (!string.IsNullOrEmpty(ViewBag.PageUrl as string))
{
<link rel="canonical" href="@ViewBag.PageUrl">
}
}
else
{
<meta name="robots" content="noindex, nofollow">
}
}
@section Styles {
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@{
var partialOutput = await Html.PartialAsync("_ThemeStyles", Model.Theme);
using (var writer = new System.IO.StringWriter())
{
partialOutput.WriteTo(writer, HtmlEncoder);
@Html.Raw(writer.ToString())
}
}
</style>
}
<div class="user-page min-vh-100 d-flex align-items-center py-4">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-6 col-md-8">
<div class="profile-card mx-auto">
<!-- Profile Image & Info -->
<div class="profile-header text-center mb-4">
@if (!string.IsNullOrEmpty(Model.ProfileImageId))
{
<img src="@Model.ProfileImageUrl" alt="@Model.DisplayName" class="profile-image-large rounded-circle mb-3">
}
else
{
<div class="profile-icon-placeholder mb-3">
<i class="fas fa-id-card"></i>
</div>
}
<h1 class="profile-name mb-0">@Model.DisplayName</h1>
</div>
<div class="text-center">
@if (!string.IsNullOrEmpty(Model.Bio))
{
<p class="profile-bio">@Model.Bio</p>
}
<!-- Links Container -->
<div class="links-container">
@if (Model.Links?.Any(l => l.IsActive) == true)
{
@for (int i = 0; i < Model.Links.Count; i++)
{
var link = Model.Links[i];
if (link.IsActive)
{
var hasExpandableContent = (!string.IsNullOrEmpty(link.Description) ||
(link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductDescription)));
<!-- Universal Link Style (TODOS OS LINKS IGUAIS) -->
<div class="universal-link" data-link-id="@i">
<!-- Header clicável (vai para o link) -->
<a href="@link.Url"
class="universal-link-header"
onclick="recordClick('@Model.Id', @i)"
target="_blank"
rel="noopener noreferrer">
<div class="universal-link-content">
@if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductImage))
{
<!-- Thumbnail para produtos -->
<img src="@link.ProductImage"
alt="@(link.ProductTitle ?? link.Title)"
class="link-thumbnail"
loading="lazy"
onerror="this.style.display='none'">
}
else if (!string.IsNullOrEmpty(link.Icon))
{
<!-- Ícone para links normais -->
<div class="link-icon">
<i class="@link.Icon"></i>
</div>
}
else
{
<!-- Ícone padrão se não tiver -->
<div class="link-icon">
<i class="fas fa-link"></i>
</div>
}
<div class="link-text-container">
<div class="link-title">
@if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductTitle))
{
@link.ProductTitle
}
else
{
@link.Title
}
</div>
@if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductPrice))
{
<div class="link-subtitle">@link.ProductPrice</div>
}
else if (!string.IsNullOrEmpty(link.Description) && link.Description.Length > 50)
{
<div class="link-subtitle">@(link.Description.Substring(0, 50))...</div>
}
</div>
</div>
@if (hasExpandableContent)
{
<!-- Seta de expansão (só aparece se tem conteúdo expandível) -->
<button class="expand-arrow"
type="button"
onclick="event.preventDefault(); event.stopPropagation(); toggleLinkDetails(@i)">
<i class="fas fa-chevron-down"></i>
</button>
}
</a>
@if (hasExpandableContent)
{
<!-- Conteúdo expandível -->
<div class="universal-link-details" id="details-@i">
@if (link.Type == BCards.Web.Models.LinkType.Product)
{
<!-- Conteúdo expandido para produtos -->
@if (!string.IsNullOrEmpty(link.ProductImage))
{
<img src="@link.ProductImage"
alt="@(link.ProductTitle ?? link.Title)"
class="expanded-image"
loading="lazy">
}
@if (!string.IsNullOrEmpty(link.ProductPrice))
{
<div class="expanded-price">@link.ProductPrice</div>
}
@if (!string.IsNullOrEmpty(link.ProductDescription))
{
<div class="expanded-description">
@link.ProductDescription
</div>
}
}
else
{
<!-- Conteúdo expandido para links normais -->
@if (!string.IsNullOrEmpty(link.Description))
{
<div class="expanded-description">
@link.Description
</div>
}
}
<div class="expanded-action">
<i class="fas fa-external-link-alt"></i>
Clique no título acima para abrir
</div>
</div>
}
</div>
}
}
}
else
{
<div class="text-muted">
<p>Nenhum link disponível no momento.</p>
</div>
}
</div>
<!-- Footer -->
<div class="profile-footer">
<!-- Promoção BCards -->
<div class="footer-promo" onclick="togglePromo(this)">
<div class="footer-promo-header">
<span>💡 Gostou desta página?</span>
<i class="fas fa-chevron-down"></i>
</div>
<div class="footer-promo-content">
Crie a sua própria página personalizada com <strong>BCards</strong>!
É rápido, fácil e profissional. Compartilhe todos os seus links em um só lugar.
<div class="mt-2">
<a href="@Url.Action("Index", "Home")" class="footer-promo-button">
<i class="fas fa-rocket"></i>
Criar Minha Página
</a>
</div>
</div>
</div>
<div class="footer-credits">
Criado com <a href="@Url.Action("Index", "Home")">BCards</a>
</div>
</div>
</div> <!-- /text-center -->
</div> <!-- /profile-card -->
</div>
</div>
</div>
</div>
@if (isPreview)
{
<div class="position-fixed top-0 start-0 w-100 bg-warning text-dark text-center py-2" style="z-index: 9999;">
<strong>MODO PREVIEW</strong> - Esta é uma prévia da sua página
</div>
}
@section Scripts {
<script>
// Função original de rastreamento de cliques
function recordClick(pageId, linkIndex) {
fetch('/click/' + pageId, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ linkIndex: linkIndex })
}).catch(function(error) {
console.log('Error recording click:', error);
});
}
// Toggle link details (função universal para todos os links)
function toggleLinkDetails(linkIndex) {
const currentDetails = document.getElementById('details-' + linkIndex);
const currentArrow = document.querySelector('[data-link-id="' + linkIndex + '"] .expand-arrow');
if (!currentDetails || !currentArrow) return;
const isCurrentlyExpanded = currentDetails.classList.contains('show');
// Fechar todos os outros links primeiro (auto-close)
const allDetails = document.querySelectorAll('.universal-link-details');
const allArrows = document.querySelectorAll('.expand-arrow');
allDetails.forEach(details => {
details.classList.remove('show');
});
allArrows.forEach(arrow => {
arrow.classList.remove('expanded');
const icon = arrow.querySelector('i');
if (icon) {
icon.style.transform = 'rotate(0deg)';
}
});
// Se não estava expandido, expandir este
if (!isCurrentlyExpanded) {
currentDetails.classList.add('show');
currentArrow.classList.add('expanded');
const icon = currentArrow.querySelector('i');
if (icon) {
icon.style.transform = 'rotate(180deg)';
}
}
}
// Toggle footer promo
function togglePromo(element) {
const content = element.querySelector('.footer-promo-content');
const arrow = element.querySelector('.footer-promo-header i');
if (content.classList.contains('show')) {
content.classList.remove('show');
arrow.style.transform = 'rotate(0deg)';
element.querySelector('.footer-promo-header').classList.remove('expanded');
} else {
content.classList.add('show');
arrow.style.transform = 'rotate(180deg)';
element.querySelector('.footer-promo-header').classList.add('expanded');
}
}
// Initialize page
document.addEventListener('DOMContentLoaded', function() {
// Garantir que todos os accordions comecem fechados
const allDetails = document.querySelectorAll('.universal-link-details, .footer-promo-content');
allDetails.forEach(detail => {
detail.classList.remove('show');
});
const allArrows = document.querySelectorAll('.expand-arrow i, .footer-promo-header i');
allArrows.forEach(arrow => {
arrow.style.transform = 'rotate(0deg)';
});
// Adicionar eventos de teclado para acessibilidade
const expandButtons = document.querySelectorAll('.expand-arrow');
expandButtons.forEach(button => {
button.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
button.click();
}
});
});
});
</script>
}