Skip to content

Commit

Permalink
Merge pull request #161 from margaritahumanitarian/add-device-donatio…
Browse files Browse the repository at this point in the history
…n-function

Submission for device donations
  • Loading branch information
Audrey Roy Greenfeld authored Sep 7, 2021
2 parents 908eb83 + d12be54 commit a904daa
Show file tree
Hide file tree
Showing 7 changed files with 1,126 additions and 70 deletions.
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,14 @@ STRIPE_SECRET_KEY = "sk_test_51JJ3vNLOlCyqSHKrp2vu93c9YzrXxDq7otphDYZqQTE10eZ0Gs
CANCEL_URL = "https://helpafamily.margaritahumanitarian.org/"
SUCCESS_URL = "https://helpafamily.margaritahumanitarian.org/thank-you"
NEXT_PUBLIC_GMAPS_JS_API_KEY = "<your Google Maps JavaScript API Key here>"


// Generate these values in the Firebase console:
// PROJECT SETTINGS > Firebase Admin SDK > Generate new private key
// Creates a downloadable JSON FILE that contains these values
FIREBASE_PROJECT_ID = "XYZ"
FIREBASE_PRIVATE_KEY_ID = "XYZ"
FIREBASE_PRIVATE_KEY = "XYZ"
FIREBASE_CLIENT_EMAIL = "XYZ"
FIREBASE_CLIENT_ID = "XYZ"
FIREBASE_CLIENT_X509_CERT_URL = "XYZ"
2 changes: 1 addition & 1 deletion components/form/SelectFormControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ SelectFormControl.propTypes = {
label: PropTypes.string,
options: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
})
),
Expand Down
26 changes: 26 additions & 0 deletions firebase.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import admin from 'firebase-admin';

const secret = {
type: 'service_account',
project_id: process.env.FIREBASE_PROJECT_ID,
private_key_id: process.env.FIREBASE_PRIVATE_KEY_ID,
private_key: process.env.FIREBASE_PRIVATE_KEY,
client_email: process.env.FIREBASE_CLIENT_EMAIL,
client_id: process.env.FIREBASE_CLIENT_ID,
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
token_uri: 'https://oauth2.googleapis.com/token',
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
client_x509_cert_url: process.env.FIREBASE_CERT_URL,
};

if (!admin.apps.length) {
try {
admin.initializeApp({
credential: admin.credential.cert(secret),
});
} catch (error) {
console.log('Firebase admin initialization error', error.stack);
}
}

export default admin.firestore();
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@contentful/rich-text-types": "^15.1.0",
"contentful": "^8.5.0",
"daisyui": "^1.14.0",
"firebase-admin": "^9.11.1",
"next": "latest",
"prop-types": "^15.7.2",
"react": "^17.0.2",
Expand Down
28 changes: 28 additions & 0 deletions pages/api/process-device-donation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { StatusCodes } from 'http-status-codes';
import admin from 'firebase-admin';

import db from '../../firebase.config';

export default async function processDeviceDonation(req, res) {
console.log(req.method);

const data = {
city: req.body.city || '',
country: req.body.country || '',
description: req.body.description || '',
email: req.body.email || '',
name: req.body.name || '',
originalPurchasePrice: req.body.originalPurchasePrice || '0',
phone: req.body.phone || '',
postalCode: req.body.postalCode || '',
state: req.body.state || '',
streetAddress: req.body.streetAddress || '',
streetAddress2: req.body.streetAddress2 || '',
timestamp: admin.firestore.FieldValue.serverTimestamp(),
debug: req.method === 'GET',
};

const result = await db.collection('DeviceDonations').add(data);
// TODO send email per https://github.com/margaritahumanitarian/helpafamily/issues/166
res.status(StatusCodes.OK).json({ receiptNumber: result.id, data });
}
159 changes: 107 additions & 52 deletions pages/give-devices.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,104 @@
import Head from 'next/head';
import React from 'react';
import { useRouter } from 'next/router';

import Footer from '../components/Footer';
import InputFormControl from '../components/form/InputFormControl';
import Modal from '../components/Modal';
import Navbar from '../components/Navbar';
import SelectFormControl from '../components/form/SelectFormControl';
import TextareaFormControl from '../components/form/TextareaFormControl';

// Use ISO 3166 country codes per https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
const COUNTRIES = [
{ value: 'united-states', label: 'United States' },
{ value: 'canada', label: 'Canada' },
{ value: 'mexico', label: 'Mexico' },
{ value: 'germany', label: 'Germany' },
{ value: 'latvia', label: 'Latvia' },
{ value: 'india', label: 'India' },
{ value: 'bangladesh', label: 'Bangladesh' },
{ value: 'philippines', label: 'Philippines' },
{ value: 'US', label: 'United States' },
{ value: 'CA', label: 'Canada' },
{ value: 'MX', label: 'Mexico' },
{ value: 'DE', label: 'Germany' },
{ value: 'LV', label: 'Latvia' },
{ value: 'IN', label: 'India' },
{ value: 'BD', label: 'Bangladesh' },
{ value: 'PH', label: 'Philippines' },
];

