Code Monkey home page Code Monkey logo

donate-wagtail's Introduction

donate-wagtail

Build Status

Table of contents

Documentation

Setup your Dev Environment with Docker

When it's done, run docker-compose up, wait for the static files to be built, and go to 0.0.0.0:8000. When you want to stop, do ^C to shut down your containers. If they don't stop properly, run docker-compose down. If you want a new dev environment, stop your containers and run inv new_env.

Secrets necessary to enable several features in a local docker development environment can be found in the 1pass, Engagement Vault, in a Note called "donate-wagtail docker .env file". Copy the contents of this file and replace the .env file that came with the repo. Do not distrubute the .env file.

It's possible to connect your IDE to the python virtual env available inside the backend container (tested with pycharm and vscode). If you run into issues, ping patjouk on slack.

To run commands with Docker, run docker-compose run [SERVICE] [COMMAND]. For example, running the python tests is done by docker-compose run backend ./dockerpythonvenv/bin/python manage.py test --settings=donate.settings_test. Since it's pretty long, most cases are covered by Invoke commands.

More information on how to use Docker for local dev is available in the Local dev documentation.

Configuration

Django Configurations is used for application configuration. The following Configuration Classes are provided:

Value Purpose
Development Base configuration, suitable for local development.
Staging Staging configuration.
Production Production configuration.
ReviewApp Review App configuration. Use this configuration for Heroku Review apps.
ThunderbirdDevelopment Base configuration that enables all the Thunderbird template and string overrides. Suitable for local development.
ThunderbirdStaging Staging configuration for Thunderbird donation configurations.
ThunderbirdProduction Production configuration for Thunderbird donation configurations.
ThunderbirdReviewApp Review App configuration for Thunderbird donation configurations.

To set the Thunderbird settings in local development, simply change your DJANGO_CONFIGURATION in your .env file to be one of the choices above (For Thunderbird, use ThunderbirdDevelopment)

Braintree configuration

The following environment variables are required to configure payment processing via Braintree:

  • BRAINTREE_MERCHANT_ID: the merchant ID for the Braintree account used to process donations.
  • BRAINTREE_MERCHANT_ACCOUNTS: a series of key-value pairs that map each supported currency to the corresponding Braintree merchant account that is configured in that currency. For example: usd=usd-ac,gbp=gbp-ac,eur=eur-ac where usd-ac, gbp-ac and eur-ac are merchant account IDs.
  • BRAINTREE_PLANS: a series of key-value pairs that map each supported currency to the corresponding Braintree subscription plan that is configured in that currency. For example: usd=usd-plan,gbp=gbp-plan,eur=eur-plan where usd-plan, gbp-plan and eur-plan are plan IDs.
  • BRAINTREE_PUBLIC_KEY: Public API key provided by Braintree.
  • BRAINTREE_PRIVATE_KEY: Private API key provided by Braintree.
  • BRAINTREE_TOKENIZATION_KEY: Tokenization key provided by Braintree.
  • BRAINTREE_USE_SANDBOX: Boolean to configure whether or not to use the Braintree sandbox.

To get the payment processing working during local development, check 1Password for an example configuration by searching for "donate-wagtail docker .env file". Without the Braintree configuration in place, you won't be able to see the PayPal button on the landing pages.

You can also find example PayPal user credentials in 1Password by searching for "Paypal Sandbox Merchant". Use these as the login information during PayPal checkout.

Webhook Configuration

There's a webhook endpoint for processing Braintree events. The events it supports are:

  • subscription_charged_successfully
  • subscription_charged_unsuccessfully
  • dispute_lost

The endpoint accepts requests on /braintree/webhook/ and will verify the payload signature to ensure it's a legitimate event. Documentation for Braintree webhooks can be found here.

Basket

Basket is a tool run by MoCo to manage newsletter subscriptions and donations. It's listening for messages (JSON) sent to a SQS queue.

Basket donations queue:

Basket has 4 event types we can use:

  • donation: process a donation and send its data to SFDC,
  • crm_petition_data: add petition signature to SFDC,
  • newsletter_signup_data: newsletter signup for the foundation site,
  • DEFAULT: process a followup Stripe event on a donation.

For this project, we're only using the donation event type.

Donation event type

