new.pug 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. extends ../layout
  2. block head-scripts
  3. script(type="text/javascript", nonce=scriptNonce, src="https://js.recurly.com/v4/recurly.js")
  4. script(type="text/javascript", nonce=scriptNonce).
  5. window.countryCode = !{StringHelper.stringifyJsonForScript(countryCode || '')}
  6. window.recurlyApiKey = "!{settings.apis.recurly.publicKey}"
  7. window.recomendedCurrency = !{StringHelper.stringifyJsonForScript(String(currency).slice(0,3))}
  8. block content
  9. main.content.content-alt
  10. .container(ng-controller="NewSubscriptionController" ng-cloak)
  11. .row.card-group
  12. .col-md-5.col-md-push-4
  13. .card.card-highlighted.card-border(ng-hide="threeDSecureFlow")
  14. .alert.alert-danger(ng-show="recurlyLoadError")
  15. strong #{translate('payment_provider_unreachable_error')}
  16. .page-header(ng-hide="recurlyLoadError")
  17. .row
  18. .col-xs-9
  19. h2 {{planName}}
  20. .col-xs-3
  21. div.dropdown.changePlanButton.pull-right(ng-cloak, dropdown)
  22. a.btn.btn-default.dropdown-toggle(
  23. href="#",
  24. data-toggle="dropdown",
  25. dropdown-toggle
  26. )
  27. | {{currencyCode}} ({{allCurrencies[currencyCode]['symbol']}})
  28. span.caret
  29. ul.dropdown-menu(role="menu")
  30. li(ng-repeat="(currency, value) in availableCurrencies")
  31. a(
  32. ng-click="changeCurrency(currency)",
  33. ) {{currency}} ({{value['symbol']}})
  34. .row(ng-if="planCode == 'student-annual' || planCode == 'student-monthly' || planCode == 'student_free_trial_7_days'")
  35. .col-xs-12
  36. p.student-disclaimer #{translate('student_disclaimer')}
  37. hr.thin
  38. .row
  39. .col-md-12.text-center
  40. div(ng-if="trialLength")
  41. span !{translate("first_few_days_free", {trialLen:'{{trialLength}}'})}
  42. span(ng-if="coupon.discountMonths && coupon.discountRate")   - {{coupon.discountMonths}} #{translate("month")}s {{coupon.discountRate}}% Off
  43. div(ng-if="price")
  44. - var priceVars = { price: "{{ availableCurrencies[currencyCode]['symbol'] }}{{ price.total }}"};
  45. span(ng-if="!coupon.singleUse && monthlyBilling")
  46. | !{translate("x_price_per_month", priceVars, ['strong'] )}
  47. span(ng-if="!coupon.singleUse && !monthlyBilling")
  48. | !{translate("x_price_per_year", priceVars, ['strong'] )}
  49. span(ng-if="coupon.singleUse && monthlyBilling")
  50. | !{translate("x_price_for_first_month", priceVars, ['strong'] )}
  51. span(ng-if="coupon.singleUse && !monthlyBilling")
  52. | !{translate("x_price_for_first_year", priceVars, ['strong'] )}
  53. div(ng-if="coupon && coupon.normalPrice")
  54. - var noDiscountPriceAngularExp = "{{ availableCurrencies[currencyCode]['symbol']}}{{coupon.normalPrice | number:2 }}";
  55. span.small(ng-if="!coupon.singleUse && monthlyBilling")
  56. | !{translate("normally_x_price_per_month", { price: noDiscountPriceAngularExp } )}
  57. span.small(ng-if="!coupon.singleUse && !monthlyBilling")
  58. | !{translate("normally_x_price_per_year", { price: noDiscountPriceAngularExp } )}
  59. span.small(ng-if="coupon.singleUse && monthlyBilling")
  60. | !{translate("then_x_price_per_month", { price: noDiscountPriceAngularExp } )}
  61. span.small(ng-if="coupon.singleUse && !monthlyBilling")
  62. | !{translate("then_x_price_per_year", { price: noDiscountPriceAngularExp } )}
  63. .row(ng-hide="recurlyLoadError")
  64. div()
  65. .col-md-12()
  66. form(
  67. name="simpleCCForm"
  68. novalidate
  69. )
  70. div.payment-method-toggle
  71. a.payment-method-toggle-switch(
  72. href
  73. ng-click="setPaymentMethod('credit_card');"
  74. ng-class="paymentMethod.value === 'credit_card' ? 'payment-method-toggle-switch-selected' : ''"
  75. )
  76. i.fa.fa-cc-mastercard.fa-2x(aria-hidden="true")
  77. span  
  78. i.fa.fa-cc-visa.fa-2x(aria-hidden="true")
  79. span  
  80. i.fa.fa-cc-amex.fa-2x(aria-hidden="true")
  81. span.sr-only Pay with Mastercard, Visa, or Amex
  82. a.payment-method-toggle-switch(
  83. href
  84. ng-click="setPaymentMethod('paypal');"
  85. ng-class="paymentMethod.value === 'paypal' ? 'payment-method-toggle-switch-selected' : ''"
  86. )
  87. i.fa.fa-cc-paypal.fa-2x(aria-hidden="true")
  88. span.sr-only Pay with PayPal
  89. .alert.alert-warning.small(ng-show="genericError")
  90. strong {{genericError}}
  91. div(ng-show="paymentMethod.value === 'credit_card'")
  92. .row
  93. .col-xs-6
  94. .form-group(ng-class="validation.errorFields.first_name || inputHasError(simpleCCForm.firstName) ? 'has-external-error' : ''")
  95. label(for="first-name") #{translate('first_name')}
  96. input#first-name.form-control(
  97. type="text"
  98. maxlength='255'
  99. data-recurly="first_name"
  100. name="firstName"
  101. ng-model="data.first_name"
  102. required
  103. )
  104. span.input-feedback-message {{ simpleCCForm.firstName.$error.required ? 'This field is required' : '' }}
  105. .col-xs-6
  106. .form-group(ng-class="validation.errorFields.last_name || inputHasError(simpleCCForm.lastName)? 'has-external-error' : ''")
  107. label(for="last-name") #{translate('last_name')}
  108. input#last-name.form-control(
  109. type="text"
  110. maxlength='255'
  111. data-recurly="last_name"
  112. name="lastName"
  113. ng-model="data.last_name"
  114. required
  115. )
  116. .form-group(ng-class="validation.errorFields.number ? 'has-external-error' : ''")
  117. label(for="card-no") #{translate("credit_card_number")}
  118. div#card-no(
  119. type="text"
  120. name="ccNumber"
  121. data-recurly='number'
  122. )
  123. .row
  124. .col-xs-3
  125. .form-group.has-feedback(ng-class="validation.errorFields.month ? 'has-external-error' : ''")
  126. label(for="month").capitalised #{translate("month")}
  127. div(
  128. type="number"
  129. name="month"
  130. data-recurly="month"
  131. )
  132. .col-xs-3
  133. .form-group.has-feedback(ng-class="validation.errorFields.year ? 'has-external-error' : ''")
  134. label(for="year").capitalised #{translate("year")}
  135. div(
  136. type="number"
  137. name="year"
  138. data-recurly="year"
  139. )
  140. .col-xs-6
  141. .form-group.has-feedback(ng-class="validation.errorFields.cvv ? 'has-external-error' : ''")
  142. label #{translate("security_code")}
  143. div(
  144. type="number"
  145. ng-model="data.cvv"
  146. data-recurly="cvv"
  147. name="cvv"
  148. cc-format-sec-code
  149. )
  150. .form-control-feedback
  151. a.form-helper(
  152. href
  153. tabindex="-1"
  154. tooltip-template="'cvv-tooltip-tpl.html'"
  155. tooltip-trigger="mouseenter"
  156. tooltip-append-to-body="true"
  157. ) ?
  158. div
  159. .row
  160. .col-xs-12
  161. .form-group(ng-class="validation.errorFields.address1 || inputHasError(simpleCCForm.address1) ? 'has-external-error' : ''")
  162. label(for="address-line-1") #{translate('address_line_1')}
  163. input#address-line-1.form-control(
  164. type="text"
  165. maxlength="255"
  166. data-recurly="address1"
  167. name="address1"
  168. ng-model="data.address1"
  169. required
  170. )
  171. span.input-feedback-message {{ simpleCCForm.address1.$error.required ? 'This field is required' : '' }}
  172. .row
  173. .col-xs-12
  174. .form-group.has-feedback(ng-class="validation.errorFields.address2 ? 'has-external-error' : ''")
  175. label(for="address-line-2") #{translate('address_line_2')}
  176. input#address-line-2.form-control(
  177. type="text"
  178. maxlength="255"
  179. data-recurly="address2"
  180. name="address2"
  181. ng-model="data.address2"
  182. )
  183. .row
  184. .col-xs-4
  185. .form-group(ng-class="validation.errorFields.postal_code || inputHasError(simpleCCForm.postalCode) ? 'has-external-error' : ''")
  186. label(for="postal-code") #{translate('postal_code')}
  187. input#postal-code.form-control(
  188. type="text"
  189. maxlength="255"
  190. data-recurly="postal_code"
  191. name="postalCode"
  192. ng-model="data.postal_code"
  193. required
  194. )
  195. span.input-feedback-message {{ simpleCCForm.postalCode.$error.required ? 'This field is required' : '' }}
  196. .col-xs-8
  197. .form-group(ng-class="validation.errorFields.country || inputHasError(simpleCCForm.country) ? 'has-external-error' : ''")
  198. label(for="country") #{translate('country')}
  199. select#country.form-control(
  200. data-recurly="country"
  201. ng-model="data.country"
  202. name="country"
  203. ng-change="updateCountry()"
  204. ng-selected="{{country.code == data.country}}"
  205. ng-model-options="{ debounce: 200 }"
  206. required
  207. )
  208. option(value='', disabled) #{translate("country")}
  209. option(value='-', disabled) --------------
  210. option(ng-repeat="country in countries" ng-bind-html="country.name" value="{{country.code}}")
  211. span.input-feedback-message {{ simpleCCForm.country.$error.required ? 'This field is required' : '' }}
  212. .form-group
  213. .checkbox
  214. label
  215. input(
  216. type="checkbox"
  217. ng-model="ui.addCompanyDetails"
  218. )
  219. |
  220. | #{translate("add_company_details")}
  221. .form-group(ng-show="ui.addCompanyDetails")
  222. label(for="company-name") #{translate("company_name")}
  223. input#company-name.form-control(
  224. type="text"
  225. name="companyName"
  226. ng-model="data.company"
  227. )
  228. .form-group(ng-show="ui.addCompanyDetails && taxes.length")
  229. label(for="vat-number") #{translate("vat_number")}
  230. input#vat-number.form-control(
  231. type="text"
  232. name="vatNumber"
  233. ng-model="data.vat_number"
  234. ng-blur="applyVatNumber()"
  235. )
  236. if (showCouponField)
  237. .form-group
  238. label(for="coupon-code") #{translate('coupon_code')}
  239. input#coupon-code.form-control(
  240. type="text"
  241. ng-blur="applyCoupon()"
  242. ng-model="data.coupon"
  243. )
  244. p(ng-if="paymentMethod.value === 'paypal'") #{translate("paypal_upgrade")}
  245. div.price-breakdown(
  246. ng-show="taxes.length"
  247. )
  248. - var priceBreakdownVars = { total: "{{ availableCurrencies[currencyCode]['symbol'] }}{{ price.total }}", subtotal: "{{availableCurrencies[currencyCode]['symbol']}}{{ price.subtotal }}", tax: "{{availableCurrencies[currencyCode]['symbol']}}{{ price.tax }}" };
  249. hr.thin
  250. span
  251. | Total:
  252. |
  253. span(ng-if="!coupon.singleUse && monthlyBilling")
  254. | !{translate("x_price_per_month_tax", priceBreakdownVars, ['strong'] )}
  255. span(ng-if="!coupon.singleUse && !monthlyBilling")
  256. | !{translate("x_price_per_year_tax", priceBreakdownVars, ['strong'] )}
  257. span(ng-if="coupon.singleUse && monthlyBilling")
  258. | !{translate("x_price_for_first_month_tax", priceBreakdownVars, ['strong'] )}
  259. span(ng-if="coupon.singleUse && !monthlyBilling")
  260. | !{translate("x_price_for_first_year_tax", priceBreakdownVars, ['strong'] )}
  261. hr.thin
  262. div.payment-submit
  263. button.btn.btn-success.btn-block(
  264. ng-click="submit()"
  265. ng-disabled="processing || !isFormValid(simpleCCForm);"
  266. )
  267. span(ng-show="processing")
  268. i.fa.fa-spinner.fa-spin(aria-hidden="true")
  269. span.sr-only #{translate('processing')}
  270. |  
  271. span(ng-if="paymentMethod.value === 'credit_card'")
  272. | {{ monthlyBilling ? '#{translate("upgrade_cc_btn")}' : '#{translate("upgrade_now")}'}}
  273. span(ng-if="paymentMethod.value !== 'credit_card'") #{translate("upgrade_paypal_btn")}
  274. p.tos-agreement-notice
  275. | By subscribing, you agree to our
  276. |
  277. a(
  278. href="/legal#Terms"
  279. target="_blank"
  280. rel="noopener noreferrer"
  281. ) terms of service
  282. | .
  283. div.three-d-secure-container.card.card-highlighted.card-border(ng-show="threeDSecureFlow")
  284. .alert.alert-info.small(aria-live="assertive")
  285. strong #{translate('card_must_be_authenticated_by_3dsecure')}
  286. div.three-d-secure-recurly-container
  287. .col-md-3.col-md-pull-4
  288. if showStudentPlan
  289. a.btn-primary.btn.plansPageStudentLink(
  290. href,
  291. ng-click="switchToStudent()"
  292. ) #{translate("special_price_student")}
  293. .card.card-first
  294. .paymentPageFeatures
  295. h3 #{translate("unlimited_projects")}
  296. p #{translate("create_unlimited_projects")}
  297. h3
  298. if plan.features.collaborators == -1
  299. - var collaboratorCount = 'Unlimited'
  300. else
  301. - var collaboratorCount = plan.features.collaborators
  302. if plan.features.collaborators == 1
  303. | #{translate("collabs_per_proj_single", {collabcount:collaboratorCount})}
  304. else
  305. | #{translate("collabs_per_proj", {collabcount:collaboratorCount})}
  306. p #{translate("work_on_single_version")}. #{translate("view_collab_edits")} in real time.
  307. h3 #{translate("full_doc_history")}
  308. p.track-changes-example
  309. | #{translate("see_what_has_been")} #[span.added #{translate("added")}]
  310. |  #{translate("and")} #[span.removed #{translate("removed")}].
  311. p
  312. | #{translate("restore_to_any_older_version")}.
  313. h3 #{translate("sync_to_dropbox")}
  314. p
  315. | #{translate("acces_work_from_anywhere")}.
  316. | #{translate("work_offline_and_sync_with_dropbox")}.
  317. hr
  318. p.small.text-center(ng-non-bindable) We're confident that you'll love #{settings.appName}, but if not you can cancel anytime. We'll give you your money back, no questions asked, if you let us know within 30 days.
  319. script(type="text/javascript", nonce=scriptNonce).
  320. ga('send', 'event', 'pageview', 'payment_form', "#{plan_code}")
  321. script(
  322. type="text/ng-template"
  323. id="cvv-tooltip-tpl.html"
  324. )
  325. p For #[strong Visa, MasterCard and Discover], the #[strong 3 digits] on the #[strong back] of your card.
  326. p For #[strong American Express], the #[strong 4 digits] on the #[strong front] of your card.