From c6129a1c63a3fa5a68269cb85f6ec2d61182717b Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro Date: Sat, 16 Aug 2025 18:55:17 -0300 Subject: [PATCH] feat: links sociais opcionais --- src/BCards.Web/Controllers/AdminController.cs | 25 + .../ViewModels/CreatePageViewModel.cs | 4 - src/BCards.Web/Views/Admin/CreatePage.cshtml | 16 +- src/BCards.Web/Views/Admin/ManagePage.cshtml | 505 +++++++++++++++--- 4 files changed, 469 insertions(+), 81 deletions(-) diff --git a/src/BCards.Web/Controllers/AdminController.cs b/src/BCards.Web/Controllers/AdminController.cs index 2786714..89dfb18 100644 --- a/src/BCards.Web/Controllers/AdminController.cs +++ b/src/BCards.Web/Controllers/AdminController.cs @@ -4,6 +4,7 @@ using BCards.Web.Utils; using BCards.Web.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; using System.Security.Claims; namespace BCards.Web.Controllers; @@ -159,8 +160,16 @@ public class AdminController : Controller if (user == null) return RedirectToAction("Login", "Auth"); + // Limpar campos de redes sociais que são apenas espaços (tratados como vazios) + CleanSocialMediaFields(model); + _logger.LogInformation($"ManagePage POST: IsNewPage={model.IsNewPage}, DisplayName={model.DisplayName}, Category={model.Category}, Links={model.Links?.Count ?? 0}"); + ModelState.Remove(x => x.InstagramUrl); + ModelState.Remove(x => x.FacebookUrl); + ModelState.Remove(x => x.TwitterUrl); + ModelState.Remove(x => x.WhatsAppNumber); + if (!ModelState.IsValid) { _logger.LogWarning("ModelState is invalid:"); @@ -958,4 +967,20 @@ public class AdminController : Controller }); } } + + private void CleanSocialMediaFields(ManagePageViewModel model) + { + // Tratar espaço em branco como campo vazio para redes sociais + if (string.IsNullOrWhiteSpace(model.WhatsAppNumber) || model.WhatsAppNumber.Trim().Length <= 1) + model.WhatsAppNumber = string.Empty; + + if (string.IsNullOrWhiteSpace(model.FacebookUrl) || model.FacebookUrl.Trim().Length <= 1) + model.FacebookUrl = string.Empty; + + if (string.IsNullOrWhiteSpace(model.InstagramUrl) || model.InstagramUrl.Trim().Length <= 1) + model.InstagramUrl = string.Empty; + + if (string.IsNullOrWhiteSpace(model.TwitterUrl) || model.TwitterUrl.Trim().Length <= 1) + model.TwitterUrl = string.Empty; + } } \ No newline at end of file diff --git a/src/BCards.Web/ViewModels/CreatePageViewModel.cs b/src/BCards.Web/ViewModels/CreatePageViewModel.cs index 510be65..338b7a3 100644 --- a/src/BCards.Web/ViewModels/CreatePageViewModel.cs +++ b/src/BCards.Web/ViewModels/CreatePageViewModel.cs @@ -20,16 +20,12 @@ public class CreatePageViewModel [Required(ErrorMessage = "Tema é obrigatório")] public string SelectedTheme { get; set; } = "minimalist"; - [Phone(ErrorMessage = "Número de WhatsApp inválido")] public string WhatsAppNumber { get; set; } = string.Empty; - [Url(ErrorMessage = "URL do Facebook inválida")] public string FacebookUrl { get; set; } = string.Empty; - [Url(ErrorMessage = "URL do X/Twitter inválida")] public string TwitterUrl { get; set; } = string.Empty; - [Url(ErrorMessage = "URL do Instagram inválida")] public string InstagramUrl { get; set; } = string.Empty; public List Links { get; set; } = new(); diff --git a/src/BCards.Web/Views/Admin/CreatePage.cshtml b/src/BCards.Web/Views/Admin/CreatePage.cshtml index bba9113..fd057ca 100644 --- a/src/BCards.Web/Views/Admin/CreatePage.cshtml +++ b/src/BCards.Web/Views/Admin/CreatePage.cshtml @@ -548,18 +548,26 @@ function generateLinksData() { } }); - // Create hidden inputs for links - $('#linksContainer').append('
'); - $('#linksData').empty(); + // Remove existing hidden link inputs + $('input[name^="Links["]').remove(); + // Create hidden inputs for links directly in the form links.forEach((link, index) => { - $('#linksData').append(` + $('#createPageForm').append(` `); }); + + // Debug: Log what we're sending + console.log('=== DEBUG GENERATELINKSDATA ==='); + console.log('Links found:', links.length); + links.forEach((link, index) => { + console.log(`Link ${index}:`, link); + }); + console.log('=== FIM DEBUG ==='); } function generatePreview() { diff --git a/src/BCards.Web/Views/Admin/ManagePage.cshtml b/src/BCards.Web/Views/Admin/ManagePage.cshtml index a57e256..0615aa5 100644 --- a/src/BCards.Web/Views/Admin/ManagePage.cshtml +++ b/src/BCards.Web/Views/Admin/ManagePage.cshtml @@ -354,53 +354,96 @@
-

