Skip to content
Merged
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
15 changes: 15 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM mcr.microsoft.com/devcontainers/typescript-node:22

ENV PNPM_HOME="/home/node/.pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable

WORKDIR /app

# This is needed so pnpm-store volume is created with correct permissions (see docker-compose.yml)
RUN mkdir -p /app/.pnpm-store
RUN chown -R node:node /app/.pnpm-store

COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
RUN chown -R node:node /home/node/.pnpm
23 changes: 23 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "Saleor app template",
"dockerComposeFile": "docker-compose.yml",
"service": "saleor-app-template",
"workspaceFolder": "/app",
"forwardPorts": [3000],
"portsAttributes": {
"3000": {
"label": "Saleor app"
}
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"GraphQL.vscode-graphql-syntax",
"GraphQL.vscode-graphql",
"streetsidesoftware.code-spell-checker"
]
}
}
}
14 changes: 14 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
saleor-app-template:
image: saleor-app-template
command: sleep infinity # keeps docker container running
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- "..:/app"
- "pnpm-store:/app/.pnpm-store"

volumes:
pnpm-store:
driver: local
6 changes: 6 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"extends": ["next", "plugin:@saleor/saleor-app/recommended", "prettier"],
"plugins": ["simple-import-sort"],
"parserOptions": {
"project": "tsconfig.json"
},
"rules": {
"import/order": "off", // to avoid conflicts with simple-import-sort
"simple-import-sort/imports": "warn",
"simple-import-sort/exports": "warn"
}
}
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ You can use any preferred technology to create Saleor Apps, but Next.js is among

## Development

#### Running app locally in development containers

