Changing from local storage to a databse - javascript

I have a kanban site which stores the data in the local storage of the browser , I know the data I have stored would be stored in the specific browser that I'm using and if I open another browser the data will not be there , Is there an easy way to change from the local storage of the browser into something else which would allow me to access the data into all browsers ?
or is there an easy way to modify my code in order for it to work for all browsers ?
Class :
export default class KanbanAPI {
static getItems(columnId) {
const column = read().find(column => column.id == columnId);
if (!column) {
return [];
}
return column.items;
}
static insertItem(columnId, content) {
const data = read();
const column = data.find(column => column.id == columnId);
const item = {
id: Math.floor(Math.random() * 100000),
content
};
if (!column) {
throw new Error("Column does not exist.");
}
column.items.push(item);
save(data);
return item;
}
static updateItem(itemId, newProps) {
const data = read();
const [item, currentColumn] = (() => {
for (const column of data) {
const item = column.items.find(item => item.id == itemId);
if (item) {
return [item, column];
}
}
})();
if (!item) {
throw new Error("Item not found.");
}
item.content = newProps.content === undefined ? item.content : newProps.content;
// Update column and position
if (
newProps.columnId !== undefined &&
newProps.position !== undefined
) {
const targetColumn = data.find(column => column.id == newProps.columnId);
if (!targetColumn) {
throw new Error("Target column not found.");
}
// Delete the item from it's current column
currentColumn.items.splice(currentColumn.items.indexOf(item), 1);
// Move item into it's new column and position
targetColumn.items.splice(newProps.position, 0, item);
}
save(data);
}
static deleteItem(itemId) {
const data = read();
for (const column of data) {
const item = column.items.find(item => item.id == itemId);
if (item) {
column.items.splice(column.items.indexOf(item), 1);
}
}
save(data);
}
}
function read() {
const json = localStorage.getItem("kanban-data");
if (!json) {
return [
{
id: 1,
items: []
},
{
id: 2,
items: []
},
{
id: 3,
items: []
},
];
}
return JSON.parse(json);
}
function save(data) {
localStorage.setItem("kanban-data", JSON.stringify(data));
}

Related

how i can get a value through key

i want to know how i can get a value/numbers through key/username ?
look like that console.log(acc.${username})
my js
...
app.get("/account", (req, res) => {
loggedIn = req.cookies.loggedIn;
username = req.cookies.username;
if (loggedIn == "true") {
db.list().then(keys => {
if (keys.includes(username)) {
res.render("settings.html", { username: username })
var data = fs.readFileSync('2FA.json');
var acc = JSON.parse(data)
//////////////////////////////////////////////
console.log(acc.${username}) // i want to see a numbers in user name look like in here
/////////////////////////////////////////////
} else {
res.redirect("/logout");
}
});
} else {
res.render("notloggedin.html");
}
});
my json
[
{
"youssefnageeb": 927342
},
{
"youssefnageeb1":310686
},
{
"youssefnageeb2": 105380
},
{
"youssefnageeb3": 431816
},
{
"youssefnageeb4": 484728
}
]
I am guessing "data" is in the format mentioned above.
So, you can do
const index = data.findIndex(function isAccountRow(row) { return typeof row[username] === 'number'; })
if(index === -1) {
return res.redirect("/logout");
}
const row = data[index];
console.log(row[username]); // will be the number

Update Google sheet Every 1hr

