diff --git a/packages/web/app/feedback/page.tsx b/packages/web/app/feedback/page.tsx index 65c58cd5..141c08df 100644 --- a/packages/web/app/feedback/page.tsx +++ b/packages/web/app/feedback/page.tsx @@ -2,10 +2,10 @@ // Import necessary modules and components import ThreeCardLayout from "../../components/ThreeCardLayout"; -import { supabase } from "../../lib/supabase/supabaseClient"; // import NextButton from '@/components/NextButton'; import { ICard } from "@/lib/api"; import { TABLES } from "@/lib/supabase/db"; +import { supabase } from "@/lib/supabase/supabaseClient"; import { useEffect, useState } from "react"; export const dynamic = "force-dynamic"; @@ -13,15 +13,15 @@ export const dynamic = "force-dynamic"; export default function UserFeedback() { // const [currentIndex, setCurrentIndex] = useState(randint(0,177)); const [userName, setUserName] = useState(""); - const [currentIndex, setCurrentIndex] = useState(0); const [answered, setAnswered] = useState>(new Set()); const [fullData, setFullData] = useState> | null>(null); + const [cards, setCards] = useState([]); const [cardArray, setCardArray] = useState> | null>(null); // Not the best way to do it-- we really should make each of these a new page and the next/prev buttons // should be linked to the next/prev page. But this is a quick fix for now. - const question_idArray = Array.from({ length: 98 }, (_, index) => index); + // const question_idArray = Array.from({ length: 291 }, (_, index) => index); // const handlePrevClick = () => { // if (fullData) { @@ -35,15 +35,30 @@ export default function UserFeedback() { // } // }; - const handleNextClick = () => { - if (fullData) { - setCardArray(fullData); - //wraps around - setCurrentIndex((currentIndex + 1) % question_idArray.length); - setAnswered(new Set()); - } else { - alert("Please wait for the rest of the cards to finish loading..."); + const randQuestionId = () => { + return Math.floor(Math.random() * 291); + }; + + const shuffleArray = (array: Number[]) => { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; } + return array; + }; + + // const shuffledQuestionIds = shuffleArray(question_idArray); + const [currentIndex, setCurrentIndex] = useState(0); + // console.log(`index ${currentIndex}, val ${shuffledQuestionIds[0]}`); + const handleNextClick = () => { + // if (fullData) { + setCardArray(fullData); + //wraps around + setCurrentIndex(currentIndex + 1); + setAnswered(new Set()); + // } else { + // alert("Please wait for the rest of the cards to finish loading..."); + // } }; //const handleNameChange = (e) => { @@ -53,14 +68,16 @@ export default function UserFeedback() { useEffect(() => { const getCard = async () => { + const randId = randQuestionId(); + console.log("Fetching cards " + randId); try { const cardsArray: Array> = []; - const { data: cards, error } = await supabase + const { data: newCards, error } = await supabase .from(TABLES.FEEDBACK_CARDS) .select("*") - .eq("question_id", 0); - if (cards) { - cardsArray.push(cards); + .eq("question_id", randId); + if (newCards) { + setCards(newCards); } setCardArray(cardsArray); console.log(cards); @@ -68,38 +85,38 @@ export default function UserFeedback() { console.error("Error fetching cards: ", error); // Handle the error appropriately in your UI } - getCards(); + // getCards(); }; getCard(); - }, []); // Run this effect only once when the component mounts + }, [currentIndex]); // Run this effect only once when the component mounts - const getCards = async () => { - const cardsArray: Array> = []; - try { - for (let i = 1; i <= question_idArray.length; i++) { - const { data: cards, error } = await supabase - .from(TABLES.FEEDBACK_CARDS) - .select("*") - .eq("question_id", i); + // const getCards = async () => { + // const cardsArray: Array> = []; + // try { + // for (let i = 1; i < question_idArray.length; i++) { + // const { data: cards, error } = await supabase + // .from(TABLES.FEEDBACK_CARDS) + // .select("*") + // .eq("question_id", shuffledQuestionIds[i]); - if (error) { - console.error("Error fetching cards: ", error); - // Handle the error appropriately in your UI - } - console.log(cards); + // if (error) { + // console.error("Error fetching cards: ", error); + // // Handle the error appropriately in your UI + // } + // // console.log(cards); - if (cards) { - cardsArray.push(cards); - } - } - setFullData(cardsArray); - // console.log(fullData); - //setCurrentIndex(Math.floor(Math.random() * cardsArray.length)); - } catch (error) { - console.error("Error fetching cards: ", error); - // Handle the error appropriately in your UI - } - }; + // if (cards) { + // cardsArray.push(cards); + // } + // } + // setFullData(cardsArray); + // // console.log(fullData); + // //setCurrentIndex(Math.floor(Math.random() * cardsArray.length)); + // } catch (error) { + // console.error("Error fetching cards: ", error); + // // Handle the error appropriately in your UI + // } + // }; if (!cardArray) { return
Loading...
; @@ -124,7 +141,7 @@ export default function UserFeedback() { { +const Citation = ({ + citation: originalCitation, + index, + fullscreen = false, +}: CitationProps) => { const hasMetadata = Object.values(originalCitation).some( (value) => value !== null && value !== "" ); @@ -35,7 +40,11 @@ const Citation = ({ citation: originalCitation, index }: CitationProps) => { const isYoutube = isYouTubeURL(source_url) && getYouTubeThumbnail(source_url); return ( -
+

#{index + 1}: {title} diff --git a/packages/web/components/CommentBoxes.tsx b/packages/web/components/CommentBoxes.tsx index f8602ef2..35d15d34 100644 --- a/packages/web/components/CommentBoxes.tsx +++ b/packages/web/components/CommentBoxes.tsx @@ -55,7 +55,7 @@ export default function CommentBox({ onClick={handleSubmit} className="bg-blue-500 w-full rounded bg-secondary px-4 py-2 text-lg text-white" > - Submit + Submit #{index + 1}

diff --git a/packages/web/components/ThreeCardLayout.css b/packages/web/components/ThreeCardLayout.css new file mode 100644 index 00000000..59ed0d0b --- /dev/null +++ b/packages/web/components/ThreeCardLayout.css @@ -0,0 +1,61 @@ +/* ThreeCardLayout.css */ +.dropdown-container { + position: relative; + } + + .dropdown-header { + cursor: pointer; + padding: 8px; + border: 1px solid #ccc; + border-radius: 4px; + display: flex; + justify-content: space-between; + align-items: center; + } + + .dropdown-content { + position: absolute; + top: 100%; + left: 0; + background-color: #fff; + border: 1px solid #ccc; + border-top: none; + border-radius: 0 0 4px 4px; + padding: 8px; + z-index: 1; + overflow: scroll; + } + + /* Rotate chevron down icon when dropdown is open */ + .rotate-180 { + transform: rotate(180deg); + } + + +.dropdown-content { + position: absolute; + top: 100%; + left: 0; + background-color: #fff; + border: 1px solid #ccc; + border-top: none; + border-radius: 0 0 4px 4px; + padding: 8px; + z-index: 1; + width: 100%; + } + + + +/* Adjust styles for screens smaller than 600px */ +@media (max-width: 600px) { + .dropdown-header { + font-size: 14px; + } + + .dropdown-content { + padding: 10px; + } + } + + \ No newline at end of file diff --git a/packages/web/components/ThreeCardLayout.tsx b/packages/web/components/ThreeCardLayout.tsx index 5e4318e0..5fd40aec 100644 --- a/packages/web/components/ThreeCardLayout.tsx +++ b/packages/web/components/ThreeCardLayout.tsx @@ -8,10 +8,12 @@ import Rubric from "@/components/Rubric"; import { TABLES } from "@/lib/supabase/db"; import { faCheckCircle, + faChevronDown, faCircleXmark, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useState } from "react"; +import Citation from "./Citation"; import CommentBox from "./CommentBoxes"; const criteria = [ @@ -22,6 +24,20 @@ const criteria = [ ]; const NUM_CARDS_PER_SET = 3; +const RESET_SCORE = 1; + +function getRandomExcluding(set: Set, n: number): number | null { + if (set.size >= n) { + return null; // No available number + } + + let randomNum; + do { + randomNum = Math.floor(Math.random() * n); + } while (set.has(randomNum)); + + return randomNum; +} export default function ThreeCardLayout({ cards, @@ -36,6 +52,7 @@ export default function ThreeCardLayout({ }) { const [scores, setScores] = useState>({}); const [activeTab, setActiveTab] = useState(0); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); // Function to update scores const handleScoreChange = (criterionId: string, score: number) => { @@ -51,9 +68,9 @@ export default function ThreeCardLayout({ // }, {}); const resetScores = { - Accuracy: 1, - Helpfulness: 1, - Balance: 1, + Accuracy: RESET_SCORE, + Helpfulness: RESET_SCORE, + Balance: RESET_SCORE, }; setScores(resetScores); @@ -111,32 +128,37 @@ export default function ThreeCardLayout({ const newAnswered = new Set(answered); newAnswered.add(index); setAnswered(newAnswered); + + console.log("Submit feedback " + newAnswered.size); + if (newAnswered.size < NUM_CARDS_PER_SET) { + const randUnscored = getRandomExcluding(newAnswered, NUM_CARDS_PER_SET); + console.log("Unscored " + randUnscored); + if (!!randUnscored) setActiveTab(randUnscored); + } } catch (error) {} }; const Tabs = () => { return Array.from({ length: NUM_CARDS_PER_SET }, (_, index) => { const isAnswered = answered.has(index); + const isSelected = activeTab === index; return (
{ setActiveTab(index); }} > - Option {index + 1}{" "} - {isAnswered ? ( - - ) : ( + + Option {index + 1}{" "} - )} +
); }); @@ -173,6 +195,48 @@ export default function ThreeCardLayout({ {element.response}

))} + {card.citations && card.citations.length > 0 && ( +
+
setIsDropdownOpen(!isDropdownOpen)} + > + Citations + +
+ {isDropdownOpen && ( +
+ {card.citations.map((citation, index) => { + const { + URL: source_url, + Name: source_name, + Title: source_title, + Published: source_publish_date, + } = citation as any; + const adaptedCitation = { + source_name, + source_publish_date, + source_title, + source_url, + }; + return ( + + ); + })} +
+ )} +
+ )}