Skip to content

Commit

Permalink
implements UI to track data upload
Browse files Browse the repository at this point in the history
  • Loading branch information
andresgnlez committed Apr 24, 2024
1 parent cf98602 commit 9871e23
Show file tree
Hide file tree
Showing 17 changed files with 358 additions and 155 deletions.
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,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
1 change: 0 additions & 1 deletion client/src/containers/admin/data-table/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,33 @@ import { format } from 'date-fns';
import { useRouter } from 'next/router';
import { useSession } from 'next-auth/react';

import useModal from 'hooks/modals';
import useModal from '@/hooks/modals';
import {
useSourcingLocations,
useSourcingLocationsMaterials,
useSourcingLocationsMaterialsTabularData,
} from 'hooks/sourcing-locations';
import DownloadMaterialsDataButton from 'containers/admin/download-materials-data-button';
import DataUploadError from 'containers/admin/data-upload-error';
import DataUploader from 'containers/uploader';
import Button, { Anchor } from 'components/button';
import Modal from 'components/modal';
import Table from 'components/table';
import { DEFAULT_PAGE_SIZES } from 'components/table/pagination/constants';
import { usePermissions } from 'hooks/permissions';
import { RoleName } from 'hooks/permissions/enums';
} from '@/hooks/sourcing-locations';
import DownloadMaterialsDataButton from '@/containers/admin/download-materials-data-button';
import DataUploadError from '@/containers/admin/data-upload-error';
import DataUploader from '@/containers/uploader';
import Button, { Anchor } from '@/components/button';
import Modal from '@/components/modal';
import Table from '@/components/table';
import { DEFAULT_PAGE_SIZES } from '@/components/table/pagination/constants';
import { usePermissions } from '@/hooks/permissions';
import { RoleName } from '@/hooks/permissions/enums';
import { useLasTask } from '@/hooks/tasks';

import type { PaginationState, SortingState, VisibilityState } from '@tanstack/react-table';
import type { TableProps } from 'components/table/component';
import type { Task } from 'types';
import type { TableProps } from '@/components/table/component';

const YEARS_COLUMNS_UNIT = 't/yr';

