mirror of
https://github.com/spbleadersofdigtal/frontend.git
synced 2024-11-25 11:43:43 +03:00
добавил загрузку фото
This commit is contained in:
parent
903461baa7
commit
7b04b42964
|
@ -9,6 +9,8 @@ export type CreateAnswerDTO = {
|
||||||
deckId: number;
|
deckId: number;
|
||||||
questionId: number;
|
questionId: number;
|
||||||
answer: any;
|
answer: any;
|
||||||
|
isFile?: boolean;
|
||||||
|
file?: File;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CreateAnswerResponse = Answer;
|
export type CreateAnswerResponse = Answer;
|
||||||
|
@ -18,7 +20,29 @@ export const createAnswer = (data: CreateAnswerDTO): Promise<CreateAnswerRespons
|
||||||
.replace(`:${QUESTION_PARAM_DECK_ID}`, String(data.deckId))
|
.replace(`:${QUESTION_PARAM_DECK_ID}`, String(data.deckId))
|
||||||
.replace(`:${QUESTION_PARAM_QUESTION_ID}`, String(data.questionId)) + '/'
|
.replace(`:${QUESTION_PARAM_QUESTION_ID}`, String(data.questionId)) + '/'
|
||||||
|
|
||||||
return axios.post(path, { answer: data.answer });
|
let inputData: any;
|
||||||
|
if (data.isFile) {
|
||||||
|
inputData = new FormData();
|
||||||
|
if (data.answer) {
|
||||||
|
inputData.append('answer', `${data.answer}`);
|
||||||
|
}
|
||||||
|
for (const key in data) {
|
||||||
|
if (key !== 'answer' && key !== 'isFile' && key !== 'deckId' && key !== 'questionId') {
|
||||||
|
// @ts-ignore
|
||||||
|
inputData.append(key, data[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputData = {
|
||||||
|
answer: data.answer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return axios.post(path, inputData, {
|
||||||
|
headers: data.isFile ? {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
} : {}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
type UseCreateAnswerOptions = {
|
type UseCreateAnswerOptions = {
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
export enum EntityType {
|
export enum EntityType {
|
||||||
text = 'text', //
|
text = 'text', // +
|
||||||
number = 'number', //
|
number = 'number', // +
|
||||||
range = 'range', //
|
range = 'range', // +
|
||||||
multiple_range = 'multiple_range', //
|
multiple_range = 'multiple_range', // +
|
||||||
select = 'select', //
|
select = 'select', // +
|
||||||
link = 'link', // добавить валидацию
|
link = 'link', // + добавить валидацию
|
||||||
date = 'date', // добавить правильную установку хинта
|
date = 'date', // +
|
||||||
photo = 'photo',
|
// photo = 'photo',
|
||||||
multiple_photo = 'multiple_photo',
|
multiple_photo = 'multiple_photo',
|
||||||
photo_description = 'photo_description',
|
photo_description = 'photo_description',
|
||||||
multiple_link_description = 'multiple_link_description',
|
multiple_link_description = 'multiple_link_description', //
|
||||||
multiple_photo_description = 'multiple_photo_description',
|
multiple_photo_description = 'multiple_photo_description',
|
||||||
multiple_links = 'multiple_links',
|
// multiple_links = 'multiple_links', // не пригодилось
|
||||||
multiple_date_description = 'multiple_date_description', //
|
multiple_date_description = 'multiple_date_description', //
|
||||||
text_array = 'text_array', // используется только в подсказке
|
text_array = 'text_array', // используется только в подсказке
|
||||||
cards = 'cards', // используется только в подсказке
|
cards = 'cards', // используется только в подсказке
|
||||||
|
|
5
src/assets/icons/upload.svg
Normal file
5
src/assets/icons/upload.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 14.25C3.41421 14.25 3.75 14.5858 3.75 15C3.75 16.4354 3.75159 17.4365 3.85315 18.1919C3.9518 18.9257 4.13225 19.3142 4.40901 19.591C4.68577 19.8678 5.07435 20.0482 5.80812 20.1469C6.56347 20.2484 7.56459 20.25 9 20.25H15C16.4354 20.25 17.4365 20.2484 18.1919 20.1469C18.9257 20.0482 19.3142 19.8678 19.591 19.591C19.8678 19.3142 20.0482 18.9257 20.1469 18.1919C20.2484 17.4365 20.25 16.4354 20.25 15C20.25 14.5858 20.5858 14.25 21 14.25C21.4142 14.25 21.75 14.5858 21.75 15V15.0549C21.75 16.4225 21.75 17.5248 21.6335 18.3918C21.5125 19.2919 21.2536 20.0497 20.6517 20.6516C20.0497 21.2536 19.2919 21.5125 18.3918 21.6335C17.5248 21.75 16.4225 21.75 15.0549 21.75H8.94513C7.57754 21.75 6.47522 21.75 5.60825 21.6335C4.70814 21.5125 3.95027 21.2536 3.34835 20.6517C2.74643 20.0497 2.48754 19.2919 2.36652 18.3918C2.24996 17.5248 2.24998 16.4225 2.25 15.0549C2.25 15.0366 2.25 15.0183 2.25 15C2.25 14.5858 2.58579 14.25 3 14.25Z" fill="currentColor"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2.25C12.2106 2.25 12.4114 2.33852 12.5535 2.49392L16.5535 6.86892C16.833 7.17462 16.8118 7.64902 16.5061 7.92852C16.2004 8.20802 15.726 8.18678 15.4465 7.88108L12.75 4.9318V16C12.75 16.4142 12.4142 16.75 12 16.75C11.5858 16.75 11.25 16.4142 11.25 16V4.9318L8.55353 7.88108C8.27403 8.18678 7.79963 8.20802 7.49393 7.92852C7.18823 7.64902 7.16698 7.17462 7.44648 6.86892L11.4465 2.49392C11.5886 2.33852 11.7894 2.25 12 2.25Z" fill="currentColor"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
17
src/components/UploadButton/UploadButton.module.scss
Normal file
17
src/components/UploadButton/UploadButton.module.scss
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
@import 'src/app/styles/vars';
|
||||||
|
|
||||||
|
.UploadButton {
|
||||||
|
width: 100%;
|
||||||
|
height: 80px !important;
|
||||||
|
//background-color: $color-on-surface-dark-400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.UploadButton__icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.UploadButton__input {
|
||||||
|
display: none;
|
||||||
|
}
|
35
src/components/UploadButton/UploadButton.tsx
Normal file
35
src/components/UploadButton/UploadButton.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import s from './UploadButton.module.scss';
|
||||||
|
import {ReactFCC} from '../../utils/ReactFCC';
|
||||||
|
import {Button, ButtonVariant} from '../Button';
|
||||||
|
import { ReactComponent as UploadIcon } from '../../assets/icons/upload.svg';
|
||||||
|
import {useId} from 'react';
|
||||||
|
|
||||||
|
export interface UploadButtonProps {
|
||||||
|
/**
|
||||||
|
* Дополнительный css-класс
|
||||||
|
*/
|
||||||
|
className?: string;
|
||||||
|
onChange?: (e: any) => void;
|
||||||
|
multiple?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UploadButton: ReactFCC<UploadButtonProps> = (props) => {
|
||||||
|
const {className, onChange, multiple} = props;
|
||||||
|
|
||||||
|
const id = useId();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button component={'label'} htmlFor={id} className={clsx(s.UploadButton, className)} variant={ButtonVariant.secondary}>
|
||||||
|
<UploadIcon className={s.UploadButton__icon} />
|
||||||
|
<input
|
||||||
|
className={s.UploadButton__input}
|
||||||
|
type="file"
|
||||||
|
id={id}
|
||||||
|
onChange={onChange}
|
||||||
|
multiple={multiple}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
1
src/components/UploadButton/index.ts
Normal file
1
src/components/UploadButton/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './UploadButton';
|
|
@ -18,6 +18,7 @@ import {generateTextFromAnswer} from './utils/generateTextFromAnswer';
|
||||||
import {Button, ButtonVariant} from '../../components/Button';
|
import {Button, ButtonVariant} from '../../components/Button';
|
||||||
import {useNavigate} from 'react-router-dom';
|
import {useNavigate} from 'react-router-dom';
|
||||||
import {DECK_PAGE_PARAM, DECK_PAGE_ROUTE} from '../../app/routes';
|
import {DECK_PAGE_PARAM, DECK_PAGE_ROUTE} from '../../app/routes';
|
||||||
|
import {generateFieldsForFileAnswers} from './utils/generateFieldsForFileAnswers';
|
||||||
|
|
||||||
export interface ChatPageProps {
|
export interface ChatPageProps {
|
||||||
/**
|
/**
|
||||||
|
@ -28,8 +29,8 @@ export interface ChatPageProps {
|
||||||
|
|
||||||
const QUESTION_POLLING_MS = 1000;
|
const QUESTION_POLLING_MS = 1000;
|
||||||
|
|
||||||
const DEFAULT_DECK_ID = 0;
|
const DEFAULT_DECK_ID = 80;
|
||||||
const DEFAULT_QUESTION_ID = 0;
|
const DEFAULT_QUESTION_ID = 25;
|
||||||
|
|
||||||
export const ChatPage: ReactFCC<ChatPageProps> = (props) => {
|
export const ChatPage: ReactFCC<ChatPageProps> = (props) => {
|
||||||
const {className} = props;
|
const {className} = props;
|
||||||
|
@ -127,16 +128,19 @@ export const ChatPage: ReactFCC<ChatPageProps> = (props) => {
|
||||||
timeout.clear();
|
timeout.clear();
|
||||||
|
|
||||||
const answerValue = generateAnswerFromData(question, data);
|
const answerValue = generateAnswerFromData(question, data);
|
||||||
|
const additionalFields = generateFieldsForFileAnswers(question, data);
|
||||||
|
|
||||||
const answer = await createAnswer({
|
const answer = await createAnswer({
|
||||||
deckId,
|
deckId,
|
||||||
questionId,
|
questionId,
|
||||||
answer: answerValue
|
answer: answerValue,
|
||||||
|
...additionalFields,
|
||||||
|
isFile: !!additionalFields && Object.keys(additionalFields).length !== 0
|
||||||
});
|
});
|
||||||
|
|
||||||
pushHistory({
|
pushHistory({
|
||||||
type: ChatItemType.send,
|
type: ChatItemType.send,
|
||||||
text: generateTextFromAnswer(question.type, answer)
|
text: generateTextFromAnswer(question.type, answer, additionalFields)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (question.next_id) {
|
if (question.next_id) {
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import {ReactFCC} from '../../../../utils/ReactFCC';
|
import {ReactFCC} from '../../../../utils/ReactFCC';
|
||||||
import {EntityType, Hint, Question} from '../../../../api/deck';
|
import {EntityType, Question} from '../../../../api/deck';
|
||||||
import {Form} from '../../../../components/Form';
|
import {Form} from '../../../../components/Form';
|
||||||
import {ChatFormText} from './components/ChatFormText/ChatFormText';
|
import {ChatFormText} from './components/ChatFormText';
|
||||||
import {ChatFormSelect} from './components/ChatFormSelect';
|
import {ChatFormSelect} from './components/ChatFormSelect';
|
||||||
import {ChatFormMultipleRange, RangeType} from './components/ChatFormMultipleRange';
|
import {ChatFormMultipleRange, RangeType} from './components/ChatFormMultipleRange';
|
||||||
import {ChatFormMultipleDateDescription} from './components/ChatFormMultipleDateDescription';
|
import {ChatFormMultipleDateDescription} from './components/ChatFormMultipleDateDescription';
|
||||||
import {ChatFormRange} from './components/ChatFormRange';
|
import {ChatFormRange} from './components/ChatFormRange';
|
||||||
import {ChatFormMultipleLinkDescription} from './components/ChatFormMultipleLinkDescription';
|
import {ChatFormMultipleLinkDescription} from './components/ChatFormMultipleLinkDescription';
|
||||||
|
import {ChatFormPhotoDescription} from './components/ChatFormPhotoDescription';
|
||||||
|
import {ChatFormMultiplePhoto} from './components/ChatFormMultiplePhoto';
|
||||||
|
import {ChatFormMultiplePhotoDescription} from './components/ChatFormMultiplePhotoDescription';
|
||||||
|
|
||||||
export interface QuestionFactoryProps {
|
export interface QuestionFactoryProps {
|
||||||
type: EntityType;
|
type: EntityType;
|
||||||
|
@ -183,6 +186,57 @@ export const QuestionFactory: ReactFCC<QuestionFactoryProps> = (props) => {
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
|
case EntityType.photo_description:
|
||||||
|
return (
|
||||||
|
<Form options={{
|
||||||
|
values: {
|
||||||
|
value: {
|
||||||
|
file: null,
|
||||||
|
text: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{({ handleSubmit, register, control }) => (
|
||||||
|
<ChatFormPhotoDescription
|
||||||
|
registration={register('value', { required: true })}
|
||||||
|
control={control as any}
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
case EntityType.multiple_photo:
|
||||||
|
return (
|
||||||
|
<Form options={{
|
||||||
|
values: {
|
||||||
|
value: {}
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{({ handleSubmit, register, control }) => (
|
||||||
|
<ChatFormMultiplePhoto
|
||||||
|
registration={register('value', { required: true })}
|
||||||
|
control={control as any}
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
case EntityType.multiple_photo_description:
|
||||||
|
return (
|
||||||
|
<Form options={{
|
||||||
|
values: {
|
||||||
|
value: []
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{({ handleSubmit, register, control }) => (
|
||||||
|
<ChatFormMultiplePhotoDescription
|
||||||
|
registration={register('value', { required: true })}
|
||||||
|
control={control as any}
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,3 +32,7 @@
|
||||||
.ChatFormMultipleDateDescription__hint {
|
.ChatFormMultipleDateDescription__hint {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ChatFormMultipleDateDescription__itemName {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
|
@ -58,7 +58,11 @@ export const ChatFormMultipleDateDescription: ReactFCC<ChatFormMultipleDateDescr
|
||||||
onChange({ ...newValue, [new Date(e.target.value).toISOString()]: text })
|
onChange({ ...newValue, [new Date(e.target.value).toISOString()]: text })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Textarea className={s.ChatFormMultipleDateDescription__textarea} placeholder={'Текст'} value={text}
|
<Textarea
|
||||||
|
rows={1}
|
||||||
|
className={s.ChatFormMultipleDateDescription__textarea}
|
||||||
|
placeholder={'Текст'}
|
||||||
|
value={text}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange({ ...value, [date]: e.target.value })
|
onChange({ ...value, [date]: e.target.value })
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -52,7 +52,9 @@ export const ChatFormMultipleLinkDescription: ReactFCC<ChatFormMultipleLinkDescr
|
||||||
onChange({ ...newValue, [e.target.value]: text })
|
onChange({ ...newValue, [e.target.value]: text })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Textarea className={s.ChatFormMultipleDateDescription__textarea}
|
<Textarea
|
||||||
|
rows={1}
|
||||||
|
className={s.ChatFormMultipleDateDescription__textarea}
|
||||||
placeholder={'Текст'}
|
placeholder={'Текст'}
|
||||||
value={text}
|
value={text}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import {ReactFCC} from '../../../../../../utils/ReactFCC';
|
||||||
|
import {ChangeEvent} from 'react';
|
||||||
|
import s from '../ChatFormPhotoDescription/ChatFormPhotoDescription.module.scss';
|
||||||
|
import {UploadButton} from '../../../../../../components/UploadButton';
|
||||||
|
import {Control, Controller, FieldValues, UseFormRegisterReturn} from 'react-hook-form';
|
||||||
|
import {SimpleButton} from '../../../SimpleButton';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
export interface ChatFormMultiplePhotoProps {
|
||||||
|
className?: string;
|
||||||
|
onSubmit: (e: any) => void;
|
||||||
|
registration: Partial<UseFormRegisterReturn>;
|
||||||
|
control: Control<FieldValues>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChatFormMultiplePhoto: ReactFCC<ChatFormMultiplePhotoProps> = (props) => {
|
||||||
|
const {className, onSubmit, registration, control } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx(s.ChatFormPhotoDescription, className)}>
|
||||||
|
<Controller control={control} render={({ field: { value, onChange }}) => (
|
||||||
|
<>
|
||||||
|
{value && Object.values(value).map((file: any, index) => (
|
||||||
|
<p key={index}>Загружен файл: {file.name}</p>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<UploadButton
|
||||||
|
multiple={true}
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (!e.target.files) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const files: any = { ...value };
|
||||||
|
Array.from(e.target.files).forEach((file, index) => {
|
||||||
|
files[`file_${Object.keys(files).length + 1}`] = file;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(files);
|
||||||
|
|
||||||
|
onChange({ ...files })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SimpleButton onClick={onSubmit} />
|
||||||
|
</>
|
||||||
|
)} name={registration.name!} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './ChatFormMultiplePhoto';
|
|
@ -0,0 +1,73 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import {ReactFCC} from '../../../../../../utils/ReactFCC';
|
||||||
|
import {Control, Controller, FieldValues, UseFormRegisterReturn} from 'react-hook-form';
|
||||||
|
import {SimpleButton} from '../../../SimpleButton';
|
||||||
|
import s from '../ChatFormMultipleDateDescription/ChatFormMultipleDateDescription.module.scss';
|
||||||
|
import {Textarea} from '../../../../../../components/Textarea';
|
||||||
|
import {Button, ButtonVariant} from '../../../../../../components/Button';
|
||||||
|
import {ChangeEvent} from 'react';
|
||||||
|
import {UploadButton} from '../../../../../../components/UploadButton';
|
||||||
|
|
||||||
|
export interface ChatFormMultiplePhotoDescriptionProps {
|
||||||
|
className?: string;
|
||||||
|
registration: Partial<UseFormRegisterReturn>;
|
||||||
|
control: Control<FieldValues>;
|
||||||
|
onSubmit: (e: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChatFormMultiplePhotoDescription: ReactFCC<ChatFormMultiplePhotoDescriptionProps> = (props) => {
|
||||||
|
const {className, registration, control, onSubmit} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx(s.ChatFormMultipleDateDescription, className)}>
|
||||||
|
<Controller control={control} render={({ field: { value, onChange }}) => (
|
||||||
|
<>
|
||||||
|
<div className={s.ChatFormMultipleDateDescription__items}>
|
||||||
|
{value.map((item: any, index: number, { length: arrLength }: any) => {
|
||||||
|
return (
|
||||||
|
<div className={s.ChatFormMultipleDateDescription__group} key={index}>
|
||||||
|
{item.file && (
|
||||||
|
<p className={s.ChatFormMultipleDateDescription__itemName}>Загружен файл: {item.file.name}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
rows={1}
|
||||||
|
className={s.ChatFormMultipleDateDescription__textarea}
|
||||||
|
placeholder={'Описание'}
|
||||||
|
value={item.text}
|
||||||
|
onChange={(e) => {
|
||||||
|
const itemIndex = value.indexOf(item);
|
||||||
|
const newItem = { ...item, text: e.target.value };
|
||||||
|
onChange([...value.slice(0, itemIndex), newItem, ...value.slice(itemIndex + 1)]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className={s.ChatFormMultipleDateDescription__buttons}>
|
||||||
|
<Button variant={ButtonVariant.secondary} onClick={() => {
|
||||||
|
const newValue = value.filter((i: any) => i !== item);
|
||||||
|
if (Object.keys(newValue).length !== 0) {
|
||||||
|
onChange([ ...newValue ])
|
||||||
|
}
|
||||||
|
}}>Удалить</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<UploadButton onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = e.target.files?.[0];
|
||||||
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange([...value, { file, text: '' }]);
|
||||||
|
e.target.value = '';
|
||||||
|
}} />
|
||||||
|
|
||||||
|
<SimpleButton className={s.ChatFormMultipleRange__button} onClick={onSubmit} />
|
||||||
|
</>
|
||||||
|
)} name={registration.name!} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './ChatFormMultiplePhotoDescription';
|
|
@ -0,0 +1,40 @@
|
||||||
|
@import 'src/app/styles/vars';
|
||||||
|
|
||||||
|
.ChatFormPhotoDescription {
|
||||||
|
@include flex-col;
|
||||||
|
gap: $spacing-small;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//.ChatFormText__richInput {
|
||||||
|
// @include flex;
|
||||||
|
// position: relative;
|
||||||
|
// width: 100%;
|
||||||
|
// min-height: $chat-input-height;
|
||||||
|
// height: 100%;
|
||||||
|
// align-items: stretch;
|
||||||
|
//
|
||||||
|
// &::before {
|
||||||
|
// content: '';
|
||||||
|
// position: absolute;
|
||||||
|
// width: 100%;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//.ChatFormText__input {
|
||||||
|
// border-radius: $chat-input-radius 0 0 $chat-input-radius !important;
|
||||||
|
// flex: 1;
|
||||||
|
// min-height: 50px !important;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//.ChatFormText__richInputButton {
|
||||||
|
// width: $chat-input-height !important;
|
||||||
|
// height: auto !important;
|
||||||
|
// border-radius: 0 $chat-input-radius $chat-input-radius 0 !important;
|
||||||
|
// padding: 0 !important;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//.ChatFormText__buttonIcon {
|
||||||
|
// width: 24px;
|
||||||
|
// height: 24px;
|
||||||
|
//}
|
|
@ -0,0 +1,52 @@
|
||||||
|
import {ReactFCC} from '../../../../../../utils/ReactFCC';
|
||||||
|
import {Textarea} from '../../../../../../components/Textarea';
|
||||||
|
import {ChangeEvent} from 'react';
|
||||||
|
import s from './ChatFormPhotoDescription.module.scss';
|
||||||
|
import {UploadButton} from '../../../../../../components/UploadButton';
|
||||||
|
import {Control, Controller, FieldValues, UseFormRegisterReturn} from 'react-hook-form';
|
||||||
|
import {SimpleButton} from '../../../SimpleButton';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
export interface ChatFormPhotoDescriptionProps {
|
||||||
|
className?: string;
|
||||||
|
onSubmit: (e: any) => void;
|
||||||
|
registration: Partial<UseFormRegisterReturn>;
|
||||||
|
control: Control<FieldValues>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChatFormPhotoDescription: ReactFCC<ChatFormPhotoDescriptionProps> = (props) => {
|
||||||
|
const {className, onSubmit, registration, control } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx(s.ChatFormPhotoDescription, className)}>
|
||||||
|
<Controller control={control} render={({ field: { value, onChange }}) => (
|
||||||
|
<>
|
||||||
|
{value.file && (
|
||||||
|
<p>Загружен файл: {value.file.name}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<UploadButton onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = e.target.files?.[0];
|
||||||
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange({ ...value, file });
|
||||||
|
e.target.value = '';
|
||||||
|
}} />
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
placeholder={'Текст'}
|
||||||
|
value={value.text}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChange({ ...value, text: e.target.value })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SimpleButton onClick={onSubmit} />
|
||||||
|
</>
|
||||||
|
)} name={registration.name!} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './ChatFormPhotoDescription';
|
|
@ -22,6 +22,12 @@ export const generateAnswerFromData = (question: Question, data: any) => {
|
||||||
};
|
};
|
||||||
case EntityType.multiple_link_description:
|
case EntityType.multiple_link_description:
|
||||||
return data.value;
|
return data.value;
|
||||||
|
case EntityType.photo_description:
|
||||||
|
return JSON.stringify(data.value.text);
|
||||||
|
case EntityType.multiple_photo:
|
||||||
|
return '';
|
||||||
|
case EntityType.multiple_photo_description:
|
||||||
|
return JSON.stringify(data.value.map((i: any) => i.text));
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
20
src/pages/chat/utils/generateFieldsForFileAnswers.ts
Normal file
20
src/pages/chat/utils/generateFieldsForFileAnswers.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import {EntityType, Question} from '../../../api/deck';
|
||||||
|
|
||||||
|
export const generateFieldsForFileAnswers = (question: Question, data: any) => {
|
||||||
|
switch (question.type) {
|
||||||
|
case EntityType.photo_description:
|
||||||
|
return {
|
||||||
|
file: data.value.file
|
||||||
|
}
|
||||||
|
case EntityType.multiple_photo:
|
||||||
|
return data.value;
|
||||||
|
case EntityType.multiple_photo_description:
|
||||||
|
const files: any = {};
|
||||||
|
data.value.forEach((i: any, index: number) => {
|
||||||
|
files[`file_${index + 1}`] = i.file;
|
||||||
|
});
|
||||||
|
return files;
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import {Answer, EntityType} from '../../../api/deck';
|
||||||
import {currencyFormatter, formatDate} from '../../../utils/fomat';
|
import {currencyFormatter, formatDate} from '../../../utils/fomat';
|
||||||
import {slugsForFormat} from '../components/ChatForm/components/ChatFormMultipleRange';
|
import {slugsForFormat} from '../components/ChatForm/components/ChatFormMultipleRange';
|
||||||
|
|
||||||
export const generateTextFromAnswer = (type: EntityType, answer: Answer) => {
|
export const generateTextFromAnswer = (type: EntityType, answer: Answer, files?: { [key: string]: File }) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EntityType.text:
|
case EntityType.text:
|
||||||
return answer.answer;
|
return answer.answer;
|
||||||
|
@ -25,6 +25,17 @@ export const generateTextFromAnswer = (type: EntityType, answer: Answer) => {
|
||||||
currencyFormatter.format(value) : value
|
currencyFormatter.format(value) : value
|
||||||
case EntityType.multiple_link_description:
|
case EntityType.multiple_link_description:
|
||||||
return Object.entries(answer.answer).map(([key, value]) => `${key}: ${value}`).join('\n');
|
return Object.entries(answer.answer).map(([key, value]) => `${key}: ${value}`).join('\n');
|
||||||
|
case EntityType.photo_description:
|
||||||
|
return `${answer.answer}\n${files?.file?.name}`
|
||||||
|
case EntityType.multiple_photo:
|
||||||
|
return Object.values(files || {}).map((file) => `${file.name}`)
|
||||||
|
case EntityType.multiple_photo_description:
|
||||||
|
let result = '';
|
||||||
|
answer.answer.forEach((desc: string, index: number, arr: any) => {
|
||||||
|
result += files?.[`file_${index + 1}`].name + '\n';
|
||||||
|
result += desc + (index !== arr.length - 1 ? '\n\n' : '');
|
||||||
|
});
|
||||||
|
return result;
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user