Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/components/data-not-avaiable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const DateNotAvailable = ({ text = " No data available to show" }) => {
return (
<div className="flex flex-col md:flex-row flex-wrap gap-2.5 w-full items-center justify-center text-rose-500">
{text}
</div>
);
};

export default DateNotAvailable;
272 changes: 272 additions & 0 deletions src/components/editor/artical-info.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
"use client";

import { Badge } from "@/components/ui/badge";
import { Calendar, User, X } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button";
import type { ContentManagement } from "@/types";
import { useAdminData } from "@/store/hooks/users/useAdminData";

interface ArticleInfoProps {
contentData: ContentManagement;
onContentDataChange: (updates: Partial<ContentManagement>) => void;
}

export const ArticleInfo = ({
contentData,
onContentDataChange,
}: ArticleInfoProps) => {
// Add keyword
const addKeyword = (keyword: string) => {
if (keyword.trim() && !contentData.keywords.includes(keyword.trim())) {
onContentDataChange({
keywords: [...contentData.keywords, keyword.trim()],
});
}
};

// Remove keyword
const removeKeyword = (keyword: string) => {
onContentDataChange({
keywords: contentData.keywords.filter((k) => k !== keyword),
});
};

// Handle Enter key for keywords
const handleKeywordKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
e.preventDefault();
const target = e.target as HTMLInputElement;
addKeyword(target.value);
target.value = "";
}
};

const { adminInfo, error, loading } = useAdminData();

if (loading) return <div className="p-4">Loading...</div>;
if (error) return <div className="p-4">Error loading data</div>;

return (
<div className="h-full border rounded-lg bg-muted/30 p-4 overflow-y-auto">
<div className="space-y-6">
{/* Status Info */}
<div className="space-y-3">
<h3 className="font-semibold text-sm">Article Status</h3>

<div className="flex items-center gap-2">
<Badge
variant={
contentData.status === "Published" ? "default" : "secondary"
}
>
{contentData.status || "Draft"}
</Badge>
{contentData.category && (
<Badge variant="outline">{contentData.category}</Badge>
)}
</div>

<div className="space-y-2 text-xs text-muted-foreground">
<div className="flex items-center gap-2">
<Calendar className="w-3 h-3" />
<span>{new Date().toLocaleDateString()}</span>
</div>
<div className="flex items-center gap-2">
<User className="w-3 h-3" />
<span>
{adminInfo?.firstname} {adminInfo?.lastname}
</span>
</div>
</div>
</div>

{/* Basic Info */}
<div className="space-y-4">
<h3 className="font-semibold text-sm">Basic Information</h3>

<div className="space-y-3">
<div>
<Label htmlFor="title" className="text-xs">
Title
</Label>
<Input
id="title"
name="title"
value={contentData.title || ""}
onChange={(e) => onContentDataChange({ title: e.target.value })}
placeholder="Article title"
className="mt-1"
/>
</div>

<div>
<Label htmlFor="subtitle" className="text-xs">
Subtitle
</Label>
<Input
id="subtitle"
name="subtitle"
value={contentData.subtitle || ""}
onChange={(e) =>
onContentDataChange({ subtitle: e.target.value })
}
placeholder="Subtitle (optional)"
className="mt-1"
/>
</div>

<div>
<Label htmlFor="coverimage" className="text-xs">
Cover Image
</Label>
<Input
id="coverimage"
name="coverimage"
type="file"
accept="image/*"
onChange={(e) => {
const file = e.target.files?.[0];
if (file) {
const url = URL.createObjectURL(file);
onContentDataChange({ coverimage: url });
}
}}
className="mt-1"
/>
{contentData.coverimage && (
<div className="mt-2">
<img
src={contentData.coverimage}
alt="Cover"
className="w-full h-20 object-cover rounded"
/>
<Button
variant="outline"
size="sm"
className="mt-1 w-full text-xs"
onClick={() => onContentDataChange({ coverimage: null })}
>
Remove
</Button>
</div>
)}
</div>
</div>
</div>

{/* SEO */}
<div className="space-y-4">
<h3 className="font-semibold text-sm">SEO Settings</h3>

<div className="space-y-3">
<div>
<Label htmlFor="metaTitle" className="text-xs">
Meta Title
</Label>
<Input
id="metaTitle"
name="metaTitle"
value={contentData.metaTitle || ""}
onChange={(e) =>
onContentDataChange({ metaTitle: e.target.value })
}
placeholder="SEO title"
maxLength={60}
className="mt-1"
/>
<div className="text-xs text-muted-foreground mt-1">
{(contentData.metaTitle || "").length}/60
</div>
</div>

<div>
<Label htmlFor="metaDescription" className="text-xs">
Meta Description
</Label>
<Textarea
id="metaDescription"
name="metaDescription"
value={contentData.metaDescription || ""}
onChange={(e) =>
onContentDataChange({ metaDescription: e.target.value })
}
placeholder="SEO description"
maxLength={155}
rows={2}
className="mt-1"
/>
<div className="text-xs text-muted-foreground mt-1">
{(contentData.metaDescription || "").length}/155
</div>
</div>

<div>
<Label htmlFor="slug" className="text-xs">
URL Slug
</Label>
<Input
id="slug"
name="slug"
value={contentData.slug || ""}
onChange={(e) => onContentDataChange({ slug: e.target.value })}
placeholder="url-slug"
className="mt-1"
/>
</div>

<div>
<Label htmlFor="focusKeyword" className="text-xs">
Focus Keyword
</Label>
<Input
id="focusKeyword"
name="focusKeyword"
value={contentData.focusKeyword || ""}
onChange={(e) =>
onContentDataChange({ focusKeyword: e.target.value })
}
placeholder="Main keyword"
className="mt-1"
/>
</div>

<div>
<Label htmlFor="keywords" className="text-xs">
Keywords
</Label>
<Input
id="keywords"
name="keywords"
placeholder="Add keyword (Enter to add)"
onKeyDown={handleKeywordKeyPress}
className="mt-1"
/>
<div className="flex flex-wrap gap-1 mt-2">
{contentData.keywords
.filter((k) => k !== "")
.map((keyword) => (
<Badge
key={keyword}
variant="secondary"
className="text-xs"
>
{keyword}
<button
className="ml-1 hover:bg-destructive/20 rounded-full"
onClick={() => removeKeyword(keyword)}
>
<X className="w-2 h-2" />
</button>
</Badge>
))}
</div>
</div>
</div>
</div>
</div>
</div>
);
};
Loading