const AdminDataPage: React.FC<{ task: Task }> = ({ task }) => {
const AdminDataPage: React.FC = () => {
const { push, query } = useRouter();
const [sorting, setSorting] = useState<SortingState>([]);
const { data: session } = useSession();
const { data: task } = useLasTask();

const { hasRole } = usePermissions();
const isAdmin = hasRole(RoleName.ADMIN);
Expand Down Expand Up @@ -220,7 +221,12 @@ const AdminDataPage: React.FC<{ task: Task }> = ({ task }) => {
Uploading a new file will replace all the current data.
</p>
<div className="mt-10">
<DataUploader variant="inline" />
<DataUploader
variant="inline"
onUploadInProgress={(isUploadInProgress) => {
if (!isUploadInProgress) closeUploadDataSourceModal();
}}
/>
</div>
</div>

Expand Down
1 change: 0 additions & 1 deletion client/src/containers/admin/data-upload-error/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useCallback, useState } from 'react';
import { format } from 'date-fns';

import { useUpdateTask, useTaskErrors } from 'hooks/tasks';
import { useProfile } from 'hooks/profile';
import UploadIcon from 'components/icons/upload-icon';
import Disclaimer from 'components/disclaimer';
import Button from 'components/button';
import { triggerCsvDownload } from 'utils/csv-download';
import { useUpdateTask, useTaskErrors } from '@/hooks/tasks';
import { useProfile } from '@/hooks/profile';
import UploadIcon from '@/components/icons/upload-icon';
import Disclaimer from '@/components/disclaimer';
import Button from '@/components/button';
import { triggerCsvDownload } from '@/utils/csv-download';

import type { Task } from 'types';
import type { DisclaimerProps } from 'components/disclaimer/component';
import type { Task } from '@/types';
import type { DisclaimerProps } from '@/components/disclaimer/component';

const VARIANT_STATUS: Record<Task['status'], DisclaimerProps['variant']> = {
completed: 'success',
Expand Down Expand Up @@ -50,16 +50,6 @@ const DataUploadError: React.FC<DataUploadErrorProps> = ({ task }) => {
>
<div className="flex w-full items-center space-x-6">
<div className="flex-1 space-y-1.5">
{task?.status === 'processing' && (
<>
<h3>Upload in progress</h3>
<p className="text-gray-500">
There is a uploading task in progress created at{' '}
{format(new Date(task.createdAt), 'MMM d, yyyy HH:mm z')}.
</p>
</>
)}

{task?.status === 'completed' && task?.errors.length === 0 && (
<>
<h3>Upload completed</h3>
Expand Down
40 changes: 0 additions & 40 deletions client/src/containers/admin/data-uploader/component.tsx

This file was deleted.

1 change: 0 additions & 1 deletion client/src/containers/admin/data-uploader/index.ts

This file was deleted.

48 changes: 48 additions & 0 deletions client/src/containers/admin/data-uploader/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { DownloadIcon } from '@heroicons/react/solid';

import DataUploadError from '@/containers/admin/data-upload-error';
import { Anchor } from '@/components/button';
import UploadTracker from '@/containers/uploader/tracker';
import { useLasTask } from '@/hooks/tasks';
import DataUploader from '@/containers/uploader';

const AdminDataUploader: React.FC = () => {
const { data: lastTask } = useLasTask();

return (
<div className="flex h-full w-full items-center justify-center">
<div className="space-y-16">
<div className="space-y-4 text-center text-lg">
<p className="font-semibold">
1. Download the Excel template and fill it with your data.
</p>
<Anchor
href="/files/data-template.xlsx"
download
target="_blank"
rel="noopener noreferrer"
icon={<DownloadIcon aria-hidden="true" />}
>
Download template
</Anchor>
</div>
<div className="flex flex-col items-center space-y-4 text-center text-lg">
<p className="font-semibold">2. Upload the filled Excel file.</p>
{lastTask?.status !== 'processing' && (
<div className="w-[640px]">
<DataUploader />
</div>
)}
{lastTask?.status === 'processing' && (
<div className="w-[880px]">
<UploadTracker />
</div>
)}
{lastTask?.status === 'failed' && <DataUploadError task={lastTask} />}
</div>
</div>
</div>
);
};

export default AdminDataUploader;
1 change: 0 additions & 1 deletion client/src/containers/uploader/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { useCallback, useEffect, useState } from 'react';
import toast from 'react-hot-toast';
import classNames from 'classnames';
import { useRouter } from 'next/router';
import { useQueryClient } from '@tanstack/react-query';

import { useUploadDataSource } from 'hooks/sourcing-data';
import { useLasTask } from 'hooks/tasks';
import FileDropzone from 'components/file-dropzone';
import { useUploadDataSource } from '@/hooks/sourcing-data';
import { LAST_TASK_PARAMS, useLasTask } from '@/hooks/tasks';
import { env } from '@/env.mjs';
import FileDropzone from '@/components/file-dropzone';

import type { FileDropZoneProps } from 'components/file-dropzone/types';
import type { FileDropZoneProps } from '@/components/file-dropzone/types';
import type { Task } from 'types';

type DataUploaderProps = {
Expand All @@ -29,7 +30,7 @@ const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUplo
const router = useRouter();
const uploadDataSource = useUploadDataSource();
const lastTask = useLasTask();
const { refetch: refetchLastTask } = lastTask;
const queryClient = useQueryClient();

const handleOnDrop: FileDropZoneProps['onDrop'] = useCallback(
(acceptedFiles) => {
Expand All @@ -40,8 +41,16 @@ const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUplo
});

uploadDataSource.mutate(formData, {
onSuccess: () => {
refetchLastTask();
onSuccess: ({ data }) => {
const { attributes, ...rest } = data;
queryClient.setQueryData(['tasks', LAST_TASK_PARAMS], {
data: [
{
...rest,
...attributes,
},
],
});
},
onError: ({ response }) => {
const errors = response?.data?.errors;
Expand All @@ -53,7 +62,7 @@ const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUplo
},
});
},
[refetchLastTask, uploadDataSource],
[uploadDataSource, queryClient],
);

const handleFileRejected: FileDropZoneProps['onDropRejected'] = useCallback((rejectedFiles) => {
Expand All @@ -69,12 +78,9 @@ const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUplo
// Status of the uploading process
const isUploading = uploadDataSource.isLoading;
const isWaiting = uploadDataSource.isSuccess && currentTaskId === lastTask.data?.id;
const isProcessing = lastTask.data?.status === 'processing';
const isWorking = isUploading || isWaiting || isProcessing;
const isCompleted =
!isWorking &&
uploadDataSource.isSuccess &&
(lastTask.data?.status === 'completed' || lastTask.data?.status === 'failed');
const isTaskFailed = lastTask.data?.status === 'failed';
const isWorking = (isUploading || isWaiting) && !isTaskFailed;
const isCompleted = !isWorking && uploadDataSource.isSuccess;

useEffect(() => {
if (!currentTaskId && lastTask.data?.id) {
Expand All @@ -83,20 +89,15 @@ const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUplo
}, [currentTaskId, lastTask.data?.id]);

useEffect(() => {
if (isCompleted && router.isReady) {
router.reload();
onUploadInProgress(false);
}
if (isCompleted) onUploadInProgress?.(false);
}, [isCompleted, onUploadInProgress, router]);

useEffect(() => {
if (isWorking && onUploadInProgress) {
onUploadInProgress(true);
}
if (isWorking && onUploadInProgress) onUploadInProgress?.(true);
}, [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 @@ -110,19 +111,6 @@ const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUplo
isUploading={isWorking}
/>
</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>
)}
</div>
);
};
Expand Down
Loading

0 comments on commit 9871e23

Please sign in to comment.