Paypal Checkout button - environment configuration - Angular 6 - javascript

I implemented the paypal express checkout in my app, and now I need to build the app for production, to go live. I used ngx-payapl, and it looks something like this:
private initConfig(): void {
this.payPalConfig = new PayPalConfig(PayPalIntegrationType.ClientSideREST,
// Here I need to see how to change the environment to
// PayPalEnvironment.Production
PayPalEnvironment.Sandbox, {
commit: true,
client: {
// how to will it trigger production for ng-build --prod?
sandbox: '...sandboxclientid...',
production: '...liveclientid...',
},
button: {
label: 'paypal',
},
transactions: [{
amount: {
currency: 'USD',
total: 30
},
description: ''
}],
onPaymentComplete: (data, actions) => {
// some api calls
},
onCancel: (data, actions) => {
console.log('Payment canceled');
},
onError: (err) => {
console.log(err);
},
onClick: () => {
// some code
}
});
}
I guess I get the live client ID from the dashboard, thats ok, and I should keep those ID's in environment files, but how can I change the environment itself here? I guess I would need the PayPalEnvironment.Production and to look for client.production?

You have 2 options: the first is as you describe, put two different values for the same configuration key under environment files. then you just need to read the key from the configuration and you'll get a different value for dev mode and prod.
The second option, you can also check in each component if you are in dev mode and to initialize payapl based on the env.
EDIT:
For the first method: from the library code this is how PayPalEnvironment is defined this is actual an enum:
export enum PayPalEnvironment {
Sandbox = 'sandbox',
Production = 'production'
}
So in order to use the environment files you should define two environment files one for dev and one for prod, you can see the full way to define config here
After adding two config files, just add one key for paypalEnv, for development put its value to 'sandbox' and for prod the value should be 'production'
for example:
// file: environment/environment.dev.ts
export const environment = {
production: false,
paypalEnv: 'sandbox',
};
then to use the configuration file, under you PyaPal component to the following:
// Change for correct path
import { environment } from '../../environments/environment';
private initConfig(): void {
this.payPalConfig = new PayPalConfig(PayPalIntegrationType.ClientSideREST,
environment.paypalEnv, {
commit: true,
client: {
// how to will it trigger production for ng-build --prod?
sandbox: '...sandboxclientid...',
production: '...liveclientid...',
},
...
});
}
For the second method you can use the following way:
import { isDevMode } from '#angular/core';
...
private initConfig(): void {
// The console.log here is just for demo but you can use the value to decide
console.log(isDevMode());
}

You can do like below ...
Just switch the PayPalEnvironment based on your environment config.
this.payPalConfig = new PayPalConfig(
PayPalIntegrationType.ClientSideREST,
environment.production
? PayPalEnvironment.Production
: PayPalEnvironment.Sandbox,
{
commit: true,
client: {
sandbox: environment.keys.paypal_sandbox_key,
production: environment.keys.paypal_production_key
}
}
// Other Configs
);
}

This should work. To change environments, just change the 'env' property from sandbox to production.
someFile.ts
import { Component, OnInit, AfterViewChecked } from "#angular/core";
import { CartService } from "../cart.service";
declare let paypal: any;
#Component({
selector: "app-shopping-cart",
templateUrl: "./shopping-cart.component.html",
styleUrls: ["./shopping-cart.component.css"]
})
export class ShoppingCartComponent implements OnInit, AfterViewChecked {
cartItemsArray = this.cart.cartItems;
constructor(private cart: CartService) {
this.cart.count.subscribe(price => {
this.finalAmount = price;
});
}
ngOnInit() {}
//Paypal
addScript: boolean = false;
finalAmount: number;
paypalConfig = {
env: "sandbox",
client: {
sandbox:
"sandbox-key",
production: "production-key"
},
commit: true,
payment: (data, actions) => {
return actions.payment.create({
payment: {
transactions: [
{ amount: { total: this.finalAmount, currency: "USD" } }
]
}
});
},
onAuthorize: (data, actions) => {
return actions.payment.execute().then(payment => {});
}
};
//End of Paypal
ngAfterViewChecked(): void {
if (!this.addScript) {
this.addPaypalScript().then(() => {
paypal.Button.render(this.paypalConfig, "#paypal-checkout-button");
});
}
}
addPaypalScript() {
this.addScript = true;
return new Promise((resolve, reject) => {
let scripttagElement = document.createElement("script");
scripttagElement.src = "https://www.paypalobjects.com/api/checkout.js";
scripttagElement.onload = resolve;
document.body.appendChild(scripttagElement);
});
}
}
someFile.component.html
<div id="paypal-checkoutout-button"></div>

