Sharepoint Framework with reactjs and hellojs in Internet Explorer 11 - javascript

I have a webpart with sharepoint framework and reactjs and i use hellojs --> hellojs
I do: npm install hellojs --save and all works fine in edge, chrome and firefox but i need this in Internet Explorer 11.
I try with a sample in js and html and works fine in internet explorer 11 but not in my sharepoint project. I have this:
import * as React from 'react';
import * as hello from 'hellojs';
import { Event } from '../interfaces/Event';
export class Authentication extends React.Component<{}, { sendEvent: boolean }> {
private refreshTokenInterval: number;
constructor(public props, public context) {
super(props, context);
this.state = {
sendEvent: true
};
}
public login(network) {
hello.init({
aad: {
name: 'Azure Active Directory',
oauth: {
version: 2,
auth: 'https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize',
grant: 'https://login.microsoftonline.com/tenant/oauth2/v2.0/token'
},
// Authorization scopes
scope: {
// you can add as many scopes to the mapping as you want here
profile: 'Group.Read.All',
offline_access: ''
},
scope_delim: ' ',
login: (p) => {
if (p.qs.response_type === 'code') {
// Let's set this to an offline access to return a refresh_token
p.qs.access_type = 'offline_access';
}
},
base: 'https://www.graph.microsoft.com/v1.0/',
get: {
me: 'me'
},
xhr: (p) => {
if (p.method === 'post' || p.method === 'put') {
JSON.parse(p);
} else if (p.method === 'patch') {
hello.utils.extend(p.query, p.data);
p.data = null;
}
return true;
},
// Don't even try submitting via form.
// This means no POST operations in <=IE9
form: false
}
});
hello.init(
{
aad: 'clientId'
},
{
redirect_uri: 'my redirect',
//redirect_uri: 'https://localhost:4321/temp/workbench.html',
scope: 'Group.Read.All'
}
);
// By defining response type to code, the OAuth flow that will return a refresh token to be used to refresh the access token
// However this will require the oauth_proxy server
hello(network).login({ display: 'none' }).then(
(authInfo) => {
console.log(authInfo);
localStorage.setItem('logged', authInfo.authResponse.access_token);
localStorage.setItem('timeToRefresh', authInfo.authResponse.expires_in.toString());
this.props.setEvent(Event.GET_ALL_GROUPS);
this.setState({ sendEvent: false });
clearInterval(this.refreshTokenInterval);
this.refreshTokenInterval = window.setInterval(() => {
let timeToRefresh = Number(localStorage['timeToRefresh']) - 1;
localStorage.setItem('timeToRefresh', timeToRefresh.toString());
if (timeToRefresh <= 200) {
localStorage.clear();
sessionStorage.clear();
}
}, 1000);
},
(e) => {
console.error('Signin error: ' + e.error.message);
}
);
}
public componentDidMount() {
let logged = localStorage['logged'];
if (logged === undefined) this.login('aad');
else {
if (this.state.sendEvent) {
this.props.setEvent(null);
this.props.setEvent(Event.GET_ALL_GROUPS);
}
}
}
public render() {
return null;
}
/*private logout(network) {
// Removes all sessions, need to call AAD endpoint to do full logout
hello(network).logout({ force: true }, console.log).then(
function() {
console.log('Out');
},
function(e) {
console.error('Sign out error: ' + e.error.message);
}
);
}*/
}
And i call this class in a main class:
public render(): JSX.Element {
return (
<div className="row">
<div className="col-md-2" style={{ maxWidth: '250px' }}>
<LeftPanel setEvent={this.getEvent} />
</div>
<div className="col-md-10">
<Authentication setEvent={this.getEvent} />
<CenterPanel event={this.state.event} context={this.props.context} />
</div>
</div>
);
}
Console in internet explorer 11:

Solved!
cd "folder with the package.json"
npm install url-polyfill --save
import 'url-polyfill';

Related

Amazon Connect Outbound CCP Softphone Number Prefill

