This commit is contained in:
mark H 2024-09-03 14:35:31 +08:00
parent a5bf267763
commit b246410e11
2 changed files with 241 additions and 3 deletions

View File

@ -1,5 +1,7 @@
import React, { useEffect, useState } from "react";
import KeyValuePair from "./KeyValuePair";
import KeyValuePair2 from "./KeyValuePair2";
import JsonEditor from "./Editors";
import { FaPaperPlane } from "react-icons/fa6";
import { IoMdDownload } from "react-icons/io";
@ -19,6 +21,7 @@ const Form: React.FC<FormProps> = ({ onSubmit, content, setisRefresh }) => {
const [headers, setHeaders] = useState(
content?.header ?? [{ key: "", value: "" }]
);
const [formData, setformData] = useState(content?.form_data ?? [{ key: "", value: "" }]);
const [jsonBody, setJsonBody] = useState(content ?? {});
const [activeTab, setActiveTab] = useState("query-params");
@ -39,9 +42,35 @@ const Form: React.FC<FormProps> = ({ onSubmit, content, setisRefresh }) => {
setHeaders([...headers, { key: "", value: "" }]);
setisSaved(false);
};
const handleAddFormData = () => {
setformData([...formData, { key: "", value: "" }]);
setisSaved(false);
};
// const handleSubmit = (e: React.FormEvent) => {
// e.preventDefault();
// const params = queryParams.reduce((acc, { key, value }) => {
// if (key) acc[key] = value;
// return acc;
// }, {} as Record<string, string>);
// const headerObj = headers.reduce((acc, { key, value }) => {
// if (key) acc[key] = value;
// return acc;
// }, {} as Record<string, string>);
// onSubmit({
// method,
// url,
// params,
// headers: headerObj,
// data: jsonBody,
// });
// };
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Reduce query parameters and headers to objects
const params = queryParams.reduce((acc, { key, value }) => {
if (key) acc[key] = value;
return acc;
@ -52,15 +81,34 @@ const Form: React.FC<FormProps> = ({ onSubmit, content, setisRefresh }) => {
return acc;
}, {} as Record<string, string>);
// If formData is not empty, convert it to FormData
let data: Record<string, any> | FormData;
if (formData.length > 0) {
data = new FormData();
formData.forEach(({ key, value }) => {
if (key) {
if (value instanceof File) {
data.append(key, value); // Append file
} else {
data.append(key, value); // Append text
}
}
});
} else {
data = jsonBody; // If formData is empty, use jsonBody
}
// Call onSubmit with the appropriate data
onSubmit({
method,
url,
params,
headers: headerObj,
data: jsonBody,
data,
});
};
const handleRequestEditorChange = (value: string) => {
setJsonBody(value);
setisSaved(false);
@ -188,6 +236,19 @@ const Form: React.FC<FormProps> = ({ onSubmit, content, setisRefresh }) => {
JSON
</button>
</li>
<li className="nav-item p-2" role="presentation">
<button
className={`nav-link ${
activeTab === "form"
? "text-[black] border-solid border-[black]"
: "text-[grey]"
}`}
id="form-tab"
onClick={() => setActiveTab("form")}
>
Form
</button>
</li>
</ul>
<div className="tab-content p-3 border-top-0 border">
@ -256,6 +317,32 @@ const Form: React.FC<FormProps> = ({ onSubmit, content, setisRefresh }) => {
/>
</div>
)}
{activeTab === "form" && (
<div
className="tab-pane fade show active h-auto overflow-hidden"
id="json"
role="tabpanel"
aria-labelledby="json-tab"
>
{formData.map((header, index) => (
<KeyValuePair2
key={index}
index={index}
pair={header}
setPairs={setformData}
pairs={formData}
setisSaved={setisSaved}
/>
))}
<button
type="button"
onClick={handleAddFormData}
className="mt-2 btn btn-outline-success border-solid border-[green] text-[green]"
>
Add Form
</button>
</div>
)}
</div>
</div>
</form>

View File

@ -0,0 +1,151 @@
import React, { useState } from "react";
import { FaCloudUploadAlt } from "react-icons/fa";
import { FaArrowDown, FaXmark } from "react-icons/fa6";
interface KeyValuePairProps {
index: number;
pair: { key: string; value: string | File[]; type: "text" | "[]" };
setPairs: React.Dispatch<
React.SetStateAction<
{ key: string; value: string | File[]; type: "text" | "file" }[]
>
>;
pairs: { key: string; value: string | File[]; type: "text" | "file" }[];
setisSaved: React.Dispatch<React.SetStateAction<boolean>>;
}
const KeyValuePair: React.FC<KeyValuePairProps> = ({
index,
pair,
setPairs,
pairs,
setisSaved,
}) => {
const [type, settype] = useState("text");
const handleKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newPairs = [...pairs];
newPairs[index] = { ...newPairs[index], key: e.target.value };
setPairs(newPairs);
setisSaved(false);
};
const handleValueChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newPairs = [...pairs];
if (type === "text") {
newPairs[index] = { ...newPairs[index], value: e.target.value };
} else if (type === "file" && e.target.files) {
const files = Array.from(e.target.files); // Support multiple files
newPairs[index] = { ...newPairs[index], value: files };
}
setPairs(newPairs);
setisSaved(false);
};
const handleTypeChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const newPairs = [...pairs];
settype(e.target.value);
newPairs[index] = {
...newPairs[index],
type: e.target.value,
value: "",
};
setPairs(newPairs);
setisSaved(false);
};
const handleRemoveFile = (fileToRemove: File) => {
const newPairs = [...pairs];
const updatedFiles = (newPairs[index].value as File[]).filter(
(file) => file !== fileToRemove
);
newPairs[index] = { ...newPairs[index], value: updatedFiles };
setPairs(newPairs);
setisSaved(false);
};
const handleRemove = () => {
const newPairs = pairs.filter((_, i) => i !== index);
setPairs(newPairs);
setisSaved(false);
};
const handleFileClick = () => {
const fileInput = document.getElementById(`file-input-${index}`);
if (fileInput) {
fileInput.click();
}
};
return (
<div className="flex items-center mb-2 w-full justify-between">
<input
type="text"
className="form-input flex-grow mr-2 max-w-[200px]"
placeholder="Key"
value={pair.key}
onChange={handleKeyChange}
/>
<select
className="form-select flex w-[100px] mr-2"
value={pair.type}
onChange={handleTypeChange}
>
<option value="text">Text</option>
<option value="file">File</option>
</select>
{type === "text" ? (
<input
type="text"
className="form-input flex-grow mr-2"
placeholder="Value"
value={pair.value as string}
onChange={handleValueChange}
/>
) : (
<div className="flex items-center min-w-[150px]">
<input
type="file"
id={`file-input-${index}`}
className="hidden"
onChange={handleValueChange}
multiple={true} // Updated to boolean for JSX
/>
<label htmlFor={`file-input-${index}`}>
<button
onClick={handleFileClick}
type="button"
className="btn p-2 flex items-center"
>
<FaCloudUploadAlt />
</button>
</label>
{Array.isArray(pair.value) && pair.value.length > 0 && (
<div className="flex flex-wrap ml-2">
{pair.value.map((file, idx) => (
<div key={idx} className="flex items-center mb-1 border-[#eee] border px-1 rounded-md ">
<span className="mr-2 text-[13px]">{file.name}</span>
<button
type="button"
className="btn btn-outline-danger text-red-400 border-none shadow-none p-1 "
onClick={() => handleRemoveFile(file)}
>
<FaXmark/>
</button>
</div>
))}
</div>
)}
</div>
)}
<button
type="button"
className="btn btn-outline-danger text-red-400 border-red-400 p-1 px-3 ml-2"
onClick={handleRemove}
>
Remove
</button>
</div>
);
};
export default KeyValuePair;