Skip to content

Commit

Permalink
Merge pull request #29 from pcode-at/feature/TD-30-molecule-login-form
Browse files Browse the repository at this point in the history
Implement login functions and basic navigation
  • Loading branch information
d-woegerbauer authored Jul 7, 2022
2 parents e501b94 + 548ee0a commit deea8a3
Show file tree
Hide file tree
Showing 22 changed files with 517 additions and 16 deletions.
1 change: 1 addition & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL="mongodb+srv://name:name@name.goh49.mongodb.net/name?retryWrites=true&w=majority"
3 changes: 1 addition & 2 deletions backend/src/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ export class UserService {
async findOneDetailed(jwt: string): Promise<UserResponse> {
const decoded = await this.jwtService.decode(jwt);
//@ts-ignore
const identifier = decoded.identifier.userIdentifier.identifier

const identifier = decoded.identifier
const user = await prisma.users.findUnique({
where: {
identifier: identifier,
Expand Down
10 changes: 7 additions & 3 deletions frontend/components/atoms/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type Props = {
disabled?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
onClick?: () => void;
children: React.ReactNode;
};

Expand All @@ -17,12 +18,12 @@ const StyledButton = styled("button", {
borderRadius: "$border-radius-medium",

color: "$neutral-100",
backgroundColor: "$brand-200",
backgroundColor: "$brand-400",
cursor: "pointer",
transition: "all 0.2s ease-in-out",

"&:hover": {
backgroundColor: "$brand-400",
backgroundColor: "$brand-500",
},

"&:disabled": {
Expand All @@ -33,6 +34,7 @@ const StyledButton = styled("button", {

"&:focus": {
outline: "none",
backgroundColor: "$brand-200",
border: "$brand-400 $borderWidths$border-width-medium solid",
},

Expand All @@ -41,6 +43,7 @@ const StyledButton = styled("button", {
medium: {},
small: {
padding: "$spacing-1x $spacing-3x",

},
},
},
Expand All @@ -51,11 +54,12 @@ export const Button: React.FC<Props> = ({
disabled = false,
leftIcon,
rightIcon,
onClick,
children,
}) => {
return (
<>
<StyledButton size={size} disabled={disabled}>
<StyledButton size={size} disabled={disabled} onClick={onClick}>
{children}
</StyledButton>
</>
Expand Down
31 changes: 23 additions & 8 deletions frontend/components/atoms/Heading/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,47 @@ import { styled } from "../../../stitches.config";
import type * as Stitches from "@stitches/react";

type Props = {
styling: Styling;
styling?: Stitches.VariantProps<typeof StyledHeading>["styling"];
color?: Stitches.VariantProps<typeof StyledHeading>["color"];
text: string;
children: React.ReactNode;
alignment?: Stitches.VariantProps<typeof StyledHeading>["alignment"];
};

const StyledHeading = styled("h1", {
width: "100%",

fontSize: "4.5rem",
fontSize: "3.5rem",
color: "black",
textAlign: "center",

variants: {
styling: {},
color: {},
alignment: {
left: {
textAlign: "left",
},
center: {
textAlign: "center",
},
right: {
textAlign: "right",
},
},
},
});

export const Heading: React.FC<Props> = ({ styling, color, text }) => {
export const Heading: React.FC<Props> = ({
styling,
color,
children,
alignment,
}) => {
return (
<>
<StyledHeading styling={styling} color={color}>
{text}
<StyledHeading styling={styling} color={color} alignment={alignment}>
{children}
</StyledHeading>
</>
);
};

export type Styling = Stitches.VariantProps<typeof StyledHeading>["styling"];
34 changes: 34 additions & 0 deletions frontend/components/atoms/ProtectedRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useEffect } from "react";
import { getAccessToken } from "../../utils/authHelper";
import { appRoutes } from "../../utils/routes";

//check if you are on the client (browser) or server
const isBrowser = () => typeof window !== "undefined";

const ProtectedRoute = ({ router, children }) => {
useEffect(() => {
checkIfUserIsLoggedIn();

async function checkIfUserIsLoggedIn() {
// Identify authenticated user
const accessToken = await getAccessToken();

let unprotectedRoutes = [
appRoutes.LOGIN,
];

/**
* @var pathIsProtected Checks if path exists in the unprotectedRoutes routes array
*/
let pathIsProtected = unprotectedRoutes.indexOf(router.pathname) === -1;

if (isBrowser() && !accessToken && pathIsProtected) {
router.push(appRoutes.LOGIN);
}
}
}, [router]);

return children;
};

export default ProtectedRoute;
24 changes: 24 additions & 0 deletions frontend/components/atoms/svg/SvgLogoBig.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react";

const SvgLogoBig = (props) => (
<svg
viewBox="0 0 111 36"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<title>{props?.title || "teamo logo"}</title>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M11.494 9.06a3.03 3.03 0 1 0 0-6.06 3.03 3.03 0 0 0 0 6.06Zm-7.679 1.262a3.03 3.03 0 0 0-1.568 5.855l3.971 1.064a3.03 3.03 0 0 1 2.246 2.927v4.802a3.03 3.03 0 0 0 6.06 0v-4.802a3.03 3.03 0 0 1 2.247-2.927l3.971-1.064a3.03 3.03 0 1 0-1.569-5.854L12.28 12.17a3.032 3.032 0 0 1-1.569 0l-6.895-1.848Z"
fill="currentColor"
/>
<path
d="M35.568 15.464v6.432c0 .448.104.776.312.984.224.192.592.288 1.104.288h1.56V26h-2.112c-2.832 0-4.248-1.376-4.248-4.128v-6.408H30.6v-2.76h1.584V9.416h3.384v3.288h2.976v2.76h-2.976Zm17.753 3.6c0 .48-.032.912-.096 1.296h-9.72c.08.96.416 1.712 1.008 2.256.592.544 1.32.816 2.184.816 1.248 0 2.136-.536 2.664-1.608h3.624c-.384 1.28-1.12 2.336-2.208 3.168-1.088.816-2.424 1.224-4.008 1.224-1.28 0-2.432-.28-3.456-.84a6.182 6.182 0 0 1-2.376-2.424c-.56-1.04-.84-2.24-.84-3.6 0-1.376.28-2.584.84-3.624a5.861 5.861 0 0 1 2.352-2.4c1.008-.56 2.168-.84 3.48-.84 1.264 0 2.392.272 3.384.816a5.63 5.63 0 0 1 2.328 2.328c.56.992.84 2.136.84 3.432Zm-3.48-.96c-.016-.864-.328-1.552-.936-2.064-.608-.528-1.352-.792-2.232-.792-.832 0-1.536.256-2.112.768-.56.496-.904 1.192-1.032 2.088h6.312Zm5.068 1.2c0-1.344.264-2.536.792-3.576.544-1.04 1.272-1.84 2.184-2.4.928-.56 1.96-.84 3.096-.84.992 0 1.856.2 2.592.6.752.4 1.352.904 1.8 1.512v-1.896h3.384V26h-3.384v-1.944c-.432.624-1.032 1.144-1.8 1.56-.752.4-1.624.6-2.616.6a5.71 5.71 0 0 1-3.072-.864c-.912-.576-1.64-1.384-2.184-2.424-.528-1.056-.792-2.264-.792-3.624Zm10.464.048c0-.816-.16-1.512-.48-2.088-.32-.592-.752-1.04-1.296-1.344a3.397 3.397 0 0 0-1.752-.48c-.624 0-1.2.152-1.728.456-.528.304-.96.752-1.296 1.344-.32.576-.48 1.264-.48 2.064s.16 1.504.48 2.112c.336.592.768 1.048 1.296 1.368.544.32 1.12.48 1.728.48.624 0 1.208-.152 1.752-.456.544-.32.976-.768 1.296-1.344.32-.592.48-1.296.48-2.112Zm23.178-6.84c1.632 0 2.944.504 3.936 1.512 1.008.992 1.512 2.384 1.512 4.176V26h-3.36v-7.344c0-1.04-.264-1.832-.792-2.376-.528-.56-1.248-.84-2.16-.84-.912 0-1.64.28-2.184.84-.528.544-.792 1.336-.792 2.376V26h-3.36v-7.344c0-1.04-.264-1.832-.792-2.376-.528-.56-1.248-.84-2.16-.84-.928 0-1.664.28-2.208.84-.528.544-.792 1.336-.792 2.376V26h-3.36V12.704h3.36v1.608c.432-.56.984-1 1.656-1.32.688-.32 1.44-.48 2.256-.48 1.04 0 1.968.224 2.784.672a4.55 4.55 0 0 1 1.896 1.872c.432-.768 1.056-1.384 1.872-1.848a5.43 5.43 0 0 1 2.688-.696Zm14.54 13.704c-1.28 0-2.432-.28-3.456-.84a6.301 6.301 0 0 1-2.424-2.424c-.576-1.04-.864-2.24-.864-3.6 0-1.36.296-2.56.888-3.6a6.253 6.253 0 0 1 2.472-2.4c1.04-.576 2.2-.864 3.48-.864 1.28 0 2.44.288 3.48.864a6.091 6.091 0 0 1 2.448 2.4c.608 1.04.912 2.24.912 3.6 0 1.36-.312 2.56-.936 3.6a6.377 6.377 0 0 1-2.496 2.424c-1.04.56-2.208.84-3.504.84Zm0-2.928c.608 0 1.176-.144 1.704-.432.544-.304.976-.752 1.296-1.344.32-.592.48-1.312.48-2.16 0-1.264-.336-2.232-1.008-2.904-.656-.688-1.464-1.032-2.424-1.032s-1.768.344-2.424 1.032c-.64.672-.96 1.64-.96 2.904s.312 2.24.936 2.928c.64.672 1.44 1.008 2.4 1.008Z"
fill="currentColor"
/>
</svg>
);

export default SvgLogoBig;
21 changes: 21 additions & 0 deletions frontend/components/atoms/svg/SvgUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from "react"

const SvgUser = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
className="feather feather-user"
{...props}
>
<title>{props?.title || 'user icon'}</title>
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
<circle cx={12} cy={7} r={4} />
</svg>
)

export default SvgUser
4 changes: 4 additions & 0 deletions frontend/components/atoms/svg/original/logo_big.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/components/atoms/svg/original/user.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions frontend/components/molecules/LoginForm/LoginForm.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import { ComponentMeta } from "@storybook/react";
import { disabledStorybookArgTypesFromStitches } from "../../../.storybook/helper";
import { LoginForm } from "./LoginForm";
import { styled } from "@stitches/react";

export default {
title: "Molecules/LoginForm",
component: LoginForm,
argTypes: {
size: {
options: ["medium", "small"],
control: { type: "radio" },
},
disabled: {
options: [true, false],
control: { type: "radio" },
},
...disabledStorybookArgTypesFromStitches,
},
} as ComponentMeta<typeof LoginForm>;

const LoginFormWrapper = styled("div", {
display: "flex",
width: "30vw",
});

export const Default = () => (
<LoginFormWrapper>
<LoginForm></LoginForm>
</LoginFormWrapper>
);
59 changes: 59 additions & 0 deletions frontend/components/molecules/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useRouter } from "next/router";
import React from "react";
import { styled } from "../../../stitches.config";
import { login } from "../../../utils/authHelper";
import { Button } from "../../atoms/Button/Button";
import { Checkbox } from "../../atoms/Checkbox/Checkbox";
import { Heading } from "../../atoms/Heading/Heading";
import { InputField } from "../../atoms/InputField/InputField";
import { PasswordField } from "../../atoms/PasswordField/PasswordField";

type Props = {};

const LoginFormLayout = styled("div", {
display: "flex",
flexDirection: "column",
justifyContent: "center",
width: "100%",
padding: "$spacing-4x",

backgroundColor: "$brand-300",
borderRadius: "$border-radius-medium",
});

export const LoginForm: React.FC<Props> = ({}) => {
const [identifier, setIdentifier] = React.useState("");
const [password, setPassword] = React.useState("");
const [rememberMe, setRememberMe] = React.useState(false);

const router = useRouter();

return (
<>
<LoginFormLayout>
<Heading alignment={"left"}>Login</Heading>
<InputField
inputType={"text"}
value={identifier}
onChange={setIdentifier}
/>
<PasswordField
value={password}
onChange={setPassword}
regex={undefined}
/>
<Checkbox onChange={undefined}>Remember me</Checkbox>
<Button
onClick={async () => {
const isLoggedIn = login(identifier, password);
if (isLoggedIn) {
router.push("/");
}
}}
>
Login
</Button>
</LoginFormLayout>
</>
);
};
77 changes: 77 additions & 0 deletions frontend/components/organisms/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import Link from "next/link";
import React from "react";
import { styled } from "../../../stitches.config";
import SvgLogoBig from "../../atoms/svg/SvgLogoBig";
import SvgUser from "../../atoms/svg/SvgUser";

type Props = {};

const NavbarLayout = styled("div", {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
padding: "$spacing-2x",
backgroundColor: "$brand-300",
});

const LogoLayout = styled("div", {
display: "flex",
height: "4vh",
});

const StyledLink = styled("a", {
color: "$neutral-100",
textDecoration: "none",
});

const NavigationItems = styled("div", {
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: "30px",
});

const UserIconLayout = styled("div", {
display: "flex",
width: "3vh",
height: "3vh",

color: "$neutral-100",
});

export const Navbar: React.FC<Props> = ({}) => {
return (
<>
<NavbarLayout>
<Link href="/" passHref>
<StyledLink>
<LogoLayout>
<SvgLogoBig></SvgLogoBig>
</LogoLayout>
</StyledLink>
</Link>
<NavigationItems>
<Link href="/" passHref>
<StyledLink>
HOME
</StyledLink>
</Link>
<Link href="/login" passHref>
<StyledLink>
LOGIN
</StyledLink>
</Link>
<Link href="/profile" passHref>
<StyledLink>
<UserIconLayout>
<SvgUser></SvgUser>
</UserIconLayout>
</StyledLink>
</Link>
</NavigationItems>
</NavbarLayout>
</>
);
};
Loading

0 comments on commit deea8a3

Please sign in to comment.