Working on email templating, updating with swagger

This commit is contained in:
2025-05-14 20:33:13 -04:00
parent 1e3c75624a
commit e46e8ab9b4
41 changed files with 1124 additions and 189 deletions

View File

@@ -17,11 +17,11 @@ export function CommunicationTable({ communications }: { communications: Communi
<Table.Tr>
<Table.Th>ID</Table.Th>
<Table.Th>Name</Table.Th>
<Table.Th>Frequencies (MHz)</Table.Th>
<Table.Th>MHz</Table.Th>
<Table.Th>Phone</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>{rows}</Table.Tbody>
</Table>
);
}
}

View File

@@ -24,4 +24,4 @@ export function RunwayTable({ runways }: { runways: Runway[] }) {
<Table.Tbody>{rows}</Table.Tbody>
</Table>
);
}
}

View File

@@ -151,10 +151,10 @@ function AirportInfoRow({ style, children }: { style?: CSSProperties; children:
);
}
function AirportInfo({ map, airport }: { map: LeafletMap, airport: Airport }) {
function AirportInfo({ map, airport }: { map: LeafletMap; airport: Airport }) {
function goToLocation(map: LeafletMap, latitude: number, longitude: number) {
if (!map) return
map.setView([latitude, longitude], map.getZoom())
if (!map) return;
map.setView([latitude, longitude], map.getZoom());
}
return (
@@ -171,9 +171,11 @@ function AirportInfo({ map, airport }: { map: LeafletMap, airport: Airport }) {
</AirportInfoSlot>
<AirportInfoSlot title={'Elevation'} style={{ paddingLeft: '1rem' }} children={`${airport.elevation_ft} ft`} />
<AirportInfoSlot style={{ marginLeft: 'auto', paddingLeft: '1rem', paddingTop: '0.5rem' }}>
<UnstyledButton onClick={() => {
goToLocation(map, airport.latitude, airport.longitude)
}}>
<UnstyledButton
onClick={() => {
goToLocation(map, airport.latitude, airport.longitude);
}}
>
<IconViewfinder />
</UnstyledButton>
</AirportInfoSlot>
@@ -181,9 +183,7 @@ function AirportInfo({ map, airport }: { map: LeafletMap, airport: Airport }) {
<Accordion chevronPosition={'right'} variant={'contained'}>
{airport.runways != null && airport.runways.length > 0 && (
<Accordion.Item value={'runways'}>
<Accordion.Control>
Runways
</Accordion.Control>
<Accordion.Control>Runways</Accordion.Control>
<Accordion.Panel>
<RunwayTable runways={airport.runways} />
</Accordion.Panel>
@@ -191,9 +191,7 @@ function AirportInfo({ map, airport }: { map: LeafletMap, airport: Airport }) {
)}
{airport.communications != null && airport.communications.length > 0 && (
<Accordion.Item value={'communication'}>
<Accordion.Control>
Communication
</Accordion.Control>
<Accordion.Control>Communication</Accordion.Control>
<Accordion.Panel>
<CommunicationTable communications={airport.communications} />
</Accordion.Panel>

View File

@@ -20,7 +20,7 @@ export function CustomControl({ position = 'bottomright', onClick, active = fals
const ctrl = new L.Control({ position });
ctrl.onAdd = () => {
return L.DomUtil.create('div', 'leaflet-bar leaflet-control custom-control');
}
};
ctrl.addTo(map);
controlRef.current = ctrl;
@@ -28,6 +28,7 @@ export function CustomControl({ position = 'bottomright', onClick, active = fals
// @ts-expect-error ctrl is a L.Control
const container = (ctrl as unknown)._container as HTMLElement;
rootRef.current = createRoot(container);
L.DomEvent.disableClickPropagation(container);
return () => {
if (rootRef.current) {
@@ -45,7 +46,7 @@ export function CustomControl({ position = 'bottomright', onClick, active = fals
href={'#'}
title={title}
className={active ? 'active' : ''}
onClick={e => {
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onClick();
@@ -59,7 +60,7 @@ export function CustomControl({ position = 'bottomright', onClick, active = fals
>
{children}
</a>
)
);
}
}, [onClick, active, title, children]);

View File

@@ -34,6 +34,7 @@ export function GroupControl({ position = 'bottomright', buttons }: GroupControl
// @ts-expect-error ctrl is a L.Control
const container = (ctrl as unknown)._container as HTMLElement;
rootRef.current = createRoot(container);
L.DomEvent.disableClickPropagation(container);
return () => {
ctrl.remove();
@@ -48,10 +49,10 @@ export function GroupControl({ position = 'bottomright', buttons }: GroupControl
{buttons.map((b, i) => (
<a
key={i}
href="#"
href='#'
title={b.title}
className={b.active ? 'active' : ''}
onClick={e => {
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
b.onClick();

View File

@@ -7,7 +7,7 @@ export function LocateControl() {
function handleClick() {
if (!navigator.geolocation) {
alert('Geolocation is not supported by your browser');
console.warn('Geolocation is not supported by your browser');
return;
}
navigator.geolocation.getCurrentPosition(
@@ -17,15 +17,14 @@ export function LocateControl() {
map.setView([latitude, longitude], map.getZoom());
},
(err) => {
console.error(err);
alert('Unable to retrieve your location');
console.warn('Unable to retrieve your location', err);
}
);
}
return (
<CustomControl onClick={handleClick} title="Go to my location">
<CustomControl onClick={handleClick} title='Go to my location'>
<IconCurrentLocation />
</CustomControl>
);
}
}

View File

@@ -3,20 +3,36 @@ import { UserContext } from './UserContext.tsx';
import { profile } from '@lib/account.ts';
import { User } from '@lib/account.types.ts';
import { Center, Loader } from '@mantine/core';
import Cookies from 'js-cookie';
const sessionExpirationName = 'session_expiration';
export function UserProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | undefined>(undefined);
const [loading, setLoading] = useState(true);
useEffect(() => {
profile().then((refreshUser) => {
if (refreshUser) {
setUser(refreshUser);
const sessionExpiration = Cookies.get(sessionExpirationName);
if (sessionExpiration != undefined) {
const date = new Date(parseInt(sessionExpiration) * 1000);
const now = new Date();
if (date > now) {
profile().then((refreshUser) => {
if (refreshUser) {
setUser(refreshUser);
} else {
setUser(undefined);
}
setLoading(false);
});
} else {
setUser(undefined);
Cookies.remove(sessionExpirationName);
setLoading(false);
}
} else {
setLoading(false);
});
}
}, []);
return (