So I'm building a simple app and I want to have phone number auth. However, after following the instructions on the site, nothing seems to be firing.
// App.js
handleNext = () => {
verifyPhoneNumber(this.state.phoneNumber);
this.setState(prevState => ({
activeStep: prevState.activeStep + 1
}));
};
...
<Button
size="small"
onClick={this.handleNext}
disabled={activeStep === maxSteps - 1}
id={"verify-phone-number-button"}
>
Next
</Button>
//Controller.js
export const verifyPhoneNumber = (phoneNumber) => {
console.log(phoneNumber) // +14084445555
firebase.auth().useDeviceLanguage();
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('verify-phone-number-button', {
'size': 'invisible',
'callback': function (response) {
// reCAPTCHA solved, allow signInWithPhoneNumber.
console.log("reCAPTCHA solved")
var appVerifier = window.recaptchaVerifier;
firebaseApp.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
.then(function (confirmationResult) {
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
window.confirmationResult = confirmationResult;
console.log("success")
}).catch(function (error) {
console.log(error)
// Error; SMS not sent
// ...
});
}
});
}
reCAPTCHA solved never gets printed meaning it never makes it there. However, it also isn't printing any error messages so I'm unsure of what is happening.
Thanks for your help!
Related
I'm new to daily-co integration in react js. Can you please suggest how to change
"Request to Join" text to "Join Meeting". Thank in advance.
At present in Iframe all content is coming. Can any one please suggest how to change
the "Request to Join" text to "Join Meeting".
My Observations:
One api is calling at the time of page is loaded:
https://b.daily.co/call-ui/16c545a8520b661e39dc13c62b335ffea4cb3651/locales/en/translation.js
{ ....
"haircheck": {
....
"setup": {
"requestToJoin": "Request to join",
"title": "Are you ready to join?",
}
},
}
//React Class component:
import React from 'react';
import DailyIframe from '#daily-co/daily-js';
import Cookies from 'universal-cookie';
import axios from '../../util/axios';
import util from '../../util/util';
const cookies = new Cookies();
class VideoCallFrame2 extends React.Component {
constructor(props) {
super(props);
this.iframeRef = React.createRef();
this.state = {
authorizationToken: 'Bearer ------------',
roomName: '',
room: null,
token: null,
rooms: [],
roomUrlWithToken: null,
isVideoHidden: false,
joinedObject: null,
status: '',
askedQuestions: [],
};
}
componentDidMount() {
this.daily = DailyIframe.wrap(
this.iframeRef.current,
{
showLeaveButton: true,
});
this.setState({
...this.state,
roomUrlWithToken: this.props.meetingRoomUrl
});
this.startRoom();
let temp = this.daily.meetingState();
this.setState({ status: temp });
this.get_candidate_position();
}
get_candidate_position = (e) => {
this.setState({
positionDetails: response.data.candidate[0]
})
}
onHandleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
joinMeetingEvents = () => {
// Meeting related events
this.daily.on('loading', () => { console.log('Loading......') })
this.daily.on('loaded', () => { console.log('Loaded......') })
this.daily.on('joining-meeting', () => { console.log('Joining......') })
this.daily.on('joined-meeting', () => {
console.log('Joined......')
})
this.daily.on('app-message', (e) => {
console.log('app-messageapp-message app-message>>>>>>> ', e)
})
this.daily.on('left-meeting', (e) => {
console.log('Left Meeting......', e)
this.props.history.push('/thankyou')
})
this.daily.on('participant-joined', (e) => {
console.log('Partcipand Joined......', e);
this.setState({
...this.state,
isVideoHidden: true
})
if (this.state.joinedObject.user_id == '') {
}
})
this.daily.on('error', (e) => {
console.log('ERROR......', e)
})
}
leftMeeeting = () => {
this.daily.leave();
this.daily.destroy();
}
startRoom = async () => {
let res = await this.daily.join({
url: this.props.meetingRoomUrl
})
this.setState({
...this.state,
joinedObject: null
})
this.daily.on('loading', () => { console.log('Loading......') })
this.daily.on('loaded', () => { console.log('Loaded......') })
this.daily.on('joining-meeting', () => { console.log('joining-meeting......') })
this.daily.on('joined-meeting', () => {
console.log('Joined meeting......');
})
this.daily.on('joined-meeting', () => {
console.log('Joined meeting......');
})
this.daily.on('meeting-session-updated', () => {
console.log('meeting-session-updated......');
});
this.daily.on('access-state-updated', (evt) => {
console.log('access-state-updated......', evt);
if (evt.access.level == 'lobby') {
//Some code
}
});
this.daily.on('participant-joining', () => { console.log('participant-joining') })
this.daily.on('left-meeting', (e) => {
this.props.history.push('/thankyouPage');
});
this.daily.on("app-message", (e) => {
let Arr = this.state.askedQuestions;
if (
e &&
e.data &&
e.data.message &&
e.data.message.endInterview == "end") {
this.leftMeeeting();
}
});
this.daily.on('participant-joined', (e) => {
console.log('Partcipand Joined......', e);
setTimeout(() => {
this.daily.sendAppMessage({ message: { intervieweraskedQuestions: this.state.askedQuestions } }, '*');
}, 3000)
})
this.daily.on('error', (e) => {
console.log('ERROR......', e)
})
}
render() {
return (
<div className="" style={{ height: '450px' }}>
<iframe className="Video-Frame video-call-frame"
title="video call iframe"
ref={this.iframeRef}
allow="camera; microphone; fullscreen; display-capture"
></iframe>
</div>
)
}
}
export default VideoCallFrame2;
I work at Daily. :) "Request to join" is shown for private rooms with "knocking" enabled. We use this language because clicking the button will alert the room owner to let you in, so you do need to ask to join -- you can't just go straight in.
This can be turned off though. If you make the room public, it will say "Join meeting" instead of "Request to join" because anyone can join. Alternatively, you can make a meeting token for anyone trying to enter a private room so they don't need to ask to join. (In this case, the button text would also be updated to "Join meeting").
More generally, you can't update button text to something custom in the Daily Prebuilt UI, but you can build your on custom UI with our APIs. That's probably too much effort just to update one button, though. :)
I have not used daily.co before but I did a little digging and confirmed my suspicions: As far as I can tell, this is not possible.
In order to for a page to edit the contents of an iFrame, the frame must be on the same origin as its parent page, as per the Same Origin Policy.
Your page is on the origin http://localhost:3001, while the frame is on an origin owned by Daily, e.g. https://server.daily.co.
This policy exists for security reasons, an example is imagine some website https://attacker.com with a frame to https://bankaccount.com, without this policy the attacker could change a button on the frame from "Click to send all money to attacker" to "Click to receive your $1 million reward!"
The only method I have found that may be plausible after doing a couple searches for "origin", "host", etc. on docs.daily.co is this reference page for "Daily's Video Component System (VCS)", but from what I can tell this cannot solve the problem as this only allows you to add an overlay to the video call, not the frame itself.
I'm using react-paypal-express-checkout
I've to options: Cash and PayPal.
Cash working fine and checks all conditions.
But bcs PayPal is a seperate component in my CartScreen component it opens and don't check a single if conditions and opens the PayPal window
The CashButton comes with function "cashTranSuccess" it's the same function as "TranSuccess"
just without the paymentID bcs it's only needed for react-paypal-express-checkout
So what I'm looking for is, to check all TranSuccess() conditions before open the PayPal window.
PayPalButton.js
import React from 'react';
import PaypalExpressBtn from 'react-paypal-express-checkout';
export default class PayPalButton extends React.Component {
render() {
const onSuccess = (payment) => {
// Congratulation, it came here means everything's fine!
console.log('The payment was succeeded!', payment);
// You can bind the "payment" object's value to your state or props or whatever here, please see below for sample returned data
this.props.tranSuccess(payment);
};
const onCancel = (data) => {
// User pressed "cancel" or close Paypal's popup!
console.log('The payment was cancelled!', data);
// You can bind the "data" object's value to your state or props or whatever here, please see below for sample returned data
};
const onError = (err) => {
// The main Paypal's script cannot be loaded or somethings block the loading of that script!
console.log('Error!', err);
// Because the Paypal's main script is loaded asynchronously from "https://www.paypalobjects.com/api/checkout.js"
// => sometimes it may take about 0.5 second for everything to get set, or for the button to appear
};
let env = 'sandbox'; // you can set here to 'production' for production
let currency = 'EUR'; // or you can set this value from your props or state
let carttotal = this.props.carttotal; // same a s above, this is the total amount (based on currency) to be paid by using Paypal express checkout
// Document on Paypal's currency code: https://developer.paypal.com/docs/classic/api/currency_codes/
const client = {
sandbox:
'',
production: 'YOUR-PRODUCTION-APP-ID',
};
// In order to get production's app-ID, you will have to send your app to Paypal for approval first
// For sandbox app-ID (after logging into your developer account, please locate the "REST API apps" section, click "Create App"):
// => https://developer.paypal.com/docs/classic/lifecycle/sb_credentials/
// For production app-ID:
// => https://developer.paypal.com/docs/classic/lifecycle/goingLive/
// NB. You can also have many Paypal express checkout buttons on page, just pass in the correct amount and they will work!
// Style Options: https://developer.paypal.com/docs/checkout/standard/customize/buttons-style-guide/ ; https://wise.com/gb/blog/custom-paypal-button
let style = {
size: 'medium',
color: 'gold',
label: 'pay',
tagline: false,
};
return (
<PaypalExpressBtn
env={env}
client={client}
currency={currency}
total={carttotal}
onError={onError}
shipping={1}
onSuccess={onSuccess}
onCancel={onCancel}
style={style}
/>
);
}
}
CartScreen
const tranSuccess = async (payment) => {
const { paymentID } = payment;
// Check time, min amoint, for delivery add delivery fees
if (timeValidation === true) {
if (sliderDeliveryValue === 'delivery') {
if (carttotal > settings[0]?.minDeliveryAmount) {
await axios.post(
'/api/payment',
{ cartItems, paymentID, time, sliderDeliveryValue, carttotal },
{
headers: { Authorization: token },
}
);
cartItems.map((remove) => {
dispatch(deleteFromCart(remove));
});
//console.log(cartItems.length);
toast.success(
'Order successful',
{
position: toast.POSITION.TOP_RIGHT,
}
);
} else {
toast.error(
`Min amount${settings[0]?.minDeliveryAmount}€`,
{
position: toast.POSITION.TOP_RIGHT,
}
);
}
} else if (sliderDeliveryValue === 'pickup') {
if (carttotal > 2) {
await axios.post(
'/api/payment',
{ cartItems, paymentID, time, sliderDeliveryValue, carttotal },
{
headers: { Authorization: token },
}
);
cartItems.map((remove) => {
dispatch(deleteFromCart(remove));
});
//console.log(cartItems.length);
toast.success(
'Order successful',
{
position: toast.POSITION.TOP_RIGHT,
}
);
} else {
toast.error(`Min amount 2.00€`, {
position: toast.POSITION.TOP_RIGHT,
});
}
} else {
toast.error('Choose delivery method', {
position: toast.POSITION.TOP_RIGHT,
});
}
} else {
toast.error('closed', {
position: toast.POSITION.TOP_RIGHT,
});
}
};
<PayPalButton
carttotal={carttotal}
tranSuccess={tranSuccess}
/>
<div onClick={cashTranSuccess}>
<CashButton />
</div>
Consider using the official #paypal/react-paypal-js
An example of validation using onInit and onClick functions and the actions.enable/disable callbacks or returning a promise (actions.resolve/reject) can be found in the developer documentation. Adapt this to check whatever condition you need.
I am working with React-Redux-Firebase. I implemented signing in with phone number. Now I am trying to implement error handling. When number is invalid I display window alert with error message. The only thing left to do is to reset recaptcha. Without it, I am getting error:
reCAPTCHA has already been rendered in this element
I was trying to do according to Firebase documentation
grecaptcha.reset(window.recaptchaWidgetId);
// Or, if you haven't stored the widget ID:
window.recaptchaVerifier.render().then(function(widgetId) {
grecaptcha.reset(widgetId);
}
but it does not work in my code. I dont have grecaptcha implemented. I tried to add it with react-grecaptcha, but it did not work.
Could someone give me a hint how to reset recaptcha after each error, please?
state = {
phone: "",
confirmationResult: {},
};
handleClick = () => {
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
"sign-in-button",
{
size: "invisible",
}
);
firebase
.signInWithPhoneNumber(`+${this.state.phone}`, recaptchaVerifier)
.then((confirmationResult) => {
this.setState({ confirmationResult });
})
.catch((error) => {
// Error; SMS not sent
// Handle Errors Here
window.alert(`${error.code}, ${error.message}`);
recaptchaVerifier.reset(); // How can I do that?
});
};
I've been struggling with this problem for several days, maybe my answer will help someone.
export const requestRecaptchVerifier = () => {
window.recaptchaVerifier = new RecaptchaVerifier(
"recapcha-container",
{
size: "invisible",
},
auth
);
};
I then call signInWithPhone from another function and handle the error like this:
await signInWithPhone(formik.values.phone)
.then(() => {
// ... my code
})
.catch(() => {
window.recaptchaVerifier.recaptcha.reset();
window.recaptchaVerifier.clear();
});
All the difference in
window.recaptchaVerifier.recaptcha.reset()
And
window.recaptchaVerifier.clear()
I'm no expert but from the documentation and by talking with you in the comment section I think you need to pass a callback. Like this:
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
'size': 'invisible',
'callback': function(response) {
// reCAPTCHA solved, allow signInWithPhoneNumber.
firebase
.signInWithPhoneNumber(`+${this.state.phone}`, recaptchaVerifier)
.then((confirmationResult) => {
this.setState({ confirmationResult });
})
.catch((error) => {
// Error; SMS not sent
// Handle Errors Here
window.alert(`${error.code}, ${error.message}`);
recaptchaVerifier.reset();
});
}
});
Reference: https://firebase.google.com/docs/auth/web/phone-auth#use-invisible-recaptcha
Hope this helps!
I have a piece of code which updates user settings when a number input box is called in react-redux. The first portion of the code works fine: The "onChange" function gets called. But now it gets weird. onChange is called twice and the code jumps through a bunch of the react back end, touches the action creator then execution skips the entire function and exits at the closing brace.
I have many other Redux functions created using the same model that work perfectly and cannot understand why this one is not being called.
Here is my code:
mapDispatchToProps
const mapDispatchToProps = (dispatch) => {
return {
SMSAdmin_Get_Users: () => { return dispatch(SMSAdmin_Get_Users()) },
SMSAdmin_Load_User: (userId, userName, oldData = null, startVal = 0, number = 20) =>
{
return dispatch(SMSAdmin_Load_User(userId, userName, oldData, startVal, number))
},
SMSAdmin_Update_User: (user, province, credits) => { return
SMSAdmin_Update_User(user, province, credits)
},
SMSAdmin_setCurrentUpload: (userName) => { return SMSAdmin_setCurrentUpload(userName) }
};
}
Calling Input
<Form.Control type="number"
style={{ width: '100px' }}
defaultValue={this.props.SMSAdmin.user.credits}
id='numCredits'
onChange={(e) => this.updateUser(e.target)}
/>
I know that in the input I don't need to pass in the event but included it should I need it in the future for some purpose.
onChange function
//this gets called twice when making a single change in the input box
updateUser = () => {
var province = document.getElementById("provinceId");
var credits = document.getElementById("numCredits");
var user = document.getElementById("lblUser");
if (user && user.value !== '') { //safeguard to avoid trying to update nothing
//execution hits here once, then after the second hit proceeds into Redux code
this.props.SMSAdmin_Update_User(user.value, province.value, credits.value);
}
}
Redux action creator
// Execution touches here
export const SMSAdmin_Update_User = (user, province, credits) => (dispatch) => {
//then here jumps to bottom
dispatch(Actions.SMSAdmin_User_Updating());
var data = { 'mode': 'UPDATE', 'user': user, 'province': province, 'credits': credits }
var init = fetchInit();//copy to not modify the original
init.method = "POST";
init.body = JSON.stringify(data);
var myReq = new Request('/dataAPI/SMS', init);
return fetch(myReq)
.then((response) => {
if (response.ok) {
return response;
}
else {
var error = new Error("Error " + response.statusText);
error.response = response;
throw error;
}
}, (error) => {
var err = new Error(error.message);
throw err;
})
.then((response) => { return response.json() })
.then((resp) => {
handleData(dispatch, Actions.SMSAdmin_User_Updated, resp)
})
.catch((err) => {
var msg = err.message;
return dispatch(Actions.SMS_Send_Failed(msg));
});
} //touches here and exits
I think that this is all the code involved. If I am missing anything let me know and I will include it. I am baffled how execution touches the function but does not execute it, nor does Chrome debug break at a breakpoint set on the function header.
The issue is that action is not dispatched properly. dispatch is not attached to SMSAdmin_Update_User function.
Inside mapDispatchToProps, update the following:
SMSAdmin_Update_User: (user, province, credits) => {
// Add dispatch here. It is already done for other functions such as SMSAdmin_Load_User
return dispatch(SMSAdmin_Update_User(user, province, credits))
},
I'm trying to use the antd upload component and pictures wall example to upload images to my firebase storage.
Initially i tried using the action property as out lined here with the same results. I then tried using the customRequest form as outlined in the solution to that question. After struggling all day, I just can't seem to get it to work. Clearly I don't understand whats going on well enough.
My various change functions..
handleCancel = () => this.setState({ previewVisible: false });
handlePreview = async file => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
this.setState({
previewImage: file.url || file.preview,
previewVisible: true,
});
};
handleChange = (info) => {
console.log('handleChange',info);
if (info.file.status === 'uploading') {
console.log('setting loading to true');
this.setState({ loading: true });
return;
}
if (info.file.status === 'done') {
console.log('setting loading to false');
getBase64(info.file.originFileObj, imageUrl => this.setState({
imageUrl,
loading: false
}));
}
};
my customupload function..
customUpload = async ({ onError, onSuccess, file }) => {
console.log("customUpload called");
console.log(file);
const storage = firebase.storage();
const metadata = {
contentType: 'image/jpeg'
};
const storageRef = await storage.ref();
// const imageName = generateHashName() //a unique name for the image
const imgFile = storageRef.child(`Property Photos/${file}.png`);
try {
const image = await imgFile.put(file, metadata);
onSuccess(null, image);
}
catch(e) {
onError(e);
};
};
my render JSX..
<Form.Item label="Photos">
<div className="clearfix">
<Upload
listType="picture-card"
fileList={fileList}
multiple={true}
accept="image"
onPreview={this.handlePreview}
onChange={this.handleChange}
customRequest={this.customUpload}
>
{this.imageUrl ? <img src={this.imageUrl} alt="avatar" /> : uploadButton}
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
</Form.Item>
Funny enough it runs and sort of works, but seems to have three issues..
When I upload an image(s) the card/box(s) shows "Upload" with the animated spinning wheel forever. It never completes and shows the image thumbnail.
When selecting mulitple images, only the first one seems to end up on firebase. Never more..
When selecting the image(s) to upload and clicking OK, there is a long pause (5 seconds?) like the application hangs before i can click anything again. not sure why that is.
It feels like i just don't understand how to use this customRequest property..
In general, what has to be done is: connect the "onProgress", "onSuccess" and "onError" callback functions of 'antd Upload' to the corresponding event observers of cloudStorage upload function.
https://firebase.google.com/docs/storage/web/upload-files#monitor_upload_progress
So, the customRequest function can be as:
let customRequest = ({
file,
onSuccess,
onError,
onProgress,
}) => {
var uploadTask = storageRef.child(`images/${file.name}`).put(file);
// Register three observers:
// 1. 'state_changed' observer, called any time the state changes
// 2. Error observer, called on failure
// 3. Completion observer, called on successful completion
uploadTask.on(
"state_changed",
function (snapshot) {
// Observe state change events such as progress, pause, and resume
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
var progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
// CONNECT ON PROGRESS
onProgress(progress)
switch (snapshot.state) {
case firebase.storage.TaskState.PAUSED: // or 'paused'
console.log("Upload is paused");
break;
case firebase.storage.TaskState.RUNNING: // or 'running'
console.log("Upload is running");
break;
}
},
function (error) {
// Handle unsuccessful uploads
// CONNECT ON ERROR
onError(error)
},
function () {
// Handle successful uploads on complete
// For instance, get the download URL: https://firebasestorage.googleapis.com/...
uploadTask.snapshot.ref
.getDownloadURL()
.then(function (downloadURL) {
console.log("File available at", downloadURL);
// CONNECT ON SUCCESS
onSuccess(downloadURL) // Pass any parameter you would like
});
}
);
};