(props)
| 22 | |
| 23 | |
| 24 | const ReadMoreBlog = (props) => { |
| 25 | const VITE_SERVER_PORT = import.meta.env.VITE_SERVER_PORT || "https://bitbox-uxbo.onrender.com"; |
| 26 | |
| 27 | const { id } = useParams(); |
| 28 | const [blogPost, setBlogPost] = useState(null); |
| 29 | const fetchData = async () => { |
| 30 | try { |
| 31 | const response = await fetch(`${VITE_SERVER_PORT}/api/blog/getById/${id}`); |
| 32 | |
| 33 | const data = await response.json(); |
| 34 | setBlogPost(data.blog); // Set the retrieved blog post to state |
| 35 | } catch (error) { |
| 36 | console.error('Error fetching blog post:', error); |
| 37 | } |
| 38 | }; |
| 39 | |
| 40 | useEffect(() => { |
| 41 | fetchData(); |
| 42 | }, [id]); |
| 43 | |
| 44 | const categoryImage = (cat) => { |
| 45 | const imgSrc = images.find(image => image.category === cat); |
| 46 | if (imgSrc) { |
| 47 | return imgSrc.src; |
| 48 | } |
| 49 | return '' // Safeguard for undefined |
| 50 | }; |
| 51 | |
| 52 | if (!blogPost) return <div>Loading...</div>; |
| 53 | |
| 54 | return ( |
| 55 | <> |
| 56 | <div className={`max-w-3xl mx-auto my-8 mt-36 ${props.mode === 'light' ? 'bg-white' : 'bg-gray-800'} rounded-lg shadow-md overflow-hidden`}> |
| 57 | <img |
| 58 | src={categoryImage(blogPost.category)} |
| 59 | alt={blogPost.title} |
| 60 | className="w-full h-64 object-cover" |
| 61 | onError={(e) => { e.target.onerror = null; e.target.src = '/placeholder.svg'; }} |
| 62 | /> |
| 63 | <div className="p-6"> |
| 64 | <h1 className={`text-3xl font-bold ${props.mode === 'light' ? 'text-gray-900' : 'text-white'} mb-4`}>{blogPost.title}</h1> |
| 65 | <div className={`flex items-center ${props.mode === 'light' ? 'text-gray-600' : 'text-gray-400'} text-sm mb-4`}> |
| 66 | <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2" viewBox="0 0 24 24" stroke="currentColor" fill="none"> |
| 67 | <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" /> |
| 68 | </svg> |
| 69 | <time dateTime={new Date(blogPost.date).toISOString()}> |
| 70 | {new Date(blogPost.date).toDateString()} |
| 71 | </time> |
| 72 | <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 ml-4 mr-2" viewBox="0 0 24 24" stroke="currentColor" fill="none"> |
| 73 | <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" /> |
| 74 | </svg> |
| 75 | <span>{blogPost.category}</span> |
| 76 | </div> |
| 77 | <div |
| 78 | className={`${props.mode === 'light' ? 'text-gray-700' : 'text-gray-100'} leading-relaxed mb-4`} |
| 79 | dangerouslySetInnerHTML={{ __html: blogPost.content }} |
| 80 | /> |
| 81 | </div> |
nothing calls this directly
no test coverage detected