Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth #3

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ yarn-error.log*

# typescript
*.tsbuildinfo

# editors
.vscode
22 changes: 22 additions & 0 deletions components/dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Center, VStack, Text } from "@chakra-ui/react"

export type FullScreenDialogProps = {
title: String;
children?: JSX.Element | JSX.Element[];
}

export const FullScreenDialog = ({ title, children }: FullScreenDialogProps) => (
<Center minHeight="100vh">
<VStack
padding="3rem"
margin="2rem"
background="#0A0A0A"
borderRadius="8px"
>
<Text fontSize="1.5rem">{title}</Text>

{children}
</VStack>
</Center>
)

58 changes: 58 additions & 0 deletions components/error_boundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { ErrorInfo } from "react";
import { FullScreenDialog } from "./dialog";
import { Center, Flex, Link, Text, VStack } from "@chakra-ui/react";

type ErrorBoundaryProps = {
children?: JSX.Element | JSX.Element[];
}

type ErrorState = {
errorMessage?: string | JSX.Element;
}

export default class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorState> {
constructor(props: ErrorBoundaryProps) {
super(props)
this.state = {}
}

static getDerivedStateFromError(error: Error) {
return { errorMessage: ErrorBoundary.translateErrorMessage(error) };
}

static translateErrorMessage(error: Error): string | JSX.Element {
switch (error.message) {
case "Network Error": return "Błąd połączenia z serwerem."
case "Request failed with status code 401": return (<Flex direction="column" alignItems="center">
<Text>Nie masz dostępu do tej strony będąc niezalogowanym!</Text>
<Link href="/auth/discord" alignSelf="center">Kliknij tutaj aby przejść do logowania.</Link>
</Flex>)
default: return error.message
}
}

componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.log("Uncaught error thrown: " + error + ". Error info: " + errorInfo)
}

render() {
if (this.state.errorMessage) {
return (
<FullScreenDialog title="Błąd">
<Text>Coś poszło nie tak. Wiadomość błędu:</Text>
<Text>{this.state.errorMessage}</Text>
</FullScreenDialog>
);
} else {
return this.props.children;
}
}
}

