312 lines
13 KiB
HTML
312 lines
13 KiB
HTML
<div class="hero-image-layout">
|
|
<!-- Sidebar -->
|
|
<app-menu class="sidebar"></app-menu>
|
|
|
|
<!-- Main Content -->
|
|
<div class="hero-image-content">
|
|
<!-- Header Section -->
|
|
<div class="hero-image-header">
|
|
<div class="header-left">
|
|
<h1 class="page-title">Hero Image Management</h1>
|
|
<p class="page-subtitle">Manage homepage hero section images</p>
|
|
</div>
|
|
<div class="header-actions">
|
|
<div class="search-box">
|
|
<i class="fa fa-search"></i>
|
|
<input
|
|
name="searchTerm"
|
|
#searchTerm="ngModel"
|
|
class="search-input"
|
|
type="search"
|
|
placeholder="Search hero images..."
|
|
ngModel
|
|
(ngModelChange)="searchHeroImages(searchTerm.value)">
|
|
</div>
|
|
<button *ngIf="isManager" class="btn-primary" data-bs-toggle="modal" data-bs-target="#addHeroImageModal">
|
|
<i class="fa fa-plus"></i>
|
|
<span>New Hero Image</span>
|
|
</button>
|
|
<button class="btn-refresh" (click)="getHeroImages(true)">
|
|
<i class="fas fa-sync" [ngClass]="{'fa-spin': refreshing }"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hero Images Grid -->
|
|
<div class="hero-images-grid" *ngIf="heroImages && heroImages.length > 0">
|
|
<div *ngFor="let heroImage of heroImages" class="hero-image-card" (click)="heroImage && onSelectHeroImage(heroImage)">
|
|
<div class="hero-image-preview" *ngIf="heroImage">
|
|
<img [src]="heroImage?.imageUrl"
|
|
[alt]="heroImage?.title || 'Hero Image'"
|
|
(error)="onImageError($event)"
|
|
loading="lazy">
|
|
<div class="active-badge" *ngIf="heroImage?.isActive">
|
|
<i class="fa fa-check-circle"></i>
|
|
<span>Active</span>
|
|
</div>
|
|
</div>
|
|
<div class="hero-image-info" *ngIf="heroImage">
|
|
<h3>{{ heroImage?.title || 'Untitled' }}</h3>
|
|
<p class="subtitle" *ngIf="heroImage?.subtitle">{{ heroImage.subtitle }}</p>
|
|
<p class="description" *ngIf="heroImage?.description">{{ heroImage.description }}</p>
|
|
<div class="hero-image-actions">
|
|
<button class="btn-action btn-edit" (click)="onEditHeroImage(heroImage); $event.stopPropagation()" title="Edit">
|
|
<i class="fas fa-edit"></i>
|
|
</button>
|
|
<button class="btn-action btn-activate"
|
|
*ngIf="!heroImage?.isActive"
|
|
(click)="onSetActiveHeroImage(heroImage); $event.stopPropagation()"
|
|
title="Set as Active">
|
|
<i class="fas fa-star"></i>
|
|
</button>
|
|
<button *ngIf="isAdmin && !heroImage?.isActive"
|
|
class="btn-action btn-delete"
|
|
(click)="onDeleteHeroImage(heroImage); $event.stopPropagation()"
|
|
title="Delete">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Loading State -->
|
|
<div *ngIf="refreshing" class="loading-state">
|
|
<div class="loading-spinner">
|
|
<i class="fas fa-spinner fa-spin"></i>
|
|
</div>
|
|
<p>Loading hero images...</p>
|
|
</div>
|
|
|
|
<!-- Empty State -->
|
|
<div *ngIf="!refreshing && (!heroImages || heroImages.length === 0)" class="empty-state">
|
|
<div class="empty-icon">
|
|
<i class="fa fa-image"></i>
|
|
</div>
|
|
<h3>No hero images yet</h3>
|
|
<p>Get started by creating your first hero image for the homepage</p>
|
|
<button *ngIf="isManager" class="btn-primary" data-bs-toggle="modal" data-bs-target="#addHeroImageModal">
|
|
<i class="fa fa-plus"></i>
|
|
<span>Create Your First Hero Image</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Hidden Modal Triggers -->
|
|
<button [hidden]="true" type="button" id="openHeroImageInfo" data-bs-toggle="modal" data-bs-target="#viewHeroImageModal"></button>
|
|
<button [hidden]="true" type="button" id="openHeroImageEdit" data-bs-toggle="modal" data-bs-target="#editHeroImageModal"></button>
|
|
|
|
<!-- View Hero Image Modal -->
|
|
<div class="modal fade" id="viewHeroImageModal" tabindex="-1">
|
|
<div class="modal-dialog modal-xl">
|
|
<div class="modal-content" *ngIf="selectedHeroImage">
|
|
<div class="modal-header">
|
|
<h3>Hero Image Details</h3>
|
|
<button class="modal-close" data-bs-dismiss="modal">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="hero-image-detail-card">
|
|
<div class="hero-image-preview-large">
|
|
<img [src]="selectedHeroImage.imageUrl" [alt]="selectedHeroImage.title">
|
|
<div class="active-badge" *ngIf="selectedHeroImage.isActive">
|
|
<i class="fa fa-check-circle"></i>
|
|
<span>Active</span>
|
|
</div>
|
|
</div>
|
|
<div class="hero-image-details">
|
|
<div class="detail-item">
|
|
<span class="detail-label">Title:</span>
|
|
<span class="detail-value">{{ selectedHeroImage.title }}</span>
|
|
</div>
|
|
<div class="detail-item" *ngIf="selectedHeroImage.subtitle">
|
|
<span class="detail-label">Subtitle:</span>
|
|
<span class="detail-value">{{ selectedHeroImage.subtitle }}</span>
|
|
</div>
|
|
<div class="detail-item" *ngIf="selectedHeroImage.description">
|
|
<span class="detail-label">Description:</span>
|
|
<span class="detail-value">{{ selectedHeroImage.description }}</span>
|
|
</div>
|
|
<div class="detail-item" *ngIf="selectedHeroImage.uploadDate">
|
|
<span class="detail-label">Uploaded:</span>
|
|
<span class="detail-value">{{ selectedHeroImage.uploadDate | date:'MMM d, y h:mm a' }}</span>
|
|
</div>
|
|
<div class="detail-item" *ngIf="selectedHeroImage.lastModified">
|
|
<span class="detail-label">Last Modified:</span>
|
|
<span class="detail-value">{{ selectedHeroImage.lastModified | date:'MMM d, y h:mm a' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Hero Image Modal -->
|
|
<div *ngIf="isManager" class="modal fade" id="addHeroImageModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h3>Add New Hero Image</h3>
|
|
<button class="modal-close" data-bs-dismiss="modal">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form #newHeroImageForm="ngForm" (ngSubmit)="onAddNewHeroImage(newHeroImageForm)">
|
|
|
|
<div class="form-section">
|
|
<h4 class="section-title">Image Information</h4>
|
|
|
|
<div class="form-group">
|
|
<label for="title">
|
|
<i class="fa fa-heading"></i>
|
|
Title *
|
|
</label>
|
|
<input type="text" id="title" name="title" class="form-input" ngModel required placeholder="Enter title">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="subtitle">
|
|
<i class="fa fa-align-left"></i>
|
|
Subtitle
|
|
</label>
|
|
<input type="text" id="subtitle" name="subtitle" class="form-input" ngModel placeholder="Enter subtitle">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="description">
|
|
<i class="fa fa-align-left"></i>
|
|
Description
|
|
</label>
|
|
<textarea id="description" name="description" class="form-textarea" rows="3" ngModel placeholder="Enter description"></textarea>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>
|
|
<i class="fa fa-image"></i>
|
|
Upload Image *
|
|
</label>
|
|
<div class="file-upload-wrapper">
|
|
<input type="file"
|
|
id="newHeroImage"
|
|
accept="image/*"
|
|
name="heroImage"
|
|
(change)="onImageChange($any($event).target.files)"
|
|
class="file-input"
|
|
required>
|
|
<label for="newHeroImage" class="file-label">
|
|
<i class="fa fa-cloud-upload-alt"></i>
|
|
<span>{{ heroImageFileName || 'Choose image (required)' }}</span>
|
|
</label>
|
|
</div>
|
|
<small class="form-text text-muted" *ngIf="!heroImageFile">
|
|
Please upload an image file (JPG, PNG, or GIF)
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button class="btn-primary"
|
|
type="button"
|
|
(click)="newHeroImageForm.ngSubmit.emit()"
|
|
[disabled]="newHeroImageForm.invalid || !heroImageFile">
|
|
<i class="fa fa-save"></i>
|
|
Create Hero Image
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Hero Image Modal -->
|
|
<div class="modal fade" id="editHeroImageModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content" *ngIf="selectedHeroImage">
|
|
<div class="modal-header">
|
|
<h3>Edit Hero Image</h3>
|
|
<button class="modal-close" data-bs-dismiss="modal">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form #editHeroImageForm="ngForm" (ngSubmit)="onUpdateHeroImage(editHeroImageForm)">
|
|
|
|
<div class="form-section">
|
|
<h4 class="section-title">Image Information</h4>
|
|
|
|
<div class="form-group">
|
|
<label for="editTitle">
|
|
<i class="fa fa-heading"></i>
|
|
Title *
|
|
</label>
|
|
<input type="text" id="editTitle" name="title" class="form-input" [(ngModel)]="selectedHeroImage.title" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="editSubtitle">
|
|
<i class="fa fa-align-left"></i>
|
|
Subtitle
|
|
</label>
|
|
<input type="text" id="editSubtitle" name="subtitle" class="form-input" [(ngModel)]="selectedHeroImage.subtitle">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="editDescription">
|
|
<i class="fa fa-align-left"></i>
|
|
Description
|
|
</label>
|
|
<textarea id="editDescription" name="description" class="form-textarea" rows="3" [(ngModel)]="selectedHeroImage.description"></textarea>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>
|
|
<i class="fa fa-image"></i>
|
|
Current Image
|
|
</label>
|
|
<div class="current-image-preview">
|
|
<img [src]="selectedHeroImage.imageUrl" [alt]="selectedHeroImage.title">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>
|
|
<i class="fa fa-image"></i>
|
|
Upload New Image (Optional)
|
|
</label>
|
|
<div class="file-upload-wrapper">
|
|
<input type="file"
|
|
id="editHeroImage"
|
|
accept="image/*"
|
|
name="heroImage"
|
|
(change)="onImageChange($any($event).target.files)"
|
|
class="file-input">
|
|
<label for="editHeroImage" class="file-label">
|
|
<i class="fa fa-cloud-upload-alt"></i>
|
|
<span>{{ heroImageFileName || 'Choose new image' }}</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button class="btn-primary" (click)="editHeroImageForm.ngSubmit.emit()" [disabled]="editHeroImageForm.invalid">
|
|
<i class="fa fa-save"></i>
|
|
Save Changes
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div> |