TP-78258 | generic upload component (#1076)

* TP-78258 | generic upload component

* TP-78258 | dra and generic upload component

* TP-78258 | dra temp

* TP-78258 | dra temp

* TP-69871 | fix issues

* TP-69871 | fix issues

* TP-69871 | fix issues

* TP-78258 | dra certificate fixes

* TP-69871 | fixed uat feedbacks

* TP-69871 | fixed uat feedbacks

* TP-69871 | fixed uat feedbacks

* TP-69871 | fixed uat feedbacks

* TP-69871 | fixed uat feedbacks
This commit is contained in:
Varnit Goyal
2024-08-22 20:33:12 +05:30
committed by GitHub
parent 875b62bce6
commit 18b455c7cf
15 changed files with 697 additions and 18 deletions

View File

@@ -211,12 +211,12 @@ const App = () => {
registerNavigateAndDispatch(navigate, dispatch);
const { config } = window;
initApm({
serviceName: config.APM_APP_NAME,
serverUrl: config.APM_BASE_URL,
serviceVersion: '1.0.0',
environment: config.ENV
});
// initApm({
// serviceName: config.APM_APP_NAME,
// serverUrl: config.APM_BASE_URL,
// serviceVersion: '1.0.0',
// environment: config.ENV
// });
const setFCMTokenRedux = (fcmToken: string) => {
dispatch(setFcmToken(fcmToken));
};

View File

@@ -5,19 +5,17 @@ const ErrorIconOutline: React.FC<IconProps> = props => {
const { className, size = 16, fillColor = '#E92C2C', onClick } = props;
return (
<svg
onClick={onClick}
className={className}
width={size}
height={size}
viewBox={`"0 0 ${size} ${size}"`}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.99967 4.66536C8.36634 4.66536 8.66634 4.96536 8.66634 5.33203V7.9987C8.66634 8.36536 8.36634 8.66536 7.99967 8.66536C7.63301 8.66536 7.33301 8.36536 7.33301 7.9987V5.33203C7.33301 4.96536 7.63301 4.66536 7.99967 4.66536ZM7.99301 1.33203C4.31301 1.33203 1.33301 4.3187 1.33301 7.9987C1.33301 11.6787 4.31301 14.6654 7.99301 14.6654C11.6797 14.6654 14.6663 11.6787 14.6663 7.9987C14.6663 4.3187 11.6797 1.33203 7.99301 1.33203ZM7.99967 13.332C5.05301 13.332 2.66634 10.9454 2.66634 7.9987C2.66634 5.05203 5.05301 2.66536 7.99967 2.66536C10.9463 2.66536 13.333 5.05203 13.333 7.9987C13.333 10.9454 10.9463 13.332 7.99967 13.332ZM8.66634 11.332H7.33301V9.9987H8.66634V11.332Z"
fill={fillColor}
d="M10.0013 5.83366C10.4596 5.83366 10.8346 6.20866 10.8346 6.66699V10.0003C10.8346 10.4587 10.4596 10.8337 10.0013 10.8337C9.54297 10.8337 9.16797 10.4587 9.16797 10.0003V6.66699C9.16797 6.20866 9.54297 5.83366 10.0013 5.83366ZM9.99297 1.66699C5.39297 1.66699 1.66797 5.40033 1.66797 10.0003C1.66797 14.6003 5.39297 18.3337 9.99297 18.3337C14.6013 18.3337 18.3346 14.6003 18.3346 10.0003C18.3346 5.40033 14.6013 1.66699 9.99297 1.66699ZM10.0013 16.667C6.31797 16.667 3.33464 13.6837 3.33464 10.0003C3.33464 6.31699 6.31797 3.33366 10.0013 3.33366C13.6846 3.33366 16.668 6.31699 16.668 10.0003C16.668 13.6837 13.6846 16.667 10.0013 16.667ZM10.8346 14.167H9.16797V12.5003H10.8346V14.167Z"
fill="#E92C2C"
/>
</svg>
);

View File

@@ -0,0 +1,29 @@
import React from 'react';
type DownloadIconProps = {
width?: number;
height?: number;
};
function DownloadIcon({ width = 20, height = 20 }: DownloadIconProps) {
return (
<svg
width={width}
height={height}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<mask id="mask0_19520_36027" maskUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
<rect width="20" height="20" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_19520_36027)">
<path
d="M4.9987 16.6663C4.54036 16.6663 4.14814 16.5033 3.82203 16.1772C3.49536 15.8505 3.33203 15.458 3.33203 14.9997V12.4997H4.9987V14.9997H14.9987V12.4997H16.6654V14.9997C16.6654 15.458 16.5023 15.8505 16.1762 16.1772C15.8495 16.5033 15.457 16.6663 14.9987 16.6663H4.9987ZM9.9987 13.333L5.83203 9.16634L6.9987 7.95801L9.16536 10.1247V3.33301H10.832V10.1247L12.9987 7.95801L14.1654 9.16634L9.9987 13.333Z"
fill="#0276FE"
/>
</g>
</svg>
);
}
export default DownloadIcon;

View File

@@ -0,0 +1,28 @@
import React from 'react';
type FileIconProps = {
width?: number;
height?: number;
};
function FileIcon({ width = 20, height = 20 }: FileIconProps) {
return (
<svg
width={width}
height={height}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<mask id="mask0_19536_36083" maskUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
<rect width="20" height="20" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_19536_36083)">
<path
d="M7 15H13V13.5H7V15ZM7 12H13V10.5H7V12ZM5.49417 18C5.08139 18 4.72917 17.8531 4.4375 17.5594C4.14583 17.2656 4 16.9125 4 16.5V3.5C4 3.0875 4.14687 2.73438 4.44062 2.44063C4.73437 2.14688 5.0875 2 5.5 2H12L16 6V16.5C16 16.9125 15.8531 17.2656 15.5592 17.5594C15.2653 17.8531 14.9119 18 14.4992 18H5.49417ZM11 7V3.5H5.5V16.5H14.5V7H11Z"
fill="#0276FE"
/>
</g>
</svg>
);
}
export default FileIcon;

View File

@@ -0,0 +1,185 @@
import React, { useRef, useState } from 'react';
import cx from 'classnames';
import UploadFileIcon from '@cp/assets/icons/UploadFileIcon';
import Button from '@primitives/Button';
import Typography from '@primitives/Typography';
import { noop } from '@utils/common';
import UploadSuccessComponent from '@cp/components/UploadComponent/UploadSuccessComponent';
import { RegisterOptions } from 'react-hook-form';
import { useMergeRefs } from '@floating-ui/react';
export type ErrorMessage = {
fileName: string | null;
message: string | boolean;
};
type UploadComponentProps = {
isSampleFileAvailable?: boolean;
supportedFile?: string;
MAX_FILE_SIZE_IN_MB?: number;
validationOfFile?: (file: File | undefined) => boolean;
file?: File | null;
setFile: (file: File | null) => void;
setHasError: (errorMessage: ErrorMessage) => void;
isValidationInfoVisible?: boolean;
uploadContentContainer?: (
handleUploadClick: (e: React.ChangeEvent) => void
) => React.ReactElement;
containerClassName?: string;
register?: RegisterOptions;
refProp?: React.Ref<HTMLInputElement>;
};
function UploadComponent({
isSampleFileAvailable = false,
MAX_FILE_SIZE_IN_MB = 5,
supportedFile = '.csv',
validationOfFile,
file: uploadedFile = null,
setFile: setUploadedFile,
setHasError = (errorMessage: ErrorMessage) => noop,
isValidationInfoVisible = false,
uploadContentContainer,
containerClassName = '',
refProp,
...rest
}: UploadComponentProps) {
const hiddenFileInput = useRef<HTMLInputElement>(null);
const [isDragging, setIsDragging] = useState(false);
const mergedRef = useMergeRefs([hiddenFileInput, refProp]);
const defaultValidationOfFile = (file: File | undefined) => {
if (file) {
if (file?.size > MAX_FILE_SIZE) {
return `File size is greater than ${MAX_FILE_SIZE_IN_MB} MB`;
}
}
return false;
};
const handleFile = (file: File | undefined) => {
if (file) {
setUploadedFile(file);
const validationFunc = validationOfFile || defaultValidationOfFile;
const fileValidationMessage = validationFunc(file);
if (!fileValidationMessage) {
setUploadedFile(file);
} else {
setHasError({
fileName: file.name,
message: fileValidationMessage
});
setUploadedFile(null);
}
}
};
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const selectedFile = event.target.files?.[0];
handleFile(selectedFile);
};
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
event.stopPropagation();
setIsDragging(true);
};
const handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
setIsDragging(true);
};
const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
setIsDragging(false);
};
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
event.stopPropagation();
setIsDragging(false);
const selectedFile = event.dataTransfer.files?.[0];
handleFile(selectedFile);
};
const MAX_FILE_SIZE = 1e6 * MAX_FILE_SIZE_IN_MB;
const handleUploadClick = (e: React.ChangeEvent<any>) => {
e.preventDefault();
hiddenFileInput.current?.focus();
hiddenFileInput.current?.click();
};
const handleDownloadClick = (e: React.ChangeEvent<any>) => {
e.preventDefault();
};
return (
<div className="">
<div className="">
<div
className={cx(
{
'border-dashed border-[2px] border-[--blue-base] bg-[--blue-light-bg] p-[24px] m-[12px] flex flex-col items-center justify-space-evenly rounded-lg':
true,
['!bg-[--blue-bg] border-1 border-solid border-[--blue-bg]']:
isDragging && !uploadedFile
},
containerClassName
)}
onDragOver={handleDragOver}
onDrop={handleDrop}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
>
<input
id="fileUpload"
type="file"
accept={supportedFile}
onChange={handleChange}
onClick={(e: React.ChangeEvent<any>) => {
e.target.value = '';
}}
ref={hiddenFileInput}
style={{ display: 'none' }}
/>
{uploadContentContainer ? (
uploadContentContainer(handleUploadClick)
) : (
<div className="upload-container-content">
<UploadFileIcon />
<div className={'text-[--grayscale-content-2]'}>
<Button variant="text" onClick={handleUploadClick}>
Click to Select
</Button>{' '}
or drag and drop here
</div>
</div>
)}
{isValidationInfoVisible ? (
<div className={'flex items-center gap-2 '}>
<Typography variant={'p5'} className="text-[--grayscale-3] text-center pt-2 pb-2">
Upload only .csv
</Typography>
<div className="w-[1px] h-[20px] bg-[#caced5] mt-[4px]" />
<Typography variant={'p5'} className="text-[--grayscale-3] text-center pt-2 pb-2">
Max 5 MB size allowed
</Typography>
</div>
) : null}
{isSampleFileAvailable ? (
<Button
onClick={handleDownloadClick}
variant="text"
className="text-center text-[--blue-base]"
>
{' '}
Download Sample file
</Button>
) : null}
</div>
</div>
</div>
);
}
export default UploadComponent;