Related

Possible to combine apollo queries (within nuxt?)

I am using nuxt and apollo together with: https://github.com/nuxt-community/apollo-module
I have a working GraphQL query (tested in GraphiQL):
(Because I want to fetch the info about my page and also some general SEO information)
{
entries(section: [pages], slug: "my-page-slug") {
slug
title
}
seomatic(uri: "/") {
metaTitleContainer
metaTagContainer
metaLinkContainer
metaScriptContainer
metaJsonLdContainer
}
}
I want to fetch this data as well with apollo in nuxt:
So I tried:
<script>
import page from '~/apollo/queries/page'
import seomatic from '~/apollo/queries/seomatic'
export default {
apollo: {
entries: {
query: page,
prefetch: ({ route }) => ({ slug: route.params.slug }),
variables() {
return { slug: this.$route.params.slug }
}
},
seomatic: {
query: seomatic,
prefetch: true
}
},
…
If I do that I will get an error message:
GraphQL error: Cannot query field "seomatic" on type "Query".
I then found this issue
https://github.com/apollographql/apollo-tooling/issues/648
and I would like to know if ths could be a problem of the apollo nuxt module.
Because following that fix indicated in the issue does not resolve anything.
I further tried to combine the two calls into one:
fragment SeoMaticFragment on Root {
seomatic(uri: "/") {
metaTitleContainer
metaTagContainer
metaLinkContainer
metaScriptContainer
metaJsonLdContainer
}
}
query myQuery($slug: String!) {
entries(section: [pages], slug: $slug) {
slug
title
}
SeoMaticFragment
}
~/apollo/queries/page.gql
But this would first throw an error
fragment Unknown type "Root"
So what is the best way to combine?
Why are the requests failing
is there an option to activate batching like described here: https://blog.apollographql.com/query-batching-in-apollo-63acfd859862
-
const client = new ApolloClient({
// ... other options ...
shouldBatch: true,
});
thank you so much in advance.
Cheers
There is actually a solution to this problem.
I found out that the result hook in vue-apollo solves this problem:
Example code that works:
<script>
import gql from 'graphql-tag'
const query = gql`
{
entries(section: [pages], slug: "my-example-page-slug") {
slug
title
}
seomatic(uri: "/") {
metaTitleContainer
metaTagContainer
metaLinkContainer
metaJsonLdContainer
}
}
`
export default {
data: () => {
return {
page: false,
seomatic: {}
}
},
apollo: {
entries: {
query,
prefetch: ({ route }) => ({ slug: route.params.slug }),
variables() {
return { slug: this.$route.params.slug }
}
},
result(result) {
this.entries = result.data.entries
this.seomatic = result.data.seomatic
}
}
}
</script>

Changing Jest mock value between tests

I have a utility file that uses the following implementation with a vuex store:
// example.js
import store from '#/store';
[...]
export default function exampleUtil(value) {
const user = store.state.user.current;
[...]
}
In my test, I found that I can successfully mock the value of user in the following two ways:
Manual mock
// store/__mocks__/index.js
export default {
state: {
user: {
current: {
roles: [],
isAdmin: false,
},
},
},
};
or
Mock function
// example.spec.js
jest.mock('#/store', () => ({
state: {
user: {
current: {
roles: [],
isAdmin: false,
},
},
},
}));
The issue that I'm running into is that I want to be able to change the value of current between tests, such as changing isAdmin to true or updating the array for roles.
What is the best way to do this using Jest mocks?
It turns out that the value of a mock can be changed inside a test directly after importing the mocked file.
Using the mock function example from above:
// example.spec.js
import store from '#/store'; // <-- add this
jest.mock('#/store', () => ({
state: {
user: {
current: {
roles: [],
isAdmin: false,
},
},
},
}));
it('should do things', () => {
store.state.user.current.roles = ['example', 'another']; // <-- change mock value here
[...]
});

JavaScript warning: Assignment to property of function parameter

I compiled vue-flash-message component from sources and got the following warning:
✘ http://eslint.org/docs/rules/no-param-reassign Assignment to property of function parameter 'Vue'
src\components\vue-flash-message\index.js:173:5
Vue.prototype[options.storage] = FlashBus;
in the following code:
export default {
install(Vue, config = {}) {
const defaults = {
method: 'flash',
storage: '$flashStorage',
createShortcuts: true,
name: 'flash-message',
};
const options = Object.assign(defaults, config);
...
const FlashBus = new Vue({
data() {
return {
storage: {
},
};
},
methods: {
flash(msg, type, opts) {
return new FlashMessage(FlashBus, msg, type, opts);
},
push(id, message) {
Vue.set(this.storage, id, message);
},
destroy(id) {
Vue.delete(this.storage, id);
},
destroyAll() {
Vue.set(this, 'storage', {});
},
},
});
...
Vue.prototype[options.storage] = FlashBus;
...
},
};
is it possible to correct the code and make it compile without warnings?
This is not an issue.
You have an ES Lint rule setup for no-param-reassign. This conflicts with Vue's way of creating plugins, where you are directed to write to the prototype directly. You can see my statement reinforced here
Your only choice is to fork that project, and ignore the line with your linter if it's bugging you that much.

How can I evaluate Python code in the document context from JavaScript in JupyterLab?

With Jupyter Notebooks, I could have a cell
%%javascript IPython.notebook.kernel.execute('x = 42')
Then, elsewhere in the document a Python code cell with x would show it bound to 42 as expected.
I'm trying to produce something similar with JupyterLab. I understand I'm supposed to write a plugin rather than using ad-hoc JS, and that's fine, but I'm not finding an interface to the kernel similar to the global IPython from notebooks:
import { JupyerLab, JupyterLabPlugin } from '#jupyterlab/application';
const extension: JupyterLabPlugin<void> = {
// ...
requires: [],
activate: (app: JupyterLab) => {
// can I get to Python evaluation through app?
// by adding another class to `requires` above?
}
}
export default extension;
Here's a hacky attempt that "works". Could still use advice if anyone knows where there is a public promise for the kernel being ready, how to avoid the intermediate class, or any other general improvements:
import { JupyterLab, JupyterLabPlugin } from '#jupyterlab/application';
import { DocumentRegistry } from '#jupyterlab/docregistry';
import { INotebookModel, NotebookPanel } from '#jupyterlab/notebook';
import { IDisposable, DisposableDelegate } from '#phosphor/disposable';
declare global {
interface Window {
'execPython': {
'readyState': string,
'exec': (code: string) => any,
'ready': Promise<void>
} | null
}
}
class ExecWidgetExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
createNew(nb: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
if (window.execPython) {
return;
}
window.execPython = {
'readyState': 'waiting',
'exec': null,
'ready': new Promise((resolve) => {
const wait = setInterval(() => {
if (!context.session.kernel || window.execPython.readyState === 'ready') {
return;
}
clearInterval(wait);
window.execPython.readyState = 'ready';
window.execPython.exec = (code: string) =>
context.session.kernel.requestExecute({ code }, true);
resolve();
}, 50);
})
};
// Usage elsewhere: execPython.ready.then(() => execPython.exec('x = 42').done.then(console.log, console.error))
return new DisposableDelegate(() => {});
}
}
const extension: JupyterLabPlugin<void> = {
'id': 'jupyterlab_foo',
'autoStart': true,
'activate': (app: JupyterLab) => {
app.docRegistry.addWidgetExtension('Notebook', new ExecWidgetExtension())
}
};
export default extension;

