Allow adding anyone's contract to a group
This commit is contained in:
parent
cb68530e2a
commit
b9931e65da
|
@ -21,11 +21,16 @@ service cloud.firestore {
|
|||
allow update: if resource.data.id == request.auth.uid
|
||||
&& request.resource.data.diff(resource.data).affectedKeys()
|
||||
.hasOnly(['bio', 'bannerUrl', 'website', 'twitterHandle', 'discordHandle', 'followedCategories', 'referredByContractId']);
|
||||
// only one referral allowed per user
|
||||
allow update: if resource.data.id == request.auth.uid
|
||||
&& request.resource.data.diff(resource.data).affectedKeys()
|
||||
.hasOnly(['referredByUserId'])
|
||||
&& !("referredByUserId" in resource.data);
|
||||
// only one referral allowed per user
|
||||
&& !("referredByUserId" in resource.data)
|
||||
// user can't refer themselves
|
||||
&& (resource.data.id != request.resource.data.referredByUserId)
|
||||
// user can't refer someone who referred them quid pro quo
|
||||
&& get(/databases/$(database)/documents/users/$(request.resource.data.referredByUserId)).referredByUserId != resource.data.id;
|
||||
|
||||
}
|
||||
|
||||
match /{somePath=**}/portfolioHistory/{portfolioHistoryId} {
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
useSortBy,
|
||||
} from 'react-instantsearch-hooks-web'
|
||||
|
||||
import { Contract } from '../../common/contract'
|
||||
import { Contract } from 'common/contract'
|
||||
import {
|
||||
Sort,
|
||||
useInitialQueryAndSort,
|
||||
|
@ -58,15 +58,24 @@ export function ContractSearch(props: {
|
|||
additionalFilter?: {
|
||||
creatorId?: string
|
||||
tag?: string
|
||||
excludeContractIds?: string[]
|
||||
}
|
||||
showCategorySelector: boolean
|
||||
onContractClick?: (contract: Contract) => void
|
||||
showPlaceHolder?: boolean
|
||||
hideOrderSelector?: boolean
|
||||
overrideGridClassName?: string
|
||||
hideQuickBet?: boolean
|
||||
}) {
|
||||
const {
|
||||
querySortOptions,
|
||||
additionalFilter,
|
||||
showCategorySelector,
|
||||
onContractClick,
|
||||
overrideGridClassName,
|
||||
hideOrderSelector,
|
||||
showPlaceHolder,
|
||||
hideQuickBet,
|
||||
} = props
|
||||
|
||||
const user = useUser()
|
||||
|
@ -136,6 +145,7 @@ export function ContractSearch(props: {
|
|||
<Row className="gap-1 sm:gap-2">
|
||||
<SearchBox
|
||||
className="flex-1"
|
||||
placeholder={showPlaceHolder ? `Search ${filter} contracts` : ''}
|
||||
classNames={{
|
||||
form: 'before:top-6',
|
||||
input: '!pl-10 !input !input-bordered shadow-none w-[100px]',
|
||||
|
@ -153,6 +163,7 @@ export function ContractSearch(props: {
|
|||
<option value="resolved">Resolved</option>
|
||||
<option value="all">All</option>
|
||||
</select>
|
||||
{!hideOrderSelector && (
|
||||
<SortBy
|
||||
items={sortIndexes}
|
||||
classNames={{
|
||||
|
@ -160,6 +171,7 @@ export function ContractSearch(props: {
|
|||
}}
|
||||
onBlur={trackCallback('select search sort')}
|
||||
/>
|
||||
)}
|
||||
<Configure
|
||||
facetFilters={filters}
|
||||
numericFilters={numericFilters}
|
||||
|
@ -187,6 +199,9 @@ export function ContractSearch(props: {
|
|||
<ContractSearchInner
|
||||
querySortOptions={querySortOptions}
|
||||
onContractClick={onContractClick}
|
||||
overrideGridClassName={overrideGridClassName}
|
||||
hideQuickBet={hideQuickBet}
|
||||
excludeContractIds={additionalFilter?.excludeContractIds}
|
||||
/>
|
||||
)}
|
||||
</InstantSearch>
|
||||
|
@ -199,8 +214,17 @@ export function ContractSearchInner(props: {
|
|||
shouldLoadFromStorage?: boolean
|
||||
}
|
||||
onContractClick?: (contract: Contract) => void
|
||||
overrideGridClassName?: string
|
||||
hideQuickBet?: boolean
|
||||
excludeContractIds?: string[]
|
||||
}) {
|
||||
const { querySortOptions, onContractClick } = props
|
||||
const {
|
||||
querySortOptions,
|
||||
onContractClick,
|
||||
overrideGridClassName,
|
||||
hideQuickBet,
|
||||
excludeContractIds,
|
||||
} = props
|
||||
const { initialQuery } = useInitialQueryAndSort(querySortOptions)
|
||||
|
||||
const { query, setQuery, setSort } = useUpdateQueryAndSort({
|
||||
|
@ -239,7 +263,7 @@ export function ContractSearchInner(props: {
|
|||
}, [])
|
||||
|
||||
const { showMore, hits, isLastPage } = useInfiniteHits()
|
||||
const contracts = hits as any as Contract[]
|
||||
let contracts = hits as any as Contract[]
|
||||
|
||||
if (isInitialLoad && contracts.length === 0) return <></>
|
||||
|
||||
|
@ -249,6 +273,9 @@ export function ContractSearchInner(props: {
|
|||
? 'resolve-date'
|
||||
: undefined
|
||||
|
||||
if (excludeContractIds)
|
||||
contracts = contracts.filter((c) => !excludeContractIds.includes(c.id))
|
||||
|
||||
return (
|
||||
<ContractsGrid
|
||||
contracts={contracts}
|
||||
|
@ -256,6 +283,8 @@ export function ContractSearchInner(props: {
|
|||
hasMore={!isLastPage}
|
||||
showTime={showTime}
|
||||
onContractClick={onContractClick}
|
||||
overrideGridClassName={overrideGridClassName}
|
||||
hideQuickBet={hideQuickBet}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -130,9 +130,32 @@ export function ContractDetails(props: {
|
|||
const { contract, bets, isCreator, disabled } = props
|
||||
const { closeTime, creatorName, creatorUsername, creatorId } = contract
|
||||
const { volumeLabel, resolvedDate } = contractMetrics(contract)
|
||||
// Find a group that this contract id is in
|
||||
const groups = useGroupsWithContract(contract.id)
|
||||
|
||||
const groups = (useGroupsWithContract(contract.id) ?? []).sort((g1, g2) => {
|
||||
return g2.createdTime - g1.createdTime
|
||||
})
|
||||
const user = useUser()
|
||||
|
||||
const groupsUserIsMemberOf = groups
|
||||
? groups.filter((g) => g.memberIds.includes(contract.creatorId))
|
||||
: []
|
||||
const groupsUserIsCreatorOf = groups
|
||||
? groups.filter((g) => g.creatorId === contract.creatorId)
|
||||
: []
|
||||
|
||||
// Priorities for which group the contract belongs to:
|
||||
// In order of created most recently
|
||||
// Group that the contract owner created
|
||||
// Group the contract owner is a member of
|
||||
// Any group the contract is in
|
||||
const groupToDisplay =
|
||||
groupsUserIsCreatorOf.length > 0
|
||||
? groupsUserIsCreatorOf[0]
|
||||
: groupsUserIsMemberOf.length > 0
|
||||
? groupsUserIsMemberOf[0]
|
||||
: groups
|
||||
? groups[0]
|
||||
: undefined
|
||||
return (
|
||||
<Row className="flex-1 flex-wrap items-center gap-x-4 gap-y-2 text-sm text-gray-500">
|
||||
<Row className="items-center gap-2">
|
||||
|
@ -153,14 +176,15 @@ export function ContractDetails(props: {
|
|||
)}
|
||||
{!disabled && <UserFollowButton userId={creatorId} small />}
|
||||
</Row>
|
||||
{/*// TODO: we can add contracts to multiple groups but only show the first it was added to*/}
|
||||
{groups && groups.length > 0 && (
|
||||
{groupToDisplay ? (
|
||||
<Row className={'line-clamp-1 mt-1 max-w-[200px]'}>
|
||||
<SiteLink href={`${groupPath(groups[0].slug)}`}>
|
||||
<SiteLink href={`${groupPath(groupToDisplay.slug)}`}>
|
||||
<UserGroupIcon className="mx-1 mb-1 inline h-5 w-5" />
|
||||
<span>{groups[0].name}</span>
|
||||
<span>{groupToDisplay.name}</span>
|
||||
</SiteLink>
|
||||
</Row>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
|
||||
{(!!closeTime || !!resolvedDate) && (
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useRouter } from 'next/router'
|
|||
import { Modal } from 'web/components/layout/modal'
|
||||
import { FilterSelectUsers } from 'web/components/filter-select-users'
|
||||
import { User } from 'common/user'
|
||||
import { uniq } from 'lodash'
|
||||
|
||||
export function EditGroupButton(props: { group: Group; className?: string }) {
|
||||
const { group, className } = props
|
||||
|
@ -35,7 +36,7 @@ export function EditGroupButton(props: { group: Group; className?: string }) {
|
|||
await updateGroup(group, {
|
||||
name,
|
||||
about,
|
||||
memberIds: [...memberIds, ...addMemberUsers.map((user) => user.id)],
|
||||
memberIds: uniq([...memberIds, ...addMemberUsers.map((user) => user.id)]),
|
||||
})
|
||||
|
||||
setIsSubmitting(false)
|
||||
|
|
|
@ -9,7 +9,7 @@ import { TextButton } from 'web/components/text-button'
|
|||
import { Group } from 'common/group'
|
||||
import { Modal } from 'web/components/layout/modal'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { joinGroup, leaveGroup } from 'web/lib/firebase/groups'
|
||||
import { addUserToGroup, leaveGroup } from 'web/lib/firebase/groups'
|
||||
import { firebaseLogin } from 'web/lib/firebase/users'
|
||||
import { GroupLink } from 'web/pages/groups'
|
||||
|
||||
|
@ -93,7 +93,7 @@ export function JoinOrLeaveGroupButton(props: {
|
|||
: false
|
||||
const onJoinGroup = () => {
|
||||
if (!currentUser) return
|
||||
joinGroup(group, currentUser.id)
|
||||
addUserToGroup(group, currentUser.id)
|
||||
}
|
||||
const onLeaveGroup = () => {
|
||||
if (!currentUser) return
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { Fragment, ReactNode } from 'react'
|
||||
import { Dialog, Transition } from '@headlessui/react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
// From https://tailwindui.com/components/application-ui/overlays/modals
|
||||
export function Modal(props: {
|
||||
children: ReactNode
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
className?: string
|
||||
}) {
|
||||
const { children, open, setOpen } = props
|
||||
const { children, open, setOpen, className } = props
|
||||
|
||||
return (
|
||||
<Transition.Root show={open} as={Fragment}>
|
||||
|
@ -45,7 +47,12 @@ export function Modal(props: {
|
|||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<div className="inline-block transform overflow-hidden text-left align-bottom transition-all sm:my-8 sm:w-full sm:max-w-md sm:p-6 sm:align-middle">
|
||||
<div
|
||||
className={clsx(
|
||||
'inline-block transform overflow-hidden text-left align-bottom transition-all sm:my-8 sm:w-full sm:max-w-md sm:p-6 sm:align-middle',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</Transition.Child>
|
||||
|
|
|
@ -14,17 +14,17 @@ type Tab = {
|
|||
export function Tabs(props: {
|
||||
tabs: Tab[]
|
||||
defaultIndex?: number
|
||||
className?: string
|
||||
labelClassName?: string
|
||||
onClick?: (tabTitle: string, index: number) => void
|
||||
}) {
|
||||
const { tabs, defaultIndex, className, onClick } = props
|
||||
const { tabs, defaultIndex, labelClassName, onClick } = props
|
||||
const [activeIndex, setActiveIndex] = useState(defaultIndex ?? 0)
|
||||
const activeTab = tabs[activeIndex] as Tab | undefined // can be undefined in weird case
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<div className="border-b border-gray-200">
|
||||
<nav className="-mb-px flex space-x-8" aria-label="Tabs">
|
||||
<nav className="-mb-px mb-4 flex space-x-8" aria-label="Tabs">
|
||||
{tabs.map((tab, i) => (
|
||||
<Link href={tab.href ?? '#'} key={tab.title} shallow={!!tab.href}>
|
||||
<a
|
||||
|
@ -42,7 +42,7 @@ export function Tabs(props: {
|
|||
? 'border-indigo-500 text-indigo-600'
|
||||
: 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700',
|
||||
'cursor-pointer whitespace-nowrap border-b-2 py-3 px-1 text-sm font-medium',
|
||||
className
|
||||
labelClassName
|
||||
)}
|
||||
aria-current={activeIndex === i ? 'page' : undefined}
|
||||
>
|
||||
|
@ -56,7 +56,7 @@ export function Tabs(props: {
|
|||
</nav>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">{activeTab?.content}</div>
|
||||
</div>
|
||||
{activeTab?.content}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ function GroupsList(props: { currentPage: string; memberItems: Item[] }) {
|
|||
<div className="mt-1 space-y-0.5">
|
||||
{memberItems.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className="group flex items-center rounded-md px-3 py-2 text-sm font-medium text-gray-600 hover:bg-gray-100 hover:text-gray-900"
|
||||
>
|
||||
|
|
|
@ -258,7 +258,7 @@ export function UserPage(props: {
|
|||
|
||||
{usersContracts !== 'loading' && commentsByContract != 'loading' ? (
|
||||
<Tabs
|
||||
className={'pb-2 pt-1 '}
|
||||
labelClassName={'pb-2 pt-1 '}
|
||||
defaultIndex={
|
||||
defaultTabTitle ? TAB_IDS.indexOf(defaultTabTitle) : 0
|
||||
}
|
||||
|
|
|
@ -74,9 +74,7 @@ export function useMembers(group: Group) {
|
|||
}
|
||||
|
||||
export async function listMembers(group: Group) {
|
||||
return (await Promise.all(group.memberIds.map(getUser))).filter(
|
||||
(user) => user
|
||||
)
|
||||
return await Promise.all(group.memberIds.map(getUser))
|
||||
}
|
||||
|
||||
export const useGroupsWithContract = (contractId: string | undefined) => {
|
||||
|
|
|
@ -102,10 +102,13 @@ export async function addUserToGroupViaSlug(groupSlug: string, userId: string) {
|
|||
console.error(`Group not found: ${groupSlug}`)
|
||||
return
|
||||
}
|
||||
return await joinGroup(group, userId)
|
||||
return await addUserToGroup(group, userId)
|
||||
}
|
||||
|
||||
export async function joinGroup(group: Group, userId: string): Promise<Group> {
|
||||
export async function addUserToGroup(
|
||||
group: Group,
|
||||
userId: string
|
||||
): Promise<Group> {
|
||||
const { memberIds } = group
|
||||
if (memberIds.includes(userId)) {
|
||||
return group
|
||||
|
@ -125,3 +128,14 @@ export async function leaveGroup(group: Group, userId: string): Promise<Group> {
|
|||
await updateGroup(newGroup, { memberIds: uniq(newMemberIds) })
|
||||
return newGroup
|
||||
}
|
||||
|
||||
export async function addContractToGroup(group: Group, contractId: string) {
|
||||
return await updateGroup(group, {
|
||||
contractIds: uniq([...group.contractIds, contractId]),
|
||||
})
|
||||
.then(() => group)
|
||||
.catch((err) => {
|
||||
console.error('error adding contract to group', err)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
import { formatMoney } from 'common/util/format'
|
||||
import { removeUndefinedProps } from 'common/util/object'
|
||||
import { ChoicesToggleGroup } from 'web/components/choices-toggle-group'
|
||||
import { getGroup, updateGroup } from 'web/lib/firebase/groups'
|
||||
import { addContractToGroup, getGroup } from 'web/lib/firebase/groups'
|
||||
import { Group } from 'common/group'
|
||||
import { useTracking } from 'web/hooks/use-tracking'
|
||||
import { useWarnUnsavedChanges } from 'web/hooks/use-warn-unsaved-changes'
|
||||
|
@ -186,9 +186,7 @@ export function NewContract(props: {
|
|||
isFree: false,
|
||||
})
|
||||
if (result && selectedGroup) {
|
||||
await updateGroup(selectedGroup, {
|
||||
contractIds: [...selectedGroup.contractIds, result.id],
|
||||
})
|
||||
await addContractToGroup(selectedGroup, result.id)
|
||||
}
|
||||
|
||||
await router.push(contractPath(result as Contract))
|
||||
|
|
|
@ -4,12 +4,14 @@ import { Group } from 'common/group'
|
|||
import { Page } from 'web/components/page'
|
||||
import { Title } from 'web/components/title'
|
||||
import { listAllBets } from 'web/lib/firebase/bets'
|
||||
import { Contract, listenForUserContracts } from 'web/lib/firebase/contracts'
|
||||
import { Contract } from 'web/lib/firebase/contracts'
|
||||
import {
|
||||
groupPath,
|
||||
getGroupBySlug,
|
||||
getGroupContracts,
|
||||
updateGroup,
|
||||
addContractToGroup,
|
||||
addUserToGroup,
|
||||
} from 'web/lib/firebase/groups'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { UserLink } from 'web/components/user-page'
|
||||
|
@ -39,7 +41,6 @@ import React, { useEffect, useState } from 'react'
|
|||
import { GroupChat } from 'web/components/groups/group-chat'
|
||||
import { LoadingIndicator } from 'web/components/loading-indicator'
|
||||
import { Modal } from 'web/components/layout/modal'
|
||||
import { PlusIcon } from '@heroicons/react/outline'
|
||||
import { checkAgainstQuery } from 'web/hooks/use-sort-and-query-params'
|
||||
import { ChoicesToggleGroup } from 'web/components/choices-toggle-group'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
@ -48,6 +49,7 @@ import ShortToggle from 'web/components/widgets/short-toggle'
|
|||
import { ShareIconButton } from 'web/components/share-icon-button'
|
||||
import { REFERRAL_AMOUNT } from 'common/user'
|
||||
import { SiteLink } from 'web/components/site-link'
|
||||
import { ContractSearch } from 'web/components/contract-search'
|
||||
|
||||
export const getStaticProps = fromPropz(getStaticPropz)
|
||||
export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
||||
|
@ -509,75 +511,46 @@ function GroupLeaderboards(props: {
|
|||
}
|
||||
|
||||
function AddContractButton(props: { group: Group; user: User }) {
|
||||
const { group, user } = props
|
||||
const { group } = props
|
||||
const [open, setOpen] = useState(false)
|
||||
const [contracts, setContracts] = useState<Contract[] | undefined>(undefined)
|
||||
const [query, setQuery] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
return listenForUserContracts(user.id, (contracts) => {
|
||||
setContracts(contracts.filter((c) => !group.contractIds.includes(c.id)))
|
||||
})
|
||||
}, [group.contractIds, user.id])
|
||||
|
||||
async function addContractToGroup(contract: Contract) {
|
||||
await updateGroup(group, {
|
||||
...group,
|
||||
contractIds: [...group.contractIds, contract.id],
|
||||
})
|
||||
async function addContractToCurrentGroup(contract: Contract) {
|
||||
await addContractToGroup(group, contract.id)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
// TODO use find-active-contracts to sort by?
|
||||
const matches = sortBy(contracts, [
|
||||
(contract) => -1 * contract.createdTime,
|
||||
]).filter(
|
||||
(c) =>
|
||||
checkAgainstQuery(query, c.question) ||
|
||||
checkAgainstQuery(query, c.description) ||
|
||||
checkAgainstQuery(query, c.tags.flat().join(' '))
|
||||
)
|
||||
const debouncedQuery = debounce(setQuery, 50)
|
||||
return (
|
||||
<>
|
||||
<Modal open={open} setOpen={setOpen}>
|
||||
<Col className={'max-h-[60vh] w-full gap-4 rounded-md bg-white p-8'}>
|
||||
<Modal open={open} setOpen={setOpen} className={'sm:p-0'}>
|
||||
<Col
|
||||
className={
|
||||
'max-h-[60vh] min-h-[60vh] w-full gap-4 rounded-md bg-white p-8'
|
||||
}
|
||||
>
|
||||
<div className={'text-lg text-indigo-700'}>
|
||||
Add a question to your group
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => debouncedQuery(e.target.value)}
|
||||
placeholder="Search your questions"
|
||||
className="input input-bordered mb-4 w-full"
|
||||
/>
|
||||
<div className={'overflow-y-scroll'}>
|
||||
{contracts ? (
|
||||
<ContractsGrid
|
||||
contracts={matches}
|
||||
loadMore={() => {}}
|
||||
hasMore={false}
|
||||
onContractClick={(contract) => {
|
||||
addContractToGroup(contract)
|
||||
}}
|
||||
<div className={'overflow-y-scroll p-1'}>
|
||||
<ContractSearch
|
||||
hideOrderSelector={true}
|
||||
onContractClick={addContractToCurrentGroup}
|
||||
showCategorySelector={false}
|
||||
overrideGridClassName={'flex grid-cols-1 flex-col gap-3 p-1'}
|
||||
showPlaceHolder={true}
|
||||
hideQuickBet={true}
|
||||
additionalFilter={{ excludeContractIds: group.contractIds }}
|
||||
/>
|
||||
) : (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</div>
|
||||
</Col>
|
||||
</Modal>
|
||||
<Row className={'items-center justify-center'}>
|
||||
<button
|
||||
className={
|
||||
'btn btn-sm btn-outline cursor-pointer gap-2 whitespace-nowrap text-sm normal-case'
|
||||
'btn btn-md btn-outline cursor-pointer gap-2 whitespace-nowrap text-sm normal-case'
|
||||
}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<PlusIcon className="mr-1 h-5 w-5" />
|
||||
Add old questions to this group
|
||||
Add an old question
|
||||
</button>
|
||||
</Row>
|
||||
</>
|
||||
|
@ -591,17 +564,11 @@ function JoinGroupButton(props: {
|
|||
const { group, user } = props
|
||||
function joinGroup() {
|
||||
if (user && !group.memberIds.includes(user.id)) {
|
||||
toast.promise(
|
||||
updateGroup(group, {
|
||||
...group,
|
||||
memberIds: [...group.memberIds, user.id],
|
||||
}),
|
||||
{
|
||||
toast.promise(addUserToGroup(group, user.id), {
|
||||
loading: 'Joining group...',
|
||||
success: 'Joined group!',
|
||||
error: "Couldn't join group",
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
return (
|
||||
|
|
|
@ -64,7 +64,7 @@ export default function LinkPage() {
|
|||
<Col className="w-full px-8">
|
||||
<Title text="Manalinks" />
|
||||
<Tabs
|
||||
className={'pb-2 pt-1 '}
|
||||
labelClassName={'pb-2 pt-1 '}
|
||||
defaultIndex={0}
|
||||
tabs={[
|
||||
{
|
||||
|
|
|
@ -86,7 +86,7 @@ export default function Notifications() {
|
|||
<div className={'p-2 sm:p-4'}>
|
||||
<Title text={'Notifications'} className={'hidden md:block'} />
|
||||
<Tabs
|
||||
className={'pb-2 pt-1 '}
|
||||
labelClassName={'pb-2 pt-1 '}
|
||||
defaultIndex={0}
|
||||
tabs={[
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user