group selector dialog (#888)
* group selector dialog * cache groups to prevent ui jumping * welcome dialog display logic * show fewer groups, more filtering
This commit is contained in:
parent
dd2b09830e
commit
f7164ddd7d
|
@ -6,9 +6,10 @@ export function PillButton(props: {
|
||||||
onSelect: () => void
|
onSelect: () => void
|
||||||
color?: string
|
color?: string
|
||||||
xs?: boolean
|
xs?: boolean
|
||||||
|
className?: string
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}) {
|
}) {
|
||||||
const { children, selected, onSelect, color, xs } = props
|
const { children, selected, onSelect, color, xs, className } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
@ -17,7 +18,8 @@ export function PillButton(props: {
|
||||||
xs ? 'text-xs' : '',
|
xs ? 'text-xs' : '',
|
||||||
selected
|
selected
|
||||||
? ['text-white', color ?? 'bg-greyscale-6']
|
? ['text-white', color ?? 'bg-greyscale-6']
|
||||||
: 'bg-greyscale-2 hover:bg-greyscale-3'
|
: 'bg-greyscale-2 hover:bg-greyscale-3',
|
||||||
|
className
|
||||||
)}
|
)}
|
||||||
onClick={onSelect}
|
onClick={onSelect}
|
||||||
>
|
>
|
||||||
|
|
89
web/components/onboarding/group-selector-dialog.tsx
Normal file
89
web/components/onboarding/group-selector-dialog.tsx
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import { sortBy } from 'lodash'
|
||||||
|
import React, { useRef } from 'react'
|
||||||
|
|
||||||
|
import { Col } from 'web/components/layout/col'
|
||||||
|
import { Title } from 'web/components/title'
|
||||||
|
import { useGroups, useMemberGroupIds } from 'web/hooks/use-group'
|
||||||
|
import { joinGroup, leaveGroup } from 'web/lib/firebase/groups'
|
||||||
|
import { useUser } from 'web/hooks/use-user'
|
||||||
|
import { Modal } from 'web/components/layout/modal'
|
||||||
|
import { PillButton } from 'web/components/buttons/pill-button'
|
||||||
|
import { Button } from 'web/components/button'
|
||||||
|
import { Group } from 'common/group'
|
||||||
|
|
||||||
|
export default function GroupSelectorDialog(props: {
|
||||||
|
open: boolean
|
||||||
|
setOpen: (open: boolean) => void
|
||||||
|
}) {
|
||||||
|
const { open, setOpen } = props
|
||||||
|
|
||||||
|
const groups = useGroups()
|
||||||
|
const user = useUser()
|
||||||
|
const memberGroupIds = useMemberGroupIds(user) || []
|
||||||
|
const cachedGroups = useRef<Group[]>()
|
||||||
|
|
||||||
|
if (groups && !cachedGroups.current) {
|
||||||
|
cachedGroups.current = groups
|
||||||
|
}
|
||||||
|
|
||||||
|
const excludedGroups = [
|
||||||
|
'features',
|
||||||
|
'personal',
|
||||||
|
'private',
|
||||||
|
'nomic',
|
||||||
|
'proofnik',
|
||||||
|
'free money',
|
||||||
|
'motivation',
|
||||||
|
'sf events',
|
||||||
|
'please resolve',
|
||||||
|
'short-term',
|
||||||
|
'washifold',
|
||||||
|
]
|
||||||
|
|
||||||
|
const displayedGroups = sortBy(cachedGroups.current ?? [], [
|
||||||
|
(group) => -1 * group.totalMembers,
|
||||||
|
(group) => -1 * group.totalContracts,
|
||||||
|
])
|
||||||
|
.filter((group) => group.anyoneCanJoin)
|
||||||
|
.filter((group) =>
|
||||||
|
excludedGroups.every((name) => !group.name.toLowerCase().includes(name))
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
(group) =>
|
||||||
|
(group.mostRecentContractAddedTime ?? 0) >
|
||||||
|
Date.now() - 1000 * 60 * 60 * 24 * 7
|
||||||
|
)
|
||||||
|
.slice(0, 30)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal open={open} setOpen={setOpen}>
|
||||||
|
<Col className="h-[32rem] rounded-md bg-white px-8 py-6 text-sm font-light md:h-[40rem] md:text-lg">
|
||||||
|
<Title text="What interests you?" />
|
||||||
|
<p className="mb-4">
|
||||||
|
Choose among the categories below to personalize your Manifold
|
||||||
|
experience.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="scrollbar-hide items-start gap-2 overflow-x-auto">
|
||||||
|
{user &&
|
||||||
|
displayedGroups.map((group) => (
|
||||||
|
<PillButton
|
||||||
|
selected={memberGroupIds.includes(group.id)}
|
||||||
|
onSelect={() =>
|
||||||
|
memberGroupIds.includes(group.id)
|
||||||
|
? leaveGroup(group, user.id)
|
||||||
|
: joinGroup(group, user.id)
|
||||||
|
}
|
||||||
|
className="mr-1 mb-2 max-w-[12rem] truncate"
|
||||||
|
>
|
||||||
|
{group.name}
|
||||||
|
</PillButton>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Button onClick={() => setOpen(false)}>Done</Button>
|
||||||
|
</Col>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import { Col } from '../layout/col'
|
||||||
import { Modal } from '../layout/modal'
|
import { Modal } from '../layout/modal'
|
||||||
import { Row } from '../layout/row'
|
import { Row } from '../layout/row'
|
||||||
import { Title } from '../title'
|
import { Title } from '../title'
|
||||||
|
import GroupSelectorDialog from './group-selector-dialog'
|
||||||
|
|
||||||
export default function Welcome() {
|
export default function Welcome() {
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
|
@ -32,17 +33,26 @@ export default function Welcome() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user || !user.shouldShowWelcome) {
|
const [groupSelectorOpen, setGroupSelectorOpen] = useState(false)
|
||||||
return <></>
|
|
||||||
} else
|
if (!user || (!user.shouldShowWelcome && !groupSelectorOpen)) return <></>
|
||||||
return (
|
|
||||||
<Modal
|
const toggleOpen = (isOpen: boolean) => {
|
||||||
open={open}
|
setUserHasSeenWelcome()
|
||||||
setOpen={(newOpen) => {
|
setOpen(isOpen)
|
||||||
setUserHasSeenWelcome()
|
|
||||||
setOpen(newOpen)
|
if (!isOpen) {
|
||||||
}}
|
setGroupSelectorOpen(true)
|
||||||
>
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<GroupSelectorDialog
|
||||||
|
open={groupSelectorOpen}
|
||||||
|
setOpen={() => setGroupSelectorOpen(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Modal open={open} setOpen={toggleOpen}>
|
||||||
<Col className="h-[32rem] place-content-between rounded-md bg-white px-8 py-6 text-sm font-light md:h-[40rem] md:text-lg">
|
<Col className="h-[32rem] place-content-between rounded-md bg-white px-8 py-6 text-sm font-light md:h-[40rem] md:text-lg">
|
||||||
{page === 0 && <Page0 />}
|
{page === 0 && <Page0 />}
|
||||||
{page === 1 && <Page1 />}
|
{page === 1 && <Page1 />}
|
||||||
|
@ -68,17 +78,15 @@ export default function Welcome() {
|
||||||
</Row>
|
</Row>
|
||||||
<u
|
<u
|
||||||
className="self-center text-xs text-gray-500"
|
className="self-center text-xs text-gray-500"
|
||||||
onClick={() => {
|
onClick={() => toggleOpen(false)}
|
||||||
setOpen(false)
|
|
||||||
setUserHasSeenWelcome()
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
I got the gist, exit welcome
|
I got the gist, exit welcome
|
||||||
</u>
|
</u>
|
||||||
</Col>
|
</Col>
|
||||||
</Col>
|
</Col>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function PageIndicator(props: { page: number; totalpages: number }) {
|
function PageIndicator(props: { page: number; totalpages: number }) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user