From 8c246c96e7ff0c40cd2991f69318b93dc348b8b4 Mon Sep 17 00:00:00 2001 From: Benjamin Sherriff Date: Mon, 23 Oct 2023 20:19:17 -0400 Subject: [PATCH] Tweaks, working on api error handling --- ui/src/api/index.ts | 18 ++++++++----- ui/src/api/users.ts | 4 +-- ui/src/app/profile/page.tsx | 30 ++++++++++++++++++++-- ui/src/app/spells/page.tsx | 4 +-- ui/src/components/Header/index.tsx | 28 ++++++++++++++------ ui/src/components/SpellModal.tsx | 41 ++++++++++++++++-------------- ui/tsconfig.json | 26 ++++++++++++++----- 7 files changed, 104 insertions(+), 47 deletions(-) diff --git a/ui/src/api/index.ts b/ui/src/api/index.ts index 4aa2eee..b5f4076 100644 --- a/ui/src/api/index.ts +++ b/ui/src/api/index.ts @@ -1,5 +1,3 @@ -// import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; - const serviceHost = process.env.SERVICE_HOST || 'http://localhost'; const servicePort = process.env.SERVICE_PORT || 5000; const baseURL = `${serviceHost}:${servicePort}`; @@ -18,17 +16,23 @@ export async function get(endpoint: string, params: Record = {}): P interface PostOptions { headers?: Record; + type?: 'json' | 'form'; } -export async function post(endpoint: string, body = {}, options?: PostOptions): Promise { +export async function post(endpoint: string, body: any, options?: PostOptions): Promise { const url = `${baseURL}/${endpoint}`; + const headers = options?.headers || {}; + if (!options?.type || options.type === 'json') { + body = JSON.stringify(body); + headers['Content-Type'] = 'application/json'; + } else if (options.type === 'form') { + headers['Content-Type'] = 'multipart/form-data'; + } const response = await fetch(url, { method: 'POST', - headers: options?.headers || { - 'Content-Type': 'application/json' - }, + headers: headers, credentials: 'include', - body: JSON.stringify(body) + body }); return response; } diff --git a/ui/src/api/users.ts b/ui/src/api/users.ts index 3331602..c6ece1f 100644 --- a/ui/src/api/users.ts +++ b/ui/src/api/users.ts @@ -11,10 +11,10 @@ export async function getPicture(): Promise { export async function setPicture(payload: File): Promise { const data = new FormData(); - data.append('file', payload); + data.append('data', payload); // TODO: Figure out why the form data object is empty const response = await post('users/picture', data, { - headers: { 'Content-Type': 'multipart/form-data' } + type: 'form' }); if (response?.status === 200) { return true; diff --git a/ui/src/app/profile/page.tsx b/ui/src/app/profile/page.tsx index 96a50d0..1507597 100644 --- a/ui/src/app/profile/page.tsx +++ b/ui/src/app/profile/page.tsx @@ -5,6 +5,7 @@ import React, { useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { useRecoilState } from 'recoil'; import { userState } from '@/state/auth'; +import { Card, Container, Grid, SimpleGrid } from '@mantine/core'; export default function Page() { const [user, setUser] = useRecoilState(userState); @@ -23,8 +24,33 @@ export default function Page() { }, [user]); if (user) { - return
Logged in as {user.email}
; + return ( + + + + +

+ {user.first_name} {user.last_name} +

+ {user.role} +
+
+ + + + test + + + + + test + + + +
+
+ ); } else { - return
Not logged in
; + return <>; } } diff --git a/ui/src/app/spells/page.tsx b/ui/src/app/spells/page.tsx index ae12099..1cf1dad 100644 --- a/ui/src/app/spells/page.tsx +++ b/ui/src/app/spells/page.tsx @@ -90,9 +90,9 @@ function SpellSection({ title, spells, onClick }: { title: string; spells: Spell

{title}

    - {spells.map((spell) => ( + {spells.map((spell, index) => (
  • onClick(spell)} diff --git a/ui/src/components/Header/index.tsx b/ui/src/components/Header/index.tsx index 85b27e5..ce51b26 100644 --- a/ui/src/components/Header/index.tsx +++ b/ui/src/components/Header/index.tsx @@ -106,6 +106,7 @@ export default function Header() { mx={'auto'} mt={-30} style={{ cursor: 'pointer' }} + bg={profilePicture ? 'transparent' : 'white'} src={profilePicture ? URL.createObjectURL(profilePicture) : undefined} /> )} @@ -131,13 +132,12 @@ export default function Header() { size='xs' variant='default' onClick={async () => { - const response = await logout(); - if (response?.status == 200) { - Cookies.remove('logged_in'); - if (refreshId) { - clearInterval(refreshId); - } - setUser(undefined); + await logout(); + Cookies.remove('logged_in'); + setUser(undefined); + setProfilePicture(null); + if (refreshId) { + clearInterval(refreshId); } }} > @@ -167,7 +167,19 @@ export default function Header() { )} - + { + setUser(u); + getPicture().then((response) => { + if (response) { + setProfilePicture(response as File); + } + }); + }} + setRefreshId={setRefreshId} + /> ); } diff --git a/ui/src/components/SpellModal.tsx b/ui/src/components/SpellModal.tsx index 2c28f2a..0e537f7 100644 --- a/ui/src/components/SpellModal.tsx +++ b/ui/src/components/SpellModal.tsx @@ -38,8 +38,8 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps) Sources: - {spell.sources.map((s) => ( - + {spell.sources.map((s, index) => ( + {s.source} {s.page ? `.${s.page}` : ''} @@ -48,8 +48,12 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps) Classes: - {spell.classes.map((c) => ( - + {spell.classes.map((c, index) => ( + {parseText(c, true)} ))} @@ -71,8 +75,8 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps) Duration: - {spell.durations.map((d) => ( - + {spell.durations.map((d, index) => ( + {capitalize(d.type)} {d.value} {capitalize(d.unit)} ))} @@ -86,7 +90,7 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps) ); } -function parseText(text: string, capitalizeFirst?: boolean) { +function parseText(text: string, capitalizeFirst?: boolean): (string | JSX.Element)[] { const regex = /{@(.*?) (.*?)}/g; const matches = text.matchAll(regex); const result = []; @@ -148,18 +152,17 @@ function handleLink(type: string, name: string) { } function SpellDescription({ spell }: { spell: Spell }) { - return ( <> {spell.description && ( <> - {spell.description.entries.map((e) => ( - <> + {spell.description.entries.map((e, index) => ( +
    {e.text &&

    {parseText(e.text)}

    } {e.list && (
      - {e.list.map((text) => ( -
    • {parseText(text)}
    • + {e.list.map((text, index) => ( +
    • {parseText(text)}
    • ))}
    )} @@ -167,23 +170,23 @@ function SpellDescription({ spell }: { spell: Spell }) { - {e.table.headers.map((label) => ( - + {e.table.headers.map((label, index) => ( + ))} - {e.table.rows.map((row) => ( - - {row.map((cell) => ( - + {e.table.rows.map((row, index) => ( + + {row.map((cell, index) => ( + ))} ))}
    {label}{label}
    {parseText(cell)}
    {parseText(cell)}
    )} - +
    ))} )} diff --git a/ui/tsconfig.json b/ui/tsconfig.json index b6a416d..597235c 100755 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -13,7 +13,7 @@ "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, - "module": "ES2022", + "module": "esnext", "moduleResolution": "Node", "resolveJsonModule": true, "isolatedModules": true, @@ -26,12 +26,24 @@ ], "baseUrl": ".", "paths": { - "@/*": ["./src/*"], - "@api/*": ["src/api"], - "@app/*": ["./src/app/*"], - "@components/*": ["src/components/*"], - "@js/*": ["src/js/*"], - "@state/*": ["src/state/*"] + "@/*": [ + "./src/*" + ], + "@api/*": [ + "src/api" + ], + "@app/*": [ + "./src/app/*" + ], + "@components/*": [ + "src/components/*" + ], + "@js/*": [ + "src/js/*" + ], + "@state/*": [ + "src/state/*" + ] } }, "include": [