Where can I initialize Firebase analytics in a Deno Fresh project? - firebase-analytics

By default Fresh only ships static pages to the browsers. Only Islands add interactivity. How can I add Firebase analytics to my Fresh App to collect data on all routes?
Usually it would work like this:
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-app.js";
import { getAnalytics, isSupported } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-analytics.js";
import "dotenv/load.ts";
const firebaseConfig = {
apiKey: Deno.env.get("apiKey"),
authDomain: Deno.env.get("authDomain"),
projectId: Deno.env.get("projectId"),
storageBucket: Deno.env.get("storageBucket"),
messagingSenderId: Deno.env.get("messagingSenderId"),
appId: Deno.env.get("appId"),
measurementId: Deno.env.get("measurementId"),
};
const firebase = initializeApp(firebaseConfig);
let analytics;
if (await isSupported()) {
analytics = getAnalytics(firebase);
console.log("Analytics initialized!");
} else {
analytics = null
console.warn("Analytics is not supported...");
}
export { firebase, analytics };
But since the isSupported() and getAnalytics(firebase) has to be run on the client in the browser I don't know where to call them.

Related

Google Functions v2 and NestJs

I'm looking into spinning up an api with nest using google cloud functions v2, looks like some people is doing it using nx: https://itnext.io/a-perfect-match-nestjs-cloud-functions-2nd-gen-nx-workspace-f13fb044e9a4, can this be done using nx?
I'm looking into a more vanilla example just using functions-framework and nest. Can somebody point me to any repo or example?
Thanks!
Nx is just tooling. It should be the same as you implement without NX. Can you try it in a normal Nestjs project?
// main.ts
const server = express()
import { http } from '#google-cloud/functions-framework'
export const createNestServer = async (expressInstance) => {
const app = await NestFactory.create(AppModule, new ExpressAdapter(expressInstance))
const globalPrefix = 'api'
app.setGlobalPrefix(globalPrefix)
app.enableCors()
return app.init()
}
createNestServer(server)
.then((v) => {
if (environment.production) {
Logger.log('šŸš€ Starting production server...')
} else {
Logger.log(`šŸš€ Starting development server on http://localhost:${process.env.PORT || 3333}`)
v.listen(process.env.PORT || 3333)
}
})
.catch((err) => Logger.error('Nest broken', err))
http('apiNEST', server)

How to store product-info into session in WooCommerce using Next.js and headless wordpress

I am currently working on a Next.js project. As Iā€™m building an online-shop, I also want to create a shopping-cart. I use wordpress (headless) via graphql and the api of WooCommerce.
Now the idea is to somehow store the product information into a session or using the local storage. I think storing the product id would be sufficient, because I want to sell online products that have an unlimited quantity and each customer can only download the product once.
What do I have to do in order that WooCommerce understands, what I want to achieve?
Is it possible instead of using an endpoint to just use the product-info from a JSON? (This is probably not so secure, but as I am only testing. It should be fine)
I have read that also cookies have to be written in order for WooCommerce to work and save the selected product into the shopping-cart.
I would be very thankful for any help šŸ˜Š
Down below I show you part of my current state...
main file for the cart:
import { getSession, storeSession } from './session';
import { getAddOrViewCartConfig } from './api';
import axios from 'axios';
import { ADD_TO_CART_ENDPOINT } from '../constants/endpoints';
import { isEmpty } from 'lodash';
export const addToCart = (productId: int, qty: int = 1) => {
const storedSession = getSession();
const addOrViewCartConfig = getAddOrViewCartConfig();
axios.post(
ADD_TO_CART_ENDPOINT, //instead of using an endpoint, I would like to pull the desired info from a JSON file
data: {
product_id: productId,
quantity: qty,
},
addOrViewCartConfig
)
.then((res: AxiosResponse<any>) => {
if (!isEmpty(storedSession)) {
storeSession(res?.headers?.['x-wc-session']);
}
viewCart();
})
.catch((err) => {
console.log('err', err);
});
};
getAddOrViewCartConfig from api:
import { getSession } from './session';
import { isEmpty } from 'lodash';
export const getAddOrViewCartConfig = () => {
const config = {
headers: {
'X-Headless-CMS': true,
},
};
const storedSession = getSession();
if (!isEmpty(storedSession)) {
config.headers['x-wc-session'] = storedSession;
}
return config;
};
getSession, storeSession from session
import { isEmpty } from "lodash";
export const storeSession = (session) => {
if(isEmpty(session)){
return null;
}
localStorage.setItem('x-wc-session',session);
}
export const getSession = ()=>{
return localStorage.getItem(key:'x-wc-session');
}

Accessing Vuex Store Before Page Load NuxtJS

