Skip to content

Commit

Permalink
Merge pull request #104 from eye-on-surveillance/AI/public-comments
Browse files Browse the repository at this point in the history
AI/public-comments
  • Loading branch information
ayyubibrahimi authored Oct 2, 2023
2 parents 437dd2c + 00c376b commit 8a7aabe
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/web/app/api/v1/cards/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const dynamic = "force-dynamic";

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || "PLACEHOLDER";
const supabaseSecretServiceKey =
process.env.SUPABASE_SERVICE_ROLE_SECRET || "PLACEHOLDER";
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || "PLACEHOLDER";

/* Create card
* Not creating directly from client because:
Expand Down
168 changes: 165 additions & 3 deletions packages/web/components/BetaCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,113 @@

import { ICard, ICitation, IResponse } from "@/lib/api";
import { CARD_SHOW_PATH, getPageURL } from "@/lib/paths";
import { supabase } from "@/lib/supabase/supabaseClient";
import { faCheck, faShare } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import moment from "moment";
import { useState } from "react";
import { useEffect, useState } from "react";
import useClipboardApi from "use-clipboard-api";
import CardResponse from "./CardResponse";
import Citation from "./Citation";

type SupabaseRealtimePayload<T = any> = {
old: T;
new: T;
};

type Comment = {
display_name: string;
content: string;
created_at: Date;
card_id: string;
};

const BetaCard = ({ card }: { card: ICard }) => {
const responses: IResponse[] = card.responses ?? [];
const citations: ICitation[] = card.citations ?? [];
const [value, copy] = useClipboardApi();
const currentUrl = getPageURL(`${CARD_SHOW_PATH}/${card.id}`);
const [recentlyCopied, setRecentlyCopied] = useState(false);
const [comments, setComments] = useState<Comment[] | null>(null);
const [commentContent, setCommentContent] = useState("");
const [displayName, setDisplayName] = useState("");
const [showCitations, setShowCitations] = useState(false);
const [showComments, setShowComments] = useState(false);

useEffect(() => {
const fetchComments = async () => {
try {
const { data, error } = await supabase
.from("comments")
.select("*")
.eq("card_id", card.id)
.order("created_at", { ascending: false });
if (error) throw error;
setComments(data);
} catch (error) {}
};
fetchComments();
}, [card.id]);

useEffect(() => {
const channel = (supabase.channel(`cards:id=eq.${card.id}`) as any)
.on(
"postgres_changes",
{
event: "INSERT",
schema: "public",
},
(payload: SupabaseRealtimePayload<Comment>) => {
if (payload.new.card_id === card.id) {
setComments((prevComments) => [
payload.new,
...(prevComments || []),
]);
}
}
)
.subscribe();

// Cleanup subscription on component unmount
return () => {
channel.unsubscribe();
};
}, [card.id]);

const handleCommentSubmit = async () => {
const newComment = {
card_id: card.id,
content: commentContent,
display_name: displayName,
created_at: new Date(),
};


setComments((prevComments) =>
prevComments
? prevComments.filter((comment) => comment !== newComment)
: null
);

setDisplayName(""); // Resetting display name
setCommentContent(""); // Resetting comment content

try {
const { data, error } = await supabase
.from("comments")
.insert([newComment]);
if (error) throw error;
setDisplayName(""); // Resetting display name after successful post
setCommentContent(""); // Resetting comment content after successful post
} catch (error) {
// If there's an error, revert the change to the comments
setComments((prevComments) =>
prevComments
? prevComments.filter((comment) => comment !== newComment)
: null
);
}
};

return (
<div className="w-full">
Expand Down Expand Up @@ -57,7 +149,7 @@ const BetaCard = ({ card }: { card: ICard }) => {
{/* Citations Section */}
<div className="mb-6 mt-4">
<button
className="mb-2 rounded px-4 py-2 text-black"
className="text-black mb-2 rounded px-4 py-2"
onClick={() => setShowCitations((prev) => !prev)}
>
{showCitations ? "Hide Citations" : "Show Citations"}
Expand All @@ -71,8 +163,78 @@ const BetaCard = ({ card }: { card: ICard }) => {
</div>
)}
</div>

{/* Comments Section */}
<div className="mt-6">
<button
className="text-black mb-2 rounded px-4 py-2"
onClick={() => setShowComments((prev) => !prev)}
>
{showComments ? "Hide Comments" : "Show Comments"}
</button>

{showComments && (
<>
<h2 className="mb-4 text-xl font-bold">Comments</h2>

<div className="mb-2">
<input
className="w-full rounded border p-2"
placeholder="Your Display Name..."
value={displayName}
onChange={(e) => setDisplayName(e.target.value)}
/>
</div>

<div className="mb-4">
<textarea
className="w-full rounded border p-2"
placeholder="Write a comment..."
value={commentContent}
onChange={(e) => setCommentContent(e.target.value)}
/>
</div>

<button
className="text-black mb-2 rounded px-4 py-2"
onClick={handleCommentSubmit}
>
Post Comment
</button>

{comments &&
comments.map((comment, index) => (
<div
key={index}
className={`mb-2 mt-4 p-2 ${
index < comments.length - 1 ? "border-b-2" : ""
} border-black`}
>
<div className="flex justify-between">
<p className="font-bold">{comment.display_name}</p>
<span className="text-sm text-gray-500">
{moment(comment.created_at).fromNow()}
</span>
</div>
<div>
{comment.content.split("\n").map((str, idx) =>
idx === comment.content.split("\n").length - 1 ? (
str
) : (
<>
{str}
<br />
</>
)
)}
</div>
</div>
))}
</>
)}
</div>
</div>
);
);
};

export default BetaCard;

0 comments on commit 8a7aabe

Please sign in to comment.