How to configure gtm to track OrderPlacedEvent in SAP-Spartacus? - spartacus-storefront

I am using Spartacus 4.2 and i am tracking a bunch of events via GTM.
I have configured gtm to track some custom and standard events but when i try to add the OrderPlacedEvent i get the following error:
Type 'TmsConfig' has no properties in common with type 'Config'
The import for OrderPlacedEvent looks like this:
import { OrderPlacedEvent } from '#spartacus/checkout/root';
GTM-Configuration:
provideConfig({
tagManager: {
gtm: {
dynamicConfiguration: true,
// TODO: Add events for tracking here
events: [
NavigationEvent,
OrderPlacedEvent,
//... (custom Events)
],
debug: true,
},
},
} as TmsConfig),
Does anybody know what im doing wrong?

I've faced a similar problem. The reason was that some feature module was referenced before the #spartacus/core and it messed up the Config type augmentation.
You need to check if some feature module doesn't get imported before #spartacus/core. For instance in app.module.ts.

Related

Spartacus Product Configurator - Authorization Code Flow breaks deep links

I am currently working on implementing the authorization code flow with Auth0 for our Spartacus application. The authentication works fine and I can navigate the page from the root. However when I try to access a deep link, e.g. /configure/vc/product/entityKey/key I get redirected to the Homepage. Same behaviour when I refresh the page.
I observed that the pages request gets canceled and instead the Router routes to "/". I don't see any Fail Actions being fired by ngrx.
Debugging the flow, I believe it has to do with the AuthService.checkOAuthParamsInUrl() method, which throws an exception in line
const result = await this.oAuthLibWrapperService.tryLogin(); (https://github.com/SAP/spartacus/blob/develop/projects/core/src/auth/user-auth/facade/auth.service.ts)
The method seems to check for the code inside the url, which is not available in deep links. I assumed it would take the token from the local storage if available.
Am I on the wrong track, or is the only possiblity to adjust the behaviour of the AuthService? If so, how should I go on with it?
Spartacus Version: 3.4.3.
rxjs Version: 6.6.7
[EDIT] My AuthConfig:
provideConfig(<AuthConfig>{
authentication: {
OAuthLibConfig: {
responseType: 'code',
redirectUri: environment.spartacus.auth.redirectUrl,
customQueryParams: {
connection: 'main-tenant-oidc',
audience: 'my-audience'
}
},
baseUrl: 'https://my-auth.auth0.com',
client_id: 'id',
client_secret: 'secret',
loginUrl: '/authorize',
tokenEndpoint: '/oauth/token',
userinfoEndpoint: '/userinfo',
revokeEndpoint: '/oauth/revoke'
}
})
[EDIT]
The AuthGuard confirms that the user is logged in, i.e. the isUserLoggedIn() function returns true.
[EDIT]
Updated to Spartacus 4 following the reference structure, no change of behaviour. I am configuring authentication via
routing: {protected: true}
My Feature Module looks like this, knowing that I definitly dont need all of the imports:
import {NgModule} from '#angular/core';
import {OrderConfirmationModule, ReplenishmentOrderConfirmationModule} from "#spartacus/checkout/components";
import {CheckoutOccModule} from "#spartacus/checkout/occ";
import {
AuthModule,
CartModule,
CartOccModule,
CostCenterOccModule,
ExternalRoutesModule,
ProductModule,
ProductOccModule,
UserOccModule
} from "#spartacus/core";
// TODO:Spartacus - 'ProductVariantsModule' was removed from #spartacus/storefront. Use #spartacus/product/variants feature-library instead. To benefit from lazy loading it by default, consider removing the module import and running the command 'ng add #spartacus/product --features=Product-Variants'.
// TODO:Spartacus - 'UserComponentModule' - Following module imports 'LoginModule', 'LoginFormModule', 'LoginRegisterModule', 'RegisterComponentModule' were removed. Those modules are now part of #spartacus/user.
import {
AddressBookModule,
BannerCarouselModule,
BannerModule,
BreadcrumbModule,
CartComponentModule,
CartPageEventModule,
CategoryNavigationModule,
CmsParagraphModule,
FooterNavigationModule,
HamburgerMenuModule,
LinkModule,
MyCouponsModule,
MyInterestsModule,
NavigationEventModule,
NavigationModule,
NotificationPreferenceModule,
OrderCancellationModule,
OrderDetailsModule,
OrderHistoryModule,
OrderReturnModule,
PaymentMethodsModule,
ProductCarouselModule,
ProductDetailsPageModule,
ProductFacetNavigationModule,
ProductImagesModule,
ProductIntroModule,
ProductListingPageModule,
ProductListModule,
ProductPageEventModule,
ProductReferencesModule,
ProductSummaryModule,
ProductTabsModule,
ReplenishmentOrderDetailsModule,
ReplenishmentOrderHistoryModule,
ReturnRequestDetailModule,
ReturnRequestListModule,
SearchBoxModule,
SiteContextSelectorModule,
StockNotificationModule,
TabParagraphContainerModule,
WishListModule
} from "#spartacus/storefront";
import {
CloseAccountModule,
ForgotPasswordModule,
RegisterComponentModule,
ResetPasswordModule,
UpdateEmailModule,
UpdatePasswordModule,
UpdateProfileModule
} from "#spartacus/user/profile/components";
import {ProductVariantsFeatureModule} from './features/product/product-variants-feature.module';
import {LoginFormModule, LoginModule, LoginRegisterModule} from "#spartacus/user/account/components";
import { UserFeatureModule } from './features/user/user-feature.module';
#NgModule({
declarations: [],
imports: [
// Migrating the StorefrontModule
ProductDetailsPageModule,
ProductListingPageModule,
ExternalRoutesModule.forRoot(),
// Migrating the CmsLibModule
HamburgerMenuModule,
CmsParagraphModule,
LinkModule,
BannerModule,
CategoryNavigationModule,
NavigationModule,
FooterNavigationModule,
BreadcrumbModule,
SearchBoxModule,
SiteContextSelectorModule,
AddressBookModule,
OrderHistoryModule,
OrderCancellationModule,
OrderReturnModule,
ReturnRequestListModule,
ReturnRequestDetailModule,
ProductListModule,
ProductFacetNavigationModule,
ProductTabsModule,
ProductCarouselModule,
ProductReferencesModule,
OrderDetailsModule,
PaymentMethodsModule,
CartComponentModule,
TabParagraphContainerModule,
OrderConfirmationModule,
ProductImagesModule,
ProductSummaryModule,
ProductIntroModule,
BannerCarouselModule,
MyCouponsModule,
WishListModule,
NotificationPreferenceModule,
MyInterestsModule,
StockNotificationModule,
ReplenishmentOrderHistoryModule,
ReplenishmentOrderConfirmationModule,
ReplenishmentOrderDetailsModule,
CloseAccountModule,
UpdateEmailModule,
UpdatePasswordModule,
UpdateProfileModule,
ForgotPasswordModule,
ResetPasswordModule,
// Migrating the StorefrontFoundationModule
AuthModule.forRoot(),
CartModule.forRoot(),
ProductModule.forRoot(),
// Migrating the OccModule
CartOccModule,
CheckoutOccModule,
ProductOccModule,
UserOccModule,
CostCenterOccModule,
// Migrating the EventsModule
CartPageEventModule,
NavigationEventModule,
ProductPageEventModule,
ProductVariantsFeatureModule,
// UserComponentModule Substitution
LoginModule,
LoginFormModule,
LoginRegisterModule,
RegisterComponentModule,
UserFeatureModule
]
})
export class SpartacusFeaturesModule {
}
[EDIT]
Important to notice: Our tokens are not being validated by SAP Commerce Backend. So it may be an issue with the error responses, that differ from the native error responses.
Thanks for any hints :)
The throw from this method is not unusual and is handled with the try-catch. This confirms even that if this throws we don't invoke this.authRedirectService.redirect(); method.
In my opinion the depth of the url should not make any difference to Auth handling. I would look either into other guards that could cause some redirect or into this code specific to this configurator routes.

