refactor(admin): show media files from GCS bucket

This commit is contained in:
Harshad 2026-02-06 17:06:44 +05:30
parent e8be7ec3b1
commit 08da62553c

View file

@ -92,41 +92,53 @@
</div>
</div>
<!-- 1. Use modal-xl for desktop real estate -->
<div class="modal fade" id="photoModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalUserName">User Details</h5>
<h5 class="modal-title">Record Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="row">
<div class="col-md-12">
<div class="d-flex align-items-center mb-3">
<img src="" id="modalImage" class="user-photo me-3" style="width: 80px; height: 80px;">
<div>
<h4 id="modalUserName" class="mb-0"></h4>
<small id="modalSession" class="text-muted"></small>
<div class="modal-body">
<div class="row">
<!-- Left Column: Media (Fixed Width for 9:16) -->
<div class="col-md-4 border-end">
<h6>Original Photo</h6>
<img src="" id="modalImage" class="img-thumbnail mb-3"
style="width: 150px; height: 150px; object-fit: cover;">
<h6>Generated Media</h6>
<div id="modalMediaContainer" class="bg-black rounded overflow-hidden shadow-sm"
style="max-width: 280px; min-height: 200px;">
<!-- Video/Audio injected here -->
</div>
</div>
<!-- Right Column: Full Data Table -->
<div class="col-md-8">
<h6>Full Entry Metadata</h6>
<div class="table-responsive">
<table class="table table-sm table-hover border">
<thead class="table-light">
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody id="modalDetailsTableBody">
<!-- Dynamic content -->
</tbody>
</table>
</div>
<h6 class="mt-4">Lyrics</h6>
<pre id="modalLyrics" class="bg-dark text-info p-3 rounded"
style="white-space: pre-wrap; font-size: 0.85rem; max-height: 300px; overflow-y: auto;">
</pre>
</div>
</div>
<div class="col-md-6">
<h6>Pet Details</h6>
<table class="table table-sm border">
<tr><td>Pet:</td><td id="modalPetName" class=""></td></tr>
<tr><td>Type:</td><td id="modalPetType"></td></tr>
<tr><td>Vibe:</td><td id="modalVibe"></td></tr>
</table>
</div>
<div class="col-md-6">
<h6>Assets</h6>
<div id="modalMediaContainer">
<!-- We will inject an <audio> or <video> tag here via JS -->
</div>
</div>
<div class="col-md-12 mt-3">
<h6>Lyrics</h6>
<pre id="modalLyrics" class="bg-dark text-white p-3 rounded small" style="max-height: 150px; overflow-y: auto;"></pre>
</div>
</div>
</div>
</div>
@ -146,11 +158,14 @@
$(document).ready(function() {
const API_BASE_URL = '';
const API_ENDPOINT = `/back/api/admin/data`;
const MEDIA_BASE_URL = 'https://storage.googleapis.com/vday2026/';
// Helper to convert container paths to web URLs
function fixStoragePath(path) {
if (!path) return '';
return path.replace(/^\/app\/storage\//, '/storage/');
// let relative_path = path.replace(/^\/app\/storage\//, '/storage/');
const isRelative = path.startsWith('uploads/') || path.startsWith('audio/') || path.startsWith('video/');
return isRelative ? MEDIA_BASE_URL + path : path;
}
// Fetch and display Sonauto credits
@ -274,39 +289,67 @@
const rowData = table.row($(this).closest('tr')).data();
// 2. Populate the Modal fields
$('#modalUserName').text(rowData.owner_name + ' - Profile');
$('.modal-title').text(`Session: ${rowData.session_id}`);
$('#modalImage').attr('src', fixStoragePath(rowData.photo_path) || "https://placehold.co/500x500/fbba0e/e11d48/jpg?text=No\nImage");
$('#modalPetName').text(rowData.pet_name || 'N/A');
$('#modalPetType').text(rowData.pet_type || 'N/A');
$('#modalVibe').text(rowData.music_vibe || 'N/A');
$('#modalSession').text(rowData.session_id);
// 3. Handle Lyrics
if (rowData.lyrics) {
$('#modalLyrics').text(rowData.lyrics);
} else {
$('#modalLyrics').text('No lyrics available yet...');
}
// 3. Dynamic Table Generation for all 20+ columns
const tableBody = $('#modalDetailsTableBody');
tableBody.empty();
// List of keys we want to display or skip
Object.entries(rowData).forEach(([key, value]) => {
// Skip keys that are handled visually (media/lyrics)
if (['photo_path', 'generated_video_path', 'generated_song_path', 'lyrics'].includes(key))
return;
let displayValue = value ?? '<span class="text-muted italic">null</span>';
// Surgical Link Detection: Only link if it has a known file extension
const isFile = typeof value === 'string' && /\.(jpg|jpeg|png|mp3|mp4|wav)$/i.test(value);
if (isFile) {
const fullUrl = fixStoragePath(value);
displayValue = `<a href="${fullUrl}" target="_blank" class="text-decoration-none text-truncate d-inline-block" style="max-width: 300px;">${value} 🔗</a>`;
}
tableBody.append(`
<tr>
<td class="fw-bold text-muted" style="width: 30%">${key.replace(/_/g, ' ')}</td>
<td class="text-break">${displayValue}</td>
</tr>
`);
});
$('#modalLyrics').text(rowData.lyrics || 'No lyrics generated.');
// 4. Handle Media (Song or Video)
const mediaContainer = $('#modalMediaContainer');
mediaContainer.empty(); // Clear previous content
console.group(`--- Media Debug: Session ${rowData.session_id} ---`);
const videoUrl = fixStoragePath(rowData.generated_video_path);
const audioUrl = fixStoragePath(rowData.generated_song_path);
console.log('Video URL:', videoUrl);
console.log('Audio URL:', audioUrl);
console.groupEnd();
// Reset container state
mediaContainer.empty().removeClass('ratio ratio-9x16 d-flex align-items-center p-3');
if (rowData.generated_video_path) {
if (videoUrl && rowData.generated_video_path) {
console.log('Injecting Video...');
mediaContainer.addClass('ratio ratio-9x16');
mediaContainer.html(`
<video controls class="w-100" style="max-height: 300px;">
<source src="${fixStoragePath(rowData.generated_video_path)}" type="video/mp4">
Your browser does not support video.
<video controls preload="metadata" class="w-100 h-100" src="${videoUrl}">
Your browser does not support the video tag.
</video>
`);
} else if (rowData.generated_song_path) {
} else if (audioUrl && rowData.generated_song_path) {
console.log('Injecting Audio...');
mediaContainer.addClass('d-flex align-items-center p-3');
mediaContainer.html(`
<audio controls class="w-100">
<source src="${fixStoragePath(rowData.generated_song_path)}" type="audio/mpeg">
<audio controls preload="metadata" class="w-100" src="${audioUrl}">
Your browser does not support audio.
</audio>
`);
} else {
mediaContainer.html('<p class="text-muted">No media available yet...</p>');
mediaContainer.html('<div class="d-flex align-items-center justify-content-center h-100 text-white-50">No Media</div>');
}
// 5. Show the Modal