website: Add a review step before submitting

to hint to the user that they should reread and check what they have written.

Also show numbers for ranked items rather than drag handles in the review step as the items can't be moved in that step.
This commit is contained in:
Adrian Cowan
2023-01-14 02:16:27 +11:00
parent 3d4b57c071
commit eb43c8b4f8
11 changed files with 134 additions and 56 deletions
+8 -2
View File
@@ -5,7 +5,13 @@ import { TrackedTextarea } from "src/components/Survey/TrackedTextarea";
import { TwoColumnsWithCards } from "src/components/Survey/TwoColumnsWithCards";
import { TaskSurveyProps } from "src/components/Tasks/Task";
export const CreateTask = ({ task, taskType, isDisabled, onReplyChanged }: TaskSurveyProps<{ text: string }>) => {
export const CreateTask = ({
task,
taskType,
isEditable,
isDisabled,
onReplyChanged,
}: TaskSurveyProps<{ text: string }>) => {
const cardColor = useColorModeValue("gray.100", "gray.700");
const titleColor = useColorModeValue("gray.800", "gray.300");
const labelColor = useColorModeValue("gray.600", "gray.400");
@@ -50,7 +56,7 @@ export const CreateTask = ({ task, taskType, isDisabled, onReplyChanged }: TaskS
text={inputText}
onTextChange={textChangeHandler}
thresholds={{ low: 20, medium: 40, goal: 50 }}
textareaProps={{ placeholder: "Write your prompt here...", isDisabled }}
textareaProps={{ placeholder: "Write your prompt here...", isDisabled, isReadOnly: !isEditable }}
/>
</Stack>
</>
+13 -2
View File
@@ -5,7 +5,12 @@ import { Sortable } from "src/components/Sortable/Sortable";
import { SurveyCard } from "src/components/Survey/SurveyCard";
import { TaskSurveyProps } from "src/components/Tasks/Task";
export const EvaluateTask = ({ task, isDisabled, onReplyChanged }: TaskSurveyProps<{ ranking: number[] }>) => {
export const EvaluateTask = ({
task,
isEditable,
isDisabled,
onReplyChanged,
}: TaskSurveyProps<{ ranking: number[] }>) => {
const cardColor = useColorModeValue("gray.100", "gray.700");
const titleColor = useColorModeValue("gray.800", "gray.300");
const labelColor = useColorModeValue("gray.600", "gray.400");
@@ -46,7 +51,13 @@ export const EvaluateTask = ({ task, isDisabled, onReplyChanged }: TaskSurveyPro
<Box mt="4" p="6" borderRadius="lg" bg={cardColor}>
<MessageTable messages={messages} />
</Box>
<Sortable items={task[sortables]} isDisabled={isDisabled} onChange={onRank} className="my-8" />
<Sortable
items={task[sortables]}
isDisabled={isDisabled}
isEditable={isEditable}
onChange={onRank}
className="my-8"
/>
</SurveyCard>
</Box>
</div>
+7 -7
View File
@@ -12,7 +12,7 @@ export const LabelTask = ({
task,
taskType,
onReplyChanged,
isDisabled,
isEditable,
}: TaskSurveyProps<{ text: string; labels: { [k: string]: number }; message_id: string }>) => {
const valid_labels = task.valid_labels;
const [sliderValues, setSliderValues] = useState<number[]>(new Array(valid_labels.length).fill(0));
@@ -65,7 +65,7 @@ export const LabelTask = ({
</Box>
)}
</>
<LabelSliderGroup labelIDs={task.valid_labels} isDisabled={isDisabled} onChange={onSliderChange} />
<LabelSliderGroup labelIDs={task.valid_labels} isEditable={isEditable} onChange={onSliderChange} />
</TwoColumnsWithCards>
</div>
);
@@ -75,10 +75,10 @@ export const LabelTask = ({
interface LabelSliderGroupProps {
labelIDs: Array<string>;
onChange: (sliderValues: number[]) => unknown;
isDisabled?: boolean;
isEditable: boolean;
}
export const LabelSliderGroup = ({ labelIDs, onChange, isDisabled }: LabelSliderGroupProps) => {
export const LabelSliderGroup = ({ labelIDs, onChange, isEditable }: LabelSliderGroupProps) => {
const [sliderValues, setSliderValues] = useState<number[]>(Array.from({ length: labelIDs.length }).map(() => 0));
return (
@@ -94,7 +94,7 @@ export const LabelSliderGroup = ({ labelIDs, onChange, isDisabled }: LabelSlider
onChange(sliderValues);
setSliderValues(newState);
}}
isDisabled={isDisabled}
isEditable={isEditable}
/>
))}
</Grid>
@@ -105,7 +105,7 @@ function CheckboxSliderItem(props: {
labelId: string;
sliderValue: number;
sliderHandler: (newVal: number) => unknown;
isDisabled: boolean;
isEditable: boolean;
}) {
const id = useId();
const { colorMode } = useColorMode();
@@ -118,7 +118,7 @@ function CheckboxSliderItem(props: {
{/* TODO: display real text instead of just the id */}
<span className={labelTextClass}>{props.labelId}</span>
</label>
<Slider defaultValue={0} isDisabled={props.isDisabled} onChangeEnd={(val) => props.sliderHandler(val / 100)}>
<Slider defaultValue={0} isDisabled={!props.isEditable} onChangeEnd={(val) => props.sliderHandler(val / 100)}>
<SliderTrack>
<SliderFilledTrack />
<SliderThumb />
+48 -20
View File
@@ -10,13 +10,14 @@ import { TaskContent } from "src/types/Task";
import { TaskReplyState } from "src/types/TaskReplyState";
import useSWRMutation from "swr/mutation";
export type TaskStatus = "NOT_SUBMITTABLE" | "DEFAULT" | "SUBMITABLE" | "SUBMITTED";
export type TaskStatus = "NOT_SUBMITTABLE" | "DEFAULT" | "VALID" | "REVIEW" | "SUBMITTED";
export interface TaskSurveyProps<T> {
// we need a task type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
task: any;
taskType: TaskInfo;
isEditable: boolean;
isDisabled?: boolean;
onReplyChanged: (state: TaskReplyState<T>) => void;
}
@@ -50,20 +51,38 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
} else if (state.state === "DEFAULT") {
if (taskStatus !== "DEFAULT") setTaskStatus("DEFAULT");
} else if (state.state === "VALID") {
if (taskStatus !== "SUBMITABLE") setTaskStatus("SUBMITABLE");
} else if (state.state == "INVALID") {
if (taskStatus !== "VALID") setTaskStatus("VALID");
} else if (state.state === "INVALID") {
setTaskStatus("NOT_SUBMITTABLE");
}
}).current;
const submitResponse = () => {
const reviewResponse = () => {
switch (taskStatus) {
case "NOT_SUBMITTABLE":
return;
case "DEFAULT":
setShowUnchangedWarning(true);
break;
case "SUBMITABLE": {
case "VALID":
setTaskStatus("REVIEW");
break;
default:
return;
}
};
const editResponse = () => {
switch (taskStatus) {
case "REVIEW":
setTaskStatus("VALID");
break;
default:
return;
}
};
const submitResponse = () => {
switch (taskStatus) {
case "REVIEW": {
trigger({
id: frontendId,
update_type: taskType.update_type,
@@ -72,11 +91,14 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
setTaskStatus("SUBMITTED");
break;
}
case "SUBMITTED":
default:
return;
}
};
const edit_mode = taskStatus === "NOT_SUBMITTABLE" || taskStatus === "DEFAULT" || taskStatus === "VALID";
const submitted = taskStatus === "SUBMITTED";
function taskTypeComponent() {
switch (taskType.category) {
case TaskCategory.Create:
@@ -85,7 +107,8 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
key={task.id}
task={task}
taskType={taskType}
isDisabled={taskStatus === "SUBMITTED"}
isEditable={edit_mode}
isDisabled={submitted}
onReplyChanged={onReplyChanged}
/>
);
@@ -95,7 +118,8 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
key={task.id}
task={task}
taskType={taskType}
isDisabled={taskStatus === "SUBMITTED"}
isEditable={edit_mode}
isDisabled={submitted}
onReplyChanged={onReplyChanged}
/>
);
@@ -105,7 +129,8 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
key={task.id}
task={task}
taskType={taskType}
isDisabled={taskStatus === "SUBMITTED"}
isEditable={edit_mode}
isDisabled={submitted}
onReplyChanged={onReplyChanged}
/>
);
@@ -115,20 +140,23 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
return (
<div>
{taskTypeComponent()}
<TaskControls task={task} taskStatus={taskStatus} onSubmit={submitResponse} onSkip={rejectTask} />
<TaskControls
task={task}
taskStatus={taskStatus}
onEdit={editResponse}
onReview={reviewResponse}
onSubmit={submitResponse}
onSkip={rejectTask}
/>
<UnchangedWarning
show={showUnchangedWarning}
title={taskType.unchanged_title || "No changes"}
message={taskType.unchanged_message || "Are you sure you would like to submit?"}
message={taskType.unchanged_message || "Are you sure you would like to continue?"}
continueButtonText={"Continue anyway"}
onClose={() => setShowUnchangedWarning(false)}
onSubmitAnyway={() => {
onContinueAnyway={() => {
if (taskStatus === "DEFAULT") {
trigger({
id: frontendId,
update_type: taskType.update_type,
content: replyContent.current,
});
setTaskStatus("SUBMITTED");
setTaskStatus("REVIEW");
setShowUnchangedWarning(false);
}
}}
+3 -3
View File
@@ -68,7 +68,7 @@ export const TaskTypes: TaskInfo[] = [
type: "rank_prompter_replies",
update_type: "message_ranking",
unchanged_title: "Order Unchanged",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to submit?",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to continue?",
},
{
label: "Rank Assistant Replies",
@@ -78,7 +78,7 @@ export const TaskTypes: TaskInfo[] = [
type: "rank_assistant_replies",
update_type: "message_ranking",
unchanged_title: "Order Unchanged",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to submit?",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to continue?",
},
{
label: "Rank Initial Prompts",
@@ -88,7 +88,7 @@ export const TaskTypes: TaskInfo[] = [
type: "rank_initial_prompts",
update_type: "message_ranking",
unchanged_title: "Order Unchanged",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to submit?",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to continue?",
},
// label
{
@@ -14,8 +14,9 @@ interface UnchangedWarningProps {
show: boolean;
title: string;
message: string;
continueButtonText: string;
onClose: () => void;
onSubmitAnyway: () => void;
onContinueAnyway: () => void;
}
export const UnchangedWarning = (props: UnchangedWarningProps) => {
@@ -32,7 +33,7 @@ export const UnchangedWarning = (props: UnchangedWarningProps) => {
<Button variant={"ghost"} onClick={props.onClose}>
Cancel
</Button>
<Button onClick={props.onSubmitAnyway}>Submit anyway</Button>
<Button onClick={props.onContinueAnyway}>{props.continueButtonText}</Button>
</Flex>
</ModalFooter>
</ModalContent>