diff --git a/src/api/BulkIssuance.ts b/src/api/BulkIssuance.ts index 4b2c4b02c..da12a915e 100644 --- a/src/api/BulkIssuance.ts +++ b/src/api/BulkIssuance.ts @@ -23,9 +23,8 @@ export const getSchemaCredDef = async () => { } }; -export const DownloadCsvTemplate = async () => { +export const DownloadCsvTemplate = async (credDefId: string) => { const orgId = await getFromLocalStorage(storageKeys.ORG_ID); - const credDefId = await getFromLocalStorage(storageKeys.CRED_DEF_ID); const url = `${apiRoutes.organizations.root}/${orgId}/${credDefId}${apiRoutes.Issuance.download}`; const axiosPayload = { diff --git a/src/common/global.css b/src/common/global.css index e590fde14..f3db9b26a 100644 --- a/src/common/global.css +++ b/src/common/global.css @@ -17,6 +17,13 @@ ul[role="tablist"] li[role="presentation"] button[aria-selected="true"] { @apply text-primary-700 border-primary-700; } +button.role-btn span { + @apply overflow-hidden; + border-radius: 8px; + padding-top: 6.5px; + padding-bottom: 6.5px; +} + .word-break-word{ word-break: break-word !important; } @@ -103,7 +110,7 @@ ul.timelinestatic { } .search-dropdown .select__control .select__placeholder { - @apply absolute flex items-start; + @apply absolute flex items-start ml-2; } .search-dropdown .select__control .select__value-container{ @@ -112,8 +119,11 @@ ul.timelinestatic { } .select__single-value{ - @apply !text-primary-700; - width: calc(100% - 5px); + @apply dark:!text-white !text-primary-700 w-fit; +} + +.select__value-container .select__value-container--has-value .select__single-value { + @apply w-fit; } .search-dropdown{ diff --git a/src/components/Issuance/BulkIssuance.tsx b/src/components/Issuance/BulkIssuance.tsx index 7aa2af268..46e0845cd 100644 --- a/src/components/Issuance/BulkIssuance.tsx +++ b/src/components/Issuance/BulkIssuance.tsx @@ -14,6 +14,8 @@ import { pathRoutes } from '../../config/pathRoutes'; import IssuancePopup from './IssuancePopup'; import SOCKET from '../../config/SocketConfig'; import { ToastContainer, toast } from 'react-toastify'; +import BreadCrumbs from '../BreadCrumbs'; +import BackButton from '../../commonComponents/backbutton' interface IValues { value: string; @@ -33,6 +35,12 @@ interface ICredentials { schemaAttributes: IAttributes | boolean; credentialDefinition: string; } + +interface IUploadMessage { + message: string + type : "success" | "failure" +} + const BulkIssuance = () => { const [csvData, setCsvData] = useState([]); const [requestId, setRequestId] = useState(""); @@ -46,7 +54,7 @@ const BulkIssuance = () => { const [openModal, setOpenModal] = useState(false); const [message, setMessage] = useState(''); const [searchText, setSearchText] = useState(''); - const [error, setError] = useState(null); + const [uploadMessage, setUploadMessage] = useState(null) const [success, setSuccess] = useState(null); const [failure, setFailure] = useState(null); @@ -86,12 +94,16 @@ const BulkIssuance = () => { ); setCredentialOptions(options); } else { - setError(response as string); + setUploadMessage({message: response as string, type: "failure"}); + setSuccess(null) + setFailure(null) } setLoading(false); } } catch (error) { - setError(error as string); + setUploadMessage({message: error as string, type: "failure"}); + setSuccess(null) + setFailure(null) } }; @@ -111,13 +123,11 @@ const BulkIssuance = () => { const DownloadSchemaTemplate = async () => { setProcess(true); - const credDefId = await getFromLocalStorage(storageKeys.CRED_DEF_ID); - - if (credDefId) { + if (credentialSelected) { try { setProcess(true); - const response = await DownloadCsvTemplate(); + const response = await DownloadCsvTemplate(credentialSelected); const { data } = response as AxiosResponse; if (data) { @@ -127,13 +137,19 @@ const BulkIssuance = () => { setSuccess('File downloaded successfully'); setProcess(false); } else { - setError('File URL is missing in the response'); + setUploadMessage({message: 'File URL is missing in the response', type: "failure"}); + setSuccess(null) + setFailure(null) } } else { - setError('API request was not successful'); + setUploadMessage({message: 'API request was not successful', type: "failure"}); + setSuccess(null) + setFailure(null) } } catch (error) { - setError(error as string); + setUploadMessage({message: error as string, type: "failure"}); + setSuccess(null) + setFailure(null) } } @@ -193,7 +209,7 @@ const BulkIssuance = () => { progress: undefined, theme: 'colored', }); - setError("Issuance process failed, please retry") + setFailure("Issuance process failed, please retry") }); }, []) @@ -202,7 +218,9 @@ const BulkIssuance = () => { setLoading(true); if (file.type !== 'text/csv') { - setError('Invalid file type. Please select only CSV files.'); + setUploadMessage({message:'Invalid file type. Please select only CSV files.', type: "failure"}); + setSuccess(null) + setFailure(null) return; } try { @@ -218,6 +236,8 @@ const BulkIssuance = () => { await wait(500); + setUploadedFileName(file?.name); + setUploadedFile(file); const response = await uploadCsvFile(payload, credentialSelected); const { data } = response as AxiosResponse; @@ -225,14 +245,13 @@ const BulkIssuance = () => { if (data?.statusCode === apiStatusCodes?.API_STATUS_CREATED) { setLoading(false); setRequestId(data?.data); - setSuccess(data?.message); setIsFileUploaded(true); - setUploadedFileName(file?.name); - setUploadedFile(file); - setError(null); + setUploadMessage({message: data?.message, type: "success"}); await handleCsvFileData(data?.data); } else { - setError(response as string); + setUploadMessage({message: response as string, type: "failure"}); + setSuccess(null) + setFailure(null) } setLoading(false); } catch (err) { @@ -313,7 +332,7 @@ const BulkIssuance = () => { } }; const clearError = () => { - setError(null); + setUploadMessage(null); }; const handleOpenConfirmation = () => { @@ -339,14 +358,13 @@ const BulkIssuance = () => { const response = await issueBulkCredential(requestId, SOCKET.id); const { data } = response as AxiosResponse; if (data?.statusCode === apiStatusCodes.API_STATUS_CREATED) { + if (data?.data) { setLoading(false); setOpenModal(false); setSuccess(data.message); + setUploadMessage(null) handleResetForConfirm() - // setTimeout(() => { - // window.location.href = pathRoutes.organizations.Issuance.connections; - // }, 2000); } else { setFailure(response as string); setLoading(false); @@ -369,419 +387,417 @@ const BulkIssuance = () => { ); return ( -
- - {(success || failure) && ( - { - setSuccess(null); - setFailure(null); - }} - viewButton={Boolean((success && success === "Issuance process completed") || (error && error === "Issuance process failed, please retry"))} - path={pathRoutes.organizations.Issuance.history} - /> - )} -
-
-

- Bulk Issuance -

- Bulk issuance by .csv +
+
+
+ +
-
-
- +
+ + {(success || failure) && ( + { + setSuccess(null); + setFailure(null); + }} + viewButton={Boolean((success && success === "Issuance process completed") || (failure && failure === "Issuance process failed, please retry"))} + path={pathRoutes.organizations.Issuance.history} + /> + )} +
-
-
-
- { + setCredentialSelected(value?.value ?? ""); + }} + /> +
+
+ {credentialSelected && selectedCred && ( + +
+

+ Schema: + {selectedCred?.schemaName || ""}{' '} + [{selectedCred?.schemaVersion}] +

+

+ {' '} + + Credential Definition: + {' '} + {selectedCred?.credentialDefinition} +

+ Attributes: +
+ {selectedCred?.schemaAttributes.map( + (element: IAttributes) => ( +
+ + {element.attributeName} + +
+ ), + )} +
-
- - )} -
-
- -
-
- {/* ---------------- */} -
-
-
-
+
+
-
- {uploadedFileName && ( -
+ {/* ---------------- */} +
+
+
+
+ +
+
+ +
- )} - {error && ( -
-

{error}

- +
+ {uploadedFileName && ( +
- - -
- )} +

+ {uploadedFileName} +

+ +
+ )} + {uploadMessage !== null && ( + + )} +
-
- - - {csvData && csvData.length > 0 && ( - -
-
-
- {csvData && csvData.length > 0 && ( -
- - - - - {csvData.length > 0 && - Object.keys(csvData[0]).map((header, index) => ( - - ))} - - - - {csvData && - csvData.length > 0 && - csvData.map((row, rowIndex) => ( - - {Object.values(row).map((cell, cellIndex) => ( - + + + {csvData && + csvData.length > 0 && + csvData.map((row, rowIndex) => ( + + {Object.values(row).map((cell, cellIndex) => ( + + ))} + + ))} + +
- {header} -
+ + {csvData && csvData.length > 0 && ( + +
+
+
+ {csvData && csvData.length > 0 && ( +
+ + + + + {csvData.length > 0 && + Object.keys(csvData[0]).map((header, index) => ( + ))} - - ))} - -
- {cell} - + {header} +
-
- )} +
+ {cell} +
+
+ )} +
-
- {currentPage.total > 1 && ( -
- -
- )} - - )} -
- {!isCredSelected && ( - <> -

Steps

-
    -
  • -

    - Select and Download -

    -

    - Select credential definition and download .CSV file -

    -
  • -
  • -

    - Fill the data -

    -

    - Fill issuance data in the downloaded .CSV file -

    -
  • -
  • -

    - Upload and Issue -

    -

    - Upload .CSV file and click on issue -

    -
  • -
- + {currentPage.total > 1 && ( +
+ +
+ )} + )} +
+ {!isCredSelected && ( + <> +

Steps

+
    +
  • +

    + Select and Download +

    +

    + Select credential definition and download .CSV file +

    +
  • +
  • +

    + Fill the data +

    +

    + Fill issuance data in the downloaded .CSV file +

    +
  • +
  • +

    + Upload and Issue +

    +

    + Upload .CSV file and click on issue +

    +
  • +
+ + )} - + -
- - + + + + + Reset + +
@@ -789,4 +805,4 @@ const BulkIssuance = () => { ); }; -export default BulkIssuance; +export default BulkIssuance; \ No newline at end of file diff --git a/src/components/Issuance/Connections.tsx b/src/components/Issuance/Connections.tsx index dfc204ef3..fffdc7e5f 100644 --- a/src/components/Issuance/Connections.tsx +++ b/src/components/Issuance/Connections.tsx @@ -10,7 +10,6 @@ import { pathRoutes } from '../../config/pathRoutes'; import BreadCrumbs from '../BreadCrumbs'; import ConnectionList from './ConnectionList'; import BackButton from '../../commonComponents/backbutton'; -import BulkIssuance from './BulkIssuance'; const Connections = () => { const [selectedConnectionList, setSelectedConnectionList] = useState< @@ -63,7 +62,8 @@ const Connections = () => { Connection -
  • + {/* Keep this code as it is, this is required in future use. */} + {/*
  • -
  • + */}
    @@ -129,14 +129,15 @@ const Connections = () => { )}
    -
    -
    +
    */}
    ); diff --git a/src/components/Issuance/History.tsx b/src/components/Issuance/History.tsx index 201977675..78b1840fb 100644 --- a/src/components/Issuance/History.tsx +++ b/src/components/Issuance/History.tsx @@ -309,7 +309,7 @@ const HistoryBulkIssuance = () => { - +
    { disabled={props.isProcessing} onClick={() => { props.onSuccess(true); + window.scrollTo({top: 0, left: 0, behavior: 'smooth'}); }} className="bg-primary-700 hover:!bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 rounded-lg inline-flex items-center text-center ml-2" > @@ -128,4 +129,4 @@ const IssuancePopup = (props: IProps) => { ); }; -export default IssuancePopup; +export default IssuancePopup; \ No newline at end of file diff --git a/src/components/Issuance/IssuedCrdentials.tsx b/src/components/Issuance/IssuedCrdentials.tsx index 657c68979..2e5261250 100644 --- a/src/components/Issuance/IssuedCrdentials.tsx +++ b/src/components/Issuance/IssuedCrdentials.tsx @@ -150,25 +150,41 @@ const CredentialList = () => {
    -
    +

    Credentials

    -
    +
    + { walletCreated && - - + + } onClickEvent={schemeSelection} /> } + { + walletCreated && + + + + + + } + onClickEvent={() => window.location.href = pathRoutes.organizations.Issuance.bulkIssuance} + /> + }
    diff --git a/src/components/RoleViewButton/index.tsx b/src/components/RoleViewButton/index.tsx index 1c2f0616b..1023fd678 100644 --- a/src/components/RoleViewButton/index.tsx +++ b/src/components/RoleViewButton/index.tsx @@ -11,10 +11,11 @@ interface RoleViewButtonProps { svgComponent?: ReactElement, onClickEvent?: () => void, feature: string + isOutline?: boolean } -const RoleViewButton = ({ buttonTitle, svgComponent, onClickEvent, feature }: RoleViewButtonProps) => { +const RoleViewButton = ({ buttonTitle, svgComponent, onClickEvent, feature, isOutline }: RoleViewButtonProps) => { const [userRoles, setUserRoles] = useState([]) @@ -30,25 +31,25 @@ const RoleViewButton = ({ buttonTitle, svgComponent, onClickEvent, feature }: Ro const isRoleAccess = (): boolean => { - if(feature === Features.CRETAE_ORG){ + if (feature === Features.CRETAE_ORG) { return true } else if (feature === Features.ISSUENCE) { - if (userRoles.includes(Roles.OWNER) - || userRoles.includes(Roles.ADMIN) - || userRoles.includes(Roles.ISSUER) + if (userRoles.includes(Roles.OWNER) + || userRoles.includes(Roles.ADMIN) + || userRoles.includes(Roles.ISSUER) ) { return true } return false - }else if (feature === Features.VERIFICATION) { - if (userRoles.includes(Roles.OWNER) - || userRoles.includes(Roles.ADMIN) - || userRoles.includes(Roles.VERIFIER) + } else if (feature === Features.VERIFICATION) { + if (userRoles.includes(Roles.OWNER) + || userRoles.includes(Roles.ADMIN) + || userRoles.includes(Roles.VERIFIER) ) { return true } return false - }else if (userRoles.includes(Roles.OWNER) || userRoles.includes(Roles.ADMIN)) { + } else if (userRoles.includes(Roles.OWNER) || userRoles.includes(Roles.ADMIN)) { return true } else { return false @@ -61,8 +62,10 @@ const RoleViewButton = ({ buttonTitle, svgComponent, onClickEvent, feature }: Ro { isRoleAccess() &&