96 switch from azure table storage to sqlite (#97)
* adding typeorm to api * switching to sqlite * switching to sqlite * switching to sqlite * migrating to sqlite * updating terraform * updating infrastructure
This commit was merged in pull request #97.
This commit is contained in:
241
client/src/components/tracksForm/TracksForm.tsx
Normal file
241
client/src/components/tracksForm/TracksForm.tsx
Normal file
@@ -0,0 +1,241 @@
|
||||
import { useEffect, useReducer, useRef } from "react";
|
||||
import { AxiosError, AxiosResponse } from "axios";
|
||||
import { TracksFormProps } from "./TracksFormProps.interface";
|
||||
import { FormMode } from "../../enums/formMode";
|
||||
import { LogbookEntry } from "../logbook/LogbookEntry.interface";
|
||||
import ConfirmationDialog from "../confirmationDialog/ConfirmationDialog";
|
||||
import { initialState, reducer } from "./reducer";
|
||||
import TrackMap from "../trackMap/TrackMap";
|
||||
import httpClient from "../../httpClient/httpClient";
|
||||
import { Button, Input, Spinner } from '@heroui/react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faUpload, faTrash, faXmark } from '@fortawesome/free-solid-svg-icons';
|
||||
import { useLogbookContext } from "../../hooks/logbookContext/UseLogbookContext";
|
||||
|
||||
const TracksForm = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState)
|
||||
const logbookContext = useLogbookContext();
|
||||
|
||||
const getTracks = async () => {
|
||||
try {
|
||||
const response: AxiosResponse = await httpClient.get(
|
||||
`api/tracks/${logbookContext.state.selectedLogId}`
|
||||
)
|
||||
|
||||
const tracks = response.data;
|
||||
|
||||
dispatch({ type: 'SET_TRACKS', payload: tracks })
|
||||
} catch (error) {
|
||||
const axiosError = error as AxiosError;
|
||||
|
||||
logbookContext.dispatch({ type: 'SET_FORM_ALERT', payload: { severity: 'danger', message: axiosError.message }})
|
||||
}
|
||||
}
|
||||
|
||||
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 order = state.tracks.length + 1
|
||||
|
||||
formData.append('file', file);
|
||||
|
||||
httpClient.interceptors.request.use((config) => {
|
||||
config.headers["Content-Type"] = 'multipart/form-data'
|
||||
|
||||
return config
|
||||
});
|
||||
|
||||
await httpClient.post(`api/tracks/${logbookContext.state.selectedLogId}/${order}`, formData);
|
||||
await getTracks();
|
||||
// const uploadUrl = uploadResponse.data.url;
|
||||
// const tracks: string[] = log.tracks ? JSON.parse(log.tracks!) : [];
|
||||
|
||||
// tracks.push(uploadUrl)
|
||||
// log.tracks = JSON.stringify(tracks);
|
||||
// await httpClient.put(`api/logs/log/${logbookContext.state.selectedLogId}`, 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 onDeleteTrack = async (id: string, filename: string, index: number) => {
|
||||
dispatch({ type: 'SET_ON_DELETE_TRACK', payload: { isConfirmDialogOpen: true, selectedTrack: { id: id, filename: filename, index: index }}})
|
||||
}
|
||||
|
||||
const onConfirmDialogConfirm = async () => {
|
||||
try {
|
||||
await httpClient.delete(`api/tracks/${state.selectedTrack!.id}/${state.selectedTrack!.filename}/${logbookContext.state.selectedLogId}`);
|
||||
|
||||
await getTracks();
|
||||
|
||||
// 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(() => {
|
||||
if (logbookContext.state.selectedLogId) {
|
||||
getTracks();
|
||||
}
|
||||
}, [logbookContext.state.selectedLogId])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(logbookContext.state.formMode)
|
||||
if (logbookContext.state.formMode === FormMode.VIEW) {
|
||||
dispatch({ type: 'SET_IS_DISABLED', payload: true });
|
||||
}
|
||||
}, [logbookContext.state.formMode]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(state.isDisabled)
|
||||
}, [state.isDisabled])
|
||||
|
||||
return (
|
||||
<div className='grid grid-cols-12 gap-3'>
|
||||
{state.tracks.length > 0 &&
|
||||
<div className="col-span-12">
|
||||
<TrackMap height='400px' logId={logbookContext.state.selectedLogId!} tracks={state.tracks} />
|
||||
</div>
|
||||
}
|
||||
<>
|
||||
{state.tracks.length > 0 && state.tracks.map((track, index) => {
|
||||
const filename: string = track.url.substring(track.url.lastIndexOf('/') + 1);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='col-span-10'>
|
||||
<Input isDisabled={state.isDisabled} key={index} type='text' value={filename}/>
|
||||
</div>
|
||||
<div className='col-span-2'>
|
||||
<Button isDisabled={state.isDisabled} key={index} isIconOnly onPress={() => onDeleteTrack(track.id, filename, index)}><FontAwesomeIcon icon={faTrash} /></Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
})}
|
||||
<div className='col-span-12'>
|
||||
<Button
|
||||
as='label'
|
||||
color='primary'
|
||||
isDisabled={state.isDisabled}
|
||||
fullWidth={true}
|
||||
startContent={<FontAwesomeIcon icon={faUpload} />}
|
||||
>
|
||||
Upload Track
|
||||
<input hidden onChange={handleFileUpload} type='file' />
|
||||
</Button>
|
||||
</div>
|
||||
{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"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// const getConfig = async () => {
|
||||
// const config = auth.isAuthenticated
|
||||
// ? { headers: { Authorization: auth.user?.access_token } }
|
||||
// : {};
|
||||
|
||||
// return config
|
||||
// }
|
||||
|
||||
// const getLog = async (): Promise<ILogbookEntry> => {
|
||||
// const logResponse: AxiosResponse = await httpClient.get(
|
||||
// `api/tracks/${selectedLogId}`,
|
||||
// await getConfig()
|
||||
// );
|
||||
// const logData: ILogbookEntry = logResponse.data;
|
||||
|
||||
// return logData
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// 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 }}})
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// useEffect(() => {
|
||||
// const updateTracks = async () => {
|
||||
// const log = await getLog();
|
||||
|
||||
// dispatch({ type: 'SET_TRACKS', payload: log.tracks! });
|
||||
// }
|
||||
|
||||
// updateTracks();
|
||||
// }, [])
|
||||
|
||||
// return (
|
||||
// <div className='grid grid-cols-12 gap-3'>
|
||||
// {}
|
||||
// {logbookContext.state.formMode === FormMode.EDIT &&
|
||||
// <>
|
||||
// {state.isLoading &&
|
||||
// <>
|
||||
// <div>
|
||||
// <Spinner size='lg' />
|
||||
// </div>
|
||||
// <div>
|
||||
// Loading...
|
||||
// </div>
|
||||
// </>
|
||||
// }
|
||||
// {!state.isLoading && state.tracks.length > 0 && state.tracks.map((track, index) => {
|
||||
// const trackSplit = track.url.split('/')
|
||||
// const filename = trackSplit[trackSplit.length - 1];
|
||||
|
||||
// return (
|
||||
// <>
|
||||
// <div>
|
||||
// <Input disabled={true} value={filename} />
|
||||
// </div>
|
||||
// <div>
|
||||
// <Button isIconOnly onPress={() => onDeleteTrack(filename, index)}><FontAwesomeIcon icon={faTrash} /></Button>
|
||||
// </div>
|
||||
// </>
|
||||
// )
|
||||
// })}
|
||||
// </>
|
||||
// }
|
||||
|
||||
|
||||
// </div>
|
||||
// )
|
||||
// }
|
||||
|
||||
export default TracksForm;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { FormMode } from "../../enums/formMode";
|
||||
|
||||
export interface TracksFormProps {
|
||||
isDrawerOpen: boolean;
|
||||
mode: FormMode;
|
||||
onOpenClose: (mode: FormMode) => void;
|
||||
selectedLogId: string | undefined;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
export interface TracksFormState {
|
||||
isConfirmDialogOpen: boolean;
|
||||
isConfirmDialogLoading: boolean;
|
||||
isDisabled: boolean;
|
||||
isLoading: boolean;
|
||||
selectedTrack: {
|
||||
id: string,
|
||||
filename: string,
|
||||
index: number
|
||||
} | undefined;
|
||||
tracks: { id: string; order: number; url: string; }[];
|
||||
}
|
||||
63
client/src/components/tracksForm/reducer.ts
Normal file
63
client/src/components/tracksForm/reducer.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { TracksFormState } from "./TracksFormState.interface";
|
||||
|
||||
type Action =
|
||||
| { type: 'SET_IS_CONFIRM_DIALOG_OPEN'; payload: boolean }
|
||||
| { type: 'SET_IS_CONFORM_DIALOG_LOADING'; payload: boolean }
|
||||
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
||||
| { type: 'SET_IS_LOADING'; payload: boolean }
|
||||
| { type: 'SET_ON_DELETE_TRACK'; payload: { isConfirmDialogOpen: boolean, selectedTrack: { id: string, filename: string, index: number } }}
|
||||
| { type: 'SET_TRACKS'; payload: { id: string; order: number; url: string }[] };
|
||||
|
||||
export const initialState: TracksFormState = {
|
||||
isConfirmDialogOpen: false,
|
||||
isConfirmDialogLoading: false,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
selectedTrack: undefined,
|
||||
tracks: []
|
||||
}
|
||||
|
||||
export const reducer = (state: TracksFormState, action: Action): TracksFormState => {
|
||||
switch (action.type) {
|
||||
case 'SET_IS_CONFIRM_DIALOG_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isConfirmDialogOpen: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_IS_CONFORM_DIALOG_LOADING': {
|
||||
return {
|
||||
...state,
|
||||
isConfirmDialogLoading: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_IS_DISABLED': {
|
||||
return {
|
||||
...state,
|
||||
isDisabled: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_IS_LOADING': {
|
||||
return {
|
||||
...state,
|
||||
isLoading: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_ON_DELETE_TRACK': {
|
||||
return {
|
||||
...state,
|
||||
isConfirmDialogOpen: action.payload.isConfirmDialogOpen,
|
||||
selectedTrack: action.payload.selectedTrack
|
||||
}
|
||||
}
|
||||
case 'SET_TRACKS': {
|
||||
return {
|
||||
...state,
|
||||
tracks: action.payload
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user