Array property in javascript class - javascript

I have this javascript class in which I have declared two properties and I have problems with the first one. I am trying to handle the tokens with Firebase in a project with node.js and react.js
export default class NoNotificationResource {
allTokens = [];
tokensLoaded = false;
constructor(messaging, database) {
this.database = database;
this.messaging = messaging;
try {
this.messaging.requestPermission().then(res => {
console.log('Permiso concedido');
}).catch(err => {
console.log('no acces', err);
});
} catch (err) {
console.log('NO hay soporte para notificaciones', err);
};
this.setupTokenRefresh();
this.database.ref('/fcmTokens').on('value', snapshot => {
this.allTokens = snapshot.val();
this.tokensLoaded = true;
})
};
setupTokenRefresh(){
this.messaging.onTokenRefresh(() => {
this.saveTokenToServer();
})
};
saveTokenToServer(){
this.messaging.getToken().then(res => {
if (this.tokensLoaded) {
const existingToken = this.findExistingToken(res);
if (existingToken) {
//Reemplazar token
} else {
//Crear nuevo token
}
}
});
}
findExistingToken(tokenToSave){
for(let tokenKey in this.allTokens){
const token = this.allTokens[tokenKey].token;
if (token === tokenToSave) {
return tokenKey;
}
}
return false;
}
}

Without the linter it doesn't show any errors (I modified your code so it doesn't look for services it cannot reach).
The only change is that I moved allTokens into the constructor - more:
Declare a class property outside of a class method
Private properties in JavaScript ES6 classes
I added a "manual" setToken to show that this.allTokens works.
'use strict'; // just to make sure
class NoNotificationResource {
tokensLoaded = false;
constructor(messaging, database) {
this.allTokens = [];
this.database = database;
this.messaging = messaging;
try {
this.messaging.requestPermission().then(res => {
console.log('Permiso concedido');
}).catch(err => {
console.log('no acces', err);
});
} catch (err) {
console.log('NO hay soporte para notificaciones', err);
};
if (this.messaging) {
this.setupTokenRefresh();
this.database.ref('/fcmTokens').on('value', snapshot => {
this.allTokens = snapshot.val();
this.tokensLoaded = true;
})
}
};
setupTokenRefresh() {
if (this.messaging && this.messaging.onTokenRefresh) {
this.messaging.onTokenRefresh(() => {
this.saveTokenToServer();
})
}
};
saveTokenToServer() {
this.messaging.getToken().then(res => {
if (this.tokensLoaded) {
const existingToken = this.findExistingToken(res);
if (existingToken) {
//Reemplazar token
} else {
//Crear nuevo token
}
}
});
}
findExistingToken(tokenToSave) {
for (let tokenKey in this.allTokens) {
const token = this.allTokens[tokenKey].token;
if (token === tokenToSave) {
return tokenKey;
}
}
return false;
}
// setting tokens "manually"
setToken(val) {
// checking if the token is already in the allTokens array
// and only add the token, if it's not
if (!this.allTokens.includes(val)) this.allTokens.push(val)
return this
}
}
const n = new NoNotificationResource()
n.findExistingToken(123)
console.log(n.setToken(123))

You can declare these two variable i.e., allTokens, tokensLoaded outside the class.
Ex:-
let allTokens = [];
let tokensLoaded = false;
export default class NoNotificationResource {
constructor(messaging, database) {
this.database = database;
this.messaging = messaging;
try {
this.messaging.requestPermission().then(res => {
console.log('Permiso concedido');
}).catch(err => {
console.log('no acces', err);
});
} catch (err) {
console.log('NO hay soporte para notificaciones', err);
};
this.setupTokenRefresh();
this.database.ref('/fcmTokens').on('value', snapshot => {
this.allTokens = snapshot.val();
this.tokensLoaded = true;
})
};
setupTokenRefresh(){
this.messaging.onTokenRefresh(() => {
this.saveTokenToServer();
})
};
saveTokenToServer(){
this.messaging.getToken().then(res => {
if (this.tokensLoaded) {
const existingToken = this.findExistingToken(res);
if (existingToken) {
//Reemplazar token
} else {
//Crear nuevo token
}
}
});
}
findExistingToken(tokenToSave){
for(let tokenKey in this.allTokens){
const token = this.allTokens[tokenKey].token;
if (token === tokenToSave) {
return tokenKey;
}
}
return false;
}
}
Or you can put it inside constructor like this this.allTokens=[];,this.tokensLoaded=false;

Related

Rxdb infinitely pulling in replicateRxCollection

