2016-05-04 10 views
0

私はTheMeteorChefのメテオでSaaSを構築しています:ブレーズテンプレートで構築されたストライプ。代わりに反応を試してみましたが、途中でどこかで失敗したと思います。私はパート2の1/2の約半分に達しましたが、プランにサインアップするかどうかをテストするには十分です。まあ、それは動作しませんが、コンソールでもエラーを出すことはありません...私は経験がほとんどない、実際に開始したので、私はいくつかの助けを得ることができると思っています。ありがとうございました。Meteor 1.3 + React Stripe Subscription

〜/クライアント/ヘルパー/ stripe.js

Meteor.startup(function() { 
    const stripeKey = Meteor.settings.public.stripe.testPublishableKey; 
    Stripe.setPublishableKey(stripeKey); 

    STRIPE = { 
    getToken: function(domElement, card, callback) { 
     Stripe.card.createToken(card, function(status, response) { 
     if(response.error) { 
      Bert.alert(response.error.message, "danger"); 
     } else { 
      STRIPE.setToken(response.id, domElement, callback); 
     } 
     }); 
    }, 
    setToken: function(token, domElement, callback) { 
     $(domElement).append($('<input type="hidden" name="stripeToken" />').val(token)); 
     callback(); 
    } 
    } 
}); 

〜/クライアント/コンポーネント/ SignUp.jsx

import React, {Component} from 'react'; 

import PlanSelectForm from '../components/PlanSelectForm.jsx'; 
import CreditCardForm from '../components/CreditCardForm.jsx'; 

export default class SignUp extends Component { 
    componentDidMount() { 
    $.validator.addMethod('usernameRegex', function(value, element) { 
     return this.optional(element) || /^[a-zA-Z0-9-_]+$/i.test(value); 
    }, "Username must contain only letters, numbers, underscores and dashes."); 
    $('#application-signup').validate({ 
     rules: { 
     username: { 
      required: true, 
      usernameRegex: true, 
      minlength: 6 
     }, 
     emailAddress: { 
      required: true, 
      email: true 
     }, 
     password: { 
      required: true, 
      minlength: 6 
     } 
     }, 
     messages: { 
     username: { 
      required: 'You can\'t leave this empty', 
      usernameRegex: 'You can use letter, numbers, underscores, and dashes.', 
      minlength: 'Too short. Use at least 6 characters.' 
     }, 
     emailAddress: { 
      required: 'You can\'t leave this empty', 
      email: 'Email is invalid or already taken.' 
     }, 
     password: { 
      required: 'You can\'t leave this empty', 
      minlength: 'Too short. Use at least 6 characters.' 
     } 
     }, 
     handleSubmit: function() { 
     STRIPE.getToken('#application-signup', { 
      number: $('[data-stripe="cardNumber"]').val(), 
      exp_month: $('[data-stripe="expMo"]').val(), 
      exp_year: $('[data-stripe="expYr"]').val(), 
      cvc: $('[data-stripe="cvc"]').val() 
     }, function() { 
      const customer = { 
      username: $('[name="username"]').val(), 
      emailAddress: $('[name="emailAddress"]').val(), 
      password: $('[name="password"]').val(), 
      plan: $('[name="selectPlan"]:checked').val(), 
      token: $('[name="stripeToken"]').val() 
      }; 

      const submitButton = $('input[type="submit"]').button('loading'); 

      Meteor.call('createTrialCustomer', customer, function(error, response) { 
      if(error) { 
       alert(error.reason); 
       submitButton.button('reset'); 
      } else { 
       if(response.error) { 
       alert(response.message); 
       submitButton.button('reset'); 
       } else { 
       Meteor.loginWithPassword(customer.emailAddress, customer.password, function(error) { 
        if(error) { 
        alert(error.reason); 
        submitButton.button('reset'); 
        } else { 
        Router.go('/chart'); 
        submitButton.button('reset'); 
        } 
       }); 
       } 
      } 
      }); 
     }); 
     } 
    }); 
    } 