I have a pretty simple requirement to click on a phone number hyperlink and have my web-app open the AWS connect soft-phone dialer with the selected number, ready for the person to press the "call button"
I have enabled an AWS connect account and I am hosting a custom CCP site via an S3 bucket (as illustrated here)
My plan is to initiate a link to the CCP page and embed a URL Search Param
"?number=04125412,customTag=helloWorld"
I have used this code on the CCP Page
Also, within the index page, I add some code to receive the input params:
<script>
var urlParams = new URLSearchParams(window.location.search);
console.log(urlParams.get('number')); //the phone number for the dialer
console.log(urlParams.get('customTag')); // the call notes for the CTR custom Attributes
</script>
I Am struggling to understand how I can interact with A: the Dialer to pre-fill the number and B: to post custom attributes to the AWS contact record during the call.
Any help would be appreciated.
I set this up in my React application but you should be able to repurpose for your needs
import React from "react";
import {connect} from 'react-redux'
import Button from "components/CustomButtons/Button.jsx";
import {receiveCallAttr, initCall, callFlow} from 'store/apps/AppSettings/actions';
class AmazonConnect extends React.Component {
constructor(props) {
super(props);
this.state = {
active:false,
reloadAttempts:0,
activeCall:{},
cip:false,
agentQueueNumber:"xxxxxxxxxx",
recordingQueueNumber:"xxxxxxxxxx"
};
this.awsConnect = this.awsConnect.bind(this)
this.loginWindow = this.loginWindow.bind(this);
this.activeWindow = this.activeWindow.bind(this);
this.initCall = this.initCall.bind(this)
this.initContact = this.initContact.bind(this)
this.redirect = this.redirect.bind(this)
}
componentWillReceiveProps(newProps){
const {AppSettings, initCall, callFlow} = newProps
const {cip, active} = this.state
if( active && !cip){
this.setState({activeCall: AppSettings.call})
if(AppSettings.call.number){
console.log("init call")
this.initCall(AppSettings.call.number)
initCall({})
}
else{
console.log("Invalid Phone number")
}
if( AppSettings.flow !== "" ){
this.setState({activeFlow: AppSettings.flow})
this.initCallFlow(AppSettings.flow)
callFlow("")
}
}
}
initCallFlow = flow => new Promise((res, rej) => {
if(this.contact){
console.log(this.contact)
let endpoint;
switch(flow){
case "agentQueue":
endpoint = window.connect.Endpoint.byPhoneNumber(this.state.agentQueueNumber);
this.contact.addConnection(endpoint, {
success: function() {
this.contact.conferenceConnections({
success: function() {
console.log("confrence success")
res("successfullly init ssn flow")
},
failure: function() {
console.log("confrence failure")
res("successfullly init ssn flow")
}
});
},
failure: function() {
rej("failed to init ssn flow")
}
});
break
case "recordingQueue":
endpoint = window.connect.Endpoint.byPhoneNumber(this.state.recordingQueueNumber);
this.contact.addConnection(endpoint, {
success: function() {
res("successfullly init recording flow")
},
failure: function() {
rej("failed to init recording flow")
}
});
break
default:
res()
break
}
}
else{
rej("no contact available")
}
})
awsConnect = () => new Promise((res, rej) => {
window.connect.core.initCCP(document.getElementById("softPhone"), {
ccpUrl: process.env.REACT_APP_AWS_CONNECT_URL, /*REQUIRED*/
loginPopup: true, /*optional, default TRUE*/
softphone: { /*optional*/
disableRingtone: false, /*optional*/
allowFramedSoftphone: true
}
});
this.bus = window.connect.core.getEventBus();
this.bus.subscribe(window.connect.AgentEvents.INIT, (agent) => {
this.activeWindow()
});
this.bus.subscribe(window.connect.EventType.TERMINATED, () => {
console.log("TERMINATED")
this.setState({cip:false})
this.logout()
});
this.bus.subscribe(window.connect.EventType.AUTH_FAIL, () => {
console.log("AUTH_FAIL")
this.logout()
})
window.connect.agent(function(agent) {
const w = window.open('', window.connect.MasterTopics.LOGIN_POPUP);
if (w) {
w.close()
}
});
window.connect.contact((contact) => {
this.contact = contact
const {receiveCallAttr} = this.props
try{
var attr = contact.getAttributes()
attr.active = true
console.log(attr)
receiveCallAttr(attr)
this.redirect()
}
catch(err){
console.log(err)
}
contact.onEnded(() => {
console.log("call ended")
receiveCallAttr({active:false})
this.setState({cip:false})
this.contact = null
})
});
res()
})
initContact = () => {
this.setState({cip:false})
}
redirect = () => {
const {location, auth, history} = this.props
switch(auth.user.type){
case "Agent":
if(location.pathname !== "/agent/management"){
history.push({
pathname: '/agent/management',
search: '',
state: {}
})
}
break;
case "Service":
//handle redirect to service page
if(location.pathname !== "/service/dashboard"){
history.push({
pathname: "/service/dashboard",
search: '',
state: {}
})
}
break;
default:
break
}
}
initCall = (phone) => {
this.initContact()
window.connect.agent(function(agent) {
const endpoint = window.connect.Endpoint.byPhoneNumber(phone)
agent.connect(endpoint , {
queueARN : process.env.CONNECT_QUEUE_ARN,
success : function(){
console.log("Success call!!!!!!")
},
failure : function(){
console.log("Call failed!!!!!!!")
}
});
});
}
logout(){
this.setState({cip:false})
this.loginWindow()
this.agent = null
this.contact = null
window.connect.core.terminate();
window.connect.core.client = new window.connect.NullClient();
window.connect.core.masterClient = new window.connect.NullClient();
window.connect.core.eventBus = new window.connect.EventBus();
window.connect.core.initialized = false;
this.bus = false;
var myNode = document.getElementById("softPhone")
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
}
}
componentWillUnmount() {
console.log("terminating aws connect session")
this.logout()
}
loginWindow(){
this.setState({active:false})
}
activeWindow(){
this.setState({active:true})
}
render() {
const displaylogin = this.state.active? "none":"block";
const displayConnect = this.state.active? "block":"none";
return (
<div>
<Button color={"rose"} onClick={this.awsConnect} style={{display:displaylogin, width:320}}>Login to AWS Connect</Button>
<div id="softPhone" style={{height:465,width:320, display:displayConnect}}>
</div>
</div>
);
}
}
function mapStateToProps(state){
return state
}
export default connect(mapStateToProps, {receiveCallAttr, initCall, callFlow})(AmazonConnect);
The previous answer by Ethan Harris helped me to reach the solution, but to distill it to allow a link to dial a number. You find the ARN in the Amazon Connect UI here:
Using the ARN copied from the Connect UI, this function seems to work for automating dialing a number. This took way more effort to figure out than I ever expected.
function dial_number(phone) {
connect.agent(function (agent) {
agent.connect(connect.Endpoint.byPhoneNumber(phone),
{
queueARN: arn
});
});
}

