+
= ({ variant = 'default', onUplo
/>
- {isWorking && (
-
-
-
-
- {isUploading && 'Uploading file...'}
- {isWaiting && 'File uploaded successfully! Starting to process the data...'}
- {isProcessing && 'Processing file...'}
-
-
-
- )}
+ {/* {true && (
+
+ //
+ //
+ //
+ //
+ // {isUploading && 'Uploading file...'}
+ // {isWaiting && 'File uploaded successfully! Starting to process the data...'}
+ // {isProcessing && 'Processing file...'}
+ //
+ //
+ //
+ )} */}
);
};
diff --git a/client/src/containers/uploader/tracker/index.tsx b/client/src/containers/uploader/tracker/index.tsx
new file mode 100644
index 000000000..15846062f
--- /dev/null
+++ b/client/src/containers/uploader/tracker/index.tsx
@@ -0,0 +1,251 @@
+import { FC, useCallback, useEffect, useState } from 'react';
+import axios from 'axios';
+
+import { cn } from '@/lib/utils';
+import { socket } from '@/lib/socket';
+import { env } from '@/env.mjs';
+import { formatPercentage } from '@/utils/number-format';
+
+const STEPS_NAMES = {
+ VALIDATING: 'Validating',
+ 'DATA SOURCING': 'Data Sourcing',
+ GEOCODING: 'Geocoding',
+ 'IMPACT CALCULATION': 'Impact Calculation',
+} as const;
+
+type ProgressTask = {
+ kind: 'DATA_IMPORT_PROGRESS';
+ data: {
+ step: 'VALIDATING' | 'DATA SOURCING' | 'IMPACT CALCULATION' | 'GEOCODING';
+ status: 'running' | 'idle' | 'completed';
+ progress: number;
+ }[];
+};
+
+const SAMPLE_DATA: ProgressTask[] = [
+ {
+ kind: 'DATA_IMPORT_PROGRESS',
+ data: [
+ {
+ step: 'VALIDATING',
+ status: 'running',
+ progress: 0,
+ },
+ {
+ step: 'DATA SOURCING',
+ status: 'idle',
+ progress: 0,
+ },
+ {
+ step: 'GEOCODING',
+ status: 'idle',
+ progress: 0,
+ },
+ {
+ step: 'IMPACT CALCULATION',
+ status: 'idle',
+ progress: 0,
+ },
+ ],
+ },
+ {
+ kind: 'DATA_IMPORT_PROGRESS',
+ data: [
+ {
+ step: 'VALIDATING',
+ status: 'running',
+ progress: 10,
+ },
+ {
+ step: 'DATA SOURCING',
+ status: 'idle',
+ progress: 0,
+ },
+ {
+ step: 'GEOCODING',
+ status: 'idle',
+ progress: 0,
+ },
+ {
+ step: 'IMPACT CALCULATION',
+ status: 'idle',
+ progress: 0,
+ },
+ ],
+ },
+ {
+ kind: 'DATA_IMPORT_PROGRESS',
+ data: [
+ {
+ step: 'VALIDATING',
+ status: 'running',
+ progress: 20,
+ },
+ {
+ step: 'DATA SOURCING',
+ status: 'idle',
+ progress: 0,
+ },
+ {
+ step: 'GEOCODING',
+ status: 'idle',
+ progress: 0,
+ },
+ {
+ step: 'IMPACT CALCULATION',
+ status: 'idle',
+ progress: 0,
+ },
+ ],
+ },
+ {
+ kind: 'DATA_IMPORT_PROGRESS',
+ data: [
+ {
+ step: 'VALIDATING',
+ status: 'completed',
+ progress: 100,
+ },
+ {
+ step: 'DATA SOURCING',
+ status: 'running',
+ progress: 23,
+ },
+ {
+ step: 'GEOCODING',
+ status: 'idle',
+ progress: 0,
+ },
+ {
+ step: 'IMPACT CALCULATION',
+ status: 'idle',
+ progress: 0,
+ },
+ ],
+ },
+ {
+ kind: 'DATA_IMPORT_PROGRESS',
+ data: [
+ {
+ step: 'VALIDATING',
+ status: 'completed',
+ progress: 100,
+ },
+ {
+ step: 'DATA SOURCING',
+ status: 'completed',
+ progress: 100,
+ },
+ {
+ step: 'GEOCODING',
+ status: 'running',
+ progress: 34,
+ },
+ {
+ step: 'IMPACT CALCULATION',
+ status: 'idle',
+ progress: 0,
+ },
+ ],
+ },
+ {
+ kind: 'DATA_IMPORT_PROGRESS',
+ data: [
+ {
+ step: 'VALIDATING',
+ status: 'completed',
+ progress: 100,
+ },
+ {
+ step: 'DATA SOURCING',
+ status: 'completed',
+ progress: 100,
+ },
+ {
+ step: 'GEOCODING',
+ status: 'completed',
+ progress: 100,
+ },
+ {
+ step: 'IMPACT CALCULATION',
+ status: 'completed',
+ progress: 100,
+ },
+ ],
+ },
+];
+
+export const UploadTracker: FC = () => {
+ const [tasksProgress, setTaskProgress] = useState
(SAMPLE_DATA[0]);
+ // ! THIS IS FOR TESTING.REMOVE
+ const [testIndex, setTestIndex] = useState(0);
+
+ // ! THIS IS FOR TESTING.REMOVE
+ const triggerSocket = useCallback(() => {
+ axios.get(env.NEXT_PUBLIC_API_URL + '/tasks/progress');
+ }, []);
+
+ useEffect(() => {
+ socket.connect();
+
+ return () => {
+ socket.disconnect();
+ };
+ }, []);
+
+ useEffect(() => {
+ function setTasksProgress(tasks: ProgressTask) {
+ setTaskProgress(tasks);
+ }
+
+ socket.on('DATA_IMPORT_PROGRESS', setTasksProgress);
+
+ return () => {
+ socket.off('DATA_IMPORT_PROGRESS', setTasksProgress);
+ };
+ }, []);
+
+ // ! THIS IS FOR TESTING.REMOVE
+ useEffect(() => {
+ function setTestProgress() {
+ setTaskProgress(SAMPLE_DATA[testIndex]);
+
+ setTestIndex((prev) => (prev + 1 >= SAMPLE_DATA.length ? 0 : prev + 1));
+ }
+
+ const intervalId = window.setInterval(setTestProgress, 1500);
+
+ return () => {
+ window.clearInterval(intervalId);
+ };
+ }, [tasksProgress, testIndex]);
+
+ return (
+
+ {/* // ! THIS IS FOR TESTING.REMOVE */}
+
+
+ {tasksProgress?.data?.map(({ step, status, progress }) => (
+
+
+ {STEPS_NAMES[step]}
+
+ {status !== 'idle' && (
+ {`Progress: ${formatPercentage(
+ progress / 100,
+ )}`}
+ )}
+
+ ))}
+
+
+ );
+};
+
+export default UploadTracker;
diff --git a/client/src/lib/socket.ts b/client/src/lib/socket.ts
new file mode 100644
index 000000000..29f011859
--- /dev/null
+++ b/client/src/lib/socket.ts
@@ -0,0 +1,7 @@
+import { io } from 'socket.io-client';
+
+import { env } from '@/env.mjs';
+
+export const socket = io(env.NEXT_PUBLIC_API_URL, {
+ autoConnect: false,
+});
diff --git a/client/src/pages/data/index.tsx b/client/src/pages/data/index.tsx
index c6e69d30c..d712d8112 100644
--- a/client/src/pages/data/index.tsx
+++ b/client/src/pages/data/index.tsx
@@ -39,17 +39,18 @@ const AdminDataPage: React.FC = () => {
Manage data | Landgriffon
- {(!isFetched || isLoading) && (
+ {/* {(!isFetched || isLoading) && (
- )}
+ )} */}
{/* Content when empty, or upload is processing or failed */}
- {isFetched && !thereIsData && }
+ {/* {isFetched && !thereIsData && } */}
+ {true && }
{/* Content when data and upload is completed */}
- {isFetched && thereIsData && }
+ {/* {isFetched && thereIsData && } */}
);
};
diff --git a/client/yarn.lock b/client/yarn.lock
index e9cdd9d02..0e1f06929 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -2556,6 +2556,13 @@ __metadata:
languageName: node
linkType: hard
+"@socket.io/component-emitter@npm:~3.1.0":
+ version: 3.1.1
+ resolution: "@socket.io/component-emitter@npm:3.1.1"
+ checksum: 93792eafb63ad15259ba00885c3cf4fdc01d969b1db10a273ccac70bed2373b5170cbc94682372d666a44e4ad8faeb176fb6cbaaeeb66c87231e2ff3d72583f9
+ languageName: node
+ linkType: hard
+
"@streamparser/json@npm:^0.0.12":
version: 0.0.12
resolution: "@streamparser/json@npm:0.0.12"
@@ -4953,7 +4960,7 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4":
+"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:~4.3.1, debug@npm:~4.3.2":
version: 4.3.4
resolution: "debug@npm:4.3.4"
dependencies:
@@ -5292,6 +5299,26 @@ __metadata:
languageName: node
linkType: hard
+"engine.io-client@npm:~6.5.2":
+ version: 6.5.3
+ resolution: "engine.io-client@npm:6.5.3"
+ dependencies:
+ "@socket.io/component-emitter": ~3.1.0
+ debug: ~4.3.1
+ engine.io-parser: ~5.2.1
+ ws: ~8.11.0
+ xmlhttprequest-ssl: ~2.0.0
+ checksum: a72596fae99afbdb899926fccdb843f8fa790c69085b881dde121285a6935da2c2c665ebe88e0e6aa4285637782df84ac882084ff4892ad2430b059fc0045db0
+ languageName: node
+ linkType: hard
+
+"engine.io-parser@npm:~5.2.1":
+ version: 5.2.2
+ resolution: "engine.io-parser@npm:5.2.2"
+ checksum: 470231215f3136a9259efb1268bc9a71f789af4e8c74da8d3b49ceb149fe3cd5c315bf0cd13d2d8d9c8f0f051c6f93b68e8fa9c89a3b612b9217bf33765c943a
+ languageName: node
+ linkType: hard
+
"enhanced-resolve@npm:^5.10.0":
version: 5.10.0
resolution: "enhanced-resolve@npm:5.10.0"
@@ -7943,6 +7970,7 @@ __metadata:
recharts: 2.9.0
rooks: 7.14.1
sharp: 0.32.6
+ socket.io-client: 4.7.5
start-server-and-test: 1.14.0
tailwind-merge: 2.2.1
tailwindcss: 3.4.1
@@ -10785,6 +10813,28 @@ __metadata:
languageName: node
linkType: hard
+"socket.io-client@npm:4.7.5":
+ version: 4.7.5
+ resolution: "socket.io-client@npm:4.7.5"
+ dependencies:
+ "@socket.io/component-emitter": ~3.1.0
+ debug: ~4.3.2
+ engine.io-client: ~6.5.2
+ socket.io-parser: ~4.2.4
+ checksum: a6994b93a753d14292682ee97ba3c925c54b63e6fcb2ed5e0aa1d7c1d6164ed4a30d993f7eaaa3017ddf868ad0a1ab996badc8310129070136d84668789ee6c9
+ languageName: node
+ linkType: hard
+
+"socket.io-parser@npm:~4.2.4":
+ version: 4.2.4
+ resolution: "socket.io-parser@npm:4.2.4"
+ dependencies:
+ "@socket.io/component-emitter": ~3.1.0
+ debug: ~4.3.1
+ checksum: 61540ef99af33e6a562b9effe0fad769bcb7ec6a301aba5a64b3a8bccb611a0abdbe25f469933ab80072582006a78ca136bf0ad8adff9c77c9953581285e2263
+ languageName: node
+ linkType: hard
+
"socks-proxy-agent@npm:^7.0.0":
version: 7.0.0
resolution: "socks-proxy-agent@npm:7.0.0"
@@ -12238,6 +12288,28 @@ __metadata:
languageName: node
linkType: hard
+"ws@npm:~8.11.0":
+ version: 8.11.0
+ resolution: "ws@npm:8.11.0"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 316b33aba32f317cd217df66dbfc5b281a2f09ff36815de222bc859e3424d83766d9eb2bd4d667de658b6ab7be151f258318fb1da812416b30be13103e5b5c67
+ languageName: node
+ linkType: hard
+
+"xmlhttprequest-ssl@npm:~2.0.0":
+ version: 2.0.0
+ resolution: "xmlhttprequest-ssl@npm:2.0.0"
+ checksum: 1e98df67f004fec15754392a131343ea92e6ab5ac4d77e842378c5c4e4fd5b6a9134b169d96842cc19422d77b1606b8df84a5685562b3b698cb68441636f827e
+ languageName: node
+ linkType: hard
+
"y18n@npm:^4.0.0":
version: 4.0.3
resolution: "y18n@npm:4.0.3"