diff --git a/.eslintrc.json b/.eslintrc.json index d50577a..02011d8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -40,6 +40,7 @@ "jsx-a11y/anchor-is-valid": 1, "react/no-did-update-set-state": "off", "max-classes-per-file": 1, - "no-unused-vars": "off" + "no-unused-vars": "off" , + "no-return-assign": "off" } } \ No newline at end of file diff --git a/package.json b/package.json index 032b333..829de45 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@types/react": "^16.9.35", "@types/react-router-dom": "^5.1.5", "bootstrap": "^4.5.0", + "braintree-web-drop-in-react": "^1.2.1", "file-loader": "5.0.2", "jquery": "^3.5.1", "jwt-decode": "^2.2.0", @@ -23,6 +24,7 @@ "react-alert-template-basic": "^1.0.0", "react-anchor-link-smooth-scroll": "^1.0.12", "react-bootstrap": "^1.3.0", + "react-braintree-fields": "^1.6.0", "react-dom": "^16.13.1", "react-ga": "^3.3.0", "react-google-recaptcha": "^2.1.0", diff --git a/src/App.tsx b/src/App.tsx index 237404f..30295c0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,6 +15,7 @@ import Home from './components/Home'; import AboutUs from './components/AboutUs'; import ContactUs from './components/ContactUs'; import Issue from './components/Issue'; +import Donate2 from './components/Donate2'; window.onload = () => { ReactGA.initialize('G-H1CSQJ6BGQ'); @@ -44,6 +45,7 @@ class App extends React.Component<{}, State, {}> { } /> } /> } /> + } /> } diff --git a/src/components/Donate.tsx b/src/components/Donate.tsx new file mode 100644 index 0000000..51de799 --- /dev/null +++ b/src/components/Donate.tsx @@ -0,0 +1,169 @@ +import React from 'react'; +import DropIn from 'braintree-web-drop-in-react'; +import { Helmet } from 'react-helmet'; +import { Braintree, HostedField } from 'react-braintree-fields'; +import getServerURL from '../serverOverride'; + +import RectangleSVG from '../static/images/story2.png'; +import handsSVG from '../static/images/valuesHero.png'; + +class Donate extends React.Component<{}, {clientToken: string, amount: string, processing: number, pageNum:number}> { + instance; + + constructor(props) { + super(props); + this.state = { + clientToken: '', amount: '5', processing: 0, pageNum: 1, + }; + } + + componentDidMount() { + // Get a client token for authorization from your server + fetch(`${getServerURL()}/generate-client-token`, { method: 'GET' }) + .then((response) => response.text()).then((responseJSON) => { + // console.log(responseJSON); + this.setState({ clientToken: responseJSON }); + }); + } + + async buy() { + // Send the nonce to your server + this.setState({ processing: 1 }); + const { nonce } = await this.instance.requestPaymentMethod(); + fetch(`${getServerURL()}/checkout-donation`, { + method: 'POST', + credentials: 'include', + body: JSON.stringify({ + payment_method_nonce: nonce, + amount: this.state.amount, + }), + }) + .then((response) => response.json()) + .then((responseJSON) => { + if (responseJSON.status === 'SUCCESS') { + console.log('yay'); // this doesn't happen + } + }); + this.setState({ pageNum: 4 }); + } + + render() { + let dropInComponent; + let buyButton; + let hostedFieldsPage; + let output; + + if (this.state.processing === 0) { + buyButton = ; + } else if (this.state.processing === 1) { + buyButton = ( + + ); + } + + if (!this.state.clientToken) { + dropInComponent = ( +
+

Loading...

