.orderByChild() is not working on Firebase (vue.js) - firebase

I'm trying to sort my data by using .orderByChild, but the data are filter by the name of the node.
I added this on Firebase :
"concerts": {
".indexOn": "expires"
}
And here is my code in my index.js file :
loadConcerts ({commit}) {
commit('setLoading', true)
firebase.database().ref("concerts").orderByChild("expires").startAt(Date.now()/1e3).limitToFirst(7).once("value")
.then((data) => {
const concerts = []
const obj = data.val()
for (let key in obj) {
concerts.push({
expires: obj[key].expires,
...
})
}
commit('setLoadedConcerts', concerts)
commit('setLoading', false)
})
I also add this :
getters: {
loadedConcerts (state) {
return state.loadedConcerts.sort((concertA, concertB) => {
return concertA.expires > concertB.expires
})
},
loadedConcert (state) {
return (concertId) => {
return state.loadedConcerts.find((concert) => {
return concert.id === concertId
})
}
Maybe someone has a clue ? Thank you

In order to list the value in the correct order (by expires) you should use the forEach() method and not use directly data.val().
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<script src="https://www.gstatic.com/firebasejs/5.5.8/firebase.js"></script>
</head>
<body>
<script>
// Initialize Firebase
var config = {
apiKey: '......',
authDomain: '......',
databaseURL: '......',
projectId: '......',
storageBucket: '......'
};
firebase.initializeApp(config);
firebase
.database()
.ref('past')
.orderByChild('expires')
.startAt(Date.now() / 1e3)
.limitToFirst(7)
.once('value')
.then(data => {
const concerts = []
data.forEach(element => {
console.log(element.val());
concerts.push({ id: element.key, expires: element.val().expires});
});
});
</script>
</body>
</html>
PS: if you want to order with the reverse order, just store in another field the value of -1*expires

Related

react query and ssr of next.js is not working

emphasized texti have some problem applying ssr.
it's my code
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
cacheTime: 1000 * 60 * 5, // 5 minute defualt
},
},
}),
);
return (
<QueryClientProvider client={queryClient}>
<Head>
<link rel="icon" type="image/x-icon" href="/favicon.svg" />
</Head>
<Hydrate state={pageProps.dehydratedState}>
<Component {...pageProps} />
</Hydrate>
<ReactQueryDevtools initialIsOpen={true} />
</QueryClientProvider>
export const getServerSideProps: GetServerSideProps = async (): Promise<{
props: { dehydratedState: DehydratedState };
}> => {
const queryClient = new QueryClient();
await queryClient.prefetchQuery(["ururlInfoQuery"], requestChallenge);
return { props: { dehydratedState: dehydrate(queryClient) } };
};
const Banner = function Banner(): JSX.Element {
const { data, isFetching } = useUrUrlInfoQuery();
const { challengeData } = ChallengeStore;
}
export const useUrUrlInfoQuery = () => {
return useQuery<ChallengeResponseType, Error | void>(["ururlInfoQuery"],
requestChallenge, {
staleTime: StaleTimeEnum.Default,
});
};
result:
defulat value: 3, 5
real value : 1, 10
this means serverSide render is not working.
data getted is init value i setted.
please, some comment help me

How can I override the client's state with the server's state in vue3 ssr?

When I was building vue3ssr recently, everything went smoothly, but the store data on the server side could never cover the store data on the client side. The following is my code, please help me to see where there is a problem
// entry-client.js
if (window && window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__);
}
router.isReady().then(() => {
app.mount('#app')
})
<script>
<template>
<div class="home">
<h1>This is Home</h1>
<h2>ssr msg: {{ msg }}</h2>
</div>
</template>
<script setup>
import useStore from "#/store";
import { computed } from "vue";
const store = useStore();
const msg = computed(() => { // => msg: ''
return store.state.msg;
});
// console.log("store", store);
</script>
<script>
// views/home.vue
export default {
asyncData: (store) => {
return store.dispatch("asyncSetMsg");
},
};
</script>
</script>
// store/index.ts
export default function useStore() {
return createStore({
state: {
msg: "",
},
getters: {},
mutations: {
SET_MSG(state, payload) {
state.msg = payload;
},
},
actions: {
// store/index.ts
asyncSetMsg({ commit }) {
return new Promise<void>((resolve, reject) => {
setTimeout(() => {
commit("SET_MSG", "This is some msg in ssr");
resolve();
}, 300);
});
},
},
modules: {},
});
}
// entry-server.js
Promise.all(componentArr).then(() => {
console.log('store.state', store.state); // => {msg: 'This is some msg in ssr'}
html += `<script>window.__INITIAL_STATE__ = ${replaceHtmlTag(JSON.stringify(store.state))}</script>`
resolve(html);
}).catch(() => {
reject(html)
})
The above is the relevant code The following is the running result, I tried to print on the server side and the client side, the result is the normal output on the server side, but there is no data on the client sid