How can I make this script run and update the google sheet every 1hr. I want new data to append at the bottom not to overwrite the existing data and is there any possibility it will delete the duplicate data automatically on the basis of Column C, deleting old values and leaves new.
function youTubeSearchResults() {
// 1. Retrieve values from column "A".
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const values = sheet.getRange("A2:A" + sheet.getLastRow()).getDisplayValues().filter(([a]) => a);
// 2. Retrieve your current values.
const modifyResults = values.flatMap(([keywords]) => {
const searchResults = JSON.parse(UrlFetchApp.fetch(`https://yt.lemnoslife.com/noKey/search?part=snippet&q=${keywords}&maxResults=10&type=video&order=viewCount&videoDuration=short&publishedAfter=2022-09-27T00:00:00Z`).getContentText());
const fSearchResults = searchResults.items.filter(function (sr) { return sr.id.kind === "youtube#video" });
return fSearchResults.map(function (sr) { return [keywords, sr.id.videoId, `https://www.youtube.com/watch?v=${sr.id.videoId}`, sr.snippet.title, sr.snippet.publishedAt, sr.snippet.channelTitle, sr.snippet.channelId, `https://www.youtube.com/channel/${sr.snippet.channelId}`, sr.snippet.thumbnails.high.url] });
});
// 3. Retrieve viewCounts and subscriberCounts.
const { videoIds, channelIds } = modifyResults.reduce((o, r) => {
o.videoIds.push(r[1]);
o.channelIds.push(r[6]);
return o;
}, { videoIds: [], channelIds: [] });
const limit = 50;
const { viewCounts, subscriberCounts } = [...Array(Math.ceil(videoIds.length / limit))].reduce((obj, _) => {
const vIds = videoIds.splice(0, limit);
const cIds = channelIds.splice(0, limit);
const res1 = YouTube.Videos.list(["statistics"], { id: vIds, maxResults: limit }).items.map(({ statistics: { viewCount } }) => viewCount);
const obj2 = YouTube.Channels.list(["statistics"], { id: cIds, maxResults: limit }).items.reduce((o, { id, statistics: { subscriberCount } }) => (o[id] = subscriberCount, o), {});
const res2 = cIds.map(e => obj2[e] || null);
obj.viewCounts = [...obj.viewCounts, ...res1];
obj.subscriberCounts = [...obj.subscriberCounts, ...res2];
return obj;
}, { viewCounts: [], subscriberCounts: [] });
const ar = [viewCounts, subscriberCounts];
const rr = ar[0].map((_, c) => ar.map(r => r[c]));
// 4. Merge data.
const res = modifyResults.map((r, i) => [...r, ...rr[i]]);
// 5. Put values on Spreadsheet.
sheet.getRange(2, 2, res.length, res[0].length).setValues(res);
}
Hourly Trigger youTubeSearchResults
function hourlytrigger() {
if(ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == "youTubeSearchResults").length==0) {
ScriptApp.newTrigger("youTubeSearchResults").timeBased().everyHours(1).create();
}
}
To append data:
sheet.getRange(sheet.getLastRow() + 1, 2, res.length, res[0].length).setValues(res);

React Native Flatlist Not Rerendering Redux

