import { Box, Button, Checkbox, Flex, Popover, PopoverAnchor, PopoverArrow, PopoverBody, PopoverCloseButton, PopoverContent, PopoverTrigger, Slider, SliderFilledTrack, SliderThumb, SliderTrack, Tooltip, useBoolean, useColorMode, useColorModeValue, useId, } from "@chakra-ui/react"; import { QuestionMarkCircleIcon } from "@heroicons/react/20/solid"; import clsx from "clsx"; import { useEffect, useReducer } from "react"; import { FiAlertCircle } from "react-icons/fi"; import { get, post } from "src/lib/api"; import { colors } from "src/styles/Theme/colors"; import { Message } from "src/types/Conversation"; import useSWR from "swr"; import useSWRMutation from "swr/mutation"; interface Label { name: string; display_text: 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 { children: React.ReactNode; message: Message; } export const FlaggableElement = (props: FlaggableElementProps) => { const [report, updateReport] = useReducer( (state: FlagReportState, action: LoadLabelsAction | UpdateValueAction | ToggleLabelAction): FlagReportState => { 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 { data, isLoading } = useSWR("/api/valid_labels", get); useEffect(() => { if (isLoading) { return; } if (!data) { updateReport({ type: "load_labels", labels: [] }); return; } const { valid_labels } = data; updateReport({ type: "load_labels", labels: valid_labels }); }, [data, isLoading]); const { trigger } = useSWRMutation("/api/set_label", post, { onSuccess: setIsEditing.off, }); const submitResponse = () => { const label_map: Map = new Map(); report.label_values.forEach(({ label, checked, value }) => { if (checked) { label_map.set(label.name, value); } }); trigger({ message_id: props.message.id, label_map: Object.fromEntries(label_map), text: props.message.text, }); }; const handleCheckboxState = (checked, label_index) => { updateReport({ type: "toggle_label", label_index, check: checked }); }; const handleSliderState = (value, label_index) => { updateReport({ type: "update_value", label_index, value }); }; return ( {props.children} {report.label_values.map(({ label, checked, value }, i) => ( ))} ); }; interface FlagCheckboxProps { label: Label; idx: number; checked: boolean; sliderValue: number; checkboxHandler: (newVal: boolean, idx: number) => void; sliderHandler: (newVal: number, idx: number) => void; } export function FlagCheckbox(props: FlagCheckboxProps): JSX.Element { let AdditionalExplanation = null; if (props.label.help_text) { AdditionalExplanation = ( ); } const id = useId(); const { colorMode } = useColorMode(); const labelTextClass = colorMode === "light" ? `text-${colors.light.text} hover:text-blue-700` : `text-${colors.dark.text} hover:text-blue-400`; return (
{ props.checkboxHandler(e.target.checked, props.idx); }} />
{ if (!props.checked) { props.checkboxHandler(true, props.idx); } }} > { props.sliderHandler(val / 100, props.idx); }} >
); }