View File

@@ -0,0 +1,53 @@
import React from 'react';
import styles from '@cp/pages/AmeyoUtility/components/UploadNumbers/index.module.scss';
import { CheckIcon, CloseIcon } from '@icons';
import Button from '@primitives/Button';
import uploadComponent from '@cp/components/UploadComponent/UploadComponent';
import ErrorIconOutline from '@cp/assets/icons/ErrorIconOutline';
import cx from 'classnames';
type UploadErrorComponent = {
message: string | boolean;
onCancel: () => void;
containerClassName?: string;
fileName: string;
};
function UploadErrorComponent({
message,
onCancel,
containerClassName,
fileName
}: UploadErrorComponent) {
return (
<>
<div
className={cx(
'flex justify-between items-center text-gray-600 p-1.5 mt-3.5 rounded-lg border border-solid border-[--red-base] bg-[#FFF5F5] h-[40px] ml-3 gap-2',
containerClassName
)}
>
<div className="flex items-center justify-between gap-1">
<ErrorIconOutline size={20} fillColor1="var(--red-base)" />
<div className="max-w-[250px] text-ellipsis whitespace-nowrap overflow-hidden">
{fileName}
</div>
</div>
<div>
<Button
variant="text"
onClick={e => {
e.preventDefault();
onCancel();
}}
>
<CloseIcon />
</Button>
</div>
</div>
<div className="text-red-400 ml-[20px] mt-[10px]"> {message}</div>
</>
);
}
export default UploadErrorComponent;

View File

@@ -0,0 +1,50 @@
import React from 'react';
import styles from '@cp/pages/AmeyoUtility/components/UploadNumbers/index.module.scss';
import { CheckIcon, CloseIcon } from '@icons';
import Button from '@primitives/Button';
import cx from 'classnames';
import CircularLoader from '@navi/web-ui/lib/icons/CircularLoaderIcon';
type UploadSuccessComponent = {
name: string;
onCancel: () => void;
containerClassName?: string;
isInProgress?: boolean;
};
function UploadSuccessComponent({
name,
onCancel,
containerClassName,
isInProgress
}: UploadSuccessComponent) {
return (
<div
className={cx(
'flex items-center justify-between text-gray-600 p-1.5 mt-3.5 rounded-lg border border-solid border-green-500 bg-[#f5fff8] h-[40px] ml-3 gap-2',
containerClassName
)}
>
<div className=" flex gap-2 items-center">
<div>
{isInProgress ? (
<CircularLoader
width={20}
height={20}
color="var(--green-base)"
fill={'var(--green-base)'}
/>
) : (
<CheckIcon width={20} height={20} color="var(--green-base)" fill="var(--green-base)" />
)}
</div>
<div className="max-w-[250px] text-ellipsis overflow-hidden">{name}</div>
</div>
<Button variant="text" onClick={onCancel}>
<CloseIcon />
</Button>
</div>
);
}
export default UploadSuccessComponent;

