feat: seo preview #44
@@ -0,0 +1,131 @@
|
|||||||
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
interface SeoPreviewData {
|
||||||
|
seo?: {
|
||||||
|
ogImage?: string;
|
||||||
|
ogTitle?: string;
|
||||||
|
seoTitle?: string;
|
||||||
|
ogDescription?: string;
|
||||||
|
metaDescription?: string;
|
||||||
|
slug?: string;
|
||||||
|
};
|
||||||
|
doctorId?: string;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SeoPreviewProps {
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
previewData?: SeoPreviewData | null;
|
||||||
|
url?: string;
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SeoPreview({
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
previewData,
|
||||||
|
url,
|
||||||
|
title = "SEO Preview",
|
||||||
|
}: SeoPreviewProps) {
|
||||||
|
const previewUrl = url || "#";
|
||||||
|
const imageUrl =
|
||||||
|
previewData?.seo?.ogImage || "https://placehold.co/1200x630?text=GG+Hospital";
|
||||||
|
const ogTitle =
|
||||||
|
previewData?.seo?.ogTitle || previewData?.seo?.seoTitle || "GG Hospital";
|
||||||
|
const ogDescription =
|
||||||
|
previewData?.seo?.ogDescription || previewData?.seo?.metaDescription ||
|
||||||
|
"No description available";
|
||||||
|
const searchTitle =
|
||||||
|
previewData?.seo?.seoTitle || previewData?.seo?.ogTitle || "SEO title preview";
|
||||||
|
const searchDescription =
|
||||||
|
previewData?.seo?.metaDescription || previewData?.seo?.ogDescription ||
|
||||||
|
"No meta description available";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
|
<DialogContent className="sm:!max-w-4xl overflow-hidden">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="text-xl">{title}</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
{previewData ? (
|
||||||
|
<div className="space-y-10 py-2">
|
||||||
|
<div>
|
||||||
|
<p className="mb-4 text-sm font-semibold text-muted-foreground">
|
||||||
|
Social Media Preview (WhatsApp / Facebook)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={previewUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="block max-w-[560px] overflow-hidden rounded-xl border bg-white shadow-sm transition hover:shadow-md"
|
||||||
|
>
|
||||||
|
<div className="aspect-[1.91/1] overflow-hidden bg-muted">
|
||||||
|
<img
|
||||||
|
src={imageUrl}
|
||||||
|
alt="OG Preview"
|
||||||
|
className="h-full w-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t bg-[#f0f2f5] px-4 py-3">
|
||||||
|
<p className="truncate text-[11px] uppercase tracking-wide text-[#65676b]">
|
||||||
|
gg-hospital.com
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 className="mt-1 line-clamp-2 text-[18px] font-semibold leading-snug text-[#1c1e21]">
|
||||||
|
{ogTitle}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p className="mt-1 line-clamp-2 text-[14px] text-[#65676b]">
|
||||||
|
{ogDescription}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="mb-4 text-sm font-semibold text-muted-foreground">
|
||||||
|
Google Search Preview
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="rounded-xl border bg-white p-6">
|
||||||
|
<a
|
||||||
|
href={previewUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="block"
|
||||||
|
>
|
||||||
|
<p className="truncate text-[14px] text-[#202124] hover:underline">
|
||||||
|
{previewUrl}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 className="mt-1 text-[22px] leading-tight text-[#1a0dab] hover:underline">
|
||||||
|
{searchTitle}
|
||||||
|
</h3>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<p className="mt-2 line-clamp-3 text-[14px] leading-6 text-[#4d5156]">
|
||||||
|
{searchDescription}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="p-6 text-sm text-muted-foreground">
|
||||||
|
No preview data available.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<DialogFooter className="p-6 border-t bg-background z-10 mt-0">
|
||||||
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
|
import SeoPreview from "@/components/SeoPreview/SeoPreview";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
@@ -1159,97 +1160,12 @@ export default function DoctorPage() {
|
|||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<Dialog open={openOgPreview} onOpenChange={setOpenOgPreview}>
|
<SeoPreview
|
||||||
<DialogContent className="sm:!max-w-4xl overflow-hidden">
|
open={openOgPreview}
|
||||||
<DialogHeader>
|
onOpenChange={setOpenOgPreview}
|
||||||
<DialogTitle className="text-xl">SEO Preview</DialogTitle>
|
previewData={previewDoctor}
|
||||||
</DialogHeader>
|
url={getDoctorUrl(previewDoctor)}
|
||||||
|
|
||||||
{previewDoctor && (
|
|
||||||
<div className="space-y-10 py-2">
|
|
||||||
{/* SOCIAL MEDIA PREVIEW */}
|
|
||||||
<div>
|
|
||||||
<p className="mb-4 text-sm font-semibold text-muted-foreground">
|
|
||||||
Social Media Preview (WhatsApp / Facebook)
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href={getDoctorUrl(previewDoctor)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="block max-w-[560px] overflow-hidden rounded-xl border bg-white shadow-sm transition hover:shadow-md"
|
|
||||||
>
|
|
||||||
{/* IMAGE */}
|
|
||||||
<div className="aspect-[1.91/1] overflow-hidden bg-muted">
|
|
||||||
<img
|
|
||||||
src={
|
|
||||||
previewDoctor?.seo?.ogImage ||
|
|
||||||
"https://placehold.co/1200x630?text=GG+Hospital"
|
|
||||||
}
|
|
||||||
alt="OG Preview"
|
|
||||||
className="h-full w-full object-cover"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* CONTENT */}
|
|
||||||
<div className="border-t bg-[#f0f2f5] px-4 py-3">
|
|
||||||
<p className="truncate text-[11px] uppercase tracking-wide text-[#65676b]">
|
|
||||||
gg-hospital.com
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 className="mt-1 line-clamp-2 text-[18px] font-semibold leading-snug text-[#1c1e21]">
|
|
||||||
{previewDoctor?.seo?.ogTitle ||
|
|
||||||
previewDoctor?.seo?.seoTitle ||
|
|
||||||
"GG Hospital"}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p className="mt-1 line-clamp-2 text-[14px] text-[#65676b]">
|
|
||||||
{previewDoctor?.seo?.ogDescription ||
|
|
||||||
previewDoctor?.seo?.metaDescription ||
|
|
||||||
"No description available"}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* GOOGLE SEARCH PREVIEW */}
|
|
||||||
<div>
|
|
||||||
<p className="mb-4 text-sm font-semibold text-muted-foreground">
|
|
||||||
Google Search Preview
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="rounded-xl border bg-white p-6">
|
|
||||||
<a
|
|
||||||
href={getDoctorUrl(previewDoctor)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="block"
|
|
||||||
>
|
|
||||||
{/* URL */}
|
|
||||||
<p className="truncate text-[14px] text-[#202124] hover:underline">
|
|
||||||
{getDoctorUrl(previewDoctor)}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* TITLE */}
|
|
||||||
<h3 className="mt-1 text-[22px] leading-tight text-[#1a0dab] hover:underline">
|
|
||||||
{previewDoctor?.seo?.seoTitle ||
|
|
||||||
previewDoctor?.seo?.ogTitle ||
|
|
||||||
"SEO title preview"}
|
|
||||||
</h3>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{/* DESCRIPTION */}
|
|
||||||
<p className="mt-2 line-clamp-3 text-[14px] leading-6 text-[#4d5156]">
|
|
||||||
{previewDoctor?.seo?.metaDescription ||
|
|
||||||
previewDoctor?.seo?.ogDescription ||
|
|
||||||
"No meta description available"}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user