Skip to content

Update getting started experience #320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: feature/nextjs-ecommerce
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion starters/nextjs/firebase-ecommerce/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ vsce-debug.log*
# Firebase
firebase-debug.log*
firebase-debug.*
.firebase
.firebase
.firebaserc

# dataconnect
dataconnect-generated/
dataconnect/.dataconnect/
46 changes: 29 additions & 17 deletions starters/nextjs/firebase-ecommerce/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@ The application provides a quick and easy to use shopping experience with featur

1. Create a new Firebase project in the [Firebase Console](https://console.firebase.google.com).
2. Enable **Email/Password Authentication**.
3. Add Firebase app secrets to `.env.local`.
4. Include Firebase app secrets in **App Hosting**.
3. Replace the relevant commented-out environment variables in `apphosting.yaml`
with your firebase config.

#### Firebase Data Connect

1. Install the **Firebase Data Connect** extension for VS Code.
2. Create a new Data Connect instance and service.
3. Set up billing for the Firebase project.
4. Switch to the Blaze plan.
5. Define the required schema, queries, and mutations.
5. Modify `dataconnect/dataconnect.yaml` to specify `serviceId`, `location`,
`schema.datasource.postgresql.database` and
`schema.datasource.postgressql.cloudSql.instanceId`
6. Deploy the schema, queries, and mutations to production.

#### Firebase Storage
Expand All @@ -48,13 +50,18 @@ The application provides a quick and easy to use shopping experience with featur
#### Firebase App Hosting

1. Connect the Firebase app to your GitHub repository.
2. Create a new backend for the application.
3. Deploy secrets to app hosting using the Firebase CLI.
4. Deploy the application to Firebase Hosting.
2. Create a new backend for the application, but do not deploy yet.
We need to set up environment variables first for the app to work.

### Stripe Setup

1. Create a new Stripe account.
2. Follow the instructions in apphosting.yaml to create the
public and private keys for your stripe application.
3. Create a webhook that listen to "Events on your account" at
<your domain>/api/stripe/webhook that receives at least
the following events: `payment_intent.succeeded`, `payment_intent.failed`,
`charge.succeeded`, `charge.updated`.
2. Add API keys (Publishable and Secret) to `.env.local`.
3. Set up a webhook endpoint in the Firebase project.
4. Add the webhook secret to `.env.local`.
Expand All @@ -63,12 +70,18 @@ The application provides a quick and easy to use shopping experience with featur

## Environment Variables

The following environment variables must be configured in `.env.local`:
The following environment variables must be configured in `apphosting.yaml`
(there are comments for where to find these values)

- **Firebase Secrets**: `NEXT_PUBLIC_FIREBASE_API_KEY`, `NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN`, `NEXT_PUBLIC_FIREBASE_PROJECT_ID`, `NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET`, `NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID`, `NEXT_PUBLIC_FIREBASE_APP_ID`.
- **Stripe Secrets**: `NEXT_PUBLIC_STRIPE_PUB_KEY`, `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`
- **Firebase Config**: `NEXT_PUBLIC_FIREBASE_API_KEY`, `NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN`, `NEXT_PUBLIC_FIREBASE_PROJECT_ID`, `NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET`, `NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID`, `NEXT_PUBLIC_FIREBASE_APP_ID`.
- **Stripe Config**: `NEXT_PUBLIC_STRIPE_PUB_KEY`, `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`
- **Google/Gemini API Key**: `GOOGLE_API_KEY`

## Deploy
Once you have set up Stripe, Data Connect, and configured your App Hosting environment, it's time to deploy!
If you have automatic rollouts enabled, simply push your changes. Otherwise, after pushing, go to the
Firebase console and click "Create Rollout".

## Application Features

### Homepage
Expand Down Expand Up @@ -148,18 +161,17 @@ To run this project locally, follow these steps:
```
npm install
```
4. Copy the example environment variables:
```
cp .env.example .env.local
```
• Fill in the required values (Firebase config, Stripe keys, Google API key, etc.).
5. Start the development server:
4. Fill in `apphosting.yaml` as guided by the comments.
5. Initialize the firebase emulator suite with `firebase init emulators`. You may
create an `apphosting.emulator.yaml` if you choose to use different configurations
during local development or you can test against your production config.
5. Start the emulator
```
npm run dev
firebase emulators:start
```
6. Open the application in your browser at:
```
http://localhost:3000
http://localhost:5002
```

---
Expand Down
66 changes: 42 additions & 24 deletions starters/nextjs/firebase-ecommerce/apphosting.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,46 @@ runConfig:
minInstances: 0

# Environment variables and secrets.
# Grant access to secrets in Cloud Secret Manager.
# See https://firebase.google.com/docs/app-hosting/configure#secret-parameters
# If you would like to change any keys' values in local development with the emulator
# (e.g. using Stripe Sandbox keys), you can overwrite values in apphosting.emulator.yaml
env:
# Grant access to secrets in Cloud Secret Manager.
# See https://firebase.google.com/docs/app-hosting/configure#secret-parameters
- variable: NEXT_PUBLIC_FIREBASE_API_KEY
secret: FIREBASE_API_KEY
- variable: NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN
secret: FIREBASE_AUTH_DOMAIN
- variable: NEXT_PUBLIC_FIREBASE_PROJECT_ID
secret: FIREBASE_PROJECT_ID
- variable: NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET
secret: FIREBASE_STORAGE_BUCKET
- variable: NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID
secret: FIREBASE_MESSAGING_SENDER_ID
- variable: NEXT_PUBLIC_FIREBASE_APP_ID
secret: FIREBASE_APP_ID
- variable: GOOGLE_API_KEY
secret: GOOGLE_API_KEY
- variable: STRIPE_ACCOUNT_ID
secret: STRIPE_ACCOUNT_ID
- variable: STRIPE_SECRET_KEY
secret: STRIPE_SECRET_KEY
- variable: NEXT_PUBLIC_STRIPE_PUB_KEY
secret: STRIPE_PUB_KEY
- variable: STRIPE_WEBHOOK_SECRET
secret: STRIPE_WEBHOOK_SECRET
# Values for Firebase config can be found by clicking the cog next to "Project Overview"
# in the firebase console and clicking "project settings"
# - variable: NEXT_PUBLIC_FIREBASE_API_KEY
# value: <YOUR VALUE HERE>
# - variable: NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN
# value: <YOUR VALUE HERE>
# - variable: NEXT_PUBLIC_FIREBASE_PROJECT_ID
# value: <YOUR VALUE HERE>
# - variable: NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET
# value: <YOUR VALUE HERE>
# - variable: NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID
# value: <YOUR VALUE HERE>
# - variable: NEXT_PUBLIC_FIREBASE_APP_ID
# value: <YOUR VALUE HERE>

# The Google API key needs access to the Generative AI APIs. Create your key by visiting
# https://ai.google.dev/gemini-api/docs and clicking "Get a Gemini API Key"
# You can then run `firebase apphosting:secrets:set google-api-key and pasting the value.
# - variable: GOOGLE_API_KEY
# secret: google-api-key

# To use stripe, you must create an account on stripe.com. From the stripe dashboard
# You can copy the NEXT_PUBLIC_STRIPE_PUB_KEY from "Publishable key" in the dashboard.
# You can set STRIPE_SECRET_KEY by calling `firebase apphosting:secrets:set stripe-secret-key`
# and pasting the value listed as "Secret key" in the dashboard.
# To get the stripe webhook secret, create a stripe webhook as described in README.md,
# go to the webhook details page and click "Reveal" under "Signing secret". Copy that value,
# run `firebase apphosting:secrets:set stripe-webhook-secret` and paste the secret value when
# prompted. The value for STRIPE_ACCOUNT_ID can be found in the upper right corner of the
# webhook details page.
# - variable: NEXT_PUBLIC_STRIPE_PUB_KEY
# value: <YOUR VALUE HERE>
# - variable: STRIPE_SECRET_KEY
# secret: stripe-secret-key
# - variable: STRIPE_ACCOUNT_ID
# value: <YOUR VALUE HERE>
# - variable: STRIPE_WEBHOOK_SECRET
# secret: stripe-webhook-secret
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
- [*SearchProductTitleUsingL2Similarity*](#searchproducttitleusingl2similarity)
- [*SearchProductReviewContentUsingL2Similarity*](#searchproductreviewcontentusingl2similarity)
- [*GetOrdersByCustomerId*](#getordersbycustomerid)
- [*GetCurrentCustomerOrders*](#getcurrentcustomerorders)
- [*GetOrderById*](#getorderbyid)
- [**Mutations**](#mutations)
- [*UpsertCustomer*](#upsertcustomer)
Expand Down Expand Up @@ -988,124 +987,10 @@ Recall that executing the `GetOrdersByCustomerId` query returns a `QueryPromise`
The `data` property is an object of type `GetOrdersByCustomerIdData`, which is defined in [default-connector/index.d.ts](./index.d.ts). It has the following fields:
```javascript
export interface GetOrdersByCustomerIdData {
orders: ({
id: UUIDString;
customerId: string;
processedAt: DateString;
chargeId?: string | null;
paymentIntentId?: string | null;
receiptUrl?: string | null;
subtotalPrice: number;
totalPrice: number;
financialStatus: string;
fulfillmentStatus: string;
orderItems_on_order: ({
id: UUIDString;
quantity: number;
price: number;
product: {
id: UUIDString;
title: string;
handle: string;
productImages_on_product: ({
url: string;
altText?: string | null;
width: number;
height: number;
})[];
} & Product_Key;
} & OrderItem_Key)[];
} & Order_Key)[];
}
```
### Using `GetOrdersByCustomerId`'s action shortcut function

```javascript
import { getDataConnect, DataConnect } from 'firebase/data-connect';
import { connectorConfig, getOrdersByCustomerId, GetOrdersByCustomerIdVariables } from '@firebasegen/default-connector';

// The `GetOrdersByCustomerId` query requires an argument of type `GetOrdersByCustomerIdVariables`:
const getOrdersByCustomerIdVars: GetOrdersByCustomerIdVariables = {
customerId: ...,
};

// Call the `getOrdersByCustomerId()` function to execute the query.
// You can use the `await` keyword to wait for the promise to resolve.
const { data } = await getOrdersByCustomerId(getOrdersByCustomerIdVars);
// Variables can be defined inline as well.
const { data } = await getOrdersByCustomerId({ customerId: ..., });

// You can also pass in a `DataConnect` instance to the action shortcut function.
const dataConnect = getDataConnect(connectorConfig);
const { data } = await getOrdersByCustomerId(dataConnect, getOrdersByCustomerIdVars);

console.log(data.orders);

// Or, you can use the `Promise` API.
getOrdersByCustomerId(getOrdersByCustomerIdVars).then((response) => {
const data = response.data;
console.log(data.orders);
});
```

### Using `GetOrdersByCustomerId`'s `QueryRef` function

```javascript
import { getDataConnect, DataConnect, executeQuery } from 'firebase/data-connect';
import { connectorConfig, getOrdersByCustomerIdRef, GetOrdersByCustomerIdVariables } from '@firebasegen/default-connector';

// The `GetOrdersByCustomerId` query requires an argument of type `GetOrdersByCustomerIdVariables`:
const getOrdersByCustomerIdVars: GetOrdersByCustomerIdVariables = {
customerId: ...,
};

// Call the `getOrdersByCustomerIdRef()` function to get a reference to the query.
const ref = getOrdersByCustomerIdRef(getOrdersByCustomerIdVars);
// Variables can be defined inline as well.
const ref = getOrdersByCustomerIdRef({ customerId: ..., });

// You can also pass in a `DataConnect` instance to the `QueryRef` function.
const dataConnect = getDataConnect(connectorConfig);
const ref = getOrdersByCustomerIdRef(dataConnect, getOrdersByCustomerIdVars);

// Call `executeQuery()` on the reference to execute the query.
// You can use the `await` keyword to wait for the promise to resolve.
const { data } = await executeQuery(ref);

console.log(data.orders);

// Or, you can use the `Promise` API.
executeQuery(ref).then((response) => {
const data = response.data;
console.log(data.orders);
});
```

## GetCurrentCustomerOrders
You can execute the `GetCurrentCustomerOrders` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [default-connector/index.d.ts](./index.d.ts):
```javascript
getCurrentCustomerOrders(): QueryPromise<GetCurrentCustomerOrdersData, undefined>;

getCurrentCustomerOrdersRef(): QueryRef<GetCurrentCustomerOrdersData, undefined>;
```
You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
```javascript
getCurrentCustomerOrders(dc: DataConnect): QueryPromise<GetCurrentCustomerOrdersData, undefined>;

getCurrentCustomerOrdersRef(dc: DataConnect): QueryRef<GetCurrentCustomerOrdersData, undefined>;
```

### Variables
The `GetCurrentCustomerOrders` query has no variables.
### Return Type
Recall that executing the `GetCurrentCustomerOrders` query returns a `QueryPromise` that resolves to an object with a `data` property.

The `data` property is an object of type `GetCurrentCustomerOrdersData`, which is defined in [default-connector/index.d.ts](./index.d.ts). It has the following fields:
```javascript
export interface GetCurrentCustomerOrdersData {
orders?: {
orders_on_customer: ({
id: UUIDString;
customerId: string;
processedAt: DateString;
chargeId?: string | null;
paymentIntentId?: string | null;
Expand Down Expand Up @@ -1134,43 +1019,55 @@ export interface GetCurrentCustomerOrdersData {
};
}
```
### Using `GetCurrentCustomerOrders`'s action shortcut function
### Using `GetOrdersByCustomerId`'s action shortcut function

```javascript
import { getDataConnect, DataConnect } from 'firebase/data-connect';
import { connectorConfig, getCurrentCustomerOrders } from '@firebasegen/default-connector';
import { connectorConfig, getOrdersByCustomerId, GetOrdersByCustomerIdVariables } from '@firebasegen/default-connector';

// The `GetOrdersByCustomerId` query requires an argument of type `GetOrdersByCustomerIdVariables`:
const getOrdersByCustomerIdVars: GetOrdersByCustomerIdVariables = {
customerId: ...,
};

// Call the `getCurrentCustomerOrders()` function to execute the query.
// Call the `getOrdersByCustomerId()` function to execute the query.
// You can use the `await` keyword to wait for the promise to resolve.
const { data } = await getCurrentCustomerOrders();
const { data } = await getOrdersByCustomerId(getOrdersByCustomerIdVars);
// Variables can be defined inline as well.
const { data } = await getOrdersByCustomerId({ customerId: ..., });

// You can also pass in a `DataConnect` instance to the action shortcut function.
const dataConnect = getDataConnect(connectorConfig);
const { data } = await getCurrentCustomerOrders(dataConnect);
const { data } = await getOrdersByCustomerId(dataConnect, getOrdersByCustomerIdVars);

console.log(data.orders);

// Or, you can use the `Promise` API.
getCurrentCustomerOrders().then((response) => {
getOrdersByCustomerId(getOrdersByCustomerIdVars).then((response) => {
const data = response.data;
console.log(data.orders);
});
```

### Using `GetCurrentCustomerOrders`'s `QueryRef` function
### Using `GetOrdersByCustomerId`'s `QueryRef` function

```javascript
import { getDataConnect, DataConnect, executeQuery } from 'firebase/data-connect';
import { connectorConfig, getCurrentCustomerOrdersRef } from '@firebasegen/default-connector';
import { connectorConfig, getOrdersByCustomerIdRef, GetOrdersByCustomerIdVariables } from '@firebasegen/default-connector';

// The `GetOrdersByCustomerId` query requires an argument of type `GetOrdersByCustomerIdVariables`:
const getOrdersByCustomerIdVars: GetOrdersByCustomerIdVariables = {
customerId: ...,
};

// Call the `getCurrentCustomerOrdersRef()` function to get a reference to the query.
const ref = getCurrentCustomerOrdersRef();
// Call the `getOrdersByCustomerIdRef()` function to get a reference to the query.
const ref = getOrdersByCustomerIdRef(getOrdersByCustomerIdVars);
// Variables can be defined inline as well.
const ref = getOrdersByCustomerIdRef({ customerId: ..., });

// You can also pass in a `DataConnect` instance to the `QueryRef` function.
const dataConnect = getDataConnect(connectorConfig);
const ref = getCurrentCustomerOrdersRef(dataConnect);
const ref = getOrdersByCustomerIdRef(dataConnect, getOrdersByCustomerIdVars);

// Call `executeQuery()` on the reference to execute the query.
// You can use the `await` keyword to wait for the promise to resolve.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,6 @@ export function getOrdersByCustomerId(dcOrVars, vars) {
return executeQuery(getOrdersByCustomerIdRef(dcOrVars, vars));
}

export function getCurrentCustomerOrdersRef(dc) {
const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined);
dcInstance._useGeneratedSdk();
return queryRef(dcInstance, 'GetCurrentCustomerOrders');
}

export function getCurrentCustomerOrders(dc) {
return executeQuery(getCurrentCustomerOrdersRef(dc));
}

export function getOrderByIdRef(dcOrVars, vars) {
const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
dcInstance._useGeneratedSdk();
Expand Down
Loading
Loading