Skip to content

Commit a408f1a

Browse files
committed
feat: add GrantAccessModal
1 parent fdbddda commit a408f1a

File tree

2 files changed

+147
-23
lines changed

2 files changed

+147
-23
lines changed

src/config/config.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const ITEMS_PER_PAGE = 6;
2+
3+
/**
4+
* See smart-contract transactions:
5+
* https://blockscout-bellecour.iex.ec/address/0x781482C39CcE25546583EaC4957Fb7Bf04C277D2
6+
*
7+
* See all idapps in the whitelist:
8+
* https://explorer.iex.ec/bellecour/address/0x0c6c77a11068db9fadfba25182e02863361f58da
9+
*/
10+
export const WEB3MAIL_IDAPPS_WHITELIST_SC =
11+
'0x781482c39cce25546583eac4957fb7bf04c277d2';

src/modules/myData/protectedData/GrantAccessModal.tsx

Lines changed: 136 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
1+
import { WEB3MAIL_IDAPPS_WHITELIST_SC } from '@/config/config';
2+
import { Address } from '@/types';
3+
import { useMutation, useQueryClient } from '@tanstack/react-query';
14
import { useState } from 'react';
5+
import { useNavigate } from 'react-router-dom';
6+
import { Alert } from '@/components/Alert';
27
import { Button } from '@/components/ui/button';
3-
import {
4-
Dialog,
5-
DialogTitle,
6-
DialogContent,
7-
DialogFooter,
8-
} from '@/components/ui/dialog.tsx';
8+
import { Dialog, DialogTitle, DialogContent } from '@/components/ui/dialog.tsx';
9+
import { toast } from '@/components/ui/use-toast';
10+
import { getDataProtectorCoreClient } from '@/externals/iexecSdkClient';
11+
import useUserStore from '@/stores/useUser.store';
912