next-i18next with next-rewrite does not work with root page rewrite path

We have an existing app, where the root "/" gets redirected to "/search" by default. It's been working fine via our next-redirects.js file:
async function redirects() {
return [
{
source: '/',
destination: '/search',
permanent: true,
},
];
}
I have to implement translation to the app, using next-i18next, so that we can have translated text + routing out of the box with NextJS. I have followed the steps in the next-i8next docs. I added the next-i18next.config.js file as:
const path = require('path');
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'es'],
},
localePath: path.resolve('./public/static/locales'), // custom path file route
};
And the next.config looks like:
const { i18n } = require('./next-i18next.config');
const defaultConfig = {
env: {
SOME_ENV,
},
images: {
deviceSizes: [980],
domains: [
'd1',
'd2',
],
},
i18n,
redirects: require('./next-redirects'),
webpack: (config, options) => {
if (!options.isServer) {
config.resolve.alias['#sentry/node'] = '#sentry/browser';
}
if (
NODE_ENV === 'production'
) {
config.plugins.push(
new SentryWebpackPlugin({
include: '.next',
ignore: ['node_modules'],
urlPrefix: '~/_next',
release: VERCEL_GITHUB_COMMIT_SHA,
})
);
}
return config;
},
};
module.exports = withPlugins([withSourceMaps], defaultConfig);
We have a custom _app file getting wrapped with the appWithTranslation HOC, and it's setup with the getInitialProps, per nextJS docs:
function MyApp({ Component, pageProps }) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentNode.removeChild(jssStyles);
}
TagManager.initialize(tagManagerArgs);
setMounted(true);
}, []);
const Layout = Component.Layout || Page;
return (
<>
<Head>
<link rel="icon" href="/favicon.png" type="image/ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<AppProviders>
<Context {...pageProps}>
<Layout {...pageProps}>
<>
<Component {...pageProps} />
<Feedback />
<PageLoader />
</>
</Layout>
</Context>
</AppProviders>
</>
);
}
MyApp.getInitialProps = async ({ Component, ctx }) => {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps({ ctx });
}
const cookies = Cookie.parse(ctx?.req?.headers?.cookie || '');
if (Object.keys(cookies).length) {
const { token } = JSON.parse(cookies?.user || '{}');
let user = null;
if (token) {
const { data } = await get('api/users', { token });
if (data) {
user = data;
user.token = token;
}
}
pageProps.user = user;
pageProps.cart = cookies?.cart;
pageProps.defaultBilling = cookies?.defaultBilling;
pageProps.reservationEstimateItem = cookies?.reservationEstimateItem;
pageProps.reservationEstimate = cookies?.reservationEstimate;
}
return { pageProps };
};
export default appWithTranslation(MyApp);
And we have our _document file to handle some Emotion theming:
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
const styles = extractCritical(initialProps.html);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
<style
data-emotion-css={styles.ids.join(' ')}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: styles.css }}
/>
</>
),
};
}
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
<script
type="text/javascript"
src="https://js.stripe.com/v2/"
async
/>
</body>
</Html>
);
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async ctx => {
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [
...React.Children.toArray(initialProps.styles),
sheets.getStyleElement(),
],
};
};
At this point the redirect logic should continue to navigate to the search page which is setup like so:
export const SearchPage = () => {
const router = useRouter();
const { t } = useTranslation('search');
return (
<>
<Head>
<title>{`${t('searchTitle')}`}</title>
<meta
property="og:title"
content={`${t('searchTitle')}`}
key="title"
/>
<meta
name="description"
content={t('metaDescription')}
/>
</Head>
<Search />
</>
);
};
SearchPage.namespace = 'SearchPage';
export const getStaticPaths = () => ({
paths: [], // indicates that no page needs be created at build time
fallback: 'blocking' // indicates the type of fallback
});
export const getStaticProps = async ({ locale }) => ({
// exposes `_nextI18Next` as props which includes our namespaced files
props: {
...await serverSideTranslations(locale, ['common', 'search']),
}
});
export default SearchPage;
The search page has the getStaticPaths & getStaticProps functions, as needed on ALL page level files, per next-i18next.
Why does this setup no longer work with the redirect?
There are no errors in the terminal.
The network tab shows a 404 error on the root route of "/"
which implies the re-writing is not working. But what about the i18n makes this not behave?
Is it something in the _app or _document files?
If I navigate to /search directly, it loads fine, so the page routes are OK it seems.
Other notes:
NextJS "next": "^10.0.2",
next-i18next "next-i18next": "^7.0.1",
There seems to be some possible issues with Next & Locales...
https://github.com/vercel/next.js/issues/20488
https://github.com/vercel/next.js/issues/18349
My workaround is not pretty, but it works:
Delete the original next-rewrite
Add a new index.js page file that handles the redirect in the getServerSideProps:
const Index = () => null;
export async function getServerSideProps({ locale }) {
return {
redirect: {
destination: `${locale !== 'en' ? `/${locale}` : ''}/search`,
permanent: true,
},
};
}
export default Index;

