Skip to content

Commit c10e145

Browse files
authored
Merge pull request #210 from wwWallet/feat/onselect-display-details
Enhance Credential Display in Presentation Selection Popup
2 parents f837907 + c3af656 commit c10e145

File tree

3 files changed

+70
-55
lines changed

3 files changed

+70
-55
lines changed

src/components/Credentials/CredentialInfo.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const renderRow = (fieldName, fieldValue) => {
4545
return null;
4646
};
4747

48-
const CredentialInfo = ({ credential }) => {
48+
const CredentialInfo = ({ credential, mainClassName="pt-5 pr-2 w-full" }) => {
4949

5050
const [parsedCredential, setParsedCredential] = useState(null);
5151

@@ -56,7 +56,7 @@ const CredentialInfo = ({ credential }) => {
5656
}, []);
5757

5858
return (
59-
<div className=" pt-5 pr-2 w-full">
59+
<div className={mainClassName}>
6060
<table className="lg:w-4/5">
6161
<tbody className="divide-y-4 divide-transparent">
6262
{parsedCredential && (

src/components/Popups/SelectCredentials.js

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { FaShare } from 'react-icons/fa';
44
import { useTranslation } from 'react-i18next';
55
import { useApi } from '../../api';
66
import { CredentialImage } from '../Credentials/CredentialImage';
7-
7+
import CredentialInfo from '../Credentials/CredentialInfo';
88

99
function SelectCredentials({ showPopup, setShowPopup, setSelectionMap, conformantCredentialsMap, verifierDomainName }) {
1010
const api = useApi();
11-
const [images, setImages] = useState([]);
11+
const [vcEntities, setVcEntities] = useState([]);
1212
const navigate = useNavigate();
1313
const { t } = useTranslation();
1414

@@ -17,8 +17,7 @@ function SelectCredentials({ showPopup, setShowPopup, setSelectionMap, conforman
1717
const [currentSelectionMap, setCurrentSelectionMap] = useState({});
1818
const [requestedFields, setRequestedFields] = useState([]);
1919
const [showRequestedFields, setShowRequestedFields] = useState(false);
20-
const [renderContent, setRenderContent] = useState(showRequestedFields);
21-
const [applyTransition, setApplyTransition] = useState(false);
20+
const [credentialDisplay, setCredentialDisplay] = useState({});
2221

2322
useEffect(() => {
2423
const getData = async () => {
@@ -30,13 +29,13 @@ function SelectCredentials({ showPopup, setShowPopup, setSelectionMap, conforman
3029

3130
try {
3231
const response = await api.get('/storage/vc');
33-
const simplifiedCredentials = response.data.vc_list
32+
const vcEntities = response.data.vc_list
3433
.filter(vcEntity =>
3534
conformantCredentialsMap[keys[currentIndex]].credentials.includes(vcEntity.credentialIdentifier)
3635
);
3736

3837
setRequestedFields(conformantCredentialsMap[keys[currentIndex]].requestedFields);
39-
setImages(simplifiedCredentials);
38+
setVcEntities(vcEntities);
4039
} catch (error) {
4140
console.error('Failed to fetch data', error);
4241
}
@@ -45,17 +44,6 @@ function SelectCredentials({ showPopup, setShowPopup, setSelectionMap, conforman
4544
getData();
4645
}, [api, currentIndex]);
4746

48-
useEffect(() => {
49-
if (showRequestedFields) {
50-
setRenderContent(true);
51-
} else if (applyTransition) {
52-
setTimeout(() => setRenderContent(false), 500);
53-
} else {
54-
setRenderContent(false);
55-
}
56-
}, [showRequestedFields, applyTransition]);
57-
58-
5947
const goToNextSelection = () => {
6048
setCurrentIndex((i) => i + 1);
6149
}
@@ -66,12 +54,9 @@ function SelectCredentials({ showPopup, setShowPopup, setSelectionMap, conforman
6654
currentMap[descriptorId] = credentialIdentifier;
6755
return currentMap;
6856
});
69-
setApplyTransition(false);
70-
setShowRequestedFields(false);
7157
goToNextSelection();
7258
};
7359

74-
7560
const handleCancel = () => {
7661
setShowPopup(false);
7762
navigate('/'); // Navigate to home page or any other route
@@ -81,10 +66,21 @@ function SelectCredentials({ showPopup, setShowPopup, setSelectionMap, conforman
8166
return null;
8267
};
8368

69+
const toggleRequestedFields = () => {
70+
setShowRequestedFields(!showRequestedFields);
71+
};
72+
73+
const toggleCredentialDisplay = (identifier) => {
74+
setCredentialDisplay(prev => ({
75+
...prev,
76+
[identifier]: !prev[identifier]
77+
}));
78+
};
79+
8480
return (
8581
<div className="fixed inset-0 flex items-center justify-center z-50">
8682
<div className="absolute inset-0 bg-black opacity-50"></div>
87-
<div className="bg-white p-4 rounded-lg shadow-lg w-full lg:max-w-[33.33%] sm:max-w-[66.67%] max-h-[90vh] z-10 relative m-4 overflow-y-auto">
83+
<div className="bg-white p-4 rounded-lg shadow-md w-full lg:max-w-[33.33%] sm:max-w-[66.67%] max-h-[90vh] z-10 relative m-4 overflow-y-auto">
8884
<h2 className="text-lg font-bold mb-2 text-custom-blue">
8985
<FaShare size={20} className="inline mr-1 mb-1" />
9086
{t('selectCredentialPopup.title')}
@@ -94,47 +90,56 @@ function SelectCredentials({ showPopup, setShowPopup, setSelectionMap, conforman
9490
{t('selectCredentialPopup.description')}
9591
</p>
9692
{requestedFields && (
97-
98-
99-
<div className="lg:p-0 p-2 mt-4 w-full">
93+
<div className="my-3 w-full">
10094
<div className="mb-2 flex items-center">
10195
<button
102-
onClick={() => { setApplyTransition(true); setShowRequestedFields(!showRequestedFields) }}
103-
className="px-2 py-2 text-white cursor-pointer flex items-center bg-custom-blue hover:bg-custom-blue-hover font-medium rounded-lg text-sm px-4 py-2 text-center dark:bg-custom-blue-hover dark:hover:bg-custom-blue-hover"
96+
onClick={toggleRequestedFields}
97+
className="px-2 py-2 text-white cursor-pointer flex items-center bg-custom-blue hover:bg-custom-blue-hover font-medium rounded-lg text-xs px-4 py-2 text-center dark:bg-custom-blue-hover dark:hover:bg-custom-blue-hover"
10498
>
10599
{showRequestedFields ? `${t('selectCredentialPopup.requestedFieldsHide')}` : `${t('selectCredentialPopup.requestedFieldsShow')}`}
106100
</button>
107101
</div>
108102

109-
<hr className="border-t border-gray-300 py-1" />
110-
111-
<div
112-
className={`overflow-hidden transition-height ${showRequestedFields ? 'max-h-96' : 'max-h-0'}`}
113-
style={{ transition: 'max-height 0.5s ease-in-out' }}
103+
<hr className="border-t border-gray-300" />
114104

115-
>
116-
{renderContent && (
117-
<>
105+
<div className={`transition-all ease-in-out duration-1000 p-2 overflow-hidden rounded-xl shadow-md bg-gray-50 ${showRequestedFields ? 'max-h-[500px] opacity-100' : 'max-h-0 opacity-0 m-0 p-0'}`}>
106+
<>
107+
{verifierDomainName && (
118108
<p className='mb-2 text-sm italic text-gray-700'>{t('selectCredentialPopup.requestedFieldsinfo')} {verifierDomainName}</p>
119-
<textarea
120-
readOnly
121-
value={requestedFields.join('\n')}
122-
className="w-full border rounded p-2 rounded-xl"
123-
rows={Math.min(3, Math.max(1, requestedFields.length))}
124-
></textarea>
125-
</>
126-
)}
109+
)}
110+
<textarea
111+
readOnly
112+
value={requestedFields.join('\n')}
113+
className="p-2 border rounded-lg text-sm"
114+
style={{ width: '-webkit-fill-available' }}
115+
rows={Math.min(3, Math.max(1, requestedFields.length))}
116+
></textarea>
117+
</>
127118
</div>
128119
</div>
129120
)}
130121

131-
<div className='flex flex-wrap justify-center flex overflow-y-auto max-h-[40vh]'>
132-
{images.map(image => (
133-
<div className="m-3 flex justify-center">
134-
<div className="relative rounded-xl w-2/3 overflow-hidden transition-shadow shadow-md hover:shadow-lg cursor-pointer">
135-
<CredentialImage key={image.credentialIdentifier} credential={image.credential} onClick={() => handleClick(image.credentialIdentifier)} className={"w-full object-cover rounded-xl"} />
122+
<div className='flex flex-wrap justify-center flex overflow-y-auto max-h-[40vh] custom-scrollbar bg-gray-50 shadow-md rounded-xl'>
123+
{vcEntities.map(vcEntity => (
124+
<>
125+
<div key={vcEntity.credentialIdentifier} className="m-3 flex flex-col items-center">
126+
<div className="relative rounded-xl w-2/3 overflow-hidden transition-shadow shadow-md hover:shadow-xl cursor-pointer">
127+
<CredentialImage key={vcEntity.credentialIdentifier} credential={vcEntity.credential} onClick={() => handleClick(vcEntity.credentialIdentifier)} className={"w-full object-cover rounded-xl"} />
128+
</div>
129+
<div className='w-2/3 mt-2'>
130+
<button
131+
onClick={() => toggleCredentialDisplay(vcEntity.credentialIdentifier)}
132+
className="text-xs py-2 w-full bg-custom-blue hover:bg-custom-blue-hover text-white font-medium rounded-lg">
133+
{credentialDisplay[vcEntity.credentialIdentifier] ? 'Hide Details' : 'Show Details'}
134+
</button>
135+
<div
136+
className={`transition-all ease-in-out duration-1000 overflow-hidden shadow-md rounded-lg ${credentialDisplay[vcEntity.credentialIdentifier] ? 'max-h-[500px] opacity-100' : 'max-h-0 opacity-0'}`}
137+
>
138+
<CredentialInfo credential={vcEntity.credential} mainClassName={"text-xs w-full"} />
139+
</div>
140+
</div>
136141
</div>
137-
</div>
142+
</>
138143
))}
139144
</div>
140145
<button

src/index.css

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,34 @@
1414
margin: 0 5px !important;
1515
}
1616

17-
/* Custom scrollbar in login */
17+
/* Custom scrollbar */
1818
.custom-scrollbar {
19-
scrollbar-width: thin;
20-
scrollbar-color: #ccc #f0f0f0;
21-
padding-right: 5px;
19+
padding-right: 10px;
2220
}
2321

2422
.custom-scrollbar::-webkit-scrollbar {
25-
width: 5px;
23+
width: 10px;
24+
}
25+
26+
.custom-scrollbar::-webkit-scrollbar-track {
27+
background-color: #f0f0f0;
28+
border-radius: 5px;
2629
}
2730

2831
.custom-scrollbar::-webkit-scrollbar-thumb {
2932
background-color: #ccc;
3033
border-radius: 5px;
34+
border: 2px solid #f0f0f0;
3135
}
3236

3337
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
3438
background-color: #888;
39+
width: 15px;
40+
border: 2px solid #888;
41+
}
42+
43+
.custom-scrollbar::-webkit-scrollbar:hover {
44+
width: 15px;
3545
}
3646

3747
/* Nav item animation on Hover */

0 commit comments

Comments
 (0)