martin
02/22/2017, 4:27 PMgc-pat
mentioned here:
now secret add gc-pat XXX
https://www.graph.cool/docs/tutorials/stripe-payments-with-mutation-callbacks-using-micro-and-now-soiyaquah7#setup-nownilan
02/22/2017, 4:28 PMmartin
02/22/2017, 4:28 PMnilan
02/22/2017, 4:28 PMnilan
02/22/2017, 4:29 PMmartin
02/22/2017, 4:29 PMnilan
02/22/2017, 4:29 PMnilan
02/22/2017, 4:29 PMmartin
02/22/2017, 4:35 PMNow, when new card details are added to a specific user, we'll run this code by means of the mutation callback
Where do I put the code? Do I create a JS file that’s somehow tied to Zeit? Never worked with Zeit before.nilan
02/22/2017, 4:37 PMmartin
02/22/2017, 4:37 PMnilan
02/22/2017, 4:37 PMnilan
02/22/2017, 4:37 PMmartin
02/22/2017, 4:39 PMnow -e STRIPE_SECRET=@stripe-secret -e GC_PAT=@gc-pat -e ENDPOINT=@endpoint create/
(replacing stripe-secret
and gc-pat
, of course) into Terminal, it gives me an error: Error! Could not read directory /Users/martinadams/create
martin
02/22/2017, 4:40 PMnilan
02/22/2017, 4:40 PMnilan
02/22/2017, 4:41 PMmartin
02/22/2017, 4:42 PMmartin
02/22/2017, 5:09 PMnilan
02/22/2017, 5:16 PMmartin
02/22/2017, 5:20 PMmartin
02/22/2017, 5:31 PMnilan
02/22/2017, 5:36 PMmartin
02/22/2017, 5:41 PMmutation
to create card details, and the node properly shows up in the console. However, nothing in Stripe. Just added you to the Graph.cool example git, which I slightly modified (to match my Model naming convention). https://github.com/ConsciousApps/LifePurposeApp-stripe-newmartin
02/22/2017, 5:42 PMnilan
02/22/2017, 5:42 PMnow
and enter the correct url?martin
02/22/2017, 5:43 PMmutation callback handler
url: https://lifepurposeapp-create-customer-ekifvzwteb.now.shmartin
02/22/2017, 5:44 PMnow -e STRIPE_SECRET=@stripe-secret -e GC_PAT=@gc-pat -e ENDPOINT=@endpoint create/
nilan
02/22/2017, 5:45 PMmartin
02/22/2017, 5:45 PMnilan
02/22/2017, 5:48 PMcartToUser
cardToUser
nilan
02/22/2017, 5:48 PMnilan
02/22/2017, 5:49 PMmartin
02/22/2017, 5:52 PMnilan
02/22/2017, 5:52 PMmartin
02/22/2017, 5:55 PMmartin
02/22/2017, 5:55 PMmartin
02/22/2017, 5:55 PMnilan
02/22/2017, 5:56 PMcardToUser
like this is undefined I guess?nilan
02/22/2017, 5:57 PMconst userId = user.id
martin
02/22/2017, 5:57 PMnilan
02/22/2017, 5:57 PMmartin
02/22/2017, 5:58 PMmartin
02/22/2017, 5:59 PMmartin
02/22/2017, 5:59 PMnilan
02/22/2017, 5:59 PMmartin
02/22/2017, 5:59 PMmartin
02/22/2017, 7:17 PMAuthenticated
for Create Node
in both CardDetails
and Purchases
Models, as per tutorial. However, the tutorial also says this:
{
allUsers(filter:{AND:[{id:$userId}, {id:$new_userId}]}){id}
}
https://www.graph.cool/docs/tutorials/stripe-payments-with-mutation-callbacks-using-micro-and-now-soiyaquah7#permission-setup
Here’s how I have the mutation
set up:
export const createCard = gql`
mutation($cardToken: String!, $userId: ID!) {
createCard: createCardDetails(
cardToken: $cardToken
cardToUserId: $userId
) {
id
}
}
`
and currently it gives me an Insufficient Permissions
GraphQL error. Any thoughts?nilan
02/22/2017, 7:18 PMmartin
02/22/2017, 7:19 PMmartin
02/22/2017, 7:20 PMEveryone
in the graphcool console.nilan
02/22/2017, 7:20 PMnilan
02/22/2017, 7:20 PMmartin
02/22/2017, 7:21 PMnilan
02/22/2017, 7:21 PMnilan
02/22/2017, 7:21 PMid
in the querynilan
02/22/2017, 7:21 PMmartin
02/22/2017, 7:21 PMEveryone
.martin
02/22/2017, 7:22 PMAuthenticated
, card was still created both in graphcool and in Stripe, but not assigned to User in graphcool)martin
02/22/2017, 7:26 PMmartin
02/22/2017, 7:27 PMonToken(token) {
const cardToken = token.id
const userId = this.props.data.user.id
this.props.createCard({ variables: { cardToken, userId } })
.then(() => {
this.props.createPurchase({ variables: { userId } })
.then((data) => {
console.log(data)
}).catch((e) => { console.error(e) })
}).catch((e) => { console.error(e) })
}
nilan
02/22/2017, 7:33 PMexport const createCard = gql`
mutation($cardToken: String!, $userId: ID!) {
createCard: createCardDetails(
cardToken: $cardToken
cardToUserId: $userId
) {
id
}
}
`
nilan
02/22/2017, 7:33 PMnilan
02/22/2017, 7:33 PMnilan
02/22/2017, 7:33 PMmartin
02/22/2017, 7:36 PMmartin
02/22/2017, 7:38 PMStartup
pricing category.)martin
02/22/2017, 7:42 PMid
from the `mutation`/`query`? I probably don’t require it anyway.nilan
02/22/2017, 7:45 PMnilan
02/22/2017, 7:45 PMmutation($cardToken: String!, $userId: ID!) {
createCard: createCardDetails(
cardToken: $cardToken
cardToUserId: $userId
) {
cardToUser {
id
}
}
}
martin
02/22/2017, 7:47 PMmartin
02/22/2017, 7:51 PMquery
for `createPurchase`:
export const createPurchase = gql`
mutation($userId: ID!) {
createPurchase: createPurchases(
amount: 999
description: "Life Purpose App"
purchaseToUserId: $userId
) {
purchaseToUser {
id
}
}
}
`
martin
02/22/2017, 7:51 PMnilan
02/22/2017, 7:51 PMGotcha. Being a complete GraphQL beginner, how would I set permission, programmatically?We are working on an easy way to do that, more information soon 🙂
nilan
02/22/2017, 7:52 PMmartin
02/22/2017, 7:53 PMcustomer
was created, but no Stripe charge
yet. Will debug… Hopefully this will be the last you hear of me regarding Stripe 😊 Have a good night!nilan
02/22/2017, 7:53 PMnow-logs
up and runningmartin
02/22/2017, 7:53 PMnilan
02/22/2017, 7:54 PMmartin
02/23/2017, 12:16 AMstripeId
wasn’t coming up. And that’s because the front-end code executed faster than the server updated the user with the stripeId
via the updateUser
mutation in the server code.
When I slowed down the front-end by 2 seconds, it was still not working. Not at 3 seconds, either. 4 seconds worked. But once it failed there, too, so I upped it to 5 seconds to be on the safe side.
BEFORE:
React front-end:
this.props.createCard({ variables: { cardToken, userId } })
.then(() => {
this.props.createPurchase({ variables: { userId } })
.then((data) => {
console.log(data)
}).catch((e) => { console.error(e) })
}).catch((e) => { console.error(e) })
AFTER:
React front-end:
this.props.createCard({ variables: { cardToken, userId } })
.then(() => {
setTimeout(() => {
this.props.createPurchase({ variables: { userId } })
.then((data) => {
console.log(data)
}).catch((e) => { console.error(e) })
}, 4000)
}).catch((e) => { console.error(e) })
martin
02/23/2017, 12:18 AMisPaid
from false
to true
in the updatePurchases
mutation. This is now making me look into subscriptions as a solution rather than clobbering together with bad fixes such as setTimeout
.martin
02/23/2017, 5:59 AMmartin
02/23/2017, 6:33 AM// Step 1: Create customer token
export const createCard = gql`
mutation($cardToken: String!, $userId: ID!) {
createCard: createCardDetails(
cardToken: $cardToken
cardToUserId: $userId
) {
cardToUser {
id
}
}
}
`
// Step 2: See if mutation callback has assigned Stripe customer ID to user
export const receiveStripeId = gql`
subscription($userId: ID!) {
receiveStripeId: updateUser(filter: {
id: $userId
}) {
stripeId
}
}
`
// Step 3: Make a purchase
export const createPurchase = gql`
mutation($userId: ID!) {
createPurchase: createPurchases(
amount: 999
description: "Life Purpose App"
purchaseToUserId: $userId
) {
purchaseToUser {
id
}
}
}
`
// Step 4: See if purchase was successful
export const checkIfPaid = gql`
subscription($userId: ID!) {
checkIfPaid: updatePurchases(filter: {
purchaseToUser: {
id: $userId
}
}) {
isPaid
}
}
`
// Step 5: If yes, upgrade app
export const upgradeApp = gql`
mutation ($userId: ID!) {
upgradeApp: updateUser(
id: $userId,
paid: true) {
id
}
}
`
Now, the front-end code. Here, token is received from Stripe
onToken(token) {
const cardToken = token.id
const userId = this.props.data.user.id
this.setState({ button: 'lpa-button hidden', loading: 'lpa-loadingwheel' })
this.props.stripePurchase()
this.props.createCard({ variables: { cardToken, userId } })
.then(() => { console.log('Creating customer...') })
.catch((e) => { console.error(e) })
}
and here, the subscription
componentWillReceiveProps(newProps) {
if (!newProps.data.loading) {
const userId = this.props.data.user.id
newProps.data.subscribeToMore({
document: receiveStripeId,
variables: { userId },
updateQuery: (previousState, { subscriptionData }) => {
const { stripeId } = subscriptionData.data.receiveStripeId
if (stripeId !== null && !this.state.paymentMade) {
console.log('Purchasing...')
this.setState({
paymentMade: true,
modalTitle: 'Upgrading...',
modalText: 'Please hang tight while you’re being upgraded.'
})
this.props.createPurchase({ variables: { userId } })
.then(() => {
console.log('Purchase complete')
})
.catch((e) => { console.error(e) })
}
},
onError: (err) => console.error(err)
})
newProps.data.subscribeToMore({
document: checkIfPaid,
variables: { userId },
updateQuery: (previousState, { subscriptionData }) => {
const { isPaid } = subscriptionData.data.checkIfPaid
if (isPaid && !this.state.appIsPaid) {
console.log('Upgrading...')
this.setState({ appIsPaid: true })
this.props.upgradeApp({ variables: { userId } })
.then(() => {
console.log('App upgraded')
this.setState({
modalTitle: 'Upgrade successful',
modalText: 'Thank you for upgrading!',
modalActionText: 'Continue',
loading: 'lpa-loadingwheel hidden'
})
})
.catch(err => console.error(err))
}
},
onError: (err) => console.error(err)
})
}
return null
}
martin
02/23/2017, 6:37 AMnilan
02/23/2017, 9:34 AMnilan
02/23/2017, 9:35 AMnilan
02/23/2017, 9:44 AMmartin
02/23/2017, 3:10 PMnilan
02/23/2017, 3:11 PMnilan
02/23/2017, 3:12 PMnilan
02/23/2017, 3:12 PMmartin
02/23/2017, 3:12 PMmartin
02/23/2017, 3:13 PMmartin
02/23/2017, 3:16 PMnilan
02/23/2017, 3:16 PMnilan
02/23/2017, 3:16 PMcreatePost
subscription is availablenilan
02/23/2017, 3:17 PMsubscription newPosts {
Post(
filter: {
mutation_in: [CREATED]
}
) {
mutation
node {
description
imageUrl
}
}
}
nilan
02/23/2017, 3:17 PMnilan
02/23/2017, 3:17 PMmartin
02/23/2017, 3:53 PMmartin
02/23/2017, 4:33 PMMixed Content: The page at 'https://' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint '<ws://subscriptions.graph.cool/ciy0lc7u302ov0119p56aari0>'. This request has been blocked; this endpoint must be available over WSS.
nilan
02/23/2017, 4:34 PMws
by wss
🙂martin
02/23/2017, 4:34 PMmartin
02/28/2017, 6:12 PMnilan
02/28/2017, 6:13 PMmartin
02/28/2017, 6:14 PMdocs
?nilan
02/28/2017, 6:14 PMmartin
02/28/2017, 6:14 PMnilan
02/28/2017, 6:14 PMmartin
02/28/2017, 6:19 PMsubscription
, the React
code can remain unchanged, right?
componentWillReceiveProps(newProps) {
const { user } = this.props.data
const userId = user.id
newProps.data.subscribeToMore({
document: receiveStripeId,
variables: { userId },
updateQuery: (previousState, { subscriptionData }) => {
const { stripeId } = subscriptionData.data.receiveStripeId
if (stripeId !== null && !this.state.paymentMade) {
console.log('Purchasing...')
this.setState({
paymentMade: true,
modalTitle: 'Upgrading...',
modalText: 'Please hang tight while you’re being upgraded.'
})
this.props.createPurchase({ variables: { userId } })
.then(() => {
console.log('Purchase complete')
})
.catch((e) => { console.error(e) })
}
},
onError: (err) => console.error(err)
})
}
nilan
02/28/2017, 6:21 PM// const { stripeId } = subscriptionData.data.receiveStripeId
const { stripeId } = subscriptionData.data.node.receiveStripeId
I believemartin
02/28/2017, 6:22 PMnilan
02/28/2017, 6:22 PM