diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 0f41171f70..d8841e11fd 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,7 +7,7 @@ */ return array( 'names' => array( - 'core.pkg.css' => 'cd54f10c', + 'core.pkg.css' => 'd9fa6161', 'core.pkg.js' => '23d653bb', 'darkconsole.pkg.js' => '8ab24e01', 'differential.pkg.css' => '4c3242f8', @@ -83,7 +83,7 @@ return array( 'rsrc/css/application/pholio/pholio-edit.css' => '3ad9d1ee', 'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49', 'rsrc/css/application/pholio/pholio.css' => '95174bdd', - 'rsrc/css/application/phortune/phortune-credit-card-form.css' => 'b25b4beb', + 'rsrc/css/application/phortune/phortune-credit-card-form.css' => '8391eb02', 'rsrc/css/application/phortune/phortune.css' => '9149f103', 'rsrc/css/application/phrequent/phrequent.css' => 'ffc185ad', 'rsrc/css/application/phriction/phriction-document-css.css' => '0d16bc9a', @@ -129,7 +129,7 @@ return array( 'rsrc/css/phui/phui-document.css' => '620b1eec', 'rsrc/css/phui/phui-feed-story.css' => 'c9f3a0b5', 'rsrc/css/phui/phui-fontkit.css' => '4394f216', - 'rsrc/css/phui/phui-form-view.css' => '8b78a986', + 'rsrc/css/phui/phui-form-view.css' => '76f0b086', 'rsrc/css/phui/phui-form.css' => 'f535f938', 'rsrc/css/phui/phui-header-view.css' => '083669db', 'rsrc/css/phui/phui-icon.css' => 'd35aa857', @@ -242,7 +242,6 @@ return array( 'rsrc/image/checker_dark.png' => 'd8e65881', 'rsrc/image/checker_light.png' => 'a0155918', 'rsrc/image/checker_lighter.png' => 'd5da91b6', - 'rsrc/image/credit_cards.png' => '72b8ede8', 'rsrc/image/darkload.gif' => '1ffd3ec6', 'rsrc/image/divot.png' => '94dded62', 'rsrc/image/examples/hero.png' => '979a86ae', @@ -766,7 +765,7 @@ return array( 'pholio-edit-css' => '3ad9d1ee', 'pholio-inline-comments-css' => '8e545e49', 'phortune-credit-card-form' => '2290aeef', - 'phortune-credit-card-form-css' => 'b25b4beb', + 'phortune-credit-card-form-css' => '8391eb02', 'phortune-css' => '9149f103', 'phrequent-css' => 'ffc185ad', 'phriction-document-css' => '0d16bc9a', @@ -784,7 +783,7 @@ return array( 'phui-font-icon-base-css' => '3dad2ae3', 'phui-fontkit-css' => '4394f216', 'phui-form-css' => 'f535f938', - 'phui-form-view-css' => '8b78a986', + 'phui-form-view-css' => '76f0b086', 'phui-header-view-css' => '083669db', 'phui-icon-view-css' => 'd35aa857', 'phui-image-mask-css' => '5a8b09c8', diff --git a/src/applications/phortune/controller/PhortunePaymentMethodCreateController.php b/src/applications/phortune/controller/PhortunePaymentMethodCreateController.php index df28a1c2a7..50210fa76c 100644 --- a/src/applications/phortune/controller/PhortunePaymentMethodCreateController.php +++ b/src/applications/phortune/controller/PhortunePaymentMethodCreateController.php @@ -20,6 +20,7 @@ final class PhortunePaymentMethodCreateController if (!$account) { return new Aphront404Response(); } + $account_id = $account->getID(); $merchant = id(new PhortuneMerchantQuery()) ->setViewer($viewer) @@ -30,8 +31,12 @@ final class PhortunePaymentMethodCreateController } $cart_id = $request->getInt('cartID'); + $subscription_id = $request->getInt('subscriptionID'); if ($cart_id) { $cancel_uri = $this->getApplicationURI("cart/{$cart_id}/checkout/"); + } else if ($subscription_id) { + $cancel_uri = $this->getApplicationURI( + "{$account_id}/subscription/edit/{$subscription_id}/"); } else { $cancel_uri = $this->getApplicationURI($account->getID().'/'); } @@ -43,26 +48,31 @@ final class PhortunePaymentMethodCreateController 'methods.'); } - $provider_id = $request->getInt('providerID'); - if (empty($providers[$provider_id])) { - $choices = array(); - foreach ($providers as $provider) { - $choices[] = $this->renderSelectProvider($provider); + if (count($providers) == 1) { + // If there's only one provider, always choose it. + $provider_id = head_key($providers); + } else { + $provider_id = $request->getInt('providerID'); + if (empty($providers[$provider_id])) { + $choices = array(); + foreach ($providers as $provider) { + $choices[] = $this->renderSelectProvider($provider); + } + + $content = phutil_tag( + 'div', + array( + 'class' => 'phortune-payment-method-list', + ), + $choices); + + return $this->newDialog() + ->setRenderDialogAsDiv(true) + ->setTitle(pht('Add Payment Method')) + ->appendParagraph(pht('Choose a payment method to add:')) + ->appendChild($content) + ->addCancelButton($cancel_uri); } - - $content = phutil_tag( - 'div', - array( - 'class' => 'phortune-payment-method-list', - ), - $choices); - - return $this->newDialog() - ->setRenderDialogAsDiv(true) - ->setTitle(pht('Add Payment Method')) - ->appendParagraph(pht('Choose a payment method to add:')) - ->appendChild($content) - ->addCancelButton($cancel_uri); } $provider = $providers[$provider_id]; @@ -114,6 +124,8 @@ final class PhortunePaymentMethodCreateController if ($cart_id) { $next_uri = $this->getApplicationURI( "cart/{$cart_id}/checkout/?paymentMethodID=".$method->getID()); + } else if ($subscription_id) { + $next_uri = $cancel_uri; } else { $account_uri = $this->getApplicationURI($account->getID().'/'); $next_uri = new PhutilURI($account_uri); @@ -140,6 +152,7 @@ final class PhortunePaymentMethodCreateController ->setWorkflow(true) ->addHiddenInput('providerID', $provider_id) ->addHiddenInput('cartID', $request->getInt('cartID')) + ->addHiddenInput('subscriptionID', $request->getInt('subscriptionID')) ->addHiddenInput('isProviderForm', true) ->appendChild( id(new AphrontFormSubmitControl()) diff --git a/src/applications/phortune/controller/PhortuneSubscriptionEditController.php b/src/applications/phortune/controller/PhortuneSubscriptionEditController.php index e2615ebb1c..8a3b3ddb93 100644 --- a/src/applications/phortune/controller/PhortuneSubscriptionEditController.php +++ b/src/applications/phortune/controller/PhortuneSubscriptionEditController.php @@ -103,6 +103,20 @@ final class PhortuneSubscriptionEditController extends PhortuneController { $view_uri); $crumbs->addTextCrumb(pht('Edit')); + + $uri = $this->getApplicationURI($account->getID().'/card/new/'); + $uri = new PhutilURI($uri); + $uri->setQueryParam('merchantID', $merchant->getID()); + $uri->setQueryParam('subscriptionID', $subscription->getID()); + + $add_method_button = phutil_tag( + 'a', + array( + 'href' => $uri, + 'class' => 'button grey', + ), + pht('Add Payment Method...')); + $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( @@ -111,6 +125,9 @@ final class PhortuneSubscriptionEditController extends PhortuneController { ->setLabel(pht('Autopay With')) ->setValue($current_phid) ->setOptions($options)) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setValue($add_method_button)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Save Changes')) diff --git a/src/applications/phortune/provider/PhortuneStripePaymentProvider.php b/src/applications/phortune/provider/PhortuneStripePaymentProvider.php index d0ed2b0b00..f751e3cbc5 100644 --- a/src/applications/phortune/provider/PhortuneStripePaymentProvider.php +++ b/src/applications/phortune/provider/PhortuneStripePaymentProvider.php @@ -277,6 +277,8 @@ final class PhortuneStripePaymentProvider extends PhortunePaymentProvider { array $errors) { $ccform = id(new PhortuneCreditCardForm()) + ->setSecurityAssurance( + pht('Payments are processed securely by Stripe.')) ->setUser($request->getUser()) ->setErrors($errors) ->addScript('https://js.stripe.com/v2/'); diff --git a/src/applications/phortune/provider/PhortuneTestPaymentProvider.php b/src/applications/phortune/provider/PhortuneTestPaymentProvider.php index 3139d2692e..02d57e3b6a 100644 --- a/src/applications/phortune/provider/PhortuneTestPaymentProvider.php +++ b/src/applications/phortune/provider/PhortuneTestPaymentProvider.php @@ -144,6 +144,8 @@ final class PhortuneTestPaymentProvider extends PhortunePaymentProvider { array $errors) { $ccform = id(new PhortuneCreditCardForm()) + ->setSecurityAssurance( + pht('This is a test payment provider.')) ->setUser($request->getUser()) ->setErrors($errors); diff --git a/src/applications/phortune/view/PhortuneCreditCardForm.php b/src/applications/phortune/view/PhortuneCreditCardForm.php index 335123e04e..58bf4cda0c 100644 --- a/src/applications/phortune/view/PhortuneCreditCardForm.php +++ b/src/applications/phortune/view/PhortuneCreditCardForm.php @@ -10,6 +10,16 @@ final class PhortuneCreditCardForm { private $cardNumberError; private $cardCVCError; private $cardExpirationError; + private $securityAssurance; + + public function setSecurityAssurance($security_assurance) { + $this->securityAssurance = $security_assurance; + return $this; + } + + public function getSecurityAssurance() { + return $this->securityAssurance; + } public function setUser(PhabricatorUser $user) { $this->user = $user; @@ -57,11 +67,11 @@ final class PhortuneCreditCardForm { $errors = $this->errors; $e_number = isset($errors[PhortuneErrCode::ERR_CC_INVALID_NUMBER]) ? pht('Invalid') - : true; + : null; $e_cvc = isset($errors[PhortuneErrCode::ERR_CC_INVALID_CVC]) ? pht('Invalid') - : true; + : null; $e_expiry = isset($errors[PhortuneErrCode::ERR_CC_INVALID_EXPIRY]) ? pht('Invalid') @@ -70,37 +80,42 @@ final class PhortuneCreditCardForm { $form ->setID($form_id) ->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel('') - ->setValue( - javelin_tag( - 'div', - array( - 'class' => 'credit-card-logos', - 'sigil' => 'has-tooltip', - 'meta' => array( - 'tip' => 'We support Visa, Mastercard, American Express, '. - 'Discover, JCB, and Diners Club.', - 'size' => 440, - ), - )))) + id(new AphrontFormTextControl()) + ->setLabel('Card Number') + ->setDisableAutocomplete(true) + ->setSigil('number-input') + ->setError($e_number)) ->appendChild( id(new AphrontFormTextControl()) - ->setLabel('Card Number') - ->setDisableAutocomplete(true) - ->setSigil('number-input') - ->setError($e_number)) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel('CVC') - ->setDisableAutocomplete(true) - ->setSigil('cvc-input') - ->setError($e_cvc)) + ->setLabel('CVC') + ->setDisableAutocomplete(true) + ->addClass('aphront-form-cvc-input') + ->setSigil('cvc-input') + ->setError($e_cvc)) ->appendChild( id(new PhortuneMonthYearExpiryControl()) - ->setLabel('Expiration') - ->setUser($this->user) - ->setError($e_expiry)); + ->setLabel('Expiration') + ->setUser($this->user) + ->setError($e_expiry)); + + $assurance = $this->getSecurityAssurance(); + if ($assurance) { + $assurance = phutil_tag( + 'div', + array( + 'class' => 'phortune-security-assurance', + ), + array( + id(new PHUIIconView()) + ->setIconFont('fa-lock grey'), + ' ', + $assurance, + )); + + $form->appendChild( + id(new AphrontFormMarkupControl()) + ->setValue($assurance)); + } return $form; } diff --git a/src/view/form/control/AphrontFormControl.php b/src/view/form/control/AphrontFormControl.php index 3c63d527d4..f2be0764b6 100644 --- a/src/view/form/control/AphrontFormControl.php +++ b/src/view/form/control/AphrontFormControl.php @@ -14,6 +14,7 @@ abstract class AphrontFormControl extends AphrontView { private $formPage; private $required; private $hidden; + private $classes; public function setHidden($hidden) { $this->hidden = $hidden; @@ -162,6 +163,11 @@ abstract class AphrontFormControl extends AphrontView { return true; } + public function addClass($class) { + $this->classes[] = $class; + return $this; + } + final public function render() { if (!$this->shouldRender()) { return null; @@ -225,6 +231,11 @@ abstract class AphrontFormControl extends AphrontView { $classes[] = 'aphront-form-control'; $classes[] = 'grouped'; $classes[] = $custom_class; + if ($this->classes) { + foreach ($this->classes as $class) { + $classes[] = $class; + } + } $style = $this->controlStyle; if ($this->hidden) { diff --git a/webroot/rsrc/css/application/phortune/phortune-credit-card-form.css b/webroot/rsrc/css/application/phortune/phortune-credit-card-form.css index b7904195ae..62a1d7a80b 100644 --- a/webroot/rsrc/css/application/phortune/phortune-credit-card-form.css +++ b/webroot/rsrc/css/application/phortune/phortune-credit-card-form.css @@ -2,7 +2,6 @@ * @provides phortune-credit-card-form-css */ -.credit-card-logos { - background: url(/rsrc/image/credit_cards.png) no-repeat 0px 2px; - height: 32px; +.phortune-security-assurance { + color: {$lightgreytext}; } diff --git a/webroot/rsrc/css/phui/phui-form-view.css b/webroot/rsrc/css/phui/phui-form-view.css index 28f4883cc6..ddd950c122 100644 --- a/webroot/rsrc/css/phui/phui-form-view.css +++ b/webroot/rsrc/css/phui/phui-form-view.css @@ -111,6 +111,10 @@ width: 100%; } +.aphront-form-cvc-input input { + width: 64px; +} + .aphront-form-input textarea { display: block; width: 100%; diff --git a/webroot/rsrc/image/credit_cards.png b/webroot/rsrc/image/credit_cards.png deleted file mode 100644 index dc54a4fca4..0000000000 Binary files a/webroot/rsrc/image/credit_cards.png and /dev/null differ