Example of a donation message sent to Basket, via SQS:

{
    'data': {
        'event_type': 'donation',
        'last_name': 'alex',
        'email': '[email protected]',
        'donation_amount': 50,
        'currency': 'usd',
        'created': 1563801762,
        'recurring': false,
        'service': 'paypal',
        'transaction_id': 'ch_1Ez1TSG8Mmx3htnxyShib70n',
        'project': 'mozillafoundation',
        'last_4': '4242',
        'donation_url': 'http://localhost:3000/en-US/',
        'locale': 'en-US',
        'conversion_amount': 50,
        'net_amount': 48.6,
        'transaction_fee': 1.4
    }
}
  • event_type: Basket event type. Should be donation,
  • first_name: first name of the donor (optional),
  • last_name: last name of the donor,
  • email: email of the donor,
  • donation_amount: amount of the donation,
  • currency: letter code for the currency,
  • created: unix timestamp,
  • recurring: false for a one-time donation or true for a recurring one,
  • service: name of the payment processor (ex: stripe or paypal)
  • transaction_id: ID generated by the payment processor,
  • project: name of the project that will receive the donation (ex: thunderbird, mozillafoundation)
  • last_4: last 4 digits of the credit card,
  • donation_url: url from which the donation was made,
  • locale: language code for the donor,
  • conversion_amount: donation amount in USD, before transaction fees,
  • net_amount: donation amount in USD, after transaction fees,
  • transaction_fee: payment processor's transaction fees in USD

Newsletter signup

We're using Basket newsletter HTTP API to signup people to our newsletter. Specs are available in Basket's documentation. (Note that this is different than the SQS approach used for donation events)

Example from donate.mozilla.org:

 { format: 'html',
   lang: 'en-US',
   newsletters: 'mozilla-foundation',
   trigger_welcome: 'N',
   source_url: 'https://donate.mozilla.org/',
   email: '[email protected]',
   country: undefined }

Notes: We want to keep the trigger_welcome at N and the format to html. We don't have the country info for now, but from what I understood, it's something we want to change.

Review App

Environment variables

Non-secret envs can be added to the app.json file. Secrets must be set on Heroku in the Review Apps section of the pipelines' settings tab.

Review App for PRs

Opening a PR will automatically create a Review App in the donate-wagtail and thunderbird-donate pipelines. A slack bot posts credentials and links to Review Apps in to the mofo-ra-donate-wagtail and mofo-ra-thunderbird-donate-wagtail channels.

Note: This only work for Mo-Fo staff: you will need to manually open a Review App on Heroku for PRs opened by external contributors.

Review App for branches

You can manually create a review app for any branch pushed to this repo. It's useful if you want to test your code on Heroku without opening a PR yet. To create one:

  • log into Heroku.
  • Go in the donate-wagtail or thunderbird-donate pipeline.
  • Click on + New app and select the branch you want to use.

The review app slack bot will post a message in either the mofo-ra-donate-wagtail or mofo-ra-thunderbird-donate-wagtail with links and credentials as soon as the review app is ready.

SSO and admin logins for local development

The default for admin login for local development is the standard Django login. To use Mozilla SSO via OpenID Connect, set the USE_CONVENTIONAL_AUTH environment variable to False.

To make sure you can log in using your Mozilla SSO credentials, your will need to create a Django superuser with your mozilla email address, using:

docker-compose exec app python manage.py createsuperuser

Adding users to the system

The security model currently requires that an existing admin creates an account for a new user first, tied to that user's Mozilla email account, before that user can can log in using SSO.

Further more, in order for SSO authentication to succeed, their account must be a member of the donate user group. To request that an account be added to this group, please file an SSO request bug, making sure to also cc a donate admin in the bug.

Translations

Translation is happening on Pontoon, in multiple projects where you can participate:

Project on Pontoon Source repository
Mozilla & Thunderbird UI strings (Django) Repository on GitHub
Mozilla (CMS content) Repository on GitHub
Thunderbird (CMS content) Repository on GitHub

The latest UI source strings are regularly exposed to Pontoon by a Localization PM using the process below. The CMS strings are automatically synchronized with the repositories.

