Fixed layouts
This commit is contained in:
@@ -4,29 +4,41 @@ import { Airport } from "@/api/airport.types";
|
||||
import AirportTablePanel from "@/components/Admin/AirportTablePanel";
|
||||
import CreateAirportPanel from "@/components/Admin/CreateAirportPanel";
|
||||
import UpdateAirportModal from "@/components/Admin/UpdateAirportModal";
|
||||
import { isAdminState } from "@/state/auth";
|
||||
import { Container, Grid, SimpleGrid } from "@mantine/core";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRecoilValue } from "recoil";
|
||||
|
||||
export default function Page() {
|
||||
const [airport, setAirport] = useState<Airport | undefined>(undefined);
|
||||
const isAdmin = useRecoilValue(isAdminState);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAdmin) {
|
||||
router.push('/');
|
||||
}
|
||||
}, [airport]);
|
||||
|
||||
return (
|
||||
<Container fluid>
|
||||
<SimpleGrid cols={{ base: 1, xs: 1 }} spacing={'md'}>
|
||||
<Grid p={'lg'}>
|
||||
<Grid.Col span={12}>
|
||||
<AirportTablePanel setAirport={setAirport} />
|
||||
<>
|
||||
{isAdmin && (
|
||||
<Container fluid>
|
||||
<SimpleGrid cols={{ base: 1, xs: 1 }} spacing={'md'}>
|
||||
<Grid p={'lg'}>
|
||||
<Grid.Col span={12}>
|
||||
<AirportTablePanel setAirport={setAirport} />
|
||||
</Grid.Col>
|
||||
<Grid.Col span={12}>
|
||||
<CreateAirportPanel />
|
||||
</Grid.Col>
|
||||
<Grid.Col span={12}>
|
||||
<CreateAirportPanel />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</SimpleGrid>
|
||||
<UpdateAirportModal airport={airport} setAirport={setAirport} />
|
||||
</Container>
|
||||
</Grid>
|
||||
</SimpleGrid>
|
||||
<UpdateAirportModal airport={airport} setAirport={setAirport} />
|
||||
</Container>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getAirport } from '@/api/airport';
|
||||
import { Airport } from '@/api/airport.types';
|
||||
import { getMetars } from '@/api/metar';
|
||||
import { Metar } from '@/api/metar.types';
|
||||
import SkyConditions from '@/components/Metars/SkyConditions';
|
||||
import { Grid, Title, Text } from '@mantine/core';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export default function Page({ params }: { params: { icao: string } }) {
|
||||
@@ -25,12 +25,14 @@ export default function Page({ params }: { params: { icao: string } }) {
|
||||
|
||||
if (airport) {
|
||||
return (
|
||||
<>
|
||||
<div className=''>
|
||||
<h3 className=''>{airport.name}</h3>
|
||||
{metar && <SkyConditions metar={metar} />}
|
||||
</div>
|
||||
</>
|
||||
<Grid gutter={80} style={{ margin: '1em auto 0'}}>
|
||||
<Grid.Col span={12}>
|
||||
<Title className='title' order={1}>{airport.icao} - {airport.name}</Title>
|
||||
<Text c="dimmed">
|
||||
{airport.municipality} | {airport.iso_region} | {airport.iso_country}
|
||||
</Text>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
);
|
||||
} else {
|
||||
return <></>;
|
||||
|
||||
@@ -1,3 +1,159 @@
|
||||
export default async function Page() {
|
||||
return <></>;
|
||||
'use client';
|
||||
|
||||
import { getAirports } from "@/api/airport";
|
||||
import { Airport } from "@/api/airport.types";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRecoilState, useRecoilValue } from "recoil";
|
||||
import { Badge, Button, Card, Grid, Group, SimpleGrid, Text, Title } from "@mantine/core";
|
||||
import classes from './profile.module.css';
|
||||
import { getFavorites, removeFavorite } from "@/api/users";
|
||||
import { getMetars } from "@/api/metar";
|
||||
import { Metar } from "@/api/metar.types";
|
||||
import { MdLocationSearching } from 'react-icons/md';
|
||||
import { useRouter } from "next/navigation";
|
||||
import { coordinatesState } from "@/state/map";
|
||||
import { userState } from "@/state/auth";
|
||||
|
||||
export default function Page() {
|
||||
const user = useRecoilValue(userState);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (!user) {
|
||||
router.push('/');
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid gutter={80}>
|
||||
<Grid.Col span={12}>
|
||||
<Card shadow="sm" m={"lg"} padding="lg" radius="md" withBorder>
|
||||
<Title className={classes.title} order={2}>
|
||||
{user?.first_name} {user?.last_name}
|
||||
</Title>
|
||||
<hr />
|
||||
<Text c="dimmed">
|
||||
|
||||
</Text>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={12}>
|
||||
<TopSection />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
function TopSection() {
|
||||
const [airports, setAirports] = useState<Airport[]>([]);
|
||||
const [metars, setMetars] = useState<Metar[]>([]);
|
||||
const router = useRouter();
|
||||
const [_, setCoordinates] = useRecoilState(coordinatesState);
|
||||
|
||||
useEffect(() => {
|
||||
updateFavorites();
|
||||
}, []);
|
||||
|
||||
function metarColor(metar?: Metar): string {
|
||||
switch (metar?.flight_category) {
|
||||
case 'VFR':
|
||||
return 'green';
|
||||
case 'MVFR':
|
||||
return 'blue';
|
||||
case 'IFR':
|
||||
return 'red';
|
||||
case 'LIFR':
|
||||
return 'purple';
|
||||
default:
|
||||
return 'gray';
|
||||
}
|
||||
}
|
||||
|
||||
function AirportCard(airport: Airport) {
|
||||
let metar = metars.find((m) => m.station_id === airport.icao);
|
||||
let color = metarColor(metar);
|
||||
let text = metar?.flight_category || 'UNKN';
|
||||
|
||||
return (
|
||||
<Card key={airport.icao} shadow="sm" padding="lg" radius="md" withBorder>
|
||||
<Group justify="space-between" mt="md" mb="xs">
|
||||
<Text fw={500} style={{ textOverflow: 'ellipsis', overflow: 'hidden', whiteSpace: 'nowrap', width: '20em' }}>{airport.name}</Text>
|
||||
<Badge color={color} variant="light">{text}</Badge>
|
||||
</Group>
|
||||
<Group style={{ cursor: 'pointer', userSelect: 'none' }} onClick={() => {
|
||||
setCoordinates({
|
||||
lat: airport.latitude,
|
||||
lon: airport.longitude,
|
||||
});
|
||||
router.push('/');
|
||||
}}>
|
||||
<MdLocationSearching size={20} />
|
||||
<Text size="sm" c="dimmed">
|
||||
{airport.latitude.toFixed(3)}, {airport.longitude.toFixed(3)}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'end',
|
||||
alignItems: 'center',
|
||||
}}>
|
||||
<Button
|
||||
variant="outline"
|
||||
color="blue"
|
||||
size="sm"
|
||||
radius="lg"
|
||||
style={{ marginTop: '10px' }}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
color="red"
|
||||
size="sm"
|
||||
radius="lg"
|
||||
style={{ marginTop: '10px' }}
|
||||
onClick={async () => {
|
||||
await removeFavorite(airport.icao);
|
||||
await updateFavorites();
|
||||
}}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
</Group>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
async function updateFavorites() {
|
||||
const favorites = await getFavorites();
|
||||
const m = (await getMetars(favorites)).data;
|
||||
setMetars(m);
|
||||
const a = (await getAirports({ icaos: favorites })).data;
|
||||
setAirports(a);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.wrapper}>
|
||||
<Grid gutter={80}>
|
||||
<Grid.Col span={{ base: 12, md: 5 }}>
|
||||
<Title className={classes.title} order={2}>
|
||||
Logbook
|
||||
</Title>
|
||||
<hr />
|
||||
<Text c="dimmed">
|
||||
Your logbook is a list of your flights. You can add flights to your logbook by clicking the "Add to logbook" button on the flight page.
|
||||
</Text>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={{ base: 12, md: 7 }}>
|
||||
<Title className={classes.title} order={2}>
|
||||
Saved Airports
|
||||
</Title>
|
||||
<hr />
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing={30}>
|
||||
{airports.map((airport) => AirportCard(airport))}
|
||||
</SimpleGrid>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
14
ui/src/app/profile/profile.module.css
Normal file
14
ui/src/app/profile/profile.module.css
Normal file
@@ -0,0 +1,14 @@
|
||||
.wrapper {
|
||||
padding: calc(var(--mantine-spacing-xl) * 2) var(--mantine-spacing-xl);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-family:
|
||||
Greycliff CF,
|
||||
var(--mantine-font-family);
|
||||
font-size: rem(36px);
|
||||
font-weight: 900;
|
||||
line-height: 1.1;
|
||||
margin-bottom: var(--mantine-spacing-md);
|
||||
color: light-dark(var(--mantine-color-black), var(--mantine-color-white));
|
||||
}
|
||||
Reference in New Issue
Block a user