View File

@@ -0,0 +1,4 @@
import uploadComponent from '@cp/components/UploadComponent/UploadComponent';
import UseUpload from '@cp/components/UploadComponent/useUpload';
export { uploadComponent, UseUpload };

View File

@@ -0,0 +1,47 @@
import React, { useCallback, useState } from 'react';
import axiosInstance from '@cp/utils/ApiHelper';
import { ErrorMessage } from '@cp/components/UploadComponent/UploadComponent';
export enum UPLOAD_STATUS {
IDLE = 'IDLE',
IN_PROGRESS = 'IN_PROGRESS',
SUCCESS = 'SUCCESS',
ERROR = 'ERROR'
}
interface UseUploadParams {
onFileUploadedSuccess?: () => void;
onFileUploadedError?: () => void;
}
function UseUpload({ onFileUploadedSuccess, onFileUploadedError }: UseUploadParams) {
const [fileStatus, setFileStatus] = useState(UPLOAD_STATUS.IDLE);
const [file, setFile] = useState(null as File | null);
const [error, setError] = useState<ErrorMessage>({ message: '', fileName: null });
const upload = useCallback((file: File, uploadUrl: string) => {
setFileStatus(UPLOAD_STATUS.IN_PROGRESS);
if (!file) {
return;
}
const formData = new FormData();
formData.append('file', file);
return axiosInstance
.put(uploadUrl, formData)
.then(_ => {
setFileStatus(UPLOAD_STATUS.SUCCESS);
onFileUploadedSuccess && onFileUploadedSuccess();
})
.catch(_ => {
setFileStatus(UPLOAD_STATUS.ERROR);
onFileUploadedError && onFileUploadedError();
});
}, []);
const resetFileStatus = useCallback(() => {
setFileStatus(UPLOAD_STATUS.IDLE);
}, []);
return { fileStatus, upload, resetFileStatus, setFile, file, error, setError };
}
export default UseUpload;

View File

