()
| 1829 | } |
| 1830 | |
| 1831 | function attachPortalLogoUploaders() { |
| 1832 | const body = document.getElementById('clientPortalsBody'); |
| 1833 | if (!body) return; |
| 1834 | |
| 1835 | body.querySelectorAll('.portal-card').forEach(card => { |
| 1836 | const uploadBtn = card.querySelector('.portal-logo-upload-btn'); |
| 1837 | if (!uploadBtn) return; |
| 1838 | if (uploadBtn.__frLogoBound) return; |
| 1839 | uploadBtn.__frLogoBound = true; |
| 1840 | |
| 1841 | const slug = (card.getAttribute('data-portal-slug') || '').trim(); |
| 1842 | const logoField = card.querySelector('[data-portal-field="logoFile"]'); |
| 1843 | |
| 1844 | // Hidden file input per card |
| 1845 | const fileInput = document.createElement('input'); |
| 1846 | fileInput.type = 'file'; |
| 1847 | fileInput.accept = 'image/*'; |
| 1848 | fileInput.style.display = 'none'; |
| 1849 | card.appendChild(fileInput); |
| 1850 | |
| 1851 | uploadBtn.addEventListener('click', (e) => { |
| 1852 | e.preventDefault(); |
| 1853 | if (!slug) { |
| 1854 | showToast(t('admin_portal_slug_required')); |
| 1855 | return; |
| 1856 | } |
| 1857 | fileInput.click(); |
| 1858 | }); |
| 1859 | |
| 1860 | fileInput.addEventListener('change', async () => { |
| 1861 | if (!fileInput.files || !fileInput.files.length) return; |
| 1862 | |
| 1863 | const file = fileInput.files[0]; |
| 1864 | const formData = new FormData(); |
| 1865 | formData.append('portal_logo', file); |
| 1866 | formData.append('slug', slug); |
| 1867 | |
| 1868 | try { |
| 1869 | const res = await fetch('/api/pro/portals/uploadLogo.php', { |
| 1870 | method: 'POST', |
| 1871 | credentials: 'include', |
| 1872 | headers: { |
| 1873 | 'X-CSRF-Token': window.csrfToken || '' |
| 1874 | }, |
| 1875 | body: formData |
| 1876 | }); |
| 1877 | |
| 1878 | const data = await safeJson(res); |
| 1879 | if (!data || data.success !== true) { |
| 1880 | throw new Error(data && data.error ? data.error : 'Upload failed'); |
| 1881 | } |
| 1882 | |
| 1883 | const fileName = data.fileName || data.filename || ''; |
| 1884 | if (logoField && fileName) { |
| 1885 | logoField.value = fileName; |
| 1886 | } |
| 1887 | |
| 1888 | showToast(t('admin_portal_logo_uploaded')); |
no test coverage detected