diff --git a/website/README.md b/website/README.md index 7d57ceaa..23570947 100644 --- a/website/README.md +++ b/website/README.md @@ -105,6 +105,20 @@ When writing code for the website, we have a few best practices: 1. Define functional React components (with types for all properties when feasible). +### URL Paths + +To use stable and consistent URL paths, we recommend the following strategy for new tasks: + +1. For any task that involves writing a free-form response, put the page under + `website/src/pages/create` with a page name matching the task type, such as + `summarize_story.tsx`. +1. For any task that evaluates, rates, or ranks content, put the page under + `website/src/pages/evaluate` with a page name matching the task type such + as `rate_summary.tsx`. + +With this we'll be able to ensure these contribution pages are hidden from +logged out users but accessible to logged in users. + ## Learn More To learn more about Next.js, take a look at the following resources: diff --git a/website/src/components/RatingRadioGroup.tsx b/website/src/components/RatingRadioGroup.tsx index 33043883..7fbcc3ac 100644 --- a/website/src/components/RatingRadioGroup.tsx +++ b/website/src/components/RatingRadioGroup.tsx @@ -1,8 +1,7 @@ -import { chakra, Box, HStack, useRadio, useRadioGroup } from "@chakra-ui/react"; +import { Box, HStack, useRadio, useRadioGroup } from "@chakra-ui/react"; const RatingRadioButton = (props) => { - const { option, ...radioProps } = props; - const { getInputProps, getCheckboxProps } = useRadio(radioProps); + const { state, getInputProps, getCheckboxProps } = useRadio(props); const input = getInputProps(); const checkbox = getCheckboxProps(); @@ -27,25 +26,33 @@ const RatingRadioButton = (props) => { px={5} py={3} > - {option} + {props.children} ); }; const RatingRadioGroup = (props) => { - const { min, max, onChange, ...rest } = props; - const { value, getRadioProps, getRootProps } = useRadioGroup({ - defaultValue: min, + const { min, max, onChange } = props; + const { getRadioProps, getRootProps } = useRadioGroup({ + name: "rating", + defaultValue: `${min}`, onChange: onChange, }); - const options = Array.from(new Array(1 + max - min), (x, i) => i + min); + const group = getRootProps(); + + const options = Array.from(new Array(1 + max - min), (x, i) => `${i + min}`); return ( - - {options.map((option) => ( - - ))} + + {options.map((option) => { + const radio = getRadioProps({ value: option }); + return ( + + {option} + + ); + })} ); }; diff --git a/website/src/middleware.ts b/website/src/middleware.ts index b383586b..dc13bf91 100644 --- a/website/src/middleware.ts +++ b/website/src/middleware.ts @@ -4,5 +4,5 @@ export { default } from "next-auth/middleware"; * Guards all pages under `/grading` and redirects them to the sign in page. */ export const config = { - matcher: ["/grading/:path*"], + matcher: ["/create/:path*", "/evaluate/:path*"], }; diff --git a/website/src/pages/create/summarize_story.tsx b/website/src/pages/create/summarize_story.tsx new file mode 100644 index 00000000..37910c55 --- /dev/null +++ b/website/src/pages/create/summarize_story.tsx @@ -0,0 +1,131 @@ +import { Textarea } from "@chakra-ui/react"; +import Head from "next/head"; +import { useRef, useState } from "react"; +import useSWRImmutable from "swr/immutable"; +import useSWRMutation from "swr/mutation"; + +import { Footer } from "src/components/Footer"; +import { Header } from "src/components/Header"; +import fetcher from "src/lib/fetcher"; +import poster from "src/lib/poster"; + +const SummarizeStory = () => { + // Use an array of tasks that record the sequence of steps until a task is + // deemed complete. + const [tasks, setTasks] = useState([]); + + const inputRef = useRef(null); + + // Fetch the very fist task. We can ignore everything except isLoading + // because the onSuccess handler will update `tasks` when ready. + const { isLoading } = useSWRImmutable("/api/new_task/summarize_story", fetcher, { + onSuccess: (data) => { + setTasks([data]); + }, + }); + + // Every time we submit an answer to the latest task, let the backend handle + // all the interactions then add the resulting task to the queue. This ends + // when we hit the done task. + const { trigger, isMutating } = useSWRMutation("/api/update_task", poster, { + onSuccess: async (data) => { + const newTask = await data.json(); + // This is the more efficient way to update a react state array. + setTasks((oldTasks) => [...oldTasks, newTask]); + }, + }); + + // Trigger a mutation that updates the current task. We should probably + // signal somewhere that this interaction is being processed. + const submitResponse = (task: { id: string }) => { + const text = inputRef.current.value.trim(); + trigger({ + id: task.id, + update_type: "text_reply_to_post", + content: { + text, + }, + }); + }; + + /** + * TODO: Make this a nicer loading screen. + */ + if (tasks.length == 0) { + return
Loading...
; + } + + return ( + <> + + Summarize A Story + + +
+
+
+ {/* Instrunction and Output panels */} +
+
+ {/* Instruction panel */} +
+
+
Instruction
+

Summarize the following story

+
+ {tasks[0].task.story} +
+
+
+ + {/* Output panel */} +
+
+