diff --git a/src/components/admin/ImageManager.tsx b/src/components/admin/ImageManager.tsx
index 22a46f403421d22ae7783ce94b7f7b6c904daf5d..92c101d7b9648eccbfd1beebbee64a370827e1d9 100644
--- a/src/components/admin/ImageManager.tsx
+++ b/src/components/admin/ImageManager.tsx
@@ -1,63 +1,318 @@
-import React, { useState } from 'react'
+import React, { useRef, useState } from 'react'
 import Button from '@material-ui/core/Button'
 import Dialog from '@material-ui/core/Dialog'
 import DialogActions from '@material-ui/core/DialogActions'
 import DialogContent from '@material-ui/core/DialogContent'
 import DialogTitle from '@material-ui/core/DialogTitle'
+import IconButton from '@material-ui/core/IconButton'
+import DeleteIcon from '@material-ui/icons/Delete'
 import CircularProgress from '@material-ui/core/CircularProgress'
+import Chip from '@material-ui/core/Chip'
 import { useEffect } from 'react'
 import { ImagesInformationResponse } from '../../types/ApiTypes'
+import { createStyles, makeStyles, Theme } from '@material-ui/core'
+import { Checkbox } from '@material-ui/core'
+import { useCallback } from 'react'
+
+const useStyles = makeStyles((theme: Theme) =>
+    createStyles({
+        previewWrapper: {
+            width: '100%',
+            maxWidth: '100%',
+            position: 'relative',
+            overflow: 'hidden',
+            borderRadius: '6px',
+            backgroundColor: theme.palette.grey[500]
+        },
+        previewWrapperSelected: {
+            '&::before': {
+                borderRadius: '6px',
+                position: 'absolute',
+                top: '0',
+                right: '0',
+                bottom: '0',
+                left: '0',
+                content: '""',
+                border: '4px solid ' + theme.palette.primary.main,
+                background: `linear-gradient(0deg, ${theme.palette.primary.main} 0%, rgba(255,255,255,0) 35%, rgba(255,255,255,0) 100%)`
+            }
+        },
+        previewImage: {
+            width: '100%'
+        },
+        previewOverlay: {
+            padding: '6px',
+            position: 'absolute',
+            display: 'grid',
+            gridTemplateColumns: 'auto auto',
+            top: '0',
+            left: '0',
+            right: '0',
+            bottom: '0'
+        },
+        content: {
+            display: 'grid',
+            gridTemplateColumns: '1fr 1fr',
+            gap: '6px'
+        },
+        deleteImage: {
+            backgroundColor: theme.palette.error.main,
+            '&:hover': {
+                backgroundColor: theme.palette.error.light
+            }
+        },
+        selectImage: {
+            justifySelf: 'start',
+            alignSelf: 'end',
+            backgroundColor: 'rgba(255, 255, 255, 0.8)',
+            borderRadius: '6px'
+        },
+        uploadDate: {
+            justifySelf: 'end',
+            alignSelf: 'end',
+            '& > p': {
+                backgroundColor: 'rgba(255, 255, 255, 0.8)',
+                margin: '0',
+                padding: '6px',
+                borderRadius: '6px'
+            }
+        },
+        hiddenInput: {
+            display: 'none'
+        },
+        dialogHeader: {
+            '& > h2': {
+                display: 'grid',
+                gridTemplateColumns: 'auto auto'
+            }
+        }
+    })
+)
+
+interface ImagePreviewProps {
+    imageMetaData: ImagesInformationResponse[number]
+    selectedUrl: string | undefined
+    onSelect: (url: string | undefined) => void
+    onDelete: (url: string | undefined) => void
+}
+
+export const ImagePreview: React.FC<ImagePreviewProps> = ({
+    imageMetaData,
+    selectedUrl,
+    onSelect,
+    onDelete
+}) => {
+    const classes = useStyles()
+
+    const isSelected = selectedUrl === imageMetaData.url
+    const wrapperClasses = [classes.previewWrapper]
+    if (isSelected) wrapperClasses.push(classes.previewWrapperSelected)
+
+    const deleteImage = useCallback(async () => {
+        if (imageMetaData.activeUsages > 0) {
+            if (
+                !window.confirm(
+                    `Dieses Bild ist aktuell ${imageMetaData.activeUsages}x zum Anzeigen ausgewählt. Wenn sie dieses Bild löschen, werden alle Referenzen ebenfalls gelöscht.`
+                )
+            ) {
+                console.log('cancelled image delete')
+                return
+            }
+        }
+
+        const res = await fetch(imageMetaData.url, { method: 'DELETE' })
+        if (res.status !== 200) {
+            console.error(
+                'failed to delete image ' +
+                    imageMetaData.url +
+                    ' | status: ' +
+                    res.status
+            )
+            return
+        }
+
+        if (selectedUrl === imageMetaData.url) {
+            onSelect(undefined) // make sure not to select deleted image
+        }
+        onDelete(imageMetaData.url)
+    }, [imageMetaData, onSelect, onDelete, selectedUrl])
+
+    return (
+        <div className={wrapperClasses.join(' ')}>
+            <div className={classes.previewOverlay}>
+                <Chip
+                    style={{ justifySelf: 'start' }}
+                    label={`${imageMetaData.activeUsages}x in Nutzung`}
+                    color="primary"
+                />
+                <div style={{ justifySelf: 'end' }}>
+                    <IconButton
+                        aria-label="delete"
+                        className={classes.deleteImage}
+                        size="small"
+                        onClick={deleteImage}
+                    >
+                        <DeleteIcon fontSize="small" />
+                    </IconButton>
+                </div>
+                <div className={classes.selectImage}>
+                    <Checkbox
+                        color="primary"
+                        checked={isSelected}
+                        onChange={(e) =>
+                            onSelect(
+                                e.target.checked ? imageMetaData.url : undefined
+                            )
+                        }
+                    ></Checkbox>
+                </div>
+                <div className={classes.uploadDate}>
+                    <p>{imageMetaData.uploaded}</p>
+                </div>
+            </div>
+            <img src={imageMetaData.url} className={classes.previewImage}></img>
+        </div>
+    )
+}
+
 interface PopupProps {
     open: boolean
     onClose: (url: string | null) => void
 }
 
 export const ImageManagerPopup: React.FC<PopupProps> = ({ open, onClose }) => {
+    const classes = useStyles()
     const [
         allImages,
         setAllImages
     ] = useState<ImagesInformationResponse | null>(null)
+    const [selectedUrl, setSelectedUrl] = useState<string | undefined>(
+        undefined
+    )
+    const fileSelectorRef = useRef<HTMLInputElement>(null)
+
+    async function fetchImages() {
+        setAllImages(null)
+        const response: ImagesInformationResponse = await (
+            await fetch('/api/image')
+        ).json()
+        if (!Array.isArray(response)) {
+            console.error('error in /api/image response', response)
+            alert('Etwas ist schief gelaufen :/')
+            return
+        }
+        setAllImages(response)
+    }
 
     useEffect(() => {
-        async function inner() {
-            const response: ImagesInformationResponse = await (
-                await fetch('/api/image')
-            ).json()
-            if (!Array.isArray(response)) {
-                console.error('error in /api/image response', response)
-                alert('Etwas ist schief gelaufen :/')
+        fetchImages() // allows async funcion inside useEffect
+    }, [])
+
+    async function uploadImage(imageFileList: FileList | null) {
+        if (!imageFileList?.[0]) {
+            // no file selected
+            alert('Keine Datei ausgewählt oder falsche Endung')
+            return
+        }
+        const imageFile: File = imageFileList[0]
+        if (imageFile.size >= 4000000) {
+            alert('Bild darf max. 4MB groß sein (empfohlen: < 500kB)')
+            return
+        }
+        if (imageFile.size > 500000) {
+            if (
+                !window.confirm(
+                    `Bild hat ${Math.ceil(
+                        imageFile.size / 1000
+                    )}kB Größe, empfohlen: <500kB. Wollen sie wirklich hochladen?`
+                )
+            ) {
                 return
             }
-            setAllImages(response)
         }
-        inner() // allows async funcion inside useEffect
-    }, [])
+        console.log('uploading image...')
+
+        const res = await fetch('/api/image', {
+            method: 'POST',
+            body: imageFile
+        })
 
-    function handleClose() {
-        onClose(null)
+        if (res.status !== 200) {
+            const body = await res.text()
+            alert('Upload failed: ' + body)
+        } else {
+            const { url } = await res.json()
+            // success, load image and set as selected
+            await fetchImages()
+            setSelectedUrl(url)
+        }
     }
 
     return (
         <Dialog
             open={open}
-            onClose={handleClose}
+            onClose={() => onClose(null)}
             aria-labelledby="alert-dialog-title"
             aria-describedby="alert-dialog-description"
         >
-            <DialogTitle id="alert-dialog-title">Bild Manager</DialogTitle>
-            {allImages ? (
-                <DialogContent>
-                    <h1>Imagessss</h1>
-                </DialogContent>
-            ) : (
-                <CircularProgress />
-            )}
-
+            <DialogTitle
+                id="alert-dialog-title"
+                className={classes.dialogHeader}
+            >
+                Bild Manager
+                <input
+                    ref={fileSelectorRef}
+                    accept="image/*"
+                    className={classes.hiddenInput}
+                    id="contained-button-file"
+                    multiple
+                    type="file"
+                    onChange={(e) => uploadImage(e.target.files)}
+                />
+                <label
+                    htmlFor="contained-button-file"
+                    style={{ justifySelf: 'end' }}
+                >
+                    <Button
+                        variant="contained"
+                        color="primary"
+                        component="span"
+                    >
+                        Bild hochladen
+                    </Button>
+                </label>
+            </DialogTitle>
+            <DialogContent className={classes.content}>
+                {allImages ? (
+                    allImages.map((iMD) => (
+                        <ImagePreview
+                            key={iMD.url}
+                            imageMetaData={iMD}
+                            selectedUrl={selectedUrl}
+                            onSelect={setSelectedUrl}
+                            onDelete={fetchImages}
+                        />
+                    ))
+                ) : (
+                    <CircularProgress />
+                )}
+            </DialogContent>
             <DialogActions>
-                <Button onClick={handleClose} color="primary">
+                <Button
+                    onClick={() => {
+                        onClose(null)
+                    }}
+                    color="primary"
+                >
                     Close
                 </Button>
-                <Button onClick={handleClose} color="primary" autoFocus>
+                <Button
+                    onClick={() => {
+                        onClose(selectedUrl ?? null)
+                    }}
+                    color="primary"
+                    autoFocus
+                >
                     Agree
                 </Button>
             </DialogActions>
diff --git a/src/components/admin/snacks & co/SnackTable.tsx b/src/components/admin/snacks & co/SnackTable.tsx
index 74304c1ac03b707013ec4f0fdbe8b894f320bd77..4ea181d03d6ee7078cfb1b542cbc0969e39afef7 100644
--- a/src/components/admin/snacks & co/SnackTable.tsx	
+++ b/src/components/admin/snacks & co/SnackTable.tsx	
@@ -89,7 +89,10 @@ export const SnackTable: React.FC<SnackTableProps> = ({
                     } else return null
                 })}
             </TableBody>
-            <ImageManagerPopup open={showImage} onClose={() => setShowImage(false)}></ImageManagerPopup>
+            <ImageManagerPopup
+                open={showImage}
+                onClose={() => setShowImage(false)}
+            ></ImageManagerPopup>
         </Table>
     )
 }