(() => {
'use strict';
const token = decodeURIComponent(location.pathname.split('/').filter(Boolean).pop() || '');
const cameraInput = document.getElementById('camera-input');
const libraryInput = document.getElementById('library-input');
const preview = document.getElementById('mobile-preview');
const uploadButton = document.getElementById('upload-btn');
const uploadPanel = document.getElementById('upload-panel');
const successPanel = document.getElementById('success-panel');
const errorPanel = document.getElementById('error-panel');
const status = document.getElementById('session-status');
const count = document.getElementById('photo-count');
const expiresCopy = document.getElementById('expires-copy');
const progress = document.getElementById('upload-progress');
const sourceButtons = [
document.getElementById('open-camera-btn'),
document.getElementById('open-library-btn'),
document.getElementById('add-camera-btn'),
document.getElementById('add-library-btn'),
document.getElementById('success-camera-btn'),
document.getElementById('success-library-btn'),
].filter(Boolean);
let selected = [];
let serverFiles = [];
let remaining = 10;
function showError(message) {
uploadPanel.classList.add('hidden');
successPanel.classList.add('hidden');
errorPanel.classList.remove('hidden');
document.getElementById('error-copy').textContent = message;
status.className = 'session-status';
status.innerHTML = 'Upload nicht verfügbar';
}
function openCamera() {
if (remaining - selected.length <= 0) return;
cameraInput.click();
}
function openLibrary() {
if (remaining - selected.length <= 0) return;
libraryInput.click();
}
function render() {
preview.innerHTML = '';
selected.forEach((file, index) => {
const figure = document.createElement('figure');
const image = document.createElement('img');
image.alt = file.name || `Foto ${index + 1}`;
const objectUrl = URL.createObjectURL(file);
image.src = objectUrl;
image.addEventListener('load', () => URL.revokeObjectURL(objectUrl), { once: true });
image.addEventListener('error', () => {
URL.revokeObjectURL(objectUrl);
image.remove();
const fallback = document.createElement('div');
fallback.className = 'mobile-preview-fallback';
fallback.innerHTML = `Bild ${index + 1}${file.name || 'Foto ausgewählt'}`;
figure.prepend(fallback);
}, { once: true });
const remove = document.createElement('button');
remove.type = 'button';
remove.textContent = '×';
remove.setAttribute('aria-label', `${file.name || 'Bild'} entfernen`);
remove.addEventListener('click', () => {
selected.splice(index, 1);
render();
});
figure.append(image, remove);
preview.appendChild(figure);
});
const total = serverFiles.length + selected.length;
count.textContent = `${total} von 10 Bildern`;
uploadButton.disabled = selected.length === 0;
uploadButton.textContent = selected.length
? `${selected.length} ${selected.length === 1 ? 'Foto' : 'Fotos'} zu Vendoo senden`
: 'Fotos zu Vendoo senden';
const noSlots = remaining - selected.length <= 0;
sourceButtons.forEach(button => { button.disabled = noSlots; });
}
function addFiles(files) {
const candidates = [...files].filter(file => file.type.startsWith('image/') || /\.(heic|heif)$/i.test(file.name || ''));
const slots = Math.max(0, remaining - selected.length);
selected.push(...candidates.slice(0, slots));
render();
}
async function loadSession() {
try {
const response = await fetch(`/mobile-upload-api/${encodeURIComponent(token)}`, { cache: 'no-store' });
const data = await response.json();
if (!response.ok) throw new Error(data.error || 'Upload-Link konnte nicht geladen werden.');
serverFiles = data.files || [];
remaining = data.remaining ?? Math.max(0, 10 - serverFiles.length);
status.className = 'session-status ok';
status.innerHTML = 'Mit Vendoo verbunden';
uploadPanel.classList.remove('hidden');
const expires = new Date(String(data.expires_at).replace(' ', 'T') + (String(data.expires_at).includes('Z') ? '' : 'Z'));
expiresCopy.textContent = Number.isNaN(expires.getTime())
? ''
: `gültig bis ${expires.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}`;
render();
} catch (error) {
showError(error.message);
}
}
async function upload() {
if (!selected.length) return;
uploadButton.disabled = true;
sourceButtons.forEach(button => { button.disabled = true; });
progress.classList.remove('hidden');
try {
const form = new FormData();
selected.forEach(file => form.append('photos', file, file.name || `mobile-${Date.now()}.jpg`));
const response = await fetch(`/mobile-upload-api/${encodeURIComponent(token)}/photos?platform=mobile`, {
method: 'POST',
body: form,
});
const data = await response.json();
if (!response.ok) throw new Error(data.error || 'Upload fehlgeschlagen.');
serverFiles = data.files || serverFiles;
remaining = data.remaining ?? Math.max(0, 10 - serverFiles.length);
selected = [];
render();
uploadPanel.classList.add('hidden');
successPanel.classList.remove('hidden');
} catch (error) {
showError(error.message);
} finally {
progress.classList.add('hidden');
uploadButton.disabled = false;
sourceButtons.forEach(button => { button.disabled = false; });
}
}
function returnToUploadAndOpen(opener) {
successPanel.classList.add('hidden');
uploadPanel.classList.remove('hidden');
window.setTimeout(opener, 50);
}
cameraInput.addEventListener('change', () => {
addFiles(cameraInput.files || []);
cameraInput.value = '';
});
libraryInput.addEventListener('change', () => {
addFiles(libraryInput.files || []);
libraryInput.value = '';
});
document.getElementById('open-camera-btn').addEventListener('click', openCamera);
document.getElementById('open-library-btn').addEventListener('click', openLibrary);
document.getElementById('add-camera-btn').addEventListener('click', openCamera);
document.getElementById('add-library-btn').addEventListener('click', openLibrary);
document.getElementById('success-camera-btn').addEventListener('click', () => returnToUploadAndOpen(openCamera));
document.getElementById('success-library-btn').addEventListener('click', () => returnToUploadAndOpen(openLibrary));
uploadButton.addEventListener('click', upload);
loadSession();
})();