frontPanel/src/create/createQuestion.tsx
2022-07-14 16:53:21 +03:00

281 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from 'react';
import { useField, Form, FormikProps, Formik } from 'formik';
import {
Select, Textarea, VStack, Checkbox, Button,
} from '@chakra-ui/react'
import 'suneditor/dist/css/suneditor.min.css'; // Import Sun Editor's CSS File
import Description from "./description";
import Settings from "./settings";
//Значения, собираемые для отправки на бэк
interface Values {
title: string;
type: string;
children: string;
description: string;
}
//Поля объектов, используемых для отображения созданных пользователем инструментов
interface ElementsOfObject {
text: string;
id: number;
isFocus: boolean;
color?: string;
}
const types = [
{desc:"текст", value:"text"},
{desc:"селект", value:"select"},
{desc:"чекбокс", value:"checkbox"},
{desc:"файл", value:"file"},
{desc:"кнопка", value:"button"},
{desc:"ничего", value:"none"}
]
const TextField = (props: any) => {
const [field, meta, helpers] = useField(props);
return (
<>
<Textarea resize="none" width="80%" {...field} {...props} />
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</>
);
};
const getFreeNumber = (array:Array<ElementsOfObject>):number => {
// Для первого элемента в списке
if (array.length === 0) {
return(0)
} else {
//Для всех последующих элементов
//Создаём массив, состоящий из id всех существующих модалок
let indexes:any = []
for (let i = 0; i < array.length; i++) {
indexes.push(array[i].id)
}
//Сортируем в порядке возрастания
indexes.sort(function compare(a:any, b:any):any {
if (a < b) { return -1;}
if (a > b) { return 1;}
return 0;
}
)
let max = indexes[indexes.length - 1]
//Создаём массив - маску от 0 до самого высокого значения id
let mask:any = []
for (let i = 0; i <= max; i++) {
mask.push(i)
}
//Ищем разницу между существующими id окон и маской. Список пропущенных значений есть список доступных имён.
let difference = indexes
.filter((num:any):any => !mask.includes(num))
.concat(mask.filter((num:any):any => !indexes.includes(num)));
// difference - массив нехватающих в списке номеров.
// Если все окна у нас по порядку, без пропусков - нужно добавить новый номер
if (difference.length === 0) {
return(max + 1)
} else {
//Иначе добавить нехватающий
return(difference[0])
}
}
}
const getIndexById = (id:number, array:Array<ElementsOfObject>):number => {
let index
for (let i = 0; i <= array.length; i++) {
if (array[i] !== undefined) {
if (array[i].id === id) {
index = i
break
}
}
}
if (typeof index === "number") {
return index
} else {
console.log("Я не нашёл нужный индекс, вывел 0")
return 0
}
}
export default () => {
const [type, setType] = React.useState<number>(4)
const [stockroom, setStockroom] = React.useState<Array<ElementsOfObject>>([])
const [focus, setFocus] = React.useState<number | undefined>() //Хранит id объекта
//При пересоздании массива для изменения фокуса объекта отменяются фокусы у всех элементов массива
const typeHC = (value:number): void => {
setType(value)
setStockroom([])
}
const changeFocus = (id: number): void => {
//Не менять фокус если снова выбрано то же окно
if (focus !== id) {
//Хранилище с отменённым фокусом у объектов (по задумке у одного элемента)
let newArr = stockroom.map((e:ElementsOfObject) => {
e.isFocus = false
return e
})
//Получаем индексы фокусированных объектов. Новый и, если есть, старый
let index = getIndexById(id, stockroom)
//Устанавливаем новый фокус и пересоздаём массив
setFocus(id)
newArr[index].isFocus = true
setStockroom([...newArr])
}
}
const changeBgColor = (color: string): void => {
if (focus !== undefined) {
let index = getIndexById(focus, stockroom)
let list = stockroom
list[index].color = color
setStockroom([...list])
}
}
const changeText = (text: string): void => {
if (focus !== undefined) {
let index = getIndexById(focus, stockroom)
let list = stockroom
list[index].text = text
setStockroom([...list])
}
}
const createObject = (obj:ElementsOfObject) => {
//Получаем и присваиваем первый свободный айдишник (по возрастанию)
const free = getFreeNumber(stockroom)
obj.id = free
//Хранилище с отменённым фокусом у объектов (по задумке у одного элемента)
let newArr = stockroom.map((e:ElementsOfObject) => {
e.isFocus = false
return e
})
//Мы должны вставить новый объект следующим после того, на котором фокус. Это достигается позиционированием в массив
if (focus === undefined){ //фокуса нет - добавляем в конец массива
newArr.push(obj)
setStockroom([...newArr])
//Говорим стейту с фокусом, что фокус изменился
setFocus(newArr.length - 1)
} else { //фокус есть - добавляем после объекта с фокусом
let index = getIndexById(focus, stockroom)
newArr.splice(index + 1, 0, obj)
//Говорим стейту с фокусом, что фокус изменился
setFocus(index + 1)
setStockroom([...newArr])
}
}
const deleteObject = (id: number): void => {
let index = getIndexById(id, stockroom)
//Проверка, что объект с таким id существует
if (stockroom[index] !== undefined) {
//Если удалён был фокусный объект - фокус теперь неизвестен
if (stockroom[index].isFocus) {
setFocus(undefined)
}
let newArr = stockroom
newArr.splice(index, 1)
setStockroom([...newArr])
}
}
return(
<>
<Formik
initialValues={{
children: '',
title: '',
type: '',
description:'описание',
}}
onSubmit={(values, actions) => {
console.log(JSON.stringify(values))
}}
>
{(props: FormikProps<Values>) => (
<Form>
<VStack>
<TextField placeholder="Заголовок" name="title" type="text" />
<Description name="description"/>
{
type === 0 ? //Тип вопроса - текст?
<TextField name="text" placeholder="текст" type="text" />
:
type === 3 ? //Тип вопроса - файл?
<input type="file"/>
:
stockroom.length === 0 ? //В поле для юзерских данных есть что-то?
null //Ничего не внесено
:
type === 1 ? //Тип вопроса - селект?
<Select
>
{
stockroom.map((e: any, i: number) => {
return <option key={i}>{e.text}</option>
})
}
</Select>
:
type === 2 ? //Тип вопроса - чекбокс?
stockroom.map((e:any, i:number) => {
return <Checkbox key={i}>{e.text}</Checkbox>
})
:
type === 4 ? //Тип вопроса - кнопка?
stockroom.map((e:any, i:number) => {
return <Button
backgroundColor={e.color}
key={i}
onClick={(event: any) => {
changeFocus(e.id)
event.target.blur()
}}
>{e.text}</Button>
})
:
null //Тип вопроса - ничего
}
</VStack>
<Settings
types={types}
stockroom={stockroom}
typeHC={typeHC}
type={type}
focus={focus}
changeFocus={changeFocus}
changeBgColor={changeBgColor}
changeText={changeText}
getIndexById={getIndexById}
createObject={createObject}
deleteObject={deleteObject}
/>
</Form>
)}
</Formik>
</>
)
}