I'm trying to use react-call-detection to detect a missed call number but something is not working

Hey there to everyone!
I'm posting my first question so I'll try to be as clear as possible!
I'm building a native android app using react-native(0.61.5), I'm using setState hook instead of the classic state and I want to use the react-native-call-detection library(1.8.2).
What is the problem?
function startListenerTapped() {
console.log('start');
callDetector = new CallDetectorManager((event, number) => {
console.log(event);
console.log('inside call detector');
if (event === 'Missed') {
console.log(event);
console.log(number);
setMissedCaller(number);
}
},
true,
() => { console.error('access denied') },
{
title: 'Phone State Permission',
message: 'This app needs access to your phone state in order to react and/or to adapt to incoming calls.'
}
)
}
I run this function when my component mounts, callDetector is set as undefined, I get the 'start' log but when I simulate a call on my AVD nothing happens.
From what I understood the CallDetectorManager works like an event listener, right?
Or do I need to start it every time a call happens?
Another thing I've had a problem with was when I was trying to run a build for the app. I have Gradle 6.0 and I had an error with the react-native-call-detection:
Attribute application#allowBackup value=(false) from AndroidManifest.xml:13:7-34
is also present at [:react-native-call-detection] AndroidManifest.xml:21:9-35 value=(true).
Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at
AndroidManifest.xml:7:5-117 to override.
I couldn't really understand what this meant, and the only thing that I've found that solved it was to create a react-native.config.js file with this line of code in it:
module.exports = { dependencies: { 'react-native-call-detection': { platforms: { android: null, }, }, }, };
Another thing that I've only noticed now is that I have a problem with the module of the library.
Could not find a declaration file for module 'react-native-call-detection'.
'c:/folders/projectName/node_modules/react-native-call-detection/index.js' implicitly has an 'any' type.
Try `npm install #types/react-native-call-detection` if it exists or add a new declaration (.d.ts) file containing `declare module 'react-native-call-detection';`
Does anybody knows what that means?!
I think I start to think that it means that I need to find an alternative to this library... AHAHA!
Any kind of help or solution would be more than welcome!
Thanks in advance for everything!

