Skip to content

Commit 3aae43f

Browse files
committed
migrate request logic to sistent
Signed-off-by: aabidsofi19 <mailtoaabid01@gmail.com>
1 parent ee672e2 commit 3aae43f

2 files changed

Lines changed: 200 additions & 55 deletions

File tree

src/custom/ShareModal/ShareModal.tsx

Lines changed: 152 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
ListWrapper,
2727
VisibilityIconWrapper
2828
} from './style';
29+
import { TypedMutationTrigger, TypedUseQuery } from '@reduxjs/toolkit/dist/query/react';
2930

3031
const options = {
3132
PUBLIC: 'Anyone with the link can edit',
@@ -158,6 +159,20 @@ interface SelectedResource {
158159
[key: string]: unknown;
159160
}
160161

162+
type ResourceAccessArg = {
163+
resourceType: string;
164+
resourceId: string;
165+
resourceAccessMappingPayload: {
166+
grant_access: string[];
167+
revoke_access: string[];
168+
notify_users: boolean;
169+
};
170+
};
171+
172+
173+
import type { MutationTrigger } from '@reduxjs/toolkit/query/react';
174+
import { startCase } from 'lodash';
175+
161176
interface ShareModalProps {
162177
/** Function to close the share modal */
163178
handleShareModalClose: () => void;
@@ -186,11 +201,13 @@ interface ShareModalProps {
186201
fetchSuggestions: (value: string) => Promise<User[]>;
187202
handleCopy: () => void;
188203
handleUpdateVisibility: (value: string) => Promise<{ error: string }>,
189-
isUpdatingVisibility: boolean,
190204
handleShareWithNewUsers: (newUsers: User[]) => Promise<{ error: string }>,
191205
canShareWithNewUsers: boolean,
192206
handleRevokeAccess: (revokedUsser: User[]) => Promise<{ error: string }>
193207
canRevokeAccess: boolean,
208+
resourceAccessMutator: MutationTrigger<ResourceAccessArg>,
209+
notify: ({ message, event_type }: { message: string, event_type: "success" | "error" }) => void,
210+
useGetAllUsersQuery: any,
194211
}
195212

196213
/**
@@ -206,40 +223,158 @@ const ShareModal: React.FC<ShareModalProps> = ({
206223
hostURL = null,
207224
handleCopy,
208225
handleUpdateVisibility,
209-
isUpdatingVisibility,
210226
canShareWithNewUsers,
211-
handleRevokeAccess,
212-
handleShareWithNewUsers,
213227
isVisibilitySelectorDisabled = false,
214-
fetchSuggestions
228+
fetchSuggestions,
229+
resourceAccessMutator,
230+
notify,
231+
useGetAllUsersQuery,
232+
215233
}: ShareModalProps): JSX.Element => {
216-
const theme = useTheme();
234+
const theme = useTheme();
217235
const [openMenu, setMenu] = useState<boolean>(false);
218236
const [shareUserData, setShareUserData] = useState<User[]>([]);
219-
const [resourceVisibility,setVisibility] = useState(selectedResource.visibility)
237+
const [resourceVisibility, setVisibility] = useState(selectedResource.visibility)
238+
const [isUpdatingVisibility, setUpdatingVisibility] = useState(false)
239+
240+
241+
242+
243+
const resourceType = dataName === "design" ? "pattern" : dataName;
244+
245+
246+
const handleShareWithNewUsers = async (newUsers: User[]) => {
247+
console.log("new users", newUsers)
248+
const grantAccessList = newUsers.map(user => ({
249+
actor_id: user.user_id ?? user.id,
250+
actor_type: "user"
251+
}))
252+
const emails = newUsers.map(u => u.email)
253+
254+
const response = await resourceAccessMutator({
255+
resourceType,
256+
resourceId: selectedResource?.id,
257+
resourceAccessMappingPayload: {
258+
grant_access: [...grantAccessList],
259+
revoke_access: [],
260+
notify_users: true
261+
}
262+
})
263+
264+
265+
266+
if (!response?.error) {
267+
const msg = `${dataName} shared with ${emails.join(", ")} `;
268+
notify({
269+
message: msg,
270+
event_type: "success"
271+
});
272+
}
273+
274+
if (response?.error) {
275+
notify({
276+
message: `An error occurred. ${dataName} not shared`,
277+
event_type: "error"
278+
});
279+
}
280+
281+
return {
282+
error: response?.error?.error
283+
}
284+
285+
};
286+
287+
288+
const handleRevokeAccess = async (revokedUsers: User[]) => {
289+
const revokeAccessList = revokedUsers.map(user => ({
290+
actor_id: user.id,
291+
actor_type: "user"
292+
}))
293+
const emails = revokedUsers.map(u => u.email)
294+
295+
const response = await resourceAccessMutator({
296+
resourceType,
297+
resourceId: selectedResource?.id,
298+
resourceAccessMappingPayload: {
299+
grant_access: [],
300+
revoke_access: [...revokeAccessList],
301+
notify_users: true
302+
}
303+
})
304+
305+
306+
if (!response?.error) {
307+
const msg = `Access to ${dataName} revoked for ${emails.join(", ")} `;
308+
notify({
309+
message: msg,
310+
event_type: "success"
311+
});
312+
313+
}
314+
315+
if (response?.error) {
316+
notify({
317+
message: `failed to revokke access to ${dataName}`,
318+
event_type: "error"
319+
});
320+
}
321+
322+
return {
323+
error: response?.error?.error
324+
}
325+
326+
};
327+
220328

221329
const handleDelete = async (email: string) => {
222330
const revoked = shareUserData.find(user => user.email == email)
223331
if (!revoked) {
224332
console.error("cant revoke user without acesss")
225-
return {error:""}
333+
return { error: "" }
226334
}
227335
return handleRevokeAccess([revoked])
228336
};
229337

230-
const handleOptionClick = async (event: SelectChangeEvent<unknown>) => {
338+
339+
const notifyVisibilityChange = (res: any, value: any) => {
340+
const UPDATE_VISIBILITY_MSG = `${startCase(dataName)} '${selectedResource.name}' is now ${value}`;
341+
const FAILED_TO_UPDATE_VISIBILITY_MSG = `Failed to update visibility. ${res?.error?.error || ""}`;
342+
343+
if (!res.error) {
344+
notify({
345+
message: UPDATE_VISIBILITY_MSG,
346+
event_type: "success"
347+
});
348+
} else {
349+
350+
notify({
351+
message: FAILED_TO_UPDATE_VISIBILITY_MSG,
352+
event_type: "error"
353+
});
354+
}
355+
}
356+
357+
const updateVisisbility = async (event: SelectChangeEvent<unknown>) => {
231358
const value = event.target.value as string;
232-
if (value == resourceVisibility){
233-
console.error("visibility is already ",value)
359+
360+
if (value == resourceVisibility) {
361+
console.error("visibility is already ", value)
234362
return
235363
}
236364

237-
const res = await handleUpdateVisibility(value)
238-
if (!res?.error){
239-
setVisibility(value)
365+
try {
366+
setUpdatingVisibility(true)
367+
const res = await handleUpdateVisibility(value)
368+
notifyVisibilityChange(res, value)
369+
if (!res?.error) {
370+
setVisibility(value)
371+
}
372+
} finally {
373+
setUpdatingVisibility(false)
240374
}
241375
};
242376

377+
243378
const handleMenuClose = () => setMenu(false);
244379

245380

@@ -276,6 +411,7 @@ const ShareModal: React.FC<ShareModalProps> = ({
276411
hostURL={hostURL}
277412
/>
278413
}
414+
useGetAllUsersQuery={useGetAllUsersQuery}
279415
fetchSuggestions={fetchSuggestions}
280416
/>
281417

@@ -298,7 +434,7 @@ const ShareModal: React.FC<ShareModalProps> = ({
298434

299435
{isUpdatingVisibility && <CircularProgress size={24} />}
300436

301-
437+
302438
{!isUpdatingVisibility && resourceVisibility === SHARE_MODE.PUBLIC && (
303439
<PublicIcon
304440
width={24}
@@ -326,7 +462,7 @@ const ShareModal: React.FC<ShareModalProps> = ({
326462
open={openMenu}
327463
onClose={handleMenuClose}
328464
onOpen={() => setMenu(true)}
329-
onChange={handleOptionClick}
465+
onChange={updateVisisbility}
330466
disabled={isVisibilitySelectorDisabled || isUpdatingVisibility}
331467
>
332468
{Object.values(SHARE_MODE).map((option) => (

src/custom/UserSearchField/UserSearchField.tsx

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import React, { useEffect, useMemo, useState } from 'react';
66
import { Avatar, Box, Chip, Grid, TextField, Typography } from '../../base';
77
import { PersonIcon } from '../../icons/Person';
88
import { useTheme } from '../../theme';
9+
import { useDebounce } from 'use-debounce';
910

1011
interface User {
1112
id: string;
@@ -40,29 +41,38 @@ interface UserSearchFieldProps {
4041
*/
4142
fetchSuggestions: (value: string) => Promise<User[]>;
4243
shareWithNewUsers: (newUsers: User[]) => Promise<{ error: string }>;
44+
useGetAllUsersQuery: any
4345
// isSharing : boolean
4446
}
4547

4648
const UserShareSearch: React.FC<UserSearchFieldProps> = ({
4749
usersData,
4850
disabled = false,
49-
fetchSuggestions,
50-
shareWithNewUsers
51+
shareWithNewUsers,
52+
useGetAllUsersQuery
5153
}: UserSearchFieldProps) => {
5254
const [error, setError] = useState<string | false>(false);
5355
const [inputValue, setInputValue] = useState('');
54-
const [options, setOptions] = useState<User[]>([]);
55-
const [open, setOpen] = useState(false);
56-
const [searchUserLoading, setSearchUserLoading] = useState(false);
5756
const [usersToShareWith, setUsersToShareWith] = useState<User[]>([]);
5857
const [isSharing, setIsSharing] = useState(false);
5958
const theme = useTheme();
59+
const [debouncedInput] = useDebounce(inputValue,300)
60+
61+
const {data:usersMatchingSearch,isLoading:searchUserLoading} = useGetAllUsersQuery({
62+
search:debouncedInput,
63+
page:0,
64+
pagesize:10,
65+
},{skip: debouncedInput.trim().length == 0})
66+
67+
const suggestions = (usersMatchingSearch?.data ?? []) as User[]
68+
69+
const open = inputValue.trim().length > 0 && suggestions?.length > 0
70+
6071

6172
const handleShareWithNewUsers = async () => {
6273
try {
6374
setIsSharing(true);
6475
const result = await shareWithNewUsers(usersToShareWith);
65-
console.log('sharing result', result);
6676
if (!result.error) {
6777
setUsersToShareWith([]);
6878
} else {
@@ -77,57 +87,56 @@ const UserShareSearch: React.FC<UserSearchFieldProps> = ({
7787

7888
const handleAdd = (_event: React.SyntheticEvent<Element, Event>, value: User[]) => {
7989
if (value) {
80-
console.log('add value', value);
8190
setUsersToShareWith(value);
8291
setInputValue('');
83-
setOpen(false);
8492
}
8593
};
8694

87-
// Memoize the debounced function to prevent recreation on each render
88-
const debouncedFetchSuggestions = useMemo(
89-
() =>
90-
debounce(async (value: string) => {
91-
console.log('debounced fetch running for:', value);
92-
if (value === '') {
93-
setOptions([]);
94-
setOpen(false);
95-
} else {
96-
setSearchUserLoading(true);
97-
const suggestions = await fetchSuggestions(value);
98-
setOptions(suggestions);
99-
setSearchUserLoading(false);
100-
setError(false);
101-
setOpen(true);
102-
}
103-
}, 300),
104-
[fetchSuggestions]
105-
);
95+
// // Memoize the debounced function to prevent recreation on each render
96+
// const debouncedFetchSuggestions = useMemo(
97+
// () =>
98+
// debounce(async (value: string) => {
99+
// console.log('debounced fetch running for:', value);
100+
// if (value === '') {
101+
// setOptions([]);
102+
// setOpen(false);
103+
// } else {
104+
// setSearchUserLoading(true);
105+
// const suggestions = await fetchSuggestions(value);
106+
// console.log("suggestions",suggestions)
107+
// setOptions(suggestions);
108+
// setSearchUserLoading(false);
109+
// setError(false);
110+
// setOpen(true);
111+
// }
112+
// }, 300),
113+
// [fetchSuggestions]
114+
// );
106115

107-
// Clean up debounce on unmount
108-
useEffect(() => {
109-
return () => {
110-
debouncedFetchSuggestions.cancel();
111-
};
112-
}, [debouncedFetchSuggestions]);
116+
// // Clean up debounce on unmount
117+
// useEffect(() => {
118+
// return () => {
119+
// debouncedFetchSuggestions.cancel();
120+
// };
121+
// }, [debouncedFetchSuggestions]);
113122

114123
// Handler for input changes
115124
const handleInputChange = (event: React.SyntheticEvent, value: string, reason: string) => {
116125
// Only process actual typing events, not clearing or blurring
117126
if (reason === 'input') {
118-
console.log('input change:', value);
119127
setInputValue(value);
120-
debouncedFetchSuggestions(value);
128+
// debouncedFetchSuggestions(value);
121129
} else if (reason === 'clear') {
122130
setInputValue('');
123-
setOptions([]);
131+
// setOptions([]);
124132
}
125133
};
126134

127-
const filteredOptions = options.filter(
128-
(option) => !usersToShareWith.concat(usersData).find((u) => u.id === option.id)
135+
const filteredOptions = suggestions.filter(
136+
(option) => !usersToShareWith.concat(usersData).find((u) => u.email === option.email)
129137
);
130138

139+
131140
const isShareDisabled = disabled || isSharing || usersToShareWith.length === 0;
132141

133142
const UserChip = ({ avatarObj, ...props }: { avatarObj: User }) => (
@@ -171,7 +180,7 @@ const UserShareSearch: React.FC<UserSearchFieldProps> = ({
171180
noOptionsText={searchUserLoading ? 'Loading...' : 'No users found'}
172181
onChange={handleAdd}
173182
onInputChange={handleInputChange}
174-
isOptionEqualToValue={(option, value) => option.id === value.id}
183+
isOptionEqualToValue={(option, value) => option.email === value.email}
175184
renderInput={(params) => (
176185
<TextField
177186
{...params}

0 commit comments

Comments
 (0)