Feature/25 logbook edit entry #30
@@ -4,7 +4,8 @@ import {
|
||||
Get,
|
||||
HttpException,
|
||||
Param,
|
||||
Post
|
||||
Post,
|
||||
Put
|
||||
} from '@nestjs/common';
|
||||
import { LogbookService } from './logbook.service';
|
||||
import { LogbookDto } from './logbook.dto';
|
||||
@@ -18,7 +19,6 @@ export class LogbookController {
|
||||
|
||||
@Get(':entryId')
|
||||
async find(@Param() params: any): Promise<LogbookEntity> {
|
||||
console.log(params);
|
||||
try {
|
||||
const entry: LogbookEntity = await this.logbookService.find(
|
||||
params.entryId
|
||||
@@ -43,7 +43,7 @@ export class LogbookController {
|
||||
return logbookEntries;
|
||||
} catch (error) {
|
||||
const customError = error as CustomError;
|
||||
console.log(error);
|
||||
|
||||
throw new HttpException(customError.message, customError.statusCode, {
|
||||
cause: customError.name
|
||||
});
|
||||
@@ -63,4 +63,20 @@ export class LogbookController {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':entryId')
|
||||
async update(
|
||||
@Param() params: any,
|
||||
@Body() logbookData: LogbookDto
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await this.logbookService.update(logbookData);
|
||||
} catch (error) {
|
||||
const customError = error as CustomError;
|
||||
|
||||
throw new HttpException(customError.message, customError.statusCode, {
|
||||
cause: customError.name
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,18 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
@Injectable()
|
||||
export class LogbookService {
|
||||
private readonly tableName = 'Logbook';
|
||||
|
||||
constructor(private readonly tableService: TableService) {}
|
||||
|
||||
async getLogbookEntries(filter: string): Promise<LogbookEntity[]> {
|
||||
try {
|
||||
const client: TableClient =
|
||||
await this.tableService.getTableClient('Logbook');
|
||||
const client: TableClient = await this.tableService.getTableClient(
|
||||
this.tableName
|
||||
);
|
||||
const entities = await client.listEntities({
|
||||
queryOptions: { filter: filter }
|
||||
});
|
||||
console.log(entities);
|
||||
const logbookEntries: LogbookEntity[] = [];
|
||||
|
||||
for await (const entity of entities) {
|
||||
@@ -73,7 +75,7 @@ export class LogbookService {
|
||||
: null,
|
||||
notes: entity.notes.toString()
|
||||
};
|
||||
console.log(logbookEntry);
|
||||
|
||||
logbookEntries.push(logbookEntry);
|
||||
}
|
||||
|
||||
@@ -118,8 +120,9 @@ export class LogbookService {
|
||||
}
|
||||
|
||||
async create(logbookData: LogbookDto): Promise<TableInsertEntityHeaders> {
|
||||
const client: TableClient =
|
||||
await this.tableService.getTableClient('Logbook');
|
||||
const client: TableClient = await this.tableService.getTableClient(
|
||||
this.tableName
|
||||
);
|
||||
const logbook: LogbookEntity = new LogbookEntity();
|
||||
|
||||
Object.assign(logbook, logbookData);
|
||||
@@ -138,4 +141,25 @@ export class LogbookService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async update(logbookData: LogbookDto): Promise<void> {
|
||||
const client: TableClient = await this.tableService.getTableClient(
|
||||
this.tableName
|
||||
);
|
||||
const logbook: LogbookEntity = new LogbookEntity();
|
||||
|
||||
Object.assign(logbook, logbookData);
|
||||
|
||||
try {
|
||||
await client.upsertEntity(logbook, 'Replace');
|
||||
} catch (error) {
|
||||
const restError: RestError = error as RestError;
|
||||
|
||||
throw new CustomError(
|
||||
restError.details['odataError']['message']['value'],
|
||||
restError.details['odataError']['code'],
|
||||
restError.statusCode
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { IActionMenuProps } from './IActionMenuProps';
|
||||
import {
|
||||
EllipsisVerticalIcon,
|
||||
@@ -26,10 +26,6 @@ const ActionMenu = ({ id, onOpenCloseForm }: IActionMenuProps) => {
|
||||
setAnchorElAction(null);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log(id);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton onClick={onOpenActionMenu}>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface ILogbookEntryFormState {
|
||||
isDisabled: boolean;
|
||||
isLoading: boolean;
|
||||
pilotOptions: { label: string; value: string }[];
|
||||
selectedEntryPilotName: string;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useReducer, useState } from 'react';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
@@ -15,13 +15,9 @@ import {
|
||||
Typography,
|
||||
XmarkIcon
|
||||
} from '@noahspan/noahspan-components';
|
||||
import {
|
||||
useForm,
|
||||
Controller,
|
||||
SubmitHandler,
|
||||
FormProvider
|
||||
} from 'react-hook-form';
|
||||
import { useForm, Controller, FormProvider } from 'react-hook-form';
|
||||
import { ILogbookEntryFormProps } from './ILogbookEntryFormProps';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import axios, { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { useHttpClient } from '../../hooks/httpClient/UseHttpClient';
|
||||
import { useAccessToken } from '../../hooks/accessToken/UseAcessToken';
|
||||
@@ -35,13 +31,8 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
mode,
|
||||
onOpenClose
|
||||
}) => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const httpClient: AxiosInstance = useHttpClient();
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [selectedEntry, setSelectedEntry] = useState();
|
||||
const [isDisabled, setIsDisabled] = useState<boolean>(false);
|
||||
const [pilotOptions, setPilotOptions] = useState<
|
||||
{ label: string; value: string }[]
|
||||
>([]);
|
||||
const { getAccessToken } = useAccessToken();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const defaultValues = {
|
||||
@@ -77,45 +68,55 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
|
||||
const onCancel = () => {
|
||||
methods.reset(defaultValues);
|
||||
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
||||
onOpenClose(FormMode.CANCEL);
|
||||
};
|
||||
|
||||
const onSubmit = async (data: unknown) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
||||
|
||||
const accessToken: string = await getAccessToken();
|
||||
|
||||
await httpClient.post(`api/logbook`, data, {
|
||||
headers: {
|
||||
Authorization: accessToken
|
||||
}
|
||||
});
|
||||
if (!entryId) {
|
||||
await httpClient.post(`api/logbook`, data, {
|
||||
headers: {
|
||||
Authorization: accessToken
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await httpClient.put(`api/logbook/${entryId}`, data, {
|
||||
headers: {
|
||||
Authorization: accessToken
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
methods.reset(defaultValues);
|
||||
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
||||
onOpenClose(FormMode.CANCEL);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const errResp = error.response;
|
||||
|
||||
console.log(errResp?.data.message);
|
||||
console.log(errResp);
|
||||
} else {
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === FormMode.VIEW) {
|
||||
setIsDisabled(true);
|
||||
dispatch({ type: 'SET_IS_DISABLED', payload: true });
|
||||
}
|
||||
}, [mode]);
|
||||
|
||||
useEffect(() => {
|
||||
const getEntry = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
||||
|
||||
const config = isAuthenticated
|
||||
? { headers: { Authorization: await getAccessToken() } }
|
||||
@@ -130,7 +131,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -148,7 +149,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
};
|
||||
});
|
||||
|
||||
setPilotOptions(newPilotsOptions);
|
||||
dispatch({ type: 'SET_PILOT_OPTIONS', payload: newPilotsOptions });
|
||||
}
|
||||
}, [pilots]);
|
||||
|
||||
@@ -182,28 +183,40 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
name="pilotId"
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
useEffect(() => {
|
||||
if (value && mode !== FormMode.ADD) {
|
||||
const pilot = pilots?.find((pilot) => pilot.id === value);
|
||||
|
||||
dispatch({
|
||||
type: 'SET_SELECTED_ENTRY_PILOT_NAME',
|
||||
payload: pilot.name
|
||||
});
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Select
|
||||
disabled={isDisabled}
|
||||
fullWidth
|
||||
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={
|
||||
pilotOptions && pilotOptions.length > 0
|
||||
? pilotOptions
|
||||
: []
|
||||
}
|
||||
value={value}
|
||||
/>
|
||||
<>
|
||||
{mode === FormMode.ADD && (
|
||||
<Select
|
||||
disabled={state.isDisabled}
|
||||
fullWidth
|
||||
onChange={onChange}
|
||||
options={
|
||||
state.pilotOptions && state.pilotOptions.length > 0
|
||||
? state.pilotOptions
|
||||
: []
|
||||
}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
{mode !== FormMode.ADD && (
|
||||
<TextField
|
||||
disabled={true}
|
||||
fullWidth
|
||||
value={state.selectedEntryPilotName}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -217,7 +230,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<DatePicker
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
@@ -233,7 +246,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.address ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
@@ -256,7 +269,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.address ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
@@ -279,7 +292,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.address ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
@@ -302,7 +315,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.address ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
@@ -325,7 +338,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.address ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
@@ -354,7 +367,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.address ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
@@ -383,7 +396,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.address ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
@@ -419,7 +432,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -450,7 +463,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -492,7 +505,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -523,7 +536,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -556,7 +569,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -587,7 +600,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -618,7 +631,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -662,7 +675,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -695,7 +708,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -726,7 +739,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -757,7 +770,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -788,7 +801,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -819,7 +832,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={
|
||||
methods.formState.errors.address ? true : false
|
||||
}
|
||||
@@ -854,7 +867,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.address ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
@@ -873,8 +886,8 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
<Grid display="flex" gap={2} justifyContent="right" size={12}>
|
||||
<Button
|
||||
disabled={
|
||||
isDisabled && mode.toString() !== FormMode.VIEW
|
||||
? isDisabled
|
||||
state.isDisabled && mode.toString() !== FormMode.VIEW
|
||||
? state.isDisabled
|
||||
: false
|
||||
}
|
||||
startIcon={<XmarkIcon />}
|
||||
@@ -886,7 +899,7 @@ const LogbookEntryForm: React.FC<ILogbookEntryFormProps> = ({
|
||||
</Button>
|
||||
{mode.toString() !== FormMode.VIEW && (
|
||||
<Button
|
||||
disabled={isDisabled}
|
||||
disabled={state.isDisabled}
|
||||
startIcon={<SaveIcon />}
|
||||
size="small"
|
||||
type="submit"
|
||||
|
||||
46
app/src/components/logbookEntryForm/reducer.tsx
Normal file
46
app/src/components/logbookEntryForm/reducer.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { ILogbookEntryFormState } from './ILogbookEntryFormState';
|
||||
|
||||
type Action =
|
||||
| { 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 = {
|
||||
isDisabled: false,
|
||||
isLoading: true,
|
||||
pilotOptions: [],
|
||||
selectedEntryPilotName: ''
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
state: ILogbookEntryFormState,
|
||||
action: Action
|
||||
): ILogbookEntryFormState => {
|
||||
switch (action.type) {
|
||||
case 'SET_IS_DISABLED': {
|
||||
return {
|
||||
...state,
|
||||
isDisabled: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_LOADING': {
|
||||
return {
|
||||
...state,
|
||||
isLoading: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_PILOT_OPTIONS': {
|
||||
return {
|
||||
...state,
|
||||
pilotOptions: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_SELECTED_ENTRY_PILOT_NAME': {
|
||||
return {
|
||||
...state,
|
||||
selectedEntryPilotName: action.payload
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user