Vanilla JS vs React Class Binding for Listener Functions

I am following some api docs where the only code examples are in vanilla JS but I am trying to use them in React Native. They give fully functional React Native apps for reference but I can't figure out how to repurpose the methods for my needs.
In the api docs it gives the example:
ConnectyCube.videochat.onCallListener = function(session, extension) {
// here show some UI with 2 buttons - accept & reject, and by accept -> run the following code:
var extension = {};
session.accept(extension);
};
ConnectyCube is an module import and I need to use this particular method in React Native. In the app they provide as an example, it looks like this in a class component:
class AppRoot extends React.Component {
componentDidMount() {
ConnectyCube.init(...config)
this.setupListeners();
}
setupListeners() {
ConnectyCube.videochat.onCallListener = this.onCallListener.bind(this);
ConnectyCube.videochat.onUserNotAnswerListener = this.onUserNotAnswerListener.bind(this);
ConnectyCube.videochat.onAcceptCallListener = this.onAcceptCallListener.bind(this);
ConnectyCube.videochat.onRemoteStreamListener = this.onRemoteStreamListener.bind(this);
ConnectyCube.videochat.onRejectCallListener = this.onRejectCallListener.bind(this);
ConnectyCube.videochat.onStopCallListener = this.onStopCallListener.bind(this);
ConnectyCube.videochat.onSessionConnectionStateChangedListener = this.onSessionConnectionStateChangedListener.bind(this);
}
onCallListener(session, extension) {
console.log('onCallListener, extension: ', extension);
const {
videoSessionObtained,
setMediaDevices,
localVideoStreamObtained,
callInProgress
} = this.props
videoSessionObtained(session);
Alert.alert(
'Incoming call',
'from user',
[
{text: 'Accept', onPress: () => {
console.log('Accepted call request');
CallingService.getVideoDevices()
.then(setMediaDevices);
CallingService.getUserMedia(session).then(stream => {
console.log(stream)
localVideoStreamObtained(stream);
CallingService.acceptCall(session);
callInProgress(true);
});
}},
{
text: 'Reject',
onPress: () => {
console.log('Rejected call request');
CallingService.rejectCall(session);
},
style: 'cancel',
},
],
{cancelable: false},
);
}
onUserNotAnswerListener(session, userId) {
CallingService.processOnUserNotAnswer(session, userId);
this.props.userIsCalling(false);
}
onAcceptCallListener(session, userId, extension) {
CallingService.processOnAcceptCallListener(session, extension);
this.props.callInProgress(true);
}
onRemoteStreamListener(session, userID, remoteStream){
this.props.remoteVideoStreamObtained(remoteStream, userID);
this.props.userIsCalling(false);
}
onRejectCallListener(session, userId, extension){
CallingService.processOnRejectCallListener(session, extension);
this.props.userIsCalling(false);
this.props.clearVideoSession();
this.props.clearVideoStreams();
}
onStopCallListener(session, userId, extension){
this.props.userIsCalling(false);
this.props.callInProgress(false);
this.props.clearVideoSession();
this.props.clearVideoStreams();
CallingService.processOnStopCallListener(session, extension);
}
onSessionConnectionStateChangedListener(session, userID, connectionState){
console.log('onSessionConnectionStateChangedListener', userID, connectionState);
}
render() {
console.log('hey');
return <AppRouter />
}
}
function mapDispatchToProps(dispatch) {
return {
videoSessionObtained: videoSession => dispatch(videoSessionObtained(videoSession)),
userIsCalling: isCalling => dispatch(userIsCalling(isCalling)),
callInProgress: inProgress => dispatch(callInProgress(inProgress)),
remoteVideoStreamObtained: remoteStream => dispatch(remoteVideoStreamObtained(remoteStream)),
localVideoStreamObtained: localStream => dispatch(localVideoStreamObtained(localStream)),
clearVideoSession: () => dispatch(clearVideoSession()),
clearVideoStreams: () => dispatch(clearVideoStreams()),
setMediaDevices: mediaDevices => dispatch(setMediaDevices(mediaDevices)),
setActiveVideoDevice: videoDevice => dispatch(setActiveVideoDevice(videoDevice))
}
}
export default connect(null, mapDispatchToProps)(AppRoot)
I want to set up the listeners but I am not using classes like the one in the component above called CallingService or using the same redux actions - I'm taking a functional approach. When I paste the code from the docs in to a service which is just a normal function, I get the error:
Cannot set property 'onCallListener' of undefined.
Any ideas welcome!
componentDidMount() {
document.addEventListener("keyup",this.login,false);
}
login = (event) => {
console.log('i have been activated on keyup event from the componentDidMount()');
};

