import React, { useState, useMemo, useRef } from 'react';
import {
Key, Send, CheckCircle, AlertCircle, Image as ImageIcon,
Bold, Italic, Link as LinkIcon, List, Heading1, Heading2,
Upload, X, Copy, Terminal, Eye, Edit3
} from 'lucide-react';
export default function HaravanSimpleBlog() {
const [apiKey, setApiKey] = useState('');
const [blogId, setBlogId] = useState('');
const [shopDomain, setShopDomain] = useState('');
const [title, setTitle] = useState('');
const [handle, setHandle] = useState('');
const [content, setContent] = useState('');
const [excerpt, setExcerpt] = useState('');
const [metaTitle, setMetaTitle] = useState('');
const [metaDescription, setMetaDescription] = useState('');
const [tags, setTags] = useState('');
const [author, setAuthor] = useState('');
const [featuredImage, setFeaturedImage] = useState(null);
const [images, setImages] = useState([]);
const [preview, setPreview] = useState(false);
const [loading, setLoading] = useState(false);
const [notification, setNotification] = useState(null);
const [curlCmd, setCurlCmd] = useState('');
const editorRef = useRef(null);
const fileInputRef = useRef(null);
const featuredInputRef = useRef(null);
const slugify = (text) =>
text.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '')
.replace(/đ/g, 'd').replace(/[^a-z0-9\s-]/g, '')
.trim().replace(/\s+/g, '-').slice(0, 70);
const handleTitle = (e) => {
const v = e.target.value;
setTitle(v);
if (!handle || handle === slugify(title)) setHandle(slugify(v));
if (!metaTitle) setMetaTitle(v);
};
// SEO quick check
const seo = useMemo(() => {
const wc = content.replace(/<[^>]*>/g, '').split(/\s+/).filter(Boolean).length;
const checks = [
{ ok: title.length >= 30 && title.length <= 60, t: `Tiêu đề ${title.length}/60 ký tự` },
{ ok: metaDescription.length >= 120 && metaDescription.length <= 160, t: `Meta desc ${metaDescription.length}/160` },
{ ok: wc >= 300, t: `${wc} từ (tối thiểu 300)` },
{ ok: !!featuredImage, t: 'Có ảnh đại diện' },
{ ok: / Viết & đẩy bài chuẩn SEO nhanh gọn {excerpt}`;
if (editorRef.current) {
editorRef.current.focus();
document.execCommand('insertHTML', false, tag);
setContent(editorRef.current.innerHTML);
}
};
const uploadFeatured = async (e) => {
const f = e.target.files[0];
if (!f) return;
const b64 = await readFile(f);
setFeaturedImage({ name: f.name, base64: b64, alt: title || f.name });
};
const buildPayload = () => ({
article: {
title,
author: author || 'Admin',
body_html: content,
summary_html: excerpt,
tags,
handle,
published: true,
meta_title: metaTitle,
meta_description: metaDescription,
...(featuredImage && {
image: {
attachment: featuredImage.base64.split(',')[1],
filename: featuredImage.name
}
})
}
});
const publish = async () => {
if (!apiKey || !blogId || !title || !content) {
return setNotification({ type: 'error', msg: 'Thiếu API Key, Blog ID, tiêu đề hoặc nội dung!' });
}
setLoading(true);
setCurlCmd('');
const payload = buildPayload();
const url = `https://apis.haravan.com/com/blogs/${blogId}/articles.json`;
// Tạo cURL dự phòng
const curl = `curl -X POST "${url}" \\
-H "Authorization: Bearer ${apiKey}" \\
-H "Content-Type: application/json" \\
-d '${JSON.stringify(payload).replace(/'/g, "'\\''")}'`;
try {
const res = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
setNotification({
type: 'success',
msg: `✓ Đăng thành công! ID: ${data.article?.id || '(xem Haravan Admin)'}`
});
} catch (err) {
// CORS hoặc lỗi khác → show cURL
setCurlCmd(curl);
setNotification({
type: 'warn',
msg: 'Trình duyệt chặn (CORS). Copy lệnh cURL bên dưới dán vào Terminal/CMD để đăng bài.'
});
} finally {
setLoading(false);
}
};
const copyCurl = () => {
navigator.clipboard.writeText(curlCmd);
setNotification({ type: 'success', msg: 'Đã copy cURL! Mở Terminal/CMD paste vào Enter để đăng.' });
};
const copyPayload = () => {
navigator.clipboard.writeText(JSON.stringify(buildPayload(), null, 2));
setNotification({ type: 'success', msg: 'Đã copy JSON payload!' });
};
return (
📝 Haravan Blog Tool
{curlCmd}
}
{title || 'Tiêu đề'}
{excerpt &&