diff --git a/src/components/Pastes/CodeEditor.jsx b/src/components/Pastes/CodeEditor.jsx
index 9d9b846..ab5c8e6 100644
--- a/src/components/Pastes/CodeEditor.jsx
+++ b/src/components/Pastes/CodeEditor.jsx
@@ -1,16 +1,29 @@
import Editor from "@monaco-editor/react";
import { useTheme } from "@/hooks/useTheme";
-import { useRef } from "react";
+import { useEffect, useRef } from "react";
import PropTypes from "prop-types";
+import * as monaco from "monaco-editor";
-const CodeEditor = ({ className = "", syntax, readOnly, onChange, value }) => {
+const CodeEditor = ({ className = "", syntax, readOnly, onChange, value, editorErrors = [] }) => {
const { theme } = useTheme();
const editorRef = useRef(null);
- const onMount = (editor) => {
- editorRef.current = editor;
- editor.focus();
- }
+ useEffect(() => {
+ if (!editorRef.current) return;
+ const model = editorRef.current.getModel();
+ if (!model) return;
+
+ monaco.editor.setModelMarkers(model, "owner", editorErrors.map(err => ({
+ startLineNumber: err.lineNumber,
+ startColumn: 1,
+ endLineNumber: err.lineNumber,
+ endColumn: model.getLineLength(err.lineNumber) + 1,
+ message: err.message,
+ severity: monaco.MarkerSeverity.Error
+ })));
+ }, [editorErrors]);
+
+ const onMount = (editor) => { editorRef.current = editor; editor.focus(); }
return (
@@ -18,7 +31,7 @@ const CodeEditor = ({ className = "", syntax, readOnly, onChange, value }) => {
language={syntax || "plaintext"}
value={value || ""}
theme={theme === "dark" ? "vs-dark" : "vs-light"}
- onChange={(value) => onChange?.(value)}
+ onChange={onChange}
onMount={onMount}
options={{
minimap: { enabled: false },
@@ -30,10 +43,6 @@ const CodeEditor = ({ className = "", syntax, readOnly, onChange, value }) => {
scrollbar: { verticalScrollbarSize: 0 },
wordWrap: "on",
formatOnPaste: true,
- suggest: {
- showFields: true,
- showFunctions: true,
- },
readOnly: readOnly || false,
}}
/>
@@ -47,6 +56,7 @@ CodeEditor.propTypes = {
readOnly: PropTypes.bool,
onChange: PropTypes.func,
value: PropTypes.string,
+ editorErrors: PropTypes.array,
};
-export default CodeEditor;
+export default CodeEditor;
\ No newline at end of file
diff --git a/src/components/Pastes/PastePanel.jsx b/src/components/Pastes/PastePanel.jsx
index e6590c4..e9cfad8 100644
--- a/src/components/Pastes/PastePanel.jsx
+++ b/src/components/Pastes/PastePanel.jsx
@@ -14,78 +14,76 @@ const PastePanel = ({ onSubmit, publicPastes }) => {
const { pasteKey } = useParams();
const navigate = useNavigate();
const { getData } = useDataContext();
- const [title, setTitle] = useState("");
- const [content, setContent] = useState("");
- const [syntax, setSyntax] = useState("");
- const [burnAfter, setBurnAfter] = useState(false);
- const [isPrivate, setIsPrivate] = useState(false);
- const [password, setPassword] = useState("");
+
+ const [formData, setFormData] = useState({
+ title: "",
+ content: "",
+ syntax: "",
+ burnAfter: false,
+ isPrivate: false,
+ password: ""
+ });
+
const [selectedPaste, setSelectedPaste] = useState(null);
- const [error, setError] = useState(null);
+ const [editorErrors, setEditorErrors] = useState([]);
+ const [fieldErrors, setFieldErrors] = useState({});
const [showPasswordModal, setShowPasswordModal] = useState(false);
- const handleSubmit = (e) => {
+ const handleSubmit = async (e) => {
e.preventDefault();
- const paste = {
- title,
- content,
- syntax,
- burnAfter: burnAfter,
- isPrivate: isPrivate,
- password: password || null,
- };
- if (onSubmit) onSubmit(paste);
- };
+ setFieldErrors({});
+ setEditorErrors([]);
- const handleSelectPaste = async (key) => {
- navigate(`/${key}`);
- };
-
- const fetchPaste = async (key, pwd = "") => {
- const url = import.meta.env.MODE === 'production' ?
- `https://api.miarma.net/v2/mpaste/pastes/${key}` :
- `http://localhost:8081/v2/mpaste/pastes/${key}`;
-
- const { data, error } = await getData(url, {}, false, {
- 'X-Paste-Password': pwd
- });
-
- if (error) {
- if (error?.status === 401) {
- setShowPasswordModal(true);
- return;
+ try {
+ if (onSubmit) await onSubmit(formData);
+ } catch (error) {
+ if (error.status === 422 && error.errors) {
+ const newFieldErrors = {};
+ Object.entries(error.errors).forEach(([field, msg]) => {
+ if (field === "content") {
+ setEditorErrors([{ lineNumber: 1, message: msg }]);
+ } else {
+ newFieldErrors[field] = msg;
+ }
+ });
+ setFieldErrors(newFieldErrors);
} else {
- setError(error);
- setSelectedPaste(null);
- return;
+ showError(error);
}
}
-
- setError(null);
- setSelectedPaste(data);
- setTitle(data.title);
- setContent(data.content);
- setSyntax(data.syntax || "plaintext");
};
- useEffect(() => {
- if (pasteKey) fetchPaste(pasteKey);
- }, [pasteKey]);
+ const handleSelectPaste = async (key) => navigate(`/${key}`);
+
+ const fetchPaste = async (key, pwd = "") => {
+ const url = import.meta.env.MODE === 'production'
+ ? `https://api.miarma.net/v2/mpaste/pastes/${key}`
+ : `http://localhost:8081/v2/mpaste/pastes/${key}`;
+
+ const data = await getData(url, { password: pwd }, false);
+
+ if (!data) return;
+
+ setSelectedPaste(data);
+ setFormData({
+ title: data.title ?? "",
+ content: data.content ?? "",
+ syntax: data.syntax || "plaintext",
+ burnAfter: data.burnAfter || false,
+ isPrivate: data.isPrivate || false,
+ password: ""
+ });
+ };
+
+ useEffect(() => { if (pasteKey) fetchPaste(pasteKey); }, [pasteKey]);
+
+ const handleChange = (key, value) => {
+ setFormData(prev => ({ ...prev, [key]: value }));
+ };
return (
<>
- {error &&
-
setError(null)} dismissible>
-
- {
- error.status == 404 ? "404: Paste no encontrada." :
- "Ha ocurrido un error al cargar la paste."
- }
-
-
- }
-