How do I load firebase data using vue and vuefire?

I'm not understanding something about getting firebase data into vue... I'm happy to delete the question or quit my job as a programmer once I get an answer ;)
I get that the data is async, so vue is trying to render the component before the data has been received. But, I don't see how to make it wait. Examples would be greatly appreciated. I've tried reading the docs, but I'm just not understanding.
It's a tiny tiny app that displays our company's parking lot and saves the user's tap (car) location to firebase (we're tired of forgetting where we parked). Grateful for any help!
Oh, and I'm using set() because only one car location needs to be saved at a time, so it's ok that the data is overwritten each time the user taps a new place on the screen.
<template>
<div id="app">
<span id="marker" class="fas fa-times" :style="{ left: leftCoord, top: topCoord }"></span>
<img #click="saveCoordinates($event)" src="./assets/parking-lot.jpg">
</div>
</template>
<script>
import firebase from 'firebase'
const config = {
apiKey: 'MY-API-KEY',
authDomain: 'MY-APP.firebaseapp.com',
databaseURL: 'https://MY-APP.firebaseio.com',
projectId: 'MY-APP',
storageBucket: 'MY-APP.appspot.com',
messagingSenderId: '1234567890'
}
const app = firebase.initializeApp(config)
const db = app.database()
const locationRef = db.ref('location')
export default {
name: 'app',
firebase: {
location: locationRef
},
mounted () {
this.leftCoord = this.location.leftCoord
this.topCoord = this.location.topCoord
},
data () {
return {
leftCoord: '',
topCoord: ''
}
},
methods: {
saveCoordinates: function (clickEvent) {
const coordinates = {
leftCoord: clickEvent.layerX,
topCoord: clickEvent.layerY
}
this.location.set(coordinates)
}
}
}
</script>
This will do the trick:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://www.gstatic.com/firebasejs/4.11.0/firebase.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuefire/dist/vuefire.js"></script>
</head>
<body>
<div id="app">
<span id="marker" class="fas fa-times" :style="{ left: leftCoord, top: topCoord }"></span>
<img #click="saveCoordinates($event)" src="./assets/parking-lot.jpg">
<img #click="readCoords" src="./assets/parking-lot.jpg">
</div>
<script>
var config = {
apiKey: ".........",
authDomain: ".........",
databaseURL: ".........",
projectId: ".........",
storageBucket: "........."
};
/* global Vue, firebase */
var db = firebase.initializeApp(config).database()
var todosRef = db.ref('todos')
const locationRef = db.ref('location')
new Vue({
el: '#app',
name: 'app',
firebase: {
location: {
source: locationRef,
asObject: true
}
},
mounted() {
locationRef.once('value', snapshot => {
this.leftCoord = this.location.leftCoord
this.topCoord = this.location.topCoord
})
},
data() {
return {
leftCoord: '',
topCoord: ''
}
},
methods: {
saveCoordinates: function (clickEvent) {
console.log(clickEvent.layerX)
const coordinates = {
leftCoord: clickEvent.layerX,
topCoord: clickEvent.layerY
}
locationRef.set(coordinates)
},
readCoords: function (clickEvent) {
console.log(this.location.leftCoord);
console.log(this.location.topCoord);
}
}
})
</script>
</body>
</html>
Apparently there is no "native" way in vuefire to wait into a mounted hook that the data is loaded, see https://github.com/vuejs/vuefire/issues/69
I've added a second image link with a new function readCoords just for testing purpose.
Note that you could also do in the mounted hook
locationRef.once('value', snapshot => {
this.leftCoord = snapshot.val().leftCoord
this.topCoord = snapshot.val().topCoord
})
I add a second answer, which is not based anymore on the mounted hook but on the callback function of the object binding.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://www.gstatic.com/firebasejs/4.11.0/firebase.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuefire/dist/vuefire.js"></script>
</head>
<body>
<div id="app">
<span id="marker" class="fas fa-times" :style="{ left: leftCoord, top: topCoord }"></span>
<img #click="saveCoordinates($event)" src="./assets/parking-lot.jpg">
</div>
<script>
var config = {
apiKey: ".........",
authDomain: ".........",
databaseURL: ".........",
projectId: ".........",
storageBucket: "........."
};
/* global Vue, firebase */
var db = firebase.initializeApp(config).database()
var todosRef = db.ref('todos')
const locationRef = db.ref('location')
new Vue({
el: '#app',
name: 'app',
firebase: {
location: {
source: locationRef,
asObject: true,
readyCallback: function () {
this.leftCoord = this.location.leftCoord
this.topCoord = this.location.topCoord
}
}
},
data() {
return {
leftCoord: '',
topCoord: ''
}
},
methods: {
saveCoordinates: function (clickEvent) {
console.log(clickEvent.layerX)
const coordinates = {
leftCoord: clickEvent.layerX,
topCoord: clickEvent.layerY
}
locationRef.set(coordinates)
}
}
})
</script>
</body>
</html>
If location is an object, you need to bind like this:
export default {
name: 'app',
firebase: {
location: {
source: db.ref('location'),
asObject: true,
readyCallback: function () {}
}
},
mounted () {
this.leftCoord = this.location.leftCoord
this.topCoord = this.location.topCoord
},
data () {
return {
leftCoord: '',
topCoord: ''
}
},
methods: {
saveCoordinates: function (clickEvent) {
const coordinates = {
leftCoord: clickEvent.layerX,
topCoord: clickEvent.layerY
}
this.$firebaseRefs.location.set(coordinates)
}
}
}
Note that when setting, we need to use this.$firebaseRefs.location.set(coordinates)
Document https://github.com/vuejs/vuefire

