diff --git a/firestore.rules b/firestore.rules
index 894367a6..d52569cd 100644
--- a/firestore.rules
+++ b/firestore.rules
@@ -47,5 +47,10 @@ service cloud.firestore {
allow read;
allow update: if request.auth.uid == resource.data.curatorId;
}
+
+ match /folds/{foldId}/followers/{userId} {
+ allow read;
+ allow write: if request.auth.uid == userId;
+ }
}
}
\ No newline at end of file
diff --git a/web/components/follow-fold-button.tsx b/web/components/follow-fold-button.tsx
new file mode 100644
index 00000000..97e29deb
--- /dev/null
+++ b/web/components/follow-fold-button.tsx
@@ -0,0 +1,50 @@
+import clsx from 'clsx'
+import { Fold } from '../../common/fold'
+import { useFollowingFold } from '../hooks/use-fold'
+import { useUser } from '../hooks/use-user'
+import { followFold, unfollowFold } from '../lib/firebase/folds'
+
+export function FollowFoldButton(props: { fold: Fold; className?: string }) {
+ const { fold, className } = props
+
+ const user = useUser()
+ const following = useFollowingFold(fold, user)
+
+ const onFollow = () => {
+ if (user) followFold(fold, user)
+ }
+
+ const onUnfollow = () => {
+ if (user) unfollowFold(fold, user)
+ }
+
+ if (!user || following === undefined)
+ return (
+
+ )
+
+ if (following) {
+ return (
+
+ )
+ }
+
+ return (
+
+ )
+}
diff --git a/web/hooks/use-fold.ts b/web/hooks/use-fold.ts
index f64694df..8caa58d2 100644
--- a/web/hooks/use-fold.ts
+++ b/web/hooks/use-fold.ts
@@ -1,6 +1,11 @@
import { useEffect, useState } from 'react'
import { Fold } from '../../common/fold'
-import { listenForFold, listenForFolds } from '../lib/firebase/folds'
+import { User } from '../../common/user'
+import {
+ listenForFold,
+ listenForFolds,
+ listenForFollow,
+} from '../lib/firebase/folds'
export const useFold = (foldId: string) => {
const [fold, setFold] = useState()
@@ -21,3 +26,13 @@ export const useFolds = () => {
return folds
}
+
+export const useFollowingFold = (fold: Fold, user: User | null | undefined) => {
+ const [following, setFollowing] = useState()
+
+ useEffect(() => {
+ if (user) return listenForFollow(fold, user, setFollowing)
+ }, [fold, user])
+
+ return following
+}
diff --git a/web/lib/firebase/folds.ts b/web/lib/firebase/folds.ts
index 3220f884..63d67806 100644
--- a/web/lib/firebase/folds.ts
+++ b/web/lib/firebase/folds.ts
@@ -1,7 +1,16 @@
-import { collection, doc, query, updateDoc, where } from 'firebase/firestore'
+import {
+ collection,
+ deleteDoc,
+ doc,
+ query,
+ setDoc,
+ updateDoc,
+ where,
+} from 'firebase/firestore'
import { Fold } from '../../../common/fold'
import { Contract, contractCollection } from './contracts'
import { db } from './init'
+import { User } from './users'
import { getValues, listenForValue, listenForValues } from './utils'
const foldCollection = collection(db, 'folds')
@@ -90,3 +99,24 @@ export function listenForFold(
) {
return listenForValue(doc(foldCollection, foldId), setFold)
}
+
+export function followFold(fold: Fold, user: User) {
+ const followDoc = doc(foldCollection, fold.id, 'followers', user.id)
+ return setDoc(followDoc, { userId: user.id })
+}
+
+export function unfollowFold(fold: Fold, user: User) {
+ const followDoc = doc(foldCollection, fold.id, 'followers', user.id)
+ return deleteDoc(followDoc)
+}
+
+export function listenForFollow(
+ fold: Fold,
+ user: User,
+ setFollow: (following: boolean) => void
+) {
+ const followDoc = doc(foldCollection, fold.id, 'followers', user.id)
+ return listenForValue(followDoc, (value) => {
+ setFollow(!!value)
+ })
+}
diff --git a/web/pages/fold/[...slugs]/index.tsx b/web/pages/fold/[...slugs]/index.tsx
index 4cdb41ca..885c5987 100644
--- a/web/pages/fold/[...slugs]/index.tsx
+++ b/web/pages/fold/[...slugs]/index.tsx
@@ -31,6 +31,7 @@ import { Leaderboard } from '../../../components/leaderboard'
import { formatMoney } from '../../../lib/util/format'
import { EditFoldButton } from '../../../components/edit-fold-button'
import Custom404 from '../../404'
+import { FollowFoldButton } from '../../../components/follow-fold-button'
export async function getStaticProps(props: { params: { slugs: string[] } }) {
const { slugs } = props.params
@@ -155,7 +156,11 @@ export default function FoldPage(props: {
- {isCurator && }
+ {isCurator ? (
+
+ ) : (
+
+ )}
diff --git a/web/pages/folds.tsx b/web/pages/folds.tsx
index f0706b38..ac240def 100644
--- a/web/pages/folds.tsx
+++ b/web/pages/folds.tsx
@@ -3,6 +3,7 @@ import Link from 'next/link'
import { useEffect, useState } from 'react'
import { Fold } from '../../common/fold'
import { CreateFoldButton } from '../components/create-fold-button'
+import { FollowFoldButton } from '../components/follow-fold-button'
import { Col } from '../components/layout/col'
import { Row } from '../components/layout/row'
import { Page } from '../components/page'
@@ -82,9 +83,7 @@ export default function Folds(props: {
{fold.name}
-
+
12 followers