Compare commits

...

7 Commits

Author SHA1 Message Date
c12b4a02e1 Merge branch 'main' into feature/81-add-totals-to-logbook-table 2025-05-16 10:23:06 -05:00
f92a858281 adding logbook page totals 2025-05-16 10:20:14 -05:00
c5f9dcce73 adding logbook page totals (#89)
* adding logbook page totals

* adding logbook page totals

* adding logbook page totals
2025-05-16 10:14:28 -05:00
cc8e2f55fe adding logbook page totals 2025-05-16 10:13:01 -05:00
b6be7a9d2c adding logbook page totals 2025-05-16 10:07:15 -05:00
729ab636be adding logbook page totals 2025-05-16 10:02:20 -05:00
a185abf6d8 display multiple kml files on same leaflet map component (#88)
* display multiple kml files on same leaflet map component

* display multiple kml files on same leaflet map component
2025-05-12 19:18:03 -05:00
4 changed files with 736 additions and 301 deletions

View File

@@ -13,7 +13,7 @@
"dependencies": { "dependencies": {
"@azure/msal-browser": "^4.0.1", "@azure/msal-browser": "^4.0.1",
"@azure/msal-react": "^3.0.1", "@azure/msal-react": "^3.0.1",
"@noahspan/noahspan-components": "1.6.0", "@noahspan/noahspan-components": "^1.9.1",
"axios": "^1.7.2", "axios": "^1.7.2",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",

View File

@@ -4,8 +4,6 @@ import { useHttpClient } from '../../hooks/httpClient/UseHttpClient';
import { AxiosInstance, AxiosResponse } from 'axios'; import { AxiosInstance, AxiosResponse } from 'axios';
import { useAccessToken } from '../../hooks/accessToken/UseAcessToken'; import { useAccessToken } from '../../hooks/accessToken/UseAcessToken';
import { useIsAuthenticated } from '@azure/msal-react'; import { useIsAuthenticated } from '@azure/msal-react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Pagination } from 'swiper/modules';
import { MapContainer, TileLayer } from 'react-leaflet'; import { MapContainer, TileLayer } from 'react-leaflet';
import ReactLeafletKml from 'react-leaflet-kml'; import ReactLeafletKml from 'react-leaflet-kml';
import 'swiper/css'; import 'swiper/css';
@@ -46,18 +44,6 @@ const LogTrackMaps = ({ rowKey, trackUrls }: LogTrackMapsProps) => {
}, [trackUrls]) }, [trackUrls])
return ( return (
<>
<Swiper
spaceBetween={30}
pagination={{
clickable: true,
}}
modules={[Pagination]}
className="mySwiper"
>
{tracks.length > 0 && tracks.map((track) => {
return (
<SwiperSlide>
<MapContainer <MapContainer
center={[45.14489, -93.21019]} center={[45.14489, -93.21019]}
scrollWheelZoom={false} scrollWheelZoom={false}
@@ -68,13 +54,10 @@ const LogTrackMaps = ({ rowKey, trackUrls }: LogTrackMapsProps) => {
attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/> />
{tracks.length > 0 && tracks.map((track) => (
<ReactLeafletKml kml={track} /> <ReactLeafletKml kml={track} />
))}
</MapContainer> </MapContainer>
</SwiperSlide>
)
})}
</Swiper>
</>
); );
} }

View File

@@ -1,15 +1,26 @@
import { import {
CellContext,
ColumnDef, ColumnDef,
Icon, HeaderContext,
IconButton,
IconName
} from '@noahspan/noahspan-components'; } from '@noahspan/noahspan-components';
import { ILogbookEntry } from './ILogbookEntry'; import { ILogbookEntry } from './ILogbookEntry';
const columnTotal = (info: HeaderContext<ILogbookEntry, unknown>): number => {
const values: number[] = info.table.getFilteredRowModel().rows.map((row: any) => Number(row.getValue(info.column.id))).filter((value: any) => !Number.isNaN(value));
let total: number = 0;
if (values.length > 0) {
total = values.reduce((accumulator, currentValue) => accumulator + currentValue, total)
}
return total;
}
const pilotName: ColumnDef<ILogbookEntry> = { const pilotName: ColumnDef<ILogbookEntry> = {
id: 'pilotName', id: 'pilotName',
accessorKey: 'pilotName', accessorKey: 'pilotName',
header: 'Pilot' header: 'Pilot',
footer: 'PAGE TOTALS'
} }
const date: ColumnDef<ILogbookEntry> = { const date: ColumnDef<ILogbookEntry> = {
id: 'date', id: 'date',
@@ -48,8 +59,9 @@ const durationOfFlight: ColumnDef<ILogbookEntry> = {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : ''
} }
const notes: ColumnDef<ILogbookEntry> = { const notes: ColumnDef<ILogbookEntry> = {
id: 'notes', id: 'notes',
@@ -85,8 +97,9 @@ export const authColumns: ColumnDef<ILogbookEntry>[] = [
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : ''
}, },
{ {
id: 'landings', id: 'landings',
@@ -99,6 +112,7 @@ export const authColumns: ColumnDef<ILogbookEntry>[] = [
id: 'landingsDay', id: 'landingsDay',
accessorKey: 'landingsDay', accessorKey: 'landingsDay',
header: 'Day', header: 'Day',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
@@ -108,6 +122,7 @@ export const authColumns: ColumnDef<ILogbookEntry>[] = [
id: 'landingsNight', id: 'landingsNight',
accessorKey: 'landingsNight', accessorKey: 'landingsNight',
header: 'Night', header: 'Night',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
@@ -126,28 +141,31 @@ export const authColumns: ColumnDef<ILogbookEntry>[] = [
id: 'instrumentActual', id: 'instrumentActual',
accessorKey: 'instrumentActual', accessorKey: 'instrumentActual',
header: 'Actual', header: 'Actual',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
}, },
{ {
id: 'instrumentSimulated', id: 'instrumentSimulated',
accessorKey: 'instrumentSimulated', accessorKey: 'instrumentSimulated',
header: 'Simulated', header: 'Simulated',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
}, },
{ {
id: 'instrumentApproaches', id: 'instrumentApproaches',
accessorKey: 'instrumentApproaches', accessorKey: 'instrumentApproaches',
header: 'Approaches', header: 'Approaches',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
@@ -157,6 +175,7 @@ export const authColumns: ColumnDef<ILogbookEntry>[] = [
id: 'instrumentHolds', id: 'instrumentHolds',
accessorKey: 'instrumentHolds', accessorKey: 'instrumentHolds',
header: 'Holds', header: 'Holds',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
@@ -166,6 +185,7 @@ export const authColumns: ColumnDef<ILogbookEntry>[] = [
id: 'instrumentNavTrack', id: 'instrumentNavTrack',
accessorKey: 'instrumentNavTrack', accessorKey: 'instrumentNavTrack',
header: 'Nav/Track', header: 'Nav/Track',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
@@ -184,67 +204,73 @@ export const authColumns: ColumnDef<ILogbookEntry>[] = [
id: 'groundTrainingReceived', id: 'groundTrainingReceived',
accessorKey: 'groundTrainingReceived', accessorKey: 'groundTrainingReceived',
header: 'Ground Training Received', header: 'Ground Training Received',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
}, },
{ {
id: 'flightTrainingReceived', id: 'flightTrainingReceived',
accessorKey: 'flightTrainingReceived', accessorKey: 'flightTrainingReceived',
header: 'Flight Training Received', header: 'Flight Training Received',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
}, },
{ {
id: 'crossCountry', id: 'crossCountry',
accessorKey: 'crossCountry', accessorKey: 'crossCountry',
header: 'Cross Country', header: 'Cross Country',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
}, },
{ {
id: 'night', id: 'night',
accessorKey: 'night', accessorKey: 'night',
header: 'Night', header: 'Night',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
}, },
{ {
id: 'solo', id: 'solo',
accessorKey: 'solo', accessorKey: 'solo',
header: 'Solo', header: 'Solo',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
}, },
{ {
id: 'pilotInCommand', id: 'pilotInCommand',
accessorKey: 'pilotInCommand', accessorKey: 'pilotInCommand',
header: 'Pilot In Command', header: 'Pilot In Command',
footer: (info: HeaderContext<ILogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'right',
headerAlign: 'right' headerAlign: 'right'
}, },
cell: (info: any) => cell: (info: CellContext<ILogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue()).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
} }
] ]
}, },

916
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff