QrRapido/Views/Account/History.cshtml
Ricardo Carneiro a7af34659b
Some checks failed
Deploy QR Rapido / test (push) Successful in 29s
Deploy QR Rapido / build-and-push (push) Failing after 4s
Deploy QR Rapido / deploy-staging (push) Has been skipped
Deploy QR Rapido / deploy-production (push) Has been skipped
feat: delete e es-py
2025-08-04 20:34:29 -03:00

276 lines
12 KiB
Plaintext

@model List<QRRapidoApp.Models.QRCodeHistory>
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@{
ViewData["Title"] = Localizer["HistoryTitle"];
Layout = "~/Views/Shared/_Layout.cshtml";
var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
}
<div class="container mt-4">
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2><i class="fas fa-history text-primary"></i> @Localizer["QRCodeHistory"]</h2>
<p class="text-muted">@Localizer["QRCodesSavedHere"]</p>
</div>
<div>
<a href="/" class="btn btn-primary">
<i class="fas fa-plus"></i> @Localizer["GenerateNewQRCode"]
</a>
</div>
</div>
@if (Model != null && Model.Any())
{
<div class="row">
@foreach (var qr in Model)
{
<div class="col-12 col-md-6 col-lg-4 mb-4">
<div class="card h-100 shadow-sm position-relative">
<!-- Delete button in top-right corner -->
<button type="button"
class="btn btn-sm btn-outline-danger position-absolute"
style="top: 8px; right: 8px; z-index: 10; padding: 4px 8px;"
onclick="confirmDeleteQR('@qr.Id')"
title="@Localizer["DeleteQRCode"]">
<i class="fas fa-trash fa-sm"></i>
</button>
<div class="card-body">
<div class="text-center mb-3">
<img src="data:image/png;base64,@qr.QRCodeBase64"
alt="QR Code"
class="img-fluid border"
style="max-width: 150px; max-height: 150px;">
</div>
<div class="mb-2">
<small class="text-muted">@Localizer["Type"]</small>
<span class="badge bg-secondary">@qr.Type</span>
</div>
<div class="mb-2">
<small class="text-muted">@Localizer["Content"]</small>
<p class="small mb-0" style="word-break: break-all;">
@if (qr.Content.Length > 50)
{
@(qr.Content.Substring(0, 50) + "...")
}
else
{
@qr.Content
}
</p>
</div>
<div class="mb-3">
<small class="text-muted">@Localizer["CreatedOn"]</small>
<br>
<small>@qr.CreatedAt.ToString("dd/MM/yyyy HH:mm")</small>
</div>
</div>
<div class="card-footer bg-light">
<div class="btn-group w-100" role="group">
<a href="/api/QR/Download/@qr.Id?format=png"
class="btn btn-sm btn-outline-primary"
title="Download PNG">
<i class="fas fa-download"></i> PNG
</a>
<a href="/api/QR/Download/@qr.Id?format=svg"
class="btn btn-sm btn-outline-primary"
title="Download SVG">
<i class="fas fa-download"></i> SVG
</a>
<a href="/api/QR/Download/@qr.Id?format=pdf"
class="btn btn-sm btn-outline-primary"
title="Download PDF">
<i class="fas fa-download"></i> PDF
</a>
<button type="button"
class="btn btn-sm btn-outline-secondary"
onclick="regenerateQR('@qr.Id')"
title="Regenerar">
<i class="fas fa-redo"></i>
</button>
</div>
</div>
</div>
</div>
}
</div>
@if (Model.Count == 50)
{
<div class="alert alert-info text-center">
<i class="fas fa-info-circle"></i>
@Localizer["ShowingRecent50QRCodes"]
</div>
}
}
else
{
<div class="text-center py-5">
<i class="fas fa-qrcode fa-4x text-muted mb-3"></i>
<h4 class="text-muted">@Localizer["NoQRCodeFound"]</h4>
<p class="text-muted">
@Localizer["QRCodesWillAppearHere"]
</p>
<a href="/" class="btn btn-primary">
<i class="fas fa-plus"></i> @Localizer["GenerateFirstQRCode"]
</a>
</div>
}
</div>
</div>
</div>
<!-- Modal de Confirmação de Exclusão -->
<div class="modal fade" id="deleteConfirmModal" tabindex="-1" aria-labelledby="deleteConfirmModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteConfirmModalLabel">@Localizer["ConfirmDeleteTitle"]</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>@Localizer["ConfirmDeleteMessage"]</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">@Localizer["No"]</button>
<button type="button" class="btn btn-danger" id="confirmDeleteBtn">@Localizer["Yes"]</button>
</div>
</div>
</div>
</div>
@section Scripts {
<script>
let qrToDelete = null;
function regenerateQR(qrId) {
// Get QR data from history and regenerate
fetch(`/api/QR/History`)
.then(response => response.json())
.then(data => {
const qrData = data.find(q => q.id === qrId);
if (qrData) {
// Parse customization settings and redirect to home with parameters
const settings = JSON.parse(qrData.customizationSettings || '{}');
const params = new URLSearchParams({
content: qrData.content,
type: qrData.type,
size: settings.size || 300,
primaryColor: settings.primaryColor || '#000000',
backgroundColor: settings.backgroundColor || '#FFFFFF'
});
window.location.href = `/?${params.toString()}`;
}
})
.catch(error => {
console.error('Error regenerating QR:', error);
alert('@Localizer["ErrorRegeneratingQR"]');
});
}
function confirmDeleteQR(qrId) {
qrToDelete = qrId;
const modal = new bootstrap.Modal(document.getElementById('deleteConfirmModal'));
modal.show();
}
function deleteQR(qrId) {
// Show loading state
const confirmBtn = document.getElementById('confirmDeleteBtn');
const originalText = confirmBtn.textContent;
confirmBtn.disabled = true;
confirmBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> @Localizer["Deleting"]...';
fetch(`/api/QR/History/${qrId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Show success message
showToast(data.message || '@Localizer["QRCodeDeleted"]', 'success');
// Remove the card from the UI
const card = document.querySelector(`[onclick="confirmDeleteQR('${qrId}')"]`).closest('.col-12');
if (card) {
card.style.transition = 'opacity 0.3s ease';
card.style.opacity = '0';
setTimeout(() => {
card.remove();
// Check if no more cards exist
const remainingCards = document.querySelectorAll('.card');
if (remainingCards.length === 0) {
location.reload(); // Reload to show "no QR codes" message
}
}, 300);
}
// Hide modal
const modal = bootstrap.Modal.getInstance(document.getElementById('deleteConfirmModal'));
modal.hide();
} else {
showToast(data.message || '@Localizer["ErrorDeletingQR"]', 'error');
}
})
.catch(error => {
console.error('Error deleting QR:', error);
showToast('@Localizer["ErrorDeletingQR"]', 'error');
})
.finally(() => {
// Reset button state
confirmBtn.disabled = false;
confirmBtn.textContent = originalText;
});
}
function showToast(message, type = 'info') {
// Create toast element
const toast = document.createElement('div');
toast.className = `alert alert-${type === 'success' ? 'success' : 'danger'} alert-dismissible fade show position-fixed`;
toast.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
toast.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(toast);
// Auto remove after 5 seconds
setTimeout(() => {
if (toast.parentNode) {
toast.remove();
}
}, 5000);
}
// Event listeners
document.addEventListener('DOMContentLoaded', function() {
// Handle confirm delete button
document.getElementById('confirmDeleteBtn').addEventListener('click', function() {
if (qrToDelete) {
deleteQR(qrToDelete);
}
});
});
// Auto-refresh the page periodically to show new QR codes
setInterval(() => {
// Only refresh if user is still on this page and there are QR codes
if (document.visibilityState === 'visible' && document.querySelector('.card')) {
location.reload();
}
}, 300000); // Refresh every 5 minutes
</script>
}