Skip to content

Commit

Permalink
Merge pull request #110 from Vizzuality/FORA-331-fe-implement-signin-…
Browse files Browse the repository at this point in the history
…flow

FE: Authentication Implementation
  • Loading branch information
agnlez authored Jan 27, 2025
2 parents a5aaa38 + 9cefaa5 commit 59370e5
Show file tree
Hide file tree
Showing 19 changed files with 567 additions and 320 deletions.
2 changes: 2 additions & 0 deletions client/src/components/button/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const THEME = {
transparent: 'text-grey-0 bg-transparent',
outline: 'text-grey-0 bg-transparent border border-grey-0',
green: 'text-grey-0 bg-green-0 border border-green-0 hover:bg-green-0/90 active:bg-green-0/75',
'green-alt':
'text-grey-0 bg-transparent border border-green-0 hover:bg-grey-0/5 active:bg-grey-0/10',
Expand Down
6 changes: 4 additions & 2 deletions client/src/components/button/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { ButtonHTMLAttributes, AnchorHTMLAttributes } from 'react';
import { LinkProps } from 'next/link';

export interface AnchorButtonProps {
theme:
theme?:
| 'transparent'
| 'outline'
| 'green'
| 'green-alt'
| 'blue'
Expand All @@ -12,7 +14,7 @@ export interface AnchorButtonProps {
| 'white-alt'
| 'black'
| 'black-alt';
size: 'xs' | 'base' | 'xl';
size?: 'xs' | 'base' | 'xl';
className?: string;
}

Expand Down
4 changes: 2 additions & 2 deletions client/src/components/forms/input/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ export const THEME = {
light: {
base: 'w-full leading-tight text-grey-0 bg-white focus:border-grey-40',
status: {
none: 'border-grey-0',
none: 'border-grey-40',
valid: 'border-green-0',
error: 'border-red-500',
disabled: 'border-grey-0 opacity-50',
disabled: 'border-grey-40 opacity-50',
},
icon: 'text-grey-0 text-opacity-50',
mode: {
Expand Down
22 changes: 22 additions & 0 deletions client/src/components/icons/circle-user/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FC, SVGProps } from 'react';

const CircleUserIcon: FC<SVGProps<SVGSVGElement>> = (props) => {
return (
<svg
width="40"
height="40"
viewBox="0 0 40 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
id="Vector"
d="M31.1719 30.0156C29.4453 27.0156 26.2031 25 22.5 25H17.5C13.7969 25 10.5547 27.0156 8.82812 30.0156C11.5781 33.0781 15.5625 35 20 35C24.4375 35 28.4219 33.0703 31.1719 30.0156ZM0 20C0 14.6957 2.10714 9.60859 5.85786 5.85786C9.60859 2.10714 14.6957 0 20 0C25.3043 0 30.3914 2.10714 34.1421 5.85786C37.8929 9.60859 40 14.6957 40 20C40 25.3043 37.8929 30.3914 34.1421 34.1421C30.3914 37.8929 25.3043 40 20 40C14.6957 40 9.60859 37.8929 5.85786 34.1421C2.10714 30.3914 0 25.3043 0 20ZM20 21.25C21.4918 21.25 22.9226 20.6574 23.9775 19.6025C25.0324 18.5476 25.625 17.1168 25.625 15.625C25.625 14.1332 25.0324 12.7024 23.9775 11.6475C22.9226 10.5926 21.4918 10 20 10C18.5082 10 17.0774 10.5926 16.0225 11.6475C14.9676 12.7024 14.375 14.1332 14.375 15.625C14.375 17.1168 14.9676 18.5476 16.0225 19.6025C17.0774 20.6574 18.5082 21.25 20 21.25Z"
fill="#DFDEDE"
/>
</svg>
);
};

export default CircleUserIcon;
1 change: 1 addition & 0 deletions client/src/components/search/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const Search: React.FC<SearchProps> = ({
className={cx({
'w-full h-full py-3 px-4': true,
[THEME[theme]]: true,
'!border-grey-0': true,
})}
onChange={handleChange}
/>
Expand Down
6 changes: 6 additions & 0 deletions client/src/constants/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ export const NAV = [
target: '_blank',
rel: 'noopener noreferrer',
},
{
label: 'Log In',
href: '/auth/signin',
className: 'border border-grey-0 rounded-lg !bg-white',
auth: true,
},
];

export const POLICIES = [
Expand Down
85 changes: 85 additions & 0 deletions client/src/containers/auth/change-password/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { FC, useCallback } from 'react';

import { Form as FormRFF, Field as FieldRFF } from 'react-final-form';

import { useRouter } from 'next/navigation';

import { FORM_ERROR } from 'final-form';

import { AuthWrapper } from 'containers/wrapper/component';

import LinkButton, { Button } from 'components/button/component';
import Input from 'components/forms/input/component';

import authenticationService from 'services/authentication';

const ChangePassword: FC<{ token: string | undefined }> = ({ token }) => {
const router = useRouter();

const handleFormSubmit = useCallback(
async ({
password,
passwordConfirmation,
}: {
password: string;
passwordConfirmation: string;
}) => {
try {
const res = await authenticationService.changePassword(
token,
password,
passwordConfirmation
);

if (res?.status === 200) {
router.push('/auth/signin');
} else {
throw new Error('Failed to change password');
}
} catch (err) {
return {
[FORM_ERROR]: err instanceof Error ? err.message : 'An unexpected error occurred',
};
}
},
[router, token]
);

return (
<AuthWrapper>
<FormRFF
onSubmit={handleFormSubmit}
initialValues={{ password: '', passwordConfirmation: '' }}
>
{({ submitError, handleSubmit }) => (
<form className="space-y-5" onSubmit={handleSubmit} autoComplete="off">
<h2 className="text-3xl text-center font-normal">Change password</h2>
<div>
<label>New password</label>
<FieldRFF name="password" type="password">
{({ input }) => <Input {...input} />}
</FieldRFF>
</div>
<div>
<label>Confirm password</label>
<FieldRFF name="passwordConfirmation" type="password">
{({ input }) => <Input {...input} />}
</FieldRFF>
</div>
{submitError && <div className="text-red-0">{submitError}</div>}
<div className="flex justify-between gap-3">
<LinkButton theme="outline" className="flex-1" href="/auth/signin">
Cancel
</LinkButton>
<Button theme="green" size="base" className="flex-1" type="submit">
<span>Reset password</span>
</Button>
</div>
</form>
)}
</FormRFF>
</AuthWrapper>
);
};

export default ChangePassword;
152 changes: 83 additions & 69 deletions client/src/containers/footer/component.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React from 'react';
import React, { useMemo } from 'react';

import cx from 'classnames';

import Image from 'next/image';
import Link from 'next/link';
import { useRouter } from 'next/router';

import { useSession } from 'next-auth/react';

import { NAV, POLICIES } from 'constants/nav';

Expand All @@ -16,80 +19,91 @@ import LINKEDIN_SVG from 'svgs/social/linkedin.svg?sprite';
import TWITTER_SVG from 'svgs/social/twitter.svg?sprite';

const Footer = () => {
const { pathname } = useRouter();
const { data: session } = useSession();
const hideNav = useMemo(() => {
return pathname.includes('/auth');
}, [pathname]);
const NAV_ITEMS = useMemo(() => {
return NAV.filter((n) => !(session && n.auth));
}, [session]);

return (
<footer>
<div className="py-14 bg-blue-0/5">
<Wrapper>
<div className="flex flex-col justify-between space-y-10 md:space-y-0 md:flex-row">
<div className="flex flex-col items-center justify-between space-y-10 md:items-start md:space-y-0 md:flex-row md:space-x-20">
<Link href="/">
<Image
src={`${process.env.NEXT_PUBLIC_BASE_PATH}${LOGO_MONOCHROME_SVG}`}
alt="Logo"
width={122}
height={56}
priority
/>
</Link>
{!hideNav && (
<div className="py-14 bg-blue-0/5">
<Wrapper>
<div className="flex flex-col justify-between space-y-10 md:space-y-0 md:flex-row">
<div className="flex flex-col items-center justify-between space-y-10 md:items-start md:space-y-0 md:flex-row md:space-x-20">
<Link href="/">
<Image
src={`${process.env.NEXT_PUBLIC_BASE_PATH}${LOGO_MONOCHROME_SVG}`}
alt="Logo"
width={122}
height={56}
priority
/>
</Link>

<nav className="flex">
<ul className="gap-10 space-y-3 text-center md:text-left md:columns-2">
{NAV.map((item) => {
const { href, label, target, rel } = item;
<nav className="flex">
<ul className="gap-10 space-y-3 text-center md:text-left md:columns-2">
{NAV_ITEMS.map((item) => {
const { href, label, target, rel } = item;

return (
<li key={href}>
{target === '_blank' && (
<a
href={href}
target={target}
rel={rel}
className="py-2 text-base font-semibold hover:opacity-75"
>
{label}
</a>
)}
{!target && (
<Link
href={href}
className="py-2 text-base font-semibold hover:opacity-75"
>
{label}
</Link>
)}
</li>
);
})}
</ul>
</nav>
</div>
return (
<li key={href}>
{target === '_blank' && (
<a
href={href}
target={target}
rel={rel}
className="py-2 text-base font-semibold hover:opacity-75"
>
{label}
</a>
)}
{!target && (
<Link
href={href}
className="py-2 text-base font-semibold hover:opacity-75"
>
{label}
</Link>
)}
</li>
);
})}
</ul>
</nav>
</div>

<div className="flex flex-col space-y-2.5 items-center">
<h3 className="text-sm font-bold text-grey-0">Follow us on:</h3>
<ul className="flex items-center space-x-2.5">
<li>
<a
href="https://www.linkedin.com/company/funders-for-regenerative-agriculture/"
target="_blank"
rel="noopener noreferrer"
>
<Icon icon={LINKEDIN_SVG} className="w-6 h-6" />
</a>
</li>
<li>
<a
href="https://twitter.com/FORAFunders"
target="_blank"
rel="noopener noreferrer"
>
<Icon icon={TWITTER_SVG} className="w-6 h-6" />
</a>
</li>
</ul>
<div className="flex flex-col space-y-2.5 items-center">
<h3 className="text-sm font-bold text-grey-0">Follow us on:</h3>
<ul className="flex items-center space-x-2.5">
<li>
<a
href="https://www.linkedin.com/company/funders-for-regenerative-agriculture/"
target="_blank"
rel="noopener noreferrer"
>
<Icon icon={LINKEDIN_SVG} className="w-6 h-6" />
</a>
</li>
<li>
<a
href="https://twitter.com/FORAFunders"
target="_blank"
rel="noopener noreferrer"
>
<Icon icon={TWITTER_SVG} className="w-6 h-6" />
</a>
</li>
</ul>
</div>
</div>
</div>
</Wrapper>
</div>
</Wrapper>
</div>
)}
<div className="w-full py-5 text-sm text-white bg-blue-0">
<Wrapper>
<div className="flex flex-col items-center justify-between space-y-5 md:space-y-0 md:flex-row">
Expand Down
Loading

0 comments on commit 59370e5

Please sign in to comment.