Clean up dashboard
This commit is contained in:
+241
-165
@@ -173,11 +173,12 @@
|
|||||||
|
|
||||||
.project-qr-grid {
|
.project-qr-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
grid-template-columns: 1fr;
|
||||||
gap: var(--spacing-4);
|
gap: var(--spacing-3);
|
||||||
padding: var(--spacing-6);
|
padding: var(--spacing-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* QR Card Base Styles */
|
||||||
.qr-card {
|
.qr-card {
|
||||||
background: var(--white);
|
background: var(--white);
|
||||||
border: 1px solid var(--gray-200);
|
border: 1px solid var(--gray-200);
|
||||||
@@ -199,39 +200,106 @@
|
|||||||
background: linear-gradient(135deg, var(--white), #f8fafc);
|
background: linear-gradient(135deg, var(--white), #f8fafc);
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-card-header {
|
/* Compact QR Card Layout for Unassigned Cards */
|
||||||
|
.qr-card-compact {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
gap: var(--spacing-3);
|
gap: var(--spacing-4);
|
||||||
margin-bottom: var(--spacing-3);
|
width: 100%;
|
||||||
|
padding: var(--spacing-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-preview {
|
.qr-preview-compact {
|
||||||
width: 60px;
|
width: 70px;
|
||||||
height: 60px;
|
height: 70px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 2px solid var(--gray-200);
|
border: 2px solid var(--gray-200);
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-preview img {
|
.qr-preview-compact img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-card:hover .qr-preview {
|
.qr-card:hover .qr-preview-compact {
|
||||||
border-color: var(--primary-color);
|
border-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-info {
|
.qr-info-compact {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.qr-name-compact {
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--gray-900);
|
||||||
|
margin: 0 0 var(--spacing-1) 0;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-details-row {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-4);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-url-short {
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-status-compact {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0 var(--spacing-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-actions-compact {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-1);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard QR Card Layout for Project Cards */
|
||||||
|
.qr-card-layout {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-4);
|
||||||
|
margin-bottom: var(--spacing-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-preview-large {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
overflow: hidden;
|
||||||
|
border: 2px solid var(--gray-200);
|
||||||
|
transition: var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-preview-large img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-card:hover .qr-preview-large {
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-details {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
.qr-name {
|
.qr-name {
|
||||||
font-size: var(--font-size-base);
|
font-size: var(--font-size-base);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -240,13 +308,27 @@
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-location {
|
.qr-detail-item {
|
||||||
color: var(--gray-600);
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--spacing-1);
|
gap: 0.5rem;
|
||||||
margin-bottom: var(--spacing-2);
|
font-size: var(--font-size-sm);
|
||||||
|
color: var(--gray-600);
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-detail-item i {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
width: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--gray-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-detail-item span {
|
||||||
|
word-break: break-word;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-status-badge {
|
.qr-status-badge {
|
||||||
@@ -269,18 +351,12 @@
|
|||||||
color: #dc2626;
|
color: #dc2626;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-actions {
|
.qr-card-actions {
|
||||||
position: absolute;
|
|
||||||
top: var(--spacing-3);
|
|
||||||
right: var(--spacing-3);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--spacing-1);
|
gap: var(--spacing-2);
|
||||||
opacity: 0;
|
justify-content: flex-start;
|
||||||
transition: var(--transition);
|
padding-top: var(--spacing-3);
|
||||||
}
|
border-top: 1px solid var(--gray-200);
|
||||||
|
|
||||||
.qr-card:hover .qr-actions {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-action-btn {
|
.qr-action-btn {
|
||||||
@@ -317,16 +393,6 @@
|
|||||||
color: var(--white);
|
color: var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-action-btn.delete {
|
|
||||||
background: rgba(239, 68, 68, 0.1);
|
|
||||||
color: #dc2626;
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-action-btn.delete:hover {
|
|
||||||
background: #dc2626;
|
|
||||||
color: var(--white);
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-action-btn.toggle {
|
.qr-action-btn.toggle {
|
||||||
background: rgba(245, 158, 11, 0.1);
|
background: rgba(245, 158, 11, 0.1);
|
||||||
color: #d97706;
|
color: #d97706;
|
||||||
@@ -337,6 +403,7 @@
|
|||||||
color: var(--white);
|
color: var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Empty States */
|
||||||
.empty-project-qr {
|
.empty-project-qr {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: var(--spacing-8) var(--spacing-4);
|
padding: var(--spacing-8) var(--spacing-4);
|
||||||
@@ -368,6 +435,41 @@
|
|||||||
margin-bottom: var(--spacing-4);
|
margin-bottom: var(--spacing-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-empty {
|
||||||
|
text-align: center;
|
||||||
|
padding: 4rem 2rem;
|
||||||
|
color: var(--gray-600);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-empty .empty-icon {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
margin: 0 auto 2rem;
|
||||||
|
background: var(--gray-100);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 3rem;
|
||||||
|
color: var(--gray-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-empty h3 {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--gray-900);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-empty p {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
max-width: 500px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unassigned QR Section */
|
||||||
.unassigned-qr-section {
|
.unassigned-qr-section {
|
||||||
background: var(--white);
|
background: var(--white);
|
||||||
border: 1px solid var(--gray-200);
|
border: 1px solid var(--gray-200);
|
||||||
@@ -404,6 +506,7 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Modal Styles */
|
||||||
.modal {
|
.modal {
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -517,26 +620,26 @@
|
|||||||
padding-bottom: var(--spacing-2);
|
padding-bottom: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-detail-item {
|
.qr-detail-section .qr-detail-item {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 120px 1fr;
|
grid-template-columns: 100px 1fr;
|
||||||
gap: var(--spacing-3);
|
gap: var(--spacing-3);
|
||||||
margin-bottom: var(--spacing-4);
|
margin-bottom: var(--spacing-4);
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-detail-item:last-child {
|
.qr-detail-section .qr-detail-item:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-detail-item label {
|
.qr-detail-section .qr-detail-item label {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--gray-700);
|
color: var(--gray-700);
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-detail-item span {
|
.qr-detail-section .qr-detail-item span {
|
||||||
color: var(--gray-900);
|
color: var(--gray-900);
|
||||||
font-size: var(--font-size-base);
|
font-size: var(--font-size-base);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
@@ -576,40 +679,7 @@
|
|||||||
min-width: 140px;
|
min-width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-empty {
|
/* Animations */
|
||||||
text-align: center;
|
|
||||||
padding: 4rem 2rem;
|
|
||||||
color: var(--gray-600);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-empty .empty-icon {
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
margin: 0 auto 2rem;
|
|
||||||
background: var(--gray-100);
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 3rem;
|
|
||||||
color: var(--gray-400);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-empty h3 {
|
|
||||||
font-size: 2rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--gray-900);
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-empty p {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
max-width: 500px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; }
|
from { opacity: 0; }
|
||||||
to { opacity: 1; }
|
to { opacity: 1; }
|
||||||
@@ -626,6 +696,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.project-header {
|
.project-header {
|
||||||
padding: var(--spacing-3) var(--spacing-4);
|
padding: var(--spacing-3) var(--spacing-4);
|
||||||
@@ -647,18 +718,47 @@
|
|||||||
gap: var(--spacing-2);
|
gap: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-qr-grid {
|
.qr-card-compact {
|
||||||
grid-template-columns: 1fr;
|
flex-direction: column;
|
||||||
padding: var(--spacing-4);
|
text-align: center;
|
||||||
|
gap: var(--spacing-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-card-header {
|
.qr-info-compact {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-details-row {
|
||||||
|
flex-direction: column;
|
||||||
gap: var(--spacing-2);
|
gap: var(--spacing-2);
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-preview {
|
.qr-status-compact {
|
||||||
width: 50px;
|
margin: 0;
|
||||||
height: 50px;
|
}
|
||||||
|
|
||||||
|
.qr-actions-compact {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-card-layout {
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-preview-large {
|
||||||
|
align-self: center;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-details {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-detail-item {
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unassigned-header {
|
.unassigned-header {
|
||||||
@@ -691,11 +791,6 @@
|
|||||||
height: 240px;
|
height: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-detail-item {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
gap: var(--spacing-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-modal-footer {
|
.qr-modal-footer {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -713,13 +808,6 @@
|
|||||||
text-overflow: unset;
|
text-overflow: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-actions {
|
|
||||||
position: static;
|
|
||||||
opacity: 1;
|
|
||||||
margin-top: var(--spacing-2);
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
padding: var(--spacing-4);
|
padding: var(--spacing-4);
|
||||||
}
|
}
|
||||||
@@ -872,16 +960,33 @@
|
|||||||
data-qr-event="{{ qr.location_event }}"
|
data-qr-event="{{ qr.location_event }}"
|
||||||
data-qr-url="{{ qr.qr_url if qr.qr_url else '' }}"
|
data-qr-url="{{ qr.qr_url if qr.qr_url else '' }}"
|
||||||
onclick="openQRModalFromData(this)">
|
onclick="openQRModalFromData(this)">
|
||||||
<div class="qr-card-header">
|
|
||||||
<div class="qr-preview">
|
<div class="qr-card-layout">
|
||||||
|
<div class="qr-preview-large">
|
||||||
<img src="data:image/png;base64,{{ qr.qr_code_image }}" alt="QR Code for {{ qr.name }}" loading="lazy">
|
<img src="data:image/png;base64,{{ qr.qr_code_image }}" alt="QR Code for {{ qr.name }}" loading="lazy">
|
||||||
</div>
|
</div>
|
||||||
<div class="qr-info">
|
|
||||||
|
<div class="qr-details">
|
||||||
<h4 class="qr-name">{{ qr.name }}</h4>
|
<h4 class="qr-name">{{ qr.name }}</h4>
|
||||||
<p class="qr-location">
|
<div class="qr-detail-item">
|
||||||
<i class="fas fa-map-marker-alt"></i>
|
<i class="fas fa-map-marker-alt"></i>
|
||||||
{{ qr.location }}
|
<span>{{ qr.location }}</span>
|
||||||
</p>
|
</div>
|
||||||
|
|
||||||
|
{% if qr.location_address %}
|
||||||
|
<div class="qr-detail-item">
|
||||||
|
<i class="fas fa-home"></i>
|
||||||
|
<span>{{ qr.location_address }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if qr.qr_url %}
|
||||||
|
<div class="qr-detail-item">
|
||||||
|
<i class="fas fa-link"></i>
|
||||||
|
<span>{{ qr.qr_url }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<span class="qr-status-badge {{ 'active' if qr.active_status else 'inactive' }}">
|
<span class="qr-status-badge {{ 'active' if qr.active_status else 'inactive' }}">
|
||||||
<i class="fas {{ 'fa-check-circle' if qr.active_status else 'fa-pause-circle' }}"></i>
|
<i class="fas {{ 'fa-check-circle' if qr.active_status else 'fa-pause-circle' }}"></i>
|
||||||
{{ 'Active' if qr.active_status else 'Inactive' }}
|
{{ 'Active' if qr.active_status else 'Inactive' }}
|
||||||
@@ -889,7 +994,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="qr-actions">
|
<div class="qr-card-actions">
|
||||||
<button class="qr-action-btn download" onclick="event.stopPropagation(); downloadQRFromCard(this)" title="Download QR Code">
|
<button class="qr-action-btn download" onclick="event.stopPropagation(); downloadQRFromCard(this)" title="Download QR Code">
|
||||||
<i class="fas fa-download"></i>
|
<i class="fas fa-download"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -902,10 +1007,6 @@
|
|||||||
<button class="qr-action-btn toggle" onclick="event.stopPropagation(); toggleQRCodeStatus({{ qr.id }})" title="{{ 'Deactivate' if qr.active_status else 'Activate' }} QR Code">
|
<button class="qr-action-btn toggle" onclick="event.stopPropagation(); toggleQRCodeStatus({{ qr.id }})" title="{{ 'Deactivate' if qr.active_status else 'Activate' }} QR Code">
|
||||||
<i class="fas {{ 'fa-pause' if qr.active_status else 'fa-play' }}"></i>
|
<i class="fas {{ 'fa-pause' if qr.active_status else 'fa-play' }}"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="qr-action-btn delete" onclick="event.stopPropagation(); deleteQRCode({{ qr.id }}, '{{ qr.name }}')" title="Delete QR Code">
|
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -952,24 +1053,44 @@
|
|||||||
data-qr-event="{{ qr.location_event }}"
|
data-qr-event="{{ qr.location_event }}"
|
||||||
data-qr-url="{{ qr.qr_url if qr.qr_url else '' }}"
|
data-qr-url="{{ qr.qr_url if qr.qr_url else '' }}"
|
||||||
onclick="openQRModalFromData(this)">
|
onclick="openQRModalFromData(this)">
|
||||||
<div class="qr-card-header">
|
|
||||||
<div class="qr-preview">
|
<div class="qr-card-compact">
|
||||||
|
<div class="qr-preview-compact">
|
||||||
<img src="data:image/png;base64,{{ qr.qr_code_image }}" alt="QR Code for {{ qr.name }}" loading="lazy">
|
<img src="data:image/png;base64,{{ qr.qr_code_image }}" alt="QR Code for {{ qr.name }}" loading="lazy">
|
||||||
</div>
|
</div>
|
||||||
<div class="qr-info">
|
|
||||||
<h4 class="qr-name">{{ qr.name }}</h4>
|
<div class="qr-info-compact">
|
||||||
<p class="qr-location">
|
<h4 class="qr-name-compact">{{ qr.name }}</h4>
|
||||||
|
<div class="qr-details-row">
|
||||||
|
<div class="qr-detail-item">
|
||||||
<i class="fas fa-map-marker-alt"></i>
|
<i class="fas fa-map-marker-alt"></i>
|
||||||
{{ qr.location }}
|
<span>{{ qr.location }}</span>
|
||||||
</p>
|
</div>
|
||||||
|
|
||||||
|
{% if qr.location_address %}
|
||||||
|
<div class="qr-detail-item">
|
||||||
|
<i class="fas fa-home"></i>
|
||||||
|
<span>{{ qr.location_address }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if qr.qr_url %}
|
||||||
|
<div class="qr-detail-item">
|
||||||
|
<i class="fas fa-link"></i>
|
||||||
|
<span class="qr-url-short">{{ qr.qr_url[:50] }}{% if qr.qr_url|length > 50 %}...{% endif %}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="qr-status-compact">
|
||||||
<span class="qr-status-badge {{ 'active' if qr.active_status else 'inactive' }}">
|
<span class="qr-status-badge {{ 'active' if qr.active_status else 'inactive' }}">
|
||||||
<i class="fas {{ 'fa-check-circle' if qr.active_status else 'fa-pause-circle' }}"></i>
|
<i class="fas {{ 'fa-check-circle' if qr.active_status else 'fa-pause-circle' }}"></i>
|
||||||
{{ 'Active' if qr.active_status else 'Inactive' }}
|
{{ 'Active' if qr.active_status else 'Inactive' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="qr-actions">
|
<div class="qr-actions-compact">
|
||||||
<button class="qr-action-btn download" onclick="event.stopPropagation(); downloadQRFromCard(this)" title="Download QR Code">
|
<button class="qr-action-btn download" onclick="event.stopPropagation(); downloadQRFromCard(this)" title="Download QR Code">
|
||||||
<i class="fas fa-download"></i>
|
<i class="fas fa-download"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -982,13 +1103,10 @@
|
|||||||
<button class="qr-action-btn toggle" onclick="event.stopPropagation(); toggleQRCodeStatus({{ qr.id }})" title="{{ 'Deactivate' if qr.active_status else 'Activate' }} QR Code">
|
<button class="qr-action-btn toggle" onclick="event.stopPropagation(); toggleQRCodeStatus({{ qr.id }})" title="{{ 'Deactivate' if qr.active_status else 'Activate' }} QR Code">
|
||||||
<i class="fas {{ 'fa-pause' if qr.active_status else 'fa-play' }}"></i>
|
<i class="fas {{ 'fa-pause' if qr.active_status else 'fa-play' }}"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="qr-action-btn delete" onclick="event.stopPropagation(); deleteQRCode({{ qr.id }}, '{{ qr.name }}')" title="Delete QR Code">
|
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1199,50 +1317,10 @@ class ProjectDashboardManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteQRCode(qrId, qrName) {
|
|
||||||
const confirmMessage = `Are you sure you want to permanently delete the QR code "${qrName}"?\n\nThis action cannot be undone.`;
|
|
||||||
|
|
||||||
if (!confirm(confirmMessage)) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(`/qr-codes/${qrId}/delete`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
if (window.showToast) {
|
|
||||||
window.showToast(`QR code "${qrName}" deleted successfully`, 'success');
|
|
||||||
}
|
|
||||||
|
|
||||||
const qrCard = document.querySelector(`[data-qr-id="${qrId}"]`);
|
|
||||||
if (qrCard) {
|
|
||||||
qrCard.style.transition = 'all 0.3s ease';
|
|
||||||
qrCard.style.opacity = '0';
|
|
||||||
qrCard.style.transform = 'translateY(-20px)';
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
qrCard.remove();
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new Error('Failed to delete QR code');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Delete failed:', error);
|
|
||||||
if (window.showToast) {
|
|
||||||
window.showToast('Failed to delete QR code', 'error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
openQRModalFromData(element) {
|
openQRModalFromData(element) {
|
||||||
const qrData = {
|
const qrData = {
|
||||||
name: element.dataset.qrName,
|
name: element.dataset.qrName,
|
||||||
image: element.querySelector('.qr-preview img').src,
|
image: element.querySelector('img').src,
|
||||||
location: element.dataset.qrLocation,
|
location: element.dataset.qrLocation,
|
||||||
address: element.dataset.qrAddress,
|
address: element.dataset.qrAddress,
|
||||||
event: element.dataset.qrEvent,
|
event: element.dataset.qrEvent,
|
||||||
@@ -1321,11 +1399,10 @@ class ProjectDashboardManager {
|
|||||||
|
|
||||||
downloadQRFromCard(button) {
|
downloadQRFromCard(button) {
|
||||||
const qrCard = button.closest('.qr-card');
|
const qrCard = button.closest('.qr-card');
|
||||||
const img = qrCard.querySelector('.qr-preview img');
|
const img = qrCard.querySelector('img');
|
||||||
const qrName = qrCard.dataset.qrName;
|
const qrName = qrCard.dataset.qrName;
|
||||||
|
|
||||||
if (img && img.src) {
|
if (img && img.src) {
|
||||||
// Extract base64 data from the image src
|
|
||||||
const base64Data = img.src.split('base64,')[1];
|
const base64Data = img.src.split('base64,')[1];
|
||||||
this.downloadQR(base64Data, qrName);
|
this.downloadQR(base64Data, qrName);
|
||||||
}
|
}
|
||||||
@@ -1421,7 +1498,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
window.toggleProject = (projectId) => dashboardManager.toggleProject(projectId);
|
window.toggleProject = (projectId) => dashboardManager.toggleProject(projectId);
|
||||||
window.toggleQRCodeStatus = (qrId) => dashboardManager.toggleQRCodeStatus(qrId);
|
window.toggleQRCodeStatus = (qrId) => dashboardManager.toggleQRCodeStatus(qrId);
|
||||||
window.deleteQRCode = (qrId, qrName) => dashboardManager.deleteQRCode(qrId, qrName);
|
|
||||||
window.openQRModalFromData = (element) => dashboardManager.openQRModalFromData(element);
|
window.openQRModalFromData = (element) => dashboardManager.openQRModalFromData(element);
|
||||||
window.closeQRModal = () => dashboardManager.closeQRModal();
|
window.closeQRModal = () => dashboardManager.closeQRModal();
|
||||||
window.downloadModalQR = () => dashboardManager.downloadModalQR();
|
window.downloadModalQR = () => dashboardManager.downloadModalQR();
|
||||||
|
|||||||
Reference in New Issue
Block a user