diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..6313b56c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx
index 6090468c..4aa93585 100644
--- a/website/src/pages/index.tsx
+++ b/website/src/pages/index.tsx
@@ -46,10 +46,13 @@ export default function Home() {
/>
-
+
+
>
diff --git a/website/src/pages/summarize/story.tsx b/website/src/pages/summarize/story.tsx
new file mode 100644
index 00000000..22ea8f5c
--- /dev/null
+++ b/website/src/pages/summarize/story.tsx
@@ -0,0 +1,118 @@
+// TODO(#65): Unify and simplify the task paths
+import { Textarea } from "@chakra-ui/react";
+import { useRef, useState } from "react";
+import useSWRMutation from "swr/mutation";
+import useSWRImmutable from "swr/immutable";
+
+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) => {
+ console.log(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,
+ content: {
+ update_type: "text_reply_to_post",
+ text,
+ },
+ });
+ };
+
+ /**
+ * TODO: Make this a nicer loading screen.
+ */
+ if (tasks.length == 0) {
+ return