My FlatList does not update when the props I pass from redux change. Every time I send a message I increase everyones unread message count in both firebase and in my redux store. I made sure to include key extractor and extra data, but neither helps. The only thing that changes the unread message count is a reload of the device. How do I make sure the flatList updates with MapStateToProps. I made sure to create a new object by using Object.Assign:
action:
export const sendMessage = (
message,
currentChannel,
channelType,
messageType
) => {
return dispatch => {
dispatch(chatMessageLoading());
const currentUserID = firebaseService.auth().currentUser.uid;
let createdAt = firebase.database.ServerValue.TIMESTAMP;
let chatMessage = {
text: message,
createdAt: createdAt,
userId: currentUserID,
messageType: messageType
};
FIREBASE_REF_MESSAGES.child(channelType)
.child(currentChannel)
.push(chatMessage, error => {
if (error) {
dispatch(chatMessageError(error.message));
} else {
dispatch(chatMessageSuccess());
}
});
const UNREAD_MESSAGES = FIREBASE_REF_UNREAD.child(channelType)
.child(currentChannel).child('users')
UNREAD_MESSAGES.once("value")
.then(snapshot => {
snapshot.forEach(user => {
let userKey = user.key;
// update unread messages count
if (userKey !== currentUserID) {
UNREAD_MESSAGES.child(userKey).transaction(function (unreadMessages) {
if (unreadMessages === null) {
dispatch(unreadMessageCount(currentChannel, 1))
return 1;
} else {
alert(unreadMessages)
dispatch(unreadMessageCount(currentChannel, unreadMessages + 1))
return unreadMessages + 1;
}
});
} else {
UNREAD_MESSAGES.child(userKey).transaction(function () {
dispatch(unreadMessageCount(currentChannel, 0))
return 0;
});
}
}
)
})
};
};
export const getUserPublicChannels = () => {
return (dispatch, state) => {
dispatch(loadPublicChannels());
let currentUserID = firebaseService.auth().currentUser.uid;
// get all mountains within distance specified
let mountainsInRange = state().session.mountainsInRange;
// get the user selected mountain
let selectedMountain = state().session.selectedMountain;
// see if the selected mountain is in range to add on additional channels
let currentMountain;
mountainsInRange
? (currentMountain =
mountainsInRange.filter(mountain => mountain.id === selectedMountain)
.length === 1
? true
: false)
: (currentMountain = false);
// mountain public channels (don't need to be within distance)
let currentMountainPublicChannelsRef = FIREBASE_REF_CHANNEL_INFO.child(
"Public"
)
.child(`${selectedMountain}`)
.child("Public");
// mountain private channels- only can see if within range
let currentMountainPrivateChannelsRef = FIREBASE_REF_CHANNEL_INFO.child(
"Public"
)
.child(`${selectedMountain}`)
.child("Private");
// get public channels
return currentMountainPublicChannelsRef
.orderByChild("key")
.once("value")
.then(snapshot => {
let publicChannelsToDownload = [];
snapshot.forEach(channelSnapshot => {
let channelId = channelSnapshot.key;
let channelInfo = channelSnapshot.val();
// add the channel ID to the download list
const UNREAD_MESSAGES = FIREBASE_REF_UNREAD.child("Public")
.child(channelId).child('users').child(currentUserID)
UNREAD_MESSAGES.on("value",snapshot => {
if (snapshot.val() === null) {
// get number of messages in thread if haven't opened
dispatch(unreadMessageCount(channelId, 0));
} else {
dispatch(unreadMessageCount(channelId, snapshot.val()));
}
}
)
publicChannelsToDownload.push({ id: channelId, info: channelInfo });
});
// flag whether you can check in or not
if (currentMountain) {
dispatch(checkInAvailable());
} else {
dispatch(checkInNotAvailable());
}
// if mountain exists then get private channels/ if in range
if (currentMountain) {
currentMountainPrivateChannelsRef
.orderByChild("key")
.on("value", snapshot => {
snapshot.forEach(channelSnapshot => {
let channelId = channelSnapshot.key;
let channelInfo = channelSnapshot.val();
const UNREAD_MESSAGES = FIREBASE_REF_UNREAD.child("Public")
.child(channelId).child('users').child(currentUserID)
UNREAD_MESSAGES.on("value",
snapshot => {
if (snapshot.val() === null) {
// get number of messages in thread if haven't opened
dispatch(unreadMessageCount(channelId, 0));
} else {
dispatch(unreadMessageCount(channelId, snapshot.val()));
}
}
)
publicChannelsToDownload.push({ id: channelId, info: channelInfo });
});
});
}
return publicChannelsToDownload;
})
.then(data => {
setTimeout(function () {
dispatch(loadPublicChannelsSuccess(data));
}, 150);
});
};
};
Reducer:
case types.UNREAD_MESSAGE_SUCCESS:
const um = Object.assign(state.unreadMessages, {[action.info]: action.unreadMessages});
return {
...state,
unreadMessages: um
};
Container- inside I hook up map state to props with the unread messages and pass to my component as props:
const mapStateToProps = state => {
return {
publicChannels: state.chat.publicChannels,
unreadMessages: state.chat.unreadMessages,
};
}
Component:
render() {
// rendering all public channels
const renderPublicChannels = ({ item, unreadMessages }) => {
return (
<ListItem
title={item.info.Name}
titleStyle={styles.title}
rightTitle={(this.props.unreadMessages || {} )[item.id] > 0 && `${(this.props.unreadMessages || {} )[item.id]}`}
rightTitleStyle={styles.rightTitle}
rightSubtitleStyle={styles.rightSubtitle}
rightSubtitle={(this.props.unreadMessages || {} )[item.id] > 0 && "unread"}
chevron={true}
bottomDivider={true}
id={item.Name}
containerStyle={styles.listItemStyle}
/>
);
};
return (
<View style={styles.channelList}>
<FlatList
data={this.props.publicChannels}
renderItem={renderPublicChannels}
keyExtractor={(item, index) => index.toString()}
extraData={[this.props.publicChannels, this.props.unreadMessages]}
removeClippedSubviews={false}
/>
</View>
);
}
}
Object.assign will merge everything into the first object provided as an argument, and return the same object. In redux, you need to create a new object reference, otherwise change is not guaranteed to be be picked up. Use this
const um = Object.assign({}, state.unreadMessages, {[action.info]: action.unreadMessages});
// or
const um = {...state.unreadMessages, [action.info]: action.unreadMessages }
Object.assign() does not return a new object. Due to which in the reducer unreadMessages is pointing to the same object and the component is not getting rerendered.
Use this in your reducer
const um = Object.assign({}, state.unreadMessages, {[action.info]: action.unreadMessages});

