+
+
+ |
+
+
+
+
+ { getExcerpt( post.content.rendered ) }
+
+
+
+
+
+ { post.status !== 'publish' && (
+
+ ) }
+ { post.status === 'publish' && (
+
+ ) }
+
+
+ |
+
+ { post._embedded?.author?.[ 0 ]?.name || 'Unknown' }
+ |
+
+ { post._embedded?.[ 'wp:term' ]?.[ 0 ]?.map( ( term ) => (
+
+ { term.name }
+
+ ) ) || 'Uncategorized' }
+ |
+
+ { post._embedded?.[ 'wp:term' ]?.[ 1 ]?.map( ( tag ) => (
+
+ { tag.name }
+
+ ) ) || 'No tags' }
+ |
+
+ { getStatusBadge( post.status ) }
+ |
+
+ { formatDate( post.date ) }
+ |
+
+
+
+
+ { showActions && (
+
+
+
+
+
+
+
+
+
+
+
+ ) }
+
+ |
+
+ );
+}
diff --git a/src/pages/Posts/components/PostsList.css b/src/pages/Posts/components/PostsList.css
new file mode 100644
index 0000000..91a33eb
--- /dev/null
+++ b/src/pages/Posts/components/PostsList.css
@@ -0,0 +1,224 @@
+/* Posts List Styles */
+.helix-posts-list {
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+}
+
+.helix-posts-table-container {
+ overflow-x: auto;
+}
+
+.helix-posts-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 14px;
+}
+
+.helix-posts-table th {
+ background-color: #f8f9fa;
+ padding: 16px 12px;
+ text-align: left;
+ font-weight: 600;
+ color: #1a1a1a;
+ border-bottom: 2px solid #e1e5e9;
+ white-space: nowrap;
+}
+
+.helix-posts-table td {
+ padding: 16px 12px;
+ border-bottom: 1px solid #f0f0f1;
+ vertical-align: top;
+}
+
+.helix-posts-table tbody tr:hover {
+ background-color: #f8f9fa;
+}
+
+/* Table Column Specific Styles */
+.helix-posts-table__checkbox {
+ width: 40px;
+ text-align: center;
+}
+
+.helix-posts-table__checkbox input[type="checkbox"] {
+ width: 18px;
+ height: 18px;
+ cursor: pointer;
+}
+
+.helix-posts-table__title {
+ min-width: 300px;
+}
+
+.helix-posts-table__author {
+ min-width: 120px;
+}
+
+.helix-posts-table__categories {
+ min-width: 150px;
+}
+
+.helix-posts-table__tags {
+ min-width: 150px;
+}
+
+.helix-posts-table__status {
+ min-width: 100px;
+}
+
+.helix-posts-table__date {
+ min-width: 100px;
+}
+
+.helix-posts-table__actions {
+ width: 80px;
+ text-align: center;
+}
+
+/* Post Title Styles */
+.helix-post-title__text {
+ margin: 0 0 8px 0;
+ font-size: 16px;
+ font-weight: 600;
+}
+
+.helix-post-title__text a {
+ color: #007cba;
+ text-decoration: none;
+}
+
+.helix-post-title__text a:hover {
+ color: #005a87;
+ text-decoration: underline;
+}
+
+.helix-post-title__excerpt {
+ margin: 0;
+ font-size: 13px;
+ color: #646970;
+ line-height: 1.4;
+}
+
+/* Status Badge Styles */
+.helix-status-badge {
+ padding: 4px 8px;
+ border-radius: 12px;
+ font-size: 12px;
+ font-weight: 500;
+ text-transform: capitalize;
+}
+
+.helix-status-badge--publish {
+ background-color: #d1e7dd;
+ color: #0f5132;
+}
+
+.helix-status-badge--draft {
+ background-color: #fff3cd;
+ color: #856404;
+}
+
+.helix-status-badge--private {
+ background-color: #f8d7da;
+ color: #721c24;
+}
+
+.helix-status-badge--pending {
+ background-color: #cce5ff;
+ color: #004085;
+}
+
+.helix-status-badge--future {
+ background-color: #e2e3e5;
+ color: #383d41;
+}
+
+/* Category and Tag Styles */
+.helix-category-tag,
+.helix-tag {
+ display: inline-block;
+ padding: 2px 8px;
+ margin: 2px 4px 2px 0;
+ border-radius: 12px;
+ font-size: 11px;
+ font-weight: 500;
+ background-color: #f0f0f1;
+ color: #50575e;
+}
+
+.helix-category-tag {
+ background-color: #e7f3ff;
+ color: #007cba;
+}
+
+/* Pagination Styles */
+.helix-pagination {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20px;
+ background-color: #f8f9fa;
+ border-top: 1px solid #e1e5e9;
+}
+
+.helix-pagination__info {
+ color: #646970;
+ font-size: 14px;
+}
+
+.helix-pagination__controls {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+}
+
+.helix-pagination__current {
+ font-weight: 500;
+ color: #1a1a1a;
+}
+
+/* Responsive Design */
+@media (max-width: 1024px) {
+ .helix-posts-table__categories,
+ .helix-posts-table__tags {
+ display: none;
+ }
+}
+
+@media (max-width: 768px) {
+ .helix-posts-table__author {
+ display: none;
+ }
+
+ .helix-posts-table__title {
+ min-width: 200px;
+ }
+
+ .helix-pagination {
+ flex-direction: column;
+ gap: 16px;
+ text-align: center;
+ }
+}
+
+@media (max-width: 480px) {
+ .helix-posts-table th,
+ .helix-posts-table td {
+ padding: 12px 8px;
+ font-size: 13px;
+ }
+
+ .helix-posts-table__date {
+ display: none;
+ }
+
+ .helix-post-title__text {
+ font-size: 14px;
+ }
+
+ .helix-post-title__excerpt {
+ font-size: 12px;
+ }
+}
diff --git a/src/pages/Posts/components/PostsList.jsx b/src/pages/Posts/components/PostsList.jsx
new file mode 100644
index 0000000..06ab17a
--- /dev/null
+++ b/src/pages/Posts/components/PostsList.jsx
@@ -0,0 +1,114 @@
+import React from 'react';
+import PostRow from './PostRow';
+import './PostsList.css';
+
+/**
+ * Posts List Component - Displays posts in a table format
+ */
+export default function PostsList( {
+ posts,
+ loading,
+ pagination,
+ onPageChange,
+ onDelete,
+ onStatusChange,
+} ) {
+ if ( loading ) {
+ return (
+
+
+
+ { pagination.totalPages > 1 && (
+
+
+ Showing{ ' ' }
+ { ( pagination.page - 1 ) * pagination.perPage + 1 } to{ ' ' }
+ { Math.min(
+ pagination.page * pagination.perPage,
+ pagination.total
+ ) }{ ' ' }
+ of { pagination.total } posts
+
+
+
+
+ Page { pagination.page } of{ ' ' }
+ { pagination.totalPages }
+
+
+
+
+ ) }
+
+ );
+}
diff --git a/src/pages/Posts/utils/postsAPI.js b/src/pages/Posts/utils/postsAPI.js
new file mode 100644
index 0000000..26d3d8e
--- /dev/null
+++ b/src/pages/Posts/utils/postsAPI.js
@@ -0,0 +1,201 @@
+/**
+ * Posts API Utility Functions
+ * Centralized API calls for posts management
+ */
+
+const API_BASE =
+ window.helixData?.wpRestUrl || window.location.origin + '/wp-json/wp/v2/';
+
+/**
+ * Fetch posts with filters and pagination
+ */
+export const fetchPosts = async ( params = {} ) => {
+ const queryParams = new URLSearchParams( {
+ page: 1,
+ per_page: 20,
+ ...params,
+ } );
+
+ // Remove 'all' values as they're not valid API parameters
+ [ 'status', 'author', 'dateRange' ].forEach( ( key ) => {
+ if ( params[ key ] === 'all' ) {
+ queryParams.delete( key );
+ }
+ } );
+
+ try {
+ const response = await fetch( `${ API_BASE }posts?${ queryParams }` );
+
+ if ( ! response.ok ) {
+ throw new Error( `HTTP error! status: ${ response.status }` );
+ }
+
+ const posts = await response.json();
+ const total = response.headers.get( 'X-WP-Total' );
+ const totalPages = response.headers.get( 'X-WP-TotalPages' );
+
+ return {
+ posts,
+ pagination: {
+ total: parseInt( total ) || 0,
+ totalPages: parseInt( totalPages ) || 0,
+ },
+ };
+ } catch ( error ) {
+ // eslint-disable-next-line no-console
+ console.error( 'Error fetching posts:', error );
+ throw error;
+ }
+};
+
+/**
+ * Fetch a single post by ID
+ */
+export const fetchPost = async ( postId ) => {
+ try {
+ const response = await fetch( `${ API_BASE }posts/${ postId }` );
+
+ if ( ! response.ok ) {
+ throw new Error( `HTTP error! status: ${ response.status }` );
+ }
+
+ return await response.json();
+ } catch ( error ) {
+ // eslint-disable-next-line no-console
+ console.error( 'Error fetching post:', error );
+ throw error;
+ }
+};
+
+/**
+ * Create a new post
+ */
+export const createPost = async ( postData ) => {
+ try {
+ const response = await fetch( `${ API_BASE }posts`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-WP-Nonce': window.helixData?.nonce || '',
+ },
+ body: JSON.stringify( postData ),
+ } );
+
+ if ( ! response.ok ) {
+ throw new Error( `HTTP error! status: ${ response.status }` );
+ }
+
+ return await response.json();
+ } catch ( error ) {
+ // eslint-disable-next-line no-console
+ console.error( 'Error creating post:', error );
+ throw error;
+ }
+};
+
+/**
+ * Update an existing post
+ */
+export const updatePost = async ( postId, postData ) => {
+ try {
+ const response = await fetch( `${ API_BASE }posts/${ postId }`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-WP-Nonce': window.helixData?.nonce || '',
+ },
+ body: JSON.stringify( postData ),
+ } );
+
+ if ( ! response.ok ) {
+ throw new Error( `HTTP error! status: ${ response.status }` );
+ }
+
+ return await response.json();
+ } catch ( error ) {
+ // eslint-disable-next-line no-console
+ console.error( 'Error updating post:', error );
+ throw error;
+ }
+};
+
+/**
+ * Delete a post
+ */
+export const deletePost = async ( postId ) => {
+ try {
+ const response = await fetch( `${ API_BASE }posts/${ postId }`, {
+ method: 'DELETE',
+ headers: {
+ 'X-WP-Nonce': window.helixData?.nonce || '',
+ },
+ } );
+
+ if ( ! response.ok ) {
+ throw new Error( `HTTP error! status: ${ response.status }` );
+ }
+
+ return true;
+ } catch ( error ) {
+ // eslint-disable-next-line no-console
+ console.error( 'Error deleting post:', error );
+ throw error;
+ }
+};
+
+/**
+ * Fetch authors for filter dropdown
+ */
+export const fetchAuthors = async () => {
+ try {
+ const response = await fetch( `${ API_BASE }users?per_page=100` );
+
+ if ( ! response.ok ) {
+ throw new Error( `HTTP error! status: ${ response.status }` );
+ }
+
+ return await response.json();
+ } catch ( error ) {
+ // eslint-disable-next-line no-console
+ console.error( 'Error fetching authors:', error );
+ throw error;
+ }
+};
+
+/**
+ * Fetch categories for filter dropdown
+ */
+export const fetchCategories = async () => {
+ try {
+ const response = await fetch( `${ API_BASE }categories?per_page=100` );
+
+ if ( ! response.ok ) {
+ throw new Error( `HTTP error! status: ${ response.status }` );
+ }
+
+ return await response.json();
+ } catch ( error ) {
+ // eslint-disable-next-line no-console
+ console.error( 'Error fetching categories:', error );
+ throw error;
+ }
+};
+
+/**
+ * Fetch tags for filter dropdown
+ */
+export const fetchTags = async () => {
+ try {
+ const response = await fetch( `${ API_BASE }tags?per_page=100` );
+
+ if ( ! response.ok ) {
+ throw new Error( `HTTP error! status: ${ response.status }` );
+ }
+
+ return await response.json();
+ } catch ( error ) {
+ // eslint-disable-next-line no-console
+ console.error( 'Error fetching tags:', error );
+ throw error;
+ }
+};