@@ -46,6 +46,9 @@ import InactiveTextContainer from './components/form/InactiveTextContainer';
import styles from './AgentForm.module.scss';
import cx from 'classnames';
import { Typography } from '@navi/web-ui/lib/primitives';
import UploadComponent from '@cp/components/UploadComponent/UploadComponent';
import AgentFormUploadControl from '@cp/pages/AllAgents/AgentForm/components/form/AgentFormUploadControl';
import AgentFormDownloadDraCertificate from '@cp/pages/AllAgents/AgentForm/components/form/AgentFormDownloadDraCertificate';
export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
const {
@@ -86,7 +89,8 @@ export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
getValues,
setValue,
watch,
setFocus
setFocus,
register
} = useForm<AgentFormValues>({
defaultValues
});
@@ -132,6 +136,10 @@ export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
const enableStateEdit = rolesContainAnyOfV1(agentStateAndLanguageEditRoles);
const disableStateEdit = !!(!enableStateEdit && agentData?.referenceId);
const isUserManagementRole = user?.roles?.includes(Roles.ROLE_USER_MANAGEMENT_ADMIN);
const isDraUploadAccessFeatureFlagEnabled = useSelector(
(store: RootState) => store.common.featureFlags?.draUploadAccess
);
const getAgencyCode = () => {
if (isEditable || isUserManagementRole) {
return watch('agencyCodeRequested');
@@ -179,7 +187,9 @@ export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
tertiaryRegion: agentData?.tertiaryRegion || '',
bucketGroup: agentData?.bucketGroup,
agencyCodeRequested: agentData?.agencyCodeRequested,
agentCenter: agentData?.agentCenter
agentCenter: agentData?.agentCenter,
draCertificateView: agentData?.draCertificateView,
draCertificate: {}
},
{
keepDirty: !!isDrawerOpen
@@ -262,7 +272,8 @@ export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
tertiaryLanguage,
bucketGroup,
agencyCodeRequested,
agentCenter
agentCenter,
draCertificate
} = data;
const createAgentRequest = {
@@ -287,7 +298,13 @@ export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
reportingManagerReferenceId:
managerList.find(
manager => manager?.additionalData?.emailAddress === reportingManagerEmailAddress
)?.additionalData?.referenceId || ''
)?.additionalData?.referenceId || '',
draCertificateView: {
draCertificateUpdateRequest: {
mode: 'ADD',
uploadReferenceId: draCertificate?.referenceId || null
}
}
};
createAgent(createAgentRequest, setIsSubmitButtonDisabled, setShowLoader, onClose);
};
@@ -309,7 +326,8 @@ export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
tertiaryLanguage,
bucketGroup,
agencyCodeRequested,
agentCenter
agentCenter,
draCertificate
} = data;
const updateAgentRequest = {
@@ -334,7 +352,17 @@ export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
reportingManagerReferenceId:
managerList.find(
manager => manager?.additionalData?.emailAddress === reportingManagerEmailAddress
)?.additionalData?.referenceId || ''
)?.additionalData?.referenceId || '',
draCertificateView: {
draCertificateUpdateRequest: draCertificate
? {
mode: 'EDIT',
uploadReferenceId: draCertificate?.referenceId
}
: {
mode: 'DELETE'
}
}
};
updateAgent(
@@ -706,6 +734,30 @@ export const AgentForm = forwardRef((props: AgentFormProps, ref) => {
showRequiredIcon={false}
/>
</div>
{watch('draCertificateView') ? (
<div className="w-[364px] ml-2 mt-4">
<AgentFormDownloadDraCertificate
control={control}
name={'draCertificateView'}
rules={{ required: false }}
isEditDisable={isEditDisabled || !isDraUploadAccessFeatureFlagEnabled}
/>
</div>
) : (
<div>
{isDraUploadAccessFeatureFlagEnabled ? (
<AgentFormUploadControl
control={control}
name={'draCertificate'}
rules={{ required: false }}
errors={errors}
isEditDisabled={false}
styles={{}}
setSubmitButtonDisabled={setIsSubmitButtonDisabled}
/>
) : null}
</div>
)}
</div>
</div>
</form>

View File

@@ -0,0 +1,79 @@
import React from 'react';
import Button from '@primitives/Button';
import cx from 'classnames';
import FileIcon from '@cp/assets/images/icons/FileIcon';
import DownloadIcon from '@cp/assets/images/icons/DownloadIcon';
import { Control, useController } from 'react-hook-form';
import { AgentFormValues } from '@cp/pages/AllAgents/AgentForm/interfaces/types';
import { GenericObject } from '@cp/src/types/CommonConstans';
import { getFileDownload } from '@cp/utils/commonUtils';
import { EditIcon } from '@icons';
import CrossIcon from '@cp/assets/icons/CrossIcon';
type AgentFormDownloadDraCertificateProps = {
name: keyof AgentFormValues;
containerClassName?: string;
control: Control<AgentFormValues, any>;
rules?: GenericObject;
isEditDisable: boolean;
};
function AgentFormDownloadDraCertificate({
name,
containerClassName,
control,
rules,
isEditDisable
}: AgentFormDownloadDraCertificateProps) {
const { field } = useController({
name,
control,
rules
});
return (
<>
<div className="text-[--grayscale-2] text-[14px] ml-[14px] mt-[16px]">DRA Certificate</div>
<div
className={cx(
'flex items-center justify-between text-gray-600 mt-3.5 rounded-lg border border-solid border-[--blue-border] bg-[#F0F6FF] h-[40px] ml-3 gap-2 p-2',
containerClassName
)}
>
<div className=" flex gap-2 items-center">
<div>
<FileIcon width={20} height={20} />
</div>
<div className="max-w-[200px] text-ellipsis overflow-hidden">
{'Agent DRA Certificate.pdf'}
</div>
</div>
<div className="controls flex items-center gap-1 mr-2">
{!isEditDisable ? (
<Button
variant="text"
onClick={e => {
e.preventDefault();
field.onChange(null);
}}
>
<CrossIcon height={16} width={16} fillColor={'var(--blue-base)'} />
</Button>
) : (
<Button
variant="text"
onClick={e => {
e.preventDefault();
// @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.
getFileDownload(field?.value?.draCertificate?.uri, true);
}}
>
<DownloadIcon height={20} width={20} />
</Button>
)}
</div>
</div>
</>
);
}
export default AgentFormDownloadDraCertificate;

View File

@@ -0,0 +1,137 @@
import React, { useEffect } from 'react';
import { Control, FieldErrorsImpl, RegisterOptions, useController } from 'react-hook-form';
import { AgentFormValues } from '../../interfaces/types';
import useUpload, { UPLOAD_STATUS } from '@cp/components/UploadComponent/useUpload';
import UploadComponent from '@cp/components/UploadComponent/UploadComponent';
import UploadErrorComponent from '@cp/components/UploadComponent/UploadErrorComponent';
import UploadIcon from '@navi/web-ui/lib/icons/UploadIcon';
import UploadSuccessComponent from '@cp/components/UploadComponent/UploadSuccessComponent';
import axiosInstance, { ApiKeys, getApiUrl } from '@cp/utils/ApiHelper';
type AgentFormUploadControlProps = {
control: Control<AgentFormValues, any>;
name: keyof AgentFormValues;
rules: RegisterOptions;
errors: Partial<FieldErrorsImpl<AgentFormValues>>;
isEditDisabled: boolean | undefined;
styles: CSSModuleClasses;
inputLabel?: string;
isRequired?: boolean;
setSubmitButtonDisabled: (isDisabled: boolean) => void;
};
const customAgentFormUploadComponent = (handleUploadClick: (e: React.ChangeEvent<any>) => void) => {
return (
<div>
<div className="flex items-center gap-2">
<UploadIcon color="var(--blue-base)" width={20} height={20} />
<div
className="text-[--blue-base] font-medium cursor-pointer"
onClick={e => {
handleUploadClick(e);
}}
>
{' '}
Click to Upload{' '}
<span className="text-[--grayscale-content-2]">or drag and drop here</span>
</div>
</div>
</div>
);
};
const AgentFormUploadControl: React.FC<AgentFormUploadControlProps> = props => {
const { control, name, rules, errors, styles, inputLabel = '', setSubmitButtonDisabled } = props;
const { field } = useController({
name,
control,
rules
});
const { file, setFile, upload, fileStatus, error, setError } = useUpload({});
useEffect(() => {
if (file) {
const getUploadUrl = getApiUrl(
ApiKeys.GET_DOCUMENT_UPLOAD_URL,
{},
{
documentType: 'DRA_CERTIFICATE',
documentContentType: 'PDF'
}
);
axiosInstance.get(getUploadUrl).then(async res => {
//presigned url fetch and pass it to upload function
setSubmitButtonDisabled(true);
upload(file, res.data?.preSignedPutUrl)
?.then(() => {
//on success
const ackUrl = getApiUrl(ApiKeys.DOCUMENT_UPLOAD_ACK_URL);
axiosInstance
.post(ackUrl, {
referenceId: res?.data?.referenceId,
status: 'UPLOAD_SUCCESS',
message: ''
})
.then(res => {
field.onChange(res?.data);
});
})
.catch(err => {
setError({ message: err?.message || '', fileName: file?.name || '' });
})
.finally(() => {
setSubmitButtonDisabled(false);
});
});
}
}, [file]);
return (
<>
<div className="text-[--grayscale-2] text-[14px] ml-[20px] mt-[16px]">
Upload DRA Certificate
</div>
{error?.message ? (
<div className={styles.errorContainer}>
<UploadErrorComponent
containerClassName="w-[352px] box-border ml-[18px] !px-[16px] !py-[24px]"
message={error?.message || ''}
fileName={error?.fileName || ''}
onCancel={() => {
setError({ message: '', fileName: '' });
}}
/>
</div>
) : null}
{error?.message ? null : (
<div>
{file ? (
<UploadSuccessComponent
containerClassName="w-[348px] box-border ml-[18px] !px-[16px] !py-[24px]"
name={file?.name || ''}
isInProgress={fileStatus === UPLOAD_STATUS.IN_PROGRESS}
onCancel={() => {
setFile(null);
field.onChange(null);
}}
/>
) : (
<div className="w-[360px] ml-5 mt-3">
<UploadComponent
setFile={setFile}
file={file}
uploadContentContainer={customAgentFormUploadComponent}
containerClassName="w-[348px] !py-[16px] !px-[0] box-border !m-0"
supportedFile=".pdf"
setHasError={setError}
/>
</div>
)}
</div>
)}
</>
);
};
export default AgentFormUploadControl;

View File

@@ -1,6 +1,7 @@
import { PageRequest } from '@cp/src/components/interfaces';
import { Roles } from '@cp/src/pages/auth/constants/AuthConstants';
import { Dispatch, SetStateAction } from 'react';
import { GenericObject } from '@cp/src/types/CommonConstans';
export interface AgentFormProps {
ref?: any;
@@ -33,6 +34,12 @@ export interface AgentFormValues {
bucketGroup: string;
reportingManagerReferenceId?: string;
agentCenter?: string;
draCertificate?: GenericObject;
draCertificateView?: {
draCertificate: {
uri: string;
};
};
}
export interface Agent {
@@ -62,6 +69,11 @@ export interface Agent {
agencyCodeRequested?: string;
reportingManagerReferenceId?: string;
agentCenter?: string;
draCertificateView?: {
draCertificate: {
uri: string;
};
};
}
export interface AgentPageRequest extends PageRequest {

View File

@@ -149,6 +149,7 @@ export const FeeWaiverHistoryColumnDefs: ColDefsType[] = [
{
headerName: 'Amount(incl. GST)',
field: 'feeAmount',
width: 150,
cellRenderer: (params: ICellRendererParams) => {
const value = formatAmount(params.data?.deferredAmount, false) || '--';

View File

@@ -253,7 +253,9 @@ export enum ApiKeys {
HUMAN_REMNINDER_DISPOSE_CALL_V2,
PHONENUMBER_SECONDARY_SOURCES,
VALIDATE_PHONE_NUMBER,
REMOVE_CONTACT
REMOVE_CONTACT,
GET_DOCUMENT_UPLOAD_URL,
DOCUMENT_UPLOAD_ACK_URL
}
// TODO: try to get rid of `as`
@@ -510,6 +512,8 @@ API_URLS[ApiKeys.HUMAN_REMINDER_AVAILABLITY_V2] =
API_URLS[ApiKeys.PHONENUMBER_SECONDARY_SOURCES] = '/list-longhorn-secondary-sources';
API_URLS[ApiKeys.VALIDATE_PHONE_NUMBER] = '/validate-existing-telephone/{number}';
API_URLS[ApiKeys.REMOVE_CONTACT] = '/global-access/telephone/remove';
API_URLS[ApiKeys.GET_DOCUMENT_UPLOAD_URL] = 'v2/file-uploads/upload-url';
API_URLS[ApiKeys.DOCUMENT_UPLOAD_ACK_URL] = '/v2/file-uploads/upload-ack';
// TODO: try to get rid of `as`
const MOCK_API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;