Skip to content

Commit

Permalink
Merge branch 'main' into combine-prs-branch
Browse files Browse the repository at this point in the history
  • Loading branch information
liorMar committed May 20, 2024
2 parents f20e765 + 8ce5778 commit b642e6f
Show file tree
Hide file tree
Showing 14 changed files with 530 additions and 153 deletions.
123 changes: 109 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Wix Headless Examples

This [Next.js](https://nextjs.org/) project provides a minimal example site to demonstrate basic usage of various Wix Headless APIs. The implementation focuses on simplicity and readability, rather than feature richness, performance, or completeness. This repository can be used as a quick reference for bootstrapping a Wix Headless application, but it should not be treated as a best practices guide.
This [Next.js](https://nextjs.org/) project provides a minimal example site to demonstrate basic usage of various Wix
Headless APIs. The implementation focuses on simplicity and readability, rather than feature richness, performance, or
completeness. This repository can be used as a quick reference for bootstrapping a Wix Headless application, but it
should not be treated as a best practices guide.

For a more comprehensive example of Wix Headless integration, we recommend checking out our [starter templates](https://www.wix.com/developers/headless/templates).
For a more comprehensive example of Wix Headless integration, we recommend checking out
our [starter templates](https://www.wix.com/developers/headless/templates).

You can view the latest version of this repo deployed at [https://wix-headless-example.vercel.app/](https://wix-headless-example.vercel.app/), but we recommend cloning it and experimenting with it locally.
You can view the latest version of this repo deployed
at [https://wix-headless-example.vercel.app/](https://wix-headless-example.vercel.app/), but we recommend cloning it and
experimenting with it locally.

## Getting Started

Expand All @@ -17,18 +23,107 @@ yarn dev

Open [http://localhost:3000](http://localhost:3000) in your browser to see the result.

The following files demonstrate the usage of various Wix Headless APIs:
## Wix Headless APIs Usage

* Authentication:
* Login/Logout button: [pages/members.js](./pages/members.js)
* Login callback page: [pages/login-callback.js](./pages/login-callback.js)
* Visitor cookie generation: [middleware.js](./middleware.js)
* Headless CMS: [pages/content.js](./pages/content.js)
* Headless Bookings: [pages/booking.js](./pages/booking.js)
* Headless Store: [pages/store.js](./pages/store.js)
* Headless Tickets: [pages/tickets.js](./pages/tickets.js)
* Headless Subscriptions: [pages/subscriptions.js](./pages/subscriptions.js)
This project demonstrates the usage of various Wix Headless APIs. Here's a brief overview of each:

### Authentication

The authentication process is handled in the following files:

- [`pages/members.js`](./pages/members.js): This file contains the Login/Logout button implementation. It demonstrates
how to use the [Wix Members API](https://dev.wix.com/docs/sdk/backend-modules/members/members/introduction) to get the
current user's information.
- [`pages/login-callback.js`](./pages/login-callback.js): This file handles the login callback process. It demonstrates
how to use the [Wix OAuthStrategy API](https://dev.wix.com/docs/sdk/core-modules/sdk/oauth-strategy#oauthstrategy) to
authenticate users.
- [`middleware.js`](./middleware.js): This file generates a visitor cookie if no session exists. It demonstrates how to
use the [Wix OAuthStrategy API](https://dev.wix.com/docs/sdk/core-modules/sdk/oauth-strategy#oauthstrategy) to
generate a visitor cookie.

> **[Wix Members API](https://dev.wix.com/docs/sdk/backend-modules/members/members/introduction)**: This API allows you
> to manage a site's members, including creating, updating, deleting members, retrieving member's information, and
> managing a member's community status.
>
> **[Wix OAuthStrategy API](https://dev.wix.com/docs/sdk/core-modules/sdk/oauth-strategy#oauthstrategy)**: This is an
> authentication strategy used with a Wix Client to authenticate API calls using OAuth tokens. It helps in identifying
> the
> requester's identity and their assigned roles.
### Headless CMS

The Headless CMS API is demonstrated in the [`pages/content.js`](./pages/content.js) file. This file fetches and
displays content from the Wix CMS.
It demonstrates how to use the [Wix Data API](https://dev.wix.com/docs/sdk/backend-modules/data/introduction) to
retrieve, create, update, and delete content in your site database collections.

> **[Wix Data API](https://dev.wix.com/docs/sdk/backend-modules/data/introduction)**: This API provides a complete
> solution for accessing, organizing, configuring, and managing data stored in a Wix project or your site's database.
> It allows you to create, modify, delete data collections, manage data items, create indexes for data collections, and
> connect external databases to a Wix project or site.
### Headless Bookings

The Headless Bookings API is demonstrated in the [`pages/booking.js`](./pages/booking.js) file. This file handles the
booking process.
It demonstrates how to use
the [Wix Bookings API](https://dev.wix.com/docs/sdk/backend-modules/bookings/bookings/introduction) to manage and create
bookings for services provided by your site.

> **[Wix Bookings API](https://dev.wix.com/docs/sdk/backend-modules/bookings/bookings/introduction)**: This API allows
> you to manage bookings for a site's services. It holds information about the customer and the session or schedule they
> have booked.
### Headless Store

The Headless Store API is demonstrated in the [`pages/store.js`](./pages/store.js) file. This file handles the store
operations.
It demonstrates how to use the [Wix Stores API](https://dev.wix.com/docs/sdk/backend-modules/stores) allows you to
manage your store inventory, orders, and collections,
and it also demonstrates how to use
the [Wix eCommerce API](https://dev.wix.com/docs/sdk/backend-modules/ecom/introduction) to manage carts, checkouts,
discount rules, item promotion, and orders.

> **[Wix Stores API](https://dev.wix.com/docs/sdk/backend-modules/stores)**: This API allows you to manage your store
> inventory, orders, and collections.
> It provides a comprehensive set of services for customizing store functionality.
>
> **[Wix eCommerce API](https://dev.wix.com/docs/sdk/backend-modules/ecom/introduction)**: This API provides a
> comprehensive set of services for customizing eCommerce functionality on your sites.
> It allows you to manage a site visitor's cart, handle checkout and payment flow, create and manage discount rules,
> promote items, and manage orders.
### Headless Tickets

The Headless Tickets API is demonstrated in the [`pages/tickets.js`](./pages/tickets.js) file. This file handles the
ticket operations.
It demonstrates how to use the [Wix Events API](https://dev.wix.com/docs/sdk/backend-modules/events/introduction) to
manage and sell tickets for events on your site.

> **[Wix Events API](https://dev.wix.com/docs/sdk/backend-modules/events/introduction)**: This API provides
> functionality for creating, updating, and managing events.
> It allows you to manage event details like location, scheduling, registration, tickets, RSVPs, online conferencing,
> messaging customization, and basic registration form customization.
### Headless Subscriptions

The Headless Subscriptions API is demonstrated in the [`pages/subscriptions.js`](./pages/subscriptions.js) file. This
file handles the subscription operations.
It demonstrates how to use
the [Wix Pricing Plans API](https://dev.wix.com/docs/sdk/backend-modules/pricing-plans/introduction) to manage and sell
subscriptions to services provided by your site.

> **[Wix Pricing Plans API](https://dev.wix.com/docs/sdk/backend-modules/pricing-plans/introduction)**: This API allows
> you to create and manage your plans and orders.
> It supports different pricing models like subscription, single payment for duration, and single payment unlimited.
> It also allows you to manage plan visibility, handle free plans and trial periods, and manage orders and
> subscriptions.
## Package dependency management

To ensure this repo always uses the latest APIs from the Wix JavaScript SDK, the repo is preconfigured with [Dependabot](https://docs.github.com/en/code-security/dependabot), GitHub's automated dependency management system. Due to the numerous pull requests generated by Dependabot, the repo also includes a preconfigured GitHub Action called "Combine PRs." This action can be executed manually to merge all of Dependabot's pull requests into a single PR, allowing for sanity checks to be performed only once. If the sanity check fails, each Dependabot PR can be inspected individually.
To ensure this repo always uses the latest APIs from the Wix JavaScript SDK, the repo is preconfigured
with [Dependabot](https://docs.github.com/en/code-security/dependabot), GitHub's automated dependency management system.
Due to the numerous pull requests generated by Dependabot, the repo also includes a preconfigured GitHub Action called "
Combine PRs." This action can be executed manually to merge all of Dependabot's pull requests into a single PR, allowing
for sanity checks to be performed only once. If the sanity check fails, each Dependabot PR can be inspected
individually.
18 changes: 17 additions & 1 deletion middleware.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
import { createClient, OAuthStrategy } from "@wix/sdk";
import { NextResponse } from "next/server";

// This function acts as a middleware for the Next.js application.
// We use this middleware to generate a session for the visitor.
// read more about next.js middleware here https://nextjs.org/docs/app/building-your-application/routing/middleware
export async function middleware(request) {
// generate a session for the visitor if no session exists
// We check if a session cookie exists.
// If it doesn't exist, we generate a session for the visitor.
if (!request.cookies.get("session")) {
// We create a Wix client using the createClient function from the Wix SDK.
// We're using the OAuthStrategy for authentication.
// This strategy requires a client ID.
const myWixClient = createClient({
auth: OAuthStrategy({ clientId: `9e37d7b0-3621-418f-a6b6-b82bdeaf051d` }),
});

// We call the generateVisitorTokens method from the auth module of the Wix client.
// This method generates a set of tokens for the visitor.
const visitorTokens = await myWixClient.auth.generateVisitorTokens();

// We store the tokens in a cookie named "session" in the request object so the cookie would propagate to our pages / routes
request.cookies.set("session", JSON.stringify(visitorTokens));

// We create a new response using the NextResponse.next method.
const response = NextResponse.next({
request,
});

// We also store the tokens in a cookie named "session" in the response.
response.cookies.set("session", JSON.stringify(visitorTokens));

// Finally, we return the response.
return response;
}
}
Expand Down
26 changes: 16 additions & 10 deletions pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Head from 'next/head'
import Link from 'next/link'
import Image from 'next/image'
import { Inter } from 'next/font/google'
import Head from "next/head";
import Link from "next/link";
import Image from "next/image";
import { Inter } from "next/font/google";

import '@/styles/globals.css'
import styles from '@/styles/app.module.css'
import "@/styles/globals.css";
import styles from "@/styles/app.module.css";

import LoginBar from './members';
import Examples from './content';
import LoginBar from "./members";
import Examples from "./content";

const inter = Inter({ subsets: ['latin'] });
const inter = Inter({ subsets: ["latin"] });

export default function App({ Component, pageProps }) {
return (
Expand All @@ -23,7 +23,13 @@ export default function App({ Component, pageProps }) {
<div className={styles.content}>
<header>
<Link href="/">
<Image src="/wix.svg" alt="Wix Logo" width={88} height={34} priority />
<Image
src="/wix.svg"
alt="Wix Logo"
width={88}
height={34}
priority
/>
</Link>
<LoginBar />
</header>
Expand Down
4 changes: 2 additions & 2 deletions pages/_document.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Html, Head, Main, NextScript } from 'next/document'
import { Head, Html, Main, NextScript } from "next/document";

export default function Document() {
return (
Expand All @@ -9,5 +9,5 @@ export default function Document() {
<NextScript />
</body>
</Html>
)
);
}
46 changes: 41 additions & 5 deletions pages/booking.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,82 @@ import { availabilityCalendar, services } from "@wix/bookings";
import { redirects } from "@wix/redirects";
import testIds from "@/src/utils/test-ids";

// We're creating a Wix client using the createClient function from the Wix SDK.
const myWixClient = createClient({
// We specify the modules we want to use with the client.
// In this case, we're using the services, availabilityCalendar, and redirects modules.
modules: { services, availabilityCalendar, redirects },

// We're using the OAuthStrategy for authentication.
// This strategy requires a client ID and a set of tokens.
auth: OAuthStrategy({
// The client ID is a unique identifier for the application.
// It's used to authenticate the application with the Wix platform.
clientId: `9e37d7b0-3621-418f-a6b6-b82bdeaf051d`,

// The tokens are used to authenticate the user.
// In this case, we're getting the tokens from a cookie named "session".
// If the cookie doesn't exist, we default to null.
tokens: JSON.parse(Cookies.get("session") || null),
}),
});

export default function Booking() {
// State variables for service list and availability entries
const [serviceList, setServiceList] = useState([]);
const [availabilityEntries, setAvailabilityEntries] = useState([]);

// This is function fetches the list of services.
async function fetchServices() {
// We call the queryServices method from the services module of the Wix client.
// This method retrieves the list of services.
const serviceList = await myWixClient.services.queryServices().find();

// Then, we update the state of the service list in the React component.
setServiceList(serviceList.items);
}

// This is function fetches the availability of a service.
async function fetchAvailability(service) {
// We create two Date objects for today and tomorrow.
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);

// We call the queryAvailability method from the availabilityCalendar module of the Wix client.
// This method retrieves the availability of a service.
const availability =
await myWixClient.availabilityCalendar.queryAvailability(
{
filter: {
serviceId: [service._id],
startDate: today.toISOString(),
endDate: tomorrow.toISOString(),
serviceId: [service._id], // We filter by the service ID.
startDate: today.toISOString(), // We set the start date to be today.
endDate: tomorrow.toISOString(), // We set the end date to be tomorrow.
},
},
{ timezone: "UTC" }
);
{ timezone: "UTC" }, // We set the timezone to be UTC.
); // the response contains the availability entries for the service within the specified time range.

// Then, we update the state of the availability entries in the React component.
setAvailabilityEntries(availability.availabilityEntries);
}

// This is function creates a redirect to the checkout page.
async function createRedirect(slotAvailability) {
// We call the createRedirectSession method from the redirects module of the Wix client.
// This method creates a redirect session to the checkout page.
const redirect = await myWixClient.redirects.createRedirectSession({
// We pass an object that specifies the slotAvailability for the bookingsCheckout.
bookingsCheckout: { slotAvailability, timezone: "UTC" },
// We also specify the postFlowUrl to be the current page URL. This is where the user will be redirected after the checkout flow.
callbacks: { postFlowUrl: window.location.href },
});

// Finally, we redirect the user to the URL generated by the redirect session.
window.location = redirect.redirectSession.fullUrl;
}

// Fetch services on component mount
useEffect(() => {
fetchServices();
}, []);
Expand All @@ -58,8 +90,10 @@ export default function Booking() {
<main data-testid={testIds.BOOKINGS_PAGE.CONTAINER}>
<div>
<h2>Choose a Service:</h2>
{/* Mapping through service list and displaying each service */}
{serviceList.map((service) => {
return (
// Each service is displayed in a section. When clicked, the availability of the service is fetched.
<section
key={service._id}
data-testid={testIds.BOOKINGS_PAGE.SERVICE}
Expand All @@ -72,8 +106,10 @@ export default function Booking() {
</div>
<div>
<h2>Choose a Slot:</h2>
{/* Mapping through availability entries and displaying each slot */}
{availabilityEntries.map((entry) => {
return (
// Each slot is displayed in a section. When clicked, a redirect to the checkout page is created.
<section
key={entry.slot.startDate}
data-testid={testIds.BOOKINGS_PAGE.SLOT}
Expand Down
15 changes: 11 additions & 4 deletions pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ export default function Home() {
<>
<article>
<h1>Quick start examples with Next.js for Wix Headless</h1>
<span>This is an example site to demonstrate how to use Wix&apos;s business solution APIs headless. Click each example to see how it works.</span>
<span>
<a href="https://dev.wix.com/api/sdk/about-wix-headless/overview">Documentation</a>
This is an example site to demonstrate how to use Wix&apos;s business
solution APIs headless. Click each example to see how it works.
</span>
<span>
<a href="https://dev.wix.com/api/sdk/about-wix-headless/overview">
Documentation
</a>
&nbsp;|&nbsp;
<a href="https://github.com/wix-incubator/wix-headless-example">Repo</a>
<a href="https://github.com/wix-incubator/wix-headless-example">
Repo
</a>
</span>
</article>
</>
)
);
}
Loading

0 comments on commit b642e6f

Please sign in to comment.