I am building a NextJS blogging site which uses #expo/next-adapter . This site has two pages. One is the user page and the other one is post page. The user page has getServerSideProps implemented to fetch data from Firebase. There is next/link's <Link /> implemented on the post page which points to /user/[uid].
Now the problem is if I navigate to user from post using the <Link /> Everything works ok but if I refresh the page the page becomes unresponsive and all the styling related client side JS does not run.
PS : SSR is not implemented on the post page. Please forgive me if this is a rookie mistake because I am one.
PS #2 : This project is hosted on Firebase and uses a cloud function to handle SSR. The above problem does not show up if I run the production build locally using next build && next start
Thank you in advance...
Edit #1 :
This error shows up on the browser console when I either try to manually go to /user/[uid] or refresh the page after navigating back from post
main-590e886005382c6f8e8a.js:1 Uncaught TypeError: Cannot read property 'map' of undefined
at DqTX.t.default (main-590e886005382c6f8e8a.js:1)
at Object.IKlv (main-590e886005382c6f8e8a.js:1)
at l (webpack-288ceb4b356766e18474.js:1)
at Object.BMP1 (main-590e886005382c6f8e8a.js:1)
at l (webpack-288ceb4b356766e18474.js:1)
at t (webpack-288ceb4b356766e18474.js:1)
at Array.r [as push] (webpack-288ceb4b356766e18474.js:1)
at 0c947092cfe8a35964e0670062fe3410218106ea.62154c5756c292e8972d.js:1
Edit #2: Code for the function [user].js
export async function getServerSideProps(context) {
if(admin.apps.length == 0){
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: '*************.appspot.com',
});
}
try {
const fireStore = admin.firestore();
const userDataRef = await fireStore.collection('users').where('uid', '==', `${context.query.user}`).get();
const postDataRef = await fireStore.collection('posts').where('uid', '==', `${context.query.user}`).get();
let userData;
let postData = [];
if(!userDataRef.empty){
if(userDataRef.docs[0].exists){
userData = userDataRef.docs[0].data()
}
if(!postDataRef.empty){
for(let post of postDataRef.docs){
const thumbImage = await admin.storage().bucket().file(`postData/${post.id}/${post.data().thumb}`).publicUrl();
deckData.push(JSON.parse(JSON.stringify({...post.data(), id: post.id, thumb: thumbImage})));
}
}
}
return {
props: {user: JSON.parse(JSON.stringify(userData)), posts: [...postData]}, // will be passed to the page component as props
}
} catch(e) {
return {
props: {user: 'error', posts: []},
}
}
}
Related
I'm using the following code to send a notification from one device to another using FCM. Everything works fine until before return admin.messaging().sendToDevice(...). The 'Token ID: ' log displays token ID of the receiver, but when I set the variable token_id to the sendToDevice function, the notification is not called, therefore the notification is not sent. Can someone tell me what's wrong?
var firebase = require("firebase-admin");
var serviceAccount = require("./julla-tutorial.json");
console.log("enter in then Firebase Api");
const firebaseToken = [
'e0T6j1AiRjaa7IXweJniJq:APA91bHNznSHSIey08s-C-c3gchci6wepvhP1QxQyYbmZ8LySI3wnu64iW7Q23GhA6VCdc4yodZoCFOgynfAb5C8O8VE81OcSv_LL-K3ET1IKGZ_6h35n-_q5EKFtfJWlzOqZr4IvpiB',
'dNWnSqyCQbufzv1JutNEWr:APA91bFcI9FDyRxHRBEcdw4791X0e-V0k1FjXcSstUA67l94hSojMRCd6LWr2b57azNEt3z_XLwLljMX4u2mc9cZDrAVm55Mw9CHGyue-09KofWnnHNR9XWBibc4T76xOV_DWX7T2RvW',
'cq65rtuaTCKGk5lHk7UabN:APA91bFR3kAArg6lhuBq7ktNuBk7Z9MXXk3PskqhYa8CgNaEl6MX4TQ5lo35d6XhnCQ4fEkCkyZ_j08evxE9Y4oVCRTEdqsrkccCVTE8Di47lfmDR3i1NdoL3re9oLw6F_uNsnvRoQcq'
]
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount)
})
const payload = {
notification: {
title: 'Demo 2345',
body: 'dfghj',
sound: 'default',
color: 'yellow',
android_channel_id: 'default',
channel_id: 'default'
},
data: { id: 'broadcast', channelId: 'default' }
}
const options = {
priority: 'high',
timeToLive: 60 * 60 * 24, // 1 day
};
console.log('------payload---',payload);
console.log('-----TOKEN_Array----',firebaseToken);
console.log('-------options-----',options);
firebase.messaging().sendToDevice(firebaseToken, payload, options).then(function (response) {
console.log('--------response',response);
}) .catch(function (error) {
console.log('-------rejet',reject);
});
It looks like you did not change the code from this tutorial:
https://medium.com/#jullainc/firebase-push-notifications-to-mobile-devices-using-nodejs-7d514e10dd4
you will need to change the 2nd line of code:
var serviceAccount = require("./julla-tutorial.json");
to actually point to your own firebase-push-admin.json file which holds your private keys registering your backend app with the firebase cloud messaging api. you can download this file from the firebase console as mentioned in the above article.
I recommend hiding this file from your git history by adding it to .gitignore so you dont accidentally push your private keys to a public repo.
I will link you another resource in addition to above link which helped me implement firebase push notifications in a nodeJS backend app.
https://izaanjahangir.medium.com/setting-schedule-push-notification-using-node-js-and-mongodb-95f73c00fc2e
https://github.com/izaanjahangir/schedule-push-notification-nodejs
Further I will also link you another repo where I am currently working on a fully functional firebase push notification implementation. Maybe it helps to actually see some example code.
https://gitlab.com/fiehra/plants-backend
I was exploring Remix.run and making a sample app. I came across an issue that has been bothering me for some time now. Correct me if I am wrong: action() is for handling Form submission, and loader() is for fetching data initially.
For my application, I used mongoose to connect MongoDB, defined models, and defined querying function in a query.server.ts file. I want to fetch data from the database through a function defined in the query.server.ts file when an image is clicked on the UI. How can I do that without using forms? I cannot pre-fetch the data without knowing what image was clicked by the user.
You can create a resource route. These are like regular routes, but don't export a default component (no UI).
You can use the useFetcher hook and call fetcher.load() to call your resource route. The data is in fetcher.data.
// routes/query-data.ts
export const loader: LoaderFunction = async ({request}) => {
const url = new URL(request.url)
const img = url.searchParams.get('img')
const data = await getData(img)
return json(data)
}
// routes/route.tsx
export default function Route() {
const fetcher = useFetcher()
const handleImgClick = (e) => {
const img = e.target
fetcher.load(`/query-data?img=${img.attr('src')}`)
}
return (
<div>
<img onClick={handleImageClick} src="/images/file.jpg" />
<pre>{ JSON.stringify(fetcher.data, null, 2) }</pre>
</div>
)
}
i am just trying to learn JavaScript. I have to create a web application for school. Now i am trying to fetch data from a self written api. The backend is written with express, the frontend with JavaScript. I have got a overview page, where all products are shown. After clicking on the detail button, the user should be able to view the details of the selected product. For this i use this code.
import React, { useState, useEffect } from "react";
import "./Articles.css";
function ArticleDetail({ match }) {
useEffect(() => {
fetchArticle();
}, []);
const [article, setArticle] = useState([]);
async function fetchArticle() {
try {
const response = await fetch(
`http://localhost:8000/api/articles/${match.params.id}`
);
const article = await response.json();
//console.log(data.results);
console.log(article);
setArticle(article);
return article;
} catch (error) {
console.error(error);
}
}
return (
<div>
<p>TEST</p>
<p>{article.articles.pk_article_nr}</p>
<p>TEST</p>
</div>
);
}
export default ArticleDetail;
If i run this code and don't refresh the page by myself, the correct value (pk_article_nr) is shown. If i refresh the browser manually there is this error
TypeError: Cannot read properties of undefined (reading 'pk_article_nr')
This data are shown in the console:
{articles: {…}}
articles:
article_description: "lorem ipsum"
article_expiretimestamp: "2022-01-15 18:52:27"
article_picture: null
article_timestamp: "2022-01-15 18:37:27"
article_title: "Test 4"
bid_amount: 80
fk_article_nr: 4
fk_user_userid: null
pk_article_nr: 4
pk_bid_id: 8`
Could you please help me? I haven't found anything that helps me. Maybe i just searched for the wrong thing.
Thank you,
Max
You should change
<p>{article.articles.pk_article_nr}</p>
to
<p>{article?.articles?.pk_article_nr}</p>
Reason for this to happen:
React wants to access the property before mounting, while the property has not yet received any content
What I want to do: On reset password button click send a letter to user's email using auth().sendSignInLinkToEmail(<user email>, actionCodeSettings);
After user clicks on the received link he gets navigated to the app and using dynamicLinks().getInitialLink() to get the email link he will be loged in with auth().signInWithEmailLink() method.
Here is my implementation for it:
Reset Password Screen
const handleContinue = async () => {
await FirebaseAuth.resetPassword(email);
await AsyncStorage.setItem('#email', email);
};
FirebaseAuth.js
const actionCodeSettings = {
handleCodeInApp: true,
// URL must be whitelisted in the Firebase Console.
url: 'https://examplemoxie.page.link/password_reset',
iOS: {
bundleId: '<my bundle id>',
},
android: {
bundleId: '<my bundle id>',
installApp: true,
},
};
class FirebaseAuthApp {
constructor(firebase) {
this.firebase = firebase;
}
resetPassword = emailAddress =>
auth()
.sendSignInLinkToEmail(emailAddress, actionCodeSettings)
.catch(error => logger(error));
...
}
At this point everything works pretty fine, I'm receiving an email, by clicking on it I'm getting navigated into my app and even able to read the initial link by this piece of code:
App.js
const App = () => {
const user = useAuthStatus();
useEffect(() => {
const handleDynamicLink = async link => {
// Check and handle if the link is a email login link
alert(JSON.stringify(link));
if (auth().isSignInWithEmailLink(link.url)) {
try {
// use the email we saved earlier
const email = await AsyncStorage.getItem('#email');
await auth().signInWithEmailLink(email, link.url);
/* You can now navigate to your initial authenticated screen
You can also parse the `link.url` and use the `continueurl` param to go to another screen
The `continueurl` would be the `url` passed to the action code settings */
} catch (e) {
alert(e);
}
}
};
const unsubscribe = dynamicLinks().onLink(handleDynamicLink);
/* When the app is not running and is launched by a magic link the `onLink`
method won't fire, we can handle the app being launched by a magic link like this */
dynamicLinks()
.getInitialLink()
.then(link => link && handleDynamicLink(link));
// When the component is unmounted, remove the listener
return () => unsubscribe();
}, []);
Link
https://testmoxiegirl.firebaseapp.com/__/auth/action?apiKey=<api key>&mode=signIn&oobCode=<oob code>&continueUrl=https://examplemoxie.page.link/password_reset&lang=en
My dynamic links settings
short URL link - https://examplemoxie.page.link/password_reset
dynamic link - https://moxiegirl.page/reset_password
behavior for Android - Open the deep link in your Android App / Open custom URL for not installed App
And here comes the problem, the link which i get in App.js file from getInitialLink() method is the same as my dynamic link in firebase dynamic link settings and using it for signInWithEmailLink will fail with Invalid email link error. For this to work i need to get a link sent to email but I have no clue on what I'm doing wrong.
My environment:
"react-native": "0.64.2",
"#react-native-firebase/app": "^12.4.0",
"#react-native-firebase/auth": "^12.4.0",
"#react-native-firebase/dynamic-links": "^12.4.0",
So, before posting this question I decided to check everything once more and I found a problem.
In my case, instead of using packageName in my FirebaseAuth.js
I was using bundleId for the Android settings, assuming that for the Android and iOS it should be the same keys.
Before:
const actionCodeSettings = {
...
android: {
bundleId: '<my bundle id>',
installApp: true,
},
};
After:
const actionCodeSettings = {
...
android: {
packageName: '<my bundle id>',
installApp: true,
},
};
i am using Vuex and Firebase Authentication. I got stuck when reload the page. firebase.auth().onAuthStateChanged take time to response. But i need at the same time when reload the page. I have seen many tutorials in internet, most of them is router guard, but that i don’t want. I have some route where the user has login, then can navigate to this route.
App.vue where i am applying.
created () {
firebase.auth().onAuthStateChanged(async user =>{
if (user){
await this.$store.dispatch('autoSignIn',user)
}
})
}
Here is my vuex action theat trigger when page reload to auto sign in if a user was logged before reload the page.
autoSignIn ({commit}, payload) {
commit('setUser',{email:payload.email, userId:payload.uid})
}
This is my getter
isAuthenticated:state => {
return state.user !== null && state.user !== undefined ? state.user : null
}
Here is where i am calling my getter isAuthenticated.
getEventsByUser({getters,commit}){
let data = [];
firebase.database().ref('usuario/' + getters.isAuthenticated.userId + '/eventos/')
.on("value", eventos =>{
eventos.forEach(evento =>{
data.push({"id":evento.key, ...evento.val()})
});
commit('setEventsByUser',data)
})
},
And this is the component which dispatch the action
<template>
<div>
<div v-for="(event,id) in getEventsByUser" :key="id">
{{event}}
</div>
</div>
</template>
<script>
export default {
name: "MyEvents",
computed:{
getEventsByUser(){
return this.$store.getters.getEventsByUser;
},
},
mounted() {
this.$store.dispatch('getEventsByUser')
},
}
Here is the error when i reload the page
When the page loads, Firebase checks whether the ID token that is stored for the user is still valid. This requires that it calls the server, so it may take a moment. During this check the user will be null, so your code needs to handle that everywhere.
In your onAuthStateChanged handler you handle this correctly with:
firebase.auth().onAuthStateChanged(async user =>{
if (user){
But then in getEventsByUser you assume there is a user, which (as shown by the error message) is not true. So you'll want to add a check there, to see if there's a user, before attaching the listener to the database:
getEventsByUser({getters,commit}){
let data = [];
if (getters.isAuthenticated) {
firebase.database().ref('usuario/' + getters.isAuthenticated.userId + '/eventos/')
...