I created a table to display data regarding customer orders that will likely need canceling.
If an order needs canceling, a checkbox will be checked, and the data in question will be handled via a handleCheck function that returns the rows of data in question, and a handleClick function sends the emails in question.
Currently, my handleClick function sends out the appropriate number of emails, but they're all duplicates. I am having trouble determining how to send an email for each unique row selected. Any advice would be greatly appreciated. Thanks!
Here is my handleCheck function, which gets called when a checkbox gets clicked:
const handleCheck = () => {
//R is set as row checked...
if (checked == true) {
setR(row);
setIdx(index);
console.log("row: ", r, idx);
}
//Mail is set to an array containing 'r'...
setMail([r]);
mail.push(r);
console.log("mail: ", mail);
};
This is how I define the state on r, mail, and idx:
const [r, setR]: any = useState();
const [mail, setMail]: any = useState([]);
const [idx, setIdx]: any = useState();
Here is my handleClick function, which gets called when a "send email" button gets clicked:
function EmailSnackbars() {
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen(true);
//idx is equal to index where checked == true.
//r is equal to row where checked == true.
//Currently sending correct number of emails, but these are duplicates...
for (let i = 0; i <= idx; i++) {
mail.filter((r: any) => [
r.ship_firstname,
r.ship_lastname,
r.product_id,
r.gtin,
r.description,
]);
sendMail(firstname, lastname, email, product_id, eta, gtin, description);
}
};
const handleClose = (
event?: React.SyntheticEvent | Event,
reason?: string
) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};
return (
<>
<Tooltip title="Send Email(s)">
<Button
variant="text"
size="large"
color="secondary"
onClick={handleClick}
>
<SendIcon />
</Button>
</Tooltip>
<Snackbar
open={open}
autoHideDuration={6000}
onClose={handleClose}
TransitionComponent={TransitionDown}
>
<Alert
onClose={handleClose}
severity="info"
sx={{ width: "100%" }}
elevation={11}
variant="filled"
color="info"
>
Email(s) Sent!
</Alert>
</Snackbar>
</>
);
}
Also, this is where my sendMail function is defined:
let [firstname, setFirstname]: any = useState();
let [lastname, setLastname]: any = useState();
let [email, setEmail]: any = useState();
let [eta, setEta]: any = useState();
let [gtin, setGtin]: any = useState();
let [description, setDescription]: any = useState();
let [product_id, setId]: any = useState();
//Function to send emails to customers on click of 'send email' button.
const sendMail = (
firstname: any,
lastname: any,
email: any,
eta: any,
gtin: any,
description: any,
product_id: any
) => {
const response: any = axios.post(`/api/email`, {
params: {
firstname: r.ship_firstname,
lastname: r.ship_lastname,
email: test_email,
product_id: r.product_id,
eta: r.eta,
gtin: r.gtin,
description: r.description,
},
});
};
Related
I have a radio button that when I click it calls a function with two parameters in the function (value and step), and when I make a test with testing librairy I would like that when I simulate the click of the button I return the two parameters.
Button
<Form.Check
inline
label={'form.email'}
name="media"
value={`LETTER`}
type="radio"
data-testid="EMAIL"
onClick={(e) => {
const target = e.target as HTMLTextAreaElement;
changeMedia(target.value, data);
}}
/>
Function ChangeMedia
const changeMedia = (value: any, step: any) => {
step.definition?.steps
.filter((obj: any) => obj.media.includes(value))
.map((item: any) => {
if (value === 'EMAIL') {
item.media = 'LETTER';
return item;
} else if (value === 'LETTER') {
item.media = 'EMAIL';
return item;
}
return item;
});
return data;
};
Objet Step
const step = {
definition: {
steps: [
{
document_model: 'template_circularization',
email_model: 'email_circularization',
label: {
EN: 'Circularization',
FR: 'Circularisation',
},
media: 'LETTER',
name: 'mail_circularization',
onDemandOnly: true,
},
],
},
};
Test
const radio = screen.getByTestId('EMAIL');
fireEvent.click(radio, { target: { value: 'EMAIL, step: step } });
when I do a console.log of value and step I get this :
value EMAIL
step {}
what would be the solution to retrieve the step object via firevent.click ?
I want to upload image by Vue 3 and Axios with state. But error is: array to string. I don't know what to do know. Please help me. Thank so much.
HTML:
<input
type='file'
class="hidden"
name="avatar"
id="avatar"
#change="updatePreview"
style="display: none;"
/>
Define State
const state = reactive({
user: {},
updateMovie: {
id: '',
name: '',
image: '',
}
Take file image:
function updatePreview(e) {
if (e.target.files.length === 0) {
return
}
console.log(e)
imageFile.value = e.target.files[0]
state.updateMovie.image = e.target.files[0]
}
const submitModal = (type) => {
if (type === 'edit') {
const form = {
image: state.updateMovie.image,
}
const id = state.updateMovie.id
console.log("form: ", form)
console.log(typeof form.image)
axios.post(`movie/update/${id}`, form)
.then((res) => {
if (res.status === 200) {
const data = res.data.data.movie
})
}
})
}
}
That's all. Now i don't know what to do to send data to axios.
I am new to react native. I have created a form from where I am sending some data to server. Now I want that to disabled submit button after user click on submit . once user submit data then after He unable to send data. means I want to avoid duplicate entry. please help. thanks. if possible also tell how to do it with functional component too.
here is my code
export default function Add(props) {
const { navigation } = props
const offset = (Platform.OS === 'android') ? -200 : 0;
const [AmazonError, setAmazonError] = useState([]);
const [Amazon, setAmazon] = useState('');
const [AmazonCNError, setAmazonCNError] = useState([]);
const [AmazonCN, setAmazonCN] = useState('');
const [AEPSError, setAEPSError] = useState([]);
const [AEPS, setAEPS] = useState('');
const [DMTError, setDMTError] = useState([]);
const [DMT, setDMT] = useState('');
const [BBPSError, setBBPSError] = useState([]);
const [BBPS, setBBPS] = useState('');
const [leadTagNumber, setLeadTagNumber] = useState([]);
const validateInputs = () => {
if (!Amazon.trim()) {
setAmazonError('Please Fill The Input')
return;
}
if (!AmazonCN.trim()) {
setAmazonCNError('Please Fill The Input')
return;
}
if (!AEPS.trim()) {
setAEPSError('Please Fill The Input')
return;
}
if (!DMT.trim()) {
setDMTError('Please Fill The Input')
return;
}
if (!BBPS.trim()) {
setBBPSError('Please Fill The Input')
return;
}
else
{
//+++++++++++++++++++++++++++++++++=submitting form data to api start+++++++++++++++++++++++++++++++++++
{
const leadTagNumber = props.route.params.leadTagNumber
AsyncStorage.multiGet(["application_id", "created_by",'leadTagNumber']).then(response => {
// console.log(response[0][0]) // Key1
console.log(response[0][1]) // Value1
// console.log(response[1][0]) // Key2
console.log(response[1][1]) // Value2
console.log(leadTagNumber)
fetch('https://xyxtech/Android_API_CI/uploaddata/tbservice_details', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
// We convert the React state to JSON and send it as the POST body
body: JSON.stringify([{ data}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
console.log(response)
Alert.alert("File uploaded");
return response.json();
});
});
// event.preventDefault();
}
//+++++++++++++++++++++++++++++++++submitting form data to api end++++++++++++++++++++++++++++++++++++++
Alert.alert("success")
return;
//}
}
};
const handleAmazon = (text) => {
setAmazonError('')
setAmazon(text)
}
const handleAmazonCN= (text) => {
setAmazonCNError('')
setAmazonCN(text)
}
const handleAEPS= (text) => {
setAEPSError('')
setAEPS(text)
}
const handleDMT = (text) => {
setDMTError('')
setDMT(text)
}
const handleBBPS = (text) => {
setBBPSError('')
setBBPS(text)
}
return (
<View style={{flex: 1}}>
<ScrollView style={{flex: 1,}} showsVerticalScrollIndicator={false}>
<TextInput
maxLength={30}
placeholder="AEPS (Adhar enabled payment system) *"
style={styles.inputStyle}
onChangeText={(text)=>handleAEPS(text)}
defaultValue={AEPS}
value = {AEPS} />
<Text>{AEPSError}</Text>
</ScrollView>
<Button
style={styles.inputStyleB}
title="Submit"
color="#FF8C00"
onPress={() => validateInputs()}
/>
</View>
)
}
Set new state property to enable/disable button
const [disableButton, setDisableButton] = useState(false);
Now in your button component, add disabled property with disableButton state.
<Button
style={styles.inputStyleB}
title="Submit"
color="#FF8C00"
onPress={() => validateInputs()}
disabled={disableButton}
/>
Disable you button before fetching data
setDisableButton(true) //Add this
const leadTagNumber = props.route.params.leadTagNumber
Incase of fetch error or after fetching is complete, enable button again
setDisabledButton(false)
I'm using the following validation schema in Formik:
validationSchema = {
Yup.object({
emails: Yup.array()
.of(Yup.string().email('Please enter valid email addresses only.'))
.min(1, 'At least one email address is required.')
})
}
It works very well, except that, since I'm using a Material UI AutoComplete component, when the user enters multiple invalid email addresses, they get to see the error message once per invalid email address.
Any way around this?
Here's a sandbox link: https://codesandbox.io/s/wild-sea-h2i0m?file=/src/App.tsx
What you want to do then is to make sure you filter out duplicated errors. You should make sure that each error message is unique. I wrote a function that help you do that.
I updated your EmailsField component:
import React from "react";
import Autocomplete from "#material-ui/lab/Autocomplete";
import Chip from "#material-ui/core/Chip";
import CloseIcon from "#material-ui/icons/Close";
import TextField from "#material-ui/core/TextField";
import { FieldProps } from "formik";
const isEmailValid = (email: string) =>
/^[^\s#]+#[^\s#]+\.[^\s#]+$/.test(email);
const EmailsField = ({
field,
form: { errors, touched, setTouched, setFieldValue },
...props
}: FieldProps) => {
console.log('errors', errors)
const name = field.name;
const [value, setValue] = React.useState<string[]>([]);
const [inputValue, setInputValue] = React.useState("");
const handleChange = (event: React.ChangeEvent<{}>, emails: string[]) => {
setTouched({ ...touched, [name]: true });
setValue(emails);
event.persist();
setFieldValue(name, emails);
};
const handleInputChange = (
event: React.ChangeEvent<{}>,
newInputValue: string
) => {
const options = newInputValue.split(/[ ,]+/);
const fieldValue = value
.concat(options)
.map(x => x.trim())
.filter(x => x);
if (options.length > 1) {
handleChange(event, fieldValue);
} else {
setInputValue(newInputValue);
}
};
// 1. This function will help remove duplicated errors
const getEmailErrors = (errors: any) => {
return Array.isArray(errors)
? errors.filter((email: string, i: number, arr: any) => arr.indexOf(email) === i)
: errors;
}
return (
<Autocomplete<string>
multiple
disableClearable={true}
options={[]}
freeSolo
renderTags={(emails, getTagProps) =>
emails.map((email, index) => (
<Chip
deleteIcon={<CloseIcon />}
variant="default"
label={email}
color={isEmailValid(email) ? "primary" : "secondary"}
{...getTagProps({ index })}
/>
))
}
value={value}
inputValue={inputValue}
onChange={handleChange}
onInputChange={handleInputChange}
renderInput={params => (
<TextField
{...params}
name={name}
error={touched[name] && Boolean(errors.emails)}
//---------------------------------------->>>> Call it here
helperText={touched[name] && errors.emails && getEmailErrors(errors.emails as any)}
variant="outlined"
InputProps={{ ...params.InputProps }}
{...props}
/>
)}
/>
);
};
export default EmailsField;
I'm trying to use ant design forms in my sample registration form, when i'm trying to use setFieldsValue it throws error as "Cannot use setFieldsValue unless getFieldDecorator is used". But I had already used getFieldDecorator in my code.Here is a sample of my code.
handleChange = (e) => {
const fname = e.target.name;
const fvalue = e.target.value;
this.props.setFieldsValue({
fname: fvalue
});
}
render(){
const { getFieldDecorator } = this.props.form
return (
<Row gutter={4}>
<Col className="reg-personal-details-grid-column" span={24}>
<FormItem {...formItemLayout} label="First Name">
{getFieldDecorator("firstName", {
rules: [
{
required: true
}
]
})(
<Input
placeholder="First Name"
required
name="firstName"
onChange={this.handleChange}
/>
)}
</FormItem>
</Col>
</Row>
)
}
fname is not defined in getFieldDecorator.
You should do this:
handleChange = (e) => {
const fname = e.target.name;
const fvalue = e.target.value;
this.props.form.setFieldsValue({
[fname]: fvalue
});
}
You can create your own function to do this:
export const setFieldValue = (
form: FormInstance,
name: NamePath,
value: string
): void => {
if (form && form.getFieldValue(name)) {
const fixname: string[] = [];
if (typeof name == 'object') {
name.forEach((node: string) => {
fixname.push(node);
});
} else {
fixname.push(String(name));
}
let fieldsValue: unknown;
fixname.reverse().forEach((node: string) => {
fieldsValue = {
[String(node)]: fieldsValue != undefined ? fieldsValue : value,
};
});
form.setFieldsValue(fieldsValue);
}
};
and you can use like that
setFieldValue(form, 'phone', '1111111111');
or
setFieldValue(form, ['phones', 'mobile'], '2222222222');
In Antd v4, you only required to call the setFieldsValue in useEffect function.
const [form] = Form.useForm()
useEffect(() => {
//companyInfo -> dynamic obj fetched from API
form.setFieldsValue(companyInfo);
}, [companyInfo, form]);
Then in Form use the form prop as follow:
<Form
//passing form prop
form={form}
labelCol={{ span: 8 }}
wrapperCol={{ span: 14 }}
onFinish={onFinish}
labelAlign="left"
colon={false}
>
you can use it like this
const formRef = useRef(null);
useEffect(() => {
formRef.current?.setFieldsValue({
name: data?.firstName,
});
}, [data]);
return (
<Form ref={formRef}>
<Form.Item name="name">
<Input/>
</Form.Item>