Skip to content

Commit

Permalink
fix: auth password reset
Browse files Browse the repository at this point in the history
  • Loading branch information
Pagebakers committed Feb 13, 2024
1 parent 95d59e5 commit e5fdee8
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 33 deletions.
5 changes: 5 additions & 0 deletions .changeset/cool-beds-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@saas-ui/auth': patch
---

Fixed issue where success message would not render on forgot password view
5 changes: 5 additions & 0 deletions .changeset/five-dancers-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@saas-ui/auth': patch
---

Allow view prop to controlled with new onViewChange handler
5 changes: 5 additions & 0 deletions .changeset/polite-lemons-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@saas-ui/supabase': patch
---

Fixed issue where update password would not execute
6 changes: 3 additions & 3 deletions packages/saas-ui-auth/src/components/auth-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { cx } from '@chakra-ui/utils'

import { FieldErrors } from '@saas-ui/forms'

import { Providers, AvailableProviders } from './forms/providers'
import { AuthTypeEnum, AuthActionEnum, useAuth } from '../provider'
import { AvailableProviders } from './forms/providers'
import { AuthTypeEnum, AuthActionEnum } from '../provider'

const [StylesProvider, useStyles] = createStylesContext('SuiAuthForm')

Expand Down Expand Up @@ -80,7 +80,7 @@ export interface AuthFormOptions {
*/
oauthRedirectUrl?: string
/**
* The redirecet URL after succesful magic link or password login
* The redirect URL after succesful OAuth or Magic link login
*/
redirectUrl?: string
/**
Expand Down
45 changes: 38 additions & 7 deletions packages/saas-ui-auth/src/components/auth.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react'

import { chakra, Link } from '@chakra-ui/react'
import { chakra, Link, useControllableState } from '@chakra-ui/react'

import { AuthFormOptions } from './auth-form'
import { LoginView, SignupView } from './login-view'
Expand All @@ -21,8 +21,13 @@ export const VIEWS = {
type ValueOf<T> = T[keyof T]
type ViewType = ValueOf<typeof VIEWS>

export type RedirectViews =
| typeof VIEWS.LOGIN
| typeof VIEWS.SIGNUP
| typeof VIEWS.FORGOT_PASSWORD

export interface AuthProps
extends AuthFormOptions,
extends Omit<AuthFormOptions, 'redirectUrl'>,
Omit<
FormProps<any, any>,
'title' | 'action' | 'defaultValues' | 'onSubmit' | 'onError' | 'children'
Expand All @@ -37,6 +42,10 @@ export interface AuthProps
* - otp
*/
view?: ViewType
/**
* Called when the view changes.
*/
onViewChange?(view: ViewType): void
/**
* The OAuth providers that are supported.
*/
Expand Down Expand Up @@ -77,11 +86,17 @@ export interface AuthProps
* @param error
*/
onError?: (view: ViewType, error: Error) => void
/**
* The redirect URL after succesful login
* This property is passed down to the auth service
*/
redirectUrl?: string | ((view: RedirectViews) => string | undefined)
}

export const Auth: React.FC<AuthProps> = (props) => {
const {
view = VIEWS.LOGIN,
onViewChange,
providers,
signupLink = 'Sign up',
loginLink = 'Log in',
Expand All @@ -90,16 +105,19 @@ export const Auth: React.FC<AuthProps> = (props) => {
noAccount = 'No account yet?',
haveAccount = 'Already have an account?',
onError,
redirectUrl,
...rest
} = props

const { type } = rest

const [authView, setAuthView] = React.useState(view)

React.useEffect(() => {
setAuthView(view)
}, [view])
const [authView, setAuthView] = useControllableState<ViewType>({
defaultValue: 'login',
value: view,
onChange: (view) => {
onViewChange?.(view)
},
})

const errorHandler = React.useCallback(
(view: ViewType) => (error: Error) => {
Expand All @@ -110,6 +128,16 @@ export const Auth: React.FC<AuthProps> = (props) => {
[authView]
)

const getRedirectUrl = React.useCallback(
(view: RedirectViews) => {
if (typeof redirectUrl === 'function') {
return redirectUrl(view)
}
return redirectUrl
},
[redirectUrl]
)

switch (authView) {
case VIEWS.LOGIN:
return (
Expand All @@ -123,6 +151,7 @@ export const Auth: React.FC<AuthProps> = (props) => {
link={signupLink}
/>
}
redirectUrl={getRedirectUrl(VIEWS.LOGIN)}
{...rest}
>
{type === 'password' &&
Expand Down Expand Up @@ -152,6 +181,7 @@ export const Auth: React.FC<AuthProps> = (props) => {
link={loginLink}
/>
}
redirectUrl={getRedirectUrl(VIEWS.SIGNUP)}
{...rest}
/>
)
Expand All @@ -165,6 +195,7 @@ export const Auth: React.FC<AuthProps> = (props) => {
link={backLink}
/>
}
redirectUrl={getRedirectUrl(VIEWS.FORGOT_PASSWORD)}
{...rest}
/>
)
Expand Down
22 changes: 17 additions & 5 deletions packages/saas-ui-auth/src/components/forgot-password-view.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { SubmitHandler } from '@saas-ui/forms'
import { useResetPassword } from '../provider'
import { AuthFormContainer, AuthFormTitle, AuthViewOptions } from './auth-form'
import {
AuthFormContainer,
AuthFormOptions,
AuthFormTitle,
AuthViewOptions,
} from './auth-form'
import {
ForgotPasswordForm,
ForgotPasswordFormProps,
Expand All @@ -12,6 +17,10 @@ export interface ForgotPasswordViewProps
extends AuthViewOptions,
Omit<ForgotPasswordFormProps, 'title' | 'action' | 'onError' | 'onSubmit'> {
renderSuccess?: (data: any) => React.ReactElement
/**
* The URL where the user can save their new password.
*/
redirectUrl?: string
}

export const ForgotPasswordView: React.FC<ForgotPasswordViewProps> = (
Expand All @@ -29,25 +38,28 @@ export const ForgotPasswordView: React.FC<ForgotPasswordViewProps> = (
description="Please check your email for instructions to reset your password."
/>
),
redirectUrl,
...rest
} = props

const [{ data, isResolved }, submit] = useResetPassword()

const handleSubmit: SubmitHandler<ForgotPasswordSubmitParams> = (params) => {
return submit(params).then(onSuccess).catch(onError)
return submit(params, {
redirectTo: redirectUrl,
})
.then(onSuccess)
.catch(onError)
}

const isSuccess = isResolved && data

return (
<AuthFormContainer>
{typeof title === 'string' ? (
<AuthFormTitle>{title}</AuthFormTitle>
) : (
title
)}
{isSuccess ? (
{isResolved ? (
renderSuccess(data)
) : (
<ForgotPasswordForm
Expand Down
23 changes: 5 additions & 18 deletions packages/saas-ui-supabase/src/supabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,6 @@ interface OtpParams extends AuthParams {
otp: string
}

const getParams = (): RecoveryParams => {
const hash = window.location.hash.replace('#', '')
return hash.split('&').reduce<any>((memo, part) => {
const [key, value] = part.split('=')
memo[key] = value
return memo
}, {})
}

interface SupabaseServiceAuthOptions {
loginOptions?: {
data?: object
Expand Down Expand Up @@ -264,15 +255,11 @@ export const createAuthService = <Client extends SupabaseClient>(
const onUpdatePassword = async ({
password,
}: Required<Pick<AuthParams, 'password'>>) => {
const params = getParams()

if (params?.type === 'recovery') {
const { error } = await supabase.auth.updateUser({
password,
})
if (error) {
throw error
}
const { error } = await supabase.auth.updateUser({
password,
})
if (error) {
throw error
}
}

Expand Down

0 comments on commit e5fdee8

Please sign in to comment.