Conecte suas redes sociais (todos os campos são opcionais):

- -
-
-
- - - -
-
- -
-
- - - -
-
+
+ + Redes Sociais Opcionais +

Marque apenas as redes sociais que você quer conectar. Todas são opcionais e você pode pular esta etapa.

-
-
- - - +
+ +
+
+ + +
+ + Exemplo: 5511999999999 (código do país + DDD + número) + + +
+ + +
+
+ + +
+ + +
-
-
- - +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ + + +
@@ -408,15 +451,10 @@ -
- - -
+
@@ -674,6 +712,60 @@ box-shadow: 0 4px 8px rgba(0,0,0,0.15); } +/* Social Media Input Groups */ +.social-input-group .input-group-text { + min-width: 180px; + justify-content: flex-start; + background-color: #f8f9fa; + border-right: none; + font-size: 0.9rem; + font-weight: 500; +} + +.social-input-group .form-control { + border-left: none; +} + +.social-input-group .form-control:focus { + border-color: #80bdff; + box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25); +} + +.form-check-label { + cursor: pointer; + font-weight: 500; + transition: color 0.2s ease; +} + +.form-check-label:hover { + color: #0056b3; +} + +.form-check-input:checked + .form-check-label { + color: #198754; +} + +.social-input-group { + transition: all 0.3s ease; +} + +/* Estados de validação */ +.form-control.is-valid { + border-color: #198754; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='m2.3 6.73.99-.99 1.99-1.99L6.98 2.99l-.99-.99L4.49 3.5 3.5 2.51 2.51 3.5z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.form-control.is-invalid { + border-color: #dc3545; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath d='m5.8 4.6 1.4 1.4m0 0 1.4 1.4m-1.4-1.4L5.8 8.4m1.4-1.4L8.6 5.6'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + /* Product Link Preview Styles */ .product-link-preview { background: rgba(25, 135, 84, 0.05); @@ -709,6 +801,27 @@ let currentStep = 1; $(document).ready(function() { + // Initialize social media fields + initializeSocialMedia(); + + // Check for validation errors and show toast + open accordion + checkValidationErrors(); + + // Garantir que campos não marcados sejam string vazia ao submeter + $('form').on('submit', function() { + ensureUncheckedFieldsAreEmpty(); + + // Debug: Verificar quais campos de links estão sendo enviados + console.log('=== DEBUG FORM SUBMISSION ==='); + const formData = new FormData(this); + for (let [key, value] of formData.entries()) { + if (key.includes('Links[')) { + console.log(`${key}: ${value}`); + } + } + console.log('=== FIM DEBUG ==='); + }); + // Generate slug when name or category changes $('#DisplayName, #Category').on('input change', function() { generateSlug(); @@ -867,13 +980,27 @@ } function addLinkInput(title = '', url = '', description = '', icon = '', linkType = 'Normal', id='new') { + // Encontrar o próximo índice disponível baseado em todos os campos Links[] existentes + const existingIndexes = []; + $('input[name^="Links["]').each(function() { + const name = $(this).attr('name'); + const match = name.match(/Links\[(\d+)\]/); + if (match) { + existingIndexes.push(parseInt(match[1])); + } + }); + + // Encontrar o próximo índice disponível + const nextIndex = existingIndexes.length > 0 ? Math.max(...existingIndexes) + 1 : 0; + const iconHtml = icon ? `` : ''; + const displayCount = $('.link-input-group').length + 1; const linkHtml = ` -