diff --git a/public/locales/bg/common.json b/public/locales/bg/common.json
index ae80523fc..17451819b 100644
--- a/public/locales/bg/common.json
+++ b/public/locales/bg/common.json
@@ -130,6 +130,12 @@
     "agree-with-newsletter": "Съгласявам се да получавам известия.",
     "agree-with-newsletter-campaign": "Съгласявам се да получавам новини за тази кампания и известия от Подкрепи.бг."
   },
+  "files": {
+    "attached-files": "Прикачени файлове",
+    "download": "Изтегляне",
+    "errorDeletingFile": "Грешка при изтриване на файл",
+    "deletedFile": "Успешно изтрит файл"
+  },
   "cookieConsent": "Подкрепи.бг не използва бисквитки, освен тези от трети страни, нужни за аналитичните компоненти Google Analytics и HotJar. Приемането на бисквитките ще ни помогне да подобрим вашето потребителско преживяване.",
   "cookieConsentButton": "Приемам",
   "cookieRejectButton": "Отхвърлям",
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index d0af58071..39dbaa6db 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -130,6 +130,12 @@
     "agree-with-newsletter": "I agree to receive news.",
     "agree-with-newsletter-campaign": "I agree to receive news about this campaign and news by Podkrepi.bg."
   },
+  "files": {
+    "attached-files": "Attached files",
+    "download": "Download",
+    "errorDeletingFile": "Failure deleting file",
+    "deletedFile": "Successfully deleted file"
+  },
 
   "cookieConsent": "Podkrepi.bg doesn't use cookies, except the third-party cookies required for the analytics components Google Analytics and HotJar. Accepting the cookies will help us improve your user experience.",
   "cookieConsentButton": "Accept",