1013
export default function GrantAccessModal({
1114
isSwitchingModalOpen,
1215
setSwitchingModalOpen,
16+
protectedDataAddress,
1317
}: {
1418
isSwitchingModalOpen: boolean;
1519
setSwitchingModalOpen: (openState: boolean) => void;
20+
protectedDataAddress: Address;
1621
}) {
22+
const { address: userAddress } = useUserStore();
23+
const navigate = useNavigate();
24+
const queryClient = useQueryClient();
25+
1726
const [formData, setFormData] = useState({
1827
userAddress: '',
19-
accessNumber: '',
28+
accessNumber: undefined,
2029
});
2130

2231
const handleChange = (e: { target: { name: string; value: string } }) => {
@@ -27,12 +36,65 @@ export default function GrantAccessModal({
2736
});
2837
};
2938

39+
const validateFormData = () => {
40+
if (!formData.userAddress) {
41+
return 'Please enter a user address';
42+
}
43+
if (!formData.accessNumber) {
44+
return 'Please enter a number of access';
45+
}
46+
return null;
47+
};
48+
49+
const handleGrantAccess = async () => {
50+
const errorMessage = validateFormData();
51+
if (errorMessage) {
52+
toast({ variant: 'danger', title: 'Error', description: errorMessage });
53+
throw new Error(errorMessage);
54+
} else {
55+
grantAccessMutation.mutate();
56+
}
57+
};
58+
59+
const grantAccessMutation = useMutation({
60+
mutationKey: ['grantAccess', protectedDataAddress],
61+
mutationFn: async () => {
62+
const dataProtectorCore = await getDataProtectorCoreClient();
63+
const grantedAccess = await dataProtectorCore.grantAccess({
64+
protectedData: protectedDataAddress,
65+
authorizedUser: formData.userAddress,
66+
authorizedApp: WEB3MAIL_IDAPPS_WHITELIST_SC,
67+
pricePerAccess: 0,
68+
numberOfAccess: formData.accessNumber,
69+
});
70+
71+
return grantedAccess;
72+
},
73+
onError: (err) => {
74+
console.error(err);
75+
},
76+
onSuccess: () => {
77+
queryClient.invalidateQueries({
78+
queryKey: ['granted access', protectedDataAddress, userAddress],
79+
});
80+
navigate(`/my-data/protected-data/${protectedDataAddress}`);
81+
toast({
82+
title: 'You have successfully authorized a new user.',
83+
variant: 'success',
84+
});
85+
resetForm();
86+
},
87+
});
88+
89+
const resetForm = () => {
90+
setFormData({ userAddress: '', accessNumber: undefined });
91+
};
92+
3093
return (
3194
<Dialog
3295
open={isSwitchingModalOpen}
3396
onOpenChange={(openState: boolean) => (
34-
setSwitchingModalOpen(openState),
35-
setFormData({ userAddress: '', accessNumber: '' })
97+
setSwitchingModalOpen(openState), resetForm()
3698
)}
3799
>
38100
<DialogContent>
@@ -43,6 +105,7 @@ export default function GrantAccessModal({
43105
className="mt-4 flex flex-col gap-4"
44106
onSubmit={(e) => {
45107
e.preventDefault();
108+
handleGrantAccess();
46109
}}
47110
>
48111
<div className="grid gap-2">
@@ -64,7 +127,7 @@ export default function GrantAccessModal({
64127
<Button
65128
variant="text"
66129
size="none"
67-
className="inline max-w-full justify-normal overflow-hidden text-ellipsis text-yellow-300"
130+
className="inline max-w-full justify-normal overflow-hidden text-base text-ellipsis text-yellow-300"
68131
onClick={() => {
69132
setFormData((prevData) => ({
70133
...prevData,
@@ -76,19 +139,19 @@ export default function GrantAccessModal({
76139
</Button>
77140
</div>
78141
<div>
79-
Authorize any user :{' '}
142+
Authorize myself :{' '}
80143
<Button
81144
variant="text"
82145
size="none"
83-
className="inline max-w-full justify-normal overflow-hidden text-ellipsis text-yellow-300"
146+
className="inline max-w-full justify-normal overflow-hidden text-base text-ellipsis text-yellow-300"
84147
onClick={() => {
85148
setFormData((prevData) => ({
86149
...prevData,
87-
userAddress: '0xa55513ac50fa0198c7fcd14f284229ddb8d357e6',
150+
userAddress: userAddress || '',
88151
}));
89152
}}
90153
>
91-
0xa55513ac50fa0198c7fcd14f284229ddb8d357e6
154+
{userAddress}
92155
</Button>
93156
</div>
94157
<div className="grid gap-2">
@@ -102,16 +165,66 @@ export default function GrantAccessModal({
102165
id="access_number"
103166
/>
104167
</div>
168+
{/* <div className="flex w-full max-w-[550px] flex-col gap-y-0.5 text-sm">
169+
{Object.keys(statuses).length > 0 && (
170+
<div className="mt-6">
171+
{Object.entries(statuses).map(
172+
([message, { isDone, isError }]) => (
173+
<StatusMessage
174+
key={message}
175+
message={message}
176+
isDone={isDone}
177+
isError={isError}
178+
/>
179+
)
180+
)}
181+
</div>
182+
)}
183+
</div> */}
184+
{grantAccessMutation.isError &&
185+
grantAccessMutation.error.message === 'Failed to sign data access' &&
186+
!(grantAccessMutation.error.cause as Error).message.startsWith(
187+
'ethers-user-denied'
188+
) ? (
189+
<Alert variant="error">
190+
<p>Oops, something went wrong while adding an authorized user.</p>
191+
<p>
192+
{grantAccessMutation.error.cause
193+
? grantAccessMutation.error.cause.toString()
194+
: grantAccessMutation.error.toString()}
195+
</p>
196+
<p>
197+
Are you sure your protected data was created in the same
198+
environment?'
199+
</p>
200+
</Alert>
201+
) : (
202+
grantAccessMutation.isError && (
203+
<Alert variant="error">
204+
205+
<p>
206+
Oops, something went wrong while adding an authorized user.
207+
</p>
208+
<p>
209+
{grantAccessMutation.error.cause
210+
? grantAccessMutation.error.cause.message.toString()
211+
: grantAccessMutation.error.toString()}
212+
</p>
213+
</Alert>
214+
)
215+
)}
216+
<div className="mt-2 flex justify-center gap-5">
217+
<Button
218+
variant="outline"
219+
onClick={() => setSwitchingModalOpen(false)}
220+
>
221+
Cancel
222+
</Button>
223+
<Button type="submit" isLoading={grantAccessMutation.isPending}>
224+
Add User
225+
</Button>
226+
</div>
105227
</form>
106-
<DialogFooter className="mt-2 flex !justify-center gap-5">
107-
<Button
108-
variant="outline"
109-
onClick={() => setSwitchingModalOpen(false)}
110-
>
111-
Cancel
112-
</Button>
113-
<Button>Add User</Button>
114-
</DialogFooter>
115228
</DialogContent>
116229
</Dialog>
117230
);

0 commit comments

Comments
 (0)