fix: ajuste de warnings e combos
This commit is contained in:
parent
4a7cdbf26d
commit
dbd3c8851b
@ -38,7 +38,7 @@ namespace QRRapidoApp.Configuration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var secretValue = File.ReadAllText(secretFilePath).Trim();
|
var secretValue = (string?)File.ReadAllText(secretFilePath).Trim();
|
||||||
if (!string.IsNullOrEmpty(secretValue))
|
if (!string.IsNullOrEmpty(secretValue))
|
||||||
{
|
{
|
||||||
Data[configKey] = secretValue;
|
Data[configKey] = secretValue;
|
||||||
|
|||||||
@ -170,7 +170,9 @@ namespace QRRapidoApp.Controllers
|
|||||||
var user = await _userService.GetUserByProviderAsync(scheme, providerId);
|
var user = await _userService.GetUserByProviderAsync(scheme, providerId);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
user = await _userService.CreateUserAsync(email, name ?? email, scheme, providerId);
|
// Fix CS8625: Ensure name is not null
|
||||||
|
var safeName = !string.IsNullOrEmpty(name) ? name : (email ?? "User");
|
||||||
|
user = await _userService.CreateUserAsync(email, safeName, scheme, providerId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -180,10 +182,10 @@ namespace QRRapidoApp.Controllers
|
|||||||
// Create application claims
|
// Create application claims
|
||||||
var claims = new List<Claim>
|
var claims = new List<Claim>
|
||||||
{
|
{
|
||||||
new Claim(ClaimTypes.NameIdentifier, user.Id),
|
new Claim(ClaimTypes.NameIdentifier, user.Id ?? string.Empty), // Fix CS8625
|
||||||
new Claim(ClaimTypes.Email, user.Email),
|
new Claim(ClaimTypes.Email, user.Email ?? string.Empty), // Fix CS8625
|
||||||
new Claim(ClaimTypes.Name, user.Name),
|
new Claim(ClaimTypes.Name, user.Name ?? string.Empty), // Fix CS8625
|
||||||
new Claim("Provider", user.Provider),
|
new Claim("Provider", user.Provider ?? string.Empty),
|
||||||
new Claim("IsPremium", user.IsPremium.ToString())
|
new Claim("IsPremium", user.IsPremium.ToString())
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -230,6 +232,7 @@ namespace QRRapidoApp.Controllers
|
|||||||
return RedirectToAction("Login");
|
return RedirectToAction("Login");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure we are passing a non-null userId
|
||||||
ViewBag.QRHistory = await _userService.GetUserQRHistoryAsync(userId, 10);
|
ViewBag.QRHistory = await _userService.GetUserQRHistoryAsync(userId, 10);
|
||||||
ViewBag.MonthlyQRCount = await _userService.GetQRCountThisMonthAsync(userId);
|
ViewBag.MonthlyQRCount = await _userService.GetQRCountThisMonthAsync(userId);
|
||||||
ViewBag.IsPremium = await _adDisplayService.HasValidPremiumSubscription(userId);
|
ViewBag.IsPremium = await _adDisplayService.HasValidPremiumSubscription(userId);
|
||||||
|
|||||||
@ -33,20 +33,68 @@ namespace QRRapidoApp.Controllers
|
|||||||
_markdownService = markdownService;
|
_markdownService = markdownService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> Index()
|
// Default fallback route handled by Program.cs map
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> Index(string? qrType = null)
|
||||||
{
|
{
|
||||||
var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||||
|
|
||||||
ViewBag.ShowAds = await _adDisplayService.ShouldShowAds(userId);
|
// Pass the requested QR type to the view to auto-select in combo
|
||||||
ViewBag.IsPremium = await _adDisplayService.HasValidPremiumSubscription(userId ?? "");
|
ViewBag.SelectedQRType = qrType;
|
||||||
ViewBag.IsAuthenticated = User.Identity?.IsAuthenticated ?? false;
|
|
||||||
ViewBag.UserName = User.Identity?.Name ?? "";
|
|
||||||
_adDisplayService.SetViewBagAds(ViewBag);
|
|
||||||
|
|
||||||
// SEO and Analytics data
|
// Set SEO Meta Tags based on QR Type
|
||||||
|
if (!string.IsNullOrEmpty(qrType))
|
||||||
|
{
|
||||||
|
switch (qrType.ToLower())
|
||||||
|
{
|
||||||
|
case "pix":
|
||||||
|
ViewBag.Title = "Gerador de Pix Grátis";
|
||||||
|
ViewBag.Description = "Crie QR Code PIX estático gratuitamente. Ideal para receber pagamentos e doações.";
|
||||||
|
ViewBag.Keywords = "pix, qr code pix, gerador pix, pix estatico, receber pix";
|
||||||
|
break;
|
||||||
|
case "wifi":
|
||||||
|
ViewBag.Title = _localizer["WiFiQRTitle"];
|
||||||
|
ViewBag.Description = _localizer["WiFiQRDescription"];
|
||||||
|
break;
|
||||||
|
case "vcard":
|
||||||
|
ViewBag.Title = _localizer["VCardQRTitle"] ?? "Gerador de Cartão de Visita Digital";
|
||||||
|
ViewBag.Description = _localizer["VCardQRDescription"];
|
||||||
|
break;
|
||||||
|
case "whatsapp":
|
||||||
|
ViewBag.Title = "Gerador de Link WhatsApp";
|
||||||
|
ViewBag.Description = _localizer["WhatsAppQRDescription"];
|
||||||
|
break;
|
||||||
|
case "email":
|
||||||
|
ViewBag.Title = "Gerador de QR Code Email";
|
||||||
|
ViewBag.Description = _localizer["EmailQRDescription"];
|
||||||
|
break;
|
||||||
|
case "sms":
|
||||||
|
ViewBag.Title = "Gerador de QR Code SMS";
|
||||||
|
ViewBag.Description = _localizer["SMSQRDescription"];
|
||||||
|
break;
|
||||||
|
case "text":
|
||||||
|
ViewBag.Title = "Gerador de Texto para QR";
|
||||||
|
ViewBag.Description = _localizer["TextQRDescription"];
|
||||||
|
break;
|
||||||
|
case "url":
|
||||||
|
ViewBag.Title = "Gerador de URL para QR";
|
||||||
|
ViewBag.Description = _localizer["URLQRDescription"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default SEO
|
||||||
ViewBag.Title = _config["App:TaglinePT"];
|
ViewBag.Title = _config["App:TaglinePT"];
|
||||||
ViewBag.Keywords = _config["SEO:KeywordsPT"];
|
ViewBag.Keywords = _config["SEO:KeywordsPT"];
|
||||||
ViewBag.Description = _localizer["QRGenerateDescription"];
|
ViewBag.Description = _localizer["QRGenerateDescription"];
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewBag.ShowAds = await _adDisplayService.ShouldShowAds(userId);
|
||||||
|
ViewBag.IsPremium = await _adDisplayService.HasValidPremiumSubscription(userId ?? "");
|
||||||
|
ViewBag.IsAuthenticated = User?.Identity?.IsAuthenticated ?? false;
|
||||||
|
ViewBag.UserName = User?.Identity?.Name ?? "";
|
||||||
|
_adDisplayService.SetViewBagAds(ViewBag);
|
||||||
|
|
||||||
// User stats for logged in users
|
// User stats for logged in users
|
||||||
if (!string.IsNullOrEmpty(userId))
|
if (!string.IsNullOrEmpty(userId))
|
||||||
@ -55,9 +103,42 @@ namespace QRRapidoApp.Controllers
|
|||||||
ViewBag.MonthlyQRCount = await _userService.GetQRCountThisMonthAsync(userId);
|
ViewBag.MonthlyQRCount = await _userService.GetQRCountThisMonthAsync(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return View();
|
return View("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dedicated SEO Routes - These act as virtual pages
|
||||||
|
[Route("pix")]
|
||||||
|
[Route("{culture}/pix")]
|
||||||
|
public async Task<IActionResult> Pix() => await Index("pix");
|
||||||
|
|
||||||
|
[Route("wifi")]
|
||||||
|
[Route("{culture}/wifi")]
|
||||||
|
public async Task<IActionResult> Wifi() => await Index("wifi");
|
||||||
|
|
||||||
|
[Route("vcard")]
|
||||||
|
[Route("{culture}/vcard")]
|
||||||
|
public async Task<IActionResult> VCard() => await Index("vcard");
|
||||||
|
|
||||||
|
[Route("whatsapp")]
|
||||||
|
[Route("{culture}/whatsapp")]
|
||||||
|
public async Task<IActionResult> WhatsApp() => await Index("whatsapp");
|
||||||
|
|
||||||
|
[Route("email")]
|
||||||
|
[Route("{culture}/email")]
|
||||||
|
public async Task<IActionResult> Email() => await Index("email");
|
||||||
|
|
||||||
|
[Route("sms")]
|
||||||
|
[Route("{culture}/sms")]
|
||||||
|
public async Task<IActionResult> Sms() => await Index("sms");
|
||||||
|
|
||||||
|
[Route("text")]
|
||||||
|
[Route("{culture}/text")]
|
||||||
|
public async Task<IActionResult> Text() => await Index("text");
|
||||||
|
|
||||||
|
[Route("url")]
|
||||||
|
[Route("{culture}/url")]
|
||||||
|
public async Task<IActionResult> UrlType() => await Index("url");
|
||||||
|
|
||||||
public IActionResult Privacy()
|
public IActionResult Privacy()
|
||||||
{
|
{
|
||||||
var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||||
@ -238,7 +319,18 @@ namespace QRRapidoApp.Controllers
|
|||||||
AppendUrl("/pt-BR", "daily", "0.9");
|
AppendUrl("/pt-BR", "daily", "0.9");
|
||||||
AppendUrl("/es-PY", "daily", "0.9");
|
AppendUrl("/es-PY", "daily", "0.9");
|
||||||
|
|
||||||
|
// Tools (Virtual Pages)
|
||||||
|
var tools = new[] { "pix", "wifi", "vcard", "whatsapp", "email", "sms", "text", "url" };
|
||||||
var cultures = new[] { "pt-BR", "es-PY" };
|
var cultures = new[] { "pt-BR", "es-PY" };
|
||||||
|
|
||||||
|
foreach (var culture in cultures)
|
||||||
|
{
|
||||||
|
foreach (var tool in tools)
|
||||||
|
{
|
||||||
|
AppendUrl($"/{culture}/{tool}", "weekly", "0.9");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var informationalPages = new[]
|
var informationalPages = new[]
|
||||||
{
|
{
|
||||||
new { Path = "Home/About", ChangeFreq = "monthly", Priority = "0.8" },
|
new { Path = "Home/About", ChangeFreq = "monthly", Priority = "0.8" },
|
||||||
|
|||||||
@ -40,12 +40,8 @@ namespace QRRapidoApp.Middleware
|
|||||||
|
|
||||||
var detectedCulture = DetectBrowserLanguage(context);
|
var detectedCulture = DetectBrowserLanguage(context);
|
||||||
|
|
||||||
// If the detected culture is the default, do not redirect.
|
// ALWAYS Redirect to include culture in path for consistency and SEO
|
||||||
if (detectedCulture == DefaultCulture)
|
// This ensures /pix becomes /pt-BR/pix or /es-PY/pix
|
||||||
{
|
|
||||||
await _next(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var redirectUrl = $"/{detectedCulture}";
|
var redirectUrl = $"/{detectedCulture}";
|
||||||
if (!string.IsNullOrEmpty(path))
|
if (!string.IsNullOrEmpty(path))
|
||||||
|
|||||||
16
Program.cs
16
Program.cs
@ -30,22 +30,10 @@ using System.Threading.RateLimiting;
|
|||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using AspNetCore.DataProtection.MongoDb;
|
using AspNetCore.DataProtection.MongoDb;
|
||||||
|
|
||||||
// Fix for WSL path issues - disable StaticWebAssets completely
|
// Disable StaticWebAssets for WSL compatibility (keeping this as it might still be needed for your mixed env)
|
||||||
var options = new WebApplicationOptions
|
|
||||||
{
|
|
||||||
Args = args,
|
|
||||||
ContentRootPath = Directory.GetCurrentDirectory(),
|
|
||||||
WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")
|
|
||||||
};
|
|
||||||
|
|
||||||
// Disable StaticWebAssets for WSL compatibility
|
|
||||||
Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUP__STATICWEBASSETS__ENABLED", "false");
|
Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUP__STATICWEBASSETS__ENABLED", "false");
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(options);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add Docker Secrets as configuration source (for Swarm deployments)
|
|
||||||
// Secrets override values from appsettings.json
|
|
||||||
builder.Configuration.AddDockerSecrets();
|
|
||||||
|
|
||||||
// Configure Serilog
|
// Configure Serilog
|
||||||
var loggerConfig = new LoggerConfiguration()
|
var loggerConfig = new LoggerConfiguration()
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
|
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.1-dev-00953" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.1-dev-00953" />
|
||||||
<PackageReference Include="Serilog.Sinks.OpenSearch" Version="1.3.0" />
|
<PackageReference Include="Serilog.Sinks.OpenSearch" Version="1.3.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4" />
|
||||||
<PackageReference Include="Stripe.net" Version="48.4.0" />
|
<PackageReference Include="Stripe.net" Version="48.4.0" />
|
||||||
<PackageReference Include="StackExchange.Redis" Version="2.7.4" />
|
<PackageReference Include="StackExchange.Redis" Version="2.7.4" />
|
||||||
|
|||||||
@ -760,6 +760,9 @@
|
|||||||
<data name="FastestQRGeneratorDescription" xml:space="preserve">
|
<data name="FastestQRGeneratorDescription" xml:space="preserve">
|
||||||
<value>El generador de códigos QR pya'eve (ás rápido) de la web. Rei rehe (Gratis), seguro y confiable.</value>
|
<value>El generador de códigos QR pya'eve (ás rápido) de la web. Rei rehe (Gratis), seguro y confiable.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Tools" xml:space="preserve">
|
||||||
|
<value>Herramientas</value>
|
||||||
|
</data>
|
||||||
<data name="UsefulLinks" xml:space="preserve">
|
<data name="UsefulLinks" xml:space="preserve">
|
||||||
<value>Enlaces Útiles</value>
|
<value>Enlaces Útiles</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@ -813,6 +813,9 @@
|
|||||||
<data name="FastestQRGeneratorDescription" xml:space="preserve">
|
<data name="FastestQRGeneratorDescription" xml:space="preserve">
|
||||||
<value>O gerador de QR codes mais rápido da web. Grátis, seguro e confiável.</value>
|
<value>O gerador de QR codes mais rápido da web. Grátis, seguro e confiável.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Tools" xml:space="preserve">
|
||||||
|
<value>Ferramentas</value>
|
||||||
|
</data>
|
||||||
<data name="UsefulLinks" xml:space="preserve">
|
<data name="UsefulLinks" xml:space="preserve">
|
||||||
<value>Links Úteis</value>
|
<value>Links Úteis</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@ -97,24 +97,38 @@ namespace QRRapidoApp.Services
|
|||||||
switch (stripeEvent.Type)
|
switch (stripeEvent.Type)
|
||||||
{
|
{
|
||||||
case "checkout.session.completed":
|
case "checkout.session.completed":
|
||||||
var session = stripeEvent.Data.Object as Session;
|
if (stripeEvent.Data.Object is Session session)
|
||||||
if (session?.SubscriptionId != null)
|
{
|
||||||
|
if (session.SubscriptionId != null)
|
||||||
{
|
{
|
||||||
var subscriptionService = new SubscriptionService();
|
var subscriptionService = new SubscriptionService();
|
||||||
var subscription = await subscriptionService.GetAsync(session.SubscriptionId);
|
var subscription = await subscriptionService.GetAsync(session.SubscriptionId);
|
||||||
await ProcessSubscriptionActivation(session.ClientReferenceId, subscription);
|
// Fix CS8604: Ensure ClientReferenceId is not null
|
||||||
|
var userId = session.ClientReferenceId ??
|
||||||
|
(session.Metadata != null && session.Metadata.ContainsKey("user_id") ? session.Metadata["user_id"] : null);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(userId))
|
||||||
|
{
|
||||||
|
await ProcessSubscriptionActivation(userId, subscription);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Missing userId in checkout session {session.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "invoice.finalized":
|
case "invoice.finalized":
|
||||||
var invoice = stripeEvent.Data.Object as Invoice;
|
if (stripeEvent.Data.Object is Invoice invoice)
|
||||||
|
{
|
||||||
var subscriptionLineItem = invoice.Lines?.Data
|
var subscriptionLineItem = invoice.Lines?.Data
|
||||||
.FirstOrDefault(line =>
|
.FirstOrDefault(line =>
|
||||||
!string.IsNullOrEmpty(line.SubscriptionId) ||
|
!string.IsNullOrEmpty(line.SubscriptionId) ||
|
||||||
line.Subscription != null
|
line.Subscription != null
|
||||||
);
|
);
|
||||||
|
|
||||||
string subscriptionId = null;
|
string? subscriptionId = null;
|
||||||
|
|
||||||
if (subscriptionLineItem != null)
|
if (subscriptionLineItem != null)
|
||||||
{
|
{
|
||||||
@ -133,11 +147,11 @@ namespace QRRapidoApp.Services
|
|||||||
await ProcessSubscriptionActivation(user.Id, subscription);
|
await ProcessSubscriptionActivation(user.Id, subscription);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "customer.subscription.deleted":
|
case "customer.subscription.deleted":
|
||||||
var deletedSubscription = stripeEvent.Data.Object as Subscription;
|
if (stripeEvent.Data.Object is Subscription deletedSubscription)
|
||||||
if (deletedSubscription != null)
|
|
||||||
{
|
{
|
||||||
await _userService.DeactivatePremiumStatus(deletedSubscription.Id);
|
await _userService.DeactivatePremiumStatus(deletedSubscription.Id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1580,6 +1580,24 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-select QR Type from Server Route (SEO)
|
||||||
|
const serverSelectedType = '@(ViewBag.SelectedQRType ?? "")';
|
||||||
|
if (serverSelectedType) {
|
||||||
|
const qrTypeSelect = document.getElementById('qr-type');
|
||||||
|
if (qrTypeSelect) {
|
||||||
|
// Find option with this value (case-insensitive)
|
||||||
|
const option = Array.from(qrTypeSelect.options).find(opt =>
|
||||||
|
opt.value.toLowerCase() === serverSelectedType.toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (option) {
|
||||||
|
qrTypeSelect.value = option.value;
|
||||||
|
// Trigger change event to load correct interface
|
||||||
|
qrTypeSelect.dispatchEvent(new Event('change'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -404,15 +404,24 @@
|
|||||||
<h5>QR Rapido</h5>
|
<h5>QR Rapido</h5>
|
||||||
<p class="small">@Localizer["FastestQRGeneratorDescription"]</p>
|
<p class="small">@Localizer["FastestQRGeneratorDescription"]</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-2">
|
||||||
|
<h6>@Localizer["Tools"]</h6>
|
||||||
|
<ul class="list-unstyled small">
|
||||||
|
<li><a href="/pix" class="text-light text-decoration-none">Gerador de PIX</a></li>
|
||||||
|
<li><a href="/wifi" class="text-light text-decoration-none">QR Code WiFi</a></li>
|
||||||
|
<li><a href="/whatsapp" class="text-light text-decoration-none">Link WhatsApp</a></li>
|
||||||
|
<li><a href="/vcard" class="text-light text-decoration-none">Cartão Digital</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
<h6>@Localizer["UsefulLinks"]</h6>
|
<h6>@Localizer["UsefulLinks"]</h6>
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled small">
|
||||||
<li><a href="@Url.Action("Privacy", "Home")" class="text-light">@Localizer["Privacy"]</a></li>
|
<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("Terms", "Home")" class="text-light">@Localizer["TermsOfUse"]</a></li>
|
||||||
<li><a href="@Url.Action("Upgrade", "Premium")" class="text-warning">Premium</a></li>
|
<li><a href="@Url.Action("Upgrade", "Premium")" class="text-warning">Premium</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-2">
|
||||||
<h6>@Localizer["Support"]</h6>
|
<h6>@Localizer["Support"]</h6>
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li><a href="mailto:contato@qrrapido.site" class="text-light">Contato</a></li>
|
<li><a href="mailto:contato@qrrapido.site" class="text-light">Contato</a></li>
|
||||||
|
|||||||
@ -1994,8 +1994,8 @@ class QRRapidoGenerator {
|
|||||||
const urlPreview = document.getElementById('url-preview');
|
const urlPreview = document.getElementById('url-preview');
|
||||||
|
|
||||||
// Helper to safely hide
|
// Helper to safely hide
|
||||||
const safeHide = (el) => { if (el) el.style.display = 'none'; };
|
const safeHide = (el) => { if (el) { el.style.display = 'none'; el.classList.add('disabled-state'); } };
|
||||||
const safeShow = (el) => { if (el) el.style.display = 'block'; };
|
const safeShow = (el) => { if (el) { el.style.display = 'block'; el.classList.remove('disabled-state'); } };
|
||||||
|
|
||||||
// 1. Hide EVERYTHING specific first
|
// 1. Hide EVERYTHING specific first
|
||||||
safeHide(vcardInterface);
|
safeHide(vcardInterface);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user