Initial setup:

  • Clone the donate-l10n repository locally.
  • Set the LOCAL_PATH_TO_L10N_REPO variable in your .env file. Use the absolute path to your copy of the donate-l10n repository and include the trailing slash. E.g. LOCAL_PATH_TO_L10N_REPO=/Users/username/Documents/GitHub/donate-l10n/

Exposing latest source strings:

  • Make sure your local repositories of donate-l10n and donate-wagtail are matching the latest revision from main.
  • Run inv docker-makemessages from your donate-wagtail repository.
  • Files should have been updated in your donate-l10n repository. You can now create a pull-request.

Getting the latest translations for local dev

Latest translations are uploaded to S3. To get them, run:

  • curl -o translations.tar https://donate-wagtail-translations.s3.amazonaws.com/translations.tar
  • tar -C network-api -xvf translations.tar

You don't need to run compilemessages.

The translations_github_commit_[...] file from the archive is only used for debug purposes on Heroku. It can be safely deleted if needed.

donate-wagtail's People

Contributors

ag12r avatar alanmoo avatar andy-moz avatar danielfmiranda avatar dependabot-preview[bot] avatar fjoerfoks avatar jurajcigan avatar kaedroho avatar kalobtaulien avatar koehlermichael avatar kyoshino avatar mahtab05 avatar marceloghelman avatar markh-bz avatar mergify[bot] avatar mikkcz avatar milupo avatar mmmavis avatar mozilla-pontoon avatar mtdenton avatar nicklee avatar patjouk avatar petercpg avatar piotrdrag avatar pomax avatar selimsumlu avatar solarissmoke avatar theochevalier avatar tomusher avatar ujdhesa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

donate-wagtail's Issues

Monthly card payments - set up Braintree support for multiple currencies

In order to process monthly payments, Braintree requires that:

The specified merchant account must be in the same currency as the subscription plan, or any attempted subscription transactions will trigger a validation error. If you want to use a merchant account with a different currency, you must create a new plan in the Control Panel with the indicated currency.

This means:

  1. To accept monthly donations in all of the supported currencies, we will need to set up separate merchant accounts and plans for each currency.

  2. You will need to talk to Braintree about getting access to all the currencies you want. By default they only provide the following:

    • AUD - Australian Dollar
    • BRL - Brazilian Real
    • CAD - Canadian Dollar
    • CHF - Swiss Franc
    • CZK - Czech Koruna
    • DKK - Danish Krone
    • EUR - Euro
    • GBP - British Pound
    • HKD - Hong Kong Dollar
    • HUF - Hungarian Forint
    • ILS - Israeli New Sheqel
    • INR - Indian Rupee
    • JPY - Japanese Yen
    • MXN - Mexican Peso
    • MYR - Malaysian Ringgit
    • NOK - Norwegian Krone
    • NZD - New Zealand Dollar
    • PHP - Philippine Peso
    • PLN - Polish Złoty
    • RUB - Russian Ruble
    • SEK - Swedish Krona
    • SGD - Singapore Dollar
    • THB - Thai Baht
    • TWD - New Taiwan Dollar
    • USD - United States Dollar

I don't think that either of these should be an issue, but if you haven't already it is worth talking to them about it as early as possible.

Error page templates and styles

We will need to update the 404 and 500 templates to be consistent with the rest of the site, and to present some meaningful information to the user.

