This package manages Stripe subscriptions in Vulcan. It only handles fixed price subscriptions using Stripe Elements.
The starting point of this package is the original vulcan-payments
package, so uses the same Charges
collection. Therefore, there are likely to be conflicts if you use them both together.
- This is a port of the fixed price Stripe example into Vulcan.
- This package doesn't yet handle inserting products. You must add them manually. See below:
Add your products from the Stripe dashboard, or using the Stripe CLI client. Using the CLI package can be faster, here's how in 3 steps:
-
Install the Stripe client of:
npm install --save stripe
- Make sure it's the latest version (8.79.0 or above). Check your package.json in case! -
Add your products using Stripe CLI. Paste service products into your terminal:
stripe products create \ --name="Letter Pro" \ --type=service \ --description="Unlimited letters and components."
-
Add the subscription service tiers/prices using the productId that is returned from the above command. For example, if you have monthly and annual pricing, here's how you'd add both prices to the same product:
- Add Monthly at $20 per month
stripe prices create \ -d product=prod_Hhv922zP2fFoHs \ -d unit_amount=2000 \ -d currency=usd \ -d "recurring[interval]"=month
- Add yearly at $15 per month, billed annually
To add a yearly option, create a new price, using the same product ID, and set the interval to year.
E.g. here I set the unit amount to $15
stripe prices create \ -d product=prod_Hhv922zP2fFoHs \ -d unit_amount=1500 \ -d currency=usd \ -d "recurring[interval]"=year
In your project, add a products.js
, and use addSubscriptionProduct
from meteor/vulcan:stripe-subscriptions
to add the subscription products from step 1. These are for vulcan to know about your products. Here's an example following on from the previous step:
import { addSubscriptionProduct } from 'meteor/vulcan:stripe-subscriptions';
addSubscriptionProduct(
'pro-yearly',
{
apiId: 'price_1H9xrbHdc8hnogUr6R9uDO6j',
name: 'Letter Pro',
price: '$180.00',
term:'year'
}
);
addSubscriptionProduct(
'pro-monthly',
{
apiId: 'price_1H9xrbHdc8hnogUrkRWK8b6f',
name: 'Letter Pro',
price: '$20.00',
term:'month'
}
);
The apiId can be found in your Stripe dashboard (https://dashboard.stripe.com/test/products/), it looks like this:
Now you should be set up, here's are components to add the checkout to your project:
Shows a checkout button - when clicked, a modal with the checkout form is displayed:
<Components.CheckoutModal
vulcanProductKey={this.state.checked ? "pro-yearly" : 'pro-monthly'}
buttonText="Get Pro"
associatedCollection={'Users'}
associatedDocument={currentUser._id}
fragmentName="UserSetAsPaid"
fragment={gql`
fragment UserSetAsPaid on User {
_id
status
paidAt
}
`}
/>
- vulcanProductKey: This is Vulcan's identifier of the Stripe product. It's the name provided as the first argument to
addSubscriptionProduct
in step 2. - buttonText: custom button text
- associatedCollection: this must be the String name of your collection
- associatedDocument: this must be the String ID of the document you want to associate with the subscription
The expanded modal displays the Stripe checkout using Stripe elements:
This is bare bones, but with Stripe Elements, you can customise the look and feel so that it looks native to your app. See examples here.
When a payment is successful, that user is added to the paidMembers
group (created here).
When restricting premium content, check if the user is part of the paidMembers
group:
if(Users.isMemberOf(currentUser, 'paidMembers')){
//member only stuff
}
When a subscription is cancelled, the user is not removed from the paidMembers
group. This is because users should keep access to premium services until the end of the period they have paid for.
To handle this, an extra function is provided: isSubscriptionActive
:
- It checks if the current date exceeds the subscription end date.
- At that point, status of the subscription is set to expired.
- Once the subscription status is updated, the Charges collection callback runs, and removes the user from
paidMembers
.
This should be used when the user logs in, or whenever you need to check if a user's subscription should be terminated (e.g. cancelled).
isSubscriptionActive
is an async function, here's how to add it to your vulcan component:
- Make sure you import
withMutation
import { withMutation} from "meteor/vulcan:core";
- Define the mutation at the bottom of your component, just like this:
const isSubscriptionActive = {
name: 'isSubscriptionActive',
args: { userId: 'String' }
};
- When registering your component, add it as a HoC:
registerComponent({
name: "ComponentName",
component: Component,
hocs: [[withMutation,isSubscriptionActive ]]
});
Now this.props.isSubscriptionActive()
is available to call from within your component. e.g.:
//check if the subscription is active
var subscriptionActive = await this.props.isSubscriptionActive()
//returns true or false, and updates the user group if necessary.
if(subscriptionActive && Users.isMemberOf(this.props.currentUser, 'paidMembers')){
}
- Add all checkout component examples
- Add issues/things to improve