diff --git a/src/components/admin/campaign-applications/CampaignApplicationAdminPropsEdit.tsx b/src/components/admin/campaign-applications/CampaignApplicationAdminPropsEdit.tsx
index 52171a6c7..0bfaeec3a 100644
--- a/src/components/admin/campaign-applications/CampaignApplicationAdminPropsEdit.tsx
+++ b/src/components/admin/campaign-applications/CampaignApplicationAdminPropsEdit.tsx
@@ -9,8 +9,16 @@ import {
 import { CamAppDetail } from 'components/client/campaign-application/steps/CampaignApplicationSummary'
 import CheckboxField from 'components/common/form/CheckboxField'
 import OrganizerCanEditAt from './CampaignApplicationOrganizerCanEditAt'
+import { UploadedFile } from 'components/common/file-upload/UploadedFilesList'
+import UploadedCampaignApplicationFiles from './UploadedCampaignApplicationFiles'
 
-export default function CampaignApplicationAdminPropsEdit({ id }: { id: string }) {
+export default function CampaignApplicationAdminPropsEdit({
+  id,
+  files,
+}: {
+  id: string
+  files: UploadedFile[]
+}) {
   const { t } = useTranslation('campaign-application')
   return (
     <Grid container spacing={6} justifyContent="center" direction="column" alignContent="center">
@@ -40,6 +48,9 @@ export default function CampaignApplicationAdminPropsEdit({ id }: { id: string }
           value={<OrganizerCanEditAt id={id} />}
         />
       </Grid>
+      <Grid item>
+        <UploadedCampaignApplicationFiles files={files} campaignApplicationId={id} />
+      </Grid>
     </Grid>
   )
 }
diff --git a/src/components/admin/campaign-applications/EditPage.tsx b/src/components/admin/campaign-applications/EditPage.tsx
index 7fdc80e11..76aa23936 100644
--- a/src/components/admin/campaign-applications/EditPage.tsx
+++ b/src/components/admin/campaign-applications/EditPage.tsx
@@ -2,6 +2,7 @@ import { Box, CircularProgress, Grid, Typography } from '@mui/material'
 import { red } from '@mui/material/colors'
 import { CampaignApplicationFormData } from 'components/client/campaign-application/helpers/campaignApplication.types'
 import { ActionSubmitButton } from 'components/client/campaign-application/helpers/campaignApplicationFormActions.styled'
+import { campaignApplicationAdminValidationSchema } from 'components/client/campaign-application/helpers/validation-schema'
 import CampaignApplicationBasic from 'components/client/campaign-application/steps/CampaignApplicationBasic'
 import CampaignApplicationDetails from 'components/client/campaign-application/steps/CampaignApplicationDetails'
 import CampaignApplicationOrganizer from 'components/client/campaign-application/steps/CampaignApplicationOrganizer'
@@ -21,7 +22,6 @@ import {
 } from 'service/campaign-application'
 import CampaignApplicationAdminPropsEdit from './CampaignApplicationAdminPropsEdit'
 import OrganizerCanEditAt from './CampaignApplicationOrganizerCanEditAt'
-import { campaignApplicationAdminValidationSchema } from 'components/client/campaign-application/helpers/validation-schema'
 
 export type Props = {
   id: string
@@ -83,7 +83,7 @@ export function EditLoadedCampaign({ campaign }: { campaign: CampaignApplication
             }}
             initialValues={c.initialValues}
             validationSchema={campaignApplicationAdminValidationSchema.defined()}>
-            <CampaignApplicationAdminPropsEdit id={campaign.id} />
+            <CampaignApplicationAdminPropsEdit id={campaign.id} files={campaign.documents} />
             <CampaignApplicationOrganizer isAdmin={true} />
             <CampaignApplicationBasic />
             <CampaignApplicationDetails files={c.files} setFiles={c.setFiles} />
diff --git a/src/components/admin/campaign-applications/UploadedCampaignApplicationFiles.tsx b/src/components/admin/campaign-applications/UploadedCampaignApplicationFiles.tsx
new file mode 100644
index 000000000..457dcbf7b
--- /dev/null
+++ b/src/components/admin/campaign-applications/UploadedCampaignApplicationFiles.tsx
@@ -0,0 +1,43 @@
+import { useMutation, useQueryClient } from '@tanstack/react-query'
+import { AxiosError } from 'axios'
+import { useTranslation } from 'next-i18next'
+
+import { endpoints } from 'service/apiEndpoints'
+import { ApiErrors } from 'service/apiErrors'
+
+import { UploadedFile, UploadedFilesList } from 'components/common/file-upload/UploadedFilesList'
+
+import { useSession } from 'next-auth/react'
+import {
+  fetchCampaignApplicationFile,
+  useDeleteCampaignApplicationFile,
+} from 'service/campaign-application'
+import { AlertStore } from 'stores/AlertStore'
+
+type Props = {
+  campaignApplicationId: string
+  files: UploadedFile[]
+}
+
+export default function UploadedCampaignApplicationFiles({ files, campaignApplicationId }: Props) {
+  const { t } = useTranslation(['common', 'campaign-applications'])
+  const queryClient = useQueryClient()
+  const { data: session } = useSession()
+
+  const del = useMutation<unknown, AxiosError<ApiErrors>, string>({
+    mutationFn: (fileId) => useDeleteCampaignApplicationFile(session)(fileId),
+    onError: () => AlertStore.show(t('common:alerts.errorDeletingFile'), 'error'),
+    onSuccess: () => {
+      AlertStore.show(t('common:files.deletedFile'), 'success')
+      queryClient.invalidateQueries([endpoints.campaignApplication.view(campaignApplicationId).url])
+    },
+  })
+
+  return (
+    <UploadedFilesList
+      files={files}
+      downloadQuery={(f) => fetchCampaignApplicationFile(f.id, session).then((r) => r.data)}
+      deleteMutation={(f) => del.mutateAsync(f.id)}
+    />
+  )
+}
diff --git a/src/components/common/file-upload/UploadedFilesList.tsx b/src/components/common/file-upload/UploadedFilesList.tsx
new file mode 100644
index 000000000..4c3e15a25
--- /dev/null
+++ b/src/components/common/file-upload/UploadedFilesList.tsx
@@ -0,0 +1,218 @@
+import { Close, Delete, FilePresent, Preview } from '@mui/icons-material'
+import {
+  Avatar,
+  Button,
+  IconButton,
+  List,
+  ListItem,
+  ListItemAvatar,
+  ListItemText,
+  Tooltip,
+} from '@mui/material'
+import { useTranslation } from 'next-i18next'
+import { createContext, useContext, useEffect, useState } from 'react'
+import CenteredSpinner from '../CenteredSpinner'
+
+export interface FilesListContext {
+  deleteMutation: (file: UploadedFile) => Promise<unknown>
+  files: UploadedFile[]
+  getBlobUrl: (file: UploadedFile) => Promise<string>
+  download: (file: UploadedFile) => void
+}
+
+const UploadedFilesContext = createContext<FilesListContext>({
+  files: [],
+  download: () => Promise.reject('download query missing'),
+  deleteMutation: () => Promise.reject('delete mutation missing'),
+  getBlobUrl: () => Promise.reject('Function not implemented.'),
+})
+
+export interface UploadedFilesListProps {
+  title?: string | JSX.Element | undefined
+  files: UploadedFile[]
+  downloadQuery: (f: UploadedFile) => Promise<Blob>
+  deleteMutation: (f: UploadedFile) => Promise<unknown>
+  downloadText?: string
+}
+
+export function UploadedFilesList({
+  title: maybeTitle,
+  files,
+  downloadQuery,
+  deleteMutation,
+  downloadText: maybeDownloadText,
+}: UploadedFilesListProps) {
+  const { t } = useTranslation('common')
+  const filesCtx = filesListContext({
+    files,
+    downloadQuery,
+    deleteMutation,
+  })
+
+  const title = maybeTitle != null ?? t('files.attached-files')
+  const downloadText = maybeDownloadText ?? t('files.download')
+
+  return (
+    <UploadedFilesContext.Provider value={filesCtx}>
+      <List dense>
+        {typeof title === 'string' ? <ListItemText primary={title} /> : title}
+        {(files ?? []).map((file) => (
+          <UploadedFileView key={file.id} file={file} downloadText={downloadText} />
+        ))}
+      </List>
+    </UploadedFilesContext.Provider>
+  )
+}
+
+export type UploadedFileViewProps = {
+  file: UploadedFile
+  role?: string
+  downloadText: string
+}
+
+export function UploadedFileView({ file, role, downloadText }: UploadedFileViewProps) {
+  const { deleteMutation, download } = useContext(UploadedFilesContext)
+
+  return (
+    <ListItem key={file.id}>
+      <ListItemAvatar>
+        <Avatar>
+          <FilePresent />
+        </Avatar>
+      </ListItemAvatar>
+      <ListItemText primary={file.filename} />
+      {role && <ListItemText primary={role} sx={{ textAlign: 'right', pr: 'inherit' }} />}
+      <></>
+      <Tooltip title={'download'}>
+        <Button onClick={() => download(file)}>{downloadText}</Button>
+      </Tooltip>
+      <FilePreview {...file} />
+      <IconButton edge="end" aria-label="delete" onClick={() => deleteMutation(file)}>
+        <Delete />
+      </IconButton>
+    </ListItem>
+  )
+}
+
+export function FilePreview(f: UploadedFile) {
+  const { getBlobUrl } = useContext(UploadedFilesContext)
+  const [fetch, setFetch] = useState(false)
+  const [display, setDisplay] = useState<'block' | 'none'>('none')
+  const [blobUrl, setBlobUrl] = useState<string | undefined>()
+
+  useEffect(() => {
+    if (fetch) {
+      setDisplay('block')
+      getBlobUrl(f)
+        .then(setBlobUrl)
+        .then(() => setFetch(false))
+        .catch((e) => {
+          console.log(e)
+        })
+    }
+  }, [fetch])
+  return (
+    <>
+      <Tooltip title={'preview'}>
+        <IconButton edge="end" aria-label="preview" onClick={() => setFetch(true)}>
+          <Preview />
+        </IconButton>
+      </Tooltip>
+      <div
+        style={{
+          position: 'fixed',
+          top: '5vw',
+          left: '5vh',
+          boxShadow: '2px 4px 5px',
+          width: '90vw',
+          height: '90vh',
+          zIndex: 99999,
+          display,
+          backgroundColor: 'white',
+        }}>
+        {display === 'block' ? (
+          <iframe
+            id={f.id}
+            src={blobUrl}
+            allowFullScreen={true}
+            style={{ width: '100%', height: '100%' }}
+          />
+        ) : (
+          <div style={{ width: '100%', height: '100%' }}>
+            <CenteredSpinner />
+          </div>
+        )}
+        <Button
+          color="secondary"
+          variant="outlined"
+          sx={{ position: 'absolute', right: '-2rem', top: '-2.5rem' }}
+          onClick={() => setDisplay('none')}>
+          <Close />
+        </Button>
+      </div>
+    </>
+  )
+}
+
+export interface FilesListContextInput {
+  files: UploadedFile[]
+  downloadQuery: (file: UploadedFile) => Promise<Blob>
+  deleteMutation: (file: UploadedFile) => Promise<unknown>
+}
+export function filesListContext({ files, downloadQuery, deleteMutation }: FilesListContextInput) {
+  const blobUrls: Record<string, string> = {}
+  async function downloadAndGetBlobUrl(file: UploadedFile) {
+    if (blobUrls[file.id]) {
+      return blobUrls[file.id]
+    } else {
+      return downloadQuery(file)
+        .then((blob) => {
+          const b = window.URL.createObjectURL(new Blob([blob], { type: blob.type }))
+          blobUrls[file.id] = b
+          return b
+        })
+        .catch((error) => {
+          console.error(error)
+          // don't store it so next time we'll retry fetching
+          return window.URL.createObjectURL(
+            new Blob(
+              [
+                `<html>
+                  <body>
+                    <h3 style="text-align:center; margin-top: 10%">
+                      Could not fetch the file. Please retry
+                    </h3>
+                  </body>
+                </html>`,
+              ],
+              {
+                type: 'text/html',
+              },
+            ),
+          )
+        })
+    }
+  }
+
+  async function download(f: UploadedFile) {
+    const blobUrlForDownload = await downloadAndGetBlobUrl(f)
+    const link = document.createElement('a')
+    link.href = blobUrlForDownload
+    link.setAttribute('download', `${f.filename}`)
+    link.click()
+  }
+
+  const context: FilesListContext = {
+    deleteMutation,
+    files,
+    download,
+    getBlobUrl: downloadAndGetBlobUrl,
+  }
+
+  return context
+}
+
+export interface UploadedFile {
+  id: string
+  filename: string
+}
diff --git a/src/service/apiEndpoints.ts b/src/service/apiEndpoints.ts
index 39a455d0c..ec3e81262 100644
--- a/src/service/apiEndpoints.ts
+++ b/src/service/apiEndpoints.ts
@@ -433,5 +433,7 @@ export const endpoints = {
       <Endpoint>{ url: `/campaign-application/fileById/${fileId}`, method: 'DELETE' },
     view: (id: string) => <Endpoint>{ url: `/campaign-application/byId/${id}`, method: 'GET' },
     listAllForAdmin: <Endpoint>{ url: `/campaign-application/list`, method: 'GET' },
+    getFile: (fileId: string) =>
+      <Endpoint>{ url: `/campaign-application/fileById/${fileId}`, method: 'GET' },
   },
 }
diff --git a/src/service/campaign-application.ts b/src/service/campaign-application.ts
index 58874e3ae..c909b5536 100644
--- a/src/service/campaign-application.ts
+++ b/src/service/campaign-application.ts
@@ -20,6 +20,7 @@ import { apiClient } from 'service/apiClient'
 import { endpoints } from 'service/apiEndpoints'
 import { authConfig, authQueryFnFactory } from 'service/restRequests'
 import { ApiErrors } from './apiErrors'
+import { Session } from 'next-auth'
 
 export const useCreateCampaignApplication = () => {
   const { data: session } = useSession()
@@ -51,8 +52,8 @@ export const useUploadCampaignApplicationFiles = () => {
   }
 }
 
-export const useDeleteCampaignApplicationFile = () => {
-  const { data: session } = useSession()
+export const useDeleteCampaignApplicationFile = (s?: Session | null) => {
+  const { data: session } = s != null ? { data: s } : useSession()
   return async (id: string) =>
     await apiClient.delete<UploadCampaignApplicationFilesRequest>(
       endpoints.campaignApplication.deleteFile(id).url,
@@ -300,3 +301,13 @@ export function mapCreateOrEditInput(i: CampaignApplicationFormData): CampaignAp
     ...(i.admin ?? {}), // server disregards admin-only props if the user is not admin
   }
 }
+
+export function fetchCampaignApplicationFile(fileId: string, session: Session | null) {
+  return apiClient.get<string, AxiosResponse<Blob>>(
+    endpoints.campaignApplication.getFile(fileId).url,
+    {
+      ...authConfig(session?.accessToken),
+      responseType: 'blob',
+    },
+  )
+}