diff --git a/components/EditProfilePage/EditProfilePage.tsx b/components/EditProfilePage/EditProfilePage.tsx index 2f4d845b6..b83b1b750 100644 --- a/components/EditProfilePage/EditProfilePage.tsx +++ b/components/EditProfilePage/EditProfilePage.tsx @@ -27,8 +27,9 @@ import { TestimoniesTab } from "./TestimoniesTab" import { useFlags } from "components/featureFlags" import LoginPage from "components/Login/Login" import { PendingUpgradeBanner } from "components/PendingUpgradeBanner" +import { FollowersTab } from "./FollowersTab" -const tabTitle = ["about-you", "testimonies", "following"] as const +const tabTitle = ["about-you", "testimonies", "following", "followers"] as const export type TabTitles = (typeof tabTitle)[number] export default function EditProfile({ @@ -115,6 +116,7 @@ export function EditProfileForm({ isOrg = isOrg || isPendingUpgrade const { t } = useTranslation("editProfile") + const [followerCount, setFollowerCount] = useState(null) const tabs = [ { @@ -147,6 +149,18 @@ export function EditProfileForm({ title: t("tabs.following"), eventKey: "following", content: + }, + { + title: followerCount + ? t("tabs.followersWithCount", { count: followerCount }) + : t("tabs.followers"), + eventKey: "followers", + content: ( + + ) } ] @@ -174,9 +188,7 @@ export function EditProfileForm({ > {tabs.map((t, i) => ( - <> - - + ))} diff --git a/components/EditProfilePage/FollowersTab.tsx b/components/EditProfilePage/FollowersTab.tsx new file mode 100644 index 000000000..8774d74c8 --- /dev/null +++ b/components/EditProfilePage/FollowersTab.tsx @@ -0,0 +1,109 @@ +import { functions } from "components/firebase" +import { httpsCallable } from "firebase/functions" +import { useTranslation } from "next-i18next" +import { Dispatch, ReactNode, SetStateAction, useEffect, useState } from "react" +import { useAuth } from "../auth" +import { Profile, usePublicProfile } from "components/db" +import { Internal } from "components/links" +import { FollowUserButton } from "components/shared/FollowButton" +import React from "react" +import { Col, Row, Spinner, Stack, Alert } from "../bootstrap" +import { TitledSectionCard } from "../shared" +import { OrgIconSmall } from "./StyledEditProfileComponents" + +type ProfileWithId = Profile & { profileId: string } + +export const FollowersTab = ({ + className, + setFollowerCount +}: { + className?: string + setFollowerCount: Dispatch> +}) => { + const uid = useAuth().user?.uid + const [followers, setFollowers] = useState([]) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const { t } = useTranslation("editProfile") + + useEffect(() => { + const fetchFollowers = async () => { + try { + const { data: followerIds } = await httpsCallable< + void, + ProfileWithId[] + >(functions, "getFollowers")() + setFollowers(followerIds) + setFollowerCount(followerIds.length) + setLoading(false) + } catch (err) { + console.error("Error fetching followerIds", err) + setError("Error fetching followers.") + setLoading(false) + return + } + } + if (uid) fetchFollowers() + }, [uid]) + return ( + +
+ +

{t("follow.your_followers")}

+

+ {t("follow.follower_info_disclaimer")} +

+
+ {error ? ( + {error} + ) : loading ? ( + + ) : ( + followers.map((profile, i) => ( + + )) + )} +
+
+
+
+ ) +} + +const FollowerCard = ({ + profileId, + fullName, + profileImage, + public: isPublic +}: ProfileWithId) => { + const { t } = useTranslation("profile") + const displayName = isPublic && fullName ? fullName : t("anonymousUser") + return ( +
+ + + + {isPublic ? ( + {displayName} + ) : ( + {displayName} + )} + + {isPublic ? ( + + + + ) : ( + <> + )} + +
+
+ ) +} diff --git a/components/EditProfilePage/StyledEditProfileComponents.tsx b/components/EditProfilePage/StyledEditProfileComponents.tsx index e63fc5d67..f4c8cc75b 100644 --- a/components/EditProfilePage/StyledEditProfileComponents.tsx +++ b/components/EditProfilePage/StyledEditProfileComponents.tsx @@ -42,7 +42,7 @@ export const StyledTabNav = styled(Nav).attrs(props => ({ export const TabNavWrapper = ({ children, className, ...props }: NavProps) => { return (