I'm working with rxdb and I have pull and push handlers for the backend I have used supabase
I have setup the code for replication as follows:
replication.ts
import { RxDatabase } from "rxdb";
import { RxReplicationPullStreamItem } from "rxdb/dist/types/types";
import { replicateRxCollection } from "rxdb/plugins/replication";
import { Subject } from "rxjs";
import { supabaseClient, SUPABASE_URL } from "src/config/supabase";
import { DbTables } from "src/constants/db";
import {
blockPullHandler,
blockPushHandler,
} from "./repilicationhandlers/block";
import { CheckpointType, RxBlockDocument, RxBlocksCollections } from "./types";
export async function startReplication(
database: RxDatabase<RxBlocksCollections>
) {
const pullStream$ = new Subject<
RxReplicationPullStreamItem<RxBlockDocument, CheckpointType>
>();
supabaseClient
.from(DbTables.Block)
.on("*", (payload) => {
console.log("Change received!", payload);
const doc = payload.new;
pullStream$.next({
checkpoint: {
id: doc.id,
updated: doc.updated,
},
documents: [doc] as any,
});
})
.subscribe((status: string) => {
console.log("STATUS changed");
console.dir(status);
if (status === "SUBSCRIBED") {
pullStream$.next("RESYNC");
}
});
const replicationState = await replicateRxCollection({
collection: database.blocks,
replicationIdentifier: "supabase-replication-to-" + SUPABASE_URL,
deletedField: "archived",
pull: {
handler: blockPullHandler as any,
stream$: pullStream$.asObservable(),
batchSize: 10,
},
push: {
batchSize: 1,
handler: blockPushHandler as any,
},
});
replicationState.error$.subscribe((err) => {
console.error("## replicationState.error$:");
console.log(err);
});
return replicationState;
}
blockPullHandler:
export const blockPullHandler = async (
lastCheckpoint: any,
batchSize: number
) => {
const minTimestamp = lastCheckpoint ? lastCheckpoint.updated : 0;
console.log("Pulling data", batchSize, lastCheckpoint);
const { data, error } = await supabaseClient
.from(DbTables.Block)
.select()
.gt("updated", minTimestamp)
.order("updated", { ascending: true })
.limit(batchSize);
if (error) {
console.log(error);
throw error;
}
const docs: Array<Block> = data;
return {
documents: docs,
hasMoreDocuments: false,
checkpoint:
docs.length === 0
? lastCheckpoint
: {
id: lastOfArray(docs).id,
updated: lastOfArray(docs).updated,
},
};
};
blockPushHandler:
export const blockPushHandler = async (
rows: RxReplicationWriteToMasterRow<RxBlockDocumentType>[]
) => {
if (rows.length !== 1) {
throw new Error("# pushHandler(): too many push documents");
}
const row = rows[0];
const oldDoc: any = row.assumedMasterState;
const doc: Block = row.newDocumentState;
console.log(row, oldDoc, doc);
// insert
if (!row.assumedMasterState) {
const { error } = await supabaseClient.from(DbTables.Block).insert([doc]);
console.log("Error 1", error);
if (error) {
// we have an insert conflict
const conflictDocRes: any = await supabaseClient
.from(DbTables.Block)
.select()
.eq("id", doc.id)
.limit(1);
return [conflictDocRes.data[0]];
} else {
return [];
}
}
// update
console.log("pushHandler(): is update");
const { data, error } = await supabaseClient
.from(DbTables.Block)
.update(doc)
.match({
id: doc.id,
replicationRevision: oldDoc.replicationRevision,
});
console.log("Error 2", error);
if (error) {
console.log("pushHandler(): error:");
console.log(error);
console.log(data);
throw error;
}
console.log("update response:");
console.log(data);
if (data.length === 0) {
// we have an updated conflict
const conflictDocRes: any = await supabaseClient
.from(DbTables.Block)
.select()
.eq("id", doc.id)
.limit(1);
return [conflictDocRes.data[0]];
}
return [];
};
But the issue is when I start the application and the pull handler is called correctly but it doesn't stop calling the pull handler and it sends continuous request one after another even after it has fetched the documents even when I set hasMoreDocuments to false It keeps sending requests and running the replicator. Is there something wrong with my configuration?
database.ts:
export const createDatabase = async () => {
const database = await createRxDatabase({
name: "sundaedb",
storage: getRxStorageDexie(),
});
await database.addCollections({
blocks: {
schema: blockSchema as any,
conflictHandler: conflictHandler as any,
},
documents: {
schema: documentSchema as any,
conflictHandler: conflictHandler as any,
},
});
database.blocks.preInsert((docData) => {
docData.replicationRevision = createRevision(
database.hashFunction,
docData as any
);
return docData;
}, false);
database.blocks.preRemove((docData) => {
console.log(" PRE REMOVE !!");
console.log(JSON.stringify(docData, null, 4));
const oldRevHeight = parseRevision(docData.replicationRevision).height;
docData.replicationRevision =
oldRevHeight + 1 + "-" + database.hashFunction(JSON.stringify(docData));
console.log(JSON.stringify(docData, null, 4));
return docData;
}, false);
database.blocks.preSave((docData) => {
const oldRevHeight = parseRevision(docData.replicationRevision).height;
docData.replicationRevision =
oldRevHeight + 1 + "-" + database.hashFunction(JSON.stringify(docData));
return docData;
}, false);
return database;
};