On a related note I notice that any invalid URL on the current site (e.g., https://donate.mozilla.org/foooo) redirects to the home page. Is this behaviour you want to replicate @alanmoo ? I feel like it might have SEO implications (but not an expert in this) - but would imagine this is a deliberate decision?

Basket update: which fields needs to be changed or added?

After discussing with Samir on Slack about #27, it was decided to first update basket and then connect donate-wagtail to it. To do that, we need to know what fields needs to be updated/added/remove.

Curent JSON payload sent to basket:
first_name: first name of the donor (optional),
last_name: last name of the donor,
email: email of the donor,
donation_amount: amount of the donation,
currency: letter code for the currency,
created: unix timestamp,
recurring: false for a one-time donation or true for a recurring one,
service: name of the payment processor (ex: stripe or paypal)
transaction_id: ID generated by the payment processor,
project: name of the project that will receive the donation (ex: thunderbird, mozillafoundation)
last_4: last 4 digits of the credit card,
donation_url: url from which the donation was made,
locale: language code for the donor,
conversion_amount: donation amount in USD, before transaction fees,
net_amount: donation amount in USD, after transaction fees,
transaction_fee: payment processor's transaction fees in USD.

@solarissmoke Can you review those fields? Meanwhile I'll go and ask fundraising about the transaction fees.

Develop functional specification for campaign journey

A functional specification for the campaign functionality will help us to ensure we've got all the required features covered (perhaps just this ticket can be the spec as we develop it). The bits that I think we've discussed already (but open to feedback/refinement):

  • Ability to specify custom content on the landing page for a campaign.
  • Ability to specify default donation amounts for a campaign (e.g, $3.14 for Pi day), in different currencies, with fallback to global defaults. (NB note from Jesse - "my strong preference so we don't wind up with a complex matrix of prices...").
  • Ability to specify default donation frequency (single/monthly) for a campaign.
  • Ability to specify the benefactor for a campaign and for this information to be passed through to Braintree.

Open questions/potential features to discuss:

  • Custom content on thank you page after a donation is made?
  • Confirmation email sent to donor (or is this handled separately via Salesforce)?

Push transaction data to SQS

Push data about completed transactions to SQS.

Information required

  1. API for pushing data to SQS.
  2. What information should be sent and its structure.

Technical notes

My initial thoughts for implementation are that this should be done asynchronously via a worker process.

There is an open question about how much resiliency is required in terms of retrying failed push, and whether we need to store basic transaction data (a Braintree reference number) in Wagtail as a fallback.

Currency amounts internationalization

Not sure if this is already scoped/planned as part of another ticket, so filing it just to make sure.

Amounts + currency strings everywhere on the website will need to be formatted using Intl.NumberFormat https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat

This API will handle the currency symbol formatting, but also convert numbers to the appropriate script and pick separators (decimal, thousands, etc).

Example in Arabic, where numbers are converted to the Arabic script
image

I think the current website uses a npm package, but that package relies on this API ultimately (which is definitely the way to go)

This API would also solve #93 (commented in there with the relevant example + method)

Campaign page model

Field spec

  • Hero image: image field (required)
  • Title: plain text (required)
  • Lead text: plain text (required)
  • Partner logos: orderable sequence of image fields (optional)
  • Default donation amount overrides: optional list of items mapping a currency to list of 4 suggested donation amounts.

Notes

  • If a currency is not listed in the donation amount overrides, then we will fall back to the global defaults.
  • Legal text is fetched from global configuration (i.e., does not vary per-campaign).

Paypal payment flow - monthly payment

Implementation of Paypal payment flow for monthly payments:

  1. Load Paypal checkout flow when Paypal option is selected on landing/campaign pages. Amount is determined via JS from the form on that page.
  2. Error reporting on the landing/campaign page - we need to be able to report failures or early cancellation on the page from which the Paypal modal is launched.
  3. Thank you view.

Set up sandbox accounts for payment processors

We'll need sandbox accounts for:

  1. Braintree
  2. Paypal (merchant)
  3. Paypal (buyer)

It might make sense for Mozilla to set these up and share access privately, so that you have these for development going forward.

Card payment flow - single payment

Implementation of card payment flow for single payments:

  1. User details view for capturing address information. The donation amount is sent from the precending landing/campaign page.
  2. Payment view for capturing card details via hosted fields. This view also needs to handle error reporting that isn't caught by Braintree's inline validation - e.g., things like denied transactions and blocked cards.
  3. Thank you view.

(Upsell is handled separately in #26).

  • I can complete a one-off credit card donation in USD from the landing page.
  • After completing a donation I see a thank you page that confirms the amount I have donated.

Better handling of Paypal failures

Our currently handling of Paypal failures is to render a page with "Something went wrong! Please try again later", which isn't particularly helpful to the user.

I am not sure what the best UX here is, but I think we should probably send the user back to the landing page and display an error message there.

Disable certain payment options for certain currencies

Add the ability to disable certain payment options for certain currencies - e.g., to disable Paypal for AED.

A list of supported payment methods for each currency will be maintained as part of the data for that currency, and this will be used to determine which options are visible to the user on the landing/campaign pages.

Information required

  1. Is it possible to control which card types are accepted on a per-transaction basis in Braintree (I haven't been able to find documentation that suggests it is)?

Side note - support for Amex has to be explicitly requested.

Define/review meta titles for all steps in all flows

I think it's worth reviewing the meta titles that we're setting on each step of the various flows, to make sure they are (a) consistent and (b) meaningful.

This should probably happen towards the end of the project.

Footer email signup

The designs include an email signup form in the footer.

What is the desired behaviour when the user submits this form? Will it redirect to a confirmation/thank you page, or do we process via AJAX and indicate success with a UI change?

Email signup

Overview:

Prompts the user to signup to the Mozilla email list by entering their email address, and confirming they have read the privacy policy.

Step 4/5 (Landing/Campaign > Details > Payment > Upsell (optional) > Email signup) of the process, could potentially be optional, and could show for both monthly and one off donations.

Design / Wireframe:

Desktop: https://redpen.io/eo137e0b58bf3ace18
Tablet: https://redpen.io/axd4e004cbcfbd16dd
Mobile: https://redpen.io/ahe3dd0e181414c277

Components that form this template:

  • Title
  • Sub title
  • Introductory text
  • Email signup form

Site-wide data models

I propose to use site-wide settings to store the following:

  • Legal footer text: rich text (required)
  • Top navigation menu links: orderable sequence of link blocks that can link either to a page on site or to an absolute URL (required)
  • Footer links: orderable sequence of link blocks that can link either to a page on site or to an absolute URL (required)
  • Language code to currency mapping (as defined in #1).
  • Currency information:
    • Code
    • Symbol
    • Allowed payment methods
    • Default donation amounts: for each currency, 4 default suggestion values for that currency.

It might be easier to store currency information in code instead - to make a call before starting work on this.

Other amount donation selection

The other amount field will require some js to select the checkbox when focused, and also to populate a hidden input with the amount entered.

Functional testing of flows

We are soon getting to the point where thorough testing of all the flows will be needed to make sure everything works as expected. This is a WIP list of the different flows/scenarios that we need to test, which might be worth putting into a matrix somewhere at some point.

Flows

  1. Card single payment
  2. Card monthly payment
  3. Paypal single payment
  4. Paypal monthly payment

All the above can be started from either the landing page or a campaign page - we need to test both.

Variations

  1. Valid/invalid card numbers
  2. Closing Paypal modal mid-payment
  3. Upsell/skip upsell
  4. Newsletter signup/skip newsletter signup

Translate JS

Once all the JS is in place for Braintree, we need to add translation for the strings (mostly error messages) that are used there.

Landing page model

Field spec

  • Featured image: image field (required)
  • Introductory text: rich text (required)
  • Partner logos: orderable sequence of image fields (optional)

Removing primary navigation setting

The primary navigation component will be hardcoded, so there's no longer a need for it to be editable in wagtail. With this in mind we should remove it from the wagtail settings.

Currency switching

Add currency switching capability to the landing/campaign page forms. Propose to do this after the basic donation flows (single/monthly) have been set up in USD.

When I land on the donations page I want to select either single or ongoing payment

When I land on the donations page I want to select either single or ongoing payment.

  • The user can switch between making a single or ongoing payment

  • The user will see different suggested donations depending on their selection

  • 3x suggested values will be shown for each option

  • Each view (single/ongoing) will have a default suggested donation

Post-payment email sign up

Provide the option for the user to sign up to the newsletter after they have completed payment.

Information required

  1. Where should the form data be sent (SQS)?

Single to monthly payment upsell

Implementation of a workflow to enable donors to set up a monthly payment having just completed a single payment.

Technical notes

Braintree requires a slightly different approach for setting up subscriptions - specifically creating subscriptions requires vaulting of a payment method.

The options here are:

  1. Vault all payments (including single), so that we don't have to ask for this information again at point of upsell.
  2. Don't vault single payments, in which case the user would have to go through the process of entering their details again at point of upsell.

(2) obviously makes for poor user experience, so I think (1) is the preferred option - we just need to investigate what the implications are of vaulting one-off payments (if any) and whether the Paypal flow for vaulting is more involved (if so there may be a more nuanced tradeoff that we need to make a decision on).

Confirm approach for localisation and currency detection

A few queries about localisation and currency defaults:

  1. Is browser language preference used to determine the default language presented to the user?

  2. How should the default currency be determined? Is this currently determined from location (e.g., using IP geolocation)?

  3. How should we determine suggested donation amounts in each currency? Will these vary on a per-campaign basis?

Pass additional information to Braintree custom fields

There is a requirement to pass some additional information about transactions to Braintree in the form of custom fields.

Information required

  • The specific data to be collected and passed to Braintree
  • The structure of the data - i.e., what data goes into which custom field.

Notes

Braintree custom fields must be set up in the Braintree dashboard before we can pass data to those fields - this means that some decisions need to be made about which fields to set up.

Braintree doesn't appear to restrict the length of data stored in a given field, so it should be possible for example to dump JSON into a single custom field. Whether to do this (vs separating data into multiple fields) depends largely on the use case - e.g., do you need the ability to filter payments based on a field using the Braintree API.

Develop field specifications for campaign pages

Depends on #3 - once we are reasonably clear on the functional requirements we can develop field specifications for the key content types. This will describe the editable fields that each content type will expose and any validation requirements.

rtl layouts

Ensure that all page designs work with right to left languages.

Recommend we do this by adding a class to the app div that then updates the layout accordingly, app--rtl sounds sensible to me.

This would ensure all text is set to align right, and that the layout is flipped.

Ideally we'd have a design illustrating how this works on one template, then we can interpret the rest, but it's not essential.

Error message styling

We will need to apply styling to error messages that are rendered in various places:

  1. Paypal error if you close the Paypal modal after loading it on the landing/campaign page.
  2. Form errors on the card details view (to trigger this, disable browser validation and enter say an invalid email address), and for all other forms (upsell, newsletter).
  3. Gateway errors on the card details view (to trigger this, enter a postcode longer than 9 characters for a US address).

Translation functionality

This is a broad description of the translation functionality/workflow that we need to implement - which we can then break into specific tasks for implementation. My understanding of the key requirements and flows as follows - subject to review from the Mozilla team.

Translations will be provided by Pontoon, which operates on git repositories - i.e., it pulls translatable strings from a repository and will push translated strings back to it.

Code/template string translations

These will be handled in the normal way. Django will generate .po files which Pontoon will read and update with translations when they become available.

CMS content

CMS content in Wagtail will be made translatable using the wagtail-translation package (work in progress). This package provides a framework for generating translatable pages and a UI for managing those pages within Wagtail. It provides a mechanism for extracting text from page content into a series of translatable strings.

We will need to develop a way for these translatable strings to be relayed to/from Pontoon via a repository that Pontoon can push/pull from.

Braintree customer data expects first name, last name

Braintree's customer data model expects a first name and last name for customers, but currently we don't ask for these separately.

My current approach is not to pass name information at all to Braintree - but if we want to store this information there then we will need to look at options:

  1. Ask for first name and last name separately.
  2. Do some parsing to try and split this ourselves? (This will quickly fall foul of cultural variances).
  3. Dump everything into "first name"?

I don't think this has any implication for card verification - seems that only address and CVV is used for that, but that may also be a factor. Flagging as something we need to test before going live.

Paypal payment flow - single payment

Implementation of Paypal payment flow for single payments:

  1. Load Paypal checkout flow when Paypal option is selected on landing/campaign pages. Amount is determined via JS from the form on that page.
  2. Error reporting on the landing/campaign page - we need to be able to report failures or early cancellation on the page from which the Paypal modal is launched.
  3. Thank you view.

(Upsell is handled separately in #26).

Add recaptcha

Add recaptcha to landing/campaign page forms.

We should also review what other steps we need to take to mitigate against carding attacks.

Card payment flow - monthly payment

Implementation of card payment flow for single payments:

  1. User details view for capturing address information. The donation amount is sent from the precending landing/campaign page.
  2. Payment view for capturing card details via hosted fields. This view also needs to handle error reporting that isn't caught by Braintree's inline validation - e.g., things like denied transactions and blocked cards.
  3. Thank you view.
  • I can complete a monthly credit card donation in USD from the landing page.
  • After completing a donation I see a thank you page that confirms the amount I have set up a subscription for.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.