Service worker event waitUntil() was passed a promise that rejected with 'TypeError: b is null'

This is my service worker file that shows the push notification:
importScripts('https://www.gstatic.com/firebasejs/3.5.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.5.0/firebase-messaging.js');
var config = {
apiKey: "my_key",
authDomain: "my_domain.firebaseapp.com",
databaseURL: "https://my_db.firebaseio.com",
storageBucket: "my_bucket.appspot.com",
messagingSenderId: "my_sender_id"
};
firebase.initializeApp(config);
var messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function (payload) {
var notificationTitle = 'Hello World';
var notificationOptions = {
body: 'Test push notification'
};
return self.registration.showNotification(notificationTitle,notificationOptions);
});
This is my html, where it registers the service worker:
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div>TODO write content</div>
<script src="https://www.gstatic.com/firebasejs/3.5.0/firebase.js"></script>
<script>
var config = {
apiKey: "my_key",
authDomain: "my_domain.firebaseapp.com",
databaseURL: "https://my_db.firebaseio.com",
storageBucket: "my_bucket.appspot.com",
messagingSenderId: "my_sender_id"
};
firebase.initializeApp(config);
</script>
<script>
var messaging = firebase.messaging();
var ser = '/serviceworker.js';
if ('serviceWorker' in navigator) {
// Register service worker
navigator.serviceWorker.register('./public/serviceworker.js').then(function (reg) {
messaging.useServiceWorker(reg);
messaging.requestPermission()
.then(function () {
console.log('Notification permission granted.');
return messaging.getToken()
.then(function (currentToken) {
if (currentToken) {
console.log('in if', currentToken);
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else {
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
}
};
xhttp.open("POST", "/notification", true);
xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhttp.send(JSON.stringify({token: currentToken}));
} else {
console.log('in else', currentToken);
}
}).catch(function (err) {
console.log('An error occurred while retrieving token. ', err);
});
})
.catch(function (err) {
console.log('Unable to get permission to notify. ', err);
});
messaging.onMessage(function (payload) {
var options = {
body: payload.data.body
}
var notificationObj = new Notification(payload.data.title, options);
});
}).catch(function (err) {
console.error("SW registration failed with error " + err);
});
}
</script>
</body>
</html>
Everything is working fine but when i load page for first time then i see the following error after allowing the notification permission. I am using FCM for push notification.
Service worker event waitUntil() was passed a promise that rejected with 'TypeError: b is null'.
This was fixed in version 3.5.1 of Firebase Messaging.

Resources