The easiest way of running app for local development is to use [development containers](https://containers.dev/).
If you have Visual Studio Code follow their [guide](https://code.visualstudio.com/docs/devcontainers/containers#_quick-start-open-an-existing-folder-in-a-container) on how to open existing folder in container.

Development container only creates container, you still need to start the server.

Development container will have port opened:

1. `3000` - were app dev server will listen to requests

### Requirements

Before you start, make sure you have installed:
Expand Down
47 changes: 13 additions & 34 deletions generated/graphql.ts

Large diffs are not rendered by default.

Empty file removed graphql/fragments/.gitkeep
Empty file.
12 changes: 12 additions & 0 deletions graphql/fragments/order-created.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fragment OrderCreatedWebhookPayload on OrderCreated {
order {
userEmail
id
number
user {
email
firstName
lastName
}
}
}
9 changes: 0 additions & 9 deletions graphql/queries/FetchAppDetails.graphql

This file was deleted.

Empty file removed graphql/subscriptions/.gitkeep
Empty file.
5 changes: 5 additions & 0 deletions graphql/subscriptions/order-created.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
subscription OrderCreatedSubscription {
event {
...OrderCreatedWebhookPayload
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"eslint": "8.31.0",
"eslint-config-next": "13.1.2",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"prettier": "^2.8.2",
"typescript": "5.0.4"
},
Expand Down
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/lib/no-ssr-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { PropsWithChildren } from "react";
import dynamic from "next/dynamic";
import React, { PropsWithChildren } from "react";

const Wrapper = (props: PropsWithChildren<{}>) => <React.Fragment>{props.children}</React.Fragment>;

Expand Down
1 change: 1 addition & 0 deletions src/order-example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Box, Text } from "@saleor/macaw-ui";
import gql from "graphql-tag";
import Link from "next/link";

import { useLastOrderQuery } from "../generated/graphql";

/**
Expand Down
10 changes: 5 additions & 5 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import "../styles/globals.css";

import { AppBridge, AppBridgeProvider } from "@saleor/app-sdk/app-bridge";
import { RoutePropagator } from "@saleor/app-sdk/app-bridge/next";
import { ThemeProvider } from "@saleor/macaw-ui";
import { AppProps } from "next/app";
import { useEffect } from "react";

import { ThemeProvider } from "@saleor/macaw-ui";
import { NoSSRWrapper } from "../lib/no-ssr-wrapper";
import { ThemeSynchronizer } from "../lib/theme-synchronizer";
import { GraphQLProvider } from "../providers/GraphQLProvider";
import { NoSSRWrapper } from "@/lib/no-ssr-wrapper";
import { ThemeSynchronizer } from "@/lib/theme-synchronizer";
import { GraphQLProvider } from "@/providers/GraphQLProvider";

/**
* Ensure instance is a singleton.
Expand All @@ -32,7 +32,7 @@ function NextApp({ Component, pageProps }: AppProps) {
<NoSSRWrapper>
<AppBridgeProvider appBridgeInstance={appBridgeInstance}>
<GraphQLProvider>
<ThemeProvider >
<ThemeProvider>
<ThemeSynchronizer />
<RoutePropagator />
<Component {...pageProps} />
Expand Down
1 change: 1 addition & 0 deletions src/pages/actions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Box, Button, Text } from "@saleor/macaw-ui";

import { OrderExample } from "../order-example";

/**
Expand Down
2 changes: 1 addition & 1 deletion src/pages/api/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default createManifestHandler({
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;

const manifest: AppManifest = {
name: 'Saleor App Template',
name: "Saleor App Template",
tokenTargetUrl: `${apiBaseURL}/api/register`,
appUrl: iframeBaseUrl,
/**
Expand Down
2 changes: 1 addition & 1 deletion src/pages/api/register.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createAppRegisterHandler } from "@saleor/app-sdk/handlers/next";

import { saleorApp } from "../../saleor-app";
import { saleorApp } from "@/saleor-app";

/**
* Required endpoint, called by Saleor to install app.
Expand Down
46 changes: 9 additions & 37 deletions src/pages/api/webhooks/order-created.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,12 @@
import { gql } from "urql";
import { SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { OrderCreatedWebhookPayloadFragment } from "../../../../generated/graphql";
import { saleorApp } from "../../../saleor-app";
import { createClient } from "../../../lib/create-graphq-client";

/**
* Example payload of the webhook. It will be transformed with graphql-codegen to Typescript type: OrderCreatedWebhookPayloadFragment
*/
const OrderCreatedWebhookPayload = gql`
fragment OrderCreatedWebhookPayload on OrderCreated {
order {
userEmail
id
number
user {
email
firstName
lastName
}
}
}
`;
import { createClient } from "@/lib/create-graphq-client";
import { saleorApp } from "@/saleor-app";

/**
* Top-level webhook subscription query, that will be attached to the Manifest.
* Saleor will use it to register webhook.
*/
const OrderCreatedGraphqlSubscription = gql`
# Payload fragment must be included in the root query
${OrderCreatedWebhookPayload}
subscription OrderCreated {
event {
...OrderCreatedWebhookPayload
}
}
`;
import {
OrderCreatedSubscriptionDocument,
OrderCreatedWebhookPayloadFragment,
} from "../../../../generated/graphql";

/**
* Create abstract Webhook. It decorates handler and performs security checks under the hood.
Expand All @@ -46,7 +18,7 @@ export const orderCreatedWebhook = new SaleorAsyncWebhook<OrderCreatedWebhookPay
webhookPath: "api/webhooks/order-created",
event: "ORDER_CREATED",
apl: saleorApp.apl,
query: OrderCreatedGraphqlSubscription,
query: OrderCreatedSubscriptionDocument,
});

/**
Expand Down Expand Up @@ -81,12 +53,12 @@ export default orderCreatedWebhook.createHandler((req, res, ctx) => {
* Create GraphQL client to interact with Saleor API.
*/
const client = createClient(authData.saleorApiUrl, async () => ({ token: authData.token }));

/**
* Now you can fetch additional data using urql.
* https://formidable.com/open-source/urql/docs/api/core/#clientquery
*/

// const data = await client.query().toPromise()

/**
Expand Down
3 changes: 2 additions & 1 deletion src/providers/GraphQLProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useAppBridge } from "@saleor/app-sdk/app-bridge";
import { PropsWithChildren } from "react";
import { Provider } from "urql";
import { createClient } from "../lib/create-graphq-client";

import { createClient } from "@/lib/create-graphq-client";

export function GraphQLProvider(props: PropsWithChildren<{}>) {
const { appBridgeState } = useAppBridge();
Expand Down
2 changes: 1 addition & 1 deletion src/setup-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
*
* https://vitest.dev/config/#setupfiles
*/
export {}
export {};
6 changes: 5 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
Expand Down
3 changes: 3 additions & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ export default defineConfig({
environment: "jsdom",
setupFiles: "./src/setup-tests.ts",
css: false,
alias: {
"@/": new URL("./src/", import.meta.url).pathname,
},
},
});