I was following the example shown at:
Ionic React: Implementing InAppPurchase 2 on React Hooks
I kept getting errors saying that:
"
InAppPurchase[objc]: Product (signatureyearly) does not exist or is not sucessfully initialized.
"
I have tried "com.myappname.app.signatureyearly" as well but I get similar errors.
I have double confirmed that my app bundle id is "com.myappname.app" and my IAP product ID is "signatureyearly" it is a renewal subscription and it is "Ready to submit".
Really need help with this, has been trying to figure this out for many days.
This is what I have written so far.
Thank you so much !!!!
import React, { useState, useEffect } from 'react';
import { InAppPurchase2 as iap, IAPProduct } from "#ionic-native/in-app-purchase-2";
export const TestStore: React.FC = () => {
//declare variables
const [productPrice, setPrice] = useState('')
const [product, setProduct] = useState([]) as any
//initiate initInAppPurchase function
useEffect(() => {
const init = async () => {
await initInAppPurchase();
}
init();
}, []);
const initInAppPurchase = () => {
iap.verbosity = iap.DEBUG;
iap.register({
id: "signatureyearly",
type: iap.PAID_SUBSCRIPTION
});
iap.ready(() => {
let product = iap.get('signatureyearly');
setPrice(product.price)
setProduct(product)
})
iap.refresh();
}
//if user clicks purchase button
const purchaseProduct = () => {
if (product.owned) {
alert('Product already owned, click restore button instead!')
} else {
iap.order('signatureyearly').then(() => {
iap.when("signatureyearly").approved((p: IAPProduct) => {
//store product
p.verify();
p.finish();
});
})
iap.refresh();
}
}
//if user clicks retore or promo code button
const restore = () => {
iap.when("signatureyearly").owned((p: IAPProduct) => {
if (product.owned) {
//store product
} else {
alert("You have not purchased this product before.")
}
});
iap.refresh();
}
return (
<div>
<button onClick={purchaseProduct}>TEST 4 :Buy for {productPrice}</button>
<button onClick={restore}>Restore</button>
<button onClick={restore}>Promo code</button>
</div>
);
};
Related
I've one question. I don't understand why, but my services is undefined. Someone could help me to clarify this ?
I've a component "FormLogin" with the call of this service
<script>
import { authenticationService } from '#/container.js'
import { ref } from '#vue/reactivity'
export default {
emits: ['successfullyLogged'],
setup (props, context) {
const errors = ref([])
const email = ref(null)
const password = ref(null)
const submit = () => {
errors.value = []
authenticationService()
.login(email.value, password.value)
.then(() => {
context.emit('successfullyLogged')
})
.catch(error => {
errors.value = [error.response.data.message]
})
}
return {
email,
password,
errors,
submit
}
}
}
</script>
Then i've the "global injection"
import api from '#/clients/api.js'
import TokenRepository from '#/repositories/TokenRepository.js'
import AuthenticationService from '#/services/AuthenticationService.js'
export function tokenRepository () {
return new TokenRepository()
}
export function authenticationService () {
return new AuthenticationService(api, tokenRepository)
}
And after that, the service itself
import store from "#/store"
export default (client, tokenRepository) => {
const login = (email, password) => {
return client.post('/oauth/token', {
grant_type: 'password',
client_id: process.env.VUE_APP_CLIENT_ID,
client_secret: process.env.VUE_APP_CLIENT_SECRET,
username: email,
password: password
})
.then(response => {
tokenRepository().store(response.data.access_token)
store.dispatch('account/loadUser')
})
}
const logout = () => {
tokenRepository().destroy()
store.commit('account/setUser', {})
}
return {
login,
logout
}
}
But when i run this code, fill my form fields and hit the button "submit", i've this error in console, and i don't undestand why. (And when i try to use the debugger, it appear that authenticationService in FormLogin is undefined.
Thanks in advance for your help,
Christophe
So the answer of the problem was to remove the word "new" in my container.js
Bad answer for me
export function authenticationService () {
return new AuthenticationService(api, tokenRepository)
}
Good answer for me
export function authenticationService () {
return AuthenticationService(api, tokenRepository)
}
Hi so I have a view where I have a button , When it's clicked I want a value to be saved in the db . What I get now is nothing like I click on button but nothing happens .
Here's the code I have :
<a-button type="primary" class="mb-4 text-center mr-1 float-right" #click="onSubmit">Confirm</a-button>
in my script I have:
setup(){
const onSubmit = () => {
axios.post("/insertstatut/"+876,"added").then((res)=>{
message.success(`statut ajouté`)
router.push({
path:'/cand',
}).catch(error => {
console.log('error', error);
})
} ,
)
}
}
Please if u have any idea what I should do , do share thank you.
you are using composition api feature setup in your vue code,
you need to return the methods or properties u wish to use in in your template.
setup () {
return {
onSubmit: () => {}, //some method u want to use later in template ,
show: false, // or some property
}
}
this is how your component should look
<template>
<a-button
type="primary"
class="mb-4
text-center
mr-1float-right"
#click="onSubmit"
>
Confirm
</a-button>
</template>
<script>
import AButton from './button-path/AButton.vue'
import axios from 'axios'
export default {
componets: { AButton },
setup() {
const onSubmit = () => {
axios.post('/insertstatut/' + 876, 'added').then((res) => {
message.success(`statut ajouté`)
router
.push({
path: '/cand',
})
.catch((error) => {
console.log('error', error)
})
})
}
// Expose your constants/methods/functions
return {
onSubmit,
}
},
}
</script>
I've created a small keypad app in react and I'm trying to test the input event on the app and for some reason I am not getting the expected result. I'm trying to test it to failure and success. The test I'm running is this below, I want to input 1995 (the correct combination), click the unlock button and ultimately have a message return Unlocked! but it only returns Incorrect Code! which should only happen if the code is incorrect or the input field is empty. But it shouldn't be empty as I have filled it out in the test..
here is a codesandbox: https://codesandbox.io/s/quirky-cloud-gywu6?file=/src/App.test.js:0-26
Any ideas?
test:
const setup = () => {
const utils = render(<App />);
const input = utils.getByLabelText("input-code");
return {
input,
...utils
};
};
test("It should return a successful try", async () => {
const { input, getByTestId } = setup();
await act(async () => {
fireEvent.change(input, { target: { value: "1995" } });
});
expect(input.value).toBe("1995");
await act(async () => {
fireEvent.click(getByTestId("unlockbutton"));
});
expect(getByTestId("status")).toHaveTextContent("Unlocked!");
});
the component I'm trying to test
import React, { useState, useEffect } from "react";
import Keypad from "./components/Keypad";
import "./App.css";
import "./css/Result.css";
function App() {
//correctCombination: 1995
const [result, setResult] = useState("");
const [locked, setLocked] = useState("Locked");
const [tries, setTries] = useState(0);
const [hide, setHide] = useState(true);
//Along with the maxLength property on the input,
// this is also needed for the keypad
useEffect(() => {
(function() {
if (result >= 4) {
setResult(result.slice(0, 4));
}
})();
}, [result]);
const onClick = button => {
switch (button) {
case "unlock":
checkCode();
break;
case "clear":
clear();
break;
case "backspace":
backspace();
break;
default:
setResult(result + button);
break;
}
};
const checkCode = () => {
if (result === "1995") {
setLocked("Unlocked!");
setTries(0);
} else if (tries === 3) {
setHide(false);
setLocked("Too many incorrect attempts!");
setTimeout(() => {
setHide(true);
}, 3000);
} else {
setLocked("Incorrect code!");
setTries(tries + 1);
}
};
const clear = () => {
setResult("");
};
const backspace = () => {
setResult(result.slice(0, -1));
};
const handleChange = event => {
setResult(event.target.value);
};
return (
<div className="App">
<div className="pin-body">
<h1>Pin Pad</h1>
<div className="status">
<h2 data-testid="status">{locked}</h2>
</div>
<div className="result">
<input
maxLength={4}
type="phone"
aria-label="input-code"
data-testid="inputcode"
placeholder="Enter code"
onChange={handleChange}
value={result}
/>
</div>
{hide ? <Keypad onClick={onClick} /> : false}
</div>
</div>
);
}
export default App;
I have the following component that I'm trying to test with react-testing-library:
const PasswordIconButton = ({
stateString
}) => {
const { state, dispatch } = useContext(Store);
const showPassword = getObjectValue(stateString, state);
const toggleShowPassword = event => {
event.preventDefault();
dispatch(toggleBoolean(stateString, !showPassword));
};
return (
<Layout
showPassword={showPassword}
toggleShowPassword={toggleShowPassword}
/>
);
};
export default PasswordIconButton;
const Layout = ({
showPassword,
toggleShowPassword
}) => {
return (
<IconButton onClick={toggleShowPassword} data-testid="iconButton">
{showPassword ? (
<HidePasswordIcon data-testid="hidePasswordIcon" />
) : (
<ShowPasswordIcon data-testid="showPasswordIcon" />
)}
</IconButton>
);
};
This works exactly as intended in production. If the user clicks the button then it calls toggleShowPassword() which toggles the value of boolean const showPassword.
If showPassword is equal to false and the user clicks the button, I can see that the <ShowPasswordIcon /> is removed and <HidePasswordIcon /> appears. Both have the correct data-testid attributes set.
I'm attempting to test the component will the following test:
import React from "react";
import {
render,
cleanup,
fireEvent,
waitForElement
} from "react-testing-library";
import PasswordIconButton from "./PasswordIconButton";
afterEach(cleanup);
const mockProps = {
stateString: "signUpForm.fields.password.showPassword"
};
describe("<PasswordIconButtonIcon />", () => {
it("renders as snapshot", () => {
const { asFragment } = render(<PasswordIconButton {...mockProps} />);
expect(asFragment()).toMatchSnapshot();
});
//
// ISSUE IS WITH THIS TEST:
// ::::::::::::::::::::::::::
it("shows 'hide password' icon on first click", async () => {
const { container, getByTestId } = render(
<PasswordIconButton {...mockProps} />
);
const icon = getByTestId("iconButton");
fireEvent.click(icon);
const hidePasswordIconTestId = await waitForElement(
() => getByTestId("hidePasswordIcon"),
{ container }
);
expect(hidePasswordIconTestId).not.toBeNull();
});
});
The shows 'hide password' icon on first click test always fails and I'm not sure why. The mockProps are definitely correct and work perfectly in production.
What am I missing here?
I figured it out... The issue is that I needed to wrap the component in the context provider as const { state, dispatch } = useContext(Store); won't work properly without it.
So I changed the render to:
const { container, getByTestId } = render(
<StateProvider>
<PasswordIconButton {...mockProps} />
</StateProvider>
);`
And now the test passes fine.
I'm using Ioni v4Beta and I'm traying to update the sidemenu when the user is login.
I search but the usual solution is use Events:
Ionic 3 refresh side menu after login
https://ionicframework.com/docs/api/util/Events/
But in the new version I don't find it, and I don't know how to do it
https://beta.ionicframework.com/docs/api
Thanks a lot, but I finally find how to import it:
import { Events } from '#ionic/angular';
Example on how to do it with subjects:
export const someEvent:Subject = new Subject();
export class ReceivingClass implements OnDestroy, OnInit
{
private someEventSubscription:Subscription;
public OnInit():void{
someEventSubscription = someEvent.subscribe((data) => console.log(data);
}
public onDestroy():void{
someEvent.unsubscribe();
}
}
export class SendingClass implements OnInit
{
public OnInit():void{
setTimeout(() => {
someEvent.next('hi');
}, 500);
}
}
Are you aware that Ionic v4 events will be deprecated soon?
I was also trying to update the sidemenu when a user logs in as well, so i tried using: import { Events } from '#ionic/angular';
However I got a warning referring me to this link https://angular.io/guide/observables#basic-usage-and-terms which I failed to follow because am not that familiar with observables.
After much research I found that I can still use events but I had to import them from angular's router directive.
This was my code before:
/* import was */
import { Events } from '#ionic/angular';
import { Storage } from '#ionic/storage';//ignore this import if doesn't apply to your code
/* inside the class */
constructor(
private events: Events,
private storage: Storage
) {
this.events.subscribe("updateMenu", () => {
this.storage.ready().then(() => {
this.storage.get("userLoginInfo").then((userData) => {
if (userData != null) {
console.log("User logged in.");
let user = userData.user;
console.log(user);
}
else {
console.log("No user found.");
let user = {};
}
}).catch((error)=>{
console.log(error);
});
}).catch((error)=>{
console.log(error);
});
});
}
changes i made that actually got my code working and deprecation warning gone:
/* import is now */
import { Router,RouterEvent } from '#angular/router';
import { Storage } from '#ionic/storage';//ignore this import if it does't apply to your code
Rest of code
constructor(
public router: Router,
public storage: Storage
){
this.router.events.subscribe((event: RouterEvent) => {
this.storage.ready().then(() => {
this.storage.get("userLoginInfo").then((userData) => {
if (userData != null) {
/*console.log("User logged in.");*/
let user = userData.user;
/*console.log(this.user);*/
}
else {
/*console.log("No user found.");*/
let user = {};
}
}).catch((error)=>{
console.log(error);
});
}).catch((error)=>{
console.log(error);
});
});
}
I got the idea after seeing this https://meumobi.github.io/ionic/2018/11/13/side-menu-tabs-login-page-ionic4.html. I hope my answer can be useful.
Steps to resolve the issue
import events in login page and in sidemenu view
In login page, after login success do your logic to publish the events.
for eg:
this.authService.doLogin(payload).subscribe((response) => {
if (response.status) {
this.storage.set('IS_LOGGED_IN', true);
this.events.publish('user:login');
}
}, (error) => {
console.log(error);
});
In sidemenu view, create a listener to watch the events 'user:login'
for eg:
this.menus = [];
// subscribe events
this.events.subscribe('user:login', () => {
// DO YOUR LOGIC TO SET THE SIDE MENU
this.setSidemenu();
});
// check whether the user is logged in or not
checkIsUserloggedIn() {
let isLoggedIn = false;
if (this.storage.get('IS_LOGGED_IN') == '' ||
this.storage.get('IS_LOGGED_IN') == null ||
this.storage.get('IS_LOGGED_IN') == undefined) {
isLoggedIn = false;
} else {
isLoggedIn = true;
}
return isLoggedIn;
}
// to set your sidemenus
setSidemenu() {
let isUserLoggedIn = this.checkIsUserloggedIn();
if(isUserLoggedIn) {
this.menus = ['Home', 'Aboutus', 'Contactus', 'My Profile', 'Logout'];
} else {
this.menus = ['Login', 'Home', 'Aboutus', 'Contactus'];
}
}