How to access an object by referencing its value from a string in React Native?

what exactly I want to do is, I have a file say permissions.js with contents:
Permissions.js
module..exports = {
Student: {
Read: true,
Service: "StudentService",
Teach: false
},
Teacher: {
Read: false,
Service: "TeacherService",
Teach: true
}
}
and another file functions.js:
functions.js
// functions.js
module.exports = {
StudentService: {
someFunc1: function() {...},
someFunc2: function() {...},
someFunc3: function() {...}
},
TeacherService: {
someFunc1: function() {...},
someFunc2: function() {...},
someFunc3: function() {...}
}
}
and importing both the files in school.js:
school.js
// school.js
import functions from "./path-to/functions.js";
import { Student, Teacher } from "./path-to/permissions.js";
// Making it very simple
let service = Student.Service; // service = "StudentService"
service.someFunc1() // returns someFunc1 is not a function
So what I want to do is use the service variable as a reference for the StudentService in functions.js. Cannot use require.
This doesn't isn't specific to react-native at all, just modern JS modules. This will work:
import * as functions from "./path-to/functions.js"
import { Student } from "./path-to/permissions.js"
let service = Student.Service;
functions[service].someFunc1
A better approach though would be this:
perissions.js
import { StudentService, TeacherService } from "./path-to/functions.js";
module.exports = {
Student: {
Read: true,
Service: StudentService,
Teach: false
},
Teacher: {
Read: false,
Service: TeacherService,
Teach: true
}
}
And then you never have to mess about referencing things with strings.

Categories

Resources