diff --git a/package.json b/package.json index 235f76f..c689b37 100644 --- a/package.json +++ b/package.json @@ -15,17 +15,21 @@ "test:coverage": "vitest run --coverage" }, "dependencies": { + "@hookform/resolvers": "^5.2.1", "@reduxjs/toolkit": "^2.9.0", "@remix-run/node-fetch-server": "^0.8.0", "compression": "^1.8.1", "cross-env": "^10.0.0", "express": "^5.1.0", "normalize.css": "^8.0.1", + "react-intl": "^7.1.11", + "firebase": "^12.2.1", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-intl": "^7.1.11", + "react-hook-form": "^7.62.0", "react-redux": "^9.2.0", - "react-router": "7.7.0" + "react-router": "7.7.0", + "yup": "^1.7.0" }, "devDependencies": { "@eslint/js": "^9.33.0", diff --git a/src/Types/Types.ts b/src/Types/Types.ts index 2444689..58c9220 100644 --- a/src/Types/Types.ts +++ b/src/Types/Types.ts @@ -1 +1,8 @@ export type Lang = 'en' | 'ru'; + +export interface FormDataItem { + key: string; + value: string; +} + +export type BodyValue = null | string | FormData; diff --git a/src/components/BodyEditor/BodyEditor.tsx b/src/components/BodyEditor/BodyEditor.tsx new file mode 100644 index 0000000..5021822 --- /dev/null +++ b/src/components/BodyEditor/BodyEditor.tsx @@ -0,0 +1,113 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useIntl } from 'react-intl'; +import FormDataEditor from '../FormDataEditor/FormDataEditor'; +import type { BodyValue, FormDataItem } from '../../Types/Types'; + +type BodyType = 'none' | 'raw' | 'form-data'; + +interface BodyEditorProps { + value: BodyValue; + onChange: (val: BodyValue) => void; + readOnly?: boolean; +} + +export default function BodyEditor({ + value, + onChange, + readOnly = false, +}: BodyEditorProps) { + const [error, setError] = useState(null); + const [bodyType, setBodyType] = useState('none'); + const [rawValue, setRawValue] = useState(''); + const [formDataValue, setFormDataValue] = useState([]); + + const intl = useIntl(); + + useEffect(() => { + if (typeof value === 'string') { + setBodyType('raw'); + setRawValue(value); + } else if (value instanceof FormData) { + setBodyType('form-data'); + + const arr: FormDataItem[] = []; + value.forEach((val, key) => arr.push({ key, value: String(val) })); + setFormDataValue(arr); + } else { + setBodyType('none'); + } + }, [value]); + + useEffect(() => { + if (bodyType === 'raw') { + try { + const parsedBody = JSON.parse(rawValue); + setRawValue(JSON.stringify(parsedBody, null, 2)); + setError(null); + onChange(rawValue); + } catch { + setError('Invalid JSON'); + } + } + }, [rawValue, bodyType, onChange]); + + useEffect(() => { + if (bodyType === 'form-data') { + const fd = new FormData(); + formDataValue.forEach((item) => { + if (item.key) fd.append(item.key, item.value); + }); + onChange(fd); + } + }, [formDataValue, bodyType, onChange]); + + return ( +
+ + + {bodyType === 'raw' && ( +