I put a submit test button but its not getting any data.
OBS about the code:
I'm using react select
I'm using filepond to upload images and files (its working fine)
ProductsModal is a modal component with rightColumn and leftColumn (left column is the form and right column there is a phone image with dynamic content inside which is a preview of the form.
My onSubmit function is a console.log with data from the form, but all I get is a empty object.
I have the following code
import React, { useState } from 'react'
import useForm from 'react-hook-form'
import Select from 'react-select'
import { FaRegFileAlt, FaRegImage } from 'react-icons/fa'
import { FilePond, registerPlugin } from 'react-filepond'
import { IoIosImages } from 'react-icons/io'
import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orientation'
import FilePondPluginImagePreview from 'filepond-plugin-image-preview'
import TextField from '#material-ui/core/TextField'
import Button from '~/components/Button'
import ProductsModal from '~/components/Sponsor/Modals/ProductsModal'
import IconsProductImage from '~/components/Sponsor/IconsProductImage'
import Border from '~/components/Border'
import ProductBadge from '~/components/ProductBadge'
import * as S from './styled'
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview)
export default function ModalAnnouncement({ handleCloseModal, showModal }) {
const [title, setTitle] = useState('')
const [tags, setTags] = useState([])
const [about, setAbout] = useState('')
const [files, setFiles] = useState('')
const [filePreview, setFilePreview] = useState('')
const [images, setImages] = useState('')
const [updatingFile, setUpdatingFile] = useState(false)
const [updatingImage, setUpdatingImage] = useState(false)
const { handleSubmit, setValue } = useForm()
function onSubmit(data) {
console.log('data', data)
}
function handleUpdatingFile() {
setUpdatingFile(!updatingFile)
}
function handleUpdatingImage() {
setUpdatingImage(!updatingImage)
}
function handleUpdateImages(event) {
setImages(event)
setFilePreview(event.length === 0 ? '' : URL.createObjectURL(event[0].file))
}
function handleTagsChange(tags) {
setValue('tags', tags)
setTags(tags)
}
const tagsAvailable = [
{ value: 1, label: 'artificial intelligence' },
{ value: 2, label: 'digital marketing' },
{ value: 3, label: 'big data' },
{ value: 4, label: 'blogging' },
{ value: 5, label: 'chatbot' },
{ value: 6, label: 'content marketing' },
{ value: 7, label: 'digital loyalty' },
{ value: 8, label: 'digital transformation' },
{ value: 9, label: 'email marketing' },
{ value: 10, label: 'engagement' },
]
const reactSelectStyleCustom = {
control: (base, state) => ({
...base,
boxShadow: state.isFocused ? 0 : 0,
borderColor: state.isFocused ? '#50A5D2' : base.borderColor,
borderWidth: state.isFocused ? '1px' : '1px',
'&:hover': {
borderColor: state.isFocused ? '#50A5D2' : base.borderColor,
},
}),
placeholder: defaultStyles => {
return {
...defaultStyles,
color: '#A1A1A1',
fontSize: '16px',
}
},
singleValue: provided => {
const overflow = 'visible'
const fontStyle = 'normal'
const transition = 'opacity 300ms'
return { ...provided, overflow, fontStyle, transition }
},
}
return (
<ProductsModal
modalTitle="New Announcement"
handleCloseModal={handleCloseModal}
showModal={showModal}
leftColumn={
<form onSubmit={handleSubmit(onSubmit)}>
<S.FormContainer>
<S.InputTitle>Title</S.InputTitle>
<TextField
fullWidth={true}
variant="outlined"
name="title"
placeholder="Give your announcement a title"
type="text"
value={title}
onChange={e => setTitle(e.target.value)}
/>
<div className="mt-3">
<S.InputTitle>About</S.InputTitle>
<TextField
fullWidth={true}
variant="outlined"
name="about"
multiline
rows="4"
placeholder="Tell them a little more about your announcement"
type="text"
value={about}
onChange={e => setAbout(e.target.value)}
/>
</div>
<div className="mt-3">
<S.InputTitle>Tags</S.InputTitle>
<Select
styles={reactSelectStyleCustom}
isMulti
options={tagsAvailable}
placeholder="Add tags to your announcement"
value={tags}
onChange={handleTagsChange}
/>
</div>
<div className="mt-4 mb-2">
<Border />
</div>
{updatingFile ? (
<div className="mt-2">
<div className="d-flex justify-content-center align-items-center">
<FaRegFileAlt className="mr-2" size={14} />{' '}
<S.InputTitle>Files</S.InputTitle>
</div>
<FilePond
allowMultiple={false}
files={files}
onupdatefiles={setFiles}
/>
</div>
) : (
<div className="d-flex justify-content-center">
<Button
text="Add file"
type="button"
color="#5A6978"
action={handleUpdatingFile}
width="160px"
height="40px"
/>
</div>
)}
{updatingImage ? (
<div className="mt-3">
<div className="d-flex justify-content-center align-items-center">
<FaRegImage className="mr-2" size={14} />{' '}
<S.InputTitle>Images</S.InputTitle>
</div>
<FilePond
allowMultiple={false}
files={images}
onupdatefiles={handleUpdateImages}
/>
</div>
) : (
<div className="d-flex justify-content-center">
<Button
text="Add image"
type="button"
color="#5A6978"
action={handleUpdatingImage}
width="160px"
height="40px"
/>
</div>
)}
<div className="d-flex justify-content-center">
<Button
text="Submit Form"
type="submit"
color="#5A6978"
action={(event) => { event.persist(); handleSubmit(event) }}
width="160px"
height="40px"
/>
</div>
</S.FormContainer>
</form>
}
rightColumn={
<>
<S.Phone>
<S.Screen>
<S.Content>
<div className="image-container">
{filePreview !== '' ? (
<>
<img className="animated fadeIn" src={filePreview} />
<IconsProductImage right="0" top="30%" />
<div className="ml-2 mt-3">
<S.ProductTitle>{title}</S.ProductTitle>
</div>
<div
style={{ marginTop: '-10px' }}
className="d-flex ml-2"
>
<ProductBadge
text="annoucement"
color="#D40707"
textColor="#FFF"
width="135px"
height="30px"
eventText="- engagement"
eventTextColor="#87919A"
/>
</div>
</>
) : (
<>
<img
style={{
postison: 'relative',
backgroundColor: '#CCC',
}}
className="d-flex justify-content-center align-items"
/>
<IoIosImages
style={{
position: 'absolute',
top: '125px',
right: '125px',
}}
color="red"
size={28}
/>
<div className="ml-2 mt-3">
<S.ProductTitle>
{title === '' ? (
'Title'
) : (
<S.ProductTitle>{title}</S.ProductTitle>
)}
</S.ProductTitle>
</div>
<div
style={{ marginTop: '-10px' }}
className="d-flex ml-2"
>
<ProductBadge
text="annoucement"
color="#D40707"
textColor="#FFF"
width="135px"
height="30px"
eventText="- engagement"
eventTextColor="#87919A"
/>
</div>
<S.AboutSection>
<span>{about}</span>
</S.AboutSection>
</>
)}
</div>
</S.Content>
</S.Screen>
<S.Home />
</S.Phone>
</>
}
/>
)
react-hook-form is not built to be used with controlled input elements.
Your input elements have an onChange handler attached to them which is effectively making your form a controlled one. If this is intended, you should pull the setValue method out of useForm and manually update the value to be used with react-hook-form.
See the bottom of this page to read more about using react-hook-form with controlled elements. React Hook Form FAQ
Related
I have a react component that display a card with input and button.
I want when I click the button to display a spinner, meanwhile after button click there is an axios post request to write some data on server. the problem is I don't see the spinnet after I click the button, I only see the message after my request done (2-3 sec after click)
function User(props) {
const [memo, setMemo] = useState('');
const [isUpdated, setIsUpdated] = useState(false);
const [spinner, setSpinner] = useState(false);
const onClickForm = (e) => {
e.preventDefault();
let inputValue = document.getElementById(inputId);
setSpinner(true);
axios.post(url, {
body: {
"internalid": props.internalid,
"memo": memo
},
headers: {"Content-Type": "application/json"},
redirect: 'follow'
}).then(response => {
console.log(response.data[0]);
setSpinner(false);
if (response.data[0].Success) {
setIsUpdated(true);
}
}, (error) => {
setIsUpdated(true);
setSpinner(false);
console.log(error)
}
)
setMemo('')
inputValue.value = '';
}
return (
<div key={props.index}>
<form onSubmit={e => onClickForm(e)}>
<Card className="card" key={props.index}>
<Card.Content>
<Card.Header>{props.tranid}</Card.Header>
<Card.Description>
{props.name}
</Card.Description>
<br/>
{!isUpdated ? (
<div>
<Input id={inputId} placeholder='Write to memo'
onChange={(e) => setMemo(e.target.value)}/>
<br/>
<button style={{marginTop: 20}} className="ui inverted blue button">Submit Change
</button>
</div>
) : (
<div>
{!spinner ? <p style={{color: 'green'}}>UPDATED!</p> : <CircularProgress/>}
</div>
)
}
)}
</Card.Content>
</Card>
</form>
</div>
)
}
It seems that as the conditions are set, when !isUpdated then <CircularProgress /> may not render, even though spinner is true.
In the conditional render output, perhaps try:
{!isUpdated && !spinner && (
<div>
<Input
id={inputId}
placeholder="Write to memo"
onChange={(e) => setMemo(e.target.value)}
/>
<br />
<button style={{ marginTop: 20 }} className="ui inverted blue button">
Submit Change
</button>
</div>
)}
{!isUpdated && spinner && <CircularProgress />}
{isUpdated && !spinner && <p style={{ color: "green" }}>UPDATED!</p>}
Or if ternary operator is preferred:
{isUpdated ? (
<p style={{ color: "green" }}>UPDATED!</p>
) : spinner ? (
<CircularProgress />
) : (
<div>
<Input
id={inputId}
placeholder="Write to memo"
onChange={(e) => setMemo(e.target.value)}
/>
<br />
<button style={{ marginTop: 20 }} className="ui inverted blue button">
Submit Change
</button>
</div>
)}
I want to make a form that disappears if I click outside of it.
Form Component:
const CreateTaskPopup = (props) => {
const ref = query(collection(db, "tasks"));
const mutation = useFirestoreCollectionMutation(ref);
useEffect(() => {
const closeTaskPopup = (event) => {
if (event.target.id != "addForm") {
props.setTrigger(false)
}
}
document.addEventListener('click', closeTaskPopup);
return () => document.removeEventListener('click', closeTaskPopup)
}, [])
return (props.trigger) ? (
<>
<div className="bg-darkishGrey my-4 p-1 mx-3 ml-16 cursor-pointer block"
id="addForm">
<div className="flex justify-between">
<div className="flex break-all items-center ">
<Image src={fileIcon} className="w-6 mx-2"/>
<div>
<Formik
initialValues={{
taskName: "",
taskIsDone: false,
parentId: props.parentId ? props.parentId : "",
hasChildren: false,
}}
onSubmit={(values) => {
mutation.mutate(values);
props.setTrigger(false);
}}
>
<Form>
<div className="">
<TextInput
placeholder="Type a name"
name="taskName"
type="text"
/>
</div>
</Form>
</Formik>
</div>
</div>
<div className="flex items-center">
</div>
</div>
</div>
</>
) : null
}
export default CreateTaskPopup
Text Input Component:
import { useField } from "formik";
const TextInput = ({ label, ...props}) => {
const [field, meta] = useField(props);
return (
<div>
<label id="addForm" className="text-lightestGrey text-xl block"
htmlFor={props.id || props.name}>
{label}
</label>
<input id="addForm" className="bg-darkishGrey text-xl text-almostWhite my-2
outline-none w-10/12 rounded-sm p-1 mx-3" {...field} {...props} />
{meta.touched && meta.error ? <div>{meta.error}</div>: null}
</div>
);
};
export default TextInput;
I tried giving an id to the elements inside it but it's not the best solution as it has components from the Formik library to which I can't assign an id. I don't know what would be the best solution for this problem.
I got this issue when I send data to backend which means I collect name, description, price and categories from User. It's working fine but the user click dropdown of paid option and select any option on their its came this error please check it out my code.
import { useState, useEffect } from "react";
import axios from "axios";
import InstructorRoute from "../../../components/routes/InstructorRoute";
import { Button, ButtonGroup, IconButton } from "#material-ui/core";
import CourseCreateForm from "../../../components/forms/CourseCreateForm";
import Resizer from "react-image-file-resizer";
import { toast } from "react-toastify";
import { useRouter } from "next/router";
// const { Option } = Select;
const createCourse = () => {
const router = useRouter();
// state
const [values, setValues] = useState({
name: "",
description: "",
price: "",
uploading: false,
paid: true,
loading: false,
});
const [image, setImage] = useState({});
const [preview, setPreview] = useState("");
const [uploadButtonText, setUploadButtonText] = useState("Upload Image");;
const handleChange = (e) => {
setValues({ ...values, [e.target.name]: e.target.value });
};
const handleImage = (e) => {
let file = e.target.files[0];
setPreview(window.URL.createObjectURL(file));
setUploadButtonText(file.name);
setValues({ ...values, loading: true });
// resize
Resizer.imageFileResizer(file, 720, 500, "JPEG", 100, 0, async (uri) => {
try {
let { data } = await axios.post("/api/course/upload-image", {
image: uri,
});
console.log("IMAGE UPLOADED", data);
// set image in the state
setImage(data);
setValues({ ...values, loading: false });
} catch (err) {
console.log(err);
setValues({ ...values, loading: false });
toast("Image upload failed. Try later.");
}
});
};
const handleImageRemove = async () => {
try {
// console.log(values);
setValues({ ...values, loading: true });
const res = await axios.post("/api/course/remove-image", { image });
setImage({});
setPreview("");
setUploadButtonText("Upload Image");
setValues({ ...values, loading: false });
} catch (err) {
console.log(err);
setValues({ ...values, loading: false });
toast("Image upload failed. Try later.");
}
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
console.log(values);
const { data } = await axios.post("/api/course", {
...values,
image,
});
toast.success("Great! Now you can start adding lessons");
router.push("/creator");
} catch (err) {
toast.error(err.response.data);
}
};
return (
<InstructorRoute>
<h1 className=" text-center square">Create Course</h1>
<div className="pt-3 pb-3">
<CourseCreateForm
handleSubmit={handleSubmit}
handleImage={handleImage}
handleChange={handleChange}
values={values}
setValues={setValues}
preview={preview}
uploadButtonText={uploadButtonText}
handleImageRemove={handleImageRemove}
/>
</div>
<pre style={{color:"white"}}>{JSON.stringify(values, null, 4)}</pre>
</InstructorRoute>
);
};
export default createCourse;
I send data via props createCourse to CourseCreateForm
import { Button, ButtonGroup, IconButton, Badge } from "#material-ui/core";
import Select from '#material-ui/core/Select';
import MenuItem from '#material-ui/core/MenuItem';
import Avatar from '#material-ui/core/Avatar';
// const { Option } = Select;
const CourseCreateForm = ({
handleSubmit,
handleImage,
handleChange,
values,
setValues,
preview,
uploadButtonText,
handleImageRemove,
}) => {
// const children = [];
// for (let i = 9.99; i <= 100.99; i++) {
// children.push(<Select key={i.toFixed(2)}>${i.toFixed(2)}</Select>);
// }
return (
<>
<form onSubmit={handleSubmit} className="container" style={{
padding: "30px",
color: "#fff",
// margin: "-54px 23px",
backgroundColor: "rgba(255,255,255,0.06)",
border: "1px solid rgba(255,255,255,0.1)",
width: "100%",
borderRadius: "15px",
// padding: "32px",
backdropFilter: "blur(10px)",
// position: "absolute",
// right: "0px",
// width: "300px",
/* border: 3px solid #73AD21; */
// padding: "10px",
}}>
<div className="form-group">
<input
type="text"
name="name"
className="form-control"
placeholder="Name"
value={values.name}
onChange={handleChange}
/>
</div>
<div className="form-group">
<textarea
name="description"
cols="7"
rows="7"
value={values.description}
className="form-control"
onChange={handleChange}
></textarea>
</div>
<div className="form-row">
<div className="col">
<div className="form-group">
<Select
color="secondary"
style={{ width: "100%", color: "white" }}
// size="large"
value={values.paid}
onChange={(v) => setValues({ ...values, paid: !values.paid })}
>
<MenuItem value={true}>Paid</MenuItem>
<MenuItem value={false}>Free</MenuItem>
</Select>
</div>
</div>
{values.paid && (
<div className="form-group">
<Select
defaultValue="$9.99"
style={{ width: "100%" }}
onChange={(v) => setValues({ ...values, price: v })}
// tokenSeparators={[,]}
size="large"
>
<MenuItem >100</MenuItem>
<MenuItem >200</MenuItem>
</Select>
{/* <input
type="number"
name="Price"
className="form-control"
placeholder="Enter Price"
onChange={(v) => setValues({ ...values, price:v })}
/> */}
</div>
)}
</div>
<div className="form-group">
<input
type="text"
name="category"
className="form-control"
placeholder="Category"
value={values.category}
onChange={handleChange}
/>
</div>
<div className="form-row">
<div className="col">
<div className="form-group">
<label className="btn btn-outline-secondary btn-block text-left">
{uploadButtonText}
<input
type="file"
name="image"
onChange={handleImage}
accept="image/*"
hidden
/>
</label>
</div>
</div>
{preview && (
<Badge badgeContent={"X"} onClick={handleImageRemove} style={{ cursor: "pointer" }} color="error">
<Avatar width={200} src={preview} />
</Badge>
)}
</div>
<div className="row">
<div className="col">
<Button
onClick={handleSubmit}
disabled={values.loading || values.uploading}
loading={values.loading}
size="large"
shape="round"
color="secondary"
variant="contained"
>
{values.loading ? "Saving..." : "Save & Continue"}
</Button>
</div>
</div>
</form>
</>
);
};
export default CourseCreateForm;
This is an output of the code and I specified the dropdown in red mark.
This the error actually came.
I have a react component
/* eslint-disable react/prop-types */
import { useQuery } from "react-query";
import { FormikProps, FormikValues, Field } from "formik";
import { createFormModel, IfieldObject } from "../create/formik/CreateModel";
import {
Combobox,
ComboboxInput,
ComboboxOptionText,
ComboboxPopover,
ComboboxOption,
ComboboxList,
} from "#reach/combobox";
import { getActiveMerchants } from "../../../../../request/shop";
import { useState } from "react";
import "styled-components/macro";
import Loader from "react-spinners/BarLoader";
import { useDebounce } from "use-debounce";
import ImageUploadCrop from "../../../../../common/ImageUploadCrop";
import MapViewWithSearch from "../../../../../common/MapViewWithSearch";
export const inputClass =
"rounded bg-gray-100 px-2 py-2 focus:bg-white border border-gray-100 focus:border-black block w-full";
export const arrowIcon = `data:image/svg+xml;utf8,<svg width='15' height='7' viewBox='0 0 15 7' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path fill-rule='evenodd' clip-rule='evenodd' d='M7.59952 7C7.37152 7 7.14452 6.923 6.95952 6.768L0.959518 1.768C0.535518 1.415 0.477518 0.784 0.831518 0.36C1.18452 -0.0640001 1.81452 -0.121 2.23952 0.232L7.61052 4.708L12.9725 0.393C13.4025 0.047 14.0325 0.115 14.3785 0.545C14.7245 0.975 14.6565 1.604 14.2265 1.951L8.22652 6.779C8.04352 6.926 7.82152 7 7.59952 7Z' fill='gray'/>
</svg>`;
export function BasicInformation({
formikBag,
}: {
formikBag: FormikProps<FormikValues>;
}): JSX.Element {
const {
name,
logo_image,
image,
address,
latitude,
longitude,
contact_number,
}: IfieldObject = createFormModel;
const [searchMerchantText, setSearchMerchantText] = useState<string>("");
const [selectedMerchant, setSelectedMerchant] = useState<{
merchant_name: string;
merchant_code: string;
}>({ merchant_name: "", merchant_code: "" });
const [throttledMerchantText] = useDebounce(searchMerchantText, 500);
const queryMerchantSearch = useQuery(
["merchant-search", throttledMerchantText],
() => getActiveMerchants(`name=${searchMerchantText}&limit=10&page=1`),
{
enabled: Boolean(throttledMerchantText),
}
);
const merchants = queryMerchantSearch?.data?.data?.data?.merchants ?? [];
console.log({ selectedMerchant });
return (
<div className="py-10 px-6">
<form>
<div className="flex items-center">
<div className="mb-6">
<ImageUploadCrop
title={logo_image?.label}
setFieldValue={(value: string) =>
formikBag.setFieldValue("logo_image", value)
}
logo={formikBag.values.logo_image}
/>
{formikBag.errors.logo_image && (
<p className="text-red-500">{formikBag.errors.logo_image}</p>
)}
</div>
<div className="ml-6 mb-6">
<ImageUploadCrop
title={image?.label}
setFieldValue={(value: string) =>
formikBag.setFieldValue("image", value)
}
logo={formikBag.values.image}
/>
{formikBag.errors.image && (
<p className="text-red-500">{formikBag.errors.image}</p>
)}
</div>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"name"}>{name?.label}</label>
<Field
type="text"
name="name"
placeholder="Name"
id={"name"}
className={"form-input"}
/>
{formikBag.errors.name && (
<p className="text-red-500">{formikBag.errors.name}</p>
)}
</div>
<div className="mb-6">
<div>
<Combobox>
<label className="relative block mb-2">
<p>Merchant Name*</p>
<ComboboxInput
placeholder="Search Merchant ..."
className="form-input"
name="merchant_code"
onChange={(e: any) => {
// formikBag.handleChange(e.target.value);
setSearchMerchantText(e.target.value);
}}
/>
{/* {formikBag.errors.merchant_code &&
formikBag.touched.merchant_code && (
<p className="text-red-500">
{formikBag.errors.merchant_code}
</p>
)} */}
</label>
{Array.isArray(merchants) && (
<ComboboxPopover
portal={false}
className="absolute bg-white border w-auto"
css={`
z-index: 2001;
`}
>
{queryMerchantSearch.isLoading ? (
<div className="flex items-center justify-center p-4">
<Loader />
</div>
) : merchants.length > 0 ? (
<ComboboxList className="bg-white shadow-md ">
{merchants.map((merchant, idx: number) => {
return (
<div key={idx} className="p-2 hover:bg-gray-100">
<div className="flex items-center">
<ComboboxOption
value={merchant.merchant_name}
className="w-full text-xs cursor-pointer"
onClick={() => {
setSelectedMerchant({
merchant_name: merchant.merchant_name,
merchant_code: merchant.merchant_code,
});
}}
>
<ComboboxOptionText /> -{" "}
<span className="capitalize font-semibold">
{merchant.merchant_type}
</span>
</ComboboxOption>
</div>
</div>
);
})}
</ComboboxList>
) : (
<div className="flex items-center justify-center p-8">
{throttledMerchantText
? "No results found"
: "Type merchant code ..."}
</div>
)}
</ComboboxPopover>
)}
</Combobox>
</div>
</div>
</div>
<div className="mb-6">
<label htmlFor="description">Description</label>
<Field
type="text"
name="description"
as={"textarea"}
id={"description"}
className={"form-input"}
/>
</div>
<div className="mb-6">
<label htmlFor={"address"}>{address?.label}</label>
<Field
type="text"
name="address"
id="address"
className={"form-input"}
/>
{formikBag.errors.address && (
<p className="text-red-500">{formikBag.errors.address}</p>
)}
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"latitude"}>{latitude?.label}</label>
<Field
type="number"
name="latitude"
id="latitude"
className={"form-input"}
/>
{formikBag.errors.latitude && (
<p className="text-red-500">{formikBag.errors.latitude}</p>
)}
</div>
<div className="mb-6">
<label htmlFor={"longitude"}>{longitude?.label}</label>
<Field
type="number"
name="longitude"
id="longitude"
className={"form-input"}
/>
{formikBag.errors.longitude && (
<p className="text-red-500">{formikBag.errors.longitude}</p>
)}
</div>
</div>
<div className="mb-6">
<MapViewWithSearch
lat={
formikBag.values.latitude ? formikBag.values.latitude : 23.777176
}
address={formikBag.values.address}
lng={
formikBag.values.longitude
? formikBag.values.longitude
: 90.399452
}
onChangeAddress={(lat, lng, address) => {
formikBag.setFieldValue("address", address);
formikBag.setFieldValue("latitude", lat);
formikBag.setFieldValue("longitude", lng);
}}
/>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"longitude"} className="block">
{contact_number?.label}
</label>
<input
name="contact_number"
type="text"
value={formikBag.values.contact_number}
onChange={formikBag.handleChange}
maxLength={11}
className={inputClass}
placeholder="01xxxxxx"
pattern="[0-9]+"
/>
{formikBag?.errors?.contact_number ? (
<small className="text-red-600">
{formikBag?.errors?.contact_number}
</small>
) : null}
</div>
<div className="mb-6">
<label htmlFor={"shop_type"}>{"Shop Type"}</label>
<Field as="select" name="shop_type" className="form-select">
<option value="regular">Regular</option>
<option value="campaign">Campaign</option>
<option value="express">Express</option>
</Field>
</div>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-4" role="group">
<p className="block mb-2">Is Delivery Hero Allowed</p>
<label className="mr-4">
<input
name="is_delivery_hero_allowed"
type="radio"
checked={!formikBag.values.is_delivery_hero_allowed}
onChange={() => {
formikBag.setFieldValue("is_delivery_hero_allowed", false);
}}
value="false"
/>{" "}
<span className="ml-2">No</span>
</label>
<label>
<input
name="is_delivery_hero_allowed"
type="radio"
checked={formikBag.values.is_delivery_hero_allowed}
onChange={() =>
formikBag.setFieldValue("is_delivery_hero_allowed", true)
}
value="true"
/>{" "}
<span className="ml-2">Yes</span>
</label>
</div>
<div className="mb-4" role="group">
<p className="block mb-2">Is Cash On Delivery Allowed</p>
<label className="mr-4">
<input
name="is_cod_allowed"
type="radio"
checked={!formikBag.values.is_cod_allowed}
onChange={() => {
formikBag.setFieldValue("is_cod_allowed", false);
}}
value="false"
/>{" "}
<span className="ml-2">No</span>
</label>
<label>
<input
name="is_cod_allowed"
type="radio"
checked={formikBag.values.is_cod_allowed}
onChange={() => formikBag.setFieldValue("is_cod_allowed", true)}
value="true"
/>{" "}
<span className="ml-2">Yes</span>
</label>
</div>
</div>
</form>
</div>
);
}
Now I want to pass the state value of selectedMerchant as a props of this component and then pass the props to a parent component, The parent component is
import "styled-components/macro";
import { BiLeftArrowAlt, BiRightArrowAlt } from "react-icons/bi";
import { Formik, Form } from "formik";
import { BasicInformation } from "./BasicInformation";
import AdditionalInformations from "./AdditionalInformations";
import validationSchema from "../create/formik/ValidationSchema";
import React from "react";
import { createShop } from "../../../../../request/shop";
import { removeaSinglItem } from "../../../../../utils/helper";
import { Persist } from "../../../../../common/PersistFormData";
import { toast } from "react-toastify";
import Loader from "../../../../../common/Loader";
import { useNavigate } from "react-router-dom";
import { ROUTES } from "../../../../core/route";
function _renderStepContent(step: number, formikBag: any) {
switch (step) {
case 0:
return <BasicInformation formikBag={formikBag} />;
case 1:
return <AdditionalInformations formikBag={formikBag} />;
default:
return <div>Not Found</div>;
}
}
export const CreateMotherShop = (): JSX.Element => {
const navigate = useNavigate();
const STEPS: string[] = ["Basic Information", "Additional Information"];
const [activeStep, setActiveStep] = React.useState(0);
const currentValidationSchema = validationSchema[activeStep];
const isSubmitStep = activeStep === STEPS.length - 1;
const filter = (data: any) => {
if (Array.isArray(data)) {
const temp = data.reduce((r, v) => {
v = filter(v);
if (v !== "") r.push(v);
return r;
}, []);
return temp.length ? temp : "";
}
if (data && typeof data === "object") {
const temp = Object.entries(data).reduce((r, [k, v]) => {
v = filter(v);
if (v !== "") r.push([k, v]);
return r;
}, [] as [string, unknown][]);
return temp.length ? Object.fromEntries(temp) : "";
}
return data;
};
function _handleBack() {
setActiveStep(activeStep - 1);
}
async function _submitForm(values: any, actions: any) {
try {
actions.setSubmitting(true);
const reqbody: any = {
name: values.name,
merchant_code: values.merchant_code,
description: values.description,
address: values.address,
longitude: values.longitude,
latitude: values.latitude,
logo_image: values.logo_image,
image: values.image,
contact_number: values.contact_number,
shop_type: values.shop_type,
bin_no: values.bin_no,
trade_license_no: values.trade_license_no,
key_personnel: values.key_personnel,
category_head: values.category_head,
bdm: values.bdm,
kam: values.kam,
vm: values.vm,
organisation_type: values.organisation_type,
acquisition_info: values.acquisition_info,
agreement_info: values.agreement_info,
bank_account_name: values.bank_account_name,
bank_account_no: values.bank_account_no,
bank_name: values.bank_name,
bank_branch_name: values.bank_branch_name,
bank_branch_routing_no: values.bank_branch_routing_no,
sbu_unit: values.sbu_unit,
is_mother_shop: true,
is_delivery_hero_allowed: values.is_delivery_hero_allowed,
is_cod_allowed: values.is_cod_allowed,
};
if (values.key_personnel) {
reqbody.key_personnel = values.key_personnel;
}
if (values.acquisition_info) {
reqbody.acquisition_info = values.acquisition_info;
}
if (values.agreement_info) {
reqbody.agreement_info = values.agreement_info;
}
if (values.category_head) {
reqbody.category_head = values.category_head;
}
if (values.bdm) {
reqbody.bdm = values.bdm;
}
if (values.kam) {
reqbody.bdm = values.kam;
}
if (values.vm) {
reqbody.vm = values.vm;
}
const finalPayload = filter(reqbody);
const res = await createShop(finalPayload);
if (res.status == 201) {
toast.success(res.data.message);
actions.setSubmitting(false);
await removeaSinglItem("createShop");
navigate(ROUTES.shop.linkTo);
} else {
toast.error(res.response.data.message);
}
} catch (err) {
console.log(err);
actions.setSubmitting(false);
setActiveStep(0);
toast.error("Failed to create Mother Shop");
window.location.reload();
}
}
function _handleSubmit(values: any, actions: any) {
if (isSubmitStep) {
_submitForm(values, actions);
} else {
setActiveStep(activeStep + 1);
actions.setTouched({});
actions.setSubmitting(false);
}
}
return (
<>
<div
css={`
height: 60px;
`}
className="bg-white shadow border-b-2"
>
<div className="flex items-center h-full pl-6 pr-4">
<nav className={"h-full flex items-center flex-grow"}>
<ul className="flex">
<li>
<a href="/" className="text-gray-700 hover:text-black">
Home
</a>
</li>
<li className="px-2 text-gray-600">•</li>
<li>
<a
href="/dashboard/shop/motherShop?page=1"
className="text-gray-700 hover:text-black"
>
Mother Shops
</a>
</li>
<li className="px-2 text-gray-600">•</li>
<li>
<a
href="/dashboard/shop/motherShop/create"
className="font-medium hover:text-black"
>
Create Mother Shop
</a>
</li>
</ul>
</nav>
</div>
</div>
<div className="container mx-auto pt-6 px-4">
<div
className="mb-6"
css={`
width: 800px;
display: block;
margin: 0 auto;
margin-bottom: 1rem;
`}
>
<h1>Create Mother Shop / {STEPS[activeStep]}</h1>
</div>
<div
className=""
css={`
min-height: calc(100vh - 300px);
`}
>
<div
className="bg-white rounded-lg p-4"
css={`
width: 800px;
display: block;
margin: 0 auto;
`}
>
<Formik
enableReinitialize
initialValues={{
name: "",
merchant_code: "",
description: "",
address: "",
logo_image: "",
image: "",
longitude: "",
latitude: "",
contact_number: "",
shop_type: "regular",
bin_no: "",
trade_license_no: "",
key_personnel: [
{
username: "",
designation: "",
phone_no: "",
email: "",
},
],
category_head: [
{
username: "",
},
],
bdm: [
{
username: "",
},
],
kam: [
{
username: "",
},
],
vm: [
{
username: "",
},
],
acquisition_info: [
{
acquisition_code: "",
acquisition_by: "",
acquisition_phone_no: "",
acquisition_email: "",
acquisition_date: "",
},
],
agreement_info: [
{
agreement_code: "",
agreement_scan_copy: "",
agreement_expiry_date: "",
credit_limit: "",
credit_time: "",
},
],
organisation_type: "small",
bank_account_name: "",
bank_account_no: "",
bank_name: "",
bank_branch_name: "",
bank_branch_routing_no: "",
sbu_unit: "",
is_mother_shop: true,
is_delivery_hero_allowed: false,
is_cod_allowed: false,
}}
validationSchema={currentValidationSchema}
onSubmit={_handleSubmit}
>
{(formikBag) => {
return (
<Form id="createComapny">
{_renderStepContent(activeStep, formikBag)}
{!formikBag.isSubmitting && (
<Persist name="createComapny" />
)}
<div className="flex justify-end">
{activeStep !== 0 && (
<button
onClick={_handleBack}
className="flex bg-white rounded px-4 py-2 text-black items-center border "
>
<BiLeftArrowAlt size={20} />
<span className="mr-1">Previous</span>{" "}
</button>
)}
<button
disabled={formikBag.isSubmitting}
className="ml-5 bg-black rounded px-4 py-2 text-white"
>
{formikBag.isSubmitting ? (
<div className="flex items-center justify-center">
<Loader small color={"white"} />
</div>
) : isSubmitStep ? (
<span className="mr-1">Submit</span>
) : (
<span className="flex">
<span className="mr-1 items-center">Next</span>{" "}
<BiRightArrowAlt size={20} />
</span>
)}
</button>
</div>
</Form>
);
}}
</Formik>
</div>
</div>
</div>
</>
);
};
So I want to pass the selectedMerchant props in the line <BasicInformation formikBag={formikBag} /> like <BasicInformation formikBag={formikBag} selectedMerchant={selectedMerchant} /> I tried to add the state in the props like
export function BasicInformation({
formikBag,
selectedMerchant,
}: {
formikBag: FormikProps<FormikValues>;
selectedMerchant: any;
}): JSX.Element {
--------
}
and pass the props like <BasicInformation formikBag={formikBag} selectedMerchant={selectedMerchant} /> but its giving me errors.
N.B: I will not be able to use any kind of state management tools like Redux in this project.
I am trying to use antD's calendar picker inside of a modal that has been created using Material-UI. When I put the datepicker inside of the modal component. It shows me the selection box but when I click on it, nothing opens to choose from. I tried wrapping it in a div as well, but that didn't work. Here's an image of the modal:
Modal code:
import React, { useState,useEffect } from "react";
import { withStyles } from "#material-ui/core/styles";
// import Button from "#material-ui/core/Button";
import Dialog from "#material-ui/core/Dialog";
import MuiDialogTitle from "#material-ui/core/DialogTitle";
import MuiDialogContent from "#material-ui/core/DialogContent";
import MuiDialogActions from "#material-ui/core/DialogActions";
import IconButton from "#material-ui/core/IconButton";
import CloseIcon from "#material-ui/icons/Close";
import Typography from "#material-ui/core/Typography";
import { Link } from "#material-ui/core";
import Table from "../Cards/CardTable";
import moment from "moment";
import CardLineChart from "components/Cards/CardLineChart.js";
import CardLineChart2 from "components/Cards/CardLineChart2.js";
import CardStats from "components/Cards/CardStats.js";
import { DatePicker, Space } from "antd";
const { RangePicker } = DatePicker;
const styles = (theme) => ({
root: {
width: 300,
margin: 0,
padding: theme.spacing(2),
},
closeButton: {
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500],
},
});
const DialogTitle = withStyles(styles)((props) => {
const { children, classes, onClose, ...other } = props;
return (
<MuiDialogTitle disableTypography className={classes.root} {...other}>
<Typography variant="h6">{children}</Typography>
{onClose ? (
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={onClose}
>
<CloseIcon />
</IconButton>
) : null}
</MuiDialogTitle>
);
});
const DialogContent = withStyles((theme) => ({
root: {
// width: 200,
padding: theme.spacing(2),
},
}))(MuiDialogContent);
const DialogActions = withStyles((theme) => ({
root: {
margin: 0,
padding: theme.spacing(1),
},
}))(MuiDialogActions);
export default function CustomizedDialogs(props) {
const { name } = props;
console.log("Name is ======>", name)
const [open, setOpen] = useState(false);
const [colors, setColors] = useState(false);
const [deviceMsgs,setDeviceMsgs] = useState(null)
const [start, setStart] = useState();
const [end, setEnd] = useState();
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const onChange = (dates, dateStrings) => {
if (dateStrings.length > 0) {
setStart(dateStrings[0]);
setEnd(dateStrings[1]);
}
};
const DPicker = () => {
return (
<div>
<Space direction="vertical" size={12}>
<RangePicker
ranges={{
Today: [moment(), moment()],
"This Month": [
moment().startOf("month"),
moment().endOf("month"),
],
}}
onChange={onChange}
/>
</Space>
</div>
);
};
return (
<div>
<Link variant="outlined" color="primary" onClick={handleClickOpen}>
{name}
</Link>
<Dialog
maxWidth={"xl"}
// style={{ width: "100%" }}
onClose={handleClose}
aria-labelledby="customized-dialog-title"
open={open}
>
<DialogTitle
style={{ backgroundColor: colors ? "green" : "red" }}
id="customized-dialog-title"
onClose={handleClose}
>
{name}
</DialogTitle>
<DialogContent dividers>
<div>
<DPicker /> //////// Using the picker
<div className="relative w-full pr-4 max-w-full flex-grow flex-1">
<span className="font-semibold text-xl text-blueGray-700">
Last Update : 21 April 2021 17:00:00
</span>
</div>
<div className="m-4 px-4 md:px-10 mx-auto w-full">
<div>
{/* Card stats */}
<div className="flex flex-wrap">
<div className="w-full lg:w-6/12 xl:w-3/12 px-4">
<CardStats
statSubtitle="Total"
statTitle="10"
statArrow="up"
statPercent="3.48"
statPercentColor="text-emerald-500"
statDescripiron="Since last month"
statIconName="fas fa-percent"
statIconColor="bg-lightBlue-500"
/>
</div>
<div className="w-full lg:w-6/12 xl:w-3/12 px-4">
<CardStats
statSubtitle="ACTIVE"
statTitle="6"
statArrow="down"
statPercent="3.48"
statPercentColor="text-red-500"
statDescripiron="Since last week"
statIconName="fas fa-users"
statIconColor="bg-pink-500"
/>
</div>
<div className="w-full lg:w-6/12 xl:w-3/12 px-4">
<CardStats
statSubtitle="INACTIVE"
statTitle="4"
statArrow="down"
statPercent="1.10"
statPercentColor="text-orange-500"
statDescripiron="Since yesterday"
statIconName="far fa-chart-bar"
statIconColor="bg-red-500"
/>
</div>
<div className="w-full lg:w-6/12 xl:w-3/12 px-4">
<CardStats
statSubtitle="ALERT"
statTitle="--"
statArrow="up"
statPercent="12"
statPercentColor="text-emerald-500"
statDescripiron="Since last month"
statIconName="fas fa-chart-pie"
statIconColor="bg-orange-500"
/>
</div>
</div>
</div>
</div>
</Dialog>
</div>
);
}
Obviously, you should check my solution because it is just my assumption of your problem, but anyway it seems that it can help you:
<DatePicker
getPopupContainer={(triggerNode) => {
return triggerNode.parentNode;
}}
/>
By default, popup container is located nearby body but you can change it to your modal element. The my solution above covers that
I found a solution to the problem and it is straightforward.
after tinkering in the dev-tools, I found out that the Z-index of the antd Modal is set to 1055.
A simple override to the date-picker Z-index fixes the issue : I set it to 1056.
Its className is : ".ant-picker-dropdown"
.ant-picker-dropdown{
z-index: 1056;
}
solves the issue.
This will work.
Go to Node Module > antd > dist > antd.compact.css > change the z-index of elements accordingly.