/**
* POSSE Composer — text + media upload
*/
let selectedFile = null
function initComposer () {
const textarea = document.getElementById('compose-text')
const charCount = document.getElementById('char-count')
const publishBtn = document.getElementById('publish-btn')
const resultEl = document.getElementById('publish-result')
const mediaInput = document.getElementById('media-input')
const attachBtn = document.getElementById('attach-btn')
const mediaPreview = document.getElementById('media-preview')
const previewImg = document.getElementById('preview-img')
const previewName = document.getElementById('preview-name')
const removeMedia = document.getElementById('remove-media')
const altText = document.getElementById('alt-text')
textarea.addEventListener('input', () => {
charCount.textContent = textarea.value.length
})
// Attach media
attachBtn.addEventListener('click', () => mediaInput.click())
mediaInput.addEventListener('change', () => {
const file = mediaInput.files[0]
if (!file) return
selectedFile = file
previewName.textContent = file.name + ' (' + formatSize(file.size) + ')'
altText.style.display = 'block'
if (file.type.startsWith('image/')) {
const url = URL.createObjectURL(file)
previewImg.src = url
previewImg.style.display = 'block'
} else {
previewImg.style.display = 'none'
}
mediaPreview.style.display = 'flex'
attachBtn.style.display = 'none'
})
removeMedia.addEventListener('click', () => {
selectedFile = null
mediaInput.value = ''
mediaPreview.style.display = 'none'
attachBtn.style.display = 'inline-block'
altText.style.display = 'none'
altText.value = ''
previewImg.src = ''
})
// Publish
publishBtn.addEventListener('click', async () => {
const text = textarea.value.trim()
if (!text) return
const targets = []
document.querySelectorAll('input[name="target"]:checked').forEach(cb => {
targets.push(cb.value)
})
if (targets.length === 0) {
showResult(resultEl, 'Select at least one platform', 'error')
return
}
publishBtn.disabled = true
publishBtn.textContent = selectedFile ? 'Processing & publishing...' : 'Publishing...'
try {
let data
if (selectedFile) {
// Multipart upload with media
const form = new FormData()
form.append('text', text)
form.append('targets', JSON.stringify(targets))
form.append('altText', altText.value || '')
form.append('file', selectedFile)
const res = await fetch(API.base + '/api/post-media', {
method: 'POST',
body: form
})
data = await res.json()
} else {
// Text-only
data = await API.post(text, targets)
}
if (data.error) {
showResult(resultEl, data.error, 'error')
} else if (data.errors && Object.keys(data.errors).length > 0) {
const errMsg = Object.entries(data.errors).map(([k, v]) => `${k}: ${v}`).join(', ')
showResult(resultEl, 'Partial: ' + errMsg, 'error')
} else {
showResult(resultEl, 'Published to ' + targets.join(', '), 'success')
textarea.value = ''
charCount.textContent = '0'
// Clear media
selectedFile = null
mediaInput.value = ''
mediaPreview.style.display = 'none'
attachBtn.style.display = 'inline-block'
altText.style.display = 'none'
altText.value = ''
}
} catch (err) {
showResult(resultEl, err.message, 'error')
}
publishBtn.disabled = false
publishBtn.textContent = 'Publish'
})
}
function formatSize (bytes) {
if (bytes < 1024) return bytes + ' B'
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
}
function showResult (el, msg, type) {
el.style.display = 'block'
el.className = 'result ' + type
el.textContent = msg
setTimeout(() => { el.style.display = 'none' }, 5000)
}