Shared UI Components
Overview
The Blogify frontend is built using a modular component architecture. Shared UI components are located in frontend/src/components and are designed to be reusable across the feed, profile pages, and individual post views. These components leverage Tailwind CSS for styling and TypeScript for type safety.
Authentication Components
RequireAuth
A wrapper component used to protect client-side routes. It ensures that only authenticated users can view the wrapped content. If a user is not logged in, it typically handles redirection to the login page.
Usage:
import { RequireAuth } from '@/components';
export default function ProtectedPage() {
return (
<RequireAuth>
<main>This content is only visible to logged-in users.</main>
</RequireAuth>
);
}
Content Components
PostCard
The PostCard is the primary display unit for the blog feed and user profiles. It renders a summary of a post, including the title, featured image, tags, and author metadata.
Props Interface:
| Prop | Type | Description |
| :--- | :--- | :--- |
| post | Post | The post object containing title, content, and metadata. |
| authorName | string | The display name of the post's creator. |
Usage:
<PostCard
post={postData}
authorName={authors[postData.user_id]}
/>
PostCardSkeleton
A placeholder component used during the loading state of the feed. It mirrors the layout of the PostCard using CSS animations (pulse effect) to improve perceived performance.
Usage:
{loading && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{[1, 2, 3, 4].map((i) => (
<PostCardSkeleton key={i} />
))}
</div>
)}
Navigation & Layout
Sidebar
The Sidebar component provides contextual navigation and supplementary information. In the main feed, it typically houses the "New Post" trigger (on desktop), community statistics, or tag filtering.
Pagination
A controlled component used to navigate through paginated API results. It calculates the necessary page links based on the total number of items and the current active page.
Props Interface:
| Prop | Type | Description |
| :--- | :--- | :--- |
| currentPage | number | The current active page (1-indexed). |
| totalPages | number | Total number of pages available. |
| onPageChange | (page: number) => void | Callback triggered when a new page is selected. |
Usage:
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={(page) => router.push(`/feed?page=${page}`)}
/>
Action Components
EditPostButton
A contextual button that appears on post details. It includes internal logic to verify if the currently logged-in user is the owner of the post before rendering the edit link.
Props Interface:
| Prop | Type | Description |
| :--- | :--- | :--- |
| postId | string | The UUID of the post to edit. |
| authorId | string | The ID of the post's author for ownership verification. |
DeletePostButton
Handles the deletion flow for blog posts. Like the edit button, it performs ownership checks and typically triggers a confirmation dialog or immediate API call followed by a redirect.
Props Interface:
| Prop | Type | Description |
| :--- | :--- | :--- |
| postId | string | The UUID of the post to delete. |
| authorId | string | The ID of the post's author. |