Skip to content

Commit

Permalink
feat: Show Profile info in join requests (#999)
Browse files Browse the repository at this point in the history
Added React Query Profiles query
Added batshit for batching queries
Added helper hooks
  • Loading branch information
alexrisch committed Oct 22, 2024
1 parent 5c73e65 commit 182fad5
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 13 deletions.
4 changes: 2 additions & 2 deletions components/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { Indicator } from "./Indicator";
import Picto from "./Picto/Picto";

type Props = {
export type AvatarProps = {
uri?: string | undefined;
size?: number | undefined;
style?: StyleProp<ImageStyle>;
Expand All @@ -36,7 +36,7 @@ function Avatar({
name,
showIndicator,
invertColor,
}: Props) {
}: AvatarProps) {
const colorScheme = useColorScheme();
const styles = getStyles(colorScheme, size, invertColor || false);
const firstLetter = getFirstLetterForAvatar(name || "");
Expand Down
18 changes: 8 additions & 10 deletions containers/GroupPendingRequestsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { showActionSheetWithOptions } from "@components/StateHandlers/ActionSheetStateHandler";
import { TableViewPicto } from "@components/TableView/TableViewImage";
import { useCurrentAccount, useProfilesStore } from "@data/store/accountsStore";
import { useCurrentAccount } from "@data/store/accountsStore";
import { useGroupPendingRequests } from "@hooks/useGroupPendingRequests";
import { usePreferredNames } from "@hooks/usePreferredNames";
import { translate } from "@i18n";
import { useAddToGroupMutation } from "@queries/useAddToGroupMutation";
import { invalidatePendingJoinRequestsQuery } from "@queries/usePendingRequestsQuery";
import { actionSheetColors, textSecondaryColor } from "@styles/colors";
import { updateGroupJoinRequestStatus } from "@utils/api";
import { getPreferredName, getProfile } from "@utils/profile";
import { FC, useMemo } from "react";
import { StyleSheet, Text, useColorScheme, View } from "react-native";

Expand All @@ -26,20 +26,18 @@ export const GroupPendingRequestsTable: FC<GroupPendingRequestsTableProps> = ({
const currentAccount = useCurrentAccount() as string;
const styles = useStyles();
const requests = useGroupPendingRequests(topic);
const profiles = useProfilesStore((s) => s.profiles);
const addresses = useMemo(() => requests.map((a) => a[0]), [requests]);
const preferredNames = usePreferredNames(addresses);
const { mutateAsync: addToGroup } = useAddToGroupMutation(
currentAccount,
topic
);
const tableViewItems = useMemo(() => {
const items: TableViewItemType[] = [];
requests.forEach((a) => {
requests.forEach((a, id) => {
const address = a[0];
const request = a[1];
const preferredName = getPreferredName(
getProfile(address, profiles)?.socials,
address
);
const preferredName = preferredNames[id];
items.push({
id: address,
title: preferredName,
Expand Down Expand Up @@ -101,7 +99,7 @@ export const GroupPendingRequestsTable: FC<GroupPendingRequestsTableProps> = ({
addToGroup,
colorScheme,
currentAccount,
profiles,
preferredNames,
requests,
styles.adminText,
styles.tableViewRight,
Expand All @@ -114,7 +112,7 @@ export const GroupPendingRequestsTable: FC<GroupPendingRequestsTableProps> = ({
return (
<TableView
items={tableViewItems}
title={translate("pending_approval_title")}
title={translate("membership_requests_title")}
/>
);
};
Expand Down
8 changes: 8 additions & 0 deletions hooks/usePreferredName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { getPreferredName } from "@utils/profile";

import { useProfileSocials } from "./useProfileSocials";

export const usePreferredName = (peerAddress: string) => {
const { data } = useProfileSocials(peerAddress);
return data ? getPreferredName(data, peerAddress) : peerAddress;
};
22 changes: 22 additions & 0 deletions hooks/usePreferredNames.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getPreferredName } from "@utils/profile";
import { useMemo } from "react";

import { useProfilesSocials } from "./useProfilesSocials";

/**
*
* @param peerAddress Multiple peer addresses to get their socials
* @returns array of preferred names or the address if not found
*/
export const usePreferredNames = (peerAddresses: string[]) => {
const data = useProfilesSocials(peerAddresses);
const names = useMemo(() => {
// Not sure how performant this will be, or if we can safely rely on the index
// If we can't, we should probably use a Map instead
return data.map(({ data: socials }, index) => {
const peerAddress = peerAddresses[index];
return socials ? getPreferredName(socials, peerAddress) : peerAddress;
});
}, [data, peerAddresses]);
return names;
};
7 changes: 7 additions & 0 deletions hooks/useProfileSocials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useCurrentAccount } from "@data/store/accountsStore";
import { useProfileSocialsQuery } from "@queries/useProfileSocialsQuery";

export const useProfileSocials = (peerAddress: string) => {
const currentAccount = useCurrentAccount();
return useProfileSocialsQuery(currentAccount!, peerAddress);
};
12 changes: 12 additions & 0 deletions hooks/useProfilesSocials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useCurrentAccount } from "@data/store/accountsStore";
import { useProfileSocialsQueries } from "@queries/useProfileSocialsQuery";

/**
*
* @param peerAddresses Use multiple peer addresses to get their socials
* @returns
*/
export const useProfilesSocials = (peerAddresses: string[]) => {
const currentAccount = useCurrentAccount();
return useProfileSocialsQueries(currentAccount!, peerAddresses);
};
2 changes: 1 addition & 1 deletion i18n/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ const en = {
remove_group: "Remove group",
actions_title: "ACTIONS",
members_title: "MEMBERS",
pending_approval_title: "PENDING APPROVAL",
membership_requests_title: "MEMBERSHIP REQUESTS",
group_invite_link_created_copied: "Invite link created and copied!",
group_invite_link_copied: "Invite link copied!",
group_invite_link_deleted: "Invite link deleted!",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@xmtp/proto": "^3.60.0",
"@xmtp/react-native-sdk": "^2.6.4",
"@xmtp/xmtp-js": "11.5.0",
"@yornaath/batshit": "^0.10.1",
"amazon-cognito-identity-js": "^6.3.12",
"axios": "^1.2.1",
"babel-plugin-transform-remove-console": "^6.9.4",
Expand Down
89 changes: 89 additions & 0 deletions queries/useProfileSocialsQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { ProfileSocials } from "@data/store/profilesStore";
import { useQueries, useQuery } from "@tanstack/react-query";
import { getProfilesForAddresses } from "@utils/api";
import {
create,
windowedFiniteBatchScheduler,
indexedResolver,
} from "@yornaath/batshit";

import { queryClient } from "./queryClient";

const profileSocialsQueryKey = (account: string, peerAddress: string) => [
"profileSocials",
account,
peerAddress,
];

const profileSocials = create({
fetcher: async (addresses: string[]) => {
const data = await getProfilesForAddresses(addresses);
return data;
},
resolver: indexedResolver(),
scheduler: windowedFiniteBatchScheduler({
windowMs: 10,
maxBatchSize: 150,
}),
});

const fetchProfileSocials = async (peerAddress: string) => {
const data = await profileSocials.fetch(peerAddress);
return data;
};

const profileSocialesQueryConfig = (account: string, peerAddress: string) => ({
queryKey: profileSocialsQueryKey(account, peerAddress),
queryFn: () => fetchProfileSocials(peerAddress),
enabled: !!account,
// Store for 30 days
gcTime: 1000 * 60 * 60 * 24 * 30,
refetchIntervalInBackground: false,
refetchOnWindowFocus: false,
// We really just want a 24 hour cache here
// And automatic retries if there was an error fetching
refetchOnMount: false,
staleTime: 1000 * 60 * 60 * 24,
});

export const useProfileSocialsQuery = (
account: string,
peerAddress: string
) => {
return useQuery(profileSocialesQueryConfig(account, peerAddress));
};

export const useProfileSocialsQueries = (
account: string,
peerAddresses: string[]
) => {
return useQueries({
queries: peerAddresses.map((peerAddress) =>
profileSocialesQueryConfig(account, peerAddress)
),
});
};

export const fetchProfileSocialsQuery = (
account: string,
peerAddress: string
) => {
return queryClient.fetchQuery(
profileSocialesQueryConfig(account, peerAddress)
);
};

export const setProfileSocialsQueryData = (
account: string,
peerAddress: string,
data: ProfileSocials,
updatedAt?: number
) => {
return queryClient.setQueryData(
profileSocialsQueryKey(account, peerAddress),
data,
{
updatedAt,
}
);
};
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9834,6 +9834,18 @@
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==

"@yornaath/batshit-devtools@^1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@yornaath/batshit-devtools/-/batshit-devtools-1.7.1.tgz#6c247f2c4c4e3322811beca96cb62bbf19489e04"
integrity sha512-AyttV1Njj5ug+XqEWY1smV45dTWMlWKtj1B8jcFYgBKUFyUlF/qEhD+iP1E5UaRYW6hQRYD9T2WNDwFTrOMWzQ==

"@yornaath/batshit@^0.10.1":
version "0.10.1"
resolved "https://registry.yarnpkg.com/@yornaath/batshit/-/batshit-0.10.1.tgz#f750b2bf6abb9207330eb6a5ab2356af9b79ae78"
integrity sha512-WGZ1WNoiVN6CLf28O73+6SCf+2lUn4U7TLGM9f4zOad0pn9mdoXIq8cwu3Kpf7N2OTYgWGK4eQPTflwFlduDGA==
dependencies:
"@yornaath/batshit-devtools" "^1.7.1"

"@zxing/[email protected]":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b"
Expand Down

0 comments on commit 182fad5

Please sign in to comment.