Tweaks, working on api error handling

This commit is contained in:
Benjamin Sherriff
2023-10-23 20:19:17 -04:00
parent 3eb888b57d
commit 8c246c96e7
7 changed files with 104 additions and 47 deletions

View File

@@ -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<string, any> = {}): P
interface PostOptions {
headers?: Record<string, any>;
type?: 'json' | 'form';
}
export async function post(endpoint: string, body = {}, options?: PostOptions): Promise<Response> {
export async function post(endpoint: string, body: any, options?: PostOptions): Promise<Response> {
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;
}

View File

@@ -11,10 +11,10 @@ export async function getPicture(): Promise<Blob | undefined> {
export async function setPicture(payload: File): Promise<boolean> {
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;

View File

@@ -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 <div>Logged in as {user.email}</div>;
return (
<Container mt={'2rem'}>
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing={'md'}>
<Card withBorder radius='md' padding='xl'>
<Card.Section p={'1rem'}>
<h2>
{user.first_name} {user.last_name}
</h2>
{user.role}
</Card.Section>
</Card>
<Grid gutter={'md'}>
<Grid.Col>
<Card withBorder radius='md' padding='xl'>
<Card.Section p={'1rem'}>test</Card.Section>
</Card>
</Grid.Col>
<Grid.Col>
<Card withBorder radius='md' padding='xl'>
<Card.Section p={'1rem'}>test</Card.Section>
</Card>
</Grid.Col>
</Grid>
</SimpleGrid>
</Container>
);
} else {
return <div>Not logged in</div>;
return <></>;
}
}

View File

@@ -90,9 +90,9 @@ function SpellSection({ title, spells, onClick }: { title: string; spells: Spell
<Box>
<h2>{title}</h2>
<ul>
{spells.map((spell) => (
{spells.map((spell, index) => (
<li
key={spell.id}
key={`spell-${index}`}
className='link spell-item'
style={{ width: 'fit-content' }}
onClick={() => onClick(spell)}

View File

@@ -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() {
)}
</div>
</nav>
<HeaderModal type={modalType} toggle={toggle} setUser={setUser} setRefreshId={setRefreshId} />
<HeaderModal
type={modalType}
toggle={toggle}
setUser={(u) => {
setUser(u);
getPicture().then((response) => {
if (response) {
setProfilePicture(response as File);
}
});
}}
setRefreshId={setRefreshId}
/>
</>
);
}

View File

@@ -38,8 +38,8 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps)
</Grid.Col>
<Grid.Col span={6}>
<span style={{ fontWeight: 'bold', paddingRight: '1em' }}>Sources:</span>
{spell.sources.map((s) => (
<span style={{ paddingRight: '0.6em' }}>
{spell.sources.map((s, index) => (
<span style={{ paddingRight: '0.6em' }} key={`spell-source-${index}`}>
{s.source}
{s.page ? `.${s.page}` : ''}
</span>
@@ -48,8 +48,12 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps)
<Grid.Col span={6}>
<span style={{ fontWeight: 'bold', marginRight: '1em' }}>Classes:</span>
<span style={{ overflowWrap: 'break-word' }}>
{spell.classes.map((c) => (
<span style={{ paddingRight: '0.6em', display: 'inline-block' }} className='link'>
{spell.classes.map((c, index) => (
<span
style={{ paddingRight: '0.6em', display: 'inline-block' }}
className='link'
key={`spell-class-${index}`}
>
{parseText(c, true)}
</span>
))}
@@ -71,8 +75,8 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps)
<Grid.Col span={6}>
<span style={{ fontWeight: 'bold', paddingRight: '1em' }}>Duration:</span>
<span style={{ paddingRight: '0.6em' }}>
{spell.durations.map((d) => (
<span>
{spell.durations.map((d, index) => (
<span key={`duration-${index}`}>
{capitalize(d.type)} {d.value} {capitalize(d.unit)}
</span>
))}
@@ -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) => (
<div key={`spell-description-${index}`}>
{e.text && <p>{parseText(e.text)}</p>}
{e.list && (
<ul>
{e.list.map((text) => (
<li>{parseText(text)}</li>
{e.list.map((text, index) => (
<li key={`spell-text-${index}`}>{parseText(text)}</li>
))}
</ul>
)}
@@ -167,23 +170,23 @@ function SpellDescription({ spell }: { spell: Spell }) {
<table>
<thead>
<tr>
{e.table.headers.map((label) => (
<th>{label}</th>
{e.table.headers.map((label, index) => (
<th key={`spell-header-${index}`}>{label}</th>
))}
</tr>
</thead>
<tbody>
{e.table.rows.map((row) => (
<tr>
{row.map((cell) => (
<td>{parseText(cell)}</td>
{e.table.rows.map((row, index) => (
<tr key={`spell-row-${index}`}>
{row.map((cell, index) => (
<td key={`spell-cell-${index}`}>{parseText(cell)}</td>
))}
</tr>
))}
</tbody>
</table>
)}
</>
</div>
))}
</>
)}