diff --git a/src/components/ProgressBar.tsx b/src/components/ProgressBar.tsx
new file mode 100644
index 0000000..78426a6
--- /dev/null
+++ b/src/components/ProgressBar.tsx
@@ -0,0 +1,22 @@
+import React, { ReactElement } from 'react'
+import LinearProgress, { LinearProgressProps } from '@material-ui/core/LinearProgress'
+import Typography from '@material-ui/core/Typography'
+import Box from '@material-ui/core/Box'
+
+interface Props {
+ linearProgressProps?: LinearProgressProps
+ value: number
+}
+
+export function LinearProgressWithLabel(props: Props): ReactElement {
+ return (
+
+
+
+
+
+ {`${Math.round(props.value)}%`}
+
+
+ )
+}
diff --git a/src/pages/files/AssetSyncing.tsx b/src/pages/files/AssetSyncing.tsx
new file mode 100644
index 0000000..736a9eb
--- /dev/null
+++ b/src/pages/files/AssetSyncing.tsx
@@ -0,0 +1,85 @@
+import { Context as SettingsContext } from '../../providers/Settings'
+import { Box } from '@material-ui/core'
+import { ReactElement, useContext, useEffect, useRef, useState } from 'react'
+import { DocumentationText } from '../../components/DocumentationText'
+import { LinearProgressWithLabel } from '../../components/ProgressBar'
+
+interface Props {
+ reference: string
+}
+
+export function AssetSyncing({ reference }: Props): ReactElement {
+ const { beeApi } = useContext(SettingsContext)
+
+ const syncTimer = useRef()
+ const [isRetrieveChecking, setIsRetrieveChecking] = useState(false)
+ const [syncProgress, setSyncProgress] = useState(0)
+
+ const syncCheck = async () => {
+ if (!beeApi) {
+ return
+ }
+
+ const tags = await beeApi.getAllTags()
+ const tag = tags.find(t => t.address === reference)
+
+ if (tag) {
+ const progress = ((tag.seen + tag.synced) / tag.split) * 100
+ setSyncProgress(progress)
+ }
+ }
+
+ useEffect(() => {
+ syncTimer.current = setInterval(syncCheck, 2000)
+
+ return () => {
+ if (syncTimer.current) {
+ clearInterval(syncTimer.current)
+ }
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [reference])
+
+ useEffect(() => {
+ if (syncProgress === 100 && syncTimer.current) {
+ clearInterval(syncTimer.current)
+ }
+ }, [syncProgress])
+
+ useEffect(() => {
+ /*
+ There are instances when it seems that the content isn't synchronized, despite being already available.
+ To ensure it's not due to invalid synchronization data,
+ verify availability from at least 70% using one of the stewardship endpoints.
+
+ TODO: is 70 a good number?
+ */
+ if (beeApi && !isRetrieveChecking && syncProgress > 10 && syncProgress < 100) {
+ // It's a long running task make sure only one run occurs at a time.
+ setIsRetrieveChecking(true)
+
+ beeApi.isReferenceRetrievable(reference).then(isRetriavable => {
+ if (isRetriavable) {
+ setSyncProgress(100)
+ }
+
+ setIsRetrieveChecking(false)
+ })
+ }
+ }, [syncProgress, isRetrieveChecking, beeApi, reference])
+
+ return (
+ <>
+
+
+ Files are not immediately accessible on the Swarm network. Please wait until your upload is synced to the
+ network.{' '}
+ Learn more about syncing.
+
+
+
+
+
+ >
+ )
+}
diff --git a/src/pages/files/Share.tsx b/src/pages/files/Share.tsx
index b748c89..c74e586 100644
--- a/src/pages/files/Share.tsx
+++ b/src/pages/files/Share.tsx
@@ -16,6 +16,7 @@ import { ManifestJs } from '../../utils/manifest'
import { AssetPreview } from './AssetPreview'
import { AssetSummary } from './AssetSummary'
import { DownloadActionBar } from './DownloadActionBar'
+import { AssetSyncing } from './AssetSyncing'
export function Share(): ReactElement {
const { apiUrl, beeApi } = useContext(SettingsContext)
@@ -152,6 +153,9 @@ export function Share(): ReactElement {
+
+
+
>
)}
- {step === 2 && stamp && }
+ {step === 2 && stamp && (
+ <>
+
+
+
+ Please do not close the application until your file is uploaded to your local node!
+
+
+ >
+ )}