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

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.

Related

Vue component using axios to update a preference

I am trying to update a preference, example UI attached. The default is yes but a user should have the option to select no. I know I am a little way off but I just need some help identifying where I am going wrong, any help would be really appreciated.
Parent:
<CommunicationPreference
v-for="(communication, index) in communicationPreferenceType"
:key="index + communication.name"
:consent="communication.consent"
:name="communication.name"
#accept-consent="acceptConsent"
#decline-consent="declineConsent"
/>
methods: {
async acceptConsent() {
await this.$store.dispatch('account/updateCommunicationPreferences')
},
async declineConsent() {
await this.$store.dispatch('account/updateCommunicationPreferences')
},
}
CommunicationPreference.vue component:
<Button
:text="Yes"
:type="consent === true ? 'primary' : 'secondary'"
#clicked="acceptConsent"
/>
<Button
:text="No"
:type="consent !== true ? 'primary' : 'secondary'"
#clicked="declineConsent"
/>
methods: {
acceptConsent(consent) {
this.$emit('accept', consent === true)
},
declineConsent(consent) {
this.$emit('decline', consent === false)
},
},
Store:
async updateCommunicationPreferences({ commit, state }) {
const { communicationTypeName } = state.communicationTypeName
if (!communicationTypeName) {
return
}
try {
const response = await this.$axios.put(`/communication-consent/${communicationTypeName}`)
const { data: updatedCommunicationPreferences } = response.data
commit('SET_UPDATED_COMMUNICATION_PREFERENCES', updatedCommunicationPreferences)
} catch (error) {
commit('ADD_ERROR', { id: 'updateCommunicationPreferences', error }, { root: true })
}
},
As mentioned in the comments, the name of the method called is incorrect.
As mentioned by #qimolin, the values related to each option are not being passed to the function that saves it, this can be done by passing a value at calling the action.
methods: {
async acceptConsent() {
await this.$store.dispatch('account/updateCommunicationPreferences', { consent: true })
},
async declineConsent() {
await this.$store.dispatch('account/updateCommunicationPreferences', { consent: false })
}
or even that simplified with a single method
<CommunicationPreference
v-for="(communication, index) in communicationPreferenceType"
:key="index + communication.name"
:consent="communication.consent"
:name="communication.name"
#accept-consent="acceptConsent(true)"
#decline-consent="declineConsent(false)"
/>
methods: {
async updateConsent(consent) {
await this.$store.dispatch('account/updateCommunicationPreferences', { consent })
}
}
and that parameter must be captured on action
async updateCommunicationPreferences({ commit, state }, payload) {
const { consent } = payload // true or false. This is the value selected by the user.
const { communicationTypeName } = state.communicationTypeName
if (!communicationTypeName) {
return
}
try {
const response = await this.$axios.put(`/communication-consent/${communicationTypeName}`)
const { data: updatedCommunicationPreferences } = response.data
commit('SET_UPDATED_COMMUNICATION_PREFERENCES', updatedCommunicationPreferences)
} catch (error) {
commit('ADD_ERROR', { id: 'updateCommunicationPreferences', error }, { root: true })
}
},

Quasar QSelect is not opening when performing AJAX call

I have been trying to create a simple auto complete using Quasar's select but I'm not sure if this is a bug or if I'm doing something wrong.
Problem
Whenever I click the QSelect component, it doesn't show the dropdown where I can pick the options from.
video of the problem
As soon as I click on the QSelect component, I make a request to fetch a list of 50 tags, then I populate the tags to my QSelect but the dropdown doesn't show.
Code
import type { PropType } from "vue";
import { defineComponent, h, ref } from "vue";
import type { TagCodec } from "#/services/api/resources/tags/codec";
import { list } from "#/services/api/resources/tags/actions";
import { QSelect } from "quasar";
export const TagAutoComplete = defineComponent({
name: "TagAutoComplete",
props: {
modelValue: { type: Array as PropType<TagCodec[]> },
},
emits: ["update:modelValue"],
setup(props, context) {
const loading = ref(false);
const tags = ref<TagCodec[]>([]);
// eslint-disable-next-line #typescript-eslint/ban-types
const onFilterTest = (val: string, doneFn: (update: Function) => void) => {
const parameters = val === "" ? {} : { title: val };
doneFn(async () => {
loading.value = true;
const response = await list(parameters);
if (val) {
const needle = val.toLowerCase();
tags.value = response.data.data.filter(
(tag) => tag.title.toLowerCase().indexOf(needle) > -1
);
} else {
tags.value = response.data.data;
}
loading.value = false;
});
};
const onInput = (values: TagCodec[]) => {
context.emit("update:modelValue", values);
};
return function render() {
return h(QSelect, {
modelValue: props.modelValue,
multiple: true,
options: tags.value,
dense: true,
optionLabel: "title",
optionValue: "id",
outlined: true,
useInput: true,
useChips: true,
placeholder: "Start typing to search",
onFilter: onFilterTest,
"onUpdate:modelValue": onInput,
loading: loading.value,
});
};
},
});
What I have tried
I have tried to use the several props that is available for the component but nothing seemed to work.
My understanding is that whenever we want to create an AJAX request using QSelect we should use the onFilter event emitted by QSelect and handle the case from there.
Questions
Is this the way to create a Quasar AJAX Autocomplete? (I have tried to search online but all the answers are in Quasar's forums that are currently returning BAD GATEWAY)
What am I doing wrong that it is not displaying the dropdown as soon as I click on the QSelect?
It seems updateFn may not allow being async. Shift the async action a level up to solve the issue.
const onFilterTest = async (val, update /* abort */) => {
const parameters = val === '' ? {} : { title: val };
loading.value = true;
const response = await list(parameters);
let list = response.data.data;
if (val) {
const needle = val.toLowerCase();
list = response.data.data.filter((x) => x.title.toLowerCase()
.includes(needle));
}
update(() => {
tags.value = list;
loading.value = false;
});
};
I tested it by the following code and mocked values.
// import type { PropType } from 'vue';
import { defineComponent, h, ref } from 'vue';
// import type { TagCodec } from "#/services/api/resources/tags/codec";
// import { list } from "#/services/api/resources/tags/actions";
import { QSelect } from 'quasar';
export const TagAutoComplete = defineComponent({
name: 'TagAutoComplete',
props: {
modelValue: { type: [] },
},
emits: ['update:modelValue'],
setup(props, context) {
const loading = ref(false);
const tags = ref([]);
const onFilterTest = async (val, update /* abort */) => {
// const parameters = val === '' ? {} : { title: val };
loading.value = true;
const response = await new Promise((resolve) => {
setTimeout(() => {
resolve({
data: {
data: [
{
id: 1,
title: 'Vue',
},
{
id: 2,
title: 'Vuex',
},
{
id: 3,
title: 'Nuxt',
},
{
id: 4,
title: 'SSR',
},
],
},
});
}, 3000);
});
let list = response.data.data;
if (val) {
const needle = val.toLowerCase();
list = response.data.data.filter((x) => x.title.toLowerCase()
.includes(needle));
}
update(() => {
tags.value = list;
loading.value = false;
});
};
const onInput = (values) => {
context.emit('update:modelValue', values);
};
return function render() {
return h(QSelect, {
modelValue: props.modelValue,
multiple: true,
options: tags.value,
dense: true,
optionLabel: 'title',
optionValue: 'id',
outlined: true,
useInput: true,
useChips: true,
placeholder: 'Start typing to search',
onFilter: onFilterTest,
'onUpdate:modelValue': onInput,
loading: loading.value,
});
};
},
});

Clearcache is not defined

I created this script, however the cache cleaning warning appears in the debug console which is not defined. How can I solve it?
I uploaded the code here https://codepen.io/stiac/pen/ExPjgwe
class NotificationBanner {
constructor(el) {
this.storageKey = 'notifications'
this.el = el
this.id = this.el.dataset.id
this.el.querySelector(".closebutton").onclick = () => this.close()
this.showUnlessDismissed()
}
show() {
this.el.hidden = false
}
close() {
this.el.remove()
this.updateLocalStorage()
}
showUnlessDismissed() {
if(this.getLocalStorage().includes(this.id)) {
this.close()
}
else {
this.show()
}
}
updateLocalStorage() {
const dismissedNotifications = this.getLocalStorage()
if(!dismissedNotifications.includes(this.id)) {
dismissedNotifications.push(this.id)
localStorage.setItem(this.storageKey, JSON.stringify(dismissedNotifications))
}
}
getLocalStorage() {
return JSON.parse(localStorage.getItem(this.storageKey)) || []
}
}
class NotificationBanners {
constructor() {
const notifications = [...document.querySelectorAll(".notification-banner")];
notifications.forEach(function(notification) {
return new NotificationBanner(notification);
})
}
}
new NotificationBanners()
clearcache.onclick = e => localStorage.setItem('notifications', JSON.stringify([]))
It is a script to hide a message. I wish I could set a deadline to make it appear after a few days.

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
});
});
}

Call Service to open a dialog depend on setTimeout

Hi As I am new to angular 4 I am facing some issue like "Uncaught Error: Can't resolve all parameters for" or Cyclic dependence . I have written a service which does a calculation and in setTimeout I am calling to open the MatDialog . Matdialog has two option 'Yes' or 'no' on click of the 'Yes' doing some service call and doing some calculation and again setting clearTimeout and setting new setTimeout which again open the popup after some time.
And I want to also check on each service call and depending on some condition I have again clearTimeout and set a new setTimeout which open the MatDialog .
I trying this since long time but would not find a solution . I want know Where is the right place that I can place my code and How to write service to open the Matdialog .
Written this code in main.components.ts
setTimer() {
this.notifyTime = expiryValue - 120000;
this.date1 = new Date();
this.date2 = new Date(this.notifyTime);
this.diff = this.date2.getTime() - this.date1.getTime();
let _self = this;
this.timerVar = setTimeout(function () {
let dialogRef = _self.dialog.open(DialogModalComponent, {
data: {
timer: _self.timerVar,
va: true
}
});
}, this.diff);
}
clearTimer() {
clearTimeout(this.timerVar);
}
The above is a piece of code I am using to setTimeout() and clearTimeout()
Written this code in global service where
temp points to another to main.component.ts
autoLoad() {
if (this.expiryValue) {
this.date1 = new Date();
this.diff = this.expiryValue - this.date1.getTime();
if (this.diff < 600000 && this.diff > 120000) {
this.getUpUrl('refresh').then(result => {
if (result.status == 'success') {
this.temp.clearTimer();
this.temp.showDialog(result.sessionExpiry);
}
});
}
}
And in the dialog.component.ts
ok() {
this.dialog.close();
this.temp.clearTimer();
this.temp.setTimer();
}
cancel() {
this.dialog.close();
}
The above code I am using in the dialog. temp points to my main.component.ts
you can use a setTimeout function to open a dialog after some time
this example based on angular material examples
constructor(public _dialogService: DialogService) { }
openDialog(): void {
this.clicked = true;
this._dialogService.open({ name: this.name, animal: this.animal }, () => this.clicked = false)
.then(result => {
console.log('The dialog was closed');
this.animal = result;
})
}
dialog service
#Injectable({
providedIn:'root'
})
export class DialogService {
constructor(private dialog: MatDialog) { }
open(data , onOpenCallBack , timeout:number = 2500) : Promise<any> {
return new Promise((resolve) => {
setTimeout(() => {
const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
width: '250px',
data: data
});
if (onOpenCallBack) {
onOpenCallBack()
}
dialogRef.afterClosed().subscribe(result => {
resolve(result)
});
}, timeout)
})
}
}
stackblitz demo

Categories