From 4ea256c78865b7ff5daeecb9998fc609b2124785 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 22 Jan 2024 11:01:44 +0100 Subject: [PATCH 1/2] Email & Google auth fixes. Example app update. --- .../src/auth/pages/OAuthCodeExchange.jsx | 6 +- .../forms/internal/social/SocialButton.tsx | 2 +- .../data/Generator/templates/sdk/package.json | 20 +++- .../server/src/auth/providers/email/utils.ts | 2 +- .../src/auth/providers/oauth/createRouter.ts | 4 +- .../.wasp/out/sdk/wasp/auth/forms/Auth.tsx | 9 ++ .../forms/internal/common/LoginSignupForm.tsx | 105 ++++++++++++++++-- .../useUsernameAndPassword.ts | 29 ----- .../.wasp/out/sdk/wasp/auth/forms/types.ts | 3 + .../.wasp/out/sdk/wasp/auth/login.ts | 13 --- .../.wasp/out/sdk/wasp/auth/signup.ts | 9 -- .../.wasp/out/sdk/wasp/package.json | 6 + waspc/examples/todo-typescript/main.wasp | 43 ++++++- .../20240122093642_new_auth/migration.sql | 17 +++ .../examples/todo-typescript/src/MainPage.tsx | 62 +++++------ .../todo-typescript/src/user/LoginPage.tsx | 17 --- .../todo-typescript/src/user/SignupPage.tsx | 17 --- .../todo-typescript/src/user/auth.tsx | 59 ++++++++++ .../src/user/userSignupFields.ts | 13 +++ 19 files changed, 296 insertions(+), 140 deletions(-) delete mode 100644 waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/usernameAndPassword/useUsernameAndPassword.ts delete mode 100644 waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/login.ts delete mode 100644 waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/signup.ts create mode 100644 waspc/examples/todo-typescript/migrations/20240122093642_new_auth/migration.sql delete mode 100644 waspc/examples/todo-typescript/src/user/LoginPage.tsx delete mode 100644 waspc/examples/todo-typescript/src/user/SignupPage.tsx create mode 100644 waspc/examples/todo-typescript/src/user/auth.tsx create mode 100644 waspc/examples/todo-typescript/src/user/userSignupFields.ts diff --git a/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCodeExchange.jsx b/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCodeExchange.jsx index 10b3ed4d44..295cf5fa71 100644 --- a/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCodeExchange.jsx +++ b/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCodeExchange.jsx @@ -2,9 +2,9 @@ import React, { useEffect, useRef } from 'react' import { useHistory } from 'react-router-dom' -import config from '../../config.js' -import api from '../../api' -import { initSession } from '../helpers/user' +import config from 'wasp/core/config' +import api from 'wasp/api' +import { initSession } from 'wasp/auth/helpers/user' // After a user authenticates via an Oauth 2.0 provider, this is the page that // the provider should redirect them to, while providing query string parameters diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialButton.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialButton.tsx index afad545491..47044884bc 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialButton.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialButton.tsx @@ -1,4 +1,4 @@ -import { styled } from 'wasp/stitches.config' +import { styled } from 'wasp/core/stitches.config' export const SocialButton = styled('a', { display: 'flex', diff --git a/waspc/data/Generator/templates/sdk/package.json b/waspc/data/Generator/templates/sdk/package.json index 49a618afd0..7d28a8469c 100644 --- a/waspc/data/Generator/templates/sdk/package.json +++ b/waspc/data/Generator/templates/sdk/package.json @@ -42,18 +42,30 @@ {=! Used by our code, uncodumented (but accessible) for users. =} "./auth/user": "./dist/auth/user.js", {=! Used by our code, uncodumented (but accessible) for users. =} + "./auth/helpers/user": "./dist/auth/helpers/user.js", + {=! Used by our code, uncodumented (but accessible) for users. =} "./auth/session": "./dist/auth/session.js", - {=! Not sure who uses this, ask Miho. Our code definitely does, I don't know about the users =} + {=! Used by user, documented. =} + "./auth/providers/types": "./dist/auth/providers/types.js", + {=! Used by user, documented. =} "./auth/utils": "./dist/auth/utils.js", - {=! Not sure who uses this, ask Miho. Our code definitely does, I don't know about the users =} + {=! Used by our code, uncodumented (but accessible) for users. =} "./auth/password": "./dist/auth/password.js", - {=! Not sure who uses this, ask Miho. Our code definitely does, I don't know about the users =} + {=! Used by our code, uncodumented (but accessible) for users. =} + "./auth/jwt": "./dist/auth/jwt.js", + {=! Used by user, documented. =} "./auth/validation": "./dist/auth/validation.js", {=! Used by users, documented. =} "./auth/forms/Login": "./dist/auth/forms/Login.jsx", {=! Used by users, documented. =} "./auth/forms/Signup": "./dist/auth/forms/Signup.jsx", - {=! Not sure who uses this, ask Miho. Our code definitely does, I don't know about the users =} + {=! Used by users, documented. =} + "./auth/forms/VerifyEmail": "./dist/auth/forms/VerifyEmail.jsx", + {=! Used by users, documented. =} + "./auth/forms/ForgotPassword": "./dist/auth/forms/ForgotPassword.jsx", + {=! Used by users, documented. =} + "./auth/forms/ResetPassword": "./dist/auth/forms/ResetPassword.jsx", + {=! Used by our code, uncodumented (but accessible) for users. =} "./auth/pages/createAuthRequiredPage": "./dist/auth/pages/createAuthRequiredPage.jsx", {=! Used by users, documented. =} "./api": "./dist/api/index.js", diff --git a/waspc/data/Generator/templates/server/src/auth/providers/email/utils.ts b/waspc/data/Generator/templates/server/src/auth/providers/email/utils.ts index 45da35b01a..420b0974d4 100644 --- a/waspc/data/Generator/templates/server/src/auth/providers/email/utils.ts +++ b/waspc/data/Generator/templates/server/src/auth/providers/email/utils.ts @@ -8,7 +8,7 @@ import { findAuthIdentity, deserializeAndSanitizeProviderData, type EmailProviderData, -} from 'wasp/server/utils'; +} from 'wasp/auth/utils'; import waspServerConfig from 'wasp/server/config'; import { type {= userEntityUpper =}, type {= authEntityUpper =} } from 'wasp/entities' diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/createRouter.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/createRouter.ts index 10564f1ce3..a8032b717d 100644 --- a/waspc/data/Generator/templates/server/src/auth/providers/oauth/createRouter.ts +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/createRouter.ts @@ -17,9 +17,9 @@ import { validateAndGetUserFields, } from 'wasp/auth/utils' import { createSession } from "wasp/auth/session" -import { type {= authEntityUpper =} } from "wasp/auth/entities" +import { type {= authEntityUpper =} } from "wasp/entities" import type { ProviderConfig, RequestWithWasp, UserSignupFields } from "wasp/auth/providers/types" -import { handleRejection } from "wasp/auth/utils" +import { handleRejection } from "wasp/server/utils" // For oauth providers, we have an endpoint /login to get the auth URL, // and the /callback endpoint which is used to get the actual access_token and the user info. diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/Auth.tsx b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/Auth.tsx index 92c58131f6..2adcc43f03 100644 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/Auth.tsx +++ b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/Auth.tsx @@ -10,6 +10,9 @@ import { } from './types' import { LoginSignupForm } from './internal/common/LoginSignupForm' import { MessageError, MessageSuccess } from './internal/Message' +import { ForgotPasswordForm } from './internal/email/ForgotPasswordForm' +import { ResetPasswordForm } from './internal/email/ResetPasswordForm' +import { VerifyEmailForm } from './internal/email/VerifyEmailForm' const logoStyle = { height: '3rem' @@ -51,6 +54,9 @@ function Auth ({ state, appearance, logo, socialLayout = 'horizontal', additiona const titles: Record = { login: 'Log in to your account', signup: 'Create a new account', + "forgot-password": "Forgot your password?", + "reset-password": "Reset your password", + "verify-email": "Email verification", } const title = titles[state] @@ -77,6 +83,9 @@ function Auth ({ state, appearance, logo, socialLayout = 'horizontal', additiona additionalSignupFields={additionalSignupFields} /> )} + {state === 'forgot-password' && ()} + {state === 'reset-password' && ()} + {state === 'verify-email' && ()} ) diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx index 30665b4759..194c3bd9c2 100644 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx +++ b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx @@ -19,9 +19,79 @@ import type { AdditionalSignupFieldRenderFn, FormState, } from '../../types' +import * as SocialIcons from '../social/SocialIcons' +import { SocialButton } from '../social/SocialButton' import { useHistory } from 'react-router-dom' -import { useUsernameAndPassword } from '../usernameAndPassword/useUsernameAndPassword' +import { useEmail } from '../email/useEmail' +const OrContinueWith = styled('div', { + position: 'relative', + marginTop: '1.5rem' +}) + +const OrContinueWithLineContainer = styled('div', { + position: 'absolute', + inset: '0px', + display: 'flex', + alignItems: 'center' +}) + +const OrContinueWithLine = styled('div', { + width: '100%', + borderTopWidth: '1px', + borderColor: '$gray500' +}) + +const OrContinueWithTextContainer = styled('div', { + position: 'relative', + display: 'flex', + justifyContent: 'center', + fontSize: '$sm' +}) + +const OrContinueWithText = styled('span', { + backgroundColor: 'white', + paddingLeft: '0.5rem', + paddingRight: '0.5rem' +}) +const SocialAuth = styled('div', { + marginTop: '1.5rem' +}) + +const SocialAuthLabel = styled('div', { + fontWeight: '500', + fontSize: '$sm' +}) + +const SocialAuthButtons = styled('div', { + marginTop: '0.5rem', + display: 'flex', + + variants: { + direction: { + horizontal: { + display: 'grid', + gridTemplateColumns: 'repeat(auto-fit, minmax(48px, 1fr))', + }, + vertical: { + flexDirection: 'column', + margin: '8px 0', + } + }, + gap: { + small: { + gap: '4px', + }, + medium: { + gap: '8px', + }, + large: { + gap: '16px', + } + } + } +}) +const googleSignInUrl = `${config.apiUrl}/auth/google/login` export type LoginSignupFormFields = { [key: string]: string; @@ -50,10 +120,14 @@ export const LoginSignupForm = ({ }; const hookForm = useForm() const { register, formState: { errors }, handleSubmit: hookFormHandleSubmit } = hookForm - const { handleSubmit } = useUsernameAndPassword({ + const { handleSubmit } = useEmail({ isLogin, onError: onErrorHandler, - onSuccess() { + showEmailVerificationPending() { + hookForm.reset() + setSuccessMessage(`You've signed up successfully! Check your email for the confirmation link.`) + }, + onLoginSuccess() { history.push('/') }, }); @@ -69,17 +143,32 @@ export const LoginSignupForm = ({ } return (<> + + {cta} with + + + + + + + + + + + Or continue with + +
- Username + E-mail - {errors.username && {errors.username.message}} + {errors.email && {errors.email.message}} Password diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/usernameAndPassword/useUsernameAndPassword.ts b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/usernameAndPassword/useUsernameAndPassword.ts deleted file mode 100644 index 247c1faeb4..0000000000 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/usernameAndPassword/useUsernameAndPassword.ts +++ /dev/null @@ -1,29 +0,0 @@ -import signup from '../../../signup' -import login from '../../../login' - -export function useUsernameAndPassword({ - onError, - onSuccess, - isLogin, -}: { - onError: (error: Error) => void - onSuccess: () => void - isLogin: boolean -}) { - async function handleSubmit(data) { - try { - if (!isLogin) { - await signup(data) - } - await login(data.username, data.password) - - onSuccess() - } catch (err: unknown) { - onError(err as Error) - } - } - - return { - handleSubmit, - } -} diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/types.ts b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/types.ts index 14d61ad51e..b0e3340a90 100644 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/types.ts +++ b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/types.ts @@ -5,6 +5,9 @@ import type { LoginSignupFormFields } from './internal/common/LoginSignupForm' export enum State { Login = 'login', Signup = 'signup', + ForgotPassword = 'forgot-password', + ResetPassword = 'reset-password', + VerifyEmail = 'verify-email', } export type CustomizationOptions = { diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/login.ts b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/login.ts deleted file mode 100644 index 2b4ec4b9fe..0000000000 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/login.ts +++ /dev/null @@ -1,13 +0,0 @@ -import api, { handleApiError } from 'wasp/api' -import { initSession } from './helpers/user' - -export default async function login(username: string, password: string): Promise { - try { - const args = { username, password } - const response = await api.post('/auth/username/login', args) - - await initSession(response.data.sessionId) - } catch (error) { - handleApiError(error) - } -} diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/signup.ts b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/signup.ts deleted file mode 100644 index bde50c5ebd..0000000000 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/signup.ts +++ /dev/null @@ -1,9 +0,0 @@ -import api, { handleApiError } from 'wasp/api' - -export default async function signup(userFields: { username: string; password: string }): Promise { - try { - await api.post('/auth/username/signup', userFields) - } catch (error) { - handleApiError(error) - } -} diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/package.json b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/package.json index f0ab9544d4..e518285f3e 100644 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/package.json +++ b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/package.json @@ -23,12 +23,18 @@ "./auth/logout": "./dist/auth/logout.js", "./auth/useAuth": "./dist/auth/useAuth.js", "./auth/user": "./dist/auth/user.js", + "./auth/helpers/user": "./dist/auth/helpers/user.js", "./auth/session": "./dist/auth/session.js", + "./auth/providers/types": "./dist/auth/providers/types.js", "./auth/utils": "./dist/auth/utils.js", "./auth/password": "./dist/auth/password.js", + "./auth/jwt": "./dist/auth/jwt.js", "./auth/validation": "./dist/auth/validation.js", "./auth/forms/Login": "./dist/auth/forms/Login.jsx", "./auth/forms/Signup": "./dist/auth/forms/Signup.jsx", + "./auth/forms/VerifyEmail": "./dist/auth/forms/VerifyEmail.jsx", + "./auth/forms/ForgotPassword": "./dist/auth/forms/ForgotPassword.jsx", + "./auth/forms/ResetPassword": "./dist/auth/forms/ResetPassword.jsx", "./auth/pages/createAuthRequiredPage": "./dist/auth/pages/createAuthRequiredPage.jsx", "./api": "./dist/api/index.js", "./api/*": "./dist/api/*", diff --git a/waspc/examples/todo-typescript/main.wasp b/waspc/examples/todo-typescript/main.wasp index 21d03e54dc..3ece3d406d 100644 --- a/waspc/examples/todo-typescript/main.wasp +++ b/waspc/examples/todo-typescript/main.wasp @@ -7,12 +7,28 @@ app TodoTypescript { auth: { userEntity: User, methods: { - usernameAndPassword: {}, // this is a very naive implementation, use 'email' in production instead - //google: {}, //https://wasp-lang.dev/docs/integrations/google + // usernameAndPassword: {}, // this is a very naive implementation, use 'email' in production instead + google: { + userSignupFields: import { googleUserSignupFields } from "@src/user/userSignupFields.js" + }, //https://wasp-lang.dev/docs/integrations/google //gitHub: {}, //https://wasp-lang.dev/docs/integrations/github - //email: {} //https://wasp-lang.dev/docs/guides/email-auth + email: { + userSignupFields: import { userSignupFields } from "@src/user/userSignupFields.js", + fromField: { + email: "waspy@app.com" + }, + emailVerification: { + clientRoute: EmailVerificationRoute, + }, + passwordReset: { + clientRoute: PasswordResetRoute, + } + } // https://wasp-lang.dev/docs/guides/email-auth }, onAuthFailedRedirectTo: "/login", + }, + emailSender: { + provider: Dummy } } @@ -21,6 +37,7 @@ app TodoTypescript { // Then run `wasp db studio` to open Prisma Studio and view your db models entity User {=psl id Int @id @default(autoincrement()) + address String tasks Task[] psl=} @@ -41,12 +58,28 @@ page MainPage { route LoginRoute { path: "/login", to: LoginPage } page LoginPage { - component: import { LoginPage } from "@src/user/LoginPage.tsx" + component: import { LoginPage } from "@src/user/auth.tsx" } route SignupRoute { path: "/signup", to: SignupPage } page SignupPage { - component: import { SignupPage } from "@src/user/SignupPage.tsx" + component: import { SignupPage } from "@src/user/auth.tsx" +} + +route EmailVerificationRoute { path: "/email-verify", to: EmailVerification } +page EmailVerification { + component: import { EmailVerificationPage } from "@src/user/auth.tsx" +} + +route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordReset } +page RequestPasswordReset { + component: import { RequestPasswordResetPage } from "@src/user/auth.tsx" +} + + +route PasswordResetRoute { path: "/password-reset", to: PasswordReset } +page PasswordReset { + component: import { PasswordResetPage } from "@src/user/auth.tsx" } query getTasks { diff --git a/waspc/examples/todo-typescript/migrations/20240122093642_new_auth/migration.sql b/waspc/examples/todo-typescript/migrations/20240122093642_new_auth/migration.sql new file mode 100644 index 0000000000..0633158762 --- /dev/null +++ b/waspc/examples/todo-typescript/migrations/20240122093642_new_auth/migration.sql @@ -0,0 +1,17 @@ +/* + Warnings: + + - Added the required column `address` to the `User` table without a default value. This is not possible if the table is not empty. + +*/ +-- RedefineTables +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_User" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "address" TEXT NOT NULL +); +INSERT INTO "new_User" ("id") SELECT "id" FROM "User"; +DROP TABLE "User"; +ALTER TABLE "new_User" RENAME TO "User"; +PRAGMA foreign_key_check; +PRAGMA foreign_keys=ON; diff --git a/waspc/examples/todo-typescript/src/MainPage.tsx b/waspc/examples/todo-typescript/src/MainPage.tsx index 3d43e28deb..2c8d15b5a8 100644 --- a/waspc/examples/todo-typescript/src/MainPage.tsx +++ b/waspc/examples/todo-typescript/src/MainPage.tsx @@ -1,28 +1,28 @@ -import './Main.css' -import React, { useEffect, FormEventHandler, FormEvent } from 'react' -import logout from 'wasp/auth/logout' -import { useQuery, useAction } from 'wasp/rpc' // Wasp uses a thin wrapper around react-query -import { getTasks } from 'wasp/rpc/queries' -import { createTask, updateTask, deleteTasks } from 'wasp/rpc/actions' -import waspLogo from './waspLogo.png' -import type { Task } from 'wasp/entities' -import type { User } from 'wasp/auth/types' -import { getUsername } from 'wasp/auth/user' +import "./Main.css"; +import React, { useEffect, FormEventHandler, FormEvent } from "react"; +import logout from "wasp/auth/logout"; +import { useQuery, useAction } from "wasp/rpc"; // Wasp uses a thin wrapper around react-query +import { getTasks } from "wasp/rpc/queries"; +import { createTask, updateTask, deleteTasks } from "wasp/rpc/actions"; +import waspLogo from "./waspLogo.png"; +import type { Task } from "wasp/entities"; +import type { User } from "wasp/auth/types"; +import { getFirstProviderUserId } from "wasp/auth/user"; export const MainPage = ({ user }: { user: User }) => { - const { data: tasks, isLoading, error } = useQuery(getTasks) + const { data: tasks, isLoading, error } = useQuery(getTasks); - if (isLoading) return 'Loading...' - if (error) return 'Error: ' + error + if (isLoading) return "Loading..."; + if (error) return "Error: " + error; - const completed = tasks?.filter((task) => task.isDone).map((task) => task.id) + const completed = tasks?.filter((task) => task.isDone).map((task) => task.id); return (
wasp logo {user && (

- {getUsername(user)} + {getFirstProviderUserId(user)} {`'s tasks :)`}

)} @@ -40,8 +40,8 @@ export const MainPage = ({ user }: { user: User }) => {
- ) -} + ); +}; function Todo({ id, isDone, description }: Task) { const handleIsDoneChange: FormEventHandler = async ( @@ -51,11 +51,11 @@ function Todo({ id, isDone, description }: Task) { await updateTask({ id, isDone: event.currentTarget.checked, - }) + }); } catch (err: any) { - window.alert('Error while updating task ' + err?.message) + window.alert("Error while updating task " + err?.message); } - } + }; return (
  • @@ -70,38 +70,38 @@ function Todo({ id, isDone, description }: Task) {
  • - ) + ); } function TasksList({ tasks }: { tasks: Task[] }) { - if (tasks.length === 0) return

    No tasks yet.

    + if (tasks.length === 0) return

    No tasks yet.

    ; return (
      {tasks.map((task, idx) => ( ))}
    - ) + ); } function NewTaskForm() { const handleSubmit = async (event: FormEvent) => { - event.preventDefault() + event.preventDefault(); try { - const description = event.currentTarget.description.value - console.log(description) - event.currentTarget.reset() - await createTask({ description }) + const description = event.currentTarget.description.value; + console.log(description); + event.currentTarget.reset(); + await createTask({ description }); } catch (err: any) { - window.alert('Error: ' + err?.message) + window.alert("Error: " + err?.message); } - } + }; return ( - ) + ); } diff --git a/waspc/examples/todo-typescript/src/user/LoginPage.tsx b/waspc/examples/todo-typescript/src/user/LoginPage.tsx deleted file mode 100644 index fa198154ab..0000000000 --- a/waspc/examples/todo-typescript/src/user/LoginPage.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Link } from 'react-router-dom' -import { LoginForm } from 'wasp/auth/forms/Login' - -export function LoginPage() { - return ( -
    - {/** Wasp has built-in auth forms & flows, which you can customize or opt-out of, if you wish :) - * https://wasp-lang.dev/docs/guides/auth-ui - */} - -
    - - I don't have an account yet (go to signup). - -
    - ) -} diff --git a/waspc/examples/todo-typescript/src/user/SignupPage.tsx b/waspc/examples/todo-typescript/src/user/SignupPage.tsx deleted file mode 100644 index e3599729d6..0000000000 --- a/waspc/examples/todo-typescript/src/user/SignupPage.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Link } from 'react-router-dom' -import { SignupForm } from 'wasp/auth/forms/Signup' - -export function SignupPage() { - return ( -
    - {/** Wasp has built-in auth forms & flows, which you can customize or opt-out of, if you wish :) - * https://wasp-lang.dev/docs/guides/auth-ui - */} - -
    - - I already have an account (go to login). - -
    - ) -} diff --git a/waspc/examples/todo-typescript/src/user/auth.tsx b/waspc/examples/todo-typescript/src/user/auth.tsx new file mode 100644 index 0000000000..748f271b88 --- /dev/null +++ b/waspc/examples/todo-typescript/src/user/auth.tsx @@ -0,0 +1,59 @@ +import { ResetPasswordForm } from "wasp/auth/forms/ResetPassword"; +import { LoginForm } from "wasp/auth/forms/Login"; +import { VerifyEmailForm } from "wasp/auth/forms/VerifyEmail"; +import { SignupForm } from "wasp/auth/forms/Signup"; +import { ForgotPasswordForm } from "wasp/auth/forms/ForgotPassword"; +import { Link } from "react-router-dom"; + +export function SignupPage() { + return ( +
    + {/** Wasp has built-in auth forms & flows, which you can customize or opt-out of, if you wish :) + * https://wasp-lang.dev/docs/guides/auth-ui + */} + +
    + + I already have an account (go to login). + +
    + ); +} + +export function LoginPage() { + return ( +
    + {/** Wasp has built-in auth forms & flows, which you can customize or opt-out of, if you wish :) + * https://wasp-lang.dev/docs/guides/auth-ui + */} + +
    + + I don't have an account yet (go to signup). + +
    + ); +} + +export function RequestPasswordResetPage() { + return ; +} + +export function PasswordResetPage() { + return ; +} + +export function EmailVerificationPage() { + return ; +} diff --git a/waspc/examples/todo-typescript/src/user/userSignupFields.ts b/waspc/examples/todo-typescript/src/user/userSignupFields.ts new file mode 100644 index 0000000000..f96722d64a --- /dev/null +++ b/waspc/examples/todo-typescript/src/user/userSignupFields.ts @@ -0,0 +1,13 @@ +import { defineUserSignupFields } from "wasp/auth/providers/types"; + +export const googleUserSignupFields = defineUserSignupFields({ + address: (data) => "Placeholder address", +}); +export const userSignupFields = defineUserSignupFields({ + address: (data) => { + if (typeof data.address !== "string") { + throw new Error("Address must be provided on signup."); + } + return data.address; + }, +}); From 51b7a45b53376f6e7946f73d9f008dd19be2cfd2 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 22 Jan 2024 11:05:00 +0100 Subject: [PATCH 2/2] Test out Github auth --- .../wasp/auth/forms/internal/common/LoginSignupForm.tsx | 2 ++ waspc/examples/todo-typescript/main.wasp | 6 ++++-- .../examples/todo-typescript/src/user/userSignupFields.ts | 7 ++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx index 194c3bd9c2..35fdbfd15b 100644 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx +++ b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx @@ -92,6 +92,7 @@ const SocialAuthButtons = styled('div', { } }) const googleSignInUrl = `${config.apiUrl}/auth/google/login` +const gitHubSignInUrl = `${config.apiUrl}/auth/github/login` export type LoginSignupFormFields = { [key: string]: string; @@ -148,6 +149,7 @@ export const LoginSignupForm = ({ + diff --git a/waspc/examples/todo-typescript/main.wasp b/waspc/examples/todo-typescript/main.wasp index 3ece3d406d..01cff9a68d 100644 --- a/waspc/examples/todo-typescript/main.wasp +++ b/waspc/examples/todo-typescript/main.wasp @@ -10,8 +10,10 @@ app TodoTypescript { // usernameAndPassword: {}, // this is a very naive implementation, use 'email' in production instead google: { userSignupFields: import { googleUserSignupFields } from "@src/user/userSignupFields.js" - }, //https://wasp-lang.dev/docs/integrations/google - //gitHub: {}, //https://wasp-lang.dev/docs/integrations/github + }, + gitHub: { + userSignupFields: import { githubUserSignupFields } from "@src/user/userSignupFields.js" + }, email: { userSignupFields: import { userSignupFields } from "@src/user/userSignupFields.js", fromField: { diff --git a/waspc/examples/todo-typescript/src/user/userSignupFields.ts b/waspc/examples/todo-typescript/src/user/userSignupFields.ts index f96722d64a..eca76488a9 100644 --- a/waspc/examples/todo-typescript/src/user/userSignupFields.ts +++ b/waspc/examples/todo-typescript/src/user/userSignupFields.ts @@ -1,8 +1,13 @@ import { defineUserSignupFields } from "wasp/auth/providers/types"; export const googleUserSignupFields = defineUserSignupFields({ - address: (data) => "Placeholder address", + address: () => "Placeholder address", }); + +export const githubUserSignupFields = defineUserSignupFields({ + address: () => "Placeholder address", +}); + export const userSignupFields = defineUserSignupFields({ address: (data) => { if (typeof data.address !== "string") {