“window is not defined” in Nuxt.js

I get an error porting from Vue.js to Nuxt.js.
I am trying to use vue-session in node_modules. It compiles successfully, but in the browser I see the error:
ReferenceError window is not defined
node_modules\vue-session\index.js:
VueSession.install = function(Vue, options) {
if (options && 'persist' in options && options.persist) STORAGE = window.localStorage;
else STORAGE = window.sessionStorage;
Vue.prototype.$session = {
flash: {
parent: function() {
return Vue.prototype.$session;
},
so, I followed this documentation:
rewardadd.vue:
import VueSession from 'vue-session';
Vue.use(VueSession);
if (process.client) {
require('vue-session');
}
nuxt.config.js:
build: {
vendor: ['vue-session'],
But I still cannot solve this problem.
UPDATED AUGUST 2021
The Window is not defined error results from nodejs server side scripts not recognising the window object which is native to browsers only.
As of nuxt v2.4 you don't need to add the process.client or process.browser object.
Typically your nuxt plugin directory is structured as below:
~/plugins/myplugin.js
import Vue from 'vue';
// your imported custom plugin or in this scenario the 'vue-session' plugin
import VueSession from 'vue-session';
Vue.use(VueSession);
And then in your nuxt.config.js you can now add plugins to your project using the two methods below:
METHOD 1:
Add the mode property with the value 'client' to your plugin
plugins: [
{ src: '~/plugins/myplugin.js', mode: 'client' }
]
METHOD 2: (Simpler in my opinion)
Rename your plugin with the extension .client.js and then add it to your plugins in the nuxt.config.js plugins. Nuxt 2.4.x will recognize the plugin extension as to be rendered on the server side .server.js or the client side .client.js depending on the extension used.
NOTE: Adding the file without either the .client.js or .server.js extensions will render the plugin on both the client side and the server side. Read more here.
plugins: ['~/plugins/myplugin.client.js']
There is no window object on the server side rendering side. But the quick fix is to check process.browser.
created(){
if (process.browser){
console.log(window.innerWidth, window.innerHeight);
}
}
This is a little bit sloppy but it works. Here's a good writeup about how to use plugins to do it better.
Its all covered in nuxt docs and in faq. First you need to make it a plugin. Second you need to make your plugin client side only
plugins: [
{ src: '~/plugins/vue-notifications', mode: 'client' }
]
Also vendor is not used in nuxt 2.x and your process.client not needed if its in plugin with ssr false
In Nuxt 3 you use process.client like so:
if (process.client) {
alert(window);
}
If you've tried most of the answers here and it isn't working for you, check this out, I also had the same problem when using Paystack, a payment package. I will use the OP's instances
Create a plugin with .client.js as extension so that it can be rendered on client side only. So in plugins folder,
create a file 'vue-session.client.js' which is the plugin and put in the code below
import Vue from 'vue'
import VueSession from 'vue-session'
//depending on what you need it for
Vue.use(VueSession)
// I needed mine as a component so I did something like this
Vue.component('vue-session', VueSession)
so in nuxt.config.js, Register the plugin depending on your plugin path
plugins:[
...
{ src: '~/plugins/vue-session.client.js'},
...
]
In index.vue or whatever page you want to use the package... import the package on mounted so it is available when the client page mounts...
export default {
...
mounted() {
if (process.client) {
const VueSession = () => import('vue-session')
}
}
...
}
You can check if you're running with client side or with the browser. window is not defined from the SSR
const isClientSide: boolean = typeof window !== 'undefined'
Lazy loading worked for me. Lazy loading a component in Vue is as easy as importing the component using dynamic import wrapped in a function. We can lazy load the StepProgress component as follows:
export default {
components: {
StepProgress: () => import('vue-step-progress')
}
};
On top of all the answers here, you can also face some other packages that are not compatible with SSR out of the box and that will require some hacks to work properly. Here is my answer in details.
The TLDR is that you'll sometimes need to:
use process.client
use the <client-only> tag
use a dynamic import if needed later on, like const Ace = await import('ace-builds/src-noconflict/ace')
load a component conditionally components: { [process.client && 'VueEditor']: () => import('vue2-editor') }
For me it was the case of using apex-charts in Nuxt, so I had to add ssr: false to nuxt.config.js.

What are the available options for LayoutAnimation.Types

I have a custom layout animation taken from here.
var CustomLayoutAnimation = {
duration: 200,
create: {
type: LayoutAnimation.Types.linear,
property: LayoutAnimation.Properties.opacity,
},
update: {
type: LayoutAnimation.Types.curveEaseInEaseOut,
},
};
When running the code i get the following warning
Warning: Failed config type: The config config.update.type is marked
as required in LayoutAnimation.configureNext, but its value is
undefined.
The code has an entry for update.type, yet the warning says it's undefined. I'm guessing that the permitted values have been updated since the gist was written.
I tried to find out the list of available permitted entries but they are not listed in the React Native LayoutAnimation documentation.
I'd like to know :
Is the syntax no longer correct?
Is there a webpage somewhere that details the list of availble Types?
Whenever I run into an issue like this, I go to the source code. Here's the file for LayoutAnimation.js from the react-native source code. Based on this, I see a TypesEnum const declaration at line 25 looking like this:
const TypesEnum = {
spring: true,
linear: true,
easeInEaseOut: true,
easeIn: true,
easeOut: true,
keyboard: true,
};
I suspect that's why you are erring out - curveEaseInEaseOut is not a supported type. Choose one from the list above and I think you should be good to go. Hope this helps!

Sencha touch 2.0 : Store loading, first availability

I'm trying to figure out when a store is ready to be used within my app.
I figured from the doc that if I want to display information from my store, I should listen to the 'refresh' event of my store to get notified when it has been changed (and thus also when it is first loaded).
However, using the following example:
Ext.define('MyApp.store.Config', {
extend: 'Ext.data.Store',
config: {
autoLoad: true,
autoSync: true,
model: 'MyApp.model.Config',
listeners: {
refresh: function() {
console.log(Ext.StoreManager.get('Config').getAt(0))
}
}
} });
the 'console.log' gets called twice at startup, and it fails the first time (it seems that the Store is not loaded yet). My model uses a proxy (type ajax, and a json reader).
Could someone tell me how I should proceed to avoid this error?
Thanks!
I found the reason...
I was declaring the 'stores:['Config']' property both in my app.js and in on of my controllers.
Quite hard to spot but my mistake...