11import React from 'react' ;
22import { useNavigate } from 'react-router-dom' ;
3- import { Card , CardBody , CardFooter , CardHeader , Chip } from '@nextui-org/react' ;
3+ import {
4+ Card , CardBody , CardFooter , CardHeader , Chip , Pagination , Select , SelectItem
5+ } from '@nextui-org/react' ;
46import { Post } from '../services/apiService' ;
57import { Calendar , Clock , Tag } from 'lucide-react' ;
68import DOMPurify from 'dompurify' ;
@@ -19,16 +21,19 @@ const PostList: React.FC<PostListProps> = ({
1921 posts,
2022 loading,
2123 error,
24+ page,
25+ sortBy,
26+ onPageChange,
27+ onSortChange,
2228} ) => {
23-
2429 const navigate = useNavigate ( ) ;
25-
26- // const sortOptions = [
27- // { value: "createdAt,desc", label: "Newest First" },
28- // { value: "createdAt,asc", label: "Oldest First" },
29- // { value: "title,asc", label: "Title A-Z" },
30- // { value: "title,desc", label: "Title Z-A" },
31- // ];
30+
31+ const sortOptions = [
32+ { value : "createdAt,desc" , label : "Newest First" } ,
33+ { value : "createdAt,asc" , label : "Oldest First" } ,
34+ { value : "title,asc" , label : "Title A-Z" } ,
35+ { value : "title,desc" , label : "Title Z-A" } ,
36+ ] ;
3237
3338 const formatDate = ( dateString : string ) => {
3439 return new Date ( dateString ) . toLocaleDateString ( 'en-US' , {
@@ -38,35 +43,18 @@ const PostList: React.FC<PostListProps> = ({
3843 } ) ;
3944 } ;
4045
41- // const createSanitizedHTML = (content: string) => {
42- // return {
43- // __html: DOMPurify.sanitize(content, {
44- // ALLOWED_TAGS: ['p', 'strong', 'em', 'br'],
45- // ALLOWED_ATTR: []
46- // })
47- // };
48- // };
49-
5046 const createExcerpt = ( content : string ) => {
51- // First sanitize the HTML
5247 const sanitizedContent = DOMPurify . sanitize ( content , {
5348 ALLOWED_TAGS : [ 'p' , 'strong' , 'em' , 'br' ] ,
5449 ALLOWED_ATTR : [ ]
5550 } ) ;
56-
57- // Create a temporary div to parse the HTML
5851 const tempDiv = document . createElement ( 'div' ) ;
5952 tempDiv . innerHTML = sanitizedContent ;
60-
61- // Get the text content and limit it
6253 let textContent = tempDiv . textContent || tempDiv . innerText || '' ;
6354 textContent = textContent . trim ( ) ;
64-
65- // Limit to roughly 200 characters, ending at the last complete word
6655 if ( textContent . length > 200 ) {
6756 textContent = textContent . substring ( 0 , 200 ) . split ( ' ' ) . slice ( 0 , - 1 ) . join ( ' ' ) + '...' ;
6857 }
69-
7058 return textContent ;
7159 } ;
7260
@@ -79,12 +67,12 @@ const PostList: React.FC<PostListProps> = ({
7967 }
8068
8169 const navToPostPage = ( post : Post ) => {
82- navigate ( `/posts/${ post . id } ` )
83- }
70+ navigate ( `/posts/${ post . id } ` ) ;
71+ } ;
8472
8573 return (
8674 < div className = "w-full space-y-6" >
87- { /* <div className="flex justify-end mb-4">
75+ < div className = "flex justify-end mb-4" >
8876 < Select
8977 label = "Sort by"
9078 selectedKeys = { [ sortBy ] }
@@ -97,7 +85,7 @@ const PostList: React.FC<PostListProps> = ({
9785 </ SelectItem >
9886 ) ) }
9987 </ Select >
100- </div> */ }
88+ </ div >
10189
10290 { loading ? (
10391 < div className = "space-y-4" >
@@ -114,21 +102,18 @@ const PostList: React.FC<PostListProps> = ({
114102 < >
115103 < div className = "space-y-4" >
116104 { posts ?. map ( ( post ) => (
117- < Card key = { post . id } className = "w-full p-2" isPressable = { true } onPress = { ( ) => navToPostPage ( post ) } >
118- < CardHeader className = "flex gap-3" >
119- < div className = 'flex flex-col' >
120- < h2 className = "text-xl font-bold text-left" >
121- { post . title }
122- </ h2 >
123- < p className = "text-small text-default-500" >
124- by { post . author ?. name }
125- </ p >
126- </ div >
105+ < Card
106+ key = { post . id }
107+ className = "w-full p-2"
108+ isPressable = { true }
109+ onPress = { ( ) => navToPostPage ( post ) }
110+ >
111+ < CardHeader className = "flex flex-col items-start gap-1" >
112+ < h2 className = "text-xl font-bold" > { post . title } </ h2 >
113+ < p className = "text-small text-default-500" > by { post . author ?. name } </ p >
127114 </ CardHeader >
128115 < CardBody >
129- < p className = "line-clamp-3" >
130- { createExcerpt ( post . content ) }
131- </ p >
116+ < p className = "line-clamp-3" > { createExcerpt ( post . content ) } </ p >
132117 </ CardBody >
133118 < CardFooter className = "flex flex-wrap gap-3" >
134119 < div className = "flex items-center gap-1 text-small text-default-500" >
@@ -140,9 +125,7 @@ const PostList: React.FC<PostListProps> = ({
140125 { post . readingTime } min read
141126 </ div >
142127 < div className = "flex flex-wrap gap-2" >
143- < Chip
144- className = "bg-primary-100 text-primary"
145- >
128+ < Chip className = "bg-primary-100 text-primary" >
146129 { post . category . name }
147130 </ Chip >
148131 { post . tags . map ( ( tag ) => (
@@ -160,20 +143,20 @@ const PostList: React.FC<PostListProps> = ({
160143 ) ) }
161144 </ div >
162145
163- { /* { posts && posts.totalPages > 1 && (
146+ { posts && Array . isArray ( posts ) && posts . length > 0 && (
164147 < div className = "flex justify-center mt-6" >
165148 < Pagination
166- total={posts.totalPages}
149+ total = { 10 } // replace with posts.totalPages if available
167150 page = { page }
168151 onChange = { onPageChange }
169152 showControls
170153 />
171154 </ div >
172- )} */ }
155+ ) }
173156 </ >
174157 ) }
175158 </ div >
176159 ) ;
177160} ;
178161
179- export default PostList ;
162+ export default PostList ;
0 commit comments