mirror of
https://github.com/CompassConnections/Compass.git
synced 2025-12-23 22:18:43 -05:00
Cache vote creators
This commit is contained in:
@@ -4,10 +4,9 @@ import {Row as rowFor} from 'common/supabase/utils'
|
||||
import {Content} from 'web/components/widgets/editor'
|
||||
import {JSONContent} from '@tiptap/core'
|
||||
import {VoteButtons} from 'web/components/votes/vote-buttons'
|
||||
import {getVoteCreator} from "web/lib/supabase/votes";
|
||||
import {useEffect, useState} from "react";
|
||||
import Link from "next/link";
|
||||
import {STATUS_CHOICES} from "common/votes/constants";
|
||||
import {useUserInStore} from "web/hooks/use-user-supabase";
|
||||
|
||||
export type Vote = rowFor<'votes'> & {
|
||||
votes_for: number
|
||||
@@ -17,15 +16,22 @@ export type Vote = rowFor<'votes'> & {
|
||||
status?: string
|
||||
}
|
||||
|
||||
function Username(props: {
|
||||
creatorId: string
|
||||
}) {
|
||||
const {creatorId} = props
|
||||
const creator = useUserInStore(creatorId)
|
||||
return <>
|
||||
{creator?.username &&
|
||||
<Link href={`/${creator.username}`} className="custom-link">{creator.username}</Link>}
|
||||
</>;
|
||||
}
|
||||
|
||||
export function VoteItem(props: {
|
||||
vote: Vote
|
||||
onVoted?: () => void | Promise<void>
|
||||
}) {
|
||||
const {vote, onVoted} = props
|
||||
const [creator, setCreator] = useState<any>(null)
|
||||
useEffect(() => {
|
||||
getVoteCreator(vote.creator_id).then(setCreator)
|
||||
}, [vote.creator_id])
|
||||
// console.debug('creator', creator, vote)
|
||||
return (
|
||||
<Col className={'mb-4 rounded-lg border border-canvas-200 p-4'}>
|
||||
@@ -37,8 +43,7 @@ export function VoteItem(props: {
|
||||
</Col>
|
||||
<Row className={'gap-2 mt-2 items-center justify-between w-full custom-link flex-wrap'}>
|
||||
{!!vote.priority ? <div>Priority: {vote.priority.toFixed(0)}%</div> : <p></p>}
|
||||
{!vote.is_anonymous && creator?.username &&
|
||||
<Link href={`/${creator.username}`} className="custom-link">{creator.username}</Link>}
|
||||
{!vote.is_anonymous && <Username creatorId={vote.creator_id}/>}
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEffectCheckEquality } from './use-effect-check-equality'
|
||||
import { uniqBy, uniq } from 'lodash'
|
||||
import { usePersistentLocalState } from 'web/hooks/use-persistent-local-state'
|
||||
import { filterDefined } from 'common/util/array'
|
||||
import { usePersistentInMemoryState } from './use-persistent-in-memory-state'
|
||||
import {
|
||||
DisplayUser,
|
||||
getDisplayUsers,
|
||||
getFullUserById,
|
||||
} from 'web/lib/supabase/users'
|
||||
import { FullUser } from 'common/api/user-types'
|
||||
import {useEffect, useState} from 'react'
|
||||
import {useEffectCheckEquality} from './use-effect-check-equality'
|
||||
import {uniq, uniqBy} from 'lodash'
|
||||
import {usePersistentLocalState} from 'web/hooks/use-persistent-local-state'
|
||||
import {filterDefined} from 'common/util/array'
|
||||
import {usePersistentInMemoryState} from './use-persistent-in-memory-state'
|
||||
import {DisplayUser, getDisplayUsers, getFullUserById,} from 'web/lib/supabase/users'
|
||||
import {FullUser} from 'common/api/user-types'
|
||||
|
||||
export function useUserById(userId: string | undefined) {
|
||||
const [user, setUser] = usePersistentInMemoryState<
|
||||
@@ -25,8 +21,8 @@ export function useUserById(userId: string | undefined) {
|
||||
return user
|
||||
}
|
||||
|
||||
const cache = new Map<string, DisplayUser | null>()
|
||||
|
||||
// const cache = new Map<string, DisplayUser | null>()
|
||||
//
|
||||
// export function useDisplayUserById(userId: string | undefined) {
|
||||
// const [user, setUser] = usePersistentInMemoryState<
|
||||
// DisplayUser | null | undefined
|
||||
@@ -51,45 +47,48 @@ const cache = new Map<string, DisplayUser | null>()
|
||||
// return user
|
||||
// }
|
||||
|
||||
export function useUsers(userIds: string[]) {
|
||||
const [users, setUsers] = useState<(DisplayUser | null)[] | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
const requestIdRef = useRef(0)
|
||||
useEffectCheckEquality(() => {
|
||||
const requestId = ++requestIdRef.current
|
||||
|
||||
const missing = userIds.filter((id) => !cache.has(id))
|
||||
|
||||
getDisplayUsers(missing).then((users) => {
|
||||
users.forEach((user) => {
|
||||
cache.set(user.id, user)
|
||||
})
|
||||
if (requestId !== requestIdRef.current) return
|
||||
setUsers(userIds.map((id) => cache.get(id) ?? null))
|
||||
})
|
||||
}, [userIds])
|
||||
|
||||
return users
|
||||
}
|
||||
// export function useUsers(userIds: string[]) {
|
||||
// const [users, setUsers] = useState<(DisplayUser | null)[] | undefined>(
|
||||
// undefined
|
||||
// )
|
||||
//
|
||||
// const requestIdRef = useRef(0)
|
||||
// useEffectCheckEquality(() => {
|
||||
// const requestId = ++requestIdRef.current
|
||||
//
|
||||
// const missing = userIds.filter((id) => !cache.has(id))
|
||||
//
|
||||
// getDisplayUsers(missing).then((users) => {
|
||||
// users.forEach((user) => {
|
||||
// cache.set(user.id, user)
|
||||
// })
|
||||
// if (requestId !== requestIdRef.current) return
|
||||
// setUsers(userIds.map((id) => cache.get(id) ?? null))
|
||||
// })
|
||||
// }, [userIds])
|
||||
//
|
||||
// return users
|
||||
// }
|
||||
|
||||
// TODO: decide whether in-memory or in-localstorage is better and stick to it
|
||||
|
||||
export function useUsersInStore(
|
||||
userIds: string[],
|
||||
userIds: (string | null)[],
|
||||
key: string,
|
||||
limit?: number
|
||||
) {
|
||||
const validUserIds = Array.from(new Set(userIds.filter((id): id is string => !!id)))
|
||||
|
||||
const [users, setUsers] = usePersistentLocalState<DisplayUser[] | undefined>(
|
||||
undefined,
|
||||
'use-users-in-local-storage' + key
|
||||
'use-users-in-local-storage-' + key
|
||||
)
|
||||
|
||||
// Fetch all users at least once on load.
|
||||
const [userIdsFetched, setUserIdsFetched] = useState<string[]>([])
|
||||
const fetchedSet = new Set(userIdsFetched)
|
||||
const userIdsNotFetched = userIds.filter((id) => !fetchedSet.has(id))
|
||||
|
||||
const userIdsNotFetched = validUserIds.filter((id) => !fetchedSet.has(id))
|
||||
const userIdsToFetch = limit
|
||||
? userIdsNotFetched.slice(0, limit)
|
||||
: userIdsNotFetched
|
||||
@@ -104,5 +103,12 @@ export function useUsersInStore(
|
||||
})
|
||||
}, [userIdsToFetch])
|
||||
|
||||
return users?.filter((user) => userIds.includes(user?.id))
|
||||
return users?.filter((user) => validUserIds.includes(user?.id))
|
||||
}
|
||||
|
||||
export function useUserInStore(userId: string | null) {
|
||||
if (!userId) return null // early return avoids invalid key + hook calls are safe
|
||||
|
||||
const users = useUsersInStore(userId ? [userId] : [], userId ?? 'empty')
|
||||
return users?.[0] ?? null
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import {run} from 'common/supabase/utils'
|
||||
import {db} from 'web/lib/supabase/db'
|
||||
|
||||
import {OrderBy} from "common/votes/constants";
|
||||
|
||||
export const getVotes = async (params: { orderBy: OrderBy }) => {
|
||||
const { orderBy } = params
|
||||
const {orderBy} = params
|
||||
const {data, error} = await db.rpc('get_votes_with_results' as any, {
|
||||
order_by: orderBy,
|
||||
});
|
||||
@@ -12,15 +11,3 @@ export const getVotes = async (params: { orderBy: OrderBy }) => {
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export const getVoteCreator = async (creatorId: string) => {
|
||||
const {data} = await run(
|
||||
db
|
||||
.from('users')
|
||||
.select(`id, name, username`)
|
||||
.eq('id', creatorId)
|
||||
.limit(1)
|
||||
)
|
||||
|
||||
return data[0]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user