diff --git a/packages/sylius/.env.template b/packages/sylius/.env.template new file mode 100644 index 000000000..7a50be7bd --- /dev/null +++ b/packages/sylius/.env.template @@ -0,0 +1,4 @@ +COMMERCE_PROVIDER=@vercel/commerce-sylius + +NEXT_PUBLIC_SYLIUS_API_URL= +NEXT_PUBLIC_SYLIUS_ALLOWED_IMAGE_DOMAIN= diff --git a/packages/sylius/README.md b/packages/sylius/README.md new file mode 100644 index 000000000..d396de35d --- /dev/null +++ b/packages/sylius/README.md @@ -0,0 +1,3 @@ +# Sylius Commerce Provider + +// TODO: Write readme diff --git a/packages/sylius/package.json b/packages/sylius/package.json new file mode 100644 index 000000000..4af7c69bc --- /dev/null +++ b/packages/sylius/package.json @@ -0,0 +1,82 @@ +{ + "name": "@vercel/commerce-sylius", + "version": "0.0.1", + "license": "MIT", + "scripts": { + "release": "taskr release", + "build": "taskr build", + "dev": "taskr", + "types": "tsc --emitDeclarationOnly", + "prettier-fix": "prettier --write ." + }, + "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/index.js", + "./*": [ + "./dist/*.js", + "./dist/*/index.js" + ], + "./next.config": "./dist/next.config.cjs" + }, + "typesVersions": { + "*": { + "*": [ + "src/*", + "src/*/index" + ], + "next.config": [ + "dist/next.config.d.cts" + ] + } + }, + "files": [ + "dist" + ], + "publishConfig": { + "typesVersions": { + "*": { + "*": [ + "dist/*.d.ts", + "dist/*/index.d.ts" + ], + "next.config": [ + "dist/next.config.d.cts" + ] + } + } + }, + "dependencies": { + "@vercel/commerce": "^0.0.1", + "@vercel/fetch": "^6.1.1", + "swr": "^1.2.0", + "lodash.debounce": "^4.0.8" + }, + "peerDependencies": { + "next": "^12", + "react": "^17", + "react-dom": "^17" + }, + "devDependencies": { + "@taskr/clear": "^1.1.0", + "@taskr/esnext": "^1.1.0", + "@taskr/watch": "^1.1.0", + "@types/lodash.debounce": "^4.0.6", + "@types/node": "^17.0.8", + "@types/react": "^17.0.38", + "lint-staged": "^12.1.7", + "next": "^12.0.8", + "prettier": "^2.5.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "taskr": "^1.1.0", + "taskr-swc": "^0.0.1", + "typescript": "^4.5.4" + }, + "lint-staged": { + "**/*.{js,jsx,ts,tsx,json}": [ + "prettier --write", + "git add" + ] + } +} diff --git a/packages/sylius/src/commerce.config.json b/packages/sylius/src/commerce.config.json new file mode 100644 index 000000000..5e7dd1934 --- /dev/null +++ b/packages/sylius/src/commerce.config.json @@ -0,0 +1,10 @@ +{ + "provider": "sylius", + "features": { + "cart": false, + "search": false, + "wishlist": false, + "customerAuth": false, + "customCheckout": false + } +} diff --git a/packages/sylius/src/const.ts b/packages/sylius/src/const.ts new file mode 100644 index 000000000..bf8976c7d --- /dev/null +++ b/packages/sylius/src/const.ts @@ -0,0 +1,5 @@ +export const API_URL = process.env.NEXT_PUBLIC_SYLIUS_API_URL +//export const API_CHANNEL = process.env.NEXT_PUBLIC_SALEOR_CHANNEL +//export const CHECKOUT_ID_COOKIE = 'saleor.CheckoutID' +//export const SALEOR_TOKEN = 'saleor.Token' +//export const SALEOR_CRSF_TOKEN = 'saleor.CSRFToken' diff --git a/packages/sylius/src/fetcher.ts b/packages/sylius/src/fetcher.ts new file mode 100644 index 000000000..9cef20ef8 --- /dev/null +++ b/packages/sylius/src/fetcher.ts @@ -0,0 +1,20 @@ +import { Fetcher } from '@vercel/commerce/utils/types' +import { API_URL } from './const' +import { handleFetchResponse } from './utils' + +const fetcher: Fetcher = async ({ url = API_URL, method = 'POST', body }) => { + //const token = getToken() + + return handleFetchResponse( + await fetch(url!, { + method, + body, + headers: { + //Authorization: `JWT ${token}`, + 'Content-Type': 'application/json', + }, + }) + ) +} + +export default fetcher diff --git a/packages/sylius/src/index.tsx b/packages/sylius/src/index.tsx new file mode 100644 index 000000000..bcfc1722d --- /dev/null +++ b/packages/sylius/src/index.tsx @@ -0,0 +1,9 @@ +import { getCommerceProvider, useCommerce as useCoreCommerce } from '@vercel/commerce' +import { syliusProvider, SyliusProvider } from './provider' + +export { syliusProvider } +export type { SyliusProvider } + +export const CommerceProvider = getCommerceProvider(syliusProvider) + +export const useCommerce = () => useCoreCommerce() diff --git a/packages/sylius/src/next.config.cjs b/packages/sylius/src/next.config.cjs new file mode 100644 index 000000000..a50671548 --- /dev/null +++ b/packages/sylius/src/next.config.cjs @@ -0,0 +1,8 @@ +const commerce = require('./commerce.config.json') + +module.exports = { + commerce, + images: { + domains: [process.env.NEXT_PUBLIC_SYLIUS_ALLOWED_IMAGE_DOMAIN], + }, +} diff --git a/packages/sylius/src/provider.ts b/packages/sylius/src/provider.ts new file mode 100644 index 000000000..fef3b3503 --- /dev/null +++ b/packages/sylius/src/provider.ts @@ -0,0 +1,26 @@ +//import { CHECKOUT_ID_COOKIE } from './const' +import { handler as useCart } from './cart/use-cart' +import { handler as useAddItem } from './cart/use-add-item' +import { handler as useUpdateItem } from './cart/use-update-item' +import { handler as useRemoveItem } from './cart/use-remove-item' + +import { handler as useCustomer } from './customer/use-customer' +import { handler as useSearch } from './product/use-search' + +import { handler as useLogin } from './auth/use-login' +import { handler as useLogout } from './auth/use-logout' +import { handler as useSignup } from './auth/use-signup' + +import fetcher from './fetcher' + +export const syliusProvider = { + locale: 'en-us', + //cartCookie: CHECKOUT_ID_COOKIE, + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, +} + +export type SyliusProvider = typeof syliusProvider diff --git a/packages/sylius/src/utils/handle-fetch-response.ts b/packages/sylius/src/utils/handle-fetch-response.ts new file mode 100644 index 000000000..927ab54f1 --- /dev/null +++ b/packages/sylius/src/utils/handle-fetch-response.ts @@ -0,0 +1,27 @@ +import { FetcherError } from '@vercel/commerce/utils/errors' + +export function getError(errors: any[] | null, status: number) { + errors = errors ?? [{ message: 'Failed to fetch Shopify API' }] + return new FetcherError({ errors, status }) +} + +export async function getAsyncError(res: Response) { + const data = await res.json() + return getError(data.errors, res.status) +} + +const handleFetchResponse = async (res: Response) => { + if (res.ok) { + const { data, errors } = await res.json() + + if (errors && errors.length) { + throw getError(errors, res.status) + } + + return data + } + + throw await getAsyncError(res) +} + +export default handleFetchResponse diff --git a/packages/sylius/src/utils/index.ts b/packages/sylius/src/utils/index.ts new file mode 100644 index 000000000..9084ed598 --- /dev/null +++ b/packages/sylius/src/utils/index.ts @@ -0,0 +1,18 @@ +export { default as handleFetchResponse } from './handle-fetch-response' + +/* +export { default as getSearchVariables } from './get-search-variables' +export { default as getSortVariables } from './get-sort-variables' +export { default as getBrands } from './get-brands' +export { default as getCategories } from './get-categories' +export { default as getCheckoutId } from './get-checkout-id' +export { default as checkoutCreate } from './checkout-create' +export { default as checkoutToCart } from './checkout-to-cart' +export { default as handleLogin, handleAutomaticLogin } from './handle-login' +export { default as handleAccountActivation } from './handle-account-activation' +export { default as throwUserErrors } from './throw-user-errors' +export * from './queries' +export * from './mutations' +export * from './normalize' +export * from './customer-token' +*/ diff --git a/packages/sylius/taskfile.js b/packages/sylius/taskfile.js new file mode 100644 index 000000000..39b1b2a86 --- /dev/null +++ b/packages/sylius/taskfile.js @@ -0,0 +1,20 @@ +export async function build(task, opts) { + await task + .source('src/**/*.+(ts|tsx|js)') + .swc({ dev: opts.dev, outDir: 'dist', baseUrl: 'src' }) + .target('dist') + .source('src/**/*.+(cjs|json)') + .target('dist') + task.$.log('Compiled src files') +} + +export async function release(task) { + await task.clear('dist').start('build') +} + +export default async function dev(task) { + const opts = { dev: true } + await task.clear('dist') + await task.start('build', opts) + await task.watch('src/**/*.+(ts|tsx|js|cjs|json)', 'build', opts) +} diff --git a/packages/sylius/tsconfig.json b/packages/sylius/tsconfig.json new file mode 100644 index 000000000..cd04ab2ff --- /dev/null +++ b/packages/sylius/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "outDir": "dist", + "baseUrl": "src", + "lib": ["dom", "dom.iterable", "esnext"], + "declaration": true, + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "incremental": true, + "jsx": "react-jsx" + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +}