const $ = (sel, root = document) => root.querySelector(sel);
const root = $('#app');
const TOKEN_KEY = 'andishkade_panel_token';
const getToken = () => localStorage.getItem(TOKEN_KEY);
const setToken = (t) => localStorage.setItem(TOKEN_KEY, t);
const clearToken = () => localStorage.removeItem(TOKEN_KEY);
const CATEGORIES = ['بازار جهانی', 'سیاستگذاری', 'انرژی و ESG', 'صادرات', 'تولید داخلی', 'ریسک و بحران'];
const TYPES = [
{ value: 'quarterly', label: 'فصلی' },
{ value: 'flash', label: 'فلش' },
{ value: 'risk', label: 'هشدار ریسک' },
{ value: 'free', label: 'رایگان' },
{ value: 'special', label: 'ویژه' },
];
async function api(path, { method = 'GET', body, isForm = false } = {}) {
const headers = {};
const token = getToken();
if (token) headers.Authorization = `Bearer ${token}`;
if (body && !isForm) headers['Content-Type'] = 'application/json';
const res = await fetch(path, {
method,
headers,
body: isForm ? body : (body ? JSON.stringify(body) : undefined),
});
if (res.status === 401) {
clearToken();
renderLogin('نیاز به ورود مجدد است');
throw new Error('unauthorized');
}
if (!res.ok) {
const text = await res.text();
throw new Error(text || res.statusText);
}
if (res.status === 204) return null;
return res.json();
}
function renderLogin(errorMsg = '') {
root.innerHTML = `
`;
$('#loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
try {
const data = await api('/api/auth/login', {
method: 'POST',
body: { username: fd.get('username'), password: fd.get('password') },
});
setToken(data.token);
renderList();
} catch {
renderLogin('نام کاربری یا رمز عبور اشتباه است');
}
});
}
async function renderList() {
root.innerHTML = `
پنل اندیشکده فولاد
مطالب
`;
$('#logoutBtn').addEventListener('click', () => { clearToken(); renderLogin(); });
$('#newBtn').addEventListener('click', () => renderEditor(null));
try {
const items = await api('/api/articles?limit=200');
if (!items.length) {
$('#list').innerHTML = `هنوز مطلبی ثبت نشده است.
`;
return;
}
$('#list').innerHTML = items.map((a) => `
${a.featured ? 'ویژه' : ''}
${a.category ? `${a.category}` : ''}
${a.publishDate ? `${a.publishDate}` : ''}
${a.title}
${a.summary || ''}
`).join('');
$('#list').addEventListener('click', async (e) => {
const btn = e.target.closest('button[data-action]');
if (!btn) return;
const row = btn.closest('.row');
const id = row.dataset.id;
if (btn.dataset.action === 'edit') {
const a = await api(`/api/articles/${id}`);
renderEditor(a);
} else if (btn.dataset.action === 'delete') {
if (!confirm('این مطلب حذف شود؟')) return;
await api(`/api/articles/${id}`, { method: 'DELETE' });
renderList();
}
});
} catch (err) {
console.error(err);
$('#list').innerHTML = `خطا در بارگذاری مطالب.
`;
}
}
function renderEditor(article) {
const a = article || {
title: '', category: '', type: '', author: '', authorRole: '', authorInitial: '',
publishDate: '', pages: 0, price: 0, isFree: true, summary: '', body: '',
coverImage: '', tags: [], featured: false,
};
const isEdit = !!article;
root.innerHTML = `
`;
$('#backBtn').addEventListener('click', () => renderList());
$('#coverFile').addEventListener('change', async (e) => {
const file = e.target.files?.[0];
if (!file) return;
const fd = new FormData();
fd.append('file', file);
try {
const { url } = await api('/api/uploads', { method: 'POST', body: fd, isForm: true });
$('input[name="coverImage"]').value = url;
$('#coverPreview').src = url;
} catch (err) {
alert('آپلود ناموفق بود: ' + err.message);
}
});
$('#editorForm').addEventListener('submit', async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
const tagsRaw = String(fd.get('tags') || '').split(/[,،]/).map(s => s.trim()).filter(Boolean);
const payload = {
title: fd.get('title'),
category: fd.get('category') || null,
type: fd.get('type') || null,
author: fd.get('author') || null,
authorRole: fd.get('authorRole') || null,
authorInitial: fd.get('authorInitial') || null,
publishDate: fd.get('publishDate') || null,
pages: Number(fd.get('pages') || 0),
price: Number(fd.get('price') || 0),
isFree: fd.get('isFree') === 'on',
featured: fd.get('featured') === 'on',
summary: fd.get('summary') || null,
body: fd.get('body') || null,
coverImage: fd.get('coverImage') || null,
tags: tagsRaw,
};
try {
if (isEdit) {
await api(`/api/articles/${article.id}`, { method: 'PUT', body: payload });
} else {
await api('/api/articles', { method: 'POST', body: payload });
}
renderList();
} catch (err) {
alert('ذخیره ناموفق بود: ' + err.message);
}
});
}
function escapeAttr(s) {
return String(s ?? '').replace(/&/g, '&').replace(/"/g, '"').replace(//g, '>');
}
if (getToken()) renderList();
else renderLogin();