booking
This commit is contained in:
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 bo‘lsa qo‘shamiz
|
||||
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 (30–60 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 (120–160 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 ? (
|
||||
|
||||
Reference in New Issue
Block a user