import { useEffect, useReducer } from 'react'; import LogForm from '../logForm/LogForm'; import { Alert, Box, Button, ColumnDef, Grid, Icon, IconButton, IconName, Spinner, Table, theme, Typography, useMediaQuery } from '@noahspan/noahspan-components'; import { initialState, reducer } from './reducer'; import { useHttpClient } from '../../hooks/httpClient/UseHttpClient'; import { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; import { useAccessToken } from '../../hooks/accessToken/UseAcessToken'; import { useIsAuthenticated } from '@azure/msal-react'; import { FormMode } from '../../enums/formMode'; import { authColumns, unauthColumns } from './columns'; import ActionMenu from '../actionMenu/ActionMenu'; import ConfirmationDialog from '../confirmationDialog/ConfirmationDialog'; import { ILogbookEntry } from './ILogbookEntry'; import LogbookCard from '../logbookCard/LogbookCard'; import LogTracks from '../logTracks/LogTracks'; const Logbook: React.FC = () => { const [state, dispatch] = useReducer(reducer, initialState); const httpClient: AxiosInstance = useHttpClient(); const isAuthenticated = useIsAuthenticated(); const { getAccessToken } = useAccessToken(); const isMedium = useMediaQuery(theme.breakpoints.up('md')); const actionsColumn: ColumnDef = { header: 'Actions', meta: { align: 'center', headerAlign: 'center' }, cell: (info: any) => ( ) } const tracksColumn: ColumnDef = { accessorKey: 'tracks', header: 'Tracks', cell: (info: any) => { if (info.row.original.tracks && info.row.original.tracks.length > 0) { return ( onOpenCloseTracks(FormMode.VIEW, info.row.original.rowKey)}> ) } } } const getLogbookEntries = async () => { try { dispatch({ type: 'SET_IS_LOADING', payload: true }); const config = isAuthenticated ? { headers: { Authorization: await getAccessToken() } } : {}; const response: AxiosResponse = await httpClient.get(`api/logs`, config); const entries: ILogbookEntry[] = response.data; entries.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) if (response.data.length > 0) { dispatch({ type: 'SET_ENTRIES', payload: response.data }); if (state.alert) { dispatch({ type: 'SET_ALERT', payload: undefined}) } } else { dispatch({ type: 'SET_ALERT', payload: { severity: 'info', message: 'No logbook entries found.'}}) } } catch (error) { const axiosError = error as AxiosError; dispatch({ type: 'SET_ALERT', payload: { severity: 'error', message: `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: dispatch({ type: 'SET_OPEN_CLOSE_ENTRY_FORM', payload: { formMode: mode, selectedEntryId: entryId, isFormOpen: true } }); break; case FormMode.CANCEL: dispatch({ type: 'SET_OPEN_CLOSE_ENTRY_FORM', payload: { formMode: mode, selectedEntryId: undefined, isFormOpen: false } }); break; } }; const onOpenCloseTracks = (mode: FormMode, rowKey?: string) => { switch(mode) { case FormMode.EDIT: case FormMode.VIEW: dispatch({ type: 'SET_OPEN_CLOSE_TRACKS', payload: { tracksMode: mode, isTracksOpen: true, selectedRowKey: rowKey } }) break; case FormMode.CANCEL: dispatch({ type: 'SET_OPEN_CLOSE_TRACKS', payload: { tracksMode: mode, isTracksOpen: false, selectedRowKey: undefined } }) break; } } 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/logs/log/${state.selectedEntryId}`, config); dispatch({ type: 'SET_DELETE', payload: { isConfirmationDialogOpen: false, selectedEntryId: undefined } }); await getLogbookEntries(); } catch (error) { const axiosError = error as AxiosError; dispatch({ type: 'SET_ALERT', payload: { severity: 'error', message: `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 } }); }; useEffect(() => { let newColumns: ColumnDef[]; if (isAuthenticated) { newColumns = [...authColumns]; } else { newColumns = [...unauthColumns]; } const actionsColumnExists = newColumns.find((column) => column.id === 'actions'); const tracksColumnExists = newColumns.find((column) => column.id === 'actions'); if (!actionsColumnExists) { newColumns.push(actionsColumn); } if (!tracksColumnExists) { const notesColumnIndex = newColumns.findIndex((column) => column.id === 'notes') newColumns.splice(notesColumnIndex, 0, tracksColumn) } dispatch({ type: 'SET_COLUMNS', payload: newColumns }) }, [isAuthenticated]) useEffect(() => { if (!state.isFormOpen) { getLogbookEntries(); } }, [state.isFormOpen, state.isTracksOpen]); return ( Logbook {isAuthenticated && } {!state.isLoading && state.alert && ( dispatch({ type: 'SET_ALERT', payload: undefined }) } severity={state.alert.severity} sx={{ width: '100%' }} > {state.alert.message} )} {!state.isLoading && ( {isMedium && state.columns && state.columns.length > 0 && state.entries.length > 0 && ( )} {!isMedium && state.entries.length > 0 && } )} {state.isLoading && !state.alert && ( <> Loading... )} {state.isFormOpen && ( onOpenCloseEntryForm(mode)} /> )} {state.isConfirmDialogOpen && ( )} {state.isTracksOpen && onOpenCloseTracks(mode)} selectedRowKey={state.selectedEntryId} /> } ); }; export default Logbook;