Can't Figure Out How to Use Gridsome-Plugin-Firestore - firebase

I am trying to use the gridsome-plugin-firestore plugin (https://gridsome.org/plugins/gridsome-source-firestore). I want to use that plugin to connect to a simple firestore database collection called news. News has a number of documents with various fields:
content
published_date
summary
author
title
etc.
Does anyone know how am I supposed to set up the gridsome.config file to access this collection using the gridsome-plugin-firestore plugin?. I cannot figure it out from the instructions given.

The Gridsome docs are a little clearer than npm version, but you need to generate a Firebase Admin SDK private key and download the whole file to your Gridsome app and import it into gridsome.config.js as a module, name it whatever you want for the options > credentials: require field as below.
First, you'll need the Firestore plugin
$ yarn add gridsome-source-firestore
Then in gridsome.config.js
const { db } = require('gridsome-source-firestore')
module.exports = {
plugins: [
{
use: 'gridsome-source-firestore',
options: {
credentials: require('./my-project-firebase-adminsdk-qw2123.json'), //
Replace with your credentials file you downloaded.
debug: true, // Default false, should be true to enable live data updates
ignoreImages: false, // Default false
imageDirectory: 'fg_images', // Default /fg_images
collections: [
{
ref: (db) => {
return db.collection('news')
},
slug: (doc, slugify) => {
return `/news/${slugify(doc.data.title)}`
},
children: [
{
ref: (db, parentDoc) => {
return parentDoc.ref.collection('posts')
},
slug: (doc, slugify) => {
return `/${slugify(doc.data.title)}`
},
}
]
}
]
}
}
]
}
You might have to change "posts" to "content" depending on your DB structure and alter the corresponding page queries to suit, there are some examples and other useful setup info in this Gridsome Firestore starter on Github https://github.com/u12206050/gridsome-firestore-starter.git

Related

How to prevent direct access to pages url in nextjs when used rewrites?

My problem is : I have pages/blog.js file in my project. I did localized urls like down below in the next.config.js file.
i18n:{
locales:["tr","en"],
defaultLocale:"tr"
},
async rewrites(){
return [
{
"source":"/tr/makaleler",
"destination":"/blog",
"locale":false
},
{
"source":"/en/articles",
"destination":"/blog",
"locale":false
}
]
}
It works. But problems is ; I can still access with this localhost:3000/blog. I want to make it only accessible with localhost:3000/makaleler or localhost:3000/en/articles.
Is there any way to achieve this? I have read "nextjs" documentation bu couldn't find anything useful.
Essentially what you want is not possible, The reason is if you restrict access to localhost:3000/blog by any means, then your rewrites will stop working as well.
What you probably need is redirects from localhost:3000/blog to the desired locale for your users. You can leverage Accept-Language header for example:
async redirects() {
return [
{
source: '/blog',
has: [
{
type: 'header',
key: 'accept-language',
// header starts with tr
value: 'tr(.*)',
},
],
destination: '/tr/makaleler',
permanent: false,
},
{
source: '/blog',
has: [
{
type: 'header',
key: 'accept-language',
// header does not start with tr
value: '((?!tr$).*)',
},
],
destination: '/en/articles',
permanent: false,
},
]
}
You should use Next.js Middleware in version 12.2 if you want to implement complex redirect logic based on language (or anything). You can find a quick tutorial by Vercel in Youtube here: https://youtu.be/j7rPSS9Ovsw?t=296

flutter app - trending posts by using google analytics data api

In my app, users create posts and I'd like to show trending posts by the number of views, comments, etc in a specific date range. To do that I thought I can create a custom event as below:
await FirebaseAnalytics.instance.logEvent(
name: "trending_contents",
parameters: {
"content_type": EnumToString.convertToString(type),
"content_id": contentModel.externalId,
"action_type": "post",
"point": 3,
},
);
I wonder if it is possible to use Google Analytics Data API to get trending posts by a specific date range? Or is there any better way to get trending posts instead of google analytics data API?
I finally found a solution on how to use Google Analytics Data API to manage trending content. If anyone is looking for a solution for a similar need, here is what I've done so far:
I send a custom event in specific situations such as when the user views the content etc. as below. If you use parameters' names according to predefined dimensions & metrics (see API Dimensions & Metrics), it will be easy to prepare a custom report (at least it was for me...). Later, I use contentType and contentId as dimensions and eventValue as a metric in the custom report.
await FirebaseAnalytics.instance.logEvent(
name: "trending_contents",
parameters: {
"content_type": EnumToString.convertToString(event.type),
"content_id": contentId,
"action_type": "view",
"value": 1,
},
);
Lastly, I created a scheduled cloud function that runs every 6 hours and populates firebase collection according to custom report results. This report gives contentIds in a specific date range ordered by the sum of values that I sent in a custom event
P.S. you need to create a service account in Google Cloud Console, then generate JSON credentials for it and add the file to your project (see credentialsJsonPath variable below). Then you need to add its email address to google analytics 'Property Access Management' section to access analytics data. To see Google Analytics Data API samples, you can check their GitHub repo
const { BetaAnalyticsDataClient } = require('#google-analytics/data');
exports.scheduledTrendingFunction = functions.pubsub.schedule('0 */6 * * *').onRun((context) => {
const propertyId = process.env.GA_PROPERTY_ID;
const credentialsJsonPath = process.env.GA_CRENDENTIALS_PATH;
const analyticsDataClient = new BetaAnalyticsDataClient({
keyFilename: credentialsJsonPath,
});
async function runReport(filterType) {
// [START analyticsdata_json_credentials_run_report]
const [response] = await analyticsDataClient.runReport({
property: `properties/${propertyId}`,
dateRanges: [
{
startDate: '3daysAgo',
endDate: 'today',
},
],
dimensions: [
{
name: 'contentType',
},
{
name: 'contentId'
}
],
metrics: [
{
name: 'eventValue'
},
],
dimensionFilter: {
andGroup: {
expressions: [
{
filter: {
fieldName: "eventName",
inListFilter: {
values: ["trending_contents"]
}
}
},
{
filter: {
fieldName: "contentType",
inListFilter: {
values: [filterType]
}
}
}
]
}
},
offset: 0,
limit: 20,
orderBys: [
{
desc: true,
metric: {
metricName: "eventValue"
}
}
]
});
// [END analyticsdata_json_credentials_run_report]
const batch = admin.firestore().batch();
// BATCH: delete
const trendRef = admin.firestore().collection('trends').doc(filterType);
batch.delete(trendRef);
const subTrendRef = admin.firestore().collection('trends').doc(filterType).collection('trendContents');
// console.log(response);
response.rows.forEach((row, index) => {
// BATCH: add each contentId to trend
const contentId = row['dimensionValues']['1']['value'];
batch.set(subTrendRef.doc(contentId), {priority: index + 1});
});
// Commit the batch
await batch.commit();
}
runReport("book");
return null;
});

Is Vercel Caching causing issues?

For my project i'm using prisma/supabase with next js and then hosting on vercel. Any changes i make to my github automatically generates a new development deployment on vercel. Even though my project is working fine locally, my recent generation resulted in an error which i can only think has something to do with vercels cache.
Half way through the project i added a new field 'slug' to my schema and populated my existing tables with said slug. I then used the slug when generating getStaticProps.
Everything works fine locally but when i generate a new deployment on vercel i get the following error :
Error: Unknown arg `slug` in where.comp.slug for type CompRelationFilter. Did you mean `is`?
Unknown field `slug` for select statement on model Comp. Did you mean `cID`?
at Object.validate (/vercel/path0/node_modules/#prisma/client/runtime/index.js:34758:20)
at PrismaClient._executeRequest (/vercel/path0/node_modules/#prisma/client/runtime/index.js:39752:17)
at consumer (/vercel/path0/node_modules/#prisma/client/runtime/index.js:39693:23)
at /vercel/path0/node_modules/#prisma/client/runtime/index.js:39697:49
at AsyncResource.runInAsyncScope (async_hooks.js:197:9)
at PrismaClient._request (/vercel/path0/node_modules/#prisma/client/runtime/index.js:39697:27)
at request (/vercel/path0/node_modules/#prisma/client/runtime/index.js:39802:77)
at _callback (/vercel/path0/node_modules/#prisma/client/runtime/index.js:40010:14)
at PrismaPromise.then (/vercel/path0/node_modules/#prisma/client/runtime/index.js:40017:23)
I created a new migration, synced it to my database, comfirmed its there on both prisma studio and database directly. So my only guess is it has something to do with vercel's cache, have they cached my database somewhere or something in node modules thats attributing to this error?
This is my retrieval code that works perfectly for other pages:
const data = await prisma.event.findMany({
where: {
sTime: {
gte: numericToDate(numericDate(today), [0,0]), //provided date from 0 hours
},
comp: {
slug: compPre
}},
orderBy: {
sTime: 'asc',
},
include: {
Eventor: {
select: {
title: true,
type:true,
eID: true,
imgUrl: true
}, // Return all fields
},
ch: {
select: {
title: true,
chID: true,
imgUrl: true
}, // Return all fields
},
sport: {
select: {
title: true,
sID: true
}, // Return all fields
},
comp: {
select: {
title: true,
slug: true,
cID: true,
imgUrl:true
}, // Return all fields
}},
})
Thanks for any help
Fixed it by including:
"vercel-build": "prisma generate && prisma migrate deploy && next build",
in scripts in package.json

Is there a way to dynamically assign a country to defaultCountry in firebase phone authentication for web?

I am trying to use firebase phone authentication for web and vuejs. I want to detect the country of the user and assign the detected country as the defaultCountry in the firebaseui config.
signInOptions: [
firebase.auth.EmailAuthProvider.PROVIDER_ID,
{
provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID,
recaptchaParameters: {
type: 'image',
size: 'invisible',
badge: 'bottomleft'
},
defaultCountry: `'${this.countryCode}'`
}
]
Below is the method I used to successfully get the country and assign to a variable in data ()
created() {
this.getDefaultCountry()
},
I even tried
defaultCountry: this.countryCode
If I hardcode a countryCode ('US', 'NZ', ... ), it works.
Thank you
If this.getDefaultCountry() is synchronous (i.e. doesn't require any database lookups, promises, etc), you should be able to use the following code, where defaultCountry is swapped out for a getter instead of a static value:
signInOptions: [
firebase.auth.EmailAuthProvider.PROVIDER_ID,
{
provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID,
recaptchaParameters: {
type: 'image',
size: 'invisible',
badge: 'bottomleft'
},
get defaultCountry() {
// contents of getDefaultCountry here
}
}
]
If your this.getDefaultCountry() is asynchronous, you will instead have to show some form of loading screen while you get the value, build signInOptions, give it to your FirebaseUI config and then finally render it.

Can anyone help implementing Nuxt.js Google Tag Manager with function based id

I installed and add this code to my nuxt.config.js and it works perfectly fine. (Link to package)
modules: [
['#nuxtjs/google-tag-manager', { id: 'GTM-XXXXXXX' }],
]
Now I am trying to implement instead of a static ID a function which will return an ID.
I tried to add this lines into my nuxt.config. js but it is not working. Obviously I have to put it somewhere else or so...
This is what I tried
nuxt.config.js
const code = '1234567'
id: () => {
return 'GTM-' + code
}
export default {
...
modules: [
['#nuxtjs/google-tag-manager', { id: id }],
]
...
}
What would be the correct way implementing this?
I would like to do something like that at the end.
modules: [
['#nuxtjs/google-tag-manager', {
id: ({ req }) => {
if (req.headers.referer == "exmple.com")
return 'GTM-156'
if (req.headers.referer == "exmple.it")
return 'GTM-24424'
if (req.headers.referer == "exmple.es")
return 'GTM-2424'
}
}]]
EDIT:
I solved my problem by rewriting the whole module. It is not possible to use this Module because it is loaded only on build time. I rewrote the module and moved the code into nuxtServerInit.
nuxtServerInit is called on each request (modules only onetime). In the request I asked from which domain the request is coming. Depending on the domain I add different google-tag-manager id's to the head and the plugin.
From package docs:
modules: [
['#nuxtjs/google-tag-manager', {
id: () => {
return axios.get('http://example.com/')
.then(({ data }) => {
return data.gtm_id
})
}
}]]
You can use process.env.NODE_ENV inside function which will return an ID
Edit 1
To put the gtm id, depending on req.headers.referer you need to provide context to the function returning the id. This can be done in middleware
See how it works here
https://github.com/nuxt-community/modules/blob/master/packages/google-tag-manager/plugin.js
Edit 2
As far as I understand your question, it will not work to have a query context in the config.
Look at i18n middleware: request.locale - > store - > update modules (router, vuetify, moment, etc.)
https://nuxtjs.org/examples/i18n/
~/middleware/gtm.js
export default function ({ app, store }) {
// app.$gtm contains id, you can set another from store
}
don't forget to add middleware to the page
page.vue
export default {
middleware: ['gtm']
}

Resources