adding logbook entry delete (#31)
This commit was merged in pull request #31.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpException,
|
||||
Param,
|
||||
@@ -79,4 +80,17 @@ export class LogbookController {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':rowKey')
|
||||
async delete(@Param() params: any): Promise<void> {
|
||||
try {
|
||||
await this.logbookService.delete(params.rowKey);
|
||||
} catch (error) {
|
||||
const customError = error as CustomError;
|
||||
|
||||
throw new HttpException(customError.message, customError.statusCode, {
|
||||
cause: customError.name
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,19 @@ export class LogbookEntity {
|
||||
routeTo: string;
|
||||
durationOfFlight: number | null;
|
||||
singleEngineLand: number | null;
|
||||
simulatorAtd: number | null;
|
||||
landingsDay: number | null;
|
||||
landingsNight: number | null;
|
||||
groundTrainingReceived: number;
|
||||
flightTrainingReceived: number;
|
||||
crossCountry: number | null;
|
||||
night: number | null;
|
||||
solo: number | null;
|
||||
pilotInCommand: number | null;
|
||||
instrumentActual: number | null;
|
||||
instrumentSimulated: number | null;
|
||||
instrumentApproaches: number | null;
|
||||
instrumentHolds: number | null;
|
||||
instrumentNavTrack: number | null;
|
||||
notes: string;
|
||||
simulatorAtd?: number | null;
|
||||
landingsDay?: number | null;
|
||||
landingsNight?: number | null;
|
||||
groundTrainingReceived?: number;
|
||||
flightTrainingReceived?: number;
|
||||
crossCountry?: number | null;
|
||||
night?: number | null;
|
||||
solo?: number | null;
|
||||
pilotInCommand?: number | null;
|
||||
instrumentActual?: number | null;
|
||||
instrumentSimulated?: number | null;
|
||||
instrumentApproaches?: number | null;
|
||||
instrumentHolds?: number | null;
|
||||
instrumentNavTrack?: number | null;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export class LogbookService {
|
||||
instrumentNavTrack: entity.instrumentNavTrack
|
||||
? Number(entity.instrumentNavTrack)
|
||||
: null,
|
||||
notes: entity.notes.toString()
|
||||
notes: entity.notes ? entity.notes.toString() : ''
|
||||
};
|
||||
|
||||
logbookEntries.push(logbookEntry);
|
||||
@@ -143,6 +143,7 @@ export class LogbookService {
|
||||
}
|
||||
|
||||
async update(logbookData: LogbookDto): Promise<void> {
|
||||
try {
|
||||
const client: TableClient = await this.tableService.getTableClient(
|
||||
this.tableName
|
||||
);
|
||||
@@ -150,7 +151,6 @@ export class LogbookService {
|
||||
|
||||
Object.assign(logbook, logbookData);
|
||||
|
||||
try {
|
||||
await client.upsertEntity(logbook, 'Replace');
|
||||
} catch (error) {
|
||||
const restError: RestError = error as RestError;
|
||||
@@ -162,4 +162,22 @@ export class LogbookService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async delete(rowKey: string): Promise<void> {
|
||||
try {
|
||||
const client: TableClient = await this.tableService.getTableClient(
|
||||
this.tableName
|
||||
);
|
||||
|
||||
await client.deleteEntity('entry', rowKey);
|
||||
} catch (error) {
|
||||
const restError: RestError = error as RestError;
|
||||
|
||||
throw new CustomError(
|
||||
restError.details['odataError']['message']['value'],
|
||||
restError.details['odataError']['code'],
|
||||
restError.statusCode
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
PenIcon,
|
||||
TrashIcon
|
||||
} from '@noahspan/noahspan-components';
|
||||
import { FormMode } from '../enums/formMode';
|
||||
import { FormMode } from '../../enums/formMode';
|
||||
|
||||
const ActionMenu = ({ id, onOpenCloseForm }: IActionMenuProps) => {
|
||||
const ActionMenu = ({ id, onDelete, onOpenCloseForm }: IActionMenuProps) => {
|
||||
const [anchorElAction, setAnchorElAction] = useState<null | HTMLElement>(
|
||||
null
|
||||
);
|
||||
@@ -50,7 +50,7 @@ const ActionMenu = ({ id, onOpenCloseForm }: IActionMenuProps) => {
|
||||
<ListItemText>View</ListItemText>
|
||||
</MenuItem>
|
||||
<hr className="my-3" />
|
||||
<MenuItem>
|
||||
<MenuItem onClick={() => onDelete(id)}>
|
||||
<ListItemIcon>
|
||||
<TrashIcon size="lg" />
|
||||
</ListItemIcon>
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FormMode } from '../enums/formMode';
|
||||
import { FormMode } from '../../enums/formMode';
|
||||
|
||||
export interface IActionMenuProps {
|
||||
id: string;
|
||||
onDelete: (entryId: string) => void;
|
||||
onOpenCloseForm: (formMode: FormMode, id: string) => void;
|
||||
}
|
||||
52
app/src/components/confirmationDialog/ConfirmationDialog.tsx
Normal file
52
app/src/components/confirmationDialog/ConfirmationDialog.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
CircleCheckIcon,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Spinner,
|
||||
XmarkIcon
|
||||
} from '@noahspan/noahspan-components';
|
||||
import { IDialogConfirmationProps } from './IConfirmationDialogProps';
|
||||
|
||||
const ConfirmationDialog = ({
|
||||
contentText,
|
||||
isLoading,
|
||||
isOpen,
|
||||
onCancel,
|
||||
onConfirm,
|
||||
title
|
||||
}: IDialogConfirmationProps) => {
|
||||
return (
|
||||
<Dialog
|
||||
onClose={onCancel}
|
||||
open={isOpen}
|
||||
sx={{
|
||||
'& .MuiDialog-paper': { width: '2000px' }
|
||||
}}
|
||||
>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogContent sx={{ textAlign: 'center' }}>
|
||||
{!isLoading && <DialogContentText>{contentText}</DialogContentText>}
|
||||
{isLoading && <Spinner />}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onCancel} variant="outlined" startIcon={<XmarkIcon />}>
|
||||
No
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
variant="contained"
|
||||
startIcon={<CircleCheckIcon />}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmationDialog;
|
||||
@@ -0,0 +1,8 @@
|
||||
export interface IDialogConfirmationProps {
|
||||
contentText: string;
|
||||
isLoading: boolean;
|
||||
isOpen: boolean;
|
||||
onCancel: () => void;
|
||||
onConfirm: () => void;
|
||||
title: string;
|
||||
}
|
||||
27
app/src/components/logbook/ILogbookEntry.ts
Normal file
27
app/src/components/logbook/ILogbookEntry.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export interface ILogbookEntry {
|
||||
partitionKey: string;
|
||||
rowKey: string;
|
||||
id: string;
|
||||
pilotId: string;
|
||||
date: string;
|
||||
aircraftMakeModel: string;
|
||||
aircraftIdentity: string;
|
||||
routeFrom: string;
|
||||
routeTo: string;
|
||||
durationOfFlight: number | null;
|
||||
singleEngineLand: number | null;
|
||||
simulatorAtd: number | null;
|
||||
landingsDay: number | null;
|
||||
landingsNight: number | null;
|
||||
instrumentActual: number | null;
|
||||
instrumentSimulated: number | null;
|
||||
instrumentApproaches: number | null;
|
||||
instrumentHolds: number | null;
|
||||
instrumentNavTrack: number | null;
|
||||
groundTrainingReceived: number;
|
||||
flightTrainingReceived: number;
|
||||
crossCountry: number | null;
|
||||
night: number | null;
|
||||
solo: number | null;
|
||||
pilotInCommand: number | null;
|
||||
}
|
||||
13
app/src/components/logbook/ILogbookState.ts
Normal file
13
app/src/components/logbook/ILogbookState.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { FormMode } from '../../enums/formMode';
|
||||
import { ILogbookEntry } from './ILogbookEntry';
|
||||
|
||||
export interface ILogbookState {
|
||||
entries: ILogbookEntry[];
|
||||
formMode: FormMode;
|
||||
error: string | undefined;
|
||||
isConfirmDialogLoading: boolean;
|
||||
isConfirmDialogOpen: boolean;
|
||||
isFormOpen: boolean;
|
||||
isLoading: boolean;
|
||||
selectedEntryId: string | undefined;
|
||||
}
|
||||
@@ -1,75 +1,130 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useReducer, useState } from 'react';
|
||||
import LogbookEntryForm from '../logbookEntryForm/LogbookEntryForm';
|
||||
import {
|
||||
Alert,
|
||||
Box,
|
||||
Button,
|
||||
ColumnDef,
|
||||
Grid,
|
||||
PlusIcon,
|
||||
Spinner,
|
||||
Table,
|
||||
Typography
|
||||
} from '@noahspan/noahspan-components';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import { useHttpClient } from '../../hooks/httpClient/UseHttpClient';
|
||||
import { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { useAccessToken } from '../../hooks/accessToken/UseAcessToken';
|
||||
import { useIsAuthenticated } from '@azure/msal-react';
|
||||
import { FormMode } from '../../enums/formMode';
|
||||
import ActionMenu from '../../actionMenu/ActionMenu';
|
||||
|
||||
type LogbookEntry = {
|
||||
partitionKey: string;
|
||||
rowKey: string;
|
||||
id: string;
|
||||
pilotId: string;
|
||||
date: string;
|
||||
aircraftMakeModel: string;
|
||||
aircraftIdentity: string;
|
||||
routeFrom: string;
|
||||
routeTo: string;
|
||||
durationOfFlight: number | null;
|
||||
singleEngineLand: number | null;
|
||||
simulatorAtd: number | null;
|
||||
landingsDay: number | null;
|
||||
landingsNight: number | null;
|
||||
instrumentActual: number | null;
|
||||
instrumentSimulated: number | null;
|
||||
instrumentApproaches: number | null;
|
||||
instrumentHolds: number | null;
|
||||
instrumentNavTrack: number | null;
|
||||
groundTrainingReceived: number;
|
||||
flightTrainingReceived: number;
|
||||
crossCountry: number | null;
|
||||
night: number | null;
|
||||
solo: number | null;
|
||||
pilotInCommand: number | null;
|
||||
};
|
||||
import ActionMenu from '../actionMenu/ActionMenu';
|
||||
import ConfirmationDialog from '../confirmationDialog/ConfirmationDialog';
|
||||
import { ILogbookEntry } from './ILogbookEntry';
|
||||
|
||||
const Logbook: React.FC<unknown> = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const httpClient: AxiosInstance = useHttpClient();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const { getAccessToken } = useAccessToken();
|
||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
||||
const [entryFormMode, setEntryFormMode] = useState<FormMode>(FormMode.CANCEL);
|
||||
const [selectedEntryId, setSelectedEntryId] = useState<string | undefined>();
|
||||
const [entries, setEntries] = useState([]);
|
||||
|
||||
const getLogbookEntries = async () => {
|
||||
try {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
||||
|
||||
const token = await getAccessToken();
|
||||
const config = isAuthenticated
|
||||
? { headers: { Authorization: `${token}` } }
|
||||
: {};
|
||||
const response: AxiosResponse = await httpClient.get(
|
||||
`api/logbook`,
|
||||
config
|
||||
);
|
||||
|
||||
dispatch({ type: 'SET_ENTRIES', payload: response.data });
|
||||
} catch (error) {
|
||||
const axiosError = error as AxiosError;
|
||||
|
||||
dispatch({
|
||||
type: 'SET_ERROR',
|
||||
payload: `Loading of logbook entries failed with the following message: ${axiosError.message}`
|
||||
});
|
||||
} finally {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
||||
}
|
||||
};
|
||||
|
||||
const onOpenCloseEntryForm = (mode: FormMode, entryId?: string) => {
|
||||
switch (mode) {
|
||||
case FormMode.ADD:
|
||||
case FormMode.EDIT:
|
||||
case FormMode.VIEW:
|
||||
setEntryFormMode(mode);
|
||||
setSelectedEntryId(entryId);
|
||||
setIsDrawerOpen(true);
|
||||
dispatch({
|
||||
type: 'SET_OPEN_CLOSE_ENTRY_FORM',
|
||||
payload: {
|
||||
formMode: mode,
|
||||
selectedEntryId: entryId,
|
||||
isFormOpen: true
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
case FormMode.CANCEL:
|
||||
setEntryFormMode(mode);
|
||||
setSelectedEntryId(undefined);
|
||||
setIsDrawerOpen(false);
|
||||
dispatch({
|
||||
type: 'SET_OPEN_CLOSE_ENTRY_FORM',
|
||||
payload: {
|
||||
formMode: mode,
|
||||
selectedEntryId: undefined,
|
||||
isFormOpen: false
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const columns: ColumnDef<LogbookEntry>[] = [
|
||||
const onDeleteEntry = (entryId: string) => {
|
||||
dispatch({
|
||||
type: 'SET_DELETE',
|
||||
payload: { isConfirmationDialogOpen: true, selectedEntryId: entryId }
|
||||
});
|
||||
};
|
||||
|
||||
const onConfirmationDialogConfirm = async () => {
|
||||
try {
|
||||
dispatch({ type: 'SET_IS_CONFIRMATION_DIALOG_LOADING', payload: true });
|
||||
|
||||
const token = await getAccessToken();
|
||||
const config = isAuthenticated
|
||||
? { headers: { Authorization: `${token}` } }
|
||||
: {};
|
||||
|
||||
await httpClient.delete(`api/logbook/${state.selectedEntryId}`, config);
|
||||
|
||||
dispatch({
|
||||
type: 'SET_DELETE',
|
||||
payload: { isConfirmationDialogOpen: false, selectedEntryId: undefined }
|
||||
});
|
||||
await getLogbookEntries();
|
||||
} catch (error) {
|
||||
const axiosError = error as AxiosError;
|
||||
|
||||
dispatch({
|
||||
type: 'SET_ERROR',
|
||||
payload: `Loading of logbook entries failed with the following message: ${axiosError.message}`
|
||||
});
|
||||
} finally {
|
||||
dispatch({ type: 'SET_IS_CONFIRMATION_DIALOG_LOADING', payload: false });
|
||||
}
|
||||
};
|
||||
|
||||
const onConfirmationDialogCancel = () => {
|
||||
dispatch({
|
||||
type: 'SET_DELETE',
|
||||
payload: { isConfirmationDialogOpen: false, selectedEntryId: undefined }
|
||||
});
|
||||
};
|
||||
|
||||
const columns: ColumnDef<ILogbookEntry>[] = [
|
||||
{
|
||||
accessorKey: 'pilotName',
|
||||
header: 'Pilot'
|
||||
@@ -303,6 +358,7 @@ const Logbook: React.FC<unknown> = () => {
|
||||
cell: (info) => (
|
||||
<ActionMenu
|
||||
id={info.row.original.rowKey}
|
||||
onDelete={onDeleteEntry}
|
||||
onOpenCloseForm={onOpenCloseEntryForm}
|
||||
/>
|
||||
)
|
||||
@@ -310,27 +366,10 @@ const Logbook: React.FC<unknown> = () => {
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
const getLogbookEntries = async () => {
|
||||
try {
|
||||
const token = await getAccessToken();
|
||||
const config = isAuthenticated
|
||||
? { headers: { Authorization: `${token}` } }
|
||||
: {};
|
||||
const response: AxiosResponse = await httpClient.get(
|
||||
`api/logbook`,
|
||||
config
|
||||
);
|
||||
|
||||
setEntries(response.data);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
if (isAuthenticated && !isDrawerOpen) {
|
||||
if (isAuthenticated && !state.isFormOpen) {
|
||||
getLogbookEntries();
|
||||
}
|
||||
}, [isAuthenticated, isDrawerOpen]);
|
||||
}, [isAuthenticated, state.isFormOpen]);
|
||||
|
||||
return (
|
||||
<Box sx={{ margin: '20px' }}>
|
||||
@@ -348,16 +387,51 @@ const Logbook: React.FC<unknown> = () => {
|
||||
Add Entry
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid size={12}>
|
||||
{entries.length > 0 && <Table columns={columns} data={entries} />}
|
||||
{!state.isLoading && state.error && (
|
||||
<Grid display="flex" justifyContent="center" size={12}>
|
||||
<Alert
|
||||
onClose={() =>
|
||||
dispatch({ type: 'SET_ERROR', payload: undefined })
|
||||
}
|
||||
severity="error"
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
{state.error}
|
||||
</Alert>
|
||||
</Grid>
|
||||
)}
|
||||
{!state.isLoading && (
|
||||
<Grid size={12}>
|
||||
{state.entries.length > 0 && (
|
||||
<Table columns={columns} data={state.entries} />
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
{state.isLoading && !state.error && (
|
||||
<>
|
||||
<Grid display="flex" justifyContent="center" size={12}>
|
||||
<Spinner />
|
||||
</Grid>
|
||||
<Grid display="flex" justifyContent="center" size={12}>
|
||||
Loading...
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
<LogbookEntryForm
|
||||
entryId={selectedEntryId}
|
||||
isDrawerOpen={isDrawerOpen}
|
||||
mode={entryFormMode}
|
||||
entryId={state.selectedEntryId}
|
||||
isDrawerOpen={state.isFormOpen}
|
||||
mode={state.formMode}
|
||||
onOpenClose={(mode) => onOpenCloseEntryForm(mode)}
|
||||
/>
|
||||
<ConfirmationDialog
|
||||
contentText="Are you sure you want to delete the logbook entry?"
|
||||
isLoading={state.isConfirmDialogLoading}
|
||||
isOpen={state.isConfirmDialogOpen}
|
||||
onCancel={onConfirmationDialogCancel}
|
||||
onConfirm={onConfirmationDialogConfirm}
|
||||
title="Confirm Delete"
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
92
app/src/components/logbook/reducer.ts
Normal file
92
app/src/components/logbook/reducer.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { FormMode } from '../../enums/formMode';
|
||||
import { ILogbookEntry } from './ILogbookEntry';
|
||||
import { ILogbookState } from './ILogbookState';
|
||||
|
||||
type Action =
|
||||
| {
|
||||
type: 'SET_DELETE';
|
||||
payload: {
|
||||
isConfirmationDialogOpen: boolean;
|
||||
selectedEntryId: string | undefined;
|
||||
};
|
||||
}
|
||||
| { type: 'SET_ENTRIES'; payload: ILogbookEntry[] }
|
||||
| { type: 'SET_ERROR'; payload: string | undefined }
|
||||
| { type: 'SET_FORM_MODE'; payload: FormMode }
|
||||
| { type: 'SET_IS_CONFIRMATION_DIALOG_LOADING'; payload: boolean }
|
||||
| { type: 'SET_IS_LOADING'; payload: boolean }
|
||||
| {
|
||||
type: 'SET_OPEN_CLOSE_ENTRY_FORM';
|
||||
payload: {
|
||||
formMode: FormMode;
|
||||
selectedEntryId: string | undefined;
|
||||
isFormOpen: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export const initialState: ILogbookState = {
|
||||
entries: [],
|
||||
error: undefined,
|
||||
formMode: FormMode.CANCEL,
|
||||
isConfirmDialogLoading: false,
|
||||
isConfirmDialogOpen: false,
|
||||
isFormOpen: false,
|
||||
isLoading: false,
|
||||
selectedEntryId: undefined
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
state: ILogbookState,
|
||||
action: Action
|
||||
): ILogbookState => {
|
||||
switch (action.type) {
|
||||
case 'SET_DELETE': {
|
||||
return {
|
||||
...state,
|
||||
isConfirmDialogOpen: action.payload.isConfirmationDialogOpen,
|
||||
selectedEntryId: action.payload.selectedEntryId
|
||||
};
|
||||
}
|
||||
case 'SET_ENTRIES': {
|
||||
return {
|
||||
...state,
|
||||
entries: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_ERROR': {
|
||||
return {
|
||||
...state,
|
||||
error: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_FORM_MODE': {
|
||||
return {
|
||||
...state,
|
||||
formMode: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_CONFIRMATION_DIALOG_LOADING': {
|
||||
return {
|
||||
...state,
|
||||
isConfirmDialogLoading: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_LOADING': {
|
||||
return {
|
||||
...state,
|
||||
isLoading: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_OPEN_CLOSE_ENTRY_FORM': {
|
||||
return {
|
||||
...state,
|
||||
formMode: action.payload.formMode,
|
||||
isFormOpen: action.payload.isFormOpen,
|
||||
selectedEntryId: action.payload.selectedEntryId
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
export interface ILogbookEntryFormState {
|
||||
error: string | undefined;
|
||||
isDisabled: boolean;
|
||||
isLoading: boolean;
|
||||
pilotOptions: { label: string; value: string }[];
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
AccordionSummary,
|
||||
Alert,
|
||||
Button,
|
||||
ChevronDownIcon,
|
||||
DatePicker,
|
||||
@@ -18,7 +19,7 @@ import {
|
||||
import { useForm, Controller, FormProvider } from 'react-hook-form';
|
||||
import { ILogbookEntryFormProps } from './ILogbookEntryFormProps';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import axios, { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import axios, { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { useHttpClient } from '../../hooks/httpClient/UseHttpClient';
|
||||
import { useAccessToken } from '../../hooks/accessToken/UseAcessToken';
|
||||
import { useIsAuthenticated } from '@azure/msal-react';
|
||||
@@ -96,12 +97,9 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
||||
onOpenClose(FormMode.CANCEL);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const errResp = error.response;
|
||||
const axiosError = error as AxiosError;
|
||||
|
||||
console.log(errResp);
|
||||
} else {
|
||||
}
|
||||
dispatch({ type: 'SET_ERROR', payload: axiosError.message });
|
||||
} finally {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
||||
}
|
||||
@@ -129,13 +127,15 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
|
||||
methods.reset(entry);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
const axiosError = error as AxiosError;
|
||||
|
||||
dispatch({ type: 'SET_ERROR', payload: axiosError.message });
|
||||
} finally {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
||||
}
|
||||
};
|
||||
|
||||
if (entryId) {
|
||||
if (entryId && isDrawerOpen) {
|
||||
getEntry();
|
||||
}
|
||||
}, [entryId]);
|
||||
@@ -175,6 +175,19 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
<XmarkIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
{state.error && (
|
||||
<Grid display="flex" justifyContent="center" size={12}>
|
||||
<Alert
|
||||
onClose={() =>
|
||||
dispatch({ type: 'SET_ERROR', payload: undefined })
|
||||
}
|
||||
severity="error"
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
{state.error}
|
||||
</Alert>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid alignItems="center" display="flex" size={4}>
|
||||
<Typography variant="body1">Pilot *</Typography>
|
||||
</Grid>
|
||||
@@ -200,7 +213,17 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
<Select
|
||||
disabled={state.isDisabled}
|
||||
fullWidth
|
||||
onChange={onChange}
|
||||
onChange={(event) => {
|
||||
const pilot = pilots?.find(
|
||||
(pilot) => (pilot.id = event.target.value)
|
||||
);
|
||||
|
||||
if (pilot) {
|
||||
methods.setValue('pilotName', pilot.name);
|
||||
}
|
||||
|
||||
methods.setValue('pilotId', event.target.value);
|
||||
}}
|
||||
options={
|
||||
state.pilotOptions && state.pilotOptions.length > 0
|
||||
? state.pilotOptions
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { ILogbookEntryFormState } from './ILogbookEntryFormState';
|
||||
|
||||
type Action =
|
||||
| { type: 'SET_ERROR'; payload: string | undefined }
|
||||
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
||||
| { type: 'SET_IS_LOADING'; payload: boolean }
|
||||
| { type: 'SET_PILOT_OPTIONS'; payload: { label: string; value: string }[] }
|
||||
| { type: 'SET_SELECTED_ENTRY_PILOT_NAME'; payload: string };
|
||||
|
||||
export const initialState: ILogbookEntryFormState = {
|
||||
error: undefined,
|
||||
isDisabled: false,
|
||||
isLoading: true,
|
||||
pilotOptions: [],
|
||||
@@ -18,6 +20,12 @@ export const reducer = (
|
||||
action: Action
|
||||
): ILogbookEntryFormState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ERROR': {
|
||||
return {
|
||||
...state,
|
||||
error: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_DISABLED': {
|
||||
return {
|
||||
...state,
|
||||
@@ -42,5 +50,8 @@ export const reducer = (
|
||||
selectedEntryPilotName: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user