Vue test utils: TypeError mounted

I am having an issue with Vue Test Utils. When I run a unit test, I am always confronted with:
TypeError{line: 73983, sourceURL: 'http://localhost:9876/base/index.js?045b00affe888fcd6b346c4fe50eadd13d471383', stack: 'mounted#http://localhost:9876/base/index.js?045b00affe888fcd6b346c4fe50eadd13d471383:73983:30.....
This only happens when I have the mounted() function in the Vue component
Settings.vue
mounted() {
this.$refs.address.update(this.profile.address)
},
Settings.spec.js
it('calls updateUserInformation before mount', () => {
const spy = sinon.spy(Settings.methods, 'updateUserInformation')
shallow(Settings, { propsData })
Vue.nextTick().then(() => {
spy.should.have.calledOnce()
})
})
I am using Mocha & Chai with vue-test-utils. Does anyone know why this is happening?
Thank you in advance!
UPDATE
Settings.vue component HTML
<vue-google-autocomplete
ref="address"
id="map"
classname="input"
placeholder="Address"
v-on:placechanged="getAddressPlaceChanged"
v-on:inputChange="getAddressInputChange"
:country="['sg']"
>
</vue-google-autocomplete>
Settings.vue component Javascript
export default {
components: {
GoogleMaps,
AutoComplete,
VueGoogleAutocomplete,
Partner,
},
watch: {
// whenever school changes, this function will run
school() {
// Check if school value is an empty string or character is lesser than FIX_STR_LENGTH
if (this.school === '' || this.school.length < this.FIX_STR_LENGTH) {
this.removeMarker('school')
}
this.fetchSchools()
},
},
methods: {
async onSubmit() {
// Check if input fields are empty
if (this.address !== undefined && this.phoneNumber !== null && this.school !== '') {
const { placeResultData = {}, addressData = {} } = this.address
let isSuccessful = false
let tempLat = null
let tempLong = null
let tempAddress = null
// Check if address is an empty object
if (_.isEmpty(this.address)) {
const { latlong = {}, address = '' } = this.profile
const [lat, long] = latlong.coordinates
tempLat = lat
tempLong = long
tempAddress = address
} else {
// User changed address location
tempLat = addressData.latitude
tempLong = addressData.longitude
tempAddress = placeResultData.formatted_address
}
// Validate school address array
let tempSchoolAddress = []
if (this.selectedSchool !== null) {
tempSchoolAddress.push(this.selectedSchool.postal_code)
} else {
tempSchoolAddress = this.profile.schoolAddress
}
// Construct user object for registration/update
const user = new User(
this.profile.name,
tempAddress,
tempLat,
tempLong,
tempSchoolAddress,
)
// If user does not exist in database, perform a POST API registration request
if (this.userExist === false) {
// Add user properties for user registration
user.phoneNumber = this.phoneNumber
await UserSession.register(user, localStorage.getItem('id_token')).then((response) => {
const { data = {} } = response
const profile = data.user
this.updateUserInformation(profile)
isSuccessful = true
this.profile = profile
}).catch((error) => {
console.log(error.response)
})
}
// Perform a PUT API update request
await UserSession.update(user, localStorage.getItem('id_token')).then((response) => {
const { data = {} } = response
const profile = data.user
this.updateUserInformation(profile)
isSuccessful = true
this.profile = profile
}).catch((error) => {
console.log(error.response)
})
if (isSuccessful) {
this.profileChanged()
this.hasChanged = true
}
}
},
profileChanged() {
this.$emit('profileChanged', this.profile)
},
addMarker(name, params) {
if (params === null || params === '') {
return
}
gMapSession.default(params).then((response) => {
const { location = {} } = response.data.results[0].geometry
// Remove existing marker before replacing it
this.removeMarker(name)
this.markers.push({
position: location,
name,
})
this.zoom = 11
}).catch((error) => {
console.log(error.response)
})
},
removeMarker(name) {
let index = 0
let exist = false
for (let i = 0; i < this.markers.length; i++) {
if (this.markers[i].name === name) {
index = i
exist = true
break
}
}
if (exist) {
this.markers.splice(index, 1)
}
},
// Function called when user selects an option from the school autocomplete dropdown
getSelectedSchoolData(event) {
this.selectedSchool = event
// Check if selected school is defined
if (this.selectedSchool !== undefined && this.selectedSchool !== null) {
this.addMarker('school', this.selectedSchool.postal_code)
} else {
this.removeMarker('school')
}
},
// Function called when user types in the address autocomplete input field
getAddressInputChange(data) {
const { newVal = {} } = data
if (newVal === '' || newVal.length < this.FIX_STR_LENGTH) {
this.removeMarker('user')
}
},
// Function called when user selects an option from the address autocomplete dropdown
getAddressPlaceChanged(addressData, placeResultData) {
this.address = {
placeResultData,
addressData,
}
if (addressData !== undefined && addressData !== null) {
this.addMarker('user', addressData.postal_code)
} else {
this.removeMarker('user')
}
},
async updateUserInformation(profile) {
this.phoneNumber = profile.phoneNumber
this.addMarker('user', profile.address)
// TODO: schoolAddress is an array and UI must cater to multiple schools
await SchoolSession.default(profile.schoolAddress[0]).then(async (res) => {
const { result = {} } = res.data
const { records = [] } = result
// Assume that a single postal code contains only 1 school
this.school = records[0].school_name
this.addMarker('school', records[0].postal_code)
})
},
// Fetch school information base on school search query
fetchSchools: _.debounce(function getSchools() {
if (this.school.trim() === '') {
this.schools = []
return
}
const vm = this
SchoolSession.default(this.school).then((response) => {
// JSON responses are automatically parsed.
const { records = {} } = response.data.result
vm.schools = records
}).catch((error) => {
console.log(error.response)
})
}, 500),
},
data() {
return {
FIX_STR_LENGTH: 5,
school: '',
address: '',
schools: [],
markers: [],
phoneNumber: null,
selectedSchool: null,
userExist: false,
hasChanged: false,
center: { lat: 1.3521, lng: 103.8198 },
zoom: 7,
}
},
async created() {
this.profile = this.$attrs
// Check if user was a registered member by phone number
if (this.profile.phoneNumber === undefined) {
return
}
// User exist in the database
this.userExist = !this.userExist
// Update form information
this.updateUserInformation(this.profile)
},
mounted() {
this.$refs.address.update(this.profile.address)
},
}

Firebase database how to list

I am trying to query a Firebase database. I have the following code, but it returns an empty list, when there is matching data.
loadData() {
this.firelist = this.af.database.list('/chat/', {
query: {
orderByChild: 'negativtimestamp'
}
}).map(items => {
const filtered = items.filter(item => {
item.memberId1 === this.me.uid;
});
return filtered;
});
// if me not in firelist then create new chat
if (this.me && this.me.uid) {
let chatFound: boolean = false;
console.log('this.firelist', this.firelist);
this.firelist.forEach(chatItems => {
console.log('chatItems', chatItems);
for (let i = 0; i < chatItems.length; i++) {
console.log('chatItems['+i+']', chatItems[i]);
let memberId1: string = chatItems[i].memberId1;
let memberId2: string = chatItems[i].memberId2;
if (memberId1 === this.me.uid || memberId2 === this.me.uid) {
chatFound = true;
break;
}
}
if (!chatFound) {
//this.createChat();
}
});
}
}
I think my problem is with the filter.
The following code creates a chat successfully:
createChat(img1: string, img2: string) {
this.af.database.list('/chat/').push({
memberId1: this.me.uid,
memberId2: this.you.uid,
img1: img1,
img2: img2,
displayName1: this.me.displayName,
displayName2: this.you.displayName,
lastMsg_text: 'todo',
timestamp: Date.now(),
negativtimestamp: -Date.now()
})
}
The following filter works:
this.firelist = this.af.database.list('/chat/', {
query: {
orderByChild: 'negativtimestamp'
}
}).map(items => {
const filtered = items.filter(
item => item.memberId1 === this.me.uid
);
return filtered;
});

Categories

Resources