diff --git a/src/content/applications/Tasks/settings/CreateTask.tsx b/src/content/applications/Tasks/settings/CreateTask.tsx index 1235111..713b95d 100644 --- a/src/content/applications/Tasks/settings/CreateTask.tsx +++ b/src/content/applications/Tasks/settings/CreateTask.tsx @@ -1,39 +1,40 @@ -import { useEffect, useState } from 'react'; +import React, { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; -import { yupResolver } from '@hookform/resolvers/yup'; +import { yupResolver } from "@hookform/resolvers/yup"; import * as yup from "yup"; -import TextField from '@mui/material/TextField'; -import Stack from '@mui/material/Stack'; -import { AlertColor } from '@mui/material/Alert'; -import Button from '@mui/material/Button'; -import { Box, useMediaQuery, useTheme } from '@mui/material'; -import { Dayjs } from 'dayjs'; -import { DatePicker, DatePickerProps } from '@mui/x-date-pickers'; +import TextField from "@mui/material/TextField"; +import Stack from "@mui/material/Stack"; +import { AlertColor } from "@mui/material/Alert"; +import Button from "@mui/material/Button"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; +import { Dayjs } from "dayjs"; +import { DatePicker, DatePickerProps } from "@mui/x-date-pickers"; import { useTaskService } from "src/services/tasks-service"; import { Task } from "src/models/task"; -import SuspenseLoader from 'src/components/SuspenseLoader'; -import CoverCreateTask from '../../../../components/Cover/CoverCreateTask'; -import { useSnackBar } from 'src/contexts/SnackBarContext'; -import { Helmet } from 'react-helmet-async'; -import { BigNumber, ethers } from 'ethers'; +import SuspenseLoader from "src/components/SuspenseLoader"; +import CoverCreateTask from "../../../../components/Cover/CoverCreateTask"; +import { useSnackBar } from "src/contexts/SnackBarContext"; +import { Helmet } from "react-helmet-async"; +import { BigNumber, ethers } from "ethers"; +import dayjs from "dayjs"; +import { DateValidationError } from "@mui/x-date-pickers/models"; let newTask: Task = { status: 0, - title: '', - description: '', + title: "", + description: "", reward: BigNumber.from("0"), - endDate: BigInt(''), - authorizedRoles: [BigInt('')], - creatorRole: BigInt(''), + endDate: BigInt(""), + authorizedRoles: [BigInt("")], + creatorRole: BigInt(""), assignee: "0x0000000000000000000000000000000000000000", - metadata: '' -} - + metadata: "", +}; const CreateTask = ({ data }) => { const theme = useTheme(); - const mdDown = useMediaQuery(theme.breakpoints.down('md')); - const smDown = useMediaQuery(theme.breakpoints.down('sm')); + const mdDown = useMediaQuery(theme.breakpoints.down("md")); + const smDown = useMediaQuery(theme.breakpoints.down("sm")); const { createTask } = useTaskService(); const [task, setTask] = useState(); const [valueReward, setValueReward] = useState(); @@ -42,134 +43,181 @@ const CreateTask = ({ data }) => { const [endDate, setEndDate] = useState(); const [loading, setLoading] = useState(true); const [openError, setOpenError] = useState(false); + const [error, setError] = React.useState(null); const { showSnackBar } = useSnackBar(); const handleSnackbar = (message: string, color: AlertColor) => { - showSnackBar(message, color) + showSnackBar(message, color); }; - const schema = yup.object({ - title: yup.string().required('Mandatory field.'), - creatorRole: yup.string().required('Mandatory field.').test({ - test(value, ctx) { - let role = Number(value); - if (isNaN(role)) - return ctx.createError({ message: 'Invalid number for role.' }) - return true; - } - }), - valueReward: yup.string().required('Mandatory field.').test({ - test(value, ctx) { - let role = Number(value); - if (isNaN(role)) - return ctx.createError({ message: 'Invalid value.' }) - return true; - } - }), - authorizedRoles: yup.string().required('Mandatory field.').test({ - test(value, ctx) { - let validation = true; - let roles = value.split(','); - roles.forEach(element => { - let role = Number(element); - if (isNaN(role)) - validation = false; - }); - if (!validation) - return ctx.createError({ message: 'Invalid role number.' }); - return validation; - } - }), - assignee: yup.string().test({ - test(value, ctx) { - if (value.length != 42 || value.slice(0,2) != "0x") - return ctx.createError({ message: 'Invalid address.' }); - return true; - } - }), - metadata: yup.string().required('Mandatory field.').test({ - test(value, ctx) { - if (value.slice(0,4) == "ipfs" || value.slice(0,4) == "http") + const schema = yup + .object({ + title: yup.string().required("Mandatory field."), + creatorRole: yup + .string() + .required("Mandatory field.") + .test({ + test(value, ctx) { + let role = Number(value); + if (isNaN(role)) + return ctx.createError({ message: "Invalid number for role." }); + return true; + }, + }), + valueReward: yup + .string() + .required("Mandatory field.") + .test({ + test(value, ctx) { + let role = Number(value); + if (isNaN(role)) + return ctx.createError({ message: "Invalid value." }); + return true; + }, + }), + authorizedRoles: yup + .string() + .required("Mandatory field.") + .test({ + test(value, ctx) { + let validation = true; + let roles = value.split(","); + roles.forEach((element) => { + let role = Number(element); + if (isNaN(role)) validation = false; + }); + if (!validation) + return ctx.createError({ message: "Invalid role number." }); + return validation; + }, + }), + assignee: yup.string().test({ + test(value, ctx) { + if (value.length != 42 || value.slice(0, 2) != "0x") + return ctx.createError({ message: "Invalid address." }); return true; - - return ctx.createError({ message: 'Invalid metadata. Try ipfs.io/ipfs/...' }); + }, + }), + metadata: yup + .string() + .required("Mandatory field.") + .test({ + test(value, ctx) { + if (value.slice(0, 4) == "ipfs" || value.slice(0, 4) == "http") + return true; + + return ctx.createError({ + message: "Invalid metadata. Try ipfs.io/ipfs/...", + }); + }, + }), + description: yup + .string() + .required("Mandatory field.") + .test({ + test(value, ctx) { + if (value.length < 100) + return ctx.createError({ + message: "Invalid description. Minimum 100 characters", + }); + return true; + }, + }), + endDate: yup.string().test({ + test(value, ctx) { + let date = Date.parse(endDate); + if (isNaN(date)) return ctx.createError({ message: "Invalid date." }); + return true; + }, + }), + }) + .required(); + + const currentDate = dayjs(); + const errorMessage = React.useMemo(() => { + switch (error) { + case "minDate": { + return "Select a date later than the current date"; } - }), - description: yup.string().required('Mandatory field.').test({ - test(value, ctx) { - if (value.length < 100) - return ctx.createError({ message: 'Invalid description. Minimum 100 characters' }); - return true; + + case "invalidDate": { + return "Your date is not valid"; } - }), - endDate: yup.string().test({ - test(value, ctx) { - let date = Date.parse(endDate); - if (isNaN(date)) - return ctx.createError({ message: 'Invalid date.' }); - return true; + + default: { + return ""; } - }) - }).required(); + } + }, [error]); - - const { register, handleSubmit, formState: { errors } } = useForm({ - resolver: yupResolver(schema) + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), }); - - const logoImage = "/static/images/logo/logo-footer-" + theme.palette.mode + ".svg"; + const logoImage = + "/static/images/logo/logo-footer-" + theme.palette.mode + ".svg"; - const handleChange = (event: { target: { value: any; }; }) => { + const handleChange = (event: { target: { value: any } }) => { task.description = event.target.value; - } + }; - const handleTitle = (event: { target: { value: any; }; }) => { - task.title = (event.target.value).toString(); + const handleTitle = (event: { target: { value: any } }) => { + task.title = event.target.value.toString(); }; const handleAuthorizedRoles = (event: any) => { setAuthorizedRolesStr(event.target.value); }; - const handleCreatorRole = (event: { target: { value: any; }; }) => { + const handleCreatorRole = (event: { target: { value: any } }) => { task.creatorRole = event.target.value; }; - const handleAssignee = (event: { target: { value: any; }; }) => { - task.assignee = event.target.value == '' ? "0x0000000000000000000000000000000000000000" : event.target.value; + const handleAssignee = (event: { target: { value: any } }) => { + task.assignee = + event.target.value == "" + ? "0x0000000000000000000000000000000000000000" + : event.target.value; }; - const handleMetadata = (event: { target: { value: any; }; }) => { + const handleMetadata = (event: { target: { value: any } }) => { task.metadata = event.target.value; }; - const handleDescription = (event: { target: { value: any; }; }) => { + const handleDescription = (event: { target: { value: any } }) => { task.description = event.target.value; }; - const handleReward = (event: { target: { value: any; }; }) => { + const handleReward = (event: { target: { value: any } }) => { let reward = event.target.value; setValueReward(reward); }; - const handleExpireDate = ( value: Dayjs ) => { - setExpireDate(value) - let strEndDate = value.toString(); + const handleExpireDate = (value: Dayjs) => { + setExpireDate(value); + let strEndDate = value ? value.toString() : null; setEndDate(strEndDate); }; - const onSubmit = async (event: { preventDefault: () => void; }) => { + const onSubmit = async (event: { preventDefault: () => void }) => { try { - handleSnackbar('Create Task Start process initiated with success!', 'info') - let authorizedRoles: string[] = (authorizedRolesStr).split(','); - const splittedRoles: readonly bigint[] = authorizedRoles.map(str => BigInt(str)); + handleSnackbar( + "Create Task Start process initiated with success!", + "info" + ); + let authorizedRoles: string[] = authorizedRolesStr.split(","); + const splittedRoles: readonly bigint[] = authorizedRoles.map((str) => + BigInt(str) + ); task.authorizedRoles = splittedRoles; task.reward = ethers.utils.parseEther(valueReward); let expireTimestamp = expireDate.unix(); task.endDate = BigInt(expireTimestamp); await createTask(task); - } catch (error) { console.log("Error when submitting the createTask form: ", error); setOpenError(true); @@ -180,10 +228,9 @@ const CreateTask = ({ data }) => { if (loading && data != undefined) { setTask(data); setLoading(false); - } - else { + } else { if (loading) { - setTask(newTask) + setTask(newTask); setLoading(false); } } @@ -194,117 +241,163 @@ const CreateTask = ({ data }) => { Web3Task - Create Task - - + + - - + display={"flex"} + justifyContent={"center"} + alignItems={"center"} + height={"100%"} + flexDirection={"column"} + > + - { - loading ? : ( - - - -

{errors.title?.message}

- - -

{errors.authorizedRoles?.message}

+ {loading ? ( + + ) : ( + + + - -

{errors.creatorRole?.message}

+ - -

{errors.assignee?.message}

+ - -

{errors.metadata?.message}

+ - -

{errors.description?.message}

+ - - - Pod3LabsRecompensaIcon - -
- -

{errors.valueReward?.message}

-
-
- handleExpireDate(newValue)} - slotProps={{ - textField: { size: 'medium' }, - openPickerIcon: { style: { color: theme.palette.primary.main } }, - switchViewButton: { style: { color: 'info' } } - }} - /> -

-
-
- - + + + + Pod3LabsRecompensaIcon + +
+ +
+
+ setError(newError)} + onChange={(newValue: Dayjs) => + handleExpireDate(newValue) + } + slotProps={{ + textField: { + size: "medium", + helperText: errorMessage, + }, + openPickerIcon: { + style: { color: theme.palette.primary.main }, + }, + switchViewButton: { style: { color: "info" } }, + }} + /> +

+ {errors.endDate?.message} +

+
-
- ) - } + + +
+
+ )}
-
+
); -} +}; -export default CreateTask +export default CreateTask;