Refactor Pinned Items into a reusable component

This commit is contained in:
Pico2x 2022-10-06 17:04:00 +01:00
parent 26f04fb04a
commit 59de979949
2 changed files with 118 additions and 93 deletions

View File

@ -145,8 +145,6 @@ function GroupOverviewPinned(props: {
}) {
const { group, posts, isEditable } = props
const [pinned, setPinned] = useState<JSX.Element[]>([])
const [open, setOpen] = useState(false)
const [editMode, setEditMode] = useState(false)
useEffect(() => {
async function getPinned() {
@ -185,100 +183,127 @@ function GroupOverviewPinned(props: {
...(selectedItems as { itemId: string; type: 'contract' | 'post' }[]),
],
})
setOpen(false)
}
function onDeleteClicked(index: number) {
const newPinned = group.pinnedItems.filter((item) => {
return item.itemId !== group.pinnedItems[index].itemId
})
updateGroup(group, { pinnedItems: newPinned })
}
return isEditable || (group.pinnedItems && group.pinnedItems.length > 0) ? (
pinned.length > 0 || isEditable ? (
<div>
<Row className="mb-3 items-center justify-between">
<SectionHeader label={'Pinned'} />
{isEditable && (
<Button
color="gray"
size="xs"
onClick={() => {
setEditMode(!editMode)
}}
>
{editMode ? (
'Done'
) : (
<>
<PencilIcon className="inline h-4 w-4" />
Edit
</>
)}
</Button>
)}
</Row>
<div>
<Masonry
breakpointCols={{ default: 2, 768: 1 }}
className="-ml-4 flex w-auto"
columnClassName="pl-4 bg-clip-padding"
>
{pinned.length == 0 && !editMode && (
<div className="flex flex-col items-center justify-center">
<p className="text-center text-gray-400">
No pinned items yet. Click the edit button to add some!
</p>
</div>
)}
{pinned.map((element, index) => (
<div className="relative my-2">
{element}
<PinnedItems
posts={posts}
group={group}
isEditable={isEditable}
pinned={pinned}
onDeleteClicked={onDeleteClicked}
onSubmit={onSubmit}
modalMessage={'Pin posts or markets to the overview of this group.'}
/>
) : (
<LoadingIndicator />
)
}
{editMode && (
<CrossIcon
onClick={() => {
const newPinned = group.pinnedItems.filter((item) => {
return item.itemId !== group.pinnedItems[index].itemId
})
updateGroup(group, { pinnedItems: newPinned })
}}
/>
)}
</div>
))}
{editMode && group.pinnedItems && pinned.length < 6 && (
<div className=" py-2">
<Row
className={
'relative gap-3 rounded-lg border-4 border-dotted p-2 hover:cursor-pointer hover:bg-gray-100'
}
>
<button
className="flex w-full justify-center"
onClick={() => setOpen(true)}
>
<PlusCircleIcon
className="h-12 w-12 text-gray-600"
aria-hidden="true"
/>
</button>
</Row>
</div>
export function PinnedItems(props: {
posts: Post[]
isEditable: boolean
pinned: JSX.Element[]
onDeleteClicked: (index: number) => void
onSubmit: (selectedItems: { itemId: string; type: string }[]) => void
group?: Group
modalMessage: string
}) {
const {
isEditable,
pinned,
onDeleteClicked,
onSubmit,
posts,
group,
modalMessage,
} = props
const [editMode, setEditMode] = useState(false)
const [open, setOpen] = useState(false)
return pinned.length > 0 || isEditable ? (
<div>
<Row className="mb-3 items-center justify-between">
<SectionHeader label={'Pinned'} />
{isEditable && (
<Button
color="gray"
size="xs"
onClick={() => {
setEditMode(!editMode)
}}
>
{editMode ? (
'Done'
) : (
<>
<PencilIcon className="inline h-4 w-4" />
Edit
</>
)}
</Masonry>
</div>
<PinnedSelectModal
open={open}
group={group}
posts={posts}
setOpen={setOpen}
title="Pin a post or market"
description={
<div className={'text-md my-4 text-gray-600'}>
Pin posts or markets to the overview of this group.
</Button>
)}
</Row>
<div>
<Masonry
breakpointCols={{ default: 2, 768: 1 }}
className="-ml-4 flex w-auto"
columnClassName="pl-4 bg-clip-padding"
>
{pinned.length == 0 && !editMode && (
<div className="flex flex-col items-center justify-center">
<p className="text-center text-gray-400">
No pinned items yet. Click the edit button to add some!
</p>
</div>
}
onSubmit={onSubmit}
/>
)}
{pinned.map((element, index) => (
<div className="relative my-2">
{element}
{editMode && <CrossIcon onClick={() => onDeleteClicked(index)} />}
</div>
))}
{editMode && pinned.length < 6 && (
<div className=" py-2">
<Row
className={
'relative gap-3 rounded-lg border-4 border-dotted p-2 hover:cursor-pointer hover:bg-gray-100'
}
>
<button
className="flex w-full justify-center"
onClick={() => setOpen(true)}
>
<PlusCircleIcon
className="h-12 w-12 text-gray-600"
aria-hidden="true"
/>
</button>
</Row>
</div>
)}
</Masonry>
</div>
) : (
<LoadingIndicator />
)
<PinnedSelectModal
open={open}
group={group}
posts={posts}
setOpen={setOpen}
title="Pin a post or market"
description={
<div className={'text-md my-4 text-gray-600'}>{modalMessage}</div>
}
onSubmit={onSubmit}
/>
</div>
) : (
<></>
)

View File

@ -20,8 +20,8 @@ export function PinnedSelectModal(props: {
selectedItems: { itemId: string; type: string }[]
) => void | Promise<void>
contractSearchOptions?: Partial<Parameters<typeof ContractSearch>[0]>
group: Group
posts: Post[]
group?: Group
}) {
const {
title,
@ -134,8 +134,8 @@ export function PinnedSelectModal(props: {
highlightClassName:
'!bg-indigo-100 outline outline-2 outline-indigo-300',
}}
additionalFilter={{ groupSlug: group.slug }}
persistPrefix={`group-${group.slug}`}
additionalFilter={group ? { groupSlug: group.slug } : undefined}
persistPrefix={group ? `group-${group.slug}` : undefined}
headerClassName="bg-white sticky"
{...contractSearchOptions}
/>
@ -152,7 +152,7 @@ export function PinnedSelectModal(props: {
'!bg-indigo-100 outline outline-2 outline-indigo-300',
}}
/>
{posts.length === 0 && (
{posts.length == 0 && (
<div className="text-center text-gray-500">No posts yet</div>
)}
</div>