QrRapido/Views/Shared/_Layout.cshtml
Ricardo Carneiro 72bbbeea4a
All checks were successful
Deploy QR Rapido / test (push) Successful in 1m1s
Deploy QR Rapido / build-and-push (push) Successful in 16m7s
Deploy QR Rapido / deploy-staging (push) Has been skipped
Deploy QR Rapido / deploy-production (push) Successful in 2m12s
fix: validações de tipo, receber na conta da empresa, og image e idioma.
2026-01-28 10:54:15 -03:00

513 lines
25 KiB
Plaintext

@using QRRapidoApp.Services
@using Microsoft.AspNetCore.Http.Extensions
@using Microsoft.Extensions.Localization
@using Microsoft.Extensions.Configuration
@inject AdDisplayService AdService
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment HostEnvironment
@inject IConfiguration Configuration
@{
var isDevelopment = HostEnvironment?.IsDevelopment() ?? false;
var isPremiumUser = false;
var currentCulture = System.Globalization.CultureInfo.CurrentUICulture?.Name ?? "pt-BR";
// App info for footer
var appName = Configuration["App:Name"] ?? "QR Rapido";
var appVersion = Configuration["App:Version"] ?? "1.0.0";
var appEnvironment = Configuration["App:Environment"] ?? HostEnvironment?.EnvironmentName ?? "Unknown";
var secretsLoaded = Configuration.GetValue<bool>("App:SecretsLoaded");
// SEO: Determine if current page is Spanish (for URL building)
var requestPath = Context.Request.Path.Value ?? "/";
var isSpanish = requestPath.StartsWith("/es-PY", StringComparison.OrdinalIgnoreCase);
// Get path without culture prefix for building alternate URLs
var pathWithoutCulture = requestPath;
if (isSpanish && requestPath.Length > 6)
{
pathWithoutCulture = requestPath.Substring(6); // Remove "/es-PY"
}
else if (isSpanish)
{
pathWithoutCulture = "/";
}
if (string.IsNullOrEmpty(pathWithoutCulture)) pathWithoutCulture = "/";
// Canonical URL - for Portuguese it's without prefix, for Spanish it's with /es-PY
var canonicalUrl = isSpanish
? $"https://qrrapido.site/es-PY{(pathWithoutCulture == "/" ? "" : pathWithoutCulture)}"
: $"https://qrrapido.site{pathWithoutCulture}";
// Alternate URLs for hreflang
var ptUrl = $"https://qrrapido.site{pathWithoutCulture}";
var esUrl = $"https://qrrapido.site/es-PY{(pathWithoutCulture == "/" ? "" : pathWithoutCulture)}";
// Culture prefix for internal links
var culturePrefix = isSpanish ? "/es-PY" : "";
if (User?.Identity?.IsAuthenticated == true)
{
var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
if (!string.IsNullOrWhiteSpace(userId))
{
try
{
isPremiumUser = await AdService.HasValidPremiumSubscription(userId);
}
catch
{
isPremiumUser = false;
}
}
}
}
<!DOCTYPE html>
<html lang="@currentCulture">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - QR Rapido | Gerador QR Code Ultrarrápido</title>
<!-- Cache Control Headers -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<!-- SEO Meta Tags -->
<meta name="description" content="@(ViewBag.Description ?? Localizer["QRGenerateDescription"])">
<meta name="keywords" content="@(ViewBag.Keywords ?? "qr rapido, gerador qr rapido, qr code rapido, codigo qr rapido, qr gratis rapido, generador qr rapido, qr ultrarapido")">
<meta name="author" content="QR Rapido">
<meta name="robots" content="index, follow">
<!-- Canonical URL -->
<link rel="canonical" href="@canonicalUrl">
<!-- Hreflang for multilingual SEO -->
<link rel="alternate" hreflang="pt-BR" href="@ptUrl">
<link rel="alternate" hreflang="es-PY" href="@esUrl">
<link rel="alternate" hreflang="x-default" href="@ptUrl">
<!-- Open Graph -->
<meta property="og:title" content="@(ViewBag.Title ?? "QR Rapido") - @Localizer["FastestQRGeneratorWeb"]">
<meta property="og:description" content="@(ViewBag.Description ?? Localizer["QRGenerateDescription"])">
<meta property="og:image" content="https://qrrapido.site/images/pix-og.png">
<meta property="og:url" content="@canonicalUrl">
<meta property="og:type" content="website">
<meta property="og:site_name" content="QR Rapido">
<meta property="og:locale" content="@(isSpanish ? "es_PY" : "pt_BR")">
<!-- Twitter Cards -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="QR Rapido - @Localizer["FastestQRGeneratorWeb"]">
<meta name="twitter:description" content="@Localizer["QRGenerateDescription"]">
<meta name="twitter:image" content="https://qrrapido.site/images/qrrapido-twitter-card.png">
<!-- Preload critical resources for performance -->
<link rel="preload" href="/webfonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/webfonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" as="style">
<link rel="preload" href="~/css/site.css" as="style">
<link rel="preload" href="~/css/qrrapido-theme.css" as="style">
<script type="text/javascript">
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "tufamidcvb");
</script>
@*
<!-- Hotjar Tracking Code for https://qrrapido.site -->
<script data-cfasync="false">
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:6550944,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.crossOrigin='anonymous';
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
*@
<!-- Structured Data Schema.org -->
<script type="application/ld+json">
{
"@@context": "https://schema.org",
"@@type": "WebApplication",
"name": "QR Rapido",
"description": "Gerador de QR Code ultrarrápido em português e espanhol",
"url": "https://qrrapido.site",
"applicationCategory": "UtilityApplication",
"operatingSystem": "Web",
"author": {
"@@type": "Organization",
"name": "QR Rapido"
},
"offers": {
"@@type": "Offer",
"price": "0",
"priceCurrency": "BRL",
"description": "Geração gratuita de QR codes"
},
"aggregateRating": {
"@@type": "AggregateRating",
"ratingValue": "4.8",
"reviewCount": "2547"
},
"featureList": [
"Geração em segundos",
"Suporte multilíngue",
"Sem cadastro obrigatório",
"Sem limite diário",
"Download múltiplos formatos"
]
}
</script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-64FCDJGT44"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-64FCDJGT44');
</script>
@*
<!-- Google Analytics 4 - Optimized with defer -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-64FCDJGT44"></script>
<script defer>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-64FCDJGT44');
// Custom events for QR Rapido
window.trackQRGeneration = function(type, time, isPremium) {
gtag('event', 'qr_generated', {
'event_category': 'QR Generation',
'event_label': type,
'value': Math.round(parseFloat(time) * 1000),
'custom_parameters': {
'generation_time': parseFloat(time),
'user_type': isPremium ? 'premium' : 'free',
'speed_category': time < 1.0 ? 'ultra_fast' : time < 2.0 ? 'fast' : 'normal'
}
});
};
window.trackSpeedComparison = function(ourTime, competitorAvg) {
gtag('event', 'speed_comparison', {
'event_category': 'Performance',
'our_time': parseFloat(ourTime),
'competitor_avg': parseFloat(competitorAvg),
'speed_advantage': parseFloat(competitorAvg) - parseFloat(ourTime)
});
};
window.trackLanguageChange = function(from, to) {
gtag('event', 'language_change', {
'event_category': 'Localization',
'previous_language': from,
'new_language': to
});
};
</script>
*@
@* AdSense removed - Preparing for Adsterra integration *@
<!-- Bootstrap 5 - Optimized loading -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" media="print" onload="this.media='all'">
<link rel="stylesheet" href="~/css/vendor/fontawesome.min.css" asp-append-version="true" media="print" onload="this.media='all'" />
<link rel="stylesheet" href="~/css/telegram-fab.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/rating.css" asp-append-version="true" />
<!-- Custom CSS - Critical above fold with cache busting -->
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/qrrapido-theme.css" asp-append-version="true" />
<!-- Translation variables for JavaScript -->
<script>
window.QRRapidoTranslations = {
shareError: '@Localizer["ShareError"]',
linkCopied: '@Localizer["LinkCopied"]',
enterQRContent: '@Localizer["EnterQRContent"]',
contentTooLong: '@Localizer["ContentTooLong"]',
featureNotAvailable: '@Localizer["FeatureNotAvailable"]',
vCardValidationError: '@Localizer["VCardValidationError"]',
logoTooLarge: '@Localizer["LogoTooLarge"]',
invalidLogoFormat: '@Localizer["InvalidLogoFormat"]',
premiumCornerStyleRequired: '@Localizer["PremiumCornerStyleRequired"]',
fastestGeneratorBrazil: '@Localizer["FastestGeneratorBrazil"]',
validationContentMinLength: '@Localizer["ValidationContentMinLength"]',
errorSavingHistory: '@Localizer["ErrorSavingHistory"]',
rateLimitReached: '@Localizer["RateLimitReached"]',
premiumLogoRequired: '@Localizer["PremiumLogoRequired"]',
contentAddedToastTitle: '@Localizer["ContentAddedToastTitle"]',
contentAddedToastMessage: '@Localizer["ContentAddedToastMessage"]',
generateButtonReady: '@Localizer["GenerateButtonReady"]'
};
</script>
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/images/qrrapido-favicon.svg">
<link rel="icon" type="image/png" href="/images/qrrapido-favicon-32x32.png">
<!-- Web App Manifest -->
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#007BFF">
</head>
<body>
<!-- Header with QR Rapido branding -->
<header class="navbar navbar-expand-lg navbar-light bg-white border-bottom sticky-top">
<div class="container">
<a class="navbar-brand d-flex align-items-center" href="/">
<svg width="40" height="40" class="me-2" viewBox="0 0 100 100">
<!-- QR Rapido logo with speed effect -->
<rect x="10" y="10" width="80" height="80" fill="#007BFF" rx="8"/>
<rect x="20" y="20" width="15" height="15" fill="white"/>
<rect x="65" y="20" width="15" height="15" fill="white"/>
<rect x="20" y="65" width="15" height="15" fill="white"/>
<!-- Speed lines -->
<path d="M85 45 L95 45 M85 50 L92 50 M85 55 L89 55" stroke="#FF6B35" stroke-width="2"/>
</svg>
<div>
<h1 class="h4 mb-0 text-primary fw-bold">QR Rapido</h1>
<small class="text-muted" id="tagline">@Localizer["Tagline"]</small>
</div>
</a>
<div class="navbar-nav ms-auto d-flex flex-row align-items-center gap-3">
<!-- Main Menu Dropdown -->
<div class="dropdown">
<button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="fas fa-bars"></i> <span class="d-none d-md-inline ms-1">Menu</span>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="@Url.Action("Index", "Home")">
<i class="fas fa-home me-2"></i>@Localizer["Home"]
</a></li>
<li><a class="dropdown-item" href="@Url.Action("HowToUse", "Home")">
<i class="fas fa-question-circle me-2"></i>@Localizer["HowToUse"]
</a></li>
<li><a class="dropdown-item" href="@Url.Action("FAQ", "Home")">
<i class="fas fa-comments me-2"></i>FAQ
</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="@Url.Action("About", "Home")">
<i class="fas fa-info-circle me-2"></i>@Localizer["About"]
</a></li>
<li><a class="dropdown-item" href="@Url.Action("Contact", "Home")">
<i class="fas fa-envelope me-2"></i>@Localizer["Contact"]
</a></li>
</ul>
</div>
<!-- Language selector -->
<div class="dropdown">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="fas fa-globe"></i> <span id="current-lang">PT</span>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" data-lang="pt-BR">🇧🇷 Português (Brasil)</a></li>
<li><a class="dropdown-item" href="#" data-lang="es-PY">🇵🇾 Español (Paraguay)</a></li>
@* <li><a class="dropdown-item" href="#" data-lang="en">🇺🇸 English</a></li> *@
</ul>
</div>
<!-- Theme Toggle -->
<div class="theme-toggle-container">
<button id="theme-toggle" class="btn btn-outline-secondary btn-sm" type="button" title="Alternar tema">
<i id="theme-icon" class="fas fa-sun"></i>
<span id="theme-text" class="d-none d-md-inline ms-1">Claro</span>
</button>
</div>
<!-- Global speed timer -->
<div class="d-none d-md-block">
<small class="text-success fw-bold">
<i class="fas fa-stopwatch"></i>
<span id="avg-generation-time">1.2s</span> @Localizer["Average"]
</small>
</div>
@if (User.Identity.IsAuthenticated)
{
<a href="/Pagamento/SelecaoPlano" class="btn btn-warning text-dark fw-bold shadow-sm animate-pulse">
<i class="fas fa-coins"></i> <span class="d-none d-md-inline">Comprar Créditos</span>
</a>
<div class="dropdown">
<button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="fas fa-user"></i> @User.Identity.Name
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/">
<i class="fas fa-qrcode me-2"></i> @Localizer["GenerateQRCode"]
</a></li>
<li><a class="dropdown-item" href="/Account/Profile">
<i class="fas fa-user-cog me-2"></i> @Localizer["Profile"]
</a></li>
<li><a class="dropdown-item" href="/Account/History">
<i class="fas fa-history me-2"></i> @Localizer["History"]
</a></li>
<li><hr class="dropdown-divider"></li>
<li>
<form method="post" action="/Account/Logout" class="d-inline">
<button type="submit" class="dropdown-item text-danger">
<i class="fas fa-sign-out-alt me-2"></i>@Localizer["Logout"]
</button>
</form>
</li>
</ul>
</div>
}
else
{
<a href="/Account/Login" class="btn btn-primary btn-sm">
<i class="fas fa-sign-in-alt"></i> @Localizer["Login"]
</a>
<div class="d-none d-md-block">
<small class="text-success">
<i class="fas fa-gift"></i> Cadastre-se = 5 Grátis!
</small>
</div>
}
</div>
</div>
</header>
<!-- Hero Section for speed -->
<section class="bg-gradient-primary text-white py-4 mb-4">
<div class="container text-center">
<h2 class="h5 mb-2">
<i class="fas fa-bolt"></i> @Localizer["FastestQRGeneratorWeb"]
</h2>
<p class="mb-0 opacity-75">
@Localizer["AverageTimePrefix"] <strong>@Localizer["AverageTimeValue"]</strong> @Localizer["AverageTimeSuffix"]
</p>
<div class="mt-3">
<a href="@(culturePrefix)/tutoriais" class="btn btn-sm btn-light">
<i class="fas fa-graduation-cap"></i> @Localizer["ViewTutorials"]
</a>
</div>
</div>
</section>
<!-- Ad Space Header (conditional) -->
@await Html.PartialAsync("_AdSpace", new { position = "header" })
<main role="main">
@RenderBody()
</main>
<!-- Footer -->
<footer class="bg-dark text-light py-4 mt-5">
<div class="container">
<div class="row">
<div class="col-md-5">
<h5>QR Rapido</h5>
<p class="small">@Localizer["FastestQRGeneratorDescription"]</p>
</div>
<div class="col-md-3">
<h6>@Localizer["Tools"]</h6>
<div class="row">
<div class="col-6">
<ul class="list-unstyled small">
<li><a href="@(culturePrefix)/pix" class="text-light text-decoration-none">@Localizer["PixGenerator"]</a></li>
<li><a href="@(culturePrefix)/wifi" class="text-light text-decoration-none">QR Code WiFi</a></li>
<li><a href="@(culturePrefix)/whatsapp" class="text-light text-decoration-none">Link WhatsApp</a></li>
<li><a href="@(culturePrefix)/vcard" class="text-light text-decoration-none">@Localizer["DigitalCard"]</a></li>
</ul>
</div>
<div class="col-6">
<ul class="list-unstyled small">
<li><a href="@(culturePrefix)/email" class="text-light text-decoration-none">QR Code Email</a></li>
<li><a href="@(culturePrefix)/sms" class="text-light text-decoration-none">QR Code SMS</a></li>
<li><a href="@(culturePrefix)/texto" class="text-light text-decoration-none">@Localizer["TextQR"]</a></li>
<li><a href="@(culturePrefix)/url" class="text-light text-decoration-none">QR Code URL</a></li>
</ul>
</div>
</div>
</div>
<div class="col-md-2">
<h6>@Localizer["UsefulLinks"]</h6>
<ul class="list-unstyled small">
<li><a href="@Url.Action("Privacy", "Home")" class="text-light">@Localizer["Privacy"]</a></li>
<li><a href="@Url.Action("Terms", "Home")" class="text-light">@Localizer["TermsOfUse"]</a></li>
<li><a href="@Url.Action("Upgrade", "Premium")" class="text-warning">Premium</a></li>
</ul>
</div>
<div class="col-md-2">
<h6>@Localizer["Support"]</h6>
<ul class="list-unstyled">
<li><a href="mailto:contato@qrrapido.site" class="text-light">Contato</a></li>
<li><a href="@Url.Action("FAQ", "Home")" class="text-light">@Localizer["Help"]</a></li>
</ul>
</div>
</div>
<hr>
<div class="text-center mb-2">
<small class="text-muted">
@Html.Raw(Localizer["JobMakerCredit"].ToString().Replace("JobMaker", "<a href=\"https://jobmaker.com.br\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-warning\">JobMaker</a>"))
</small>
</div>
<div class="text-center">
<small>&copy; 2024 QR Rapido. @Localizer["AllRightsReserved"]</small>
</div>
<div class="text-center mt-2">
<small class="text-muted" style="font-size: 0.7rem;">
@appName v@(appVersion) |
@appEnvironment
@if (secretsLoaded)
{
<span class="text-success" title="Docker Secrets loaded">&#x2713;</span>
}
else if (appEnvironment == "Production")
{
<span class="text-danger" title="Secrets NOT loaded from Docker!">&#x2717;</span>
}
</small>
</div>
</div>
</footer>
<!-- Cookie Consent Banner -->
@await Html.PartialAsync("_CookieConsent")
<!-- Support FAB - Available for all users, with rating option -->
@await Html.PartialAsync("_TelegramPremiumFab", isPremiumUser)
<!-- Bootstrap 5 JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/telegram-fab.js" asp-append-version="true" defer></script>
<script src="~/js/rating.js" asp-append-version="true" defer></script>
@if (isDevelopment || true) // FORCE INDIVIDUAL SCRIPTS FOR NOW TO ENSURE CHANGES ARE VISIBLE
{
<script src="~/js/simple-opcacity.js" asp-append-version="true" defer></script>
<script src="~/js/test.js" asp-append-version="true" defer></script>
<script src="~/js/qr-speed-generator.js" asp-append-version="true" defer></script>
<script src="~/js/language-switcher.js" asp-append-version="true" defer></script>
<script src="~/js/theme-toggle.js" asp-append-version="true" defer></script>
<script src="~/js/cookie-consent.js" asp-append-version="true" defer></script>
<script src="~/js/performance-optimizations.js" asp-append-version="true" defer></script>
<script src="~/js/pix-generator.js" asp-append-version="true" defer></script>
}
else
{
<script src="~/dist/app.min.js" asp-append-version="true"></script>
}
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>