From 4fa3af0fe369cf64217a0bb27258207102af2d22 Mon Sep 17 00:00:00 2001 From: Andre Rabello Date: Wed, 15 Nov 2023 19:28:21 +0000 Subject: [PATCH 1/9] chore: starting point for v3 --- .github/workflows/release-pr.yml | 42 +++ .release-please-manifest.json | 9 + .../.vscode => .vscode}/extensions.json | 0 .../cobadged/.vscode => .vscode}/launch.json | 0 CONTRIBUTING.md | 34 +++ LICENSE | 21 ++ README.md | 8 +- bun.lockb | Bin 147256 -> 620528 bytes examples/features/cobadged/README.md | 26 +- examples/features/cobadged/astro.config.mjs | 6 - examples/features/cobadged/package.json | 17 -- examples/features/cobadged/src/api/primer.ts | 45 ---- examples/features/cobadged/src/env.d.ts | 1 - .../features/cobadged/src/pages/index.astro | 247 ------------------ examples/features/drop-in/README.md | 3 + examples/frameworks/astro/README.md | 5 + examples/frameworks/next/README.md | 5 + examples/frameworks/nuxt/README.md | 5 + examples/frameworks/qwik-city/README.md | 5 + examples/frameworks/solid-start/.gitignore | 24 ++ examples/frameworks/solid-start/README.md | 3 + examples/frameworks/solid-start/package.json | 22 ++ .../frameworks/solid-start/public/favicon.ico | Bin 0 -> 664 bytes .../solid-start/src/entry-client.tsx | 3 + .../solid-start/src/entry-server.tsx | 9 + examples/frameworks/solid-start/src/root.tsx | 35 +++ .../solid-start/src/routes/index.css | 49 ++++ .../solid-start/src/routes/index.tsx | 63 +++++ examples/frameworks/solid-start/tsconfig.json | 15 ++ .../frameworks/solid-start/vite.config.ts | 12 + examples/frameworks/svelte-kit/README.md | 5 + examples/servers/bun-elysia/package.json | 2 +- examples/servers/deno-hono/package.json | 8 + .../deno-hono/src/api/createClientSession.ts | 4 +- examples/servers/node-fastify/package.json | 3 +- .../servers/node-fastify/src/utils/post.ts | 2 - package.json | 22 +- packages/preact/index.ts | 1 + packages/preact/package.json | 10 + packages/qwik/index.ts | 1 + packages/qwik/package.json | 10 + packages/react-native/index.ts | 1 + packages/react-native/package.json | 10 + packages/react/index.ts | 1 + packages/react/package.json | 10 + packages/solid/index.ts | 1 + packages/solid/package.json | 10 + packages/svelte/index.ts | 1 + packages/svelte/package.json | 10 + packages/vue/vue3/index.ts | 1 + packages/vue/vue3/package.json | 10 + release-please-config.json | 15 ++ .../features/cobadged => server}/.env.example | 0 .../features/cobadged => server}/.gitignore | 0 server/astro.config.mts | 9 + server/package.json | 15 ++ .../cobadged => server}/public/favicon.svg | 0 .../cobadged => server}/src/api/const.ts | 1 + .../src/api/createClientSession.ts | 0 server/src/api/createPayment.ts | 89 +++++++ server/src/api/createPaymentMethodToken.ts | 30 +++ server/src/components/Input.astro | 21 ++ server/src/components/SecureInput.astro | 21 ++ server/src/env.d.ts | 9 + .../src/layouts/Layout.astro | 8 +- server/src/pages/api/card.ts | 37 +++ server/src/pages/index.astro | 137 ++++++++++ server/src/pages/secure/card.astro | 102 ++++++++ server/src/pages/secure/input.astro | 10 + server/src/pages/secure/payment.astro | 73 ++++++ server/src/pages/test/csc.astro | 16 ++ server/src/pages/test/exp.astro | 16 ++ server/src/pages/test/index.astro | 35 +++ server/src/pages/test/inline.astro | 44 ++++ server/src/pages/test/name.astro | 16 ++ server/src/pages/test/number.astro | 16 ++ .../cobadged => server}/src/utils/get.spec.ts | 0 .../cobadged => server}/src/utils/get.ts | 0 server/src/utils/parseAccessToken.ts | 6 + .../src/utils/post.spec.ts | 5 +- .../cobadged => server}/src/utils/post.ts | 0 .../cobadged => server}/tsconfig.json | 0 stories/.eslintrc.json | 3 + stories/.storybook/main.ts | 17 ++ stories/.storybook/preview.ts | 13 + stories/Introduction.mdx | 3 + stories/components/Button.stories.tsx | 15 ++ stories/components/SecureCard.stories.tsx | 11 + stories/components/SecureInput.stories.tsx | 22 ++ stories/package.json | 25 ++ stories/tsconfig.json | 7 + tsconfig.json | 1 + web/.eslintrc.json | 3 + web/mitosis.config.cjs | 36 +++ web/package.json | 16 ++ web/src/components/Button.lite.tsx | 19 ++ .../payment-methods/Paypal.lite.tsx | 16 ++ web/src/components/payment-methods/env.ts | 1 + web/src/components/secure/SecureCard.lite.tsx | 16 ++ .../components/secure/SecureInput.lite.tsx | 47 ++++ web/src/components/secure/env.ts | 1 + web/src/index.ts | 3 + web/src/utils/groupBy.spec.ts | 9 + web/src/utils/groupBy.ts | 22 ++ web/src/utils/mapValue.spec.ts | 9 + web/src/utils/mapValue.ts | 20 ++ web/src/utils/omit.spec.ts | 9 + web/src/utils/omit.ts | 15 ++ web/src/utils/toKebabCase.spec.ts | 33 +++ web/src/utils/toKebabCase.ts | 5 + web/src/utils/uid.spec.ts | 24 ++ web/src/utils/uid.ts | 6 + web/src/utils/words.spec.ts | 35 +++ web/src/utils/words.ts | 23 ++ web/tsconfig.json | 8 + 115 files changed, 1701 insertions(+), 360 deletions(-) create mode 100644 .github/workflows/release-pr.yml create mode 100644 .release-please-manifest.json rename {examples/features/cobadged/.vscode => .vscode}/extensions.json (100%) rename {examples/features/cobadged/.vscode => .vscode}/launch.json (100%) create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE delete mode 100644 examples/features/cobadged/astro.config.mjs delete mode 100644 examples/features/cobadged/package.json delete mode 100644 examples/features/cobadged/src/api/primer.ts delete mode 100644 examples/features/cobadged/src/env.d.ts delete mode 100644 examples/features/cobadged/src/pages/index.astro create mode 100644 examples/features/drop-in/README.md create mode 100644 examples/frameworks/astro/README.md create mode 100644 examples/frameworks/next/README.md create mode 100644 examples/frameworks/nuxt/README.md create mode 100644 examples/frameworks/qwik-city/README.md create mode 100644 examples/frameworks/solid-start/.gitignore create mode 100644 examples/frameworks/solid-start/README.md create mode 100644 examples/frameworks/solid-start/package.json create mode 100644 examples/frameworks/solid-start/public/favicon.ico create mode 100644 examples/frameworks/solid-start/src/entry-client.tsx create mode 100644 examples/frameworks/solid-start/src/entry-server.tsx create mode 100644 examples/frameworks/solid-start/src/root.tsx create mode 100644 examples/frameworks/solid-start/src/routes/index.css create mode 100644 examples/frameworks/solid-start/src/routes/index.tsx create mode 100644 examples/frameworks/solid-start/tsconfig.json create mode 100644 examples/frameworks/solid-start/vite.config.ts create mode 100644 examples/frameworks/svelte-kit/README.md create mode 100644 examples/servers/deno-hono/package.json create mode 100644 packages/preact/index.ts create mode 100644 packages/preact/package.json create mode 100644 packages/qwik/index.ts create mode 100644 packages/qwik/package.json create mode 100644 packages/react-native/index.ts create mode 100644 packages/react-native/package.json create mode 100644 packages/react/index.ts create mode 100644 packages/react/package.json create mode 100644 packages/solid/index.ts create mode 100644 packages/solid/package.json create mode 100644 packages/svelte/index.ts create mode 100644 packages/svelte/package.json create mode 100644 packages/vue/vue3/index.ts create mode 100644 packages/vue/vue3/package.json create mode 100644 release-please-config.json rename {examples/features/cobadged => server}/.env.example (100%) rename {examples/features/cobadged => server}/.gitignore (100%) create mode 100644 server/astro.config.mts create mode 100644 server/package.json rename {examples/features/cobadged => server}/public/favicon.svg (100%) rename {examples/features/cobadged => server}/src/api/const.ts (77%) rename {examples/features/cobadged => server}/src/api/createClientSession.ts (100%) create mode 100644 server/src/api/createPayment.ts create mode 100644 server/src/api/createPaymentMethodToken.ts create mode 100644 server/src/components/Input.astro create mode 100644 server/src/components/SecureInput.astro create mode 100644 server/src/env.d.ts rename {examples/features/cobadged => server}/src/layouts/Layout.astro (85%) create mode 100644 server/src/pages/api/card.ts create mode 100644 server/src/pages/index.astro create mode 100644 server/src/pages/secure/card.astro create mode 100644 server/src/pages/secure/input.astro create mode 100644 server/src/pages/secure/payment.astro create mode 100644 server/src/pages/test/csc.astro create mode 100644 server/src/pages/test/exp.astro create mode 100644 server/src/pages/test/index.astro create mode 100644 server/src/pages/test/inline.astro create mode 100644 server/src/pages/test/name.astro create mode 100644 server/src/pages/test/number.astro rename {examples/features/cobadged => server}/src/utils/get.spec.ts (100%) rename {examples/features/cobadged => server}/src/utils/get.ts (100%) create mode 100644 server/src/utils/parseAccessToken.ts rename {examples/features/cobadged => server}/src/utils/post.spec.ts (85%) rename {examples/features/cobadged => server}/src/utils/post.ts (100%) rename {examples/features/cobadged => server}/tsconfig.json (100%) create mode 100644 stories/.eslintrc.json create mode 100644 stories/.storybook/main.ts create mode 100644 stories/.storybook/preview.ts create mode 100644 stories/Introduction.mdx create mode 100644 stories/components/Button.stories.tsx create mode 100644 stories/components/SecureCard.stories.tsx create mode 100644 stories/components/SecureInput.stories.tsx create mode 100644 stories/package.json create mode 100644 stories/tsconfig.json create mode 100644 web/.eslintrc.json create mode 100644 web/mitosis.config.cjs create mode 100644 web/package.json create mode 100644 web/src/components/Button.lite.tsx create mode 100644 web/src/components/payment-methods/Paypal.lite.tsx create mode 100644 web/src/components/payment-methods/env.ts create mode 100644 web/src/components/secure/SecureCard.lite.tsx create mode 100644 web/src/components/secure/SecureInput.lite.tsx create mode 100644 web/src/components/secure/env.ts create mode 100644 web/src/index.ts create mode 100644 web/src/utils/groupBy.spec.ts create mode 100644 web/src/utils/groupBy.ts create mode 100644 web/src/utils/mapValue.spec.ts create mode 100644 web/src/utils/mapValue.ts create mode 100644 web/src/utils/omit.spec.ts create mode 100644 web/src/utils/omit.ts create mode 100644 web/src/utils/toKebabCase.spec.ts create mode 100644 web/src/utils/toKebabCase.ts create mode 100644 web/src/utils/uid.spec.ts create mode 100644 web/src/utils/uid.ts create mode 100644 web/src/utils/words.spec.ts create mode 100644 web/src/utils/words.ts create mode 100644 web/tsconfig.json diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml new file mode 100644 index 0000000..a7ce11b --- /dev/null +++ b/.github/workflows/release-pr.yml @@ -0,0 +1,42 @@ +name: release PR + +on: + push: + branches: + - main + +jobs: + create: + runs-on: ubuntu-latest + outputs: + pr: ${{ steps.release.outputs.pr }} + steps: + - id: release + uses: google-github-actions/release-please-action@v3 + with: + command: manifest + token: ${{ secrets.SECURITY_INTEGRATIONS_PAT }} + + format: + runs-on: ubuntu-latest + needs: release-pr + if: needs.release-pr.outputs.pr + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 2 + ref: '${{ fromJSON(needs.release-pr.outputs.pr).headBranchName }}' + token: ${{ secrets.SECURITY_INTEGRATIONS_PAT }} + + - uses: oven-sh/setup-bun@v1 + + - run: bun i --frozen-lockfile + + - run: bun run format + + - name: ammend release-please's commit + run: | + git config user.name '$GITHUB_ACTOR' + git config user.email '$GITHUB_ACTOR@users.noreply.github.com' + git commit -a --amend --no-edit + git push -f -u origin HEAD diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..c5409c7 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,9 @@ +{ + "packages/preact": "2.0.0", + "packages/qwik": "2.0.0", + "packages/react": "2.0.0", + "packages/react-native": "2.0.0", + "packages/solid": "2.0.0", + "packages/svelte": "2.0.0", + "packages/vue/vue3": "2.0.0" +} diff --git a/examples/features/cobadged/.vscode/extensions.json b/.vscode/extensions.json similarity index 100% rename from examples/features/cobadged/.vscode/extensions.json rename to .vscode/extensions.json diff --git a/examples/features/cobadged/.vscode/launch.json b/.vscode/launch.json similarity index 100% rename from examples/features/cobadged/.vscode/launch.json rename to .vscode/launch.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fd2db7f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# Contributing + +## Folder structure and workspaces + +- `examples`: examples for merchants to use as inspiration +- `packages`: components built with Mitosis +- `server`: Checkout server in Astro, PCI compliant +- `stories`: Storybook for developing/testing components, currently uses React +- `web`: components written in Mitosis + +## Dependencies + +1. Install [Bun](https://bun.sh) +2. Run `bun i` on a terminal + +That's it 😄 + +### Running locally + +```sh +bun start +``` + +Automatically starts `components`, `stories`, and `server`. +Opens `stories` and `server` on the browser. + +### Other scripts + +Look at `package.json#scripts` for a complete list. +Use with: + +```sh +bun run - - - - diff --git a/examples/features/drop-in/README.md b/examples/features/drop-in/README.md new file mode 100644 index 0000000..655064c --- /dev/null +++ b/examples/features/drop-in/README.md @@ -0,0 +1,3 @@ +# Drop-in + +## TODO diff --git a/examples/frameworks/astro/README.md b/examples/frameworks/astro/README.md new file mode 100644 index 0000000..1b1d429 --- /dev/null +++ b/examples/frameworks/astro/README.md @@ -0,0 +1,5 @@ +# Astro + +This example integrates Primer's [Preact](https://preactjs.com) components with [Astro](https://astro.build). + +## TODO diff --git a/examples/frameworks/next/README.md b/examples/frameworks/next/README.md new file mode 100644 index 0000000..4551b2a --- /dev/null +++ b/examples/frameworks/next/README.md @@ -0,0 +1,5 @@ +# Next + +This example integrates Primer's [React](https://react.dev) components with [Next](https://nextjs.org). + +## TODO diff --git a/examples/frameworks/nuxt/README.md b/examples/frameworks/nuxt/README.md new file mode 100644 index 0000000..c2ba1ed --- /dev/null +++ b/examples/frameworks/nuxt/README.md @@ -0,0 +1,5 @@ +# Nuxt + +This example integrates Primer's [Vue](https://vuejs.org) components with [Nuxt](https://nuxt.com). + +## TODO diff --git a/examples/frameworks/qwik-city/README.md b/examples/frameworks/qwik-city/README.md new file mode 100644 index 0000000..8ac3b47 --- /dev/null +++ b/examples/frameworks/qwik-city/README.md @@ -0,0 +1,5 @@ +# Qwik City + +This example integrates Primer's [Qwik](https://qwik.builder.io) components with [Qwik City](https://qwik.builder.io/docs/qwikcity). + +## TODO diff --git a/examples/frameworks/solid-start/.gitignore b/examples/frameworks/solid-start/.gitignore new file mode 100644 index 0000000..8f09412 --- /dev/null +++ b/examples/frameworks/solid-start/.gitignore @@ -0,0 +1,24 @@ + +dist +.solid +.output +.vercel +.netlify +netlify + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +*.launch +.settings/ + +# Temp +gitignore + +# System Files +.DS_Store +Thumbs.db diff --git a/examples/frameworks/solid-start/README.md b/examples/frameworks/solid-start/README.md new file mode 100644 index 0000000..62fd899 --- /dev/null +++ b/examples/frameworks/solid-start/README.md @@ -0,0 +1,3 @@ +# SolidStart + +This example integrates Primer's [Solid](https://www.solidjs.com) components with [SolidStart](https://start.solidjs.com). diff --git a/examples/frameworks/solid-start/package.json b/examples/frameworks/solid-start/package.json new file mode 100644 index 0000000..fd04b40 --- /dev/null +++ b/examples/frameworks/solid-start/package.json @@ -0,0 +1,22 @@ +{ + "name": "@primer-io/checkout-server-solid", + "private": true, + "type": "module", + "scripts": { + "start": "solid-start dev --open", + "build": "solid-start build", + "deploy": "solid-start start" + }, + "dependencies": { + "@solidjs/router": "^0.9.1", + "solid-styled-components": "^0.28.5", + "solid-js": "^1.8.5", + "solid-start": "^0.3.10" + }, + "devDependencies": { + "@solidjs/meta": "^0.29.1", + "solid-start-vercel": "^0.3.10", + "vercel": "^32.5.5", + "vite": "^5.0.0" + } +} diff --git a/examples/frameworks/solid-start/public/favicon.ico b/examples/frameworks/solid-start/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..fb282da0719ef6ab4c1732df93be6216b0d85520 GIT binary patch literal 664 zcmV;J0%!e+P)m9ebk1R zejT~~6f_`?;`cEd!+`7(hw@%%2;?RN8gX-L?z6cM( zKoG@&w+0}f@Pfvwc+deid)qgE!L$ENKYjViZC_Zcr>L(`2oXUT8f0mRQ(6-=HN_Ai zeBBEz3WP+1Cw`m!49Wf!MnZzp5bH8VkR~BcJ1s-j90TAS2Yo4j!J|KodxYR%3Numw zA?gq6e`5@!W~F$_De3yt&uspo&2yLb$(NwcPPI-4LGc!}HdY%jfq@AFs8LiZ4k(p} zZ!c9o+qbWYs-Mg zgdyTALzJX&7QXHdI_DPTFL33;w}88{e6Zk)MX0kN{3DX9uz#O_L58&XRH$Nvvu;fO zf&)7@?C~$z1K<>j0ga$$MIg+5xN;eQ?1-CA=`^Y169@Ab6!vcaNP=hxfKN%@Ly^R* zK1iv*s1Yl6_dVyz8>ZqYhz6J4|3fQ@2LQeX@^%W(B~8>=MoEmBEGGD1;gHXlpX>!W ym)!leA2L@`cpb^hy)P75=I!`pBYxP7<2VfQ3j76qLgzIA0000 , document); diff --git a/examples/frameworks/solid-start/src/entry-server.tsx b/examples/frameworks/solid-start/src/entry-server.tsx new file mode 100644 index 0000000..4ce3774 --- /dev/null +++ b/examples/frameworks/solid-start/src/entry-server.tsx @@ -0,0 +1,9 @@ +import { + createHandler, + renderAsync, + StartServer, +} from 'solid-start/entry-server'; + +export default createHandler( + renderAsync((event) => ), +); diff --git a/examples/frameworks/solid-start/src/root.tsx b/examples/frameworks/solid-start/src/root.tsx new file mode 100644 index 0000000..e1c9d01 --- /dev/null +++ b/examples/frameworks/solid-start/src/root.tsx @@ -0,0 +1,35 @@ +// @refresh reload +import { Routes } from '@solidjs/router'; +import { Suspense } from 'solid-js'; +import { + Body, + FileRoutes, + Head, + Html, + Meta, + Scripts, + Title, +} from 'solid-start'; +import { ErrorBoundary } from 'solid-start/error-boundary'; + +export default function Root() { + return ( + + + Solid @primer-io/checkout + + + + + + + + + + + + + + + ); +} diff --git a/examples/frameworks/solid-start/src/routes/index.css b/examples/frameworks/solid-start/src/routes/index.css new file mode 100644 index 0000000..be20073 --- /dev/null +++ b/examples/frameworks/solid-start/src/routes/index.css @@ -0,0 +1,49 @@ +html { + box-sizing: border-box; +} + +*, +*::after, +*::before { + box-sizing: inherit; +} + +body { + display: grid; + font-family: Gordita, Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + height: 100vh; + margin: 0; + width: 100vw; +} + +main { + display: grid; + place-items: center; +} + +form { + border: 2px solid black; + border-radius: 8px; + display: grid; + gap: 16px; + padding: 24px; + place-items: center; +} + +label { + display: grid; + gap: 4px; +} + +input { + border: 1px solid black; + border-radius: 4px; + height: 40px; + padding: 8px; +} + +iframe { + border: none; + height: 48px; +} diff --git a/examples/frameworks/solid-start/src/routes/index.tsx b/examples/frameworks/solid-start/src/routes/index.tsx new file mode 100644 index 0000000..a2eb298 --- /dev/null +++ b/examples/frameworks/solid-start/src/routes/index.tsx @@ -0,0 +1,63 @@ +import { SecureInput } from '@primer-io/checkout-solid'; +import './index.css'; + +export default function Home() { + return ( +
+
{ + ev.preventDefault(); + }} + > + + + + + +
+
+ ); +} diff --git a/examples/frameworks/solid-start/tsconfig.json b/examples/frameworks/solid-start/tsconfig.json new file mode 100644 index 0000000..4caf78e --- /dev/null +++ b/examples/frameworks/solid-start/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.json", + "include": ["."], + "compilerOptions": { + // "baseUrl": "./", + // "moduleResolution": "Node", + "jsx": "preserve", + "jsxImportSource": "solid-js", + + // "allowSyntheticDefaultImports": true, + // "esModuleInterop": true, + + "types": ["solid-start/env"] + } +} diff --git a/examples/frameworks/solid-start/vite.config.ts b/examples/frameworks/solid-start/vite.config.ts new file mode 100644 index 0000000..6a781bc --- /dev/null +++ b/examples/frameworks/solid-start/vite.config.ts @@ -0,0 +1,12 @@ +import vercel from 'solid-start-vercel'; +import solid from 'solid-start/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [ + solid({ + adapter: vercel({ edge: true }), + ssr: true, + }), + ], +}); diff --git a/examples/frameworks/svelte-kit/README.md b/examples/frameworks/svelte-kit/README.md new file mode 100644 index 0000000..4af43c8 --- /dev/null +++ b/examples/frameworks/svelte-kit/README.md @@ -0,0 +1,5 @@ +# SvelteKit + +This example integrates Primer's [Svelte](https://svelte.dev) components with [SvelteKit](https://kit.svelte.dev). + +## TODO diff --git a/examples/servers/bun-elysia/package.json b/examples/servers/bun-elysia/package.json index 41a1e2d..dc3858b 100644 --- a/examples/servers/bun-elysia/package.json +++ b/examples/servers/bun-elysia/package.json @@ -9,6 +9,6 @@ "start": "bun run --watch src/index.ts" }, "dependencies": { - "elysia": "^0.7.25" + "elysia": "^0.7.28" } } diff --git a/examples/servers/deno-hono/package.json b/examples/servers/deno-hono/package.json new file mode 100644 index 0000000..8ac6fef --- /dev/null +++ b/examples/servers/deno-hono/package.json @@ -0,0 +1,8 @@ +{ + "name": "@primer-io/example-server-deno-hono", + "type": "module", + "version": "1.0.0", + "private": true, + "author": "@primer-io", + "license": "MIT" +} diff --git a/examples/servers/deno-hono/src/api/createClientSession.ts b/examples/servers/deno-hono/src/api/createClientSession.ts index b27d232..45f81f8 100644 --- a/examples/servers/deno-hono/src/api/createClientSession.ts +++ b/examples/servers/deno-hono/src/api/createClientSession.ts @@ -1,5 +1,5 @@ -import { post } from '../utils/post.ts'; -import { primerApiUrl, primerHeaders } from './const.ts'; +import { post } from '../utils/post.js'; +import { primerApiUrl, primerHeaders } from './const.js'; export function createClientSession(info: Info) { return post( diff --git a/examples/servers/node-fastify/package.json b/examples/servers/node-fastify/package.json index b262c90..e0abec8 100644 --- a/examples/servers/node-fastify/package.json +++ b/examples/servers/node-fastify/package.json @@ -14,8 +14,7 @@ }, "dependencies": { "dotenv": "^16.3.1", - "fastify": "^4.24.3", - "node-fetch": "^3.3.2" + "fastify": "^4.24.3" }, "devDependencies": { "concurrently": "^8.2.2", diff --git a/examples/servers/node-fastify/src/utils/post.ts b/examples/servers/node-fastify/src/utils/post.ts index 624b6c2..388b6a9 100644 --- a/examples/servers/node-fastify/src/utils/post.ts +++ b/examples/servers/node-fastify/src/utils/post.ts @@ -1,5 +1,3 @@ -import fetch from 'node-fetch'; - export async function post( url: string, body: Record, diff --git a/package.json b/package.json index 5765369..cbfb4fc 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,26 @@ { "name": "@primer-io/checkout", + "version": "3.0.0", + "license": "MIT", "private": true, - "version": "2.x.x", "type": "module", "workspaces": [ - "examples/*/*" + "examples/*/*", + "packages/*", + "packages/vue/vue3", + "server", + "stories", + "web" ], "scripts": { + "start": "concurrently bun:start:*", + "start:server": "bun --cwd server start", + "start:storybook": "bun --cwd stories start", + "start:web": "bun --cwd web start", + "build": "concurrently bun:build:*", + "build:server": "bun --cwd server build", + "build:storybook": "bun --cwd stories build", + "build:web": "bun --cwd web build", "lint": "concurrently bun:lint:*", "lint:commit": "commitlint --from origin/main --to HEAD --verbose", "lint:es": "eslint . --ignore-path .gitignore --report-unused-disable-directives --max-warnings 0", @@ -20,11 +34,11 @@ "update": "bunx npm-check-updates --root -u -ws && bun i" }, "devDependencies": { - "@commitlint/config-conventional": "^18.4.0", + "@commitlint/config-conventional": "^18.4.2", "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", "@vitest/coverage-v8": "^0.34.6", - "commitlint": "^18.4.1", + "commitlint": "^18.4.2", "concurrently": "^8.2.2", "eslint": "^8.53.0", "prettier": "^3.1.0", diff --git a/packages/preact/index.ts b/packages/preact/index.ts new file mode 100644 index 0000000..8420b10 --- /dev/null +++ b/packages/preact/index.ts @@ -0,0 +1 @@ +export * from './src'; diff --git a/packages/preact/package.json b/packages/preact/package.json new file mode 100644 index 0000000..beb09e9 --- /dev/null +++ b/packages/preact/package.json @@ -0,0 +1,10 @@ +{ + "name": "@primer-io/checkout-preact", + "version": "1.0.0", + "license": "MIT", + "type": "module", + "sideEffects": false, + "description": "Primer components for Preact", + "repository": "git@github.com:primer-io/checkout-web.git", + "author": "@primer-io" +} diff --git a/packages/qwik/index.ts b/packages/qwik/index.ts new file mode 100644 index 0000000..8420b10 --- /dev/null +++ b/packages/qwik/index.ts @@ -0,0 +1 @@ +export * from './src'; diff --git a/packages/qwik/package.json b/packages/qwik/package.json new file mode 100644 index 0000000..16cf9e7 --- /dev/null +++ b/packages/qwik/package.json @@ -0,0 +1,10 @@ +{ + "name": "@primer-io/checkout-qwik", + "version": "3.0.0", + "license": "MIT", + "type": "module", + "sideEffects": false, + "description": "Primer components for Qwik", + "repository": "git@github.com:primer-io/checkout-web.git", + "author": "@primer-io" +} diff --git a/packages/react-native/index.ts b/packages/react-native/index.ts new file mode 100644 index 0000000..8420b10 --- /dev/null +++ b/packages/react-native/index.ts @@ -0,0 +1 @@ +export * from './src'; diff --git a/packages/react-native/package.json b/packages/react-native/package.json new file mode 100644 index 0000000..d11c125 --- /dev/null +++ b/packages/react-native/package.json @@ -0,0 +1,10 @@ +{ + "name": "@primer-io/checkout-react-native", + "version": "3.0.0", + "license": "MIT", + "type": "module", + "sideEffects": false, + "description": "Primer components for React Native", + "repository": "git@github.com:primer-io/checkout-web.git", + "author": "@primer-io" +} diff --git a/packages/react/index.ts b/packages/react/index.ts new file mode 100644 index 0000000..8420b10 --- /dev/null +++ b/packages/react/index.ts @@ -0,0 +1 @@ +export * from './src'; diff --git a/packages/react/package.json b/packages/react/package.json new file mode 100644 index 0000000..d8f0c4e --- /dev/null +++ b/packages/react/package.json @@ -0,0 +1,10 @@ +{ + "name": "@primer-io/checkout-react", + "version": "3.0.0", + "license": "MIT", + "type": "module", + "sideEffects": false, + "description": "Primer components for React", + "repository": "git@github.com:primer-io/checkout-web.git", + "author": "@primer-io" +} diff --git a/packages/solid/index.ts b/packages/solid/index.ts new file mode 100644 index 0000000..8420b10 --- /dev/null +++ b/packages/solid/index.ts @@ -0,0 +1 @@ +export * from './src'; diff --git a/packages/solid/package.json b/packages/solid/package.json new file mode 100644 index 0000000..14cc402 --- /dev/null +++ b/packages/solid/package.json @@ -0,0 +1,10 @@ +{ + "name": "@primer-io/checkout-solid", + "version": "3.0.0", + "license": "MIT", + "type": "module", + "sideEffects": false, + "description": "Primer components for Solid", + "repository": "git@github.com:primer-io/checkout-web.git", + "author": "@primer-io" +} diff --git a/packages/svelte/index.ts b/packages/svelte/index.ts new file mode 100644 index 0000000..8420b10 --- /dev/null +++ b/packages/svelte/index.ts @@ -0,0 +1 @@ +export * from './src'; diff --git a/packages/svelte/package.json b/packages/svelte/package.json new file mode 100644 index 0000000..f0a993c --- /dev/null +++ b/packages/svelte/package.json @@ -0,0 +1,10 @@ +{ + "name": "@primer-io/checkout-svelte", + "version": "3.0.0", + "license": "MIT", + "type": "module", + "sideEffects": false, + "description": "Primer components for Svelte", + "repository": "git@github.com:primer-io/checkout-web.git", + "author": "@primer-io" +} diff --git a/packages/vue/vue3/index.ts b/packages/vue/vue3/index.ts new file mode 100644 index 0000000..8420b10 --- /dev/null +++ b/packages/vue/vue3/index.ts @@ -0,0 +1 @@ +export * from './src'; diff --git a/packages/vue/vue3/package.json b/packages/vue/vue3/package.json new file mode 100644 index 0000000..cf71dcd --- /dev/null +++ b/packages/vue/vue3/package.json @@ -0,0 +1,10 @@ +{ + "name": "@primer-io/checkout-vue", + "version": "3.0.0", + "license": "MIT", + "type": "module", + "sideEffects": false, + "description": "Primer components for Vue", + "repository": "git@github.com:primer-io/checkout-web.git", + "author": "@primer-io" +} diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..12f2f67 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,15 @@ +{ + "packages": { + "packages/preact": {}, + "packages/qwik": {}, + "packages/react": {}, + "packages/react-native": {}, + "packages/solid": {}, + "packages/svelte": {}, + "packages/vue/vue3": {} + }, + "prerelease-type": "next", + "prerelease": true, + "release-type": "node", + "tag-separator": "@" +} diff --git a/examples/features/cobadged/.env.example b/server/.env.example similarity index 100% rename from examples/features/cobadged/.env.example rename to server/.env.example diff --git a/examples/features/cobadged/.gitignore b/server/.gitignore similarity index 100% rename from examples/features/cobadged/.gitignore rename to server/.gitignore diff --git a/server/astro.config.mts b/server/astro.config.mts new file mode 100644 index 0000000..010a712 --- /dev/null +++ b/server/astro.config.mts @@ -0,0 +1,9 @@ +import vercel from '@astrojs/vercel/serverless'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + adapter: vercel({ edgeMiddleware: true }), + output: 'server', + site: 'https://primer-checkout.vercel.app', +}); diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..d2ccbcb --- /dev/null +++ b/server/package.json @@ -0,0 +1,15 @@ +{ + "name": "@primer-io/checkout-secure-server", + "private": true, + "type": "module", + "version": "0.0.1", + "scripts": { + "start": "astro dev --open", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/vercel": "^5.2.0", + "astro": "^3.5.5" + } +} diff --git a/examples/features/cobadged/public/favicon.svg b/server/public/favicon.svg similarity index 100% rename from examples/features/cobadged/public/favicon.svg rename to server/public/favicon.svg diff --git a/examples/features/cobadged/src/api/const.ts b/server/src/api/const.ts similarity index 77% rename from examples/features/cobadged/src/api/const.ts rename to server/src/api/const.ts index 03dac47..8b35ac8 100644 --- a/examples/features/cobadged/src/api/const.ts +++ b/server/src/api/const.ts @@ -6,3 +6,4 @@ export const primerHeaders = { }; export const primerApiUrl = 'https://api.sandbox.primer.io'; +export const primerSdkApiUrl = 'https://sdk.api.sandbox.primer.io'; diff --git a/examples/features/cobadged/src/api/createClientSession.ts b/server/src/api/createClientSession.ts similarity index 100% rename from examples/features/cobadged/src/api/createClientSession.ts rename to server/src/api/createClientSession.ts diff --git a/server/src/api/createPayment.ts b/server/src/api/createPayment.ts new file mode 100644 index 0000000..e862acd --- /dev/null +++ b/server/src/api/createPayment.ts @@ -0,0 +1,89 @@ +import { post } from '../utils/post'; +import { primerHeaders, primerSdkApiUrl } from './const'; + +export function createPayment(accessToken: string, paymentMethodToken: string) { + return post( + `${primerSdkApiUrl}/payments`, + { paymentMethodToken }, + { + ...primerHeaders, + 'primer-client-token': accessToken, + }, + ); +} + +type Payment = { + amount: number; + currencyCode: string; + customerId: string; + date: string; + dateUpdated: string; + id: string; + order: Record; + paymentMethod: PaymentMethod; + processor: Processor; + orderId: string; + status: string; + statusReason: StatusReason; + transactions: Transaction[]; +}; + +type PaymentMethod = { + analyticsId: string; + authorizationType: string; + isVaulted: boolean; + isVerified: boolean; + paymentMethodData: { + binData: BinData[]; + cardholderName: string; + expirationMonth: string; + expirationYear: string; + first6Digits: string; + isNetworkTokenized: boolean; + last4Digits: string; + network: string; + }; + paymentMethodToken: string; + paymentMethodType: string; + threeDSecureAuthentication: { + responseCode: string; + }; +}; + +type BinData = { + accountFundingType: string; + accountNumberType: string; + issuerCountryCode: string; + network: string; + prepaidReloadableIndicator: string; + productCode: string; + productName: string; + productUsageType: string; + regionalRestriction: string; +}; + +type Processor = { + amountCaptured: number; + amountRefunded: number; + name: string; + processorMerchantId: string; +}; + +type StatusReason = { + code: string; + declineType: string; + message: string; + type: string; +}; + +type Transaction = { + amount: number; + currencyCode: string; + date: string; + processorMerchantId: string; + processorName: string; + processorStatus: string; + processorStatusReason: StatusReason[]; + processorTransactionId: string; + transactionType: string; +}; diff --git a/server/src/api/createPaymentMethodToken.ts b/server/src/api/createPaymentMethodToken.ts new file mode 100644 index 0000000..0200e13 --- /dev/null +++ b/server/src/api/createPaymentMethodToken.ts @@ -0,0 +1,30 @@ +import { post } from '../utils/post'; +import { primerHeaders, primerSdkApiUrl } from './const'; + +export async function createPaymentMethodToken( + accessToken: string, + cardInfo: CardInfo, +) { + const { token } = await post( + `${primerSdkApiUrl}/payment-instruments`, + { paymentInstrument: cardInfo }, + { + ...primerHeaders, + 'primer-client-token': accessToken, + }, + ); + + return token; +} + +type CardInfo = { + cardholderName: string; + cvv: string; + expirationMonth: string; + expirationYear: string; + number: string; +}; + +type PaymentInstrument = { + token: string; +}; diff --git a/server/src/components/Input.astro b/server/src/components/Input.astro new file mode 100644 index 0000000..187a99f --- /dev/null +++ b/server/src/components/Input.astro @@ -0,0 +1,21 @@ +--- +type Props = astroHTML.JSX.IntrinsicElements['input']; +--- + + + + diff --git a/server/src/components/SecureInput.astro b/server/src/components/SecureInput.astro new file mode 100644 index 0000000..62e1f07 --- /dev/null +++ b/server/src/components/SecureInput.astro @@ -0,0 +1,21 @@ +--- +import Input from './Input.astro'; +type Props = astroHTML.JSX.IntrinsicElements['input']; +--- + + + + diff --git a/server/src/env.d.ts b/server/src/env.d.ts new file mode 100644 index 0000000..fe5d63c --- /dev/null +++ b/server/src/env.d.ts @@ -0,0 +1,9 @@ +/// + +interface ImportMetaEnv { + readonly API_KEY: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/examples/features/cobadged/src/layouts/Layout.astro b/server/src/layouts/Layout.astro similarity index 85% rename from examples/features/cobadged/src/layouts/Layout.astro rename to server/src/layouts/Layout.astro index 8d3c48a..6e35fc1 100644 --- a/examples/features/cobadged/src/layouts/Layout.astro +++ b/server/src/layouts/Layout.astro @@ -6,11 +6,11 @@ interface Props { const { title } = Astro.props; --- - + - + @@ -40,8 +40,4 @@ const { title } = Astro.props; margin: 0; width: 100vw; } - - body > div { - display: none; - } diff --git a/server/src/pages/api/card.ts b/server/src/pages/api/card.ts new file mode 100644 index 0000000..eb72d98 --- /dev/null +++ b/server/src/pages/api/card.ts @@ -0,0 +1,37 @@ +import type { APIRoute } from 'astro'; +import { createClientSession } from '../../api/createClientSession'; +import { createPayment } from '../../api/createPayment'; +import { createPaymentMethodToken } from '../../api/createPaymentMethodToken'; +import { parseAccessToken } from '../../utils/parseAccessToken'; + +export const POST: APIRoute = async ({ request }) => { + const data = Object.fromEntries(await request.formData()) as Obj; + + if (!data) + return new Response( + JSON.stringify({ message: 'Missing required fields' }), + { status: 400 }, + ); + + const [expirationMonth, year] = data.expiryDate.trim().split('/'); + + const { clientToken } = await createClientSession({ + amount: 100, + currencyCode: 'GBP', + }); + const accessToken = parseAccessToken(clientToken); + + const paymentMethodToken = await createPaymentMethodToken(accessToken, { + cardholderName: data.name, + cvv: data.securityCode.trim(), + expirationMonth, + expirationYear: `${new Date().getFullYear().toString().slice(0, 2)}${year}`, + number: data.cardNumber.replaceAll(/\s/g, ''), + }); + + const response = await createPayment(accessToken, paymentMethodToken); + + return new Response(JSON.stringify(response, null, 2), { status: 200 }); +}; + +type Obj = Record; diff --git a/server/src/pages/index.astro b/server/src/pages/index.astro new file mode 100644 index 0000000..a8df2b4 --- /dev/null +++ b/server/src/pages/index.astro @@ -0,0 +1,137 @@ +--- +import Layout from '../layouts/Layout.astro'; + +const { url } = Astro; +const src = 'https://goat-assets.production.core.primer.io'; +--- + + +
+
+
+ + + PayPal + +
+ +
+
+ +
+ + + Pay with card + +
+ +
+
+
+
+
+ + + + diff --git a/server/src/pages/secure/card.astro b/server/src/pages/secure/card.astro new file mode 100644 index 0000000..d87678b --- /dev/null +++ b/server/src/pages/secure/card.astro @@ -0,0 +1,102 @@ +--- +import Input from '../../components/Input.astro'; +import Layout from '../../layouts/Layout.astro'; + +const autofill = Astro.url.searchParams.has('autofill') || undefined; +const autofocus = Astro.url.searchParams.has('autofocus') || undefined; +const api = Astro.url.searchParams.has('api') || undefined; +--- + + +
+
+ + + + + +
+
+
+ + diff --git a/server/src/pages/secure/input.astro b/server/src/pages/secure/input.astro new file mode 100644 index 0000000..0342994 --- /dev/null +++ b/server/src/pages/secure/input.astro @@ -0,0 +1,10 @@ +--- +import SecureInput from '../../components/SecureInput.astro'; +import Layout from '../../layouts/Layout.astro'; + +const searchParams = Object.fromEntries(Astro.url.searchParams); +--- + + + + diff --git a/server/src/pages/secure/payment.astro b/server/src/pages/secure/payment.astro new file mode 100644 index 0000000..884ffd4 --- /dev/null +++ b/server/src/pages/secure/payment.astro @@ -0,0 +1,73 @@ +--- +import { createClientSession } from '../../api/createClientSession'; +import { createPayment } from '../../api/createPayment'; +import { createPaymentMethodToken } from '../../api/createPaymentMethodToken'; +import Layout from '../../layouts/Layout.astro'; +import { parseAccessToken } from '../../utils/parseAccessToken'; + +const { request } = Astro; + +const data = Object.fromEntries(await request.formData()) as CreatePayment; + +type CreatePayment = { + cardNumber: string; + expiryDate: string; + name: string; + securityCode: string; +}; + +if (!data) throw new Error('Missing required fields'); + +const [expirationMonth, year] = data.expiryDate.trim().split('/'); + +const clientSession = createClientSession({ + amount: 100, + currencyCode: 'GBP', +}); +const paymentMethodToken = clientSession.then(async ({ clientToken }) => { + const accessToken = parseAccessToken(clientToken); + const paymentMethodToken = await createPaymentMethodToken(accessToken, { + cardholderName: data.name, + cvv: data.securityCode.trim(), + expirationMonth, + expirationYear: `${new Date().getFullYear().toString().slice(0, 2)}${year}`, + number: data.cardNumber.replaceAll(/\s/g, ''), + }); + return { accessToken, paymentMethodToken }; +}); +const payment = paymentMethodToken.then(({ accessToken, paymentMethodToken }) => + createPayment(accessToken, paymentMethodToken) +); +--- + + +
+

Creating payment...

+ {clientSession.then(() =>

Session updated...

)} + {paymentMethodToken.then(() =>

Payment method token created...

)} + { + payment.then((payment) => ( + <> +

Payment created:

+ {JSON.stringify(payment, null, 2)} + + )) + } +
+
+ + diff --git a/server/src/pages/test/csc.astro b/server/src/pages/test/csc.astro new file mode 100644 index 0000000..87f856e --- /dev/null +++ b/server/src/pages/test/csc.astro @@ -0,0 +1,16 @@ +--- +import Layout from '../../layouts/Layout.astro'; +--- + + + + + + diff --git a/server/src/pages/test/exp.astro b/server/src/pages/test/exp.astro new file mode 100644 index 0000000..ba650d6 --- /dev/null +++ b/server/src/pages/test/exp.astro @@ -0,0 +1,16 @@ +--- +import Layout from '../../layouts/Layout.astro'; +--- + + + + + + diff --git a/server/src/pages/test/index.astro b/server/src/pages/test/index.astro new file mode 100644 index 0000000..33c9d4f --- /dev/null +++ b/server/src/pages/test/index.astro @@ -0,0 +1,35 @@ +--- +import Layout from '../../layouts/Layout.astro'; + +const src = 'https://primer-checkout.vercel.app/test'; +--- + + +
+ +
+ + +
+ +
+
+ + diff --git a/server/src/pages/test/inline.astro b/server/src/pages/test/inline.astro new file mode 100644 index 0000000..e8fe2e1 --- /dev/null +++ b/server/src/pages/test/inline.astro @@ -0,0 +1,44 @@ +--- +import Layout from '../../layouts/Layout.astro'; +--- + + +
+ +
+ + +
+ +
+
+ + diff --git a/server/src/pages/test/name.astro b/server/src/pages/test/name.astro new file mode 100644 index 0000000..92ca679 --- /dev/null +++ b/server/src/pages/test/name.astro @@ -0,0 +1,16 @@ +--- +import Layout from '../../layouts/Layout.astro'; +--- + + + + + + diff --git a/server/src/pages/test/number.astro b/server/src/pages/test/number.astro new file mode 100644 index 0000000..3ef6d2c --- /dev/null +++ b/server/src/pages/test/number.astro @@ -0,0 +1,16 @@ +--- +import Layout from '../../layouts/Layout.astro'; +--- + + + + + + diff --git a/examples/features/cobadged/src/utils/get.spec.ts b/server/src/utils/get.spec.ts similarity index 100% rename from examples/features/cobadged/src/utils/get.spec.ts rename to server/src/utils/get.spec.ts diff --git a/examples/features/cobadged/src/utils/get.ts b/server/src/utils/get.ts similarity index 100% rename from examples/features/cobadged/src/utils/get.ts rename to server/src/utils/get.ts diff --git a/server/src/utils/parseAccessToken.ts b/server/src/utils/parseAccessToken.ts new file mode 100644 index 0000000..ee382bf --- /dev/null +++ b/server/src/utils/parseAccessToken.ts @@ -0,0 +1,6 @@ +export function parseAccessToken(clientToken: string) { + const [header, payload] = clientToken.split('.'); + const encoded = payload || header; + const { accessToken } = JSON.parse(atob(encoded)) as { accessToken: string }; + return accessToken; +} diff --git a/examples/features/cobadged/src/utils/post.spec.ts b/server/src/utils/post.spec.ts similarity index 85% rename from examples/features/cobadged/src/utils/post.spec.ts rename to server/src/utils/post.spec.ts index c6de182..fe2869a 100644 --- a/examples/features/cobadged/src/utils/post.spec.ts +++ b/server/src/utils/post.spec.ts @@ -4,8 +4,7 @@ import { post } from './post'; describe('post', () => { beforeEach(() => { vi.clearAllMocks(); - const response = { json: () => {} }; - vi.spyOn(globalThis, 'fetch').mockResolvedValue(response as any); + globalThis.fetch = vi.fn(() => ({ json: () => ({}) }) as any); }); it('should read JSON from the response', async () => { @@ -28,7 +27,7 @@ describe('post', () => { }); }); - it.only('should handle errors', async () => { + it('should handle errors', async () => { const error = { description: 'description' }; vi.mocked(fetch).mockResolvedValueOnce({ json: () => ({ error }) } as any); diff --git a/examples/features/cobadged/src/utils/post.ts b/server/src/utils/post.ts similarity index 100% rename from examples/features/cobadged/src/utils/post.ts rename to server/src/utils/post.ts diff --git a/examples/features/cobadged/tsconfig.json b/server/tsconfig.json similarity index 100% rename from examples/features/cobadged/tsconfig.json rename to server/tsconfig.json diff --git a/stories/.eslintrc.json b/stories/.eslintrc.json new file mode 100644 index 0000000..6eb5150 --- /dev/null +++ b/stories/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["../.eslintrc.json", "plugin:storybook/recommended"] +} diff --git a/stories/.storybook/main.ts b/stories/.storybook/main.ts new file mode 100644 index 0000000..2d22349 --- /dev/null +++ b/stories/.storybook/main.ts @@ -0,0 +1,17 @@ +import type { StorybookConfig } from '@storybook/react-vite'; + +export default { + stories: ['../**/*.mdx', '../**/*.stories.ts{,x}'], + addons: [ + '@storybook/addon-essentials', + '@storybook/addon-interactions', + '@storybook/addon-links', + ], + framework: { + name: '@storybook/react-vite', + options: {}, + }, + docs: { + autodocs: 'tag', + }, +} satisfies StorybookConfig; diff --git a/stories/.storybook/preview.ts b/stories/.storybook/preview.ts new file mode 100644 index 0000000..25da13f --- /dev/null +++ b/stories/.storybook/preview.ts @@ -0,0 +1,13 @@ +import type { Preview } from '@storybook/react'; + +export default { + parameters: { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, + }, +} satisfies Preview; diff --git a/stories/Introduction.mdx b/stories/Introduction.mdx new file mode 100644 index 0000000..e2f357d --- /dev/null +++ b/stories/Introduction.mdx @@ -0,0 +1,3 @@ +# Primer Checkout Web + +v3 diff --git a/stories/components/Button.stories.tsx b/stories/components/Button.stories.tsx new file mode 100644 index 0000000..3c64b3c --- /dev/null +++ b/stories/components/Button.stories.tsx @@ -0,0 +1,15 @@ +import { Button } from '@primer-io/checkout-react'; +import type { Meta, StoryObj } from '@storybook/react'; + +export default { + component: Button, + tags: ['autodocs'], +} satisfies Meta; + +type Story = StoryObj>; + +export const Basic: Story = { + args: { + children: 'Button', + }, +}; diff --git a/stories/components/SecureCard.stories.tsx b/stories/components/SecureCard.stories.tsx new file mode 100644 index 0000000..1ebfd0d --- /dev/null +++ b/stories/components/SecureCard.stories.tsx @@ -0,0 +1,11 @@ +import { SecureCard } from '@primer-io/checkout-react'; +import type { Meta, StoryObj } from '@storybook/react'; + +export default { + component: SecureCard, + tags: ['autodocs'], +} satisfies Meta; + +type Story = StoryObj>; + +export const Basic: Story = {}; diff --git a/stories/components/SecureInput.stories.tsx b/stories/components/SecureInput.stories.tsx new file mode 100644 index 0000000..3f2bf31 --- /dev/null +++ b/stories/components/SecureInput.stories.tsx @@ -0,0 +1,22 @@ +import { SecureInput } from '@primer-io/checkout-react'; +import type { Meta, StoryObj } from '@storybook/react'; + +export default { + component: SecureInput, + tags: ['autodocs'], + argTypes: { + onInput: { action: 'onInput' }, + }, +} satisfies Meta; + +type Story = StoryObj>; + +/** + * An input that cannot have its value inspected by any malicious attacker, + * unless they have direct access to the machine running the browser. + */ +export const Basic: Story = { + args: { + name: 'basic', + }, +}; diff --git a/stories/package.json b/stories/package.json new file mode 100644 index 0000000..a416072 --- /dev/null +++ b/stories/package.json @@ -0,0 +1,25 @@ +{ + "name": "@primer-io/checkout-stories", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "storybook dev -p 6006", + "build": "storybook build -o ../storybook-static" + }, + "devDependencies": { + "@storybook/addon-essentials": "^7.5.3", + "@storybook/addon-interactions": "^7.5.3", + "@storybook/addon-links": "^7.5.3", + "@storybook/blocks": "^7.5.3", + "@storybook/react": "^7.5.3", + "@storybook/react-vite": "^7.5.3", + "@storybook/testing-library": "^0.2.2", + "@types/react": "^18.2.37", + "@types/react-dom": "^18.2.15", + "eslint-plugin-storybook": "^0.6.15", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "storybook": "^7.5.3" + } +} diff --git a/stories/tsconfig.json b/stories/tsconfig.json new file mode 100644 index 0000000..e529ecf --- /dev/null +++ b/stories/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../tsconfig.json", + "include": ["."], + "compilerOptions": { + "jsx": "react-jsx" + } +} diff --git a/tsconfig.json b/tsconfig.json index 6f3c1bc..388804a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { + "include": ["web"], "compilerOptions": { "lib": ["ESNext", "DOM", "DOM.Iterable"], "module": "ESNext", diff --git a/web/.eslintrc.json b/web/.eslintrc.json new file mode 100644 index 0000000..13f4117 --- /dev/null +++ b/web/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["../.eslintrc.json", "plugin:@builder.io/mitosis/recommended"] +} diff --git a/web/mitosis.config.cjs b/web/mitosis.config.cjs new file mode 100644 index 0000000..d0b147b --- /dev/null +++ b/web/mitosis.config.cjs @@ -0,0 +1,36 @@ +/** @type {import('@builder.io/mitosis').MitosisConfig} */ +// eslint-disable-next-line no-undef +module.exports = { + dest: '../packages', + files: 'src/**', + exclude: ['**/*.spec.ts'], + + // commented targets do not support "context" + targets: [ + // 'angular', + // 'customElement', + // 'html', + // 'lit', + 'preact', + 'qwik', + 'react', + 'reactNative', + 'solid', + 'svelte', + 'vue3', + // 'webcomponent', + ], + + commonOptions: { + typescript: true, + }, + options: { + preact: { typescript: true }, + qwik: { typescript: true }, + react: { typescript: true }, + reactNative: { typescript: true }, + solid: { typescript: true }, + svelte: { typescript: true }, + vue3: { typescript: true }, + }, +}; diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..458b364 --- /dev/null +++ b/web/package.json @@ -0,0 +1,16 @@ +{ + "name": "@primer-io/checkout-web", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "watch 'bun run build' ./src", + "build": "mitosis build" + }, + "devDependencies": { + "@builder.io/eslint-plugin-mitosis": "^0.0.15", + "@builder.io/mitosis": "^0.0.134", + "@builder.io/mitosis-cli": "^0.0.93", + "watch": "^1.0.2" + } +} diff --git a/web/src/components/Button.lite.tsx b/web/src/components/Button.lite.tsx new file mode 100644 index 0000000..f0486fa --- /dev/null +++ b/web/src/components/Button.lite.tsx @@ -0,0 +1,19 @@ +import { useStyle } from '@builder.io/mitosis'; +import { JSX } from '@builder.io/mitosis/jsx-runtime'; + +type Props = JSX.IntrinsicElements['button']; + +export default function Button(props: Props) { + return + ); +} + +// eslint-disable-next-line @builder.io/mitosis/only-default-function-and-imports +useStyle(` + background-color: rgb(255 196 58); +`); diff --git a/web/src/components/payment-methods/env.ts b/web/src/components/payment-methods/env.ts new file mode 100644 index 0000000..88fe799 --- /dev/null +++ b/web/src/components/payment-methods/env.ts @@ -0,0 +1 @@ +export const assetsSource = 'https://goat-assets.production.core.primer.io'; diff --git a/web/src/components/secure/SecureCard.lite.tsx b/web/src/components/secure/SecureCard.lite.tsx new file mode 100644 index 0000000..3333ab0 --- /dev/null +++ b/web/src/components/secure/SecureCard.lite.tsx @@ -0,0 +1,16 @@ +import { useStyle } from '@builder.io/mitosis'; +import { JSX } from '@builder.io/mitosis/jsx-runtime'; +import { src } from './env'; + +type Props = Omit; + +export default function SecureCard(props: Props) { + return -
- - -
- - - - - diff --git a/server/src/pages/test/inline.astro b/server/src/pages/test/inline.astro deleted file mode 100644 index e8fe2e1..0000000 --- a/server/src/pages/test/inline.astro +++ /dev/null @@ -1,44 +0,0 @@ ---- -import Layout from '../../layouts/Layout.astro'; ---- - - -
- -
- - -
- -
-
- - diff --git a/server/src/pages/test/name.astro b/server/src/pages/test/name.astro deleted file mode 100644 index 92ca679..0000000 --- a/server/src/pages/test/name.astro +++ /dev/null @@ -1,16 +0,0 @@ ---- -import Layout from '../../layouts/Layout.astro'; ---- - - - - - - diff --git a/server/src/pages/test/number.astro b/server/src/pages/test/number.astro deleted file mode 100644 index 3ef6d2c..0000000 --- a/server/src/pages/test/number.astro +++ /dev/null @@ -1,16 +0,0 @@ ---- -import Layout from '../../layouts/Layout.astro'; ---- - - - - - - From c7850ac82fec663a369c56646a4aa4c5526ca374 Mon Sep 17 00:00:00 2001 From: Andre Rabello Date: Fri, 17 Nov 2023 10:37:31 +0000 Subject: [PATCH 6/9] feat: compose payment methods --- server/src/components/Payment/Klarna.astro | 20 +++ server/src/components/Payment/PayPal.astro | 20 +++ .../components/Payment/PaymentButton.astro | 26 ++++ .../components/Payment/PaymentMethod.astro | 72 +++++++++++ server/src/pages/index.astro | 117 ++++-------------- server/src/pages/secure/input.astro | 4 +- server/src/pages/secure/payment.astro | 4 +- 7 files changed, 169 insertions(+), 94 deletions(-) create mode 100644 server/src/components/Payment/Klarna.astro create mode 100644 server/src/components/Payment/PayPal.astro create mode 100644 server/src/components/Payment/PaymentButton.astro create mode 100644 server/src/components/Payment/PaymentMethod.astro diff --git a/server/src/components/Payment/Klarna.astro b/server/src/components/Payment/Klarna.astro new file mode 100644 index 0000000..013d85a --- /dev/null +++ b/server/src/components/Payment/Klarna.astro @@ -0,0 +1,20 @@ +--- +import PaymentButton from '../Payment/PaymentButton.astro'; +type Props = astroHTML.JSX.IntrinsicElements['button']; +--- + + + + diff --git a/server/src/components/Payment/PayPal.astro b/server/src/components/Payment/PayPal.astro new file mode 100644 index 0000000..7a8b381 --- /dev/null +++ b/server/src/components/Payment/PayPal.astro @@ -0,0 +1,20 @@ +--- +import PaymentButton from './PaymentButton.astro'; +type Props = astroHTML.JSX.IntrinsicElements['button']; +--- + + + + diff --git a/server/src/components/Payment/PaymentButton.astro b/server/src/components/Payment/PaymentButton.astro new file mode 100644 index 0000000..ee7a778 --- /dev/null +++ b/server/src/components/Payment/PaymentButton.astro @@ -0,0 +1,26 @@ +--- +type Props = astroHTML.JSX.IntrinsicElements['button']; +--- + + + + diff --git a/server/src/components/Payment/PaymentMethod.astro b/server/src/components/Payment/PaymentMethod.astro new file mode 100644 index 0000000..bca27b9 --- /dev/null +++ b/server/src/components/Payment/PaymentMethod.astro @@ -0,0 +1,72 @@ +--- +type Props = astroHTML.JSX.IntrinsicElements['details'] & { + label: string; + logo: string; +}; + +const { children, label, logo, ...props } = Astro.props; +--- + +
+ + + {label} + +
+ +
+
+ + diff --git a/server/src/pages/index.astro b/server/src/pages/index.astro index a8df2b4..fe69ce8 100644 --- a/server/src/pages/index.astro +++ b/server/src/pages/index.astro @@ -1,37 +1,38 @@ --- +import Klarna from '../components/Payment/Klarna.astro'; +import PayPal from '../components/Payment/PayPal.astro'; +import PaymentMethod from '../components/Payment/PaymentMethod.astro'; import Layout from '../layouts/Layout.astro'; const { url } = Astro; -const src = 'https://goat-assets.production.core.primer.io'; +const goatSrc = 'https://goat-assets.production.core.primer.io'; ---
-
- - - PayPal - -
- -
-
- -
- - - Pay with card - -
- -
-
+ + + + + + + + + + +
@@ -52,77 +53,11 @@ const src = 'https://goat-assets.production.core.primer.io'; min-width: 400px; } - details { - border: 1px solid #e0e0e0; - border-radius: 8px; - display: flex; - overflow: hidden; - place-content: center; - place-items: center; - } - - summary { - box-sizing: border-box; - cursor: pointer; - display: flex; - gap: 12px; - height: 48px; - padding: 16px; - place-items: center; - transition: background-color 0.15s; - - &:hover { - background-color: hsl(0 0% 90%); - } - - &:active { - background-color: hsl(0 0% 80%); - } - - &:before { - content: ''; - border: 1px solid #757575; - border-radius: 100vw; - padding: 4px; - height: 20px; - width: 20px; - - [open] > & { - background: radial-gradient(#212121 50%, transparent 55%); - } - } - } - - div { - box-sizing: border-box; - display: grid; - padding: 16px; - } - iframe { border: 0; height: 400px; width: 100%; } - - button { - background-color: hsl(42 100% 61%); - border: 0; - border-radius: 4px; - cursor: pointer; - font-size: 16px; - height: 48px; - padding: 16px; - transition: background-color 0.15s; - - &:hover { - background-color: hsl(42 100% 50%); - } - - &:active { - background-color: hsl(42 100% 40%); - } - }