Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
andresgnlez committed Apr 18, 2024
1 parent 7453d3a commit a500fad
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 20 deletions.
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"recharts": "2.9.0",
"rooks": "7.14.1",
"sharp": "0.32.6",
"socket.io-client": "4.7.5",
"tailwind-merge": "2.2.1",
"tailwindcss": "3.4.1",
"tailwindcss-animate": "1.0.7",
Expand Down
14 changes: 12 additions & 2 deletions client/src/containers/admin/data-uploader/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DownloadIcon } from '@heroicons/react/solid';
import DataUploadError from 'containers/admin/data-upload-error';
import DataUploader from 'containers/uploader';
import { Anchor } from 'components/button';
import UploadTracker from '@/containers/uploader/tracker';

import type { Task } from 'types';

Expand All @@ -27,9 +28,18 @@ const AdminDataPage: React.FC<{ task: Task }> = ({ task }) => {
Download template
</Anchor>
</div>
<div className="w-[640px] space-y-4 text-center text-lg">
<div className="space-y-4 text-center text-lg">
<p className="font-semibold">2. Upload the filled Excel file.</p>
<DataUploader onUploadInProgress={setIsUploading} />
{false && (
<div className="w-[640px]">
<DataUploader onUploadInProgress={setIsUploading} />
</div>
)}
{true && (
<div className="w-[880px]">
<UploadTracker />
</div>
)}
{!isUploading && task?.status === 'failed' && <DataUploadError task={task} />}
</div>
</div>
Expand Down
27 changes: 14 additions & 13 deletions client/src/containers/uploader/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUplo
}, [isWorking, onUploadInProgress]);

return (
<div className="relative w-full min-w-[640px]">
<div className="relative w-full">
<div
className={classNames('relative z-10 rounded-xl bg-white', {
'p-4 shadow-lg': variant === 'default',
Expand All @@ -111,18 +111,19 @@ const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUplo
/>
</div>

{isWorking && (
<div className="w-full px-20">
<div className="rounded-b-xl bg-white px-10 py-4">
<div className="h-[4px] w-full rounded bg-gradient-to-r from-[#5FCFF9] via-[#42A56A] to-[#F5CA7D]" />
<p className="mt-1 text-left text-xs text-gray-500">
{isUploading && 'Uploading file...'}
{isWaiting && 'File uploaded successfully! Starting to process the data...'}
{isProcessing && 'Processing file...'}
</p>
</div>
</div>
)}
{/* {true && (
<UploadTracker />
// <div className="w-full px-20">
// <div className="rounded-b-xl bg-white px-10 py-4">
// <div className="h-[4px] w-full rounded bg-gradient-to-r from-[#5FCFF9] via-[#42A56A] to-[#F5CA7D]" />
// <p className="mt-1 text-left text-xs text-gray-500">
// {isUploading && 'Uploading file...'}
// {isWaiting && 'File uploaded successfully! Starting to process the data...'}
// {isProcessing && 'Processing file...'}
// </p>
// </div>
// </div>
)} */}
</div>
);
};
Expand Down
251 changes: 251 additions & 0 deletions client/src/containers/uploader/tracker/index.tsx
Original file line number Diff line number Diff line change
@@ -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<ProgressTask>(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 (
<div className="w-full rounded-3xl bg-white px-8 py-10">
{/* // ! THIS IS FOR TESTING.REMOVE */}
<button type="button" onClick={triggerSocket} className="mb-8">
Trigger Socket
</button>
<div className="grid grid-cols-4 gap-1">
{tasksProgress?.data?.map(({ step, status, progress }) => (
<div className="flex flex-col items-start" key={step}>
<span
className={cn('text-base text-gray-400 transition-colors', {
'text-gray-900': ['running', 'completed'].includes(status),
})}
>
{STEPS_NAMES[step]}
</span>
{status !== 'idle' && (
<span className="text-sm text-gray-500">{`Progress: ${formatPercentage(
progress / 100,
)}`}</span>
)}
</div>
))}
</div>
</div>
);
};

export default UploadTracker;
7 changes: 7 additions & 0 deletions client/src/lib/socket.ts
Original file line number Diff line number Diff line change
@@ -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,
});
9 changes: 5 additions & 4 deletions client/src/pages/data/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,18 @@ const AdminDataPage: React.FC = () => {
<title>Manage data | Landgriffon</title>
</Head>

{(!isFetched || isLoading) && (
{/* {(!isFetched || isLoading) && (
<div className="flex h-full w-full items-center justify-center">
<Loading className="h-5 w-5 text-navy-400" />
</div>
)}
)} */}

{/* Content when empty, or upload is processing or failed */}
{isFetched && !thereIsData && <AdminDataUploader task={lastTask} />}
{/* {isFetched && !thereIsData && <AdminDataUploader task={lastTask} />} */}
{true && <AdminDataUploader task={lastTask} />}

{/* Content when data and upload is completed */}
{isFetched && thereIsData && <AdminDataTable task={lastTask} />}
{/* {isFetched && thereIsData && <AdminDataTable task={lastTask} />} */}
</AdminLayout>
);
};
Expand Down
Loading

0 comments on commit a500fad

Please sign in to comment.