This commit is contained in:
Samandar Turgunboyev
2025-10-30 18:28:17 +05:00
parent 352efd6391
commit 39f5b8ca3c
13 changed files with 650 additions and 115 deletions

View File

@@ -9,17 +9,15 @@ export interface AllSeoData {
total_pages: number;
page_size: number;
current_page: number;
results: [
{
id: number;
title: string;
description: string;
keywords: string;
og_title: string;
og_description: string;
og_image: string;
},
];
results: {
id: number;
title: string;
description: string;
keywords: string;
og_title: string;
og_description: string;
og_image: string;
}[];
};
}
@@ -28,10 +26,20 @@ export interface DetailSeoData {
data: {
id: number;
title: string;
title_uz: string;
title_ru: string;
description: string;
description_uz: string;
description_ru: string;
keywords: string;
keywords_uz: string;
keywords_ru: string;
og_title: string;
og_title_uz: string;
og_title_ru: string;
og_description: string;
og_description_uz: string;
og_description_ru: string;
og_image: string;
};
}

View File

@@ -24,20 +24,30 @@ import { toast } from "sonner";
type SeoData = {
title: string;
title_ru: string;
description: string;
description_ru: string;
keywords: string;
keywords_ru: string;
ogTitle: string;
ogTitle_ru: string;
ogDescription: string;
ogDescription_ru: string;
ogImage: File | null | string;
};
export default function Seo() {
const [formData, setFormData] = useState<SeoData>({
title: "",
title_ru: "",
description: "",
description_ru: "",
keywords: "",
keywords_ru: "",
ogTitle: "",
ogTitle_ru: "",
ogDescription: "",
ogDescription_ru: "",
ogImage: null,
});
const { t } = useTranslation();
@@ -52,6 +62,11 @@ export default function Seo() {
});
setFormData({
description: "",
description_ru: "",
keywords_ru: "",
ogDescription_ru: "",
ogTitle_ru: "",
title_ru: "",
keywords: "",
ogDescription: "",
ogImage: null,
@@ -80,6 +95,11 @@ export default function Seo() {
setEdit(null);
setFormData({
description: "",
description_ru: "",
keywords_ru: "",
ogDescription_ru: "",
ogTitle_ru: "",
title_ru: "",
keywords: "",
ogDescription: "",
ogImage: null,
@@ -104,6 +124,11 @@ export default function Seo() {
setEdit(null);
setFormData({
description: "",
description_ru: "",
keywords_ru: "",
ogDescription_ru: "",
ogTitle_ru: "",
title_ru: "",
keywords: "",
ogDescription: "",
ogImage: null,
@@ -170,12 +195,17 @@ export default function Seo() {
useEffect(() => {
if (detailSeo) {
setFormData({
description: detailSeo.description,
keywords: detailSeo.keywords,
ogDescription: detailSeo.og_description,
description: detailSeo.description_uz,
keywords: detailSeo.keywords_uz,
ogDescription: detailSeo.og_description_uz,
ogImage: detailSeo.og_image,
ogTitle: detailSeo.og_title,
title: detailSeo.title,
ogTitle: detailSeo.og_title_uz,
title: detailSeo.title_uz,
description_ru: detailSeo.description_ru,
keywords_ru: detailSeo.keywords_ru,
ogDescription_ru: detailSeo.og_description_ru,
ogTitle_ru: detailSeo.og_title_ru,
title_ru: detailSeo.title_ru,
});
setImagePreview(detailSeo.og_image || null);
}
@@ -184,10 +214,15 @@ export default function Seo() {
const handleSave = () => {
const form = new FormData();
form.append("title", formData.title);
form.append("title_ru", formData.title_ru);
form.append("description", formData.description);
form.append("description_ru", formData.description_ru);
form.append("keywords", formData.keywords);
form.append("keywords_ru", formData.keywords_ru);
form.append("og_title", formData.ogTitle);
form.append("og_title_ru", formData.ogTitle_ru);
form.append("og_description", formData.ogDescription);
form.append("og_description_ru", formData.ogDescription_ru);
// faqat File bolsa qoshamiz
if (formData.ogImage instanceof File) {
@@ -250,6 +285,29 @@ export default function Seo() {
</div>
</div>
<div>
<label className="block text-sm font-semibold text-white mb-2">
<FileText className="inline w-4 h-4 mr-1" /> {t("Page Title")}{" "}
(ru)
</label>
<input
type="text"
name="title_ru"
value={formData.title_ru}
onChange={handleChange}
placeholder={t("Sahifa sarlavhasi (3060 belgi)") + " ru"}
className="w-full bg-slate-700 text-white px-4 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<div className="flex items-center justify-between mt-2">
{isValidTitle && (
<CheckCircle className="w-5 h-5 text-green-400" />
)}
{getTitleLength() > 0 && !isValidTitle && (
<AlertCircle className="w-5 h-5 text-yellow-400" />
)}
</div>
</div>
{/* Description */}
<div>
<label className="block text-sm font-semibold text-white mb-2">
@@ -275,6 +333,30 @@ export default function Seo() {
</div>
</div>
<div>
<label className="block text-sm font-semibold text-white mb-2">
{t("Meta Description")} (ru)
</label>
<textarea
name="description_ru"
value={formData.description_ru}
onChange={handleChange}
placeholder={t("Sahifa tavsifi (120160 belgi)") + " (ru)"}
className="w-full bg-slate-700 text-white px-4 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
/>
<div className="flex items-center justify-between mt-2">
<span className="text-sm text-slate-400">
{getDescriptionLength()} / 160
</span>
{isValidDescription && (
<CheckCircle className="w-5 h-5 text-green-400" />
)}
{getDescriptionLength() > 0 && !isValidDescription && (
<AlertCircle className="w-5 h-5 text-yellow-400" />
)}
</div>
</div>
{/* Keywords */}
<div>
<label className="block text-sm font-semibold text-white mb-2">
@@ -293,6 +375,25 @@ export default function Seo() {
</p>
</div>
<div>
<label className="block text-sm font-semibold text-white mb-2">
{t("Keywords")} (ru)
</label>
<input
type="text"
name="keywords_ru"
value={formData.keywords_ru}
onChange={handleChange}
placeholder={
t("Kalit so'zlar (vergul bilan ajratilgan)") + " (ru)"
}
className="w-full bg-slate-700 text-white px-4 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<p className="text-xs text-slate-400 mt-1">
{t("Masalan: Python, Web Development, Coding")}
</p>
</div>
{/* OG Tags */}
<div className="border-t border-slate-700 pt-6">
<h3 className="text-sm font-semibold text-white mb-4">
@@ -314,6 +415,20 @@ export default function Seo() {
/>
</div>
<div>
<label className="block text-sm text-slate-300 mb-2">
{t("OG Title")} (ru)
</label>
<input
type="text"
name="ogTitle_ru"
value={formData.ogTitle_ru}
onChange={handleChange}
placeholder={t("Ijtimoiy tarmoqdagi sarlavha") + " (ru)"}
className="w-full bg-slate-700 text-white px-4 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-sm text-slate-300 mb-2">
{t("OG Description")}
@@ -327,6 +442,19 @@ export default function Seo() {
/>
</div>
<div>
<label className="block text-sm text-slate-300 mb-2">
{t("OG Description")} (ru)
</label>
<textarea
name="ogDescription_ru"
value={formData.ogDescription_ru}
onChange={handleChange}
placeholder={t("Ijtimoiy tarmoqdagi tavsif") + " (ru)"}
className="w-full bg-slate-700 text-white px-4 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
/>
</div>
<div>
<label className="block text-sm text-slate-300 mb-2">
<ImageIcon className="inline w-4 h-4 mr-1" />{" "}
@@ -368,7 +496,7 @@ export default function Seo() {
<button
onClick={handleSave}
disabled={isPending}
disabled={allSeo && allSeo.length !== 0}
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 rounded-lg transition-colors disabled:opacity-50"
>
{isPending || editPending ? (