Context: I am trying to get Google Maps place data via the place_id on the beforeEnter() route guard. Essentially, I want the data to load when someone enters the url exactly www.example.com/place/{place_id}. Currently, everything works directly when I use my autocomplete input and then enter the route but it does not work when I directly access the url from a fresh tab. I've been able to solve this using the beforeEnter() route guard in traditional Vue, but cannot solve for this using Nuxt. Please help!
Question: How can I access the Vuex Store before a page loads in Nuxt?
Error: Any solution I try (see below) I either end up with a blank page or the page will not load (I think it is stuck in a loop and cannot resolve the Promise).
Attempted Solutions:
Using Middleware like below:
middleware({ store, params }) {
return store.dispatch('myModule/fetchLocation', params.id)
}
Using asyncData like below:
data(){
return{
filteredLocation: {}
}
}
// snip
async asyncData({ store, params }) {
const { data } = await store.dispatch('myModule/fetchLocation', params.id)
return filteredLocation = data
}
I tried looking into fetch, but apparently you no longer have access to context
Example Code:
In one of my store modules:
/* global google */
import Vue from 'vue'
import * as VueGoogleMaps from '~/node_modules/vue2-google-maps/src/main'
Vue.use(VueGoogleMaps, {
load: {
key: process.env.VUE_APP_GMAP_KEY,
libraries: 'geometry,drawing,places'
}
})
export const state = () => ({
selectedLocation: {}
})
export const actions = {
fetchLocation({ commit }, params) {
return new Promise((resolve) => {
Vue.$gmapApiPromiseLazy().then(() => {
const request = {
placeId: params,
fields: [
'name',
'rating',
'formatted_phone_number',
'geometry',
'place_id',
'website',
'review',
'user_ratings_total',
'photo',
'vicinity',
'price_level'
]
}
const service = new google.maps.places.PlacesService(
document.createElement('div')
)
service.getDetails(request, function(place, status) {
if (status === 'OK') {
commit('SET_PLACE', place)
resolve()
}
})
})
})
}
}
export const mutations = {
SET_PLACE: (state, selection) => {
state.selectedInstructor = selection
}
}
EDIT: I already have it in a plugin named google-maps.js and in my nuxt.config.js file I have:
plugins: [
{ src: '~/plugins/google-maps.js' }
]
//
//
build: {
transpile: [/^vue2-google-maps.js($|\/)/],
extend(config, ctx) {}
}
Using Middleware is how we can access Vuex before page loads. try putting the configuration part in a custom Nuxt plugin.
Create a file in Plugins folder (you can name it global.js).
Put this
import Vue from 'vue'
import * as VueGoogleMaps from '~/node_modules/vue2-google-maps/src/main'
Vue.use(VueGoogleMaps, {
load: {
key: process.env.VUE_APP_GMAP_KEY,
libraries: 'geometry,drawing,places'
}
})
in global.js.
Then add the plugin in nuxt.config.js like this.
plugins: [
'~/plugins/global.js'
]
Also, make sure you're using underscore before 'page_id' name in your folder structure.

How to pass const to multiple components / Spliting React-Redux-Router files

