Improve Customize UI
This commit is contained in:
parent
438c12da57
commit
1fbadf8181
|
@ -1,14 +1,22 @@
|
|||
import clsx from 'clsx'
|
||||
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
|
||||
import { MenuIcon } from '@heroicons/react/solid'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { Subtitle } from 'web/components/subtitle'
|
||||
import { keyBy } from 'lodash'
|
||||
import { XCircleIcon } from '@heroicons/react/outline'
|
||||
import { Button } from './button'
|
||||
import { updateUser } from 'web/lib/firebase/users'
|
||||
import { leaveGroup } from 'web/lib/firebase/groups'
|
||||
import { User } from 'common/user'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { Group } from 'common/group'
|
||||
|
||||
export function ArrangeHome(props: {
|
||||
sections: { label: string; id: string }[]
|
||||
sections: { label: string; id: string; group?: Group }[]
|
||||
setSectionIds: (sections: string[]) => void
|
||||
}) {
|
||||
const { sections, setSectionIds } = props
|
||||
|
@ -40,8 +48,9 @@ export function ArrangeHome(props: {
|
|||
|
||||
function DraggableList(props: {
|
||||
title: string
|
||||
items: { id: string; label: string }[]
|
||||
items: { id: string; label: string; group?: Group }[]
|
||||
}) {
|
||||
const user = useUser()
|
||||
const { title, items } = props
|
||||
return (
|
||||
<Droppable droppableId={title.toLowerCase()}>
|
||||
|
@ -66,6 +75,7 @@ function DraggableList(props: {
|
|||
snapshot.isDragging && 'z-[9000] bg-gray-200'
|
||||
)}
|
||||
item={item}
|
||||
user={user}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -79,23 +89,52 @@ function DraggableList(props: {
|
|||
}
|
||||
|
||||
const SectionItem = (props: {
|
||||
item: { id: string; label: string }
|
||||
item: { id: string; label: string; group?: Group }
|
||||
user: User | null | undefined
|
||||
className?: string
|
||||
}) => {
|
||||
const { item, className } = props
|
||||
const { item, user, className } = props
|
||||
const { group } = item
|
||||
|
||||
return (
|
||||
<div
|
||||
<Row
|
||||
className={clsx(
|
||||
className,
|
||||
'flex flex-row items-center gap-4 rounded bg-gray-50 p-2'
|
||||
'items-center justify-between gap-4 rounded bg-gray-50 p-2'
|
||||
)}
|
||||
>
|
||||
<Row className="items-center gap-4">
|
||||
<MenuIcon
|
||||
className="h-5 w-5 flex-shrink-0 text-gray-500"
|
||||
aria-hidden="true"
|
||||
/>{' '}
|
||||
{item.label}
|
||||
</div>
|
||||
</Row>
|
||||
|
||||
{group && (
|
||||
<Button
|
||||
color="gray-white"
|
||||
onClick={() => {
|
||||
if (user) {
|
||||
const homeSections = (user.homeSections ?? []).filter(
|
||||
(id) => id !== group.id
|
||||
)
|
||||
updateUser(user.id, { homeSections })
|
||||
|
||||
toast.promise(leaveGroup(group, user.id), {
|
||||
loading: 'Unfollowing group...',
|
||||
success: `Unfollowed ${group.name}`,
|
||||
error: "Couldn't unfollow group, try again?",
|
||||
})
|
||||
}
|
||||
}}
|
||||
>
|
||||
<XCircleIcon
|
||||
className={clsx('h-5 w-5 flex-shrink-0')}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</Button>
|
||||
)}
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'
|
|||
import { Group } from 'common/group'
|
||||
import { User } from 'common/user'
|
||||
import {
|
||||
getGroup,
|
||||
getMemberGroups,
|
||||
GroupMemberDoc,
|
||||
groupMembers,
|
||||
|
@ -102,6 +103,21 @@ export const useMemberGroupIds = (user: User | null | undefined) => {
|
|||
return memberGroupIds
|
||||
}
|
||||
|
||||
export function useMemberGroupsSubscription(user: User | null | undefined) {
|
||||
const cachedGroups = useMemberGroups(user?.id) ?? []
|
||||
const groupIds = useMemberGroupIds(user)
|
||||
const [groups, setGroups] = useState(cachedGroups)
|
||||
|
||||
useEffect(() => {
|
||||
if (groupIds) {
|
||||
Promise.all(groupIds.map((id) => getGroup(id))).then((groups) =>
|
||||
setGroups(filterDefined(groups))
|
||||
)
|
||||
}
|
||||
}, [groupIds])
|
||||
return groups
|
||||
}
|
||||
|
||||
export function useMembers(groupId: string | undefined) {
|
||||
const [members, setMembers] = useState<User[]>([])
|
||||
useEffect(() => {
|
||||
|
|
|
@ -7,12 +7,12 @@ import { Row } from 'web/components/layout/row'
|
|||
import { Page } from 'web/components/page'
|
||||
import { SiteLink } from 'web/components/site-link'
|
||||
import { Title } from 'web/components/title'
|
||||
import { useMemberGroups } from 'web/hooks/use-group'
|
||||
import { useMemberGroupsSubscription } from 'web/hooks/use-group'
|
||||
import { useTracking } from 'web/hooks/use-tracking'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { updateUser } from 'web/lib/firebase/users'
|
||||
import { track } from 'web/lib/service/analytics'
|
||||
import { getHomeItems } from '.'
|
||||
import { getHomeItems, TrendingGroupsSection } from '.'
|
||||
|
||||
export default function Home() {
|
||||
const user = useUser()
|
||||
|
@ -27,7 +27,7 @@ export default function Home() {
|
|||
setHomeSections(newHomeSections)
|
||||
}
|
||||
|
||||
const groups = useMemberGroups(user?.id) ?? []
|
||||
const groups = useMemberGroupsSubscription(user)
|
||||
const { sections } = getHomeItems(groups, homeSections)
|
||||
|
||||
return (
|
||||
|
@ -38,7 +38,15 @@ export default function Home() {
|
|||
<DoneButton />
|
||||
</Row>
|
||||
|
||||
<ArrangeHome sections={sections} setSectionIds={updateHomeSections} />
|
||||
<Col className="gap-8 md:flex-row">
|
||||
<Col className="flex-1">
|
||||
<ArrangeHome
|
||||
sections={sections}
|
||||
setSectionIds={updateHomeSections}
|
||||
/>
|
||||
</Col>
|
||||
<TrendingGroupsSection className="flex-1" user={user} full />
|
||||
</Col>
|
||||
</Col>
|
||||
</Page>
|
||||
)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { ReactNode, useEffect, useState } from 'react'
|
||||
import React, { ReactNode } from 'react'
|
||||
import Router from 'next/router'
|
||||
import {
|
||||
AdjustmentsIcon,
|
||||
|
@ -22,18 +22,13 @@ import { SiteLink } from 'web/components/site-link'
|
|||
import { usePrivateUser, useUser } from 'web/hooks/use-user'
|
||||
import {
|
||||
useMemberGroupIds,
|
||||
useMemberGroups,
|
||||
useMemberGroupsSubscription,
|
||||
useTrendingGroups,
|
||||
} from 'web/hooks/use-group'
|
||||
import { Button } from 'web/components/button'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { ProbChangeTable } from 'web/components/contract/prob-change-table'
|
||||
import {
|
||||
getGroup,
|
||||
groupPath,
|
||||
joinGroup,
|
||||
leaveGroup,
|
||||
} from 'web/lib/firebase/groups'
|
||||
import { groupPath, joinGroup, leaveGroup } from 'web/lib/firebase/groups'
|
||||
import { usePortfolioHistory } from 'web/hooks/use-portfolio-history'
|
||||
import { formatMoney } from 'common/util/format'
|
||||
import { useProbChanges } from 'web/hooks/use-prob-changes'
|
||||
|
@ -57,17 +52,7 @@ export default function Home() {
|
|||
useSaveReferral()
|
||||
usePrefetch(user?.id)
|
||||
|
||||
const cachedGroups = useMemberGroups(user?.id) ?? []
|
||||
const groupIds = useMemberGroupIds(user)
|
||||
const [groups, setGroups] = useState(cachedGroups)
|
||||
|
||||
useEffect(() => {
|
||||
if (groupIds) {
|
||||
Promise.all(groupIds.map((id) => getGroup(id))).then((groups) =>
|
||||
setGroups(filterDefined(groups))
|
||||
)
|
||||
}
|
||||
}, [groupIds])
|
||||
const groups = useMemberGroupsSubscription(user)
|
||||
|
||||
const { sections } = getHomeItems(groups, user?.homeSections ?? [])
|
||||
|
||||
|
@ -77,7 +62,10 @@ export default function Home() {
|
|||
|
||||
<Col className="pm:mx-10 gap-4 px-4 pb-12 pt-4 sm:pt-0">
|
||||
<Row className={'mb-2 w-full items-center justify-between gap-8'}>
|
||||
<Row className="items-center gap-2">
|
||||
<Title className="!mt-0 !mb-0" text="Home" />
|
||||
<CustomizeButton justIcon />
|
||||
</Row>
|
||||
<DailyStats user={user} />
|
||||
</Row>
|
||||
|
||||
|
@ -110,11 +98,12 @@ export const getHomeItems = (groups: Group[], sections: string[]) => {
|
|||
// Accommodate old home sections.
|
||||
if (!isArray(sections)) sections = []
|
||||
|
||||
const items = [
|
||||
const items: { id: string; label: string; group?: Group }[] = [
|
||||
...HOME_SECTIONS,
|
||||
...groups.map((g) => ({
|
||||
label: g.name,
|
||||
id: g.id,
|
||||
group: g,
|
||||
})),
|
||||
]
|
||||
const itemsById = keyBy(items, 'id')
|
||||
|
@ -225,7 +214,6 @@ function GroupSection(props: {
|
|||
<Col>
|
||||
<SectionHeader label={group.name} href={groupPath(group.slug)}>
|
||||
<Button
|
||||
className=""
|
||||
color="gray-white"
|
||||
onClick={() => {
|
||||
if (user) {
|
||||
|
@ -312,20 +300,24 @@ function DailyStats(props: {
|
|||
)
|
||||
}
|
||||
|
||||
function TrendingGroupsSection(props: { user: User | null | undefined }) {
|
||||
const { user } = props
|
||||
export function TrendingGroupsSection(props: {
|
||||
user: User | null | undefined
|
||||
full?: boolean
|
||||
className?: string
|
||||
}) {
|
||||
const { user, full, className } = props
|
||||
const memberGroupIds = useMemberGroupIds(user) || []
|
||||
|
||||
const groups = useTrendingGroups().filter(
|
||||
(g) => !memberGroupIds.includes(g.id)
|
||||
)
|
||||
const count = 25
|
||||
const count = full ? 100 : 25
|
||||
const chosenGroups = groups.slice(0, count)
|
||||
|
||||
return (
|
||||
<Col>
|
||||
<Col className={className}>
|
||||
<SectionHeader label="Trending groups" href="/explore-groups">
|
||||
<CustomizeButton />
|
||||
{!full && <CustomizeButton className="mb-1" />}
|
||||
</SectionHeader>
|
||||
<Row className="flex-wrap gap-2">
|
||||
{chosenGroups.map((g) => (
|
||||
|
@ -359,10 +351,14 @@ function TrendingGroupsSection(props: { user: User | null | undefined }) {
|
|||
)
|
||||
}
|
||||
|
||||
function CustomizeButton() {
|
||||
function CustomizeButton(props: { justIcon?: boolean; className?: string }) {
|
||||
const { justIcon, className } = props
|
||||
return (
|
||||
<SiteLink
|
||||
className="mb-2 flex flex-row items-center text-xl hover:no-underline"
|
||||
className={clsx(
|
||||
className,
|
||||
'flex flex-row items-center text-xl hover:no-underline'
|
||||
)}
|
||||
href="/home/edit"
|
||||
>
|
||||
<Button size="lg" color="gray" className={clsx('flex gap-2')}>
|
||||
|
@ -370,7 +366,7 @@ function CustomizeButton() {
|
|||
className={clsx('h-[24px] w-5 text-gray-500')}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Customize
|
||||
{!justIcon && 'Customize'}
|
||||
</Button>
|
||||
</SiteLink>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user