+
+ ); + } else { + dropInComponent = ( +
+ (this.instance = instance)} + /> + {buyButton} +
+ ); + } + + const welcomePage = ( +
+
+
Your donation makes a difference
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
1. Select Amount
+
+ + + + + +
+ +
+
+ +
+
+ ); + + const thankYouPage = ( +
+
Thank you for your donation
+ Extra text about where the donation goes +
+ +
+
+ ); + + if (this.state.pageNum === 1) { + output = welcomePage; + } else if (this.state.pageNum === 2) { + output = hostedFieldsPage; + } else if (this.state.pageNum === 3) { + output = ( +
+
+
+ (this.instance = instance)} + /> +
+
+
{buyButton}
+
+ ); + // doing {dropInComponent} doesn't work? + } else if (this.state.pageNum === 4) { + output = thankYouPage; + } + + return ( +
+ + Welcome + + + {output} +
+ ); + } +} + +// card: 4111 1111 1111 1111, year: 01/24 + +export default (Donate); diff --git a/src/components/Donate2.tsx b/src/components/Donate2.tsx new file mode 100644 index 0000000..ca3fc64 --- /dev/null +++ b/src/components/Donate2.tsx @@ -0,0 +1,214 @@ +// import { any } from 'prop-types'; +// import React from 'react'; +// import { Braintree, HostedField } from 'react-braintree-fields'; + +// class Donate2 extends React.PureComponent<{},{token:any, amount:string}>{ +// instance; +// braintree: any; +// numberField: any; + +// constructor(props) { +// super(props); +// this.braintree = React.createRef(); +// this.numberField = React.createRef(); +// this.state = { +// token: null, +// amount: '5', +// } +// } + +// //cannot use this since the braintree uses the token not as a string +// // componentDidMount() { +// // // Get a client token for authorization from your server +// // console.log('got here'); +// // fetch(`${getServerURL()}/generate-client-token`, { method: 'GET' }) +// // .then((response) => response.text()).then((responseJSON) => { +// // // console.log(responseJSON); +// // this.setState({ clientToken: responseJSON }); +// // }); +// // console.log(this.state.clientToken); +// // } + +// //this compiles, sets the token as an object instead of a string + +// // componentDidMount(){ +// // fetch('${getServerURL()}/generate-client-token', {method:'GET'}) +// // .then((response) => { +// // this.setState({token:response}); +// // }); +// // console.log('got a token'); +// // } + +// async buy() { +// // Send the nonce to your server +// const { nonce } = await this.instance.requestPaymentMethod(); +// fetch(`${getServerURL()}/checkout-donation`, { +// method: 'POST', +// credentials: 'include', +// body: JSON.stringify({ +// payment_method_nonce: nonce, +// amount: this.state.amount, +// }), +// }) +// .then((response) => response.json()) +// .then((responseJSON) => { +// if (responseJSON.status === 'SUCCESS') { +// console.log('yay'); // this doesn't happen +// } +// }); +// } + +// render() { +// return ( +//
+//

Braintree Hosted Fields Demo

+ +// this.state.token} +// authorization = 'sandbox_gpr679yy_tj4vmtfr3qqmc9yb' +// styles={{ +// input: { +// 'font-size': '14px', +// 'font-family': 'helvetica, tahoma, calibri, sans-serif', +// color: '#7d6b6b', +// }, +// ':focus': { +// color: 'black', +// }, +// }} +// > +//
+// (this.ccNum = ccNum)} /> +// +// +//
+//
+//
+// +//
+//
+// ); +// } + +// } + +// export default (Donate2); + +import React from 'react'; +import { Braintree, HostedField } from 'react-braintree-fields'; +import getServerURL from '../serverOverride'; + +const Donate2 = () => { + const [tokenize, setTokenizeFunc] = React.useState(); + const [cardType, setCardType] = React.useState(''); + const [error, setError] = React.useState(null); + const [token, setToken] = React.useState(null); + const [focusedFieldName, setFocusedField] = React.useState(''); + const numberField = React.useRef(); + const cvvField = React.useRef(); + const cardholderNameField = React.useRef(); + + const handleError = (newError) => { + setError(newError.message || String(newError)); + }; + + const onFieldBlur = (field, event) => setFocusedField(''); + const onFieldFocus = (field, event) => setFocusedField(event.emittedBy); + + const getAuthorization = () => { + fetch(`${getServerURL()}/generate-client-token`, { method: 'GET' }) + .then((response) => response.text()).then((responseJSON) => { + console.log(responseJSON); + return responseJSON; + }); + }; + + const getToken = () => { + // @ts-ignore: Object is possibly 'null'. + tokenize() + .then(setToken) + .catch(handleError); + }; + + const renderResult = (title, obj) => { + if (!obj) { return null; } + return ( +
+ + {title} + : + +
{JSON.stringify(obj, null, 4)}
+
+ ); + }; + + return ( +
+ setTokenizeFunc(() => ref)} + styles={{ + input: { + 'font-size': 'inherit', + }, + ':focus': { + color: 'blue', + }, + }} + > + {renderResult('Error', error)} + {renderResult('Token', token)} + +
+ Number: + +

+ Card type: + {cardType} +

+ Name: + + Date: + + CVV: + + Zip: + +
+ +
+
+ +
+
+ ); +}; + +export default Donate2; diff --git a/src/components/Header.tsx b/src/components/Header.tsx index d4b29b7..fb8227b 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -86,12 +86,12 @@ class Header extends Component<{}, {}, {}> { Contact Us -
  • - +
  • + - +