// idea by David Barral:
// https://medium.com/trabe/catching-asynchronous-errors-in-react-using-error-boundaries-5e8a5fd7b971
// thanks
export const usePromiseError = () => {
const [_, setError] = React.useState(null);
return React.useCallback(err => setError(() => { throw err }), [setError]);
};
123 changes: 106 additions & 17 deletions components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ import {
Box, Button, ButtonProps, Center, Flex, IconButton, LayoutProps, Link,
LinkProps,
Menu, MenuButton, MenuItem, MenuList, Spacer,
Image,
Text,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
import { getProfileByUserId, Profile } from "../lib/profile";
import { getSession } from "../lib/auth";
import { usePromiseError } from "./error_boundary";

const LOGIN_DISCORD_URL = "/api/auth/discord"
const LOGIN_DISCORD_URL = "/auth/discord"

type NavItem = {
title: string;
Expand All @@ -32,18 +38,35 @@ const NAV_ITEMS: Array<NavItem> = [
},
]

const NavBar = () => {
// if profile -> loaded profile for current session successfully
// if null -> not logged in
// if undefined -> page is loading / fetching profile data from api
const [profile, setProfile] = useState<Profile | null | undefined>(undefined)
const throwError = usePromiseError()
useEffect(() => {
let session = getSession()
if (session) {
getProfileByUserId(session.userId)
.then(setProfile)
.catch(throwError)
} else {
setProfile(null)
}
}, [])

return (
<Center>
<Box width="80%" maxWidth="77.5rem" height="8rem" padding="4rem 0rem 4rem 0rem" zIndex="100">
<DesktopNavBar profile={profile} />

<MobileNavBar profile={profile} />
</Box>
</Center>
);
}

const NavBar = () => (
<Center>
<Box width="70%" maxWidth="77.5rem" height="8rem" padding="4rem 0rem 4rem 0rem" zIndex="100">
<DesktopNavBar />

<MobileNavBar />
</Box>
</Center>
)

const DesktopNavBar = () => (
const DesktopNavBar = ({ profile }: { profile: Profile | null | undefined }) => (
<Flex display={{ base: "none", '2xl': "flex" }} alignItems="center">
<Logo />

Expand All @@ -62,14 +85,15 @@ const DesktopNavBar = () => (

<Spacer />

<LoginWithDiscord />
<UserMenu profile={profile} />
</Flex>
)

const MobileNavBar = () => (
const MobileNavBar = ({ profile }: { profile: Profile | null | undefined }) => (
<Box display={{ base: "flex", '2xl': "none" }} alignItems="center">
<Menu>
<MenuButton
id="menu_button"
width="2.5rem"
as={IconButton}
aria-label='Nawigacja'
Expand All @@ -79,7 +103,9 @@ const MobileNavBar = () => (
<MenuList borderWidth="0">
{NAV_ITEMS.map(item => (<MobileNavBarItem key={item.title} {...item} />))}

<MobileNavBarItem display={{ base: "flex", md: "none" }} title="Zaloguj się przez Discord"
<MobileNavBarItem
display={{ base: profile == null ? "flex" : "none", md: "none" }}
title="Zaloguj się przez Discord"
href={LOGIN_DISCORD_URL} />
</MenuList>
</Menu>
Expand All @@ -92,7 +118,9 @@ const MobileNavBar = () => (

<Spacer />

<LoginWithDiscord display={{ base: "none", md: "flex" }} />
<UserMenu profile={profile} buttonProps={{
display: { base: "none", md: "flex" },
}} />
</Box>
)

Expand All @@ -117,12 +145,73 @@ const Logo = (props: LinkProps) => (
</Link>
)

type MenuProps = {
profile: Profile | null | undefined
buttonProps?: ButtonProps
}

const UserMenu = ({ profile, buttonProps }: MenuProps) => {
if (profile === undefined) {
return <></>
} else if (profile === null) {
return <LoginWithDiscord {...buttonProps} />
} else {
return <LoggedInUser profile={profile} />
}
}

const LoginWithDiscord = (props: ButtonProps) => (
<Link href={LOGIN_DISCORD_URL}>
<Button variant="discordLogin" marginLeft="3rem" {...props}>
<Button
variant="userMenu"
textTransform="uppercase"
marginLeft="3rem"
height="2.75rem"
{...props}
>
ZALOGUJ SIĘ PRZEZ DISCORD
</Button>
</Link>
)

const LoggedInUser = ({ profile }: { profile: Profile }) => {
return (
<Menu placement="bottom-end">
<MenuButton
id="menu_button"
as={IconButton}
aria-label='Profil'
icon={
<Flex
variant="userMenu"
height="2.75rem"
borderRadius="5"
bg="#000"
color="#fff"
fontWeight="900"
padding="0.875rem 1.313rem 0.875rem 1.313rem"
alignItems="center"
>
<Image src={profile.avatarUrl} borderRadius="full" maxW="1.75rem" maxH="1.75rem" />

<Text marginLeft="1rem" display={{ base: "none", md: "flex" }}>{profile.name}</Text>
</Flex>
}
variant='ghost'>
</MenuButton>

<MenuList borderWidth="0" minW="0" justifyContent="end">
<MobileNavBarItem
title="Ustawienia"
href="/settings"
/>
<MobileNavBarItem
title="Wyloguj się"
href="/auth/logout"
/>
</MenuList>
</Menu>
);
}

export default NavBar;
22 changes: 15 additions & 7 deletions components/section.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import { Box, Container, Flex, Heading, SimpleGrid, Text } from "@chakra-ui/react";
import { Box, BoxProps, Container, Flex, Heading, SimpleGrid, Text } from "@chakra-ui/react";
import * as CSS from "csstype";

type SectionProps = {
id: string;
id?: string;
title: String;
description: String;
small?: boolean;
children?: JSX.Element | JSX.Element[];
}

export const Section = ({ id, title, description, children }: SectionProps) => (
<Box id={id} margin={5} width="100%">
export const Section = ({ id, title, description, small, children, ...boxProps }: SectionProps & BoxProps) => (
<Box id={id} margin={5} width="100%" {...boxProps}>
<Flex
textAlign={{ base: "center", lg: "start" }}
direction="column"
>
<Heading>{title}</Heading>
<Text marginTop={3} variant="secondary" marginBottom="2rem">{description}</Text>
<Heading fontSize={small ? "1.5rem" : "2.25rem"}>{title}</Heading>
<Text
marginTop="0.5rem"
variant="secondary"
marginBottom={small ? "1rem" : "2rem"}
fontSize={small ? "1rem" : "1.25rem"}
>
{description}
</Text>
</Flex>
{children}
</Box>
Expand All @@ -39,7 +47,7 @@ export const SectionCard = ({ minHeight, children }: SectionCardProps) => (
<Flex
gridColumnStart={1}
gridRowStart={1}
padding={{base: "1.5rem 1.5rem 0 1.5rem", lg: "3.125rem 3.125rem 0 3.125rem"}}
padding={{ base: "1.5rem 1.5rem 0 1.5rem", lg: "3.125rem 3.125rem 0 3.125rem" }}
direction="column"
alignItems="center">
{children}
Expand Down
6 changes: 6 additions & 0 deletions lib/activitylog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type ActivityLog = {
id: number;
createdAt: number;
name: string;
data: any;
}
Loading