Is there any way to implement try again button into ionic app?

I want to create an app that has an alert for check connection with two button one is exit for the exit app and two is try again for check connection again,
I searched about it and I tried about it, but I can n't solved this problem please help me.
import { Injectable } from '#angular/core';
import { Network } from '#ionic-native/network/ngx';
import { AlertController } from '#ionic/angular';
#Injectable({
providedIn: 'root'
})
export class CheckInternetService {
public base: string; // this will be set in the constructor based on if we're in dev or prod
timer: any;
constructor(private network: Network, private alertCtrl: AlertController) {}
async presentAlert() {
const alert = await this.alertCtrl.create({
header: 'خطا',
backdropDismiss: false,
subHeader: 'قطعی انترنت',
message: 'لطفا انترنت خودرا چک کنید',
buttons: [{
text: 'خروج',
handler: () => {
navigator['app'].exitApp();
}
},
{
text: 'تلاش مجدد',
handler: () => {
this.doSomething().then(res => {
this.checkConnection();
});
}
}
],
});
await alert.present();
}
doSomething() {
return new Promise((resolve, reject) => {
// pretend a long-running task
this.timer = setTimeout(() => { resolve(true); }, 3000);
});
}
checkConnection(): boolean {
if (document.URL.includes('https://') || document.URL.includes('http://')) {
this.base = 'http://127.0.0.1:3001/';
} else {
this.base = 'https://url.to_actual_URL.com/';
}
const type = this.network.type;
let online;
if (type === 'unknown' || type === 'none' || type === undefined) {
online = false;
this.presentAlert();
} else {
online = true;
clearTimeout(this.timer);
}
this.network.onDisconnect().subscribe( () => {
online = false;
this.presentAlert();
});
this.network.onConnect().subscribe( () => {
online = true;
clearTimeout(this.timer);
});
return online;
}
}
This is my code that I was trying on, I work on this code but I do n't any answer, please help me.
You can make try again button with out any timer, you can use this code for your problem:
async presentAlert() {
this.alertCtrl.dismiss();
const alert = await this.alertCtrl.create({
header: 'خطا',
backdropDismiss: false,
subHeader: 'قطعی انترنت',
message: 'لطفا انترنت خودرا چک کنید',
buttons: [{
text: 'خروج',
handler: () => {
navigator['app'].exitApp();
}
},
{
text: 'تلاش مجدد',
// role: 'cancel',
handler: () => {
// this.doSomething().then(res => {
// this.checkConnection();
// });
const type = this.network.type;
if (type === 'unknown' || type === 'none' || type === undefined) {
this.presentAlert();
}
},
}
],
});
await alert.present();
}
I don't think you can have a alert box with two buttons because Alert box gives only one button "OK" to select and proceed. . You can show a modal instead of a alert box with as much button as you want.

