mirror of
https://github.com/wassname/Open-Assistant.git
synced 2026-09-12 12:03:06 +08:00
website: Enable label when clicking on disabled slider
This commit is contained in:
@@ -22,7 +22,7 @@ import {
|
|||||||
useId,
|
useId,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { FlagIcon, QuestionMarkCircleIcon } from "@heroicons/react/20/solid";
|
import { FlagIcon, QuestionMarkCircleIcon } from "@heroicons/react/20/solid";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useReducer } from "react";
|
||||||
import fetcher from "src/lib/fetcher";
|
import fetcher from "src/lib/fetcher";
|
||||||
import poster from "src/lib/poster";
|
import poster from "src/lib/poster";
|
||||||
import { Message } from "src/types/Conversation";
|
import { Message } from "src/types/Conversation";
|
||||||
@@ -30,10 +30,38 @@ import { colors } from "styles/Theme/colors";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import useSWRMutation from "swr/mutation";
|
import useSWRMutation from "swr/mutation";
|
||||||
|
|
||||||
interface textFlagLabels {
|
interface Label {
|
||||||
attributeName: string;
|
name: string;
|
||||||
labelText: string;
|
display_text: string;
|
||||||
additionalExplanation?: string;
|
help_text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LoadLabelsAction {
|
||||||
|
type: "load_labels";
|
||||||
|
labels: Label[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateValueAction {
|
||||||
|
type: "update_value";
|
||||||
|
label_index: number;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ToggleLabelAction {
|
||||||
|
type: "toggle_label";
|
||||||
|
label_index: number;
|
||||||
|
check: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LabelValue {
|
||||||
|
label: Label;
|
||||||
|
checked: boolean;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FlagReportState {
|
||||||
|
label_values: LabelValue[];
|
||||||
|
submittable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FlaggableElementProps {
|
interface FlaggableElementProps {
|
||||||
@@ -42,9 +70,34 @@ interface FlaggableElementProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const FlaggableElement = (props: FlaggableElementProps) => {
|
export const FlaggableElement = (props: FlaggableElementProps) => {
|
||||||
const [labels, setLabels] = useState([]);
|
const [report, updateReport] = useReducer(
|
||||||
const [checkboxValues, setCheckboxValues] = useState([]);
|
(state: FlagReportState, action: LoadLabelsAction | UpdateValueAction | ToggleLabelAction): FlagReportState => {
|
||||||
const [sliderValues, setSliderValues] = useState([]);
|
const makeState = (label_values: LabelValue[]): FlagReportState => {
|
||||||
|
const submittable = label_values.map(({ checked }) => checked).some(Boolean);
|
||||||
|
return { label_values, submittable };
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (action.type) {
|
||||||
|
case "load_labels":
|
||||||
|
return makeState(
|
||||||
|
action.labels.map((label) => {
|
||||||
|
return { label, checked: false, value: 1 };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
case "toggle_label": {
|
||||||
|
const values_copy = state.label_values.slice();
|
||||||
|
values_copy[action.label_index].checked = action.check;
|
||||||
|
return makeState(values_copy);
|
||||||
|
}
|
||||||
|
case "update_value": {
|
||||||
|
const values_copy = state.label_values.slice();
|
||||||
|
values_copy[action.label_index].value = action.value;
|
||||||
|
return makeState(values_copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label_values: [], submittable: false }
|
||||||
|
);
|
||||||
const [isEditing, setIsEditing] = useBoolean();
|
const [isEditing, setIsEditing] = useBoolean();
|
||||||
const backgroundColor = useColorModeValue("gray.200", "gray.700");
|
const backgroundColor = useColorModeValue("gray.200", "gray.700");
|
||||||
|
|
||||||
@@ -54,14 +107,7 @@ export const FlaggableElement = (props: FlaggableElementProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { valid_labels } = data;
|
const { valid_labels } = data;
|
||||||
const newLabels = valid_labels.map((valid_label) => ({
|
updateReport({ type: "load_labels", labels: valid_labels });
|
||||||
attributeName: valid_label.name,
|
|
||||||
labelText: valid_label.display_text,
|
|
||||||
additionalExplanation: valid_label.help_text,
|
|
||||||
}));
|
|
||||||
setSliderValues(new Array(newLabels.length).fill(1));
|
|
||||||
setCheckboxValues(new Array(newLabels.length).fill(false));
|
|
||||||
setLabels(newLabels);
|
|
||||||
}, [data, isLoading]);
|
}, [data, isLoading]);
|
||||||
|
|
||||||
const { trigger } = useSWRMutation("/api/set_label", poster, {
|
const { trigger } = useSWRMutation("/api/set_label", poster, {
|
||||||
@@ -72,9 +118,9 @@ export const FlaggableElement = (props: FlaggableElementProps) => {
|
|||||||
|
|
||||||
const submitResponse = () => {
|
const submitResponse = () => {
|
||||||
const label_map: Map<string, number> = new Map();
|
const label_map: Map<string, number> = new Map();
|
||||||
labels.forEach((flag, i) => {
|
report.label_values.forEach(({ label, checked, value }) => {
|
||||||
if (checkboxValues[i]) {
|
if (checked) {
|
||||||
label_map.set(flag.attributeName, sliderValues[i]);
|
label_map.set(label.name, value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
trigger({
|
trigger({
|
||||||
@@ -84,19 +130,11 @@ export const FlaggableElement = (props: FlaggableElementProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCheckboxState = (isChecked, idx) => {
|
const handleCheckboxState = (checked, label_index) => {
|
||||||
setCheckboxValues(
|
updateReport({ type: "toggle_label", label_index, check: checked });
|
||||||
checkboxValues.map((val, i) => {
|
|
||||||
return i === idx ? isChecked : val;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const handleSliderState = (newVal, idx) => {
|
const handleSliderState = (value, label_index) => {
|
||||||
setSliderValues(
|
updateReport({ type: "update_value", label_index, value });
|
||||||
sliderValues.map((val, i) => {
|
|
||||||
return i === idx ? newVal : val;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -127,20 +165,20 @@ export const FlaggableElement = (props: FlaggableElementProps) => {
|
|||||||
<PopoverCloseButton />
|
<PopoverCloseButton />
|
||||||
</div>
|
</div>
|
||||||
<PopoverBody>
|
<PopoverBody>
|
||||||
{labels.map((option, i) => (
|
{report.label_values.map(({ label, checked, value }, i) => (
|
||||||
<FlagCheckbox
|
<FlagCheckbox
|
||||||
option={option}
|
label={label}
|
||||||
key={i}
|
key={i}
|
||||||
idx={i}
|
idx={i}
|
||||||
checkboxValues={checkboxValues}
|
checked={checked}
|
||||||
sliderValues={sliderValues}
|
sliderValue={value}
|
||||||
checkboxHandler={handleCheckboxState}
|
checkboxHandler={handleCheckboxState}
|
||||||
sliderHandler={handleSliderState}
|
sliderHandler={handleSliderState}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<Flex justify="center">
|
<Flex justify="center">
|
||||||
<Button
|
<Button
|
||||||
isDisabled={!checkboxValues.some(Boolean)}
|
isDisabled={!report.submittable}
|
||||||
onClick={submitResponse}
|
onClick={submitResponse}
|
||||||
className={`bg-indigo-600 text-${useColorModeValue(
|
className={`bg-indigo-600 text-${useColorModeValue(
|
||||||
colors.light.text,
|
colors.light.text,
|
||||||
@@ -157,17 +195,17 @@ export const FlaggableElement = (props: FlaggableElementProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface FlagCheckboxProps {
|
interface FlagCheckboxProps {
|
||||||
option: textFlagLabels;
|
label: Label;
|
||||||
idx: number;
|
idx: number;
|
||||||
checkboxValues: boolean[];
|
checked: boolean;
|
||||||
sliderValues: number[];
|
sliderValue: number;
|
||||||
checkboxHandler: (newVal: boolean, idx: number) => void;
|
checkboxHandler: (newVal: boolean, idx: number) => void;
|
||||||
sliderHandler: (newVal: number, idx: number) => void;
|
sliderHandler: (newVal: number, idx: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FlagCheckbox(props: FlagCheckboxProps): JSX.Element {
|
export function FlagCheckbox(props: FlagCheckboxProps): JSX.Element {
|
||||||
let AdditionalExplanation = null;
|
let AdditionalExplanation = null;
|
||||||
if (props.option.additionalExplanation) {
|
if (props.label.help_text) {
|
||||||
AdditionalExplanation = (
|
AdditionalExplanation = (
|
||||||
<a href="#" className="group flex items-center space-x-2.5 text-sm ">
|
<a href="#" className="group flex items-center space-x-2.5 text-sm ">
|
||||||
<QuestionMarkCircleIcon
|
<QuestionMarkCircleIcon
|
||||||
@@ -190,28 +228,37 @@ export function FlagCheckbox(props: FlagCheckboxProps): JSX.Element {
|
|||||||
<Flex gap={1}>
|
<Flex gap={1}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={id}
|
id={id}
|
||||||
|
isChecked={props.checked}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
props.checkboxHandler(e.target.checked, props.idx);
|
props.checkboxHandler(e.target.checked, props.idx);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<label className="text-sm form-check-label" htmlFor={id}>
|
<label className="text-sm form-check-label" htmlFor={id}>
|
||||||
<span className={labelTextClass}>{props.option.labelText}</span>
|
<span className={labelTextClass}>{props.label.display_text}</span>
|
||||||
{AdditionalExplanation}
|
{AdditionalExplanation}
|
||||||
</label>
|
</label>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<Slider
|
<div
|
||||||
width="100px"
|
onClick={() => {
|
||||||
isDisabled={!props.checkboxValues[props.idx]}
|
if (!props.checked) {
|
||||||
defaultValue={100}
|
props.checkboxHandler(true, props.idx);
|
||||||
onChangeEnd={(val) => {
|
}
|
||||||
props.sliderHandler(val / 100, props.idx);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SliderTrack>
|
<Slider
|
||||||
<SliderFilledTrack />
|
width="100px"
|
||||||
<SliderThumb />
|
isDisabled={!props.checked}
|
||||||
</SliderTrack>
|
defaultValue={100}
|
||||||
</Slider>
|
onChangeEnd={(val) => {
|
||||||
|
props.sliderHandler(val / 100, props.idx);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SliderTrack>
|
||||||
|
<SliderFilledTrack />
|
||||||
|
<SliderThumb />
|
||||||
|
</SliderTrack>
|
||||||
|
</Slider>
|
||||||
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user