diff --git a/src/components/Comment copy.jsx b/src/components/Comment copy.jsx
new file mode 100644
index 0000000..3357618
--- /dev/null
+++ b/src/components/Comment copy.jsx
@@ -0,0 +1,371 @@
+import React, { useEffect, useState } from 'react';
+import MDEditor, { commands } from '@uiw/react-md-editor';
+import { Card } from "./ui/card";
+import { Label } from "./ui/label";
+import { Button } from "./ui/button";
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog";
+import { Input } from "./ui/input";
+import { useIsLoggedIn } from '../lib/isLoggedIn';
+
+const COMMENTS_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/comments/';
+const MINIO_UPLOAD_URL = 'https://hostapi2.cs1.hz.siliconpin.com/api/storage/upload';
+
+export default function Comment(props) {
+ const [comments, setComments] = useState([]);
+ const [newComment, setNewComment] = useState({ comment: '' });
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [submitSuccess, setSubmitSuccess] = useState(false);
+ const [submitError, setSubmitError] = useState('');
+ const [isLoadingComments, setIsLoadingComments] = useState(true);
+ const [editorMode, setEditorMode] = useState('edit');
+ const [imageDialogOpen, setImageDialogOpen] = useState(false);
+ const [imageUrlInput, setImageUrlInput] = useState('');
+ const [imageUploadFile, setImageUploadFile] = useState(null);
+ const [imageUploadPreview, setImageUploadPreview] = useState('');
+ const [uploadProgress, setUploadProgress] = useState(0);
+ const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn();
+
+ // Custom image command for MDEditor
+ const customImageCommand = {
+ name: 'image',
+ keyCommand: 'image',
+ buttonProps: { 'aria-label': 'Insert image' },
+ icon: (
+
+ ),
+ execute: () => {
+ setImageDialogOpen(true);
+ },
+ };
+
+ // Get all default commands and replace the image command
+ const allCommands = commands.getCommands().map(cmd => {
+ if (cmd.name === 'image') {
+ return customImageCommand;
+ }
+ return cmd;
+ });
+
+ // Load comments when component mounts
+ useEffect(() => {
+ if (props.topicId) {
+ fetchComments(props.topicId);
+ }
+ }, [props.topicId]);
+
+ const fetchComments = async (topicId) => {
+ setIsLoadingComments(true);
+ try {
+ const response = await fetch(`${COMMENTS_API_URL}?topicId=${topicId}`, {
+ method: 'GET',
+ credentials: 'include',
+ });
+
+ const data = await response.json();
+ if (!response.ok) {
+ throw new Error(data.message || 'Failed to fetch comments');
+ }
+
+ if (data.success && data.comments) {
+ setComments(data.comments);
+ } else {
+ throw new Error('Invalid response format');
+ }
+ } catch (error) {
+ console.error('Error fetching comments:', error);
+ setSubmitError('Failed to load comments');
+ } finally {
+ setIsLoadingComments(false);
+ }
+ };
+
+ // Upload file to MinIO
+ const uploadToMinIO = async (file) => {
+ const formData = new FormData();
+ formData.append('file', file);
+ formData.append('api_key', 'wweifwehfwfhwhtuyegbvijvbfvegfreyf');
+
+ try {
+ const response = await fetch(MINIO_UPLOAD_URL, {
+ method: 'POST',
+ body: formData,
+ credentials: 'include'
+ });
+
+ if (!response.ok) {
+ throw new Error('Upload failed');
+ }
+
+ const data = await response.json();
+ return data.publicUrl;
+ } catch (error) {
+ console.error('Upload error:', error);
+ throw error;
+ }
+ };
+
+ // Handle image URL insertion
+ const handleInsertImageUrl = () => {
+ if (imageUrlInput) {
+ const imgMarkdown = ``;
+ setNewComment(prev => ({
+ ...prev,
+ comment: prev.comment ? `${prev.comment}\n${imgMarkdown}` : imgMarkdown
+ }));
+ setImageDialogOpen(false);
+ setImageUrlInput('');
+ }
+ };
+
+ // Handle image file selection
+ const handleImageFileSelect = (e) => {
+ const file = e.target.files[0];
+ if (file) {
+ setImageUploadFile(file);
+
+ // Create preview
+ const reader = new FileReader();
+ reader.onload = () => {
+ setImageUploadPreview(reader.result);
+ };
+ reader.readAsDataURL(file);
+ }
+ };
+
+ // Upload image file to MinIO and insert into editor
+ const handleImageUpload = async () => {
+ if (!imageUploadFile) return;
+
+ try {
+ setIsSubmitting(true);
+ setUploadProgress(0);
+
+ const uploadedUrl = await uploadToMinIO(imageUploadFile);
+
+ // Insert markdown for the uploaded image
+ const imgMarkdown = ``;
+ setNewComment(prev => ({
+ ...prev,
+ comment: prev.comment ? `${prev.comment}\n${imgMarkdown}` : imgMarkdown
+ }));
+
+ setImageDialogOpen(false);
+ setImageUploadFile(null);
+ setImageUploadPreview('');
+ } catch (error) {
+ setSubmitError('Failed to upload image: ' + error.message);
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ const handleSubmitComment = async (e) => {
+ e.preventDefault();
+ setIsSubmitting(true);
+ setSubmitError('');
+
+ try {
+ const response = await fetch(`${COMMENTS_API_URL}?query=new-comment`, {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ ...newComment,
+ topicId: props.topicId
+ }),
+ });
+
+ if (response.ok) {
+ setNewComment({ comment: '' });
+ setSubmitSuccess(true);
+ setTimeout(() => setSubmitSuccess(false), 3000);
+
+ // Refresh comments after successful submission
+ await fetchComments(props.topicId);
+ } else {
+ const errorData = await response.json();
+ setSubmitError(errorData.message || 'Failed to submit comment');
+ }
+ } catch (error) {
+ setSubmitError('Network error. Please try again.');
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ const getUserInitials = (name) => {
+ if (!name) return 'U';
+ const words = name.trim().split(' ');
+ return words
+ .slice(0, 2)
+ .map(word => word[0].toUpperCase())
+ .join('');
+ };
+
+ return (
+ <>
+ {/* Comments List */}
+
+
Comments ({comments.length})
+
+ {isLoadingComments ? (
+
+ ) : comments.length === 0 ? (
+
No comments yet. Be the first to comment!
+ ) : (
+ comments.map(comment => (
+
+
+
+
+ {getUserInitials(comment.userName)}
+
+
+
+
+
+ {comment.userName || 'User'}
+
+
+ {new Date(comment.created_at).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric'
+ })}
+
+
+
+
+
+
+
+
+ ))
+ )}
+
+
+ {/* Comments Section with MDEditor */}
+
+
+
+
Leave a Comment
+ {submitSuccess && (
+
+ Thank you for your comment!
+
+ )}
+ {submitError && (
+
+ {submitError}
+
+ )}
+
+
+
+ {/* Image Upload Dialog */}
+
+
+ {loading ? (
+ <>
+
+
+ Loading...
+
+ >
+ ) : !isLoggedIn ? (
+ <>
+
+
+ Join the conversation! Log in or sign up to post a comment
+
+ >
+ ) : null}
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/components/Comment.jsx b/src/components/Comment.jsx
new file mode 100644
index 0000000..e6b0512
--- /dev/null
+++ b/src/components/Comment.jsx
@@ -0,0 +1,200 @@
+import React, { useEffect, useState } from 'react';
+import { Card } from "./ui/card";
+import { Label } from "./ui/label";
+import { Textarea } from "./ui/textarea";
+import { Button } from "./ui/button";
+import { useIsLoggedIn } from '../lib/isLoggedIn';
+
+const COMMENTS_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/comments/';
+
+export default function Comment(props) {
+ const [comments, setComments] = useState([]);
+ const [newComment, setNewComment] = useState({ comment: '' });
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [submitSuccess, setSubmitSuccess] = useState(false);
+ const [submitError, setSubmitError] = useState('');
+ const [isLoadingComments, setIsLoadingComments] = useState(true);
+ const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn();
+
+ // Load comments when component mounts or when topicId changes
+ useEffect(() => {
+ if (props.topicId) {
+ fetchComments(props.topicId);
+ }
+ }, [props.topicId]);
+
+ const fetchComments = async (topicId) => {
+ setIsLoadingComments(true);
+ try {
+ const response = await fetch(`${COMMENTS_API_URL}?topicId=${topicId}`, {
+ method: 'GET',
+ credentials: 'include',
+ });
+
+ const data = await response.json();
+ if (!response.ok) {
+ throw new Error(data.message || 'Failed to fetch comments');
+ }
+
+ if (data.success && data.comments) {
+ setComments(data.comments);
+ } else {
+ throw new Error('Invalid response format');
+ }
+ } catch (error) {
+ console.error('Error fetching comments:', error);
+ setSubmitError('Failed to load comments');
+ } finally {
+ setIsLoadingComments(false);
+ }
+ };
+
+ const handleInputChange = (e) => {
+ const { name, value } = e.target;
+ setNewComment(prev => ({
+ ...prev,
+ [name]: value
+ }));
+ };
+
+ const handleSubmitComment = async (e) => {
+ e.preventDefault();
+ setIsSubmitting(true);
+ setSubmitError('');
+
+ try {
+ const response = await fetch(`${COMMENTS_API_URL}?query=new-comment`, {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ ...newComment,
+ topicId: props.topicId
+ }),
+ });
+
+ if (response.ok) {
+ setNewComment({ comment: '' });
+ setSubmitSuccess(true);
+ setTimeout(() => setSubmitSuccess(false), 3000);
+
+ // Refresh comments after successful submission
+ await fetchComments(props.topicId);
+ } else {
+ const errorData = await response.json();
+ setSubmitError(errorData.message || 'Failed to submit comment');
+ }
+ } catch (error) {
+ setSubmitError('Network error. Please try again.');
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ const getUserInitials = (name) => {
+ if (!name) return 'U';
+ const words = name.trim().split(' ');
+ return words
+ .slice(0, 2)
+ .map(word => word[0].toUpperCase())
+ .join('');
+ };
+
+ return (
+ <>
+ {/* Comments List */}
+
+
Comments ({comments.length})
+
+ {isLoadingComments ? (
+
+ ) : comments.length === 0 ? (
+
No comments yet. Be the first to comment!
+ ) : (
+ comments.map(comment => (
+
+
+
+
+ {getUserInitials(comment.userName)}
+
+
+
+
+
+ {comment.userName || 'User'}
+
+
+ {new Date(comment.created_at).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric'
+ })}
+
+
+
{comment.comment}
+
+
+
+ ))
+ )}
+
+
+ {/* Comments Section */}
+
+
+
+
Leave a Comment
+ {submitSuccess && (
+
+ Thank you for your comment!
+
+ )}
+ {submitError && (
+
+ {submitError}
+
+ )}
+
+
+ {loading ? (
+ <>
+
+
+ Loading...
+
+ >
+ ) : !isLoggedIn ? (
+ <>
+
+
+ Join the conversation! Log in or sign up to post a comment
+
+ >
+ ) : null}
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/components/TopicDetail.jsx b/src/components/TopicDetail.jsx
index 4bd1a81..2f2472b 100644
--- a/src/components/TopicDetail.jsx
+++ b/src/components/TopicDetail.jsx
@@ -1,9 +1,15 @@
import React, { useState, useEffect } from "react";
import { marked } from 'marked';
-
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./ui/card";
+import { Label } from "./ui/label";
+import { Textarea } from "./ui/textarea";
+import { Button } from "./ui/button";
+import { useIsLoggedIn } from '../lib/isLoggedIn';
+import Comment from './Comment';
+const COMMENTS_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/comments/';
export default function TopicDetail(props) {
const [showCopied, setShowCopied] = useState(false);
-
+
if (!props.topic) {
return Topic not found
;
}
@@ -12,31 +18,6 @@ export default function TopicDetail(props) {
const title = props.topic.title;
const text = `Check out this article: ${title}`;
- // const shareOnFacebook = () => {
- // window.open(`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`, '_blank');
- // };
-
- // const shareOnTwitter = () => {
- // window.open(`https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(text)}`, '_blank');
- // };
-
- // const shareOnLinkedIn = () => {
- // window.open(`https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}`, '_blank');
- // };
-
- // const shareOnReddit = () => {
- // window.open(`https://www.reddit.com/submit?url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}`, '_blank');
- // };
-
- // const shareOnWhatsApp = () => {
- // window.open(`https://wa.me/?text=${encodeURIComponent(`${text} ${shareUrl}`)}`, '_blank');
- // };
-
- // const shareViaEmail = () => {
- // window.open(`mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(`${text}\n\n${shareUrl}`)}`);
- // };
-
-
const shareOnSocialMedia = (platform) => {
switch (platform){
case 'facebook':
@@ -125,7 +106,7 @@ export default function TopicDetail(props) {
return (
-
+
{props.topic.title}
{/* Enhanced Social Share Buttons */}
@@ -211,11 +192,11 @@ export default function TopicDetail(props) {
-
+
+
);
-}
\ No newline at end of file
+}
+
+// bg-[#6d9e37]
\ No newline at end of file