diff --git a/web/package-lock.json b/web/package-lock.json index 8d194350e6765bdc34341ef8a3abe07c7899b848..dd8e9e47bb7a6a9d80a02df029dbc72644a66fd1 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -20,10 +20,12 @@ "axios": "^1.6.8", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-dropzone": "^14.2.3", "react-hook-form": "^7.51.2", "react-pro-sidebar": "^1.1.0", "react-router-dom": "^6.22.3", "react-scripts": "5.0.1", + "react-toastify": "^10.0.5", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, @@ -5394,6 +5396,14 @@ "node": ">= 4.0.0" } }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "engines": { + "node": ">=4" + } + }, "node_modules/autoprefixer": { "version": "10.4.18", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", @@ -6209,6 +6219,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -8439,6 +8457,17 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -15080,6 +15109,22 @@ "react": "^18.2.0" } }, + "node_modules/react-dropzone": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz", + "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.6.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", @@ -15230,6 +15275,18 @@ } } }, + "node_modules/react-toastify": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", + "integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/web/package.json b/web/package.json index f36efbd589ff32f2155b6d383a848966e61fb095..3ac96a940a595f0fd22374d9975027b12a631ed6 100644 --- a/web/package.json +++ b/web/package.json @@ -15,10 +15,12 @@ "axios": "^1.6.8", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-dropzone": "^14.2.3", "react-hook-form": "^7.51.2", "react-pro-sidebar": "^1.1.0", "react-router-dom": "^6.22.3", "react-scripts": "5.0.1", + "react-toastify": "^10.0.5", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, diff --git a/web/src/components/admin_panel_navbar/admin_navbar.tsx b/web/src/components/admin_panel_navbar/admin_navbar.tsx index 424bd0633d14451ce363068a75b14018fdda6fbf..6a65a776c3c60b79d224a95655c0e873160c506d 100644 --- a/web/src/components/admin_panel_navbar/admin_navbar.tsx +++ b/web/src/components/admin_panel_navbar/admin_navbar.tsx @@ -5,7 +5,11 @@ import { useAuth } from "../../context/auth_context"; import { Link } from "react-router-dom"; import './assets/styles/style.css'; -export const AdminPanelNavBar = () => { +interface props{ + windowActive: boolean; +} + +export const AdminPanelNavBar = ({windowActive}:props) => { const {user, logout} = useAuth(); const [toggle, setToggle] = useState(false); @@ -17,7 +21,21 @@ export const AdminPanelNavBar = () => {
setToggle(!toggle)}/> + onClick={() => { + windowActive + ? + setToggle(false) + : + setToggle(!toggle) + }} + style={ + windowActive + ? + {cursor: "auto"} + : + {cursor: "pointer"} + } + /> {toggle &&
diff --git a/web/src/components/admin_panel_navbar/assets/styles/style.css b/web/src/components/admin_panel_navbar/assets/styles/style.css index 0762a6709c9e7e0d467a5cf68bd373d6b71dfb5c..7e82ea4711c167bc0a8caa4c0bc7ef3f948e2a04 100644 --- a/web/src/components/admin_panel_navbar/assets/styles/style.css +++ b/web/src/components/admin_panel_navbar/assets/styles/style.css @@ -15,12 +15,12 @@ .profile{ position: absolute; right: 20px; + user-select: none; } .user-pic{ width: 30px; border-radius: 50%; - cursor: pointer; background: white; } @@ -30,6 +30,7 @@ right: 10%; max-width: 400px; overflow: hidden; + z-index: 1000; transition: max-height 0.5s; } diff --git a/web/src/components/image_dropzone/assets/css/styles.css b/web/src/components/image_dropzone/assets/css/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..e5e00a1a63f78f37498b76c2dc5cd5afa7956c78 --- /dev/null +++ b/web/src/components/image_dropzone/assets/css/styles.css @@ -0,0 +1,27 @@ +.image_dropzone_container { + width: 90%; +} + +.image_dropzone { + cursor: pointer; + border-color: #eeeeee; + border-style: dashed; + background-color: #fafafa; + outline: none; + color: #bdbdbd; + aspect-ratio: 1/1; + display: flex; + justify-content: center; + align-items: center; +} + +.image_dropzone:hover { + border-color: rgb(106, 188, 226); + color: rgb(43, 38, 38); +} + +.image_dropzone img { + height: 100%; + width: 100%; + object-fit: contain; +} \ No newline at end of file diff --git a/web/src/components/image_dropzone/image_dropzone.tsx b/web/src/components/image_dropzone/image_dropzone.tsx new file mode 100644 index 0000000000000000000000000000000000000000..add3c59c09ccc42081bc1dc4eee2d42ea9d9f212 --- /dev/null +++ b/web/src/components/image_dropzone/image_dropzone.tsx @@ -0,0 +1,73 @@ +import { ToastContainer, toast } from 'react-toastify'; +import './assets/css/styles.css' +import { useDropzone } from "react-dropzone"; +import { useState } from 'react'; +import "react-toastify/dist/ReactToastify.css"; +import { UseFormSetValue } from 'react-hook-form'; +import { TownFormValues } from '../../infraestructure/entities/town_form_values'; + +interface props { + setValue : UseFormSetValue +} + +export const ImageDropzone = ({setValue}: props) => { + const MAX_SIZE = 10485760; + const [preview, setPreview] = useState(null); + const {fileRejections,getRootProps, getInputProps} = useDropzone( + { + multiple: false, + maxSize: MAX_SIZE, + accept: { + 'image/jpeg': [], + 'image/png': [] + }, + onDrop(acceptedFiles, fileRejections) { + const file = new FileReader; + + fileRejections.map(({file, errors}) => ( + toast.error(errors[0].message, { + position: "bottom-right", + autoClose: 1500, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: false, + draggable: true, + progress: undefined, + theme: "colored" + }))); + + acceptedFiles.map((file)=>{ + {setValue('imageURL',file)} + }); + + file.onload = () => { + setPreview(file.result); + }; + + file.readAsDataURL(acceptedFiles[0]); + } + } + ); + + return ( +
+
+ + {preview ? ( + + ) : ( +

Arrastra tu imagen o seleccionala dando click aquí.

+ )} +
+ +
+ + ); +} \ No newline at end of file diff --git a/web/src/components/sa_panel_town/sa_panel_town_register/css/styles.css b/web/src/components/sa_panel_town/sa_panel_town_register/css/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..2445be2fb3d51e905731dcbe9f677e562c51e221 --- /dev/null +++ b/web/src/components/sa_panel_town/sa_panel_town_register/css/styles.css @@ -0,0 +1,155 @@ +*{ + user-select: none; +} + +.town_register_wrap { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + width: 70vw; + height: 90vh; + background: green; + display: flex; + flex-direction: column; +} + +.town_register_header { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + padding: 5px; +} + +.town_register_close_btn{ + display: inline-block; + cursor: pointer; + position: absolute; + right: 5px; +} + +.town_register_content { + background: white; + width: 100%; + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.town_register_content form{ + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.town_description_image_cont { + width: 100%; + background: lightgray; + flex-grow: 1; + display: flex; + flex-direction: row; +} + +.town_desc{ + height: 100%; + width: 55%; + display: flex; + flex-direction: column; + padding: 20px; +} + +.image_container { + height: 100%; + width: 45%; + background: white; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.image_container div { + justify-content: center; + align-items: center; +} + +.town_desc div{ + display: flex; + align-items: center; + justify-content: center; +} + +.towm_desc_input_cnt{ + height: 100%; + width: 100%; + flex-grow: 1; +} + +.towm_desc_input_cnt textarea{ + width: 100%;; + height: 100%; + padding: 5px; + overflow-y: auto; + resize: none; +} + +.state_select{ + display: flex; + flex-direction: column; + width: 40%; + justify-content: center; + align-items: center; +} + +.state_select label { + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto; +} + +.state_select select{ + width: 60%; +} + +.town_name_state_input { + display: flex; + flex-direction: row; + margin-top: 5px; + margin-bottom: 5px; +} + +.town_name_input{ + width: 40%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.town_name_input input{ + width: 70%; + border-radius: 3px; +} + +.town_name_input .form_input::focus { + border-width: 1px; +} + +.language_change_cnt{ + width: 20%; +} + +.change_lang_btn{ + cursor: pointer; +} + +.language_change_cnt { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx b/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9f796dd5564228db3e8222e7b6ebcaa0fa12968a --- /dev/null +++ b/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx @@ -0,0 +1,111 @@ +import { faWindowClose, faLanguage } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import './css/styles.css' +import { ImageDropzone } from "../../image_dropzone/image_dropzone"; +import { Dispatch, SetStateAction, useState } from "react"; +import { useTownRegister } from "../../../hooks/useTownRegister"; + +interface props { + setWindowActive: Dispatch>, + setShowRegisterPanel: Dispatch> +} + +export const SuperadminPanelTownRegister = ({setWindowActive, setShowRegisterPanel}:props) => { + const { + statesList, + register, + setValue, + handleSubmit, + errors, + onSubmit + } = useTownRegister(); + const [isEnglish, setIsEnglish] = useState(false); + const [spanishDescription, setSpanishDescription] = useState(""); + const [englishDescription, setEnglishDescription] = useState(""); + + return ( +
+
+ Registra el pueblo mágico + {setShowRegisterPanel(false); setWindowActive(false)}}/> +
+
+
+
+
+ + + setIsEnglish(!isEnglish) + } + /> +
+
+ + +
+
+ + {statesList == null ? + + : + + } +
+
+
+
+
Descripción del pueblo mágico
+
+ { + isEnglish ? +