I'm going through the docs, and I cannot see where I'm going wrong. Can somebody maybe shed some light? I think I'm not referencing functions() or firebase correctly. Thanks! Here's all of the code:
firebase.js
import firebase from 'firebase/app' import 'firebase/auth' import 'firebase/firestore' import 'firebase/functions' const dev = true export const app = !firebase.apps.length ? firebase.initializeApp({ apiKey: "AIzaSyBDrj-rL-Mzswu9VXhgp-RuvP9Hvl1kqQ0", authDomain: "edit-elements.firebaseapp.com", databaseURL: "https://edit-elements-default-rtdb.firebaseio.com", projectId: "edit-elements", storageBucket: "edit-elements.appspot.com", messagingSenderId: "340652433701", appId: "1:340652433701:web:a26472592c1538bbac7acc", measurementId: "G-945XC7348K" }) : firebase.app() export const auth = app.auth() export const db = app.firestore() export const functions = dev ? app.functions().useEmulator("localhost", '5001') : app.functions() checkout.js (where the function createFreeOrder is called)
import PayPalComponent from '../components/PayPalComponent' import { Button, Grid, TextField, Typography } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' import { useAuth } from '../contexts/AuthContext' import { useCart } from '../contexts/CartContext' import Cart from '../components/Cart' import LoginForm from '../components/LoginForm' import SignupForm from '../components/SignupForm' import { useEffect, useState } from 'react' import { client } from '../prismic-configuration' import { Actions } from '../utils/cartActions' import { db, functions } from '../firebase' const theme = makeStyles({ checkoutContainer: { margin: 'auto', maxWidth: '1200px', paddingTop: '2rem', '&: section': { minHeight: '100vh' }, couponInput: { '& fieldset': { borderRadius: '6px 0px 0px 6px' } } } }) export default function Checkout() { const { currentUser } = useAuth() const { cart, cartTotal, dispatch } = useCart() const styles = theme() const [showLogin, setShowLogin] = useState(false) const hasItems = Boolean(Object.keys(cart.products).length) const [couponCode, setCouponCode] = useState('') const [couponError, setCouponError] = useState('') const cartCost = cartTotal() console.log(functions, db) const checkCoupon = async () => { setCouponError('') if (couponCode == '') return null console.log('NOTICE: Please note that the coupons are checked server-side, so any attempt to manipulate them here will do nothing, and you *will* be charged the price without a valid coupon') await client.getByUID('coupon', couponCode.toLowerCase()) .then(res => { if (res.data) dispatch({ type: Actions.ADD_COUPON, payload: res }) }) .catch(err => setCouponError('No Coupon / Expired Coupon')) } const handleFreeOrder = async () => { const createFreeOrder = functions.httpsCallable('createFreeOrder') createFreeOrder(cart.products) } return ( <Grid container direction="column" className={styles.checkoutContainer}> <Grid item> <Typography variant="h1" mb={'2rem'}>Shopping Cart</Typography> </Grid> { !currentUser && <> <Grid item p={'.5rem'}> <Typography variant="subtitle1">Please note that accounts are required for purchase, as it allows us to securely generate download tokens and process invoices.</Typography> </Grid> { !showLogin ? <Grid item> <SignupForm dontRedirect/> <Typography>Already have an account? <span style={{cursor: 'pointer'}} onClick={prev => setShowLogin(true)}>Click here</span> to login.</Typography> </Grid> : <Grid item> <LoginForm /> <Typography>Don't have an account? <span style={{color: '#5e5e5e', cursor: 'pointer'}} onClick={prev => setShowLogin(false)}>Click here</span> to login.</Typography> </Grid> } </> } <Grid container> <Grid item xs={12}> <Cart /> </Grid> { hasItems && <Grid item xs={12} sx={{textAlign: 'right'}} p={3} > <TextField className={styles.couponInput} helperText={couponError} label="Coupon Code" value={couponCode.toUpperCase()} onChange={(e) => setCouponCode(e.target.value)} /><Button disableElevation sx={{padding: '1rem', borderRadius: '0px 6px 6px 0px'}} onClick={ checkCoupon } variant="contained">Check Code</Button> </Grid> } { hasItems && <Grid container style={{textAlign: 'right'}} justifyContent="flex-end"> <Grid item xs={12} sm={8} p={3}> { (cartTotal() > 0.00) ? <PayPalComponent /> : <Button onClick={handleFreeOrder} color="amber" style={{ padding: '1rem' }} variant="contained">Claim Product(s)</Button>} </Grid> </Grid> } </Grid> </Grid> ) } functions/index.js file (firebase functions file):
const firebase = require('firebase-admin'); const functions = require('firebase-functions'); // // Create and Deploy Your First Cloud Functions // // https://firebase.google.com/docs/functions/write-firebase-functions // // exports.helloWorld = functions.https.onRequest((request, response) => { // functions.logger.info("Hello logs!", {structuredData: true}); // response.send("Hello from Firebase!"); // }); exports.newsletterSignup = functions.https.onCall((data, ctx) => { console.log('ctx obj', ctx, 'ctx req', ctx.req) const sgMail = require('@sendgrid/mail') sgMail.setApiKey(process.env.SENDGRID_API_KEY) const msg = ("hello") res.send('Received').end() }) exports.createFreeOrder = functions.https.onCall(async (data, ctx) => { const firebase = require('firebase-admin') const db = require('firebase/firebase-firestore') console.log('data and ctx', data, ctx) }) exports.createPaypalOrder = functions.https.onCall(async (data, ctx) => { const checkoutNodeSDK = require('@paypal/checkout-server-sdk') const Prismic = require('@prismicio/client') const products = data.products const env = () => { const clientId = process.env.PAYPAL_CLIENT.id const clientSecret = process.env.PAYPAL_CLIENT.clientSecret return new checkoutNodeSDK.core.SandboxEnvironment(clientId, clientSecret) } const client = () => { return new checkoutNodeSDK.core.PayPalHttpClient(env) } // The request for PayPal const request = new paypal.orders.OrdersCreateRequest() request.prefer('return=representation') request.requestBody({ intent: 'Capture', purchase_units: [{ amount: { currency_code: 'USD', value: 0 } }] }) let order try { order = await client().execute(request) } catch { } })