feat/live-preview #1

Merged
ricardo merged 16 commits from feat/live-preview into Release/V0.0.3 2025-07-23 02:24:34 +00:00
2 changed files with 86 additions and 22 deletions
Showing only changes of commit 7df77b371a - Show all commits

View File

@ -457,17 +457,32 @@ public class AdminController : Controller
} }
[HttpPost] [HttpPost]
public async Task<IActionResult> DeletePage() [Route("DeletePage/{id}")]
public async Task<IActionResult> DeletePage(string id)
{ {
var user = await _authService.GetCurrentUserAsync(User); var user = await _authService.GetCurrentUserAsync(User);
if (user == null) if (user == null)
return RedirectToAction("Login", "Auth"); return RedirectToAction("Login", "Auth");
var userPage = await _userPageService.GetUserPageAsync(user.Id); try
if (userPage != null)
{ {
await _userPageService.DeletePageAsync(userPage.Id); // Verificar se a página existe e pertence ao usuário
TempData["Success"] = "Página excluída com sucesso!"; var page = await _userPageService.GetPageByIdAsync(id);
if (page == null || page.UserId != user.Id)
{
TempData["Error"] = "Página não encontrada ou você não tem permissão para excluí-la.";
return RedirectToAction("Dashboard");
}
// Excluir a página
await _userPageService.DeletePageAsync(id);
TempData["Success"] = $"Página '{page.DisplayName}' excluída com sucesso!";
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao excluir página com ID: {PageId}", id);
TempData["Error"] = "Erro ao excluir página. Tente novamente.";
} }
return RedirectToAction("Dashboard"); return RedirectToAction("Dashboard");

View File

@ -15,7 +15,7 @@
<div> <div>
@if (!string.IsNullOrEmpty(Model.CurrentUser.ProfileImage)) @if (!string.IsNullOrEmpty(Model.CurrentUser.ProfileImage))
{ {
<img src="@Model.CurrentUser.ProfileImage" alt="@Model.CurrentUser.Name" <img src="@Model.CurrentUser.ProfileImage" alt="@Model.CurrentUser.Name"
class="rounded-circle" style="width: 60px; height: 60px; object-fit: cover;"> class="rounded-circle" style="width: 60px; height: 60px; object-fit: cover;">
} }
</div> </div>
@ -27,10 +27,19 @@
{ {
<div class="col-md-6 col-lg-4 mb-3"> <div class="col-md-6 col-lg-4 mb-3">
<div class="card h-100 @(page.Status == BCards.Web.ViewModels.PageStatus.Active ? "" : "border-warning")"> <div class="card h-100 @(page.Status == BCards.Web.ViewModels.PageStatus.Active ? "" : "border-warning")">
<div class="card-body"> <div class="card-body position-relative" style="padding-top: 20px;">
<h6 class="card-title">@(page.DisplayName)</h6> <!-- Botão de excluir no canto superior direito -->
<button class="btn btn-sm btn-outline-danger position-absolute"
style="top: 8px; right: 8px; z-index: 10; padding: 4px 6px;"
data-bs-toggle="modal"
data-bs-target="#deleteModal-@(page.Id)"
title="Excluir página">
<i class="fas fa-trash-alt" style="font-size: 11px;"></i>
</button>
<h6 class="card-title" style="padding-right: 35px;">@(page.DisplayName)</h6>
<p class="text-muted small mb-2">@(page.Category)/@(page.Slug)</p> <p class="text-muted small mb-2">@(page.Category)/@(page.Slug)</p>
<div class="mb-2"> <div class="mb-2">
@switch (page.Status) @switch (page.Status)
{ {
@ -62,11 +71,11 @@
</div> </div>
</div> </div>
} }
<div class="d-flex gap-1 flex-wrap"> <div class="d-flex gap-1 flex-wrap">
<a href="@Url.Action("ManagePage", new { id = page.Id })" <a href="@Url.Action("ManagePage", new { id = page.Id })"
class="btn btn-sm btn-outline-primary flex-fill">Editar</a> class="btn btn-sm btn-outline-primary flex-fill">Editar</a>
<a href="@(page.PublicUrl)" target="_blank" <a href="@(page.PublicUrl)" target="_blank"
class="btn btn-sm btn-outline-success flex-fill">Ver</a> class="btn btn-sm btn-outline-success flex-fill">Ver</a>
</div> </div>
</div> </div>
@ -76,7 +85,7 @@
</div> </div>
</div> </div>
} }
<!-- Card para Criar Nova Página --> <!-- Card para Criar Nova Página -->
@if (Model.CanCreateNewPage) @if (Model.CanCreateNewPage)
{ {
@ -86,7 +95,7 @@
<div> <div>
<i class="fas fa-plus fa-2x text-muted mb-3"></i> <i class="fas fa-plus fa-2x text-muted mb-3"></i>
<h6 class="text-muted">Criar Nova Página</h6> <h6 class="text-muted">Criar Nova Página</h6>
<a href="@Url.Action("ManagePage", new { id = "new" })" <a href="@Url.Action("ManagePage", new { id = "new" })"
class="btn btn-primary">Começar</a> class="btn btn-primary">Começar</a>
</div> </div>
</div> </div>
@ -120,7 +129,7 @@
<div class="alert alert-warning d-flex align-items-center"> <div class="alert alert-warning d-flex align-items-center">
<i class="fas fa-exclamation-triangle me-3"></i> <i class="fas fa-exclamation-triangle me-3"></i>
<div> <div>
<strong>Limite atingido!</strong> <strong>Limite atingido!</strong>
Você já criou o máximo de @Model.CurrentPlan.MaxPages página(s) para seu plano atual. Você já criou o máximo de @Model.CurrentPlan.MaxPages página(s) para seu plano atual.
<a href="@Url.Action("Pricing", "Home")" class="alert-link ms-2">Fazer upgrade</a> <a href="@Url.Action("Pricing", "Home")" class="alert-link ms-2">Fazer upgrade</a>
</div> </div>
@ -141,7 +150,7 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<h5 class="text-capitalize mb-1">@Model.CurrentPlan.Name</h5> <h5 class="text-capitalize mb-1">@Model.CurrentPlan.Name</h5>
@if (Model.CurrentPlan.Type == BCards.Web.Models.PlanType.Trial) @if (Model.CurrentPlan.Type == BCards.Web.Models.PlanType.Trial)
{ {
<p class="text-warning mb-2"> <p class="text-warning mb-2">
@ -153,7 +162,7 @@
{ {
<p class="text-muted small mb-2">R$ @Model.CurrentPlan.Price.ToString("F2")/mês</p> <p class="text-muted small mb-2">R$ @Model.CurrentPlan.Price.ToString("F2")/mês</p>
} }
<div class="mb-3"> <div class="mb-3">
<div class="d-flex justify-content-between small mb-1"> <div class="d-flex justify-content-between small mb-1">
<span>Páginas</span> <span>Páginas</span>
@ -161,14 +170,14 @@
</div> </div>
<div class="progress" style="height: 6px;"> <div class="progress" style="height: 6px;">
@{ @{
var pagesPercentage = Model.CurrentPlan.MaxPages > 0 ? var pagesPercentage = Model.CurrentPlan.MaxPages > 0 ?
(double)Model.UserPages.Count / Model.CurrentPlan.MaxPages * 100 : 0; (double)Model.UserPages.Count / Model.CurrentPlan.MaxPages * 100 : 0;
} }
<div class="progress-bar @(pagesPercentage >= 80 ? "bg-warning" : "bg-primary")" <div class="progress-bar @(pagesPercentage >= 80 ? "bg-warning" : "bg-primary")"
style="width: @pagesPercentage%"></div> style="width: @pagesPercentage%"></div>
</div> </div>
</div> </div>
<div class="small mb-2"> <div class="small mb-2">
<i class="fas fa-link me-2"></i> <i class="fas fa-link me-2"></i>
Links por página: @(Model.CurrentPlan.MaxLinksPerPage == int.MaxValue ? "Ilimitado" : Model.CurrentPlan.MaxLinksPerPage.ToString()) Links por página: @(Model.CurrentPlan.MaxLinksPerPage == int.MaxValue ? "Ilimitado" : Model.CurrentPlan.MaxLinksPerPage.ToString())
@ -181,7 +190,7 @@
<i class="fas fa-palette me-2"></i> <i class="fas fa-palette me-2"></i>
Temas customizáveis: @(Model.CurrentPlan.AllowsCustomThemes ? "✅" : "❌") Temas customizáveis: @(Model.CurrentPlan.AllowsCustomThemes ? "✅" : "❌")
</div> </div>
@if (Model.CurrentPlan.Type == BCards.Web.Models.PlanType.Trial) @if (Model.CurrentPlan.Type == BCards.Web.Models.PlanType.Trial)
{ {
<a href="@Url.Action("Pricing", "Home")" class="btn btn-warning w-100"> <a href="@Url.Action("Pricing", "Home")" class="btn btn-warning w-100">
@ -271,6 +280,46 @@
</div> </div>
</div> </div>
<!-- Modais de Confirmação para Excluir Páginas -->
@foreach (var page in Model.UserPages)
{
<div class="modal fade" id="deleteModal-@(page.Id)" tabindex="-1" aria-labelledby="deleteModalLabel-@(page.Id)" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header border-bottom-0">
<h5 class="modal-title" id="deleteModalLabel-@(page.Id)">
<i class="fas fa-exclamation-triangle text-warning me-2"></i>
Confirmar Exclusão
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center">
<div class="mb-3">
<i class="fas fa-trash-alt fa-3x text-danger mb-3"></i>
</div>
<h6>Tem certeza que deseja excluir a página <strong>"@(page.DisplayName)"</strong>?</h6>
<p class="text-muted small mb-0">
Esta ação não pode ser desfeita. Todos os dados da página, incluindo estatísticas, serão perdidos permanentemente.
</p>
</div>
<div class="modal-footer border-top-0 justify-content-center">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
<i class="fas fa-times me-2"></i>
Cancelar
</button>
<form method="post" action="@Url.Action("DeletePage", new { id = page.Id })" class="d-inline">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-danger">
<i class="fas fa-trash-alt me-2"></i>
Excluir Página
</button>
</form>
</div>
</div>
</div>
</div>
}
@if (TempData["Success"] != null) @if (TempData["Success"] != null)
{ {
<div class="toast-container position-fixed top-0 end-0 p-3"> <div class="toast-container position-fixed top-0 end-0 p-3">