All checks were successful
BCards Deployment Pipeline / Run Tests (push) Successful in 4s
BCards Deployment Pipeline / PR Validation (push) Has been skipped
BCards Deployment Pipeline / Build and Push Image (push) Successful in 15m22s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 1m54s
BCards Deployment Pipeline / Deploy to Test (x86 - Local) (push) Has been skipped
BCards Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Deployment Pipeline / Deployment Summary (push) Successful in 0s
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
618 lines
24 KiB
Plaintext
618 lines
24 KiB
Plaintext
@model BCards.Web.ViewModels.CreatePageViewModel
|
|
@{
|
|
ViewData["Title"] = "Criar Página";
|
|
Layout = "_Layout";
|
|
}
|
|
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12 col-lg-8 mx-auto">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-primary text-white">
|
|
<h4 class="mb-0">
|
|
<i class="fas fa-magic"></i>
|
|
Criar Sua Página de Links
|
|
</h4>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<!-- Progress Bar -->
|
|
<div class="progress mb-4" style="height: 8px;">
|
|
<div class="progress-bar" role="progressbar" style="width: 20%" id="wizardProgress"></div>
|
|
</div>
|
|
|
|
<form asp-action="CreatePage" method="post" id="createPageForm">
|
|
|
|
<!-- Step 1: Informações Básicas -->
|
|
<div class="wizard-step" id="step1">
|
|
<h5 class="step-title">
|
|
<span class="step-number">1</span>
|
|
Informações Básicas
|
|
</h5>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="DisplayName" class="form-label">Nome da Página</label>
|
|
<input asp-for="DisplayName" class="form-control" placeholder="Ex: João Silva">
|
|
<span asp-validation-for="DisplayName" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="Category" class="form-label">Categoria</label>
|
|
<select asp-for="Category" class="form-select">
|
|
<option value="">Selecione uma categoria</option>
|
|
@foreach (var category in ViewBag.Categories as List<BCards.Web.Models.Category> ?? new List<BCards.Web.Models.Category>())
|
|
{
|
|
<option value="@category.Name">@category.Name</option>
|
|
}
|
|
</select>
|
|
<span asp-validation-for="Category" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="BusinessType" class="form-label">Tipo</label>
|
|
<select asp-for="BusinessType" class="form-select">
|
|
<option value="individual">Pessoa Física</option>
|
|
<option value="company">Empresa</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="slugPreview" class="form-label">URL da Página</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">page/</span>
|
|
<span class="input-group-text" id="categorySlug">categoria</span>
|
|
<span class="input-group-text">/</span>
|
|
<input type="text" class="form-control" id="slugPreview" readonly>
|
|
<input asp-for="Slug" type="hidden">
|
|
</div>
|
|
<small class="form-text text-muted">URL gerada automaticamente</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label asp-for="Bio" class="form-label">Bio/Descrição</label>
|
|
<textarea asp-for="Bio" class="form-control" rows="3" placeholder="Uma breve descrição sobre você ou sua empresa..."></textarea>
|
|
<span asp-validation-for="Bio" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2: Seleção de Tema -->
|
|
<div class="wizard-step d-none" id="step2">
|
|
<h5 class="step-title">
|
|
<span class="step-number">2</span>
|
|
Escolha Seu Tema Visual
|
|
</h5>
|
|
|
|
<div class="row">
|
|
@foreach (var theme in ViewBag.Themes as List<BCards.Web.Models.PageTheme> ?? new List<BCards.Web.Models.PageTheme>())
|
|
{
|
|
<div class="col-md-4 mb-3">
|
|
<div class="theme-card" data-theme="@theme.Name.ToLower()">
|
|
<div class="theme-preview" style="background: @theme.BackgroundColor; color: @theme.TextColor;">
|
|
<div class="theme-header" style="background-color: @theme.PrimaryColor;">
|
|
<div class="theme-avatar"></div>
|
|
<h6>@theme.Name</h6>
|
|
</div>
|
|
<div class="theme-links">
|
|
<div class="theme-link" style="background-color: @theme.PrimaryColor;"></div>
|
|
<div class="theme-link" style="background-color: @theme.SecondaryColor;"></div>
|
|
</div>
|
|
</div>
|
|
<div class="theme-name">
|
|
@theme.Name
|
|
@if (theme.IsPremium)
|
|
{
|
|
<span class="badge bg-warning">Premium</span>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<input asp-for="SelectedTheme" type="hidden">
|
|
</div>
|
|
|
|
<!-- Step 3: Links Principais -->
|
|
<div class="wizard-step d-none" id="step3">
|
|
<h5 class="step-title">
|
|
<span class="step-number">3</span>
|
|
Links Principais
|
|
</h5>
|
|
|
|
<div id="linksContainer">
|
|
<!-- Links will be added dynamically -->
|
|
</div>
|
|
|
|
<button type="button" class="btn btn-outline-primary" id="addLinkBtn">
|
|
<i class="fas fa-plus"></i> Adicionar Link
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Step 4: Redes Sociais -->
|
|
<div class="wizard-step d-none" id="step4">
|
|
<h5 class="step-title">
|
|
<span class="step-number">4</span>
|
|
Redes Sociais
|
|
</h5>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="WhatsAppNumber" class="form-label">
|
|
<i class="fab fa-whatsapp text-success"></i>
|
|
WhatsApp
|
|
</label>
|
|
<input asp-for="WhatsAppNumber" class="form-control" placeholder="+55 11 99999-9999">
|
|
<span asp-validation-for="WhatsAppNumber" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="FacebookUrl" class="form-label">
|
|
<i class="fab fa-facebook text-primary"></i>
|
|
Facebook
|
|
</label>
|
|
<input asp-for="FacebookUrl" class="form-control" placeholder="https://facebook.com/seu-perfil">
|
|
<span asp-validation-for="FacebookUrl" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="TwitterUrl" class="form-label">
|
|
<i class="fab fa-x-twitter"></i>
|
|
X / Twitter
|
|
</label>
|
|
<input asp-for="TwitterUrl" class="form-control" placeholder="https://x.com/seu-perfil">
|
|
<span asp-validation-for="TwitterUrl" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="InstagramUrl" class="form-label">
|
|
<i class="fab fa-instagram text-danger"></i>
|
|
Instagram
|
|
</label>
|
|
<input asp-for="InstagramUrl" class="form-control" placeholder="https://instagram.com/seu-perfil">
|
|
<span asp-validation-for="InstagramUrl" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 5: Preview e Finalização -->
|
|
<div class="wizard-step d-none" id="step5">
|
|
<h5 class="step-title">
|
|
<span class="step-number">5</span>
|
|
Preview e Finalização
|
|
</h5>
|
|
|
|
<div class="preview-container">
|
|
<div class="preview-phone">
|
|
<div class="preview-screen" id="previewScreen">
|
|
<!-- Preview will be generated here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-center mt-4">
|
|
<p class="text-muted">Sua página estará disponível em:</p>
|
|
<strong id="finalUrl">page/categoria/seu-slug</strong>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Navigation Buttons -->
|
|
<div class="wizard-navigation mt-4">
|
|
<button type="button" class="btn btn-secondary" id="prevBtn" style="display: none;">
|
|
<i class="fas fa-arrow-left"></i> Anterior
|
|
</button>
|
|
|
|
<button type="button" class="btn btn-primary float-end" id="nextBtn">
|
|
Próximo <i class="fas fa-arrow-right"></i>
|
|
</button>
|
|
|
|
<button type="submit" class="btn btn-success float-end d-none" id="submitBtn">
|
|
<i class="fas fa-check"></i> Criar Página
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.wizard-step {
|
|
min-height: 400px;
|
|
}
|
|
|
|
.step-title {
|
|
color: #495057;
|
|
margin-bottom: 2rem;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 2px solid #e9ecef;
|
|
}
|
|
|
|
.step-number {
|
|
display: inline-block;
|
|
width: 30px;
|
|
height: 30px;
|
|
line-height: 30px;
|
|
background-color: #007bff;
|
|
color: white;
|
|
border-radius: 50%;
|
|
text-align: center;
|
|
margin-right: 0.5rem;
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.theme-card {
|
|
cursor: pointer;
|
|
border: 2px solid transparent;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.theme-card:hover,
|
|
.theme-card.selected {
|
|
border-color: #007bff;
|
|
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
|
|
}
|
|
|
|
.theme-preview {
|
|
height: 120px;
|
|
position: relative;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.theme-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.5rem;
|
|
border-radius: 4px;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.theme-avatar {
|
|
width: 20px;
|
|
height: 20px;
|
|
border-radius: 50%;
|
|
background-color: rgba(255, 255, 255, 0.3);
|
|
}
|
|
|
|
.theme-header h6 {
|
|
margin: 0;
|
|
font-size: 0.75rem;
|
|
color: white;
|
|
}
|
|
|
|
.theme-links {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.theme-link {
|
|
height: 8px;
|
|
border-radius: 4px;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.theme-name {
|
|
padding: 0.75rem;
|
|
text-align: center;
|
|
font-weight: 500;
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.link-input-group {
|
|
background-color: #f8f9fa;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 8px;
|
|
padding: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.preview-container {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
min-height: 300px;
|
|
}
|
|
|
|
.preview-phone {
|
|
width: 300px;
|
|
height: 400px;
|
|
border: 8px solid #333;
|
|
border-radius: 20px;
|
|
background-color: #000;
|
|
padding: 20px 10px;
|
|
position: relative;
|
|
}
|
|
|
|
.preview-screen {
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: #fff;
|
|
border-radius: 12px;
|
|
overflow-y: auto;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.wizard-navigation {
|
|
border-top: 1px solid #dee2e6;
|
|
padding-top: 1rem;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
let currentStep = 1;
|
|
const totalSteps = 5;
|
|
let linkCount = 0;
|
|
|
|
$(document).ready(function() {
|
|
initializeWizard();
|
|
|
|
// Generate slug when name or category changes
|
|
$('#DisplayName, #Category').on('input change', function() {
|
|
generateSlug();
|
|
});
|
|
|
|
// Theme selection
|
|
$('.theme-card').on('click', function() {
|
|
$('.theme-card').removeClass('selected');
|
|
$(this).addClass('selected');
|
|
const themeName = $(this).data('theme');
|
|
$('#SelectedTheme').val(themeName);
|
|
});
|
|
|
|
// Navigation
|
|
$('#nextBtn').on('click', function() {
|
|
if (validateCurrentStep()) {
|
|
nextStep();
|
|
}
|
|
});
|
|
|
|
$('#prevBtn').on('click', function() {
|
|
prevStep();
|
|
});
|
|
|
|
// Add link functionality
|
|
$('#addLinkBtn').on('click', function() {
|
|
addLinkInput();
|
|
});
|
|
|
|
// Form submission
|
|
$('#createPageForm').on('submit', function(e) {
|
|
generateLinksData();
|
|
});
|
|
});
|
|
|
|
function initializeWizard() {
|
|
updateProgressBar();
|
|
updateNavigationButtons();
|
|
addLinkInput(); // Add first link input
|
|
}
|
|
|
|
function nextStep() {
|
|
if (currentStep < totalSteps) {
|
|
$(`#step${currentStep}`).addClass('d-none');
|
|
currentStep++;
|
|
$(`#step${currentStep}`).removeClass('d-none');
|
|
|
|
if (currentStep === 5) {
|
|
generatePreview();
|
|
}
|
|
|
|
updateProgressBar();
|
|
updateNavigationButtons();
|
|
}
|
|
}
|
|
|
|
function prevStep() {
|
|
if (currentStep > 1) {
|
|
$(`#step${currentStep}`).addClass('d-none');
|
|
currentStep--;
|
|
$(`#step${currentStep}`).removeClass('d-none');
|
|
updateProgressBar();
|
|
updateNavigationButtons();
|
|
}
|
|
}
|
|
|
|
function updateProgressBar() {
|
|
const progress = (currentStep / totalSteps) * 100;
|
|
$('#wizardProgress').css('width', progress + '%');
|
|
}
|
|
|
|
function updateNavigationButtons() {
|
|
$('#prevBtn').toggle(currentStep > 1);
|
|
|
|
if (currentStep === totalSteps) {
|
|
$('#nextBtn').addClass('d-none');
|
|
$('#submitBtn').removeClass('d-none');
|
|
} else {
|
|
$('#nextBtn').removeClass('d-none');
|
|
$('#submitBtn').addClass('d-none');
|
|
}
|
|
}
|
|
|
|
function validateCurrentStep() {
|
|
let isValid = true;
|
|
|
|
switch (currentStep) {
|
|
case 1:
|
|
if (!$('#DisplayName').val() || !$('#Category').val()) {
|
|
alert('Por favor, preencha o nome e a categoria.');
|
|
isValid = false;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (!$('#SelectedTheme').val()) {
|
|
alert('Por favor, selecione um tema.');
|
|
isValid = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
function generateSlug() {
|
|
const name = $('#DisplayName').val();
|
|
const category = $('#Category').val();
|
|
|
|
if (name && category) {
|
|
$.post('/Admin/GenerateSlug', { category: category, name: name })
|
|
.done(function(data) {
|
|
$('#Slug').val(data.slug);
|
|
$('#slugPreview').val(data.slug);
|
|
$('#categorySlug').text(category);
|
|
$('#finalUrl').text(`page/${category}/${data.slug}`);
|
|
});
|
|
}
|
|
}
|
|
|
|
function addLinkInput() {
|
|
linkCount++;
|
|
const linkHtml = `
|
|
<div class="link-input-group" data-link="${linkCount}">
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<h6 class="mb-0">Link ${linkCount}</h6>
|
|
<button type="button" class="btn btn-sm btn-outline-danger remove-link-btn">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-2">
|
|
<label class="form-label">Título</label>
|
|
<input type="text" class="form-control link-title" placeholder="Ex: Meu Site">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-2">
|
|
<label class="form-label">URL</label>
|
|
<input type="url" class="form-control link-url" placeholder="https://exemplo.com">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<label class="form-label">Descrição (opcional)</label>
|
|
<input type="text" class="form-control link-description" placeholder="Breve descrição do link">
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
$('#linksContainer').append(linkHtml);
|
|
|
|
// Add remove functionality
|
|
$('.remove-link-btn').off('click').on('click', function() {
|
|
$(this).closest('.link-input-group').remove();
|
|
});
|
|
}
|
|
|
|
function generateLinksData() {
|
|
const links = [];
|
|
$('.link-input-group').each(function() {
|
|
const title = $(this).find('.link-title').val();
|
|
const url = $(this).find('.link-url').val();
|
|
const description = $(this).find('.link-description').val();
|
|
|
|
if (title && url) {
|
|
links.push({
|
|
Title: title,
|
|
Url: url,
|
|
Description: description,
|
|
Icon: ''
|
|
});
|
|
}
|
|
});
|
|
|
|
// Remove existing hidden link inputs
|
|
$('input[name^="Links["]').remove();
|
|
|
|
// Create hidden inputs for links directly in the form
|
|
links.forEach((link, index) => {
|
|
$('#createPageForm').append(`
|
|
<input type="hidden" name="Links[${index}].Title" value="${link.Title}" />
|
|
<input type="hidden" name="Links[${index}].Url" value="${link.Url}" />
|
|
<input type="hidden" name="Links[${index}].Description" value="${link.Description}" />
|
|
<input type="hidden" name="Links[${index}].Icon" value="${link.Icon}" />
|
|
`);
|
|
});
|
|
|
|
// 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() {
|
|
const name = $('#DisplayName').val();
|
|
const bio = $('#Bio').val();
|
|
const selectedTheme = $('#SelectedTheme').val();
|
|
|
|
let previewHtml = `
|
|
<div class="text-center">
|
|
<div class="mb-3">
|
|
<div style="width: 60px; height: 60px; background-color: #ddd; border-radius: 50%; margin: 0 auto;"></div>
|
|
</div>
|
|
<h5 class="mb-2">${name}</h5>
|
|
<p class="text-muted small mb-3">${bio}</p>
|
|
<div class="d-grid gap-2">
|
|
`;
|
|
|
|
// Add links preview
|
|
$('.link-input-group').each(function() {
|
|
const title = $(this).find('.link-title').val();
|
|
if (title) {
|
|
previewHtml += `<div class="btn btn-primary btn-sm">${title}</div>`;
|
|
}
|
|
});
|
|
|
|
// Add social media preview
|
|
if ($('#WhatsAppNumber').val()) {
|
|
previewHtml += `<div class="btn btn-success btn-sm"><i class="fab fa-whatsapp"></i> WhatsApp</div>`;
|
|
}
|
|
if ($('#FacebookUrl').val()) {
|
|
previewHtml += `<div class="btn btn-primary btn-sm"><i class="fab fa-facebook"></i> Facebook</div>`;
|
|
}
|
|
if ($('#TwitterUrl').val()) {
|
|
previewHtml += `<div class="btn btn-dark btn-sm"><i class="fab fa-x-twitter"></i> X / Twitter</div>`;
|
|
}
|
|
if ($('#InstagramUrl').val()) {
|
|
previewHtml += `<div class="btn btn-danger btn-sm"><i class="fab fa-instagram"></i> Instagram</div>`;
|
|
}
|
|
|
|
previewHtml += `</div></div>`;
|
|
|
|
$('#previewScreen').html(previewHtml);
|
|
}
|
|
</script>
|
|
|
|
@section Scripts {
|
|
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
|
} |