Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#514 Implement voting on Community note #516

Merged
merged 13 commits into from
Dec 14, 2024
113 changes: 113 additions & 0 deletions checkers-app/src/components/myvotes/CommunityCard.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a section to show the links too? These will be the links identified by the GenAI system. Will help the checkers review the links to make sure the note is congruent with the link

Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React, {useState} from "react";
import {Card, CardBody, Typography, Button} from "@material-tailwind/react";
import { UserIcon } from "@heroicons/react/24/solid";

interface PropType {
en: string;
cn: string;
links: string[];
downvoted: boolean;
}

// Helper function to detect URLs and split the text
const splitTextByUrls = (text: string) => {
// This regex will match URLs
const urlRegex = /(https?:\/\/[^\s]+)/g;
let match;
let lastIndex = 0;
const parts = [];

// Find al matches and their indices
while ((match = urlRegex.exec(text)) !== null) {
const url = match[0];
const index = match.index;

// Push text before URL
if (index > lastIndex) {
parts.push({ text: text.substring(lastIndex, index), isUrl: false});
}

// Push URL
parts.push({ text: url, isUrl: true});

// Update lastIndex to end of current URL
lastIndex = index + url.length;
}

// Push remaining text after last URL
if (lastIndex < text.length) {
parts.push({ text: text.substring(lastIndex), isUrl: false});
}

return parts;
}

export default function CommunityCard(prop: PropType){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can change the "CommunityCard" name to "CommunityNoteCard"? Same for categories etc. I'm always very concerned about getting the nomenclature meaningful so ppl can easily understand the code

const [isExpanded, setIsExpanded] = useState(false);
const lengthBeforeTruncation = 300;
const { en, cn, links, downvoted } = prop;

const toggleExpansion = () => {
setIsExpanded(!isExpanded);
};

let displayText = en ?? "";

const shouldTruncate = displayText.length > lengthBeforeTruncation;
const textToShow =
isExpanded || !shouldTruncate
? displayText
: displayText.slice(0, lengthBeforeTruncation) + "...";

// Split text by URLs
const textParts = splitTextByUrls(textToShow)

return (
<Card className="bg-blue-100 overflow-y-auto overflow-x-hidden max-w-md w-full h-full max-h-full p-3 mb-2">
<CardBody className="-m-3">
<Typography className="flex items-center mb-2">
<UserIcon className="h-6 w-6 text-[#ff8932] mr-2 flex-shrink-0"/>
<p className="font-semibold leading-none">Community Note:</p>
</Typography>

<Typography className="w-full">
{textParts.map((part, index) => {
// Split the text part by new lines
const lines = part.text.split("\n");
return (
<React.Fragment key={index}>
{lines.map((line, lineIndex) => (
<React.Fragment key={lineIndex}>
{part.isUrl ? (
<a
href={line}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:underline"
>
{line}
</a>
) : (
<span>{line}</span>
)}
{lineIndex < lines.length - 1 && <br />}
</React.Fragment>
))}
</React.Fragment>
);
})}
</Typography>
{shouldTruncate && (
<Button
onClick={toggleExpansion}
variant="text"
className="p-0 text-primary-color3"
size="sm"
>
{isExpanded ? "Show Less" : "Read More"}
</Button>
)}
</CardBody>
</Card>
)
}
92 changes: 92 additions & 0 deletions checkers-app/src/components/vote/CommunityCategories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { useState } from "react";
import { TrophyIcon } from "@heroicons/react/20/solid";
import { CheckBadgeIcon } from "@heroicons/react/24/solid";
import { XCircleIcon } from "@heroicons/react/24/outline";
import { Button } from "@material-tailwind/react"
import { ForwardIcon } from "@heroicons/react/24/solid";

interface PropType {
messageId: string | null;
voteRequestId: string | null;
currentCommunityCategory: string | null;
onNextStep: (value: number) => void;
onSelectCommunityCategory: (communityCategory: string | null) => void;
}

const CATEGORIES = [
{
name: "great",
icon: <TrophyIcon className = "h-7 w-7" />,
display: "Great",
description: "Good response, can't do any better",
},
{
name: "acceptable",
icon: <CheckBadgeIcon className = "h-7 w-7" />,
display: "Acceptable",
description: "Acceptable response, but can be improved"
},
{
name: "unacceptable",
icon: <XCircleIcon className="h-7 w-7" />,
display: "Unacceptable",
description: "Unacceptable response"
}
]


export default function CommunityCategories(Prop: PropType) {
const currentCategory = Prop.currentCommunityCategory
const messageId = Prop.messageId;
const voteRequestId = Prop.voteRequestId;
const [selectedCategory, setSelectedCategory] = useState<string | null>(currentCategory);
const [communityCategory, setCommunityCategory] = useState<string | null>(currentCategory);

const handleCommunityCategoryChange = (category: string) => {
switch(category) {
default:
setCommunityCategory(category);
Prop.onSelectCommunityCategory(category);
break;
}
}

const handleSelection = (categoryName: string) => {
setSelectedCategory(categoryName);
handleCommunityCategoryChange(categoryName);
}

const handleNextStep = (value: number) => {
Prop.onNextStep(value)
}

return (
<div className="grid grid-flow-row gap-y-4 items-center">
{CATEGORIES.map((cat, index) => (
<>
<Button
className={`flex flex-row items-center justify-start gap-2 max-w-md space-x-3 text-sm
${
selectedCategory === cat.name
? "bg-primary-color3"
: "bg-primary-color"}`}
key={index}
onClick={() => handleSelection(cat.name)}
>
{cat.icon}
{cat.display}
</Button>
</>
))}

{communityCategory ? (
<Button fullWidth className="flex items-center justify-center gap-3 bg-green-400" size="sm"
onClick = {() => handleNextStep(2)}
>
Move to next step
<ForwardIcon className="h-5 w-5"/>
</Button>
) : null}
</div>
)
}
Loading
Loading