    render() { 
    console.log(this); 
    return (
     <form id="application-signup" className="signup"> 
     <h4>Account details</h4> 
     <div className="form-group"> 
      <label for="username">Username</label> 
      <input type="text" 
       name="username" 
       className="form-control" 
       placeholder="Username" /> 
     </div> 
     <div className="form-group"> 
      <label for="emailAddress">Email Address</label> 
      <input type="email" 
       name="emailAddress" 
       className="form-control" 
       placeholder="Email Address" /> 
     </div> 
     <div className="form-group"> 
      <label for="password">Password</label> 
      <input type="password" 
       name="password" 
       className="form-control" 
       placeholder="Password" /> 
     </div> 
     <h4 className="page-header">Payment Information</h4> 
     <label>Which plan sounds <em>amazing</em>?</label> 
     <PlanSelectForm /> 
     <div className="form-group"> 
      <CreditCardForm />{/* data={signup} /> */} 
     </div> 
     <div className="form-group"> 
      <input type="submit" 
       className="btn btn-success btn-block" 
       data-loading-text="Setting up your trial..." 
       value="Put me on the rocketship" /> 
     </div> 
     </form> 
    ) 
    } 
} 

注:このチュートリアルでは、TheMeteorChefはダイナミックを使用していますdata = "signup"コンテキストを持つCreditCardFormのテンプレート。私は彼がCCテンプレートは後で再び使用されることを述べていると思うが、私はまだそれを行っていない。とにかく、私は "サインアップ"の意味を知らなかったので、コメントアウトしました。もしあなたが知っていれば、それについても教えてください。

〜/クライアント/コンポーネント/ PlanSelectForm.jsx

import React, {Component} from 'react'; 

export default class PlanSelectForm extends Component { 
    componentDidMount() { 
    const firstPlanItem = $('.select-plan a:first-child'); 
    firstPlanItem.addClass('active'); 
    firstPlanItem.find('input').prop('checked', true); 
    } 

    plans() { 
    return Meteor.settings.public.plans; 
    } 

    handleClickItem(e) { 
    const parent = $(e.target).closest('.list-group-item'); 
    console.log(parent); 
    parent.addClass('active'); 
    $('.list-group-item').not(parent).removeClass('active'); 
    $('.list-group-item').not(parent).find('input[type="radio"]').prop('checked', false); 
    parent.find('input[type="radio"]').prop('checked', true); 
    } 

    render() { 
    let plans = this.plans(); 
    if(!plans) { 
     return(<div>loading...</div>); 
    } 
    return (
     <div className="list-group select-plan"> 
     {plans.map((plan) => { 
      return (
      <a key={plan.id} 
       href="#" 
       className="list-group-item" 
       onClick={this.handleClickItem.bind(this)}> 
       <input key={plan.id} 
        type="radio" 
        ref="selectPlan" 
        id={`selectPlan_${plan.id}`} 
        value={plan.name} /> 
       {plan.name} {plan.amount.usd}/{plan.interval} 
      </a> 
     ) 
     })} 
     </div> 
    ) 
    } 
} 

〜/クライアント/コンポーネント/ CreditCardForm.jsx

import React, {Component} from 'react'; 

export default class CreditCardForm extends Component { 
    render() { 
    return (
     <div> 
     <div className="row"> 
      <div className="col-xs-12"> 
      <div className="form-group"> 
       <label className="text-success"> 
       <i className="fa fa-lock"></i> Card Number 
       </label> 
       <input type="text" 
        data-stripe="cardNumber" 
        className="form-control card-number" 
        placeholder="Card Number" /> 
      </div> 
      </div> 
     </div> 
     <div className="row"> 
      <div className="col-xs-4"> 
      <label>Exp. Mo.</label> 
      <input type="text" 
        data-stripe="expMo" 
        className="form-control exp-month" 
        placeholder="Exp. Mo." /> 
      </div> 
      <div className="col-xs-4"> 
      <label>Exp. Yr.</label> 
      <input type="text" 
        data-stripe="expYr" 
        className="form-control exp-year" 
        placeholder="Exp. Yr." /> 
      </div> 
      <div className="col-xs-4"> 
      <label>CVC</label> 
      <input type="text" 
        data-stripe="cvc" 
        className="form-control cvc" 
        placeholder="CVC" /> 
      </div> 
     </div> 
     </div> 
    ) 
    } 
} 

〜/サーバー/ signup.js