I am creating a Spotify app with its API. I want 4 views (like '/', 'nowPlaying', 'favouriteArtists', 'favouriteSongs').
I need to setAccessToken for using functions like getMyCurrentPlaybackState() in every new page, right?. Idk if I need to if(params.access_token){spotifyWebApi.setAccessToken(params.access_token)} in every container that will use functions like getMyCurrentPlaybackState(). I was thinking of creating a Spotify.jsx container that handle the store of the Spotify Object (which is used in the token and in every container that use spotify functions). But with this Spotify.jsx i don't know either if it is a good approach nor how to connect its needed spotifyWebApi const to every container file and token file.
For better understanding of my idea: I would create a Token.jsx that has getHashParams() and a Playing.jsx that has getNowPlaying(). Every one needs the spotifyWebApi const.
import React, { Component } from 'react';
import Spotify from 'spotify-web-api-js';
const spotifyWebApi = new Spotify();
class App extends Component {
constructor(){
super();
const params = this.getHashParams();
this.state = {
loggedIn: params.access_token ? true : false,
nowPlaying: {
name: 'Not Checked',
image: ''
}
}
if (params.access_token){
spotifyWebApi.setAccessToken(params.access_token)
}
}
getHashParams() {
var hashParams = {};
var e, r = /([^&;=]+)=?([^&;]*)/g,
q = window.location.hash.substring(1);
while ( e = r.exec(q)) {
hashParams[e[1]] = decodeURIComponent(e[2]);
}
return hashParams;
}
getNowPlaying(){
spotifyWebApi.getMyCurrentPlaybackState()
.then((response) => {
this.setState({
nowPlaying: {
name: response.item.name,
image: response.item.album.images[0].url
}
})
})
}
}
Your title mentions Redux, but I don't see your code utilizing it. With Redux, you could get the access_token and then store it in state. This will allow you to use it in any Redux connected component.
Also, with Redux, you can use Redux Thunk (or similar) middleware that will allow you to use Redux actions to call an API. So then you would just write the different API calls as Redux actions, which would allow you to call them from any component, and have the results added to your Redux store (which again, can be used in any Redux connected component).
So, for example, your getNowPlaying() function could be an action looking something like this:
function getNowPlaying() {
return function (dispatch, getState) {
// get the token and init the api
const access_token = getState().spotify.access_token
spotifyWebApi.setAccessToken(access_token)
return spotifyWebApi.getMyCurrentPlaybackState().then((response) => {
dispatch({
type: 'SET_NOW_PLAYING',
name: response.item.name,
image: response.item.album.images[0].url
})
})
}
}
Note: You'll need to configure the Redux reducer for "spotify" (or however you want to structure your store) to store the data you need.
So, you could then call getNowPlaying() from any component. It stores the results in the redux store, which you could also use from any connected component. And you can use the same technique of getting the access_token from the store when needed in the actions.
Alternatively, if you didn't want to use Redux, you could provide context values to all child components, using React's Context features. You could do this with that token that each component would need in your setup. But Redux, in my opinion, is the better option for you here.
Instead of passing this const to other components, I would create a SpotifyUtils.jsx and inside it declare the const. And in this helper file I would export functions so other components can use them.
For example:
import Spotify from 'spotify-web-api-js';
const spotifyWebApi = new Spotify();
let token = null
export function isLoggedIn() {
return !!token
}
export function setAccessToke(_token) {
token = _token;
spotifyWebApi.setAccessToken(_token);
}
export function getNowPlaying(){
return spotifyWebApi.getMyCurrentPlaybackState()
.then((response) => {
return {
name: response.item.name,
image: response.item.album.images[0].url
}
})
}
So that in the components you can use them like so:
import React, { Component } from 'react';
import {
isLoggedIn,
setAccessToken,
getNowPlaying,
} from 'helpers/SpotifyUtils'
class App extends Component {
constructor(){
super();
this.state = {
loggedIn: isLoggedIn(),
nowPlaying: {
name: 'Not Checked',
image: ''
}
}
getHashParams() {
var hashParams = {};
var e, r = /([^&;=]+)=?([^&;]*)/g,
q = window.location.hash.substring(1);
while ( e = r.exec(q)) {
hashParams[e[1]] = decodeURIComponent(e[2]);
}
return hashParams;
}
componentDidMount() {
if (!this.state.loggedIn) {
const params = this.getHashParams();
if (params.access_token) {
setAccessToken(params.access_token)
getNowPlaying()
.then(nowPlaying => this.setState({ nowPlaying }))
}
}
}
}
This will enable your spotifyWebApi const to be reused in any component you import the helper functions. I am particularly found of this pattern, creating utils or helpers in a generic fashion so that you can reuse code easily. Also if spotify Web Api releases a breaking change, your refactor will be easier because you will only need to refactor the SpotifyUtils.jsx file since it will be the only file using import Spotify from 'spotify-web-api-js'

angular 6 universal issue 'Module not found: Error: Can't resolve './dist/server/main' in '/var/www/html/angular6/testing''

I am trying to do universal rendering in angular 6 with the help of this link.I followed the steps mentioned in the above link,but it shows following error.
ERROR in ./server.ts
Module not found: Error: Can't resolve './dist/server/main' in '/var/www/html/angular6/testing'
# ./server.ts 16:9-38
server.ts
// These are important and needed before anything else
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { enableProdMode } from '#angular/core';
import * as express from 'express';
import { join } from 'path';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express server
const app = express();
const PORT = process.env.PORT || 3005;
const DIST_FOLDER = join(process.cwd(), 'dist');
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
// Express Engine
import { ngExpressEngine } from '#nguniversal/express-engine';
// Import module map for lazy loading
import { provideModuleMap } from '#nguniversal/module-map-ngfactory-loader';
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));
// TODO: implement data requests securely
app.get('/api/*', (req, res) => {
res.status(404).send('data requests are not supported');
});
// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('index', { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node server listening on http://localhost:${PORT}`);
});
can anyone please help me to solve this issue?I already spend lot of time in this issue.
There were a number of breaking changes and the documentation isn't up to date.
Step 3 of https://github.com/angular/angular-cli/wiki/stories-universal-rendering fixed the issue you mentioned for me.
I had been using the nx workspace generator and it was serving up the server into the browser rather than building the files in angular.json as outlined below:
"architect": {
"build": { ... }
"server": {
"builder": "#angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/your-project-name-server",
"main": "src/main.server.ts",
"tsConfig": "src/tsconfig.server.json"
}
}
}