diff --git a/website/src/components/Dashboard/TaskOption.tsx b/website/src/components/Dashboard/TaskOption.tsx index 3497d14c..0401fd97 100644 --- a/website/src/components/Dashboard/TaskOption.tsx +++ b/website/src/components/Dashboard/TaskOption.tsx @@ -15,9 +15,9 @@ import Link from "next/link"; import { useTranslation } from "next-i18next"; import { useMemo } from "react"; import { getTypeSafei18nKey } from "src/lib/i18n"; -import { TaskType } from "src/types/Task"; +import { TaskCategory, TaskInfo, TaskType } from "src/types/Task"; -import { TaskCategory, TaskCategoryLabels, TaskInfo, TaskInfos } from "../Tasks/TaskTypes"; +import { TaskCategoryLabels, TaskInfos } from "../Tasks/TaskTypes"; export interface TasksOptionProps { content: Partial>; diff --git a/website/src/components/TaskPage/TaskPage.tsx b/website/src/components/TaskPage/TaskPage.tsx index c76ec3d1..b6242702 100644 --- a/website/src/components/TaskPage/TaskPage.tsx +++ b/website/src/components/TaskPage/TaskPage.tsx @@ -19,9 +19,8 @@ export const TaskPage = ({ type }: TaskPageProps) => { const taskApiHook = useMemo(() => taskApiHooks[type], [type]); const hookState = taskApiHook(type); - const { response } = hookState; - const body = useMemo(() => { + const { response } = hookState; switch (response.taskAvailability) { case "AWAITING_INITIAL": return ; @@ -29,10 +28,17 @@ export const TaskPage = ({ type }: TaskPageProps) => { case "NONE_AVAILABLE": return ; - case "AVAILABLE": - return ; + case "AVAILABLE": { + const { task, taskInfo } = response; + const context = { ...hookState, task, taskInfo }; + return ( + + + + ); + } } - }, [response, t]); + }, [hookState, t]); // NOTE: this is independent of the fetched task type, it is usually identical, but not for the random task. const taskInfo = TaskInfos.find((taskType) => taskType.type === type); @@ -42,7 +48,7 @@ export const TaskPage = ({ type }: TaskPageProps) => { {t(getTypeSafei18nKey(`${taskInfo.id}.label`))} - {body} + {body} ); }; diff --git a/website/src/components/Tasks/Task/Task.stories.tsx b/website/src/components/Tasks/Task/Task.stories.tsx index fe7122b9..cb0cd5c3 100644 --- a/website/src/components/Tasks/Task/Task.stories.tsx +++ b/website/src/components/Tasks/Task/Task.stories.tsx @@ -1,20 +1,22 @@ import React from "react"; - -import { Task } from "./Task"; +import { Task } from "src/components/Tasks/Task"; +import { TaskInfos } from "src/components/Tasks/TaskTypes"; +import { TaskContext } from "src/context/TaskContext"; export default { title: "tasks/Task", component: Task, }; -const Template = ({ frontendId, task, isLoading, completeTask, skipTask }) => { +const Template = ({ providerValue }) => { return ( - + + + ); }; -export const Default = Template.bind({}); -Default.args = { +const exampleProviderValue = { frontendId: "1234", task: { conversation: [], @@ -25,11 +27,18 @@ Default.args = { type: "label_prompter_reply", valid_labels: ["spam", "fails_task"], }, + taskInfo: TaskInfos.find((t) => t.type === "label_prompter_reply"), isLoading: false, - completeTask: (id, update_type, content) => { + completeTask: (content) => { console.log(content); }, skipTask: () => { console.log("skip"); }, + rejectTask: () => { + console.log("reject"); + }, }; + +export const Default = Template.bind({}); +Default.args = { providerValue: exampleProviderValue }; diff --git a/website/src/components/Tasks/Task/Task.tsx b/website/src/components/Tasks/Task/Task.tsx index 2ddb863d..f251cdd0 100644 --- a/website/src/components/Tasks/Task/Task.tsx +++ b/website/src/components/Tasks/Task/Task.tsx @@ -66,7 +66,7 @@ export const Task = () => { const { t } = useTranslation("tasks"); const rootEl = useRef(null); const replyContent = useRef(null); - const { rejectTask, completeTask, response, isLoading } = useTaskContext(); + const { rejectTask, completeTask, isLoading, task, taskInfo } = useTaskContext(); const [taskStatus, taskEvent] = useReducer( ( status: TaskStatus, @@ -108,11 +108,6 @@ export const Task = () => { { mode: "EDIT", replyValidity: "INVALID" } ); - if (response.taskAvailability !== "AVAILABLE") { - throw new Error("Cannot render task when it is unavailable yet"); - } - const { task, taskInfo } = response; - const updateValidity = useCallback( (replyValidity: TaskReplyValidity) => taskEvent({ action: "UPDATE_VALIDITY", replyValidity }), [taskEvent] @@ -129,10 +124,10 @@ export const Task = () => { [replyContent] ); - const submitResponse = useCallback(() => { + const submitResponse = useCallback(async () => { if (taskStatus.mode === "REVIEW") { - completeTask(replyContent.current); taskEvent({ action: "SET_SUBMITTED" }); + await completeTask(replyContent.current); scrollToTop(rootEl.current); } }, [taskStatus.mode, completeTask]); diff --git a/website/src/components/Tasks/TaskHeader/TaskHeader.tsx b/website/src/components/Tasks/TaskHeader/TaskHeader.tsx index c4095eb8..65284898 100644 --- a/website/src/components/Tasks/TaskHeader/TaskHeader.tsx +++ b/website/src/components/Tasks/TaskHeader/TaskHeader.tsx @@ -1,8 +1,8 @@ import { HStack, IconButton, Link, Stack, Text, useColorModeValue } from "@chakra-ui/react"; import { HelpCircle } from "lucide-react"; import { useTranslation } from "next-i18next"; -import type { TaskInfo } from "src/components/Tasks/TaskTypes"; import { getTypeSafei18nKey } from "src/lib/i18n"; +import { TaskInfo } from "src/types/Task"; interface TaskHeaderProps { /** diff --git a/website/src/context/TaskContext.ts b/website/src/context/TaskContext.ts index 8950ddfd..dfbf145d 100644 --- a/website/src/context/TaskContext.ts +++ b/website/src/context/TaskContext.ts @@ -1,7 +1,13 @@ import { createContext, useContext } from "react"; import { TaskApiHook } from "src/types/Hooks"; -import { BaseTask } from "src/types/Task"; +import { BaseTask, TaskInfo } from "src/types/Task"; -export const TaskContext = createContext>(null); +export interface TaskContextType + extends Omit, "response"> { + task: Task; + taskInfo: TaskInfo; +} + +export const TaskContext = createContext>(null); export const useTaskContext = () => useContext(TaskContext); diff --git a/website/src/hooks/tasks/useGenericTaskAPI.tsx b/website/src/hooks/tasks/useGenericTaskAPI.tsx index f6fd2e40..7a7d651b 100644 --- a/website/src/hooks/tasks/useGenericTaskAPI.tsx +++ b/website/src/hooks/tasks/useGenericTaskAPI.tsx @@ -6,7 +6,8 @@ import { BaseTask, ServerTaskResponse, TaskResponse, TaskType as TaskTypeEnum } import useSWRImmutable from "swr/immutable"; import useSWRMutation from "swr/mutation"; -export const useGenericTaskAPI = ( +// TODO: provide type for the content reply, this will be much harder since the replies vary vastly +export const useGenericTaskAPI = ( taskType: TaskTypeEnum ): TaskApiHook => { const [response, setResponse] = useState>({ taskAvailability: "AWAITING_INITIAL" }); diff --git a/website/src/pages/dashboard.tsx b/website/src/pages/dashboard.tsx index 35c254a4..bd857fc7 100644 --- a/website/src/pages/dashboard.tsx +++ b/website/src/pages/dashboard.tsx @@ -4,9 +4,8 @@ import { useTranslation } from "next-i18next"; import { useEffect, useMemo, useState } from "react"; import { LeaderboardWidget, TaskOption, WelcomeCard } from "src/components/Dashboard"; import { getDashboardLayout } from "src/components/Layout"; -import { TaskCategory } from "src/components/Tasks/TaskTypes"; import { get } from "src/lib/api"; -import { AvailableTasks, TaskType } from "src/types/Task"; +import { AvailableTasks, TaskCategory, TaskType } from "src/types/Task"; export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; import useSWR from "swr";