Meteor.methods({ 
    createTrialCustomer: function(customer) { 
    check(customer, { 
     name: String, 
     emailAddress: String, 
     password: String, 
     plan: String, 
     token: String 
    }); 

    const emailRegex = new RegExp(customer.emailAddress, 'i'); 
    const usernameRegex = new RegExp(customer.username, 'i'); 
    const lookupEmail = Meteor.users.findOne({'emails.address': emailRegex}); 
    const lookupUser = Meteor.users.findOne({'username': usernameRegex}); 

    if(!lookupEmail) { 
     if(!lookupUser) { 
     const newCustomer = new Future(); 

     Meteor.call('stripeCreateCustomer', customer.token, customer.emailAddress, function(error, stripeCustomer) { 
      if(error) { 
      console.log(error); 
      } else { 
      const customerId = stripeCustomer.id, 
        plan  = customer.plan; 

      Meteor.call('stripeCreateSubscription', customerId, plan, function(error, response) { 
       if(error) { 
       console.log(error); 
       } else { 
       try { 
        const user = Accounts.createUser({ 
        username: customer.username, 
        email: customer.emailAddress, 
        password: customer.password 
        }); 

        const subscription = { 
        customerId: customerId, 
        subscription: { 
         plan: { 
         name: customer.plan, 
         used: 0 
         }, 
         payment: { 
         card: { 
          type: stripeCustomer.sources.data[0].brand, 
          lastFour: stripeCustomer.sources.data[0].last4 
         }, 
         nextPaymentDue: response.current_period_end 
         } 
        } 
        } 
        Meteor.users.update(user, { 
        $set: subscription 
        }, function(error, response) { 
        if(error) { 
         console.log(error); 
        } else { 
         newCustomer.return(user); 
        } 
        }); 
       } catch(exception) { 
        newCustomer.return(exception); 
       } 
       } 
      }); 
      } 
     }); 
     return newCustomer.wait(); 
     } else { 
     throw new Meteor.Error('username-exists', 'Sorry, that username is already active!'); 
     } 
    } else { 
     throw new Meteor.Erro('email-exists', 'Sorry, that email is already active!') 
    } 
    }, 
}) 

〜/サーバー/ stripe.js

const secret = Meteor.settings.private.stripe.testSecretKey; 
const Stripe = StripeAPI(secret); 

Meteor.methods({ 
    stripeCreateCustomer: function(token, email) { 
    check(token, String); 
    check(email, String); 

    const stripeCustomer = new Future(); 

    Stripe.customers.create({ 
     source: token, 
     email: email 
    }, function(error, customer) { 
     if(error){ 
     stripeCustomer.return(error); 
     } else { 
     stripeCustomer.return(customer); 
     } 
    }); 

    return stripeCustomer.wait(); 
    }, 

    stripeCreateSubscription: function(customer, plan) { 
    check(customer, String); 
    check(plan, String); 

    const stripeSubscription = new Future(); 

    Stripe.customers.createSubscription(customer, { 
     plan: plan 
    }, function(error, subscription) { 
     if(error) { 
     stripeSubscription.return(error); 
     } else { 
     stripeSubscription.return(subscription); 
     } 
    }); 

    return stripeSubscription.wait(); 
    } 
}) 

パッケージ読書のための

"dependencies": { 
    "meteor-node-stubs": "~0.2.0", 
    "react": "^15.0.2", 
    "react-addons-css-transition-group": "^15.0.2", 
    "react-dom": "^15.0.2", 
    "react-mounter": "^1.2.0" 
    }, 



accounts-base 
accounts-password 
session 
check 
random 

kadira:flow-router 
ultimatejs:tracker-react 
meteortoys:allthings 

fourseven:scss 
fortawesome:fontawesome 
themeteorchef:bert 
themeteorchef:jquery-validation 
momentjs:moment 

mrgalaxy:stripe 

おかげで、私はそれが苦痛ではなかったことを願っています。

+0

** **質問は何ですか?デバッグの助けを求める質問(「なぜこのコードは動作しませんか?」)には、目的の動作、特定の問題またはエラー、および質問自体の中でそれを再現するのに必要な最短コードが含まれていなければなりません。明確な問題文がない質問は、他の読者にとって有用ではありません。参照:[最小限で完全で検証可能なサンプルの作成方法](http://stackoverflow.com/help/mcve) – Polygnome

答えて

0

mrgalaxy:stripeをインポートしましたか? それは私が推測する

import { StripeAPI } from 'meteor/mrgalaxy:stripe'

のようなものになります。

ANW、あなたがNPMによってインストールすることができます。 npm install stripe

import Stripe from 'stripe'

その後、

Stripe('your_secret_key')

関連する問題