0

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 { } }) 
0

1 Answer 1

2

The problem is here:

export const functions = dev ? app.functions().useEmulator("localhost", '5001') : app.functions() 

httpsCallable does not exists on the useEmulator method. Instead you should specify to use emulators before trying to use them like this:

const dev = true; const functions = app.functions(); // Checking if dev is true. If yes, use emulator if (dev) functions.useEmulator("localhost", 5001) export {functions} 
Sign up to request clarification or add additional context in comments.

2 Comments

I never would've gotten that. Thank you so much! This fixed it! Do you know by chance an easier way to test for local development rather than a flag? Maybe a NODE_ENV or something? I'd like to take away as many manual flags as possible, so it will use emulators when I'm developing, and switch to live ones when I push to production. :)
@JoelHager you can use the dotenv package in your React app as mentioned here. Then you can easily check it by process.env.ENV add any multiple env variables.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.