export default function GiveDevicesPage() {
const router = useRouter();
const [modalText, setModalText] = React.useState('');
const [isModalOpen, setModalOpen] = React.useState(false);
const [name, setName] = React.useState('');
const [email, setEmail] = React.useState('');
const [country, setCountry] = React.useState(COUNTRIES[0].id);
const [country, setCountry] = React.useState(COUNTRIES[0].value);
const [streetAddress, setStreetAddress] = React.useState('');
const [streetAddress2, setStreetAddress2] = React.useState('');
const [city, setCity] = React.useState('');
const [state, setState] = React.useState('');
const [postalCode, setPostalCode] = React.useState('');
const [phoneNumber, setPhoneNumber] = React.useState('');
const [valueOfDevice, setValueOfDevice] = React.useState('');
const [about, setAbout] = React.useState('');
const [phone, setPhone] = React.useState('');
const [originalPurchasePrice, setOriginalPurchasePrice] = React.useState('');
const [description, setDescription] = React.useState('');

const handleSubmit = (event) => {
const hideModal = () => setModalOpen(false);

const showModal = (message) => {
setModalText(message);
setModalOpen(true);
};

const handleSubmit = async (event) => {
event.preventDefault();

console.log({
name,
email,
country,
streetAddress,
city,
state,
postalCode,
phoneNumber,
valueOfDevice,
about,
if (name.trim().length === 0) {
showModal('Please add your name.');
return;
}

if (email.trim().length === 0) {
showModal('Please add your email address.');
return;
}

if (streetAddress.trim().length === 0) {
showModal('Please add your street address.');
return;
}

if (city.trim().length === 0) {
showModal('Please add your city.');
return;
}

if (state.trim().length === 0) {
showModal('Please add your state or province.');
return;
}

if (postalCode.trim().length === 0) {
showModal('Please add your postal code.');
return;
}

// Create the donate device request forward to the checkout page
const response = await fetch('/api/process-device-donation', {
body: JSON.stringify({
name,
email,
country,
streetAddress,
streetAddress2,
city,
state,
postalCode,
phone,
originalPurchasePrice,
description,
}),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
});
await response.json();
router.push('/thank-you');
};

return (
Expand All @@ -55,98 +109,96 @@ export default function GiveDevicesPage() {
<Navbar />
<main>
<div className="m-auto w-3/4 p-10 my-10 bg-green-300 border border-gray-300">
<div className="bg-gray-100 flex justify-center mb-5">
<p className="mt-1 text-xl text-black-600">
{
'This section is still being worked on, please contact us at the following email instead: '
}
<a
className="mt-1 text-xl underline"
href="mailto:[email protected]"
>
{'[email protected]'}
</a>
</p>
</div>
<div className="mt-10 sm:mt-0">
<div className="md:grid md:grid-cols-3 md:gap-6">
<div className="md:col-span-1">
<div className="px-4 sm:px-0">
<h3 className="text-lg font-medium leading-6 text-gray-900">
{'Personal Information'}
{'Laptop Donations for Families'}
</h3>
<p className="mt-1 text-sm text-gray-600">
{'Use a permanent address where you can receive mail.'}
{`Mail us your used or new laptop. We'll set up the donated laptops in our public computer room for the families to use for free. Some of the donated laptops will go to the families who don't have home computers, or who don't have enough computers for all their children to use.`}
</p>
</div>
</div>
<div className="mt-5 md:mt-0 md:col-span-2">
<div className="card bordered">
<div className="card-body bg-white">
<form onSubmit={handleSubmit}>
<h3 className="text-lg font-medium leading-6 text-red-900">
{'Required fields are marked with *'}
</h3>
<InputFormControl
id="name"
label="Name"
label="Name *"
onChange={setName}
value={name}
/>
<InputFormControl
id="email"
label="Email address"
label="Email address *"
onChange={setEmail}
type="email"
value={email}
/>
<SelectFormControl
id="country"
label="Country / Region"
label="Country / Region *"
onChange={setCountry}
options={COUNTRIES}
value={country}
/>
<InputFormControl
id="streetAddress"
label="Street address"
label="Street address *"
onChange={setStreetAddress}
placeholder="Use an address where you can receive mail."
value={streetAddress}
/>
<InputFormControl
id="streetAddress2"
label="Street address 2"
onChange={setStreetAddress2}
placeholder="Extra address data can go here"
value={streetAddress2}
/>
<InputFormControl
id="city"
label="City"
label="City *"
onChange={setCity}
value={city}
/>
<InputFormControl
id="state"
label="State / Province"
label="State / Province *"
onChange={setState}
value={state}
/>
<InputFormControl
id="postalCode"
label="ZIP / Postal"
label="ZIP / Postal *"
onChange={setPostalCode}
value={postalCode}
/>
<InputFormControl
id="phone"
label="Phone Number"
onChange={setPhoneNumber}
onChange={setPhone}
type="tel"
value={phoneNumber}
value={phone}
/>
<InputFormControl
id="originalPurchasePrice"
label="Original Purchase Price"
onChange={setValueOfDevice}
value={valueOfDevice}
onChange={setOriginalPurchasePrice}
value={originalPurchasePrice}
/>
<TextareaFormControl
id="description"
label="Additional information"
onChange={setAbout}
onChange={setDescription}
placeholder="Tell us about each laptop, tablet, and/or smartphone you'd like to donate"
value={about}
value={description}
/>
<div className="flex items-center justify-center py-2">
<button className="btn btn-primary" type="submit">
Expand All @@ -162,6 +214,9 @@ export default function GiveDevicesPage() {
</div>
<Footer />
</main>
<Modal isOpen={isModalOpen} onClose={hideModal}>
{modalText}
</Modal>
</>
);
}
Loading

1 comment on commit a904daa

@vercel
Copy link

@vercel vercel bot commented on a904daa Sep 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.