From 346fdfaeb90cef12b7034920ce36f4c011594ddc Mon Sep 17 00:00:00 2001 From: Charles Zhao Date: Mon, 21 Oct 2024 19:52:17 +0800 Subject: [PATCH 1/3] feat: add sign up with password sample --- packages/sign-up-with-password/.eslintrc.cjs | 24 +++++++ packages/sign-up-with-password/favicon.ico | Bin 0 -> 15406 bytes packages/sign-up-with-password/index.html | 36 ++++++++++ packages/sign-up-with-password/package.json | 32 +++++++++ .../src/include.d/vite-env.d.ts | 1 + packages/sign-up-with-password/src/index.ts | 67 ++++++++++++++++++ packages/sign-up-with-password/tsconfig.json | 11 +++ pnpm-lock.yaml | 33 +++++++++ 8 files changed, 204 insertions(+) create mode 100644 packages/sign-up-with-password/.eslintrc.cjs create mode 100644 packages/sign-up-with-password/favicon.ico create mode 100644 packages/sign-up-with-password/index.html create mode 100644 packages/sign-up-with-password/package.json create mode 100644 packages/sign-up-with-password/src/include.d/vite-env.d.ts create mode 100644 packages/sign-up-with-password/src/index.ts create mode 100644 packages/sign-up-with-password/tsconfig.json diff --git a/packages/sign-up-with-password/.eslintrc.cjs b/packages/sign-up-with-password/.eslintrc.cjs new file mode 100644 index 0000000..0b1a0e0 --- /dev/null +++ b/packages/sign-up-with-password/.eslintrc.cjs @@ -0,0 +1,24 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + extends: '@silverhand/eslint-config', + rules: { + 'jsx-a11y/no-autofocus': 'off', + 'unicorn/prefer-string-replace-all': 'off', + 'no-restricted-syntax': 'off', + '@silverhand/fp/no-mutation': 'off', + }, + overrides: [ + { + files: ['*.config.js', '*.config.ts', '*.d.ts'], + rules: { + 'import/no-unused-modules': 'off', + }, + }, + { + files: ['*.d.ts'], + rules: { + 'import/no-unassigned-import': 'off', + }, + }, + ], +}; diff --git a/packages/sign-up-with-password/favicon.ico b/packages/sign-up-with-password/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3cf672d954d2e7a259eefa9d3fecc5a65eebd7e7 GIT binary patch literal 15406 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 W_BYinf7Sh&?|Z-hfA0UD2mS}C&gzo@ literal 0 HcmV?d00001 diff --git a/packages/sign-up-with-password/index.html b/packages/sign-up-with-password/index.html new file mode 100644 index 0000000..5342181 --- /dev/null +++ b/packages/sign-up-with-password/index.html @@ -0,0 +1,36 @@ + + + + + + Logto experience sample + + + + + + +
+
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ +
+ + diff --git a/packages/sign-up-with-password/package.json b/packages/sign-up-with-password/package.json new file mode 100644 index 0000000..9a70ca9 --- /dev/null +++ b/packages/sign-up-with-password/package.json @@ -0,0 +1,32 @@ +{ + "name": "@logto/experience-sample-password-sign-up", + "description": "A sample project demonstrates how to use Logto Experience API to build a identifier & password sign-up page.", + "author": "Silverhand Inc. ", + "license": "MIT", + "version": "0.0.0", + "type": "module", + "scripts": { + "precommit": "lint-staged", + "start": "vite", + "dev": "logto-tunnel --verbose & vite", + "build": "tsc -b && vite build", + "lint": "eslint --ext .ts src", + "preview": "vite preview" + }, + "devDependencies": { + "@logto/experience-sample-shared": "workspace:^", + "@logto/schemas": "^1.19.0", + "@silverhand/eslint-config": "^6.0.1", + "@silverhand/ts-config": "^6.0.0", + "eslint": "^8.56.0", + "lint-staged": "^15.0.0", + "prettier": "^3.0.0", + "stylelint": "^15.0.0", + "typescript": "^5.5.3", + "vite": "^5.4.0" + }, + "stylelint": { + "extends": "@silverhand/eslint-config/.stylelintrc" + }, + "prettier": "@silverhand/eslint-config/.prettierrc" +} diff --git a/packages/sign-up-with-password/src/include.d/vite-env.d.ts b/packages/sign-up-with-password/src/include.d/vite-env.d.ts new file mode 100644 index 0000000..e058f21 --- /dev/null +++ b/packages/sign-up-with-password/src/include.d/vite-env.d.ts @@ -0,0 +1 @@ +import 'vite/client'; diff --git a/packages/sign-up-with-password/src/index.ts b/packages/sign-up-with-password/src/index.ts new file mode 100644 index 0000000..a69235d --- /dev/null +++ b/packages/sign-up-with-password/src/index.ts @@ -0,0 +1,67 @@ +import { Api } from '@logto/experience-sample-shared/api'; +import logo from '@logto/experience-sample-shared/assets/logto-logo-light.svg'; +import { InteractionEvent } from '@logto/schemas'; + +import '@logto/experience-sample-shared/scss/normalized.scss'; + +const api = new Api({ baseUrl: window.location.origin }); + +window.addEventListener('load', () => { + document.querySelector('.logo')?.setAttribute('src', logo); + const form = document.querySelector('form'); + const submitButton = document.querySelector('.submit-button'); + const errorContainer = document.querySelector('.error-message'); + + form?.addEventListener('submit', async (event) => { + event.preventDefault(); + errorContainer?.classList.remove('hidden'); + const formData = new FormData(event.currentTarget as HTMLFormElement); + const username = formData.get('username')?.toString(); + const password = formData.get('password')?.toString(); + const confirmPassword = formData.get('confirm-password')?.toString(); + + try { + submitButton?.setAttribute('disabled', 'disabled'); + submitButton?.classList.add('loading'); + + if (!username || !password) { + throw new Error('Username and password are required.'); + } + + if (password !== confirmPassword) { + throw new Error('Passwords do not match.'); + } + + await api.experience.initInteraction( + { interactionEvent: InteractionEvent.Register }, + { format: 'json' } + ); + + // Ensure the username is not already taken. + // You can also use `type: 'email'` or `type: 'phone'`, if that's your sign-up identifier. + await api.experience.addUserProfile({ type: 'username', value: username }); + + // Continue registering with password. + await api.experience.addUserProfile({ type: 'password', value: password }); + + // Unlink registering with verification code or social, register with identifier and password does not + // require a verification step in prior, but the identification step is still required. + await api.experience.identifyUser({}); + + const { redirectTo } = await api.experience.submitInteraction({ format: 'json' }); + window.location.replace(redirectTo); + } catch (error) { + console.error(error); + if (errorContainer) { + errorContainer.classList.remove('hidden'); + errorContainer.innerHTML = + error instanceof Error + ? error.message + : 'Error occurred. Please check debugger console for details.'; + } + + submitButton?.removeAttribute('disabled'); + submitButton?.classList.remove('loading'); + } + }); +}); diff --git a/packages/sign-up-with-password/tsconfig.json b/packages/sign-up-with-password/tsconfig.json new file mode 100644 index 0000000..b962e88 --- /dev/null +++ b/packages/sign-up-with-password/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@silverhand/ts-config/tsconfig.base", + "compilerOptions": { + "baseUrl": "./", + "outDir": "dist", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 062851c..1096ba5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -84,6 +84,39 @@ importers: specifier: ^5.4.6 version: 5.4.6(@types/node@22.3.0)(sass-embedded@1.77.8) + packages/sign-up-with-password: + devDependencies: + '@logto/experience-sample-shared': + specifier: workspace:^ + version: link:../shared + '@logto/schemas': + specifier: ^1.19.0 + version: 1.19.0(zod@3.23.8) + '@silverhand/eslint-config': + specifier: ^6.0.1 + version: 6.0.1(eslint@8.57.0)(prettier@3.3.3)(typescript@5.5.4) + '@silverhand/ts-config': + specifier: ^6.0.0 + version: 6.0.0(typescript@5.5.4) + eslint: + specifier: ^8.56.0 + version: 8.57.0 + lint-staged: + specifier: ^15.0.0 + version: 15.2.9 + prettier: + specifier: ^3.0.0 + version: 3.3.3 + stylelint: + specifier: ^15.0.0 + version: 15.11.0(typescript@5.5.4) + typescript: + specifier: ^5.5.3 + version: 5.5.4 + vite: + specifier: ^5.4.0 + version: 5.4.0(@types/node@22.3.0)(sass-embedded@1.77.8) + packages: '@babel/code-frame@7.24.7': From 312736d1d055cf168df79222f07f4b0ed9faa32b Mon Sep 17 00:00:00 2001 From: Charles Zhao Date: Tue, 22 Oct 2024 10:42:06 +0800 Subject: [PATCH 2/3] fix: pnpm lockfile --- pnpm-lock.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1096ba5..2d11e42 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,7 +115,7 @@ importers: version: 5.5.4 vite: specifier: ^5.4.0 - version: 5.4.0(@types/node@22.3.0)(sass-embedded@1.77.8) + version: 5.4.6(@types/node@22.3.0)(sass-embedded@1.77.8) packages: @@ -3273,10 +3273,10 @@ snapshots: eslint-config-prettier: 9.1.0(eslint@8.57.0) eslint-config-xo: 0.44.0(eslint@8.57.0) eslint-config-xo-typescript: 4.0.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-consistent-default-export-name: 0.0.15 eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-n: 17.10.2(eslint@8.57.0) eslint-plugin-no-use-extend-native: 0.5.0 eslint-plugin-prettier: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.3) @@ -3963,13 +3963,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.6 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.6 is-core-module: 2.15.0 @@ -3980,14 +3980,14 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -4009,7 +4009,7 @@ snapshots: eslint: 8.57.0 ignore: 5.3.2 - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -4019,7 +4019,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.0 is-glob: 4.0.3 From 30828aa32b5582688a0338895867da19fa82f616 Mon Sep 17 00:00:00 2001 From: Charles Zhao Date: Wed, 23 Oct 2024 19:30:24 +0800 Subject: [PATCH 3/3] refactor: improve code --- packages/sign-up-with-password/index.html | 2 +- packages/sign-up-with-password/src/index.ts | 61 ++++++++++----------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/packages/sign-up-with-password/index.html b/packages/sign-up-with-password/index.html index 5342181..a7c7efd 100644 --- a/packages/sign-up-with-password/index.html +++ b/packages/sign-up-with-password/index.html @@ -12,7 +12,7 @@
- +
diff --git a/packages/sign-up-with-password/src/index.ts b/packages/sign-up-with-password/src/index.ts index a69235d..4424a45 100644 --- a/packages/sign-up-with-password/src/index.ts +++ b/packages/sign-up-with-password/src/index.ts @@ -1,5 +1,5 @@ import { Api } from '@logto/experience-sample-shared/api'; -import logo from '@logto/experience-sample-shared/assets/logto-logo-light.svg'; +import { clearError, handleError, setSubmitLoading } from '@logto/experience-sample-shared/utils'; import { InteractionEvent } from '@logto/schemas'; import '@logto/experience-sample-shared/scss/normalized.scss'; @@ -7,22 +7,18 @@ import '@logto/experience-sample-shared/scss/normalized.scss'; const api = new Api({ baseUrl: window.location.origin }); window.addEventListener('load', () => { - document.querySelector('.logo')?.setAttribute('src', logo); const form = document.querySelector('form'); - const submitButton = document.querySelector('.submit-button'); - const errorContainer = document.querySelector('.error-message'); form?.addEventListener('submit', async (event) => { event.preventDefault(); - errorContainer?.classList.remove('hidden'); - const formData = new FormData(event.currentTarget as HTMLFormElement); - const username = formData.get('username')?.toString(); - const password = formData.get('password')?.toString(); - const confirmPassword = formData.get('confirm-password')?.toString(); + setSubmitLoading(true); + clearError(); try { - submitButton?.setAttribute('disabled', 'disabled'); - submitButton?.classList.add('loading'); + const formData = new FormData(form); + const username = formData.get('username')?.toString(); + const password = formData.get('password')?.toString(); + const confirmPassword = formData.get('confirm-password')?.toString(); if (!username || !password) { throw new Error('Username and password are required.'); @@ -32,36 +28,37 @@ window.addEventListener('load', () => { throw new Error('Passwords do not match.'); } - await api.experience.initInteraction( - { interactionEvent: InteractionEvent.Register }, - { format: 'json' } - ); + /** + * Step 1: Initialize a register type interaction. + */ + await api.experience.initInteraction({ interactionEvent: InteractionEvent.Register }); - // Ensure the username is not already taken. - // You can also use `type: 'email'` or `type: 'phone'`, if that's your sign-up identifier. + /** + * Step 2: Ensure the username is not already taken. + */ await api.experience.addUserProfile({ type: 'username', value: username }); - // Continue registering with password. + /** + * Step 3: Continue registering with password. + */ await api.experience.addUserProfile({ type: 'password', value: password }); - // Unlink registering with verification code or social, register with identifier and password does not - // require a verification step in prior, but the identification step is still required. + /** + * Step 4: Identify the user. + * + * Note: Unlike registering with verification code or social, register with identifier and password + * does not require a verification step in prior, but the identification step is still required. + */ await api.experience.identifyUser({}); - const { redirectTo } = await api.experience.submitInteraction({ format: 'json' }); + /** + * Step 5: Submit the interaction and redirect back to your app after the interaction is completed. + */ + const { redirectTo } = await api.experience.submitInteraction(); window.location.replace(redirectTo); } catch (error) { - console.error(error); - if (errorContainer) { - errorContainer.classList.remove('hidden'); - errorContainer.innerHTML = - error instanceof Error - ? error.message - : 'Error occurred. Please check debugger console for details.'; - } - - submitButton?.removeAttribute('disabled'); - submitButton?.classList.remove('loading'); + handleError(error); + setSubmitLoading(false); } }); });