Skip to content

Commit

Permalink
Allow settings tags on multiple listings at once
Browse files Browse the repository at this point in the history
  • Loading branch information
DinerIsmail committed Oct 8, 2024
1 parent 18e5fc0 commit 0976bc5
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 13 deletions.
28 changes: 28 additions & 0 deletions app/api/tags/[id]/listings/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import prisma from '../../../../../prisma/client'

export async function PUT(request: Request, { params }) {
const id = params.id
const listingIds = await request.json()

const listingIdsToConnect = listingIds.map((id) => ({ id }))

try {
const tag = await prisma.tag.update({
where: {
id: Number(id),
},
data: {
listings: {
connect: listingIdsToConnect,
},
},
})

return Response.json({ data: tag })
} catch (e) {
console.error(`[RW] Unable to add tag to listings - ${e}`)
return new Response(`Unable to add tag to listings - ${e}`, {
status: 500,
})
}
}
2 changes: 1 addition & 1 deletion components/admin/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ const SidebarContent = ({ onClose, ...rest }: SidebarProps) => {
<Heading as="h2" fontSize="1.25rem">
Like what you see?
</Heading>
<Text mb="0.75rem">
<Text mb="0.75rem" fontSize="0.9375rem" color="gray.600">
Consider making a donation to help us host and develop the
Resilience Web platform 🙏🏼
</Text>
Expand Down
1 change: 0 additions & 1 deletion components/admin/tags/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { NewTagDialog } from './tag-dialog'
const Header = () => {
const { isOpen, onOpen, onClose } = useDisclosure()
const { mutate: createTag } = useCreateTag()

const { selectedWebId } = useAppContext()

const handleSubmit = useCallback(
Expand Down
64 changes: 53 additions & 11 deletions components/admin/tags/list/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import { memo, useCallback, useState } from 'react'

import useUpdateTag from '@hooks/tags/useUpdateTag'
import useDeleteTag from '@hooks/tags/useDeleteTag'
import useAddTagToListings from '@hooks/tags/useAddTagToListings'
import useListings from '@hooks/listings/useListings'
import { UpdateTagDialog } from '../header/tag-dialog'
import AddTagToListingsDialog from './add-to-listings-dialog'

const columns = [
{
Expand All @@ -28,33 +31,54 @@ const columns = [
]

const List = ({ tags }) => {
const { isOpen, onOpen, onClose } = useDisclosure()
const {
isOpen: isUpdateTagDialogOpen,
onOpen: onUpdateTagDialogOpen,
onClose: onUpdateTagDialogClose,
} = useDisclosure()
const {
isOpen: isAddToListingsDialogOpen,
onOpen: onAddToListingsDialogOpen,
onClose: onAddToListingsDialogClose,
} = useDisclosure()
const { listings, isPending: isLoadingListings } = useListings()
const { mutate: updateTag } = useUpdateTag()
const { mutate: deleteTag } = useDeleteTag()
const { mutate: addTagToListings } = useAddTagToListings()

const [selectedTagId, setSelectedTagId] = useState(null)
const selectedTag = tags.find((tag) => tag.id === selectedTagId)

const handleOpen = (tagId) => {
const handleOpenUpdateTagDialog = (tagId) => {
setSelectedTagId(tagId)
onOpen()
onUpdateTagDialogOpen()
}

const handleSubmit = useCallback(
(data) => {
onClose()
onUpdateTagDialogClose()
updateTag({
...data,
id: selectedTagId,
})
},
[onClose, updateTag, selectedTagId],
[onUpdateTagDialogClose, updateTag, selectedTagId],
)

const handleDelete = useCallback(() => {
onClose()
onUpdateTagDialogClose()
deleteTag({ id: selectedTagId })
}, [deleteTag, onClose, selectedTagId])
}, [deleteTag, onUpdateTagDialogClose, selectedTagId])

const handleOpenAddTagToListingsDialog = (tagId) => {
setSelectedTagId(tagId)
onAddToListingsDialogOpen()
}

const handleAddTagToListingsSubmit = (data) => {
onAddToListingsDialogClose()
addTagToListings({ tagId: selectedTagId, listingIds: data })
}

if (!tags) {
return null
Expand All @@ -64,7 +88,7 @@ const List = ({ tags }) => {
<>
<TableContainer borderRadius="10px" borderStyle="solid" borderWidth="1px">
<Table fontSize="sm" background="#ffffff">
<Thead bg={'gray.50'}>
<Thead bg="gray.50">
<Tr>
{columns.map((column, index) => (
<Th whiteSpace="nowrap" scope="col" key={index}>
Expand All @@ -84,6 +108,16 @@ const List = ({ tags }) => {
return (
<Td key={index}>
<strong>{cell.length}</strong>
<Button
onClick={() =>
handleOpenAddTagToListingsDialog(row.id)
}
variant="outline"
size="sm"
ml="0.5rem"
>
Add tag to listings
</Button>
</Td>
)
}
Expand All @@ -98,7 +132,7 @@ const List = ({ tags }) => {
<Stack direction="column" spacing={2}>
<Button
colorScheme="blue"
onClick={() => handleOpen(row.id)}
onClick={() => handleOpenUpdateTagDialog(row.id)}
size="sm"
>
Edit
Expand All @@ -112,11 +146,19 @@ const List = ({ tags }) => {
</TableContainer>
<UpdateTagDialog
tag={selectedTag}
isOpen={isOpen}
onClose={onClose}
isOpen={isUpdateTagDialogOpen}
onClose={onUpdateTagDialogClose}
onDelete={handleDelete}
onSubmit={handleSubmit}
/>
{selectedTag && !isLoadingListings && isAddToListingsDialogOpen && (
<AddTagToListingsDialog
tag={selectedTag}
listings={listings}
onClose={onAddToListingsDialogClose}
onSubmit={handleAddTagToListingsSubmit}
/>
)}
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useMemo } from 'react'
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
ModalFooter,
Stack,
Checkbox,
useCheckboxGroup,
Button,
} from '@chakra-ui/react'

export default function AddTagToListingsDialog({
tag,
listings,
onClose,
onSubmit,
}) {
const linkedListingsIds = useMemo(() => {
return tag.listings.map((listing) => listing.id)
}, [tag.listings])
const { value, getCheckboxProps } = useCheckboxGroup({
defaultValue: linkedListingsIds,
})

const handleSubmit = () => {
const integerValues = value.map((v) => Number(v))
onSubmit(integerValues)
}

return (
<Modal
isCentered
isOpen
onClose={onClose}
size={{ base: 'full', md: 'md' }}
>
<ModalOverlay />
<ModalContent>
<ModalHeader>Add tag to listings</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Stack spacing={[1, 5]}>
{listings.map((listing) => (
<Checkbox
key={listing.id}
{...getCheckboxProps({ value: listing.id })}
>
{listing.title}
</Checkbox>
))}
</Stack>
</ModalBody>
<ModalFooter>
<Button
mt={4}
ml={2}
variant="rw"
type="submit"
onClick={handleSubmit}
>
Submit
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}
1 change: 1 addition & 0 deletions components/admin/tags/list/add-to-listings-dialog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './AddTagToListingsDialog'
6 changes: 6 additions & 0 deletions hooks/listings/useUpdateListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ export default function useUpdateListing() {
queryClient.invalidateQueries({
queryKey: ['listings', 'list', { webSlug }],
})
queryClient.invalidateQueries({
queryKey: ['categories', { webSlug }],
})
queryClient.invalidateQueries({
queryKey: ['tags', { webSlug }],
})
},
})
}
30 changes: 30 additions & 0 deletions hooks/tags/useAddTagToListings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useAppContext } from '@store/hooks'

async function addTagToListingsRequest({ tagId, listingIds }) {
const response = await fetch(`/api/tags/${tagId}/listings`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json;charset=utf-8',
},
body: JSON.stringify(listingIds),
})

const data = await response.json()
const { tag } = data
return tag
}

export default function useAddTagToListings() {
const queryClient = useQueryClient()
const { selectedWebSlug: webSlug } = useAppContext()

return useMutation({
mutationFn: addTagToListingsRequest,
onSettled: () => {
void queryClient.invalidateQueries({
queryKey: ['tags', { webSlug }],
})
},
})
}

0 comments on commit 0976bc5

Please sign in to comment.