commit 0d90d67bb66c32a9098a6630a9415092f063c06c
Author: Vaclav Honzik <vaclavhonzik98@gmail.com>
Date:   Sun Apr 24 19:26:38 2022 +0200

    map dialogs + catalog filter fix
    
    re #9547 #9545

diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 921cc39..a083fd3 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -11,12 +11,13 @@ import Login from './features/Auth/Login'
 import CatalogItemDetail from './features/Catalog/CatalogItemDetail'
 import Navigation from './features/Navigation/Navigation'
 import TrackingTool from './features/TrackingTool/TrackingTool'
+import Logout from './features/Auth/Logout'
+import ThemeWrapper from './features/Theme/ThemeWrapper'
 
 const App = () => {
-    const theme: Theme = useSelector((state: RootState) => state.theme.theme)
 
     return (
-        <ThemeProvider theme={theme}>
+        <ThemeWrapper>
             <Navigation>
                 <Container>
                     <Routes>
@@ -27,12 +28,13 @@ const App = () => {
                             element={<CatalogItemDetail />}
                         />
                         <Route path="/login" element={<Login />} />
+                        <Route path="/logout" element={<Logout />} />
                         <Route path="/map" element={<TrackingTool />} />
                         <Route path="*" element={<NotFound />} />
                     </Routes>
                 </Container>
             </Navigation>
-        </ThemeProvider>
+        </ThemeWrapper>
     )
 }
 
diff --git a/frontend/src/features/Auth/Login.tsx b/frontend/src/features/Auth/Login.tsx
index 5effcc9..b4ece4b 100644
--- a/frontend/src/features/Auth/Login.tsx
+++ b/frontend/src/features/Auth/Login.tsx
@@ -50,7 +50,6 @@ const Login = () => {
     return (
         <Fragment>
             <Typography variant="h3">Login</Typography>
-            <p>Credentials = admin:password</p>
 
             <form onSubmit={formik.handleSubmit}>
                 <TextField
diff --git a/frontend/src/features/Auth/Logout.tsx b/frontend/src/features/Auth/Logout.tsx
new file mode 100644
index 0000000..75874ff
--- /dev/null
+++ b/frontend/src/features/Auth/Logout.tsx
@@ -0,0 +1,25 @@
+import { useEffect } from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+import { Navigate } from 'react-router-dom'
+import { RootState } from '../redux/store'
+import { logout } from './userSlice'
+
+// Component that logs the user out if they are logged in
+const Logout = () => {
+    const userLoggedIn = useSelector(
+        (state: RootState) => state.user.isLoggedIn
+    )
+
+    const dispatch = useDispatch()
+    
+    // Check whether the user is logged in and if so log them out
+    useEffect(() => {
+        if (userLoggedIn) {
+            dispatch(logout())
+        }
+    }, [dispatch, userLoggedIn])
+
+    return <Navigate to="/" />
+}
+
+export default Logout
diff --git a/frontend/src/features/Auth/userSlice.ts b/frontend/src/features/Auth/userSlice.ts
index 0c8c0ab..bd85f6c 100644
--- a/frontend/src/features/Auth/userSlice.ts
+++ b/frontend/src/features/Auth/userSlice.ts
@@ -52,8 +52,8 @@ export const userSlice = createSlice({
             return ({ ...state, ...action.payload })
         })
         builder.addCase(logIn.rejected, (state, action) => {
-            if (action.payload && typeof action.payload === 'string') {
-                return ({ ...state, lastErr: action.payload })
+            if (action.payload && typeof action.error.message === 'string') {
+                return ({ ...state, lastErr: action.error.message })
             }
         })
     },
diff --git a/frontend/src/features/Catalog/CatalogFilter.tsx b/frontend/src/features/Catalog/CatalogFilter.tsx
index 48827bf..776d8f5 100644
--- a/frontend/src/features/Catalog/CatalogFilter.tsx
+++ b/frontend/src/features/Catalog/CatalogFilter.tsx
@@ -6,7 +6,7 @@ import {
     Stack,
     TextField,
 } from '@mui/material'
-import { Fragment } from 'react'
+import { Fragment, useEffect } from 'react'
 import { useDispatch, useSelector } from 'react-redux'
 import { setFilter, setFilterOpen } from './catalogSlice'
 import { fetchItems } from './catalogThunks'
@@ -29,6 +29,10 @@ const CatalogFilter = () => {
         dispatch(fetchItems())
     }
 
+    useEffect(() => {
+        console.log(filter)
+    }, [filter])
+
     return (
         <Fragment>
             <Button
@@ -51,8 +55,10 @@ const CatalogFilter = () => {
                                     id="name"
                                     label="Name"
                                     onChange={(e: any) => {
-                                        filter.name = e.target.value
-                                        dispatch(setFilter(filter))
+                                        dispatch(setFilter({
+                                            ...filter,
+                                            name: e.target.value
+                                        }))
                                     }}
                                     value={filter.name}
                                 />
@@ -61,8 +67,10 @@ const CatalogFilter = () => {
                                     id="type"
                                     label="Type"
                                     onChange={(e: any) => {
-                                        filter.type = e.target.value
-                                        dispatch(setFilter(filter))
+                                        dispatch(setFilter({
+                                            ...filter,
+                                            type: e.target.value
+                                        }))
                                     }}
                                     value={filter.type}
                                 />
@@ -78,8 +86,10 @@ const CatalogFilter = () => {
                                     id="stateOrTerritory"
                                     label="State or territory"
                                     onChange={(e: any) => {
-                                        filter.country = e.target.value
-                                        dispatch(setFilter(filter))
+                                        dispatch(setFilter({
+                                            ...filter,
+                                            country: e.target.value
+                                        }))
                                     }}
                                     value={filter.country}
                                 />
diff --git a/frontend/src/features/Catalog/catalogSlice.tsx b/frontend/src/features/Catalog/catalogSlice.tsx
index e3bf159..62e44a3 100644
--- a/frontend/src/features/Catalog/catalogSlice.tsx
+++ b/frontend/src/features/Catalog/catalogSlice.tsx
@@ -68,7 +68,7 @@ const catalogSlice = createSlice({
         builder.addCase(fetchItems.rejected, (state, action) => ({
             ...state,
             loading: false,
-            error: action.payload as string,
+            error: action.error.message as string,
         }))
     },
 })
diff --git a/frontend/src/features/Home/Home.tsx b/frontend/src/features/Home/Home.tsx
index 0ca56df..e7f521d 100644
--- a/frontend/src/features/Home/Home.tsx
+++ b/frontend/src/features/Home/Home.tsx
@@ -5,25 +5,9 @@ import { logout } from '../Auth/userSlice'
 import { RootState } from '../redux/store'
 
 const Home = () => {
-    const dispatch = useDispatch()
-
-    const userLoggedIn = useSelector(
-        (state: RootState) => state.user.isLoggedIn
-    )
-
     return (
         <Fragment>
             <h1>Home</h1>
-            {userLoggedIn ? (
-                <Button
-                    size="large"
-                    variant="contained"
-                    color="primary"
-                    onClick={() => dispatch(logout())}
-                >
-                    Logout
-                </Button>
-            ) : null}
         </Fragment>
     )
 }
diff --git a/frontend/src/features/Navigation/Navigation.tsx b/frontend/src/features/Navigation/Navigation.tsx
index 3ec1d6b..892ba47 100644
--- a/frontend/src/features/Navigation/Navigation.tsx
+++ b/frontend/src/features/Navigation/Navigation.tsx
@@ -5,21 +5,18 @@ import Drawer from '@mui/material/Drawer'
 import CssBaseline from '@mui/material/CssBaseline'
 import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar'
 import Toolbar from '@mui/material/Toolbar'
-import List from '@mui/material/List'
 import Typography from '@mui/material/Typography'
-import Divider from '@mui/material/Divider'
 import IconButton from '@mui/material/IconButton'
 import MenuIcon from '@mui/icons-material/Menu'
-import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'
-import ChevronRightIcon from '@mui/icons-material/ChevronRight'
-import ListItem from '@mui/material/ListItem'
-import ListItemIcon from '@mui/material/ListItemIcon'
-import ListItemText from '@mui/material/ListItemText'
-import InboxIcon from '@mui/icons-material/MoveToInbox'
-import MailIcon from '@mui/icons-material/Mail'
 import { Fragment, FunctionComponent } from 'react'
 import NavigationMenu from './NavigationMenu'
-import { Paper } from '@mui/material'
+import { Paper, Stack } from '@mui/material'
+import { useDispatch, useSelector } from 'react-redux'
+import { toggleTheme } from '../Theme/themeSlice'
+import { RootState } from '../redux/store'
+
+import DarkModeIcon from '@mui/icons-material/DarkMode'
+import LightModeIcon from '@mui/icons-material/LightMode'
 
 const drawerWidth = 240
 
@@ -83,6 +80,16 @@ const PersistentDrawerLeft: FunctionComponent<DrawerProps> = ({ children }) => {
         setOpen(true)
     }
 
+    const colorThemeMode = useSelector(
+        (state: RootState) => state.theme.paletteMode
+    )
+
+    const dispatch = useDispatch()
+
+    const onToggleTheme = () => {
+        dispatch(toggleTheme())
+    }
+
     return (
         <Fragment>
             <Paper style={{ minHeight: '100vh', borderRadius: 0 }}>
@@ -99,9 +106,22 @@ const PersistentDrawerLeft: FunctionComponent<DrawerProps> = ({ children }) => {
                             >
                                 <MenuIcon />
                             </IconButton>
-                            <Typography variant="h6" noWrap component="div">
-                                Assyrian Toponyms App Prototype
-                            </Typography>
+                            {/* <Box> */}
+                                <Typography variant="h6" noWrap component="div">
+                                    Assyrian Toponyms App Prototype
+                                </Typography>
+                                <Stack sx={{ml: 'auto'}} alignItems="flex-end">
+                                {colorThemeMode === 'dark' ? (
+                                    <IconButton onClick={onToggleTheme}>
+                                        <LightModeIcon />
+                                    </IconButton>
+                                ) : (
+                                    <IconButton onClick={onToggleTheme}>
+                                        <DarkModeIcon />
+                                    </IconButton>
+                                )}
+                                </Stack>
+                            {/* </Box> */}
                         </Toolbar>
                     </AppBar>
                     <NavigationMenu
diff --git a/frontend/src/features/Navigation/navigationMenuItems.ts b/frontend/src/features/Navigation/navigationMenuItems.ts
index 69dfcec..8a0bf34 100644
--- a/frontend/src/features/Navigation/navigationMenuItems.ts
+++ b/frontend/src/features/Navigation/navigationMenuItems.ts
@@ -6,6 +6,8 @@ import MapIcon from '@mui/icons-material/Map'
 import PersonIcon from '@mui/icons-material/Person'
 import LoginIcon from '@mui/icons-material/Login'
 import { SvgIconTypeMap } from '@mui/material'
+import DataSaverOffIcon from '@mui/icons-material/DataSaverOff'
+import LogoutIcon from '@mui/icons-material/Logout'
 
 export interface NavigationMenuItem {
     name: string
@@ -18,7 +20,10 @@ export interface NavigationMenuItem {
 
 const visitorRole = 'VISITOR'
 const visitorRoleOnly = 'VISITOR_ONLY'
+const loggedInRole = 'LOGGED_IN'
 const visitorAccess = new Set([visitorRole])
+const adminAccess = new Set(['ADMIN'])
+const loggedInAccess = new Set([loggedInRole])
 
 const items: NavigationMenuItem[] = [
     {
@@ -53,9 +58,9 @@ const items: NavigationMenuItem[] = [
     {
         name: 'Admin',
         path: '/admin',
-        accessibleTo: new Set(['ADMIN']),
+        accessibleTo: adminAccess,
         icon: PersonIcon,
-        position: 4,
+        position: 5,
     },
     // TODO move this to the top
     {
@@ -65,6 +70,20 @@ const items: NavigationMenuItem[] = [
         icon: LoginIcon,
         position: 5,
     },
+    {
+        name: 'Statistics',
+        path: '/stats',
+        accessibleTo: adminAccess,
+        icon: DataSaverOffIcon,
+        position: 4,
+    },
+    {
+        name: 'Logout',
+        path: '/logout',
+        accessibleTo: loggedInAccess,
+        icon: LogoutIcon,
+        position: 1337,
+    }
 ]
 
 const getNavigationItems = (_userRoles: string[]): NavigationMenuItem[] => {
@@ -74,6 +93,7 @@ const getNavigationItems = (_userRoles: string[]): NavigationMenuItem[] => {
         userRoles.push( visitorRole, visitorRoleOnly)
     } else {
         userRoles.push(visitorRole)
+        userRoles.push(loggedInRole)
     }
 
     return items // else return everything the user has privileges to
diff --git a/frontend/src/features/Reusables/ButtonOpenableDialog.tsx b/frontend/src/features/Reusables/ButtonOpenableDialog.tsx
new file mode 100644
index 0000000..366d10c
--- /dev/null
+++ b/frontend/src/features/Reusables/ButtonOpenableDialog.tsx
@@ -0,0 +1,66 @@
+import { Button, Dialog } from '@mui/material'
+import { Fragment, FunctionComponent, ReactNode, useState } from 'react'
+
+export interface ButtonOpenableDialogProps {
+    onOpenCallback?: () => void // this callback is always executed when the dialog is opened
+    onCloseCallback?: () => void // this callback is always executed when the dialog is closed
+    buttonText: string // the text of the button that opens the dialog
+    buttonColor: // the color of the button that opens the dialog
+    'primary' | 'secondary' | 'warning' | 'error' | 'success' | 'inherit'
+    buttonVariant: 'text' | 'outlined' | 'contained' // the variant of the button that opens the dialog
+    children: ReactNode // the content of the dialog
+    maxWidth?: 'xs' | 'sm' | 'md' | 'lg' // the max width of the dialog
+}
+
+// Generic dialog that can be opened by a button and closed by clicking on the backdrop.
+const ButtonOpenableDialog: FunctionComponent<ButtonOpenableDialogProps> = ({
+    onOpenCallback,
+    onCloseCallback,
+    buttonText,
+    buttonColor,
+    buttonVariant,
+    children,
+    maxWidth,
+}) => {
+    const [open, setOpen] = useState(false)
+
+    // Change maxWidth to large if its undefined
+    maxWidth = maxWidth ?? 'lg'
+
+    const onOpen = () => {
+        if (onOpenCallback) {
+            // execute the callback if exists
+            onOpenCallback()
+        }
+        setOpen(true)
+    }
+    const onClose = () => {
+        if (onCloseCallback) {
+            // execute the callback if exists
+            onCloseCallback()
+        }
+        setOpen(false)
+    }
+
+    return (
+        <Fragment>
+            <Button
+                onClick={onOpen}
+                color={buttonColor}
+                variant={buttonVariant}
+            >
+                {buttonText}
+            </Button>
+            <Dialog
+                fullWidth={true}
+                open={open}
+                onClose={onClose}
+                maxWidth={maxWidth}
+            >
+                {children}
+            </Dialog>
+        </Fragment>
+    )
+}
+
+export default ButtonOpenableDialog
diff --git a/frontend/src/features/Theme/ThemeWrapper.tsx b/frontend/src/features/Theme/ThemeWrapper.tsx
new file mode 100644
index 0000000..1cfa71f
--- /dev/null
+++ b/frontend/src/features/Theme/ThemeWrapper.tsx
@@ -0,0 +1,55 @@
+import { PaletteMode } from "@mui/material"
+import { createTheme, Theme, ThemeProvider } from '@mui/material/styles'
+import { FunctionComponent, ReactNode, useEffect, useState } from "react"
+import { useSelector } from "react-redux"
+import { RootState } from "../redux/store"
+
+export interface ThemeWrapperProps {
+    children: ReactNode
+}
+
+const ThemeWrapper: FunctionComponent<ThemeWrapperProps> = ({ children }) => {
+    
+    const buildTheme = (paletteMode: PaletteMode) =>
+        createTheme({
+            palette: {
+                mode: paletteMode,
+            },
+            shape: {
+                borderRadius: 16
+            },
+            typography: {
+                fontFamily: [
+                    '-apple-system',
+                    'BlinkMacSystemFont',
+                    '"Segoe UI"',
+                    'Roboto',
+                    '"Helvetica Neue"',
+                    'Arial',
+                    'sans-serif',
+                    '"Apple Color Emoji"',
+                    '"Segoe UI Emoji"',
+                    '"Segoe UI Symbol"',
+                ].join(','),
+            },
+        })
+
+    const paletteMode = useSelector(
+        (state: RootState) => state.theme.paletteMode
+    )
+
+    const [theme, setTheme] = useState<Theme>(buildTheme(paletteMode))
+    useEffect(() => {
+        setTheme(() => {
+            return buildTheme(paletteMode)
+        })
+    }, [paletteMode])
+
+    return (
+        <ThemeProvider theme={theme}>
+            {children}
+            </ThemeProvider>
+    )
+}
+
+export default ThemeWrapper
\ No newline at end of file
diff --git a/frontend/src/features/Theme/themeReducer.ts b/frontend/src/features/Theme/themeReducer.ts
deleted file mode 100644
index 504142a..0000000
--- a/frontend/src/features/Theme/themeReducer.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { createTheme, Theme } from '@mui/material/styles'
-import { AnyAction } from 'redux'
-import { persist } from '../../utils/statePersistence'
-
-export interface ThemeState {
-    theme: Theme
-    themeType: 'Light' | 'Dark'
-}
-
-const statePersistName = 'theme'
-
-const initialTheme = createTheme({
-    palette: {
-        mode: 'light'
-    },
-    typography: {
-        fontFamily: [
-      '-apple-system',
-      'BlinkMacSystemFont',
-      '"Segoe UI"',
-      'Roboto',
-      '"Helvetica Neue"',
-      'Arial',
-      'sans-serif',
-      '"Apple Color Emoji"',
-      '"Segoe UI Emoji"',
-      '"Segoe UI Symbol"',
-    ].join(','),
-    }
-})
-const initialState: ThemeState = {
-    theme: initialTheme,
-    themeType: 'Light',
-}
-
-export enum ThemeStateActions {
-    TOGGLE_THEME = 'TOGGLE_THEME',
-    SET_LIGHT_MODE = 'SET_LIGHT_MODE',
-    SET_DARK_MODE = 'SET_DARK_MODE',
-}
-
-const themeReducer = (state: ThemeState = initialState, action: AnyAction) => {
-    // TODO add all the actions
-    switch (action.type) {
-        case ThemeStateActions.TOGGLE_THEME:
-            return persist(statePersistName, state)
-
-        default:
-            return state
-    }
-}
-
-export default themeReducer
diff --git a/frontend/src/features/Theme/themeSlice.ts b/frontend/src/features/Theme/themeSlice.ts
new file mode 100644
index 0000000..162dea3
--- /dev/null
+++ b/frontend/src/features/Theme/themeSlice.ts
@@ -0,0 +1,33 @@
+import { createSlice } from '@reduxjs/toolkit'
+import { persistReducer } from 'redux-persist'
+import storage from 'redux-persist/lib/storage'
+import { PaletteMode } from '@mui/material'
+
+export interface ThemeState {
+    paletteMode: PaletteMode
+}
+
+const persistConfig = {
+    key: 'theme',
+    storage, // localStorage for browsers
+}
+
+const initialState: ThemeState = {
+    paletteMode: 'light',
+}
+
+const themeSlice = createSlice({
+    name: 'theme',
+    initialState,
+    reducers: {
+        toggleTheme: (state) => ({
+            ...state,
+            paletteMode: state.paletteMode === 'light' ? 'dark' : 'light',
+        }),
+    },
+})
+
+const themeReducer = persistReducer(persistConfig, themeSlice.reducer)
+// const themeReducer = themeSlice.reducer
+export const { toggleTheme } = themeSlice.actions
+export default themeReducer
diff --git a/frontend/src/features/TrackingTool/FileUpload.tsx b/frontend/src/features/TrackingTool/FileUpload.tsx
new file mode 100644
index 0000000..a5b4b5b
--- /dev/null
+++ b/frontend/src/features/TrackingTool/FileUpload.tsx
@@ -0,0 +1,158 @@
+import {
+    Button,
+    DialogContent,
+    DialogTitle,
+    Link,
+    Stack,
+    Typography,
+} from '@mui/material'
+import { useFormik } from 'formik'
+import { Fragment, useState } from 'react'
+import * as yup from 'yup'
+import axiosInstance from '../../api/api'
+import ButtonOpenableDialog from '../Reusables/ButtonOpenableDialog'
+import AttachmentIcon from '@mui/icons-material/Attachment'
+import DeleteIcon from '@mui/icons-material/Delete'
+import SendIcon from '@mui/icons-material/Send'
+
+const FileUpload = () => {
+    const [filename, setFilename] = useState<string | undefined>(undefined)
+
+    const validationSchema = yup.object().shape({
+        file: yup.mixed().required('File is required'),
+    })
+
+    const [submitButtonEnabled, setSubmitButtonEnabled] = useState(true)
+
+    const formik = useFormik({
+        initialValues: {
+            file: undefined,
+        },
+        validationSchema,
+        onSubmit: async (values) => {
+            // TODO actually send the file somewhere
+            // TODO implement me
+
+            const formData = new FormData()
+            // @ts-ignore for now
+            formData.append('file', values.file as File)
+
+            const { data } = await axiosInstance.post('/path', formData, {
+                headers: {
+                    'Content-Type': 'multipart/form-data',
+                },
+            })
+        },
+    })
+
+    // Callback when user selects the file
+    const onFileSelected = (event: any) => {
+        const file = event.currentTarget.files[0]
+        if (file) {
+            setFilename(file.name)
+            formik.setFieldValue('file', file)
+        }
+    }
+
+    const onClose = () => {
+        setFilename(undefined)
+        formik.resetForm()
+    }
+
+    const onClearSelectedFile = () => {
+        setFilename(undefined)
+        formik.setFieldValue('file', undefined)
+    }
+
+    return (
+        <ButtonOpenableDialog
+            buttonText="Upload File"
+            buttonColor="primary"
+            buttonVariant="contained"
+            onCloseCallback={onClose}
+            maxWidth="xs"
+        >
+            <DialogTitle>Upload New File</DialogTitle>
+            <DialogContent>
+                <form onSubmit={formik.handleSubmit}>
+                    {!filename ? (
+                        <Fragment>
+                            <Stack
+                                direction="row"
+                                justifyContent="flex-end"
+                                alignItems="center"
+                            >
+                                <Button
+                                    variant="contained"
+                                    color="primary"
+                                    component="label"
+                                    // size="small"
+                                    startIcon={<AttachmentIcon />}
+                                >
+                                    Select File
+                                    <input
+                                        id="file"
+                                        name="file"
+                                        type="file"
+                                        hidden
+                                        onChange={onFileSelected}
+                                    />
+                                </Button>
+                            </Stack>
+                        </Fragment>
+                    ) : (
+                        <Fragment>
+                            <Stack direction="row" spacing={1}>
+                                <Typography
+                                    sx={{
+                                        // textOverflow: 'ellipsis',
+                                        // overflow: 'hidden',
+                                    }}
+                                    variant="body1"
+                                >
+                                    Selected File:{' '}
+                                </Typography>
+                                <Typography
+                                    sx={{
+                                        textOverflow: 'ellipsis',
+                                        overflow: 'hidden',
+                                    }}
+                                    // color="text.secondary"
+                                    component={Link}
+                                    // download={(formik.values?.file as File).}
+                                    // align="right"
+                                >
+                                    {filename}
+                                </Typography>
+                            </Stack>
+                            <Stack
+                                direction="row"
+                                justifyContent="flex-end"
+                                alignItems="center"
+                                spacing={2}
+                                sx={{mt: 2}}
+                            >
+                                <Button
+                                    // sx={{ mb: 2, mt: 1 }}
+                                    variant="contained"
+                                    size="small"
+                                    endIcon={<DeleteIcon />}
+                                    onClick={onClearSelectedFile}
+                                >
+                                    Remove Selection
+                                </Button>
+                                <Button size="small" type="submit" variant="contained" startIcon={<SendIcon />}>
+                                Submit
+                            </Button>
+                            </Stack>
+                            
+                            
+                        </Fragment>
+                    )}
+                </form>
+            </DialogContent>
+        </ButtonOpenableDialog>
+    )
+}
+
+export default FileUpload
diff --git a/frontend/src/features/TrackingTool/PlaintextUpload.tsx b/frontend/src/features/TrackingTool/PlaintextUpload.tsx
new file mode 100644
index 0000000..98788d7
--- /dev/null
+++ b/frontend/src/features/TrackingTool/PlaintextUpload.tsx
@@ -0,0 +1,72 @@
+import {
+    Button,
+    DialogContent,
+    DialogTitle,
+    Stack,
+    TextField,
+} from '@mui/material'
+import { useFormik } from 'formik'
+import { Fragment } from 'react'
+import ButtonOpenableDialog from '../Reusables/ButtonOpenableDialog'
+import SendIcon from '@mui/icons-material/Send'
+import ClearIcon from '@mui/icons-material/Clear'
+
+const PlaintextUpload = () => {
+    const formik = useFormik({
+        initialValues: {
+            text: '',
+        },
+        onSubmit: () => {
+        },
+    })
+
+    const resetForm = () => {
+        formik.resetForm()
+    }
+
+    return (
+        <Fragment>
+            <ButtonOpenableDialog
+                buttonText="Plaintext"
+                buttonColor="primary"
+                buttonVariant="contained"
+            >
+                <DialogTitle>Plaintext Input</DialogTitle>
+                <DialogContent>
+                    <form onSubmit={formik.handleChange}>
+                        <TextField
+                            sx={{ my: 2 }}
+                            fullWidth
+                            multiline
+                            label="Plaintext input"
+                            rows={10}
+                            name="text"
+                            value={formik.values.text}
+                            onChange={formik.handleChange}
+                        />
+                        <Stack
+                            alignItems="flex-end"
+                            justifyContent="flex-end"
+                            spacing={2}
+                            direction="row"
+                        >
+                            <Button
+                                variant="contained"
+                                color="secondary"
+                                onClick={resetForm}
+                                startIcon={<ClearIcon />}
+                            >
+                                Clear
+                            </Button>
+                            <Button type="submit" variant="contained" startIcon={<SendIcon />}>
+                                Submit
+                            </Button>
+                        </Stack>
+                    </form>
+                </DialogContent>
+            </ButtonOpenableDialog>
+        </Fragment>
+    )
+}
+
+export default PlaintextUpload
diff --git a/frontend/src/features/TrackingTool/TrackingTool.tsx b/frontend/src/features/TrackingTool/TrackingTool.tsx
index 6992632..75fec31 100644
--- a/frontend/src/features/TrackingTool/TrackingTool.tsx
+++ b/frontend/src/features/TrackingTool/TrackingTool.tsx
@@ -4,10 +4,12 @@ import AddIcon from '@mui/icons-material/Add'
 import { MapContainer, Marker, Polyline, Popup, TileLayer } from 'react-leaflet'
 import mapConfig from '../../config/mapConfig'
 import TextPath from 'react-leaflet-textpath'
+import PlaintextUpload from './PlaintextUpload'
+import FileUpload from './FileUpload'
 
 // Page with tracking tool
 const TrackingTool = () => {
-    const generateDummyPath = () => {
+    const createDummyPathCoords = () => {
         // Sample dummy path to display
         const dummyPath = []
         for (let i = 0; i < 10; i += 1) {
@@ -25,15 +27,15 @@ const TrackingTool = () => {
         return dummyPath
     }
 
-    const createDummyPathPolylines = () => {
-        const dummyPath = generateDummyPath()
+    const createDummyPath = () => {
+        const coords = createDummyPathCoords()
         const polylines: any[] = []
 
-        if (dummyPath.length < 2) {
+        if (coords.length < 2) {
             return []
         }
 
-        for (let i = 0; i < dummyPath.length - 1; i += 1) {
+        for (let i = 0; i < coords.length - 1; i += 1) {
             polylines.push(
                 // <Polyline
                 //     key={i}
@@ -51,13 +53,13 @@ const TrackingTool = () => {
                 //     </Polyline>
                 <TextPath
                     positions={[
-                        [dummyPath[i].latitude, dummyPath[i].longitude],
-                        [dummyPath[i + 1].latitude, dummyPath[i + 1].longitude],
+                        [coords[i].latitude, coords[i].longitude],
+                        [coords[i + 1].latitude, coords[i + 1].longitude],
                     ]}
                     text="►"
                     attributes={{
                         'font-size': 25,
-                        'fill': 'blue'
+                        fill: 'blue',
                     }}
                     repeat
                     center
@@ -68,10 +70,10 @@ const TrackingTool = () => {
             )
         }
 
-        return polylines
+        return [polylines, coords]
     }
 
-    const polylines = createDummyPathPolylines()
+    const [polylines, coords] = createDummyPath()
 
     return (
         <Fragment>
@@ -94,20 +96,8 @@ const TrackingTool = () => {
                         >
                             Upload:
                         </Typography>
-                        <Button
-                            variant="contained"
-                            color="primary"
-                            startIcon={<AddIcon />}
-                        >
-                            Plaintext
-                        </Button>
-                        <Button
-                            variant="contained"
-                            color="primary"
-                            startIcon={<AddIcon />}
-                        >
-                            File
-                        </Button>
+                        <PlaintextUpload />
+                        <FileUpload />
                     </Stack>
                 </Grid>
                 <Grid
@@ -132,6 +122,9 @@ const TrackingTool = () => {
                             attribution={mapConfig.attribution}
                             url={mapConfig.url}
                         />
+                        {coords.map(({ latitude, longitude }, idx) => (
+                            <Marker position={[latitude, longitude]} />
+                        ))}
                         {polylines}
                     </MapContainer>
                 </Grid>
diff --git a/frontend/src/features/redux/store.ts b/frontend/src/features/redux/store.ts
index b3addad..e5bc471 100644
--- a/frontend/src/features/redux/store.ts
+++ b/frontend/src/features/redux/store.ts
@@ -2,7 +2,7 @@ import { applyMiddleware, combineReducers, createStore } from 'redux'
 import { persistStore } from 'redux-persist'
 import thunk from 'redux-thunk'
 import userReducer from '../Auth/userSlice'
-import themeReducer from '../Theme/themeReducer'
+import themeReducer from '../Theme/themeSlice'
 import catalogReducer from '../Catalog/catalogSlice'
 import { composeWithDevTools } from 'redux-devtools-extension'
 
@@ -16,7 +16,7 @@ const store = createStore(
         catalog: catalogReducer,
     }),
     process.env.REACT_APP_DEV_ENV === 'true'
-        ? composeEnhancers(
+        ? composeEnhancers( // ComposeEnhancers will inject redux-devtools-extension
               applyMiddleware(thunk) // Thunk middleware so we can async fetch data from the api
           )
         : applyMiddleware(thunk)