Remove class for another user vue.js

I have chat message system.
I have code:
<template>
<li :class="className">
{{ message }}
</li>
</template>
<script>
export default {
props: [
'message',
'user',
'time',
'seen',
],
computed: {
className() {
return this.seen;
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>
App.js:
data:{
message: '',
convId: 1,
chat: {
message: [],
user: [],
time: [],
seen: [],
},
typing: '',
},
....
watch: {
message() {
Echo.private('chat')
.whisper('typing', {
name: this.message
});
}
},
methods: {
send(){
if(this.message.length != 0 && this.message.length <= 4000) {
this.chat.message.push(this.message);
this.chat.user.push('you');
this.chat.time.push(this.getTime());
this.chat.seen.push('unread'). //set class unread message for user
axios.post('/sendMessage', {
message: this.message,
//lastName: 'Flintstone'
})
.then(response => {
console.log(response);
this.message = '';
})
.catch(error => {
console.log(error);
});
}
},
seenMessage() {
axios.post('/setMessagesSeen/' + this.convId) //this request mark messages in chat all readed for auhenticated user
.then( response => { this.chat.seen.push(''); //remove unread class })
.catch( response => { console.log(response) } )
},
getTime() {
let time = new Date();
return time.getHours() + ':' + time.getMinutes();
}
},
mounted() {
Echo.private('chat')
.listen('ChatEvent', (e) => {
this.chat.message.push(e.message);
this.chat.user.push(e.user);
this.chat.time.push(this.getTime());
this.chat.seen.push('unread'). //set class unread message for user
console.log(e);
})
.listenForWhisper('typing', (e) => {
if(e.name != '')
this.typing = 'typing..';
else
this.typing = null;
});
}
My chat.blade.php:
<message v-for="value,index in chat.message"
:key=value.index
:user=chat.user[index]
:message="chat.message[index]"
:time="chat.time[index]"
:seen="chat.seen[index]"
>
</message>
<div class="form-group">
<textarea maxlength="4000" cols="80" rows="3" class="message-input form-control" v-model='message' v-on:click="seenMessage"></textarea>
</div>
<div class="form-group">
<button type="button" class="btn btn-lg btn-primary" v-on:click="send">Send message</button>
</div>
My function seen:
public function setMessagesSeen(Conversation $conversation) {
$user = User::find(Auth::id());
$conversations = Chat::conversation($conversation->id);
//$dd = Chat::conversations($conversation)->for($user)->readAll();
dd(Chat::conversations($conversations)->for($user)->getMessages()->where('body', 'asdfsadfsd'));
//$message = Chat::messages($message)->for($user)->markRead();
broadcast(new HasSeenMessage($message));
return response('ok');
}
How I can send class "unread" to element div other user? I can paste class on current user, and I get color on element chat only for me, but how I can hide element for me and other user, when message is seen?
I want do read/unread function for users.
Example:
If user in real time send message I send class unread, when other user click on textarea, I remove class unread, and said user, that message is seen. How I can do it in real time add/remove class unread? My function is not working.
To do this you have to create an Event in your Laravel application that you will broadcast on a precise channel (you can for example give the name 'chat. {Conversation}. {User_id}') and with Laravel Echo you will listen this event!
I allowed myself to make some changes in your code -:)
I presume you have this class HasSeenEvent
<?php
namespace App\Events;
use App\Order;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class HasSeenEvent implements ShouldBroadcast
{
use SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #param Message $message
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
public function broadcastOn()
{
// I presume we can get conversation id like this : $this->message->conversation->id
return new PrivateChannel('chat.'.$this->message->conversation->id.'.'.$this->message->sender->id);
}
}
Then, in your routes/broadcast.php declare this route chat.{conversation}.{user_id}
In the function where you put the 'seen' to 1 you broadcast the event at the same time
broadcast(new HasSeenMessage($message))
Then you listen to this event in your vuejs code
components/Message.js
<template>
<li :class="className">
{{ message }}
</li>
</template>
<script>
export default {
props: [
'message',
'user',
'time',
'readed',
],
computed: {
className() {
return this.readed == 1 ? 'seen' : 'unread';
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>
chat.blade.php
<message v-for="message,index in chat.messages"
:key="index"
:user="message.user"
:message="message.content"
:time="message.time"
:readed="message.readed"
>
</message>
<div class="form-group">
<button type="button" class="btn btn-lg btn-primary" v-on:click="send">Send message</button>
</div>
App.js
data: {
message: '',
convId: 1,
chat: {
messages: [],
/* message: [],
user: [],
time: [],
seen: [], */
},
typing: '',
},
....
watch: {
message() {
Echo.private('chat')
.whisper('typing', {
name: this.message
});
}
},
methods: {
send() {
if (this.message.length != 0 && this.message.length <= 4000) {
let data = {
content: this.message,
user: 'you',
time:this.getTime(),
readed: 0
}
this.chat.messages.push(data)
data = {}
axios.post('/sendMessage', {
message: this.message,
//lastName: 'Flintstone'
})
.then(response => {
console.log(response);
this.message = '';
})
.catch(error => {
console.log(error);
});
}
},
seenMessage() {
axios.post('/setMessagesSeen/' + this.convId) //this request mark messages in chat all readed for auhenticated user
.then(response => {
//This is not the best way to do that
this.chat.messages[this.messages.length -1 ].readed = 0
}).catch(response => {
console.log(response)
})
},
getTime() {
let time = new Date();
return time.getHours() + ':' + time.getMinutes();
}
},
mounted() {
Echo.private('chat')
.listen('ChatEvent', (e) => {
this.chat.messages.push({
content: e.message,
user: e.user,
time: this.getTime(),
readed: 0
})
console.log(e);
})
.listenForWhisper('typing', (e) => {
if (e.name != '')
this.typing = 'typing..';
else
this.typing = null;
});
// I presume to can access to user info
let that = this
Echo.private('chat.'+convId+'.'+user.id)
.listen('HasSeenMessage', (e) => {
let message = e.message
let lookingForMessage = that.chat.messages.find((m) => {
// I presume in your db messages table has field content and time
return m.content == message.content && m.time => message.time
})
try {
lookingForMessage.readed = 1
}catch (err){
// message not found
console.log(err)
}
})
}
Hope it helped you!

Where the client dom got attached to the react dom for filestack-react?

This question is for someone very good with react as well as understand filestack-js
I read the whole source code for src/ReactFilestack.jsx but I can't find the part where filestack attach itself to the dom.. somehow it just magically .. did without using ref or ReactDom whatsoever.
if possible anyone can point me to the line that the dom attachment
from client to <Tag> happens?https://github.com/filestack/filestack-react/blob/master/src/ReactFilestack.jsx
Thanks!
import React, { Component } from 'react';
import filestack from 'filestack-js';
import PropTypes from 'prop-types';
class ReactFilestack extends Component {
static defaultProps = {
file: null,
link: false,
buttonText: 'Pick file',
buttonClass: '',
onSuccess: result => console.log(result),
onError: error => console.error(error),
mode: 'pick',
options: {},
security: null,
children: null,
render: null,
cname: null,
};
static propTypes = {
file: PropTypes.objectOf(PropTypes.any),
apikey: PropTypes.string.isRequired,
link: PropTypes.bool,
mode: PropTypes.string,
buttonText: PropTypes.string,
buttonClass: PropTypes.string,
onSuccess: PropTypes.func,
onError: PropTypes.func,
options: PropTypes.objectOf(PropTypes.any),
security: PropTypes.objectOf(PropTypes.any),
children: PropTypes.node,
render: PropTypes.func,
cname: PropTypes.string,
};
onClickPick = (event) => {
event.stopPropagation();
event.preventDefault();
const {
apikey,
onSuccess,
onError,
options,
mode,
file,
security,
cname
} = this.props;
const onFinished = (result) => {
if (typeof onSuccess === 'function') {
onSuccess(result);
} else {
console.log(result);
}
};
const onFail = (error) => {
if (typeof onError === 'function') {
onError(error);
} else {
console.error(error);
}
};
this.initClient(mode, apikey, options, file, security, cname)
.then(onFinished)
.catch(onFail);
};
initClient = (mode, apikey, options, file, security, cname) => {
const { url, handle } = options;
delete options.handle;
delete options.url;
const client = filestack.init(apikey, security, cname);
if (mode === 'transform') {
return new Promise((resolve, reject) => {
try {
resolve(client.transform(url, options));
} catch (err) {
reject(err);
}
});
} else if (mode === 'retrieve') {
return client.retrieve(handle, options);
} else if (mode === 'metadata') {
return client.metadata(handle, options);
} else if (mode === 'storeUrl') {
return client.storeURL(url, options);
} else if (mode === 'upload') {
return client.upload(file, options);
} else if (mode === 'remove') {
return client.remove(handle, security);
}
return client.pick(options);
};
render () {
const { buttonClass, buttonText, link, children, render: CustomRender } = this.props;
if (CustomRender) {
return (
<CustomRender onPick={this.onClickPick} />
);
}
const Tag = link ? 'a' : 'button';
return (
<Tag
name="filestack"
onClick={this.onClickPick}
className={buttonClass}
>
{children || buttonText}
</Tag>
);
}
}
export default ReactFilestack;
Looking at the code and the docs, it appears that when triggering an action filestack will append a div to the dom and put its UI in it. The UI displays as a modal and there is no way to mount it within a react component using the package you linked.
Nowadays they could use portals to make the UI a child of its parent react component.
This behaviour can be observed by looking in the Dom inspector. You should see a div appear in the bottom of the document. It did not create a 'dom' but only a dom element and mounted their ui on it.

Categories