Follow and unfollow folds

This commit is contained in:
jahooma 2022-01-26 14:03:32 -06:00
parent c3f49c44a0
commit 76841e53b1
6 changed files with 110 additions and 6 deletions

View File

@ -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;
}
}
}

View File

@ -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 (
<button className={clsx('btn btn-sm invisible', className)}>
Follow
</button>
)
if (following) {
return (
<button
className={clsx(
'btn btn-primary btn-sm hover:bg-red-500 hover:border-red-500',
className
)}
onClick={onUnfollow}
>
Following
</button>
)
}
return (
<button
className={clsx('btn btn-secondary bg-indigo-500 btn-sm', className)}
onClick={onFollow}
>
Follow
</button>
)
}

View File

@ -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<Fold | null | undefined>()
@ -21,3 +26,13 @@ export const useFolds = () => {
return folds
}
export const useFollowingFold = (fold: Fold, user: User | null | undefined) => {
const [following, setFollowing] = useState<boolean | undefined>()
useEffect(() => {
if (user) return listenForFollow(fold, user, setFollowing)
}, [fold, user])
return following
}

View File

@ -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)
})
}

View File

@ -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: {
<Page wide>
<Row className="justify-between mb-6 px-1">
<Title className="!m-0" text={fold.name} />
{isCurator && <EditFoldButton className="ml-1" fold={fold} />}
{isCurator ? (
<EditFoldButton className="ml-1" fold={fold} />
) : (
<FollowFoldButton className="ml-1" fold={fold} />
)}
</Row>
<Col className="md:hidden text-gray-500 gap-2 mb-6 px-1">

View File

@ -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: {
</Link>
<Row className="justify-between items-center gap-2">
<SiteLink href={foldPath(fold)}>{fold.name}</SiteLink>
<button className="btn btn-secondary btn-sm z-10 mb-1">
Follow
</button>
<FollowFoldButton className="z-10 mb-1" fold={fold} />
</Row>
<Row className="items-center gap-2 text-gray-500 text-sm">
<div>12 followers</div>