Working on airport drawer

This commit is contained in:
2025-05-28 21:21:25 -04:00
parent 25608db372
commit 7dedc7a8dc
5 changed files with 79 additions and 10 deletions

View File

@@ -45,11 +45,13 @@ async fn register(user: web::Json<RegisterRequest>, req: HttpRequest) -> HttpRes
// Send confirmation email
if let Some(email) = email {
tokio::spawn(async move {
if let Err(err) = send_confirm_email(&email, &ip_address).await {
log::error!("Failed to send confirmation email: {}", err);
};
});
if !email.is_empty() {
tokio::spawn(async move {
if let Err(err) = send_confirm_email(&email, &ip_address).await {
log::error!("Failed to send confirmation email: {}", err);
};
});
}
}
HttpResponse::Created().json(user_response)

View File

@@ -2,6 +2,7 @@
force=0
push=0
push_all=0
API_VERSION=$(sed -n 's/^version *= *"\([^"]*\)".*/\1/p' "$(pwd)"/api/Cargo.toml)
UI_VERSION=$(sed -n 's/.*"version": *"\([^"]*\)".*/\1/p' "$(pwd)"/ui/package.json)
@@ -17,6 +18,13 @@ for arg in "$@"; do
push=1
shift
;;
-a|--push-all)
push_all=1
shift
;;
*)
shift
;;
esac
done
@@ -69,3 +77,14 @@ if echo "$changed_files" | grep -q "^api/"; then
fi
fi
fi
# Push all tags
if [ $push_all -eq 1 ]; then
if [ $force -eq 1 ]; then
echo "Force-pushing ALL tags to remote"
git push -f origin --tags
else
echo "Pushing ALL tags to remote"
git push origin --tags
fi
fi

View File

@@ -1,10 +1,10 @@
import {
Accordion,
Badge,
Box,
Box, Button,
Divider,
Drawer,
Group,
Group, Stack,
Tabs,
TabsList,
Text,
@@ -15,12 +15,13 @@ import { Airport, AirportCategory } from '@lib/airport.types.ts';
import { getMarkerColor, Metar } from '@lib/metar.types.ts';
import { CSSProperties, forwardRef, ReactNode, useEffect, useState } from 'react';
import { useMediaQuery } from '@mantine/hooks';
import { IconViewfinder } from '@tabler/icons-react';
import { IconStar, IconStarFilled, IconViewfinder } from '@tabler/icons-react';
import { RunwayTable } from '@components/AirportDrawer/RunwayTable.tsx';
import { CommunicationTable } from '@components/AirportDrawer/CommunicationTable.tsx';
import { useMap } from 'react-leaflet';
import type { Map as LeafletMap } from 'leaflet';
import { getMetars } from '@lib/metar.ts';
import { useUserContext } from '@components/context/UserContext.tsx';
export function AirportDrawer({
airport,
@@ -29,6 +30,9 @@ export function AirportDrawer({
airport: Airport | null;
setAirport: (airport: Airport | null) => void;
}) {
const { user, favorites, toggleFavorite } = useUserContext();
const isAdmin = user?.role === 'ADMIN';
const isFavorite = airport ? favorites.includes(airport.icao) : false;
const [metar, setMetar] = useState<Metar | undefined>(undefined);
const isMobile = useMediaQuery('(max-width: 768px)');
const map = useMap();
@@ -73,6 +77,15 @@ export function AirportDrawer({
>
<Drawer.Content>
<Drawer.Header>
<UnstyledButton
onClick={() => toggleFavorite(airport.icao)}
aria-label={isFavorite ? 'Unfavorite airport' : 'Favorite airport'}
style={{ padding: 4 }}
>
{isFavorite
? <IconStarFilled size={24} color="#faca15" />
: <IconStar size={24} />}
</UnstyledButton>
<Drawer.Title>
<Text size={'xl'}>{airport.name}</Text>
</Drawer.Title>
@@ -104,6 +117,7 @@ export function AirportDrawer({
<TabsList grow>
<Tabs.Tab value={'info'}>Info</Tabs.Tab>
<Tabs.Tab value={'weather'}>Weather</Tabs.Tab>
{ user && <Tabs.Tab value={'manage'}>Manage</Tabs.Tab> }
</TabsList>
<Tabs.Panel value={'info'}>
<AirportInfo map={map} airport={airport} />
@@ -111,6 +125,23 @@ export function AirportDrawer({
<Tabs.Panel value={'weather'}>
<WeatherInfo metar={airport.latest_metar} />
</Tabs.Panel>
{user && (
<Tabs.Panel value={'manage'}>
{isAdmin ? (
<Stack mt="md">
<Button onClick={() => {}}>Update METAR</Button>
<Button onClick={() => {}}>Edit Airport</Button>
<Button color="red" onClick={() => {}}>
Delete Airport
</Button>
</Stack>
) : (
<Stack mt="md">
<Button onClick={() => {}}>Request Edit</Button>
</Stack>
)}
</Tabs.Panel>
)}
</Tabs>
</Box>
</Drawer.Body>

View File

@@ -5,12 +5,16 @@ interface UserContextType {
user?: User;
setUser: (user: User | undefined) => void;
loading: boolean;
favorites: string[];
toggleFavorite: (icao: string) => void;
}
export const UserContext = createContext<UserContextType>({
user: undefined,
setUser: () => {},
loading: true
loading: true,
favorites: [],
toggleFavorite: () => {},
});
export function useUserContext(): UserContextType {

View File

@@ -9,8 +9,21 @@ const sessionExpirationName = 'session_expiration';
export function UserProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | undefined>(undefined);
const [favorites, setFavorites] = useState<string[]>(() => {
return JSON.parse(localStorage.getItem('favorites') || '[]')
})
const [loading, setLoading] = useState(true);
const toggleFavorite = (icao: string) => {
setFavorites((prev) => {
const next = prev.includes(icao)
? prev.filter((i) => i !== icao)
: [...prev, icao]
localStorage.setItem('favorites', JSON.stringify(next))
return next
})
}
useEffect(() => {
const sessionExpiration = Cookies.get(sessionExpirationName);
@@ -36,7 +49,7 @@ export function UserProvider({ children }: { children: ReactNode }) {
}, []);
return (
<UserContext.Provider value={{ user, setUser, loading }}>
<UserContext.Provider value={{ user, setUser, loading, favorites, toggleFavorite }}>
{loading ? (
<Center style={{ height: '100vh' }}>
<Loader size='xl' />