trying to store api responses in asyncstorage but I am unable to store it

here I have pasted code which is written class component for mobx state management and i am calling it to another file,the thing is I have above 450 api responses and it need to store locally so i have tried it but i am not getting any value nor the data stored in database pls help me out thanks in advance ..
class ProductStore {
constructor() {
makeAutoObservable(this);
}
screenWidth = width;
screenHeight = height;
headerHeight = 0;
isiOS = Platform.OS === 'ios';
isAndroid = Platform.OS === 'android';
isProductLoading = 'pending';
productData = [];
filterdData = [];
search = '';
isFlatlistRender = false;
setFields(eName, data) {
this[eName] = data;
console.log(eName, data);
}
getproductData = () => {
if (this.isProductLoading == 'loading') {
return true;
}
this.isProductLoading = 'loading';
this.productData = [];
let headers = new Headers();
headers.set(
'Authorization',
'Basic ' + encode('username:password'),
);
fetch('some_url', {
method: 'GET',
headers: headers,
})
.then(response => response.json())
.then(responseJson => {
console.log('.....', responseJson);
AsyncStorage.setItem(
'ACCESS_TOKEN',
JSON.stringify(responseJson),
err => {
if (err) {
console.log('an error');
throw err;
}
console.log('success');
},
).catch(err => {
console.log('error is: ' + err);
});
try {
const value = AsyncStorage.getItem('ACCESS_TOKEN');
if (value !== null) {
console.log(JSON.parse(value));
}
} catch (error) {}
this.productData = responseJson;
this.isProductLoading = 'done';
})
.catch(error => {
console.error(error);
this.isProductLoading = 'error';
});
};
}
export default new ProductStore();
AsyncStorage.getItem() returns a promise, not the value. So, just add a then block after the line AsyncStorage.getItem('ACCESS_TOKEN');. It would be like this
AsyncStorage.getItem('ACCESS_TOKEN').then(value => {
if (value !== null) {
console.log(JSON.parse(value));
}
}).catch(err => console.error(err));

Getting a nested parameter return value in the wrapped function return

I have a scenario where I need to get the return value from a function that passed to another function as a parameter. I tried multiple ways. But couldn't get the returnValue to the CreateProfileComponent from ProfileAction.js file.
// ProfileAction.js
export default (database) => {
return {
createProfile: async (createdProfile) => {
const profileCollection = database.get("profiles");
const { name, email } = createdProfile;
try {
await database.action(async () => {
const returnValue = await profileCollection.create((profile) => {
profile.name = name;
profile.email = email;
});
});
} catch (error) {
console.log("createProfile", error);
}
},
};
};
// CreateProfileComponent.js
const CreateProfileComponent = () => {
const database = useDatabase();
const profileAction = ProfileAction(database);
const createdRecord = await profileAction.createProfile({
name: "John Doe",
email: "johndoe#gmail.com",
});
}
Finally what I want is the returnValue value in CreateProfileComponent. The functions database.actions() and profileCollection.create() are used from a third party library (WatermelonDB)
I am not sure what database.action does but you should return a value in this function. Like following: return await database.action(async () => {
And throw an error on catch
export default (database) => {
return {
createProfile: async (createdProfile) => {
const profileCollection = database.get("profiles");
const { name, email } = createdProfile;
try {
return await database.action(async () => {
const returnValue = await profileCollection.create((profile) => {
profile.name = name;
profile.email = email;
});
});
} catch (error) {
console.log("createProfile", error);
throw error;
}
},
};
};
// CreateProfileComponent.js
const CreateProfileComponent = () => {
const database = useDatabase();
const profileAction = ProfileAction(database);
try {
const createdRecord = await profileAction.createProfile({
name: "John Doe",
email: "johndoe#gmail.com",
});
} catch (e) {
}
}

Not able to get Gmail Read-Only mails using Gmail API. The languages used here are html and javascript

I have written three files which are: home-flatfull.jsp, settings-social-prefs.html and
google-js-api-wrapper.js files.
In home-flatfull.jsp file, I have written as below:
head.js('jscore/lib/base64.js', 'jscore/lib/google-js-api.js', 'jscore/lib/google-js-api-wrapper.js', function () {
var config = {
apiKey: 'AIzaSyCa52K8J68kr5b4S7Afu1FQzeleCfvzOFs',
clientId: '492662354647-877atvgj1a0pu82nrutsm50rcmg0lufh.apps.googleusercontent.com',
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"],
scopes: 'https://www.googleapis.com/auth/gmail.readonly',
listener: function(response){
console.log(' Check google ');
console.log(response);
}
};
googleJSAPI = GoogleJSAPI.getInstance(config);
});
In settings-social-prefs.html file I have defined as below:
<a onclick="googleJSAPI.signIn()" class="btn btn-sm btn-default">
{{agile_lng_translate 'prefs-email' 'enable'}}
</a>
In google-js-api-wrapper.js file, I have defined as below:
class GoogleJSAPI {
emailRegx = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
instance;
isActive = false;
constructor(config) {
console.log(' google code loaded ');
gapi.load('client:auth2', () => {
gapi.client.init({
apiKey: config.apiKey,
clientId: config.clientId,
discoveryDocs: config.discoveryDocs,
scope: config.scopes
}).then(() => {
this.isActive = true;
console.log(' config loaded ');
gapi.auth2.getAuthInstance().isSignedIn.listen(config.listener);
}, (error) => {
this.isActive = false;
console.log(JSON.stringify(error, null, 2));
});
});
}
static getInstance(config) {
if (!this.instance) {
this.instance = new GoogleJSAPI(config);
}
return this.instance;
}
isActive() {
return this.isActive;
}
isUserLoggedIn() {
return gapi.auth2.getAuthInstance().isSignedIn.get();
}
signIn = () => {
gapi.auth2.getAuthInstance().signIn();
}
signOut() {
gapi.auth2.getAuthInstance().signOut();
}
getSorted(a, b) {
return new Date(b.date).getTime() - new Date(a.date).getTime();
}
getMailList(queryObject) {
return new Promise((resolve, reject) => {
gapi.client.gmail.users.messages.list(queryObject).then(function (response) {
resolve(response.result);
});
});
}
getMailContentById(id) {
return new Promise((resolve, reject) => {
gapi.client.gmail.users.messages.get({
'userId': 'me', 'id': id
}).then((response) => {
let message = {};
let headers = response.result.payload.headers;
headers.forEach((header) => {
if (header.name === "From") {
message['from'] = header.value;
} else if (header.name === "Subject") {
message['subject'] = header.value;
} else if (header.name === "To") {
message['to'] = theader.value;
} else if (header.name === "Date") {
message['date'] = header.value;
} else if (header.name === "Cc") {
message['cc'] = header.value;
}
});
try {
if (response.result.payload) {
let body = "";
if (response.result.payload.body.size > 0) {
body = response.result.payload.body.data;
} else {
let bodyParts = response.result.payload.parts;
bodyParts.forEach((part, index) => {
if (part.type = "text/html") {
//console.log(index);
body = part.body.data;
return;
}
});
}
message['message'] = Base64.decode(body);
// console.log(message['body']);
}
} catch (e) {
//console.log(index);
//console.log(response.result);
//console.log(e);
}
resolve(message);
});
});
}
getInboxMailsWithContent(nextPageToken, fromEmail) {
var qData = '';
var queryObject = {
'userId': 'me',
'labelIds': ['INBOX']
};
if (nextPageToken) {
queryObject['pageToken'] = nextPageToken;
}
if (fromEmail) {
qData += 'from:' + fromEmail;
}
queryObject['q'] = qData;
return new Promise((resolve, reject) => {
gapi.client.gmail.users.messages.list(queryObject).then((response) => {
let resultObject = {
nextPageToken: response.result.nextPageToken
};
let messages = new Array();
let rawMessages = response.result.messages;
rawMessages.forEach((rawMessage, index) => {
gapi.client.gmail.users.messages.get({
'userId': 'me', 'id': rawMessage.id
}).then((response) => {
let message = {
id: rawMessage.id
};
let headers = response.result.payload.headers;
headers.forEach((header) => {
if (header.name === "From") {
message['from'] = header.value;
} else if (header.name === "Subject") {
message['subject'] = header.value;
} else if (header.name === "To") {
message['to'] = header.value;
} else if (header.name === "Date") {
message['date'] = header.value;
} else if (header.name === "Cc") {
message['cc'] = header.value;
}
});
try {
if (response.result.payload) {
let body = "";
if (response.result.payload.body.size > 0) {
body = response.result.payload.body.data;
} else {
let bodyParts = response.result.payload.parts;
bodyParts.forEach((part, index) => {
if (part.type = "text/html") {
f //console.log(index);
body = part.body.data;
return;
}
});
}
message['message'] = Base64.decode(body);
// console.log(message['body']);
}
} catch (e) {
//console.log(index);
//console.log(response.result);
//console.log(e);
}
messages[index] = message;
});
});
// resultObject.messages = messages.sort(this.getSorted);
resultObject.messages = messages;
resolve(resultObject);
});
});
}
}
function getInboxMailsWithContent(nextPageToken, fromEmail, callback) {
googleJSAPI.getInboxMailsWithContent(nextPageToken, fromEmail).then((response) => {
setTimeout(() => {
if (callback && typeof (callback) == "function") {
callback(response);
}
}, 3000);
});
}
When I clicked on enable button in settings-social-prefs.html file, I am just getting the gmail login page and gmail password page once I have provided gmail username and password, I got the consent screen which asks to allow access to user's email then I am getting the blank screen without getting the Gmail Read-Only mails of a specified user who has logged in. Can you please help me on this to get Gmail Read-Only mails when I click on enable button.
you may turn off two factor authentication (if on) and also "allow low secure apps to connect" in google my account settings
Ps: Displaying API in public should be avoided :-)

Angular 2 Firebase CRUD using ReplaySubject

I did not manage to remove a deleted item from screen.
New or updated items are reflected in screen, but I don't know what to do to reflect deleted ones.
I even created a separated list (using methods findIndex, emit) and splice the element from that list but it didn't work as well.
My provider:
export class AssetTypeService {
private assettypes$: any;
private assettypesRef: any;
private assettypeslist: AssetType[] = [];
constructor(private http: Http) {
this.assettypesRef = firebase.database().ref('asset-type');
this.assettypesRef.on('child_added', this.handleDataChildAdded, this);
this.assettypesRef.on('child_changed', this.handleDataChildAdded, this);
this.assettypesRef.on('child_removed', this.handleDataChildRemoved, this);
this.assettypes$ = new ReplaySubject();
}
get getAssetTypes() {
return this.assettypes$;
}
handleDataChildAdded(snap) {
try {
let type: AssetType = <AssetType>{};
type.id = snap.key;
type.description = snap.val().description;
this.assettypes$.next(type);
} catch (error) {
console.log('catching', error);
}
}
handleDataChildRemoved(snap) {
try {
let index: number = this.findIndex(snap.key);
if (index !== -1) {
this.assettypeslist.splice(index, 1);
this.emit();
}
} catch (error) {
console.log('catching', error);
}
}
private findIndex(key: string): number {
return this.assettypeslist.findIndex((assetType: AssetType) => {
return assetType.id === key;
});
}
private emit(): void {
this.assettypes$.next(this.assettypeslist);
}
saveAssetType(assetType: AssetType) {
if (assetType.id == undefined) {
assetType.id = firebase.database().ref().child('asset-type').push().key;
}
var updates = {};
updates['/asset-type/' + assetType.id] = assetType;
return firebase.database().ref().update(updates);
}
getAssetType(uid: string) {
let assetType: AssetType = <AssetType>{};
return firebase.database().ref('/asset-type/' + uid).once('value').then(function (snapshot) {
assetType = { id: snapshot.key, description: snapshot.val().description };
return assetType;
});
}
deleteAssetType(uid: string) {
return firebase.database().ref('asset-type/' + uid).remove();
}
}
My controller:
ngOnInit() {
this.getAssetTypes();
}
getAssetTypes() {
this.assetTypeService.getAssetTypes.subscribe((data) => {
let alreadyExists = false;
this.types.forEach(function (assetType) {
if (assetType.id == data.id) {
alreadyExists = true;
assetType.description = data.description;
}
});
if (!alreadyExists) {
this.types.push(data);
}
}, (err) => {
console.error(err);
console.log(err);
});
}
deleteAssetType(uid: string) {
this.assetTypeService.deleteAssetType(uid).then(data => {
this.showToast('Asset type deleted successfully');
});
}

Categories