-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #54 from blockydevs/HAF-12-forgot-password-reset-p…
…assword Haf 12 forgot password reset password
- Loading branch information
Showing
14 changed files
with
392 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
packages/apps/human-app/frontend/src/api/servieces/worker/send-reset-link.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { z } from 'zod'; | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import { useNavigate } from 'react-router-dom'; | ||
import { apiClient } from '@/api/api-client'; | ||
import { apiPaths } from '@/api/api-paths'; | ||
import { routerPaths } from '@/router/router-paths'; | ||
|
||
export const sendResetLinkDtoSchema = z.object({ | ||
email: z.string().email(), | ||
}); | ||
|
||
export type SendResetLinkDto = z.infer<typeof sendResetLinkDtoSchema>; | ||
|
||
const SendResetLinkSuccessResponseSchema = z.unknown(); | ||
|
||
function sendResetLinkMutationFn(data: SendResetLinkDto) { | ||
return apiClient(apiPaths.worker.sendResetLink.path, { | ||
successSchema: SendResetLinkSuccessResponseSchema, | ||
options: { method: 'POST', body: JSON.stringify(data) }, | ||
}); | ||
} | ||
|
||
export function useSendResetLinkMutation() { | ||
const queryClient = useQueryClient(); | ||
const navigate = useNavigate(); | ||
|
||
return useMutation({ | ||
mutationFn: sendResetLinkMutationFn, | ||
onSuccess: async (_, { email }) => { | ||
navigate(routerPaths.worker.sendResetLinkSuccess, { state: { email } }); | ||
await queryClient.invalidateQueries(); | ||
}, | ||
onError: async () => { | ||
await queryClient.invalidateQueries(); | ||
}, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
packages/apps/human-app/frontend/src/components/data-entry/password/password-checks.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { t } from 'i18next'; | ||
import { z } from 'zod'; | ||
import type { PasswordCheck } from '@/components/data-entry/password/password-check-label'; | ||
import { | ||
password8Chars, | ||
passwordLowercase, | ||
passwordNumeric, | ||
passwordSpecialCharacter, | ||
passwordUppercase, | ||
} from '@/shared/helpers/regex'; | ||
|
||
export const passwordChecks: PasswordCheck[] = [ | ||
{ | ||
requirementsLabel: t('validation.password8Chars'), | ||
schema: z.string().regex(password8Chars), | ||
}, | ||
{ | ||
requirementsLabel: t('validation.passwordUppercase'), | ||
schema: z.string().regex(passwordUppercase), | ||
}, | ||
{ | ||
requirementsLabel: t('validation.passwordLowercase'), | ||
schema: z.string().regex(passwordLowercase), | ||
}, | ||
{ | ||
requirementsLabel: t('validation.passwordNumeric'), | ||
schema: z.string().regex(passwordNumeric), | ||
}, | ||
{ | ||
requirementsLabel: t('validation.passwordSpecialCharacter'), | ||
schema: z.string().regex(passwordSpecialCharacter), | ||
}, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
packages/apps/human-app/frontend/src/hooks/use-location-state.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* eslint-disable @typescript-eslint/no-unsafe-member-access -- that's ok because we validate this members with zod */ | ||
import { useEffect, useState } from 'react'; | ||
import type { Location } from 'react-router-dom'; | ||
import { useLocation, useNavigate } from 'react-router-dom'; | ||
import type { z } from 'zod'; | ||
import { routerPaths } from '@/router/router-paths'; | ||
|
||
interface UseLocationStateProps<T> { | ||
schema: z.ZodSchema<T>; | ||
locationStorage?: keyof Location; | ||
keyInStorage?: string; | ||
onErrorRedirectPath?: string; | ||
} | ||
|
||
export function useLocationState<T>({ | ||
keyInStorage, | ||
onErrorRedirectPath = routerPaths.homePage, | ||
locationStorage = 'state', | ||
schema, | ||
}: UseLocationStateProps<T>) { | ||
const location = useLocation(); | ||
const navigate = useNavigate(); | ||
const [fieldFromState, setFieldFromState] = useState<T>(); | ||
|
||
useEffect(() => { | ||
try { | ||
const storage = ( | ||
keyInStorage | ||
? location[locationStorage]?.[keyInStorage] | ||
: location[locationStorage] | ||
) as unknown; | ||
|
||
const validFiled = schema.parse(storage); | ||
setFieldFromState(validFiled); | ||
} catch { | ||
navigate(onErrorRedirectPath, { replace: true }); | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps -- call this effect once | ||
}, []); | ||
|
||
return { | ||
field: fieldFromState, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
...apps/human-app/frontend/src/pages/worker/send-reset-link/send-reset-link-success.page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { Grid, Typography } from '@mui/material'; | ||
import { Trans, useTranslation } from 'react-i18next'; | ||
import { Link } from 'react-router-dom'; | ||
import { z } from 'zod'; | ||
import { PageCard } from '@/components/ui/page-card'; | ||
import { Button } from '@/components/ui/button'; | ||
import { routerPaths } from '@/router/router-paths'; | ||
import { colorPalette } from '@/styles/color-palette'; | ||
import { useLocationState } from '@/hooks/use-location-state'; | ||
|
||
export function SendResetLinkWorkerSuccessPage() { | ||
const { t } = useTranslation(); | ||
const { field: email } = useLocationState({ | ||
keyInStorage: 'email', | ||
schema: z.string().email(), | ||
}); | ||
|
||
return ( | ||
<PageCard title={t('worker.sendResetLinkForm.title')}> | ||
<Grid container gap="2rem"> | ||
<Typography> | ||
<Trans | ||
i18nKey="worker.sendResetLinkSuccess.paragraph1" | ||
values={{ email }} | ||
> | ||
Strong <Typography variant="buttonMedium" /> | ||
</Trans> | ||
</Typography> | ||
<Typography color={colorPalette.primary.light} variant="body1"> | ||
{t('worker.sendResetLinkSuccess.paragraph2')} | ||
</Typography> | ||
<Typography variant="body1"> | ||
<Trans | ||
i18nKey="worker.sendResetLinkSuccess.paragraph3" | ||
values={{ email }} | ||
> | ||
Strong <Typography variant="buttonMedium" /> | ||
</Trans> | ||
</Typography> | ||
<Button | ||
component={Link} | ||
fullWidth | ||
to={routerPaths.worker.signIn} | ||
variant="contained" | ||
> | ||
{t('worker.sendResetLinkSuccess.btn')} | ||
</Button> | ||
|
||
<Typography variant="body1"> | ||
<Trans | ||
i18nKey="worker.sendResetLinkSuccess.paragraph4" | ||
values={{ email }} | ||
> | ||
Strong | ||
<Typography variant="buttonMedium" /> | ||
<Link to={routerPaths.homePage} /> | ||
</Trans> | ||
</Typography> | ||
</Grid> | ||
</PageCard> | ||
); | ||
} |
Oops, something went wrong.