Files
noahspan-flying/app/src/components/logTracks/LogTracks.tsx
noahspannbauer f76244d00c Feature/73 add flights page (#75)
* adding flights page

* adding flights page

* adding flights page
2025-03-23 11:09:25 -05:00

209 lines
7.1 KiB
TypeScript

import { useEffect, useReducer } from "react";
import { Button, Drawer, Grid, Icon, IconButton, IconName, Spinner, TextField, theme, Typography, useMediaQuery } from "@noahspan/noahspan-components";
import { useHttpClient } from "../../hooks/httpClient/UseHttpClient";
import { AxiosInstance, AxiosResponse } from "axios";
import { useAccessToken } from "../../hooks/accessToken/UseAcessToken";
import { LogTracksProps } from "./LogTracksProps.interface";
import { FormMode } from "../../enums/formMode";
import { useIsAuthenticated } from "@azure/msal-react";
import { ILogbookEntry } from "../logbook/ILogbookEntry";
import ConfirmationDialog from "../confirmationDialog/ConfirmationDialog";
import { initialState, reducer } from "./reducer";
import LogTrackMaps from "../logTrackMaps/LogTrackMaps";
const LogTracks = ({ isDrawerOpen, mode, onOpenClose, selectedRowKey }: LogTracksProps) => {
const [state, dispatch] = useReducer(reducer, initialState)
const httpClient: AxiosInstance = useHttpClient();
const { getAccessToken } = useAccessToken();
const isAuthenticated = useIsAuthenticated();
const isMedium = useMediaQuery(theme.breakpoints.up('md'));
const getConfig = async () => {
const config = isAuthenticated
? { headers: { Authorization: await getAccessToken() } }
: {};
return config
}
const getLog = async (): Promise<ILogbookEntry> => {
const logResponse: AxiosResponse = await httpClient.get(
`api/logs/log/${selectedRowKey}`,
await getConfig()
);
const logData: ILogbookEntry = logResponse.data;
return logData
}
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
try {
dispatch({ type: 'SET_IS_LOADING', payload: true})
const file = event.target.files![0]
const formData = new FormData();
const config = await getConfig();
const formDataConfig = {
headers: {
...config.headers,
'Content-Type': 'multipart/form-data'
}
}
formData.append('file', file);
const uploadResponse: AxiosResponse = await httpClient.post(`api/logs/log/${selectedRowKey}/track`, formData, formDataConfig);
const uploadUrl = uploadResponse.data.url;
const log = await getLog();
const tracks: string[] = JSON.parse(log.tracks!);
tracks.push(uploadUrl)
log.tracks = JSON.stringify(tracks);
await httpClient.put(`api/logs/log/${selectedRowKey}`, log, config);
const updatedLog = await getLog();
dispatch({ type: 'SET_TRACKS', payload: JSON.parse(updatedLog.tracks!) })
} catch (error) {
console.log(error)
} finally {
dispatch({ type: 'SET_IS_LOADING', payload: false });
}
}
const onCancel = () => {
onOpenClose(FormMode.CANCEL)
}
const onDeleteTrack = async (fileName: string, index: number) => {
dispatch({ type: 'SET_ON_DELETE_TRACK', payload: { isConfirmDialogOpen: true, selectedTrack: { fileName: fileName, index: index }}})
}
const onConfirmDialogConfirm = async () => {
try {
const config = await getConfig();
await httpClient.delete(`api/logs/log/${selectedRowKey}/track?fileName=${state.selectedTrack!.fileName}`, config);
const log = await getLog();
const tracks: string[] = JSON.parse(log.tracks!);
tracks.splice(state.selectedTrack!.index, 1);
log.tracks = JSON.stringify(tracks);
await httpClient.put(`api/logs/log/${selectedRowKey}`, log, config);
const updatedLog = await getLog();
dispatch({ type: 'SET_TRACKS', payload: JSON.parse(updatedLog.tracks!) })
dispatch({ type: 'SET_IS_CONFIRM_DIALOG_OPEN', payload: false })
} catch (error) {
console.log(error);
}
}
const onConfirmDialogCancel = async () => {
dispatch({ type: 'SET_IS_CONFIRM_DIALOG_OPEN', payload: false })
}
useEffect(() => {
const updateTracks = async () => {
const log = await getLog();
dispatch({ type: 'SET_TRACKS', payload: JSON.parse(log.tracks!) });
}
updateTracks();
}, [])
return (
<Drawer
open={isDrawerOpen}
anchor='right'
PaperProps={{
sx: {
padding: '30px',
width: isMedium ? '33%' : '75%'
}
}}
>
<Grid container spacing={2}>
<Grid size={11}>
<Typography variant="h4">{`${mode.toString().toLowerCase().charAt(0).toUpperCase() + mode.toString().slice(1).toLowerCase()} Tracks`}</Typography>
</Grid>
<Grid display="flex" justifyContent="right" size={1}>
<IconButton disabled={state.isLoading ? true : false} onClick={onCancel}>
<Icon iconName={IconName.XMARK} />
</IconButton>
</Grid>
{mode === FormMode.EDIT &&
<>
{state.isLoading &&
<>
<Grid display="flex" justifyContent="center" size={12}>
<Spinner />
</Grid>
<Grid display="flex" justifyContent="center" size={12}>
Loading...
</Grid>
</>
}
{!state.isLoading && state.tracks.length > 0 && state.tracks.map((track, index) => {
const trackSplit = track.split('/')
const filename = trackSplit[trackSplit.length - 1];
return (
<>
<Grid size={11}>
<TextField disabled={true} fullWidth value={filename} />
</Grid>
<Grid size={1}>
<IconButton onClick={() => onDeleteTrack(filename, index)}><Icon iconName={IconName.TRASH} /></IconButton>
</Grid>
</>
)
})}
<Grid display='flex' gap={2} justifyContent='right' size={12}>
<Button
disabled={state.isLoading ? true : false}
startIcon={<Icon iconName={IconName.XMARK} />}
variant="outlined"
onClick={onCancel}
size="small"
>
{mode.toString() !== FormMode.VIEW ? 'Cancel' : 'Close'}
</Button>
{mode.toString() !== FormMode.VIEW && (
<Button
component='label'
disabled={state.isLoading ? true : false}
startIcon={<Icon iconName={IconName.UPLOAD} />}
variant='contained'
>
Upload Track
<input hidden onChange={handleFileUpload} type='file' />
</Button>
)}
</Grid>
</>
}
{mode === FormMode.VIEW &&
<LogTrackMaps rowKey={selectedRowKey!} trackUrls={state.tracks} />
}
</Grid>
{state.isConfirmDialogOpen && (
<ConfirmationDialog
contentText="Are you sure you want to delete this track?"
isLoading={state.isConfirmDialogLoading}
isOpen={state.isConfirmDialogOpen}
onCancel={onConfirmDialogCancel}
onConfirm={onConfirmDialogConfirm}
title="Confirm Delete"
/>
)}
</Drawer>
)
}
export default LogTracks;