Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"use client"

import { useEffect, useState } from "react"
import {
CloseButton,
DialogActions,
DialogBody,
DialogHeader,
DialogTitle,
Modal,
} from "@/components/common/dialog"
import type { LocationWithRelations } from "@/lib/prisma/location/types"

type ConfirmArchiveLocationModalProps = {
open: boolean
onClose: () => void
location: LocationWithRelations | null
updateLocation: (
location: Partial<LocationWithRelations>,
prevLocation: Partial<LocationWithRelations>
) => Promise<LocationWithRelations | null>
revalidateTable: () => Promise<void>
}

export const ConfirmArchiveLocationModal = ({
open,
onClose,
location,
updateLocation,
revalidateTable,
}: ConfirmArchiveLocationModalProps) => {
const [formData, setFormData] = useState<LocationWithRelations | null>(null)
const [previousLocation, setPreviousLocation] = useState<LocationWithRelations | null>(null)
const [archiveConfirmation, setArchiveConfirmation] = useState("")

const isArchived = location?.deletedAt !== null

useEffect(() => {
if (open && location) {
setFormData(location)
setPreviousLocation(location)
}
}, [open, location])

if (!location || !formData || !previousLocation) return null

const handleSave = async () => {
if (formData) {
await updateLocation(
{ ...formData, deletedAt: isArchived ? null : new Date() },
previousLocation
)
await revalidateTable()
setArchiveConfirmation("")
onClose()
}
}

return (
<Modal open={open} onClose={onClose} size="sm">
<DialogHeader trailing={<CloseButton onClick={onClose} />} className="bg-background-danger">
<DialogTitle className="text-white">
{isArchived ? "Unarchive" : "Archive"} Location
</DialogTitle>
</DialogHeader>

<DialogBody>
<form className="space-y-5">
<div>
<label
htmlFor="archive-location"
className="block text-sm font-medium text-typography-primary"
>
Type "<span className="text-typography-danger">{location.name}</span>" to confirm{" "}
{isArchived ? "unarchiving" : "archiving"} this location.
</label>
<input
id="archive-location"
value={archiveConfirmation}
onChange={(e) => setArchiveConfirmation(e.target.value)}
autoComplete="off"
className="mt-2 block w-full rounded-md border border-border-dark px-2 py-1 text-xs text-typography-primary"
/>
</div>
</form>
</DialogBody>

<DialogActions>
<button type="button" className="tertiary" onClick={onClose}>
Cancel
</button>
<button
type="button"
className="primary danger"
onClick={handleSave}
disabled={archiveConfirmation !== location.name}
>
{isArchived ? "Unarchive" : "Archive"}
</button>
</DialogActions>
</Modal>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./ConfirmArchiveLocationModal"
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ describe("EditLocationModal", () => {
const updateLocation = vi.fn().mockResolvedValue(location)
const revalidateTable = vi.fn().mockResolvedValue(undefined)
const doesLocationCodeExist = vi.fn().mockResolvedValue(false)
const openConfirmArchiveLocationModal = vi.fn()

render(
<EditLocationModal
Expand All @@ -89,6 +90,7 @@ describe("EditLocationModal", () => {
updateLocation={updateLocation}
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
openConfirmArchiveLocationModal={openConfirmArchiveLocationModal}
/>
)

Expand All @@ -101,6 +103,7 @@ describe("EditLocationModal", () => {
const updateLocation = vi.fn().mockResolvedValue(location)
const revalidateTable = vi.fn().mockResolvedValue(undefined)
const doesLocationCodeExist = vi.fn().mockResolvedValue(false)
const openConfirmArchiveLocationModal = vi.fn()

render(
<EditLocationModal
Expand All @@ -113,6 +116,7 @@ describe("EditLocationModal", () => {
updateLocation={updateLocation}
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
openConfirmArchiveLocationModal={openConfirmArchiveLocationModal}
/>
)

Expand All @@ -127,6 +131,7 @@ describe("EditLocationModal", () => {
const updateLocation = vi.fn().mockResolvedValue(location)
const revalidateTable = vi.fn().mockResolvedValue(undefined)
const doesLocationCodeExist = vi.fn().mockResolvedValue(false)
const openConfirmArchiveLocationModal = vi.fn()

const { queryByText } = render(
<EditLocationModal
Expand All @@ -139,6 +144,7 @@ describe("EditLocationModal", () => {
updateLocation={updateLocation}
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
openConfirmArchiveLocationModal={openConfirmArchiveLocationModal}
/>
)

Expand All @@ -156,6 +162,7 @@ describe("EditLocationModal", () => {
const updateLocation = vi.fn().mockResolvedValue(archivedLocation)
const revalidateTable = vi.fn().mockResolvedValue(undefined)
const doesLocationCodeExist = vi.fn().mockResolvedValue(false)
const openConfirmArchiveLocationModal = vi.fn()

render(
<EditLocationModal
Expand All @@ -168,11 +175,94 @@ describe("EditLocationModal", () => {
updateLocation={updateLocation}
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
openConfirmArchiveLocationModal={openConfirmArchiveLocationModal}
/>
)

await waitFor(() =>
expect(screen.getByText("This location is archived and cannot be edited.")).toBeTruthy()
)
})

it("shows Archive button with text 'Archive' for active location", async () => {
const onClose = vi.fn()
const updateLocation = vi.fn().mockResolvedValue(location)
const revalidateTable = vi.fn().mockResolvedValue(undefined)
const doesLocationCodeExist = vi.fn().mockResolvedValue(false)
const openConfirmArchiveLocationModal = vi.fn()

render(
<EditLocationModal
open={true}
onClose={onClose}
location={location}
services={services}
counters={counters}
staffUsers={staffUsers}
updateLocation={updateLocation}
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
openConfirmArchiveLocationModal={openConfirmArchiveLocationModal}
/>
)

await waitFor(() => expect(screen.getByText("Archive")).toBeTruthy())
})

it("calls openConfirmArchiveLocationModal when Archive button is clicked", async () => {
const onClose = vi.fn()
const updateLocation = vi.fn().mockResolvedValue(location)
const revalidateTable = vi.fn().mockResolvedValue(undefined)
const doesLocationCodeExist = vi.fn().mockResolvedValue(false)
const openConfirmArchiveLocationModal = vi.fn()

render(
<EditLocationModal
open={true}
onClose={onClose}
location={location}
services={services}
counters={counters}
staffUsers={staffUsers}
updateLocation={updateLocation}
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
openConfirmArchiveLocationModal={openConfirmArchiveLocationModal}
/>
)

await waitFor(() => expect(screen.getByText("Archive")).toBeTruthy())
fireEvent.click(screen.getByText("Archive"))
expect(openConfirmArchiveLocationModal).toHaveBeenCalled()
})

it("shows Unarchive button for archived location", async () => {
const archivedLocation = {
...location,
deletedAt: new Date(),
} as LocationWithRelations

const onClose = vi.fn()
const updateLocation = vi.fn().mockResolvedValue(archivedLocation)
const revalidateTable = vi.fn().mockResolvedValue(undefined)
const doesLocationCodeExist = vi.fn().mockResolvedValue(false)
const openConfirmArchiveLocationModal = vi.fn()

render(
<EditLocationModal
open={true}
onClose={onClose}
location={archivedLocation}
services={services}
counters={counters}
staffUsers={staffUsers}
updateLocation={updateLocation}
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
openConfirmArchiveLocationModal={openConfirmArchiveLocationModal}
/>
)

await waitFor(() => expect(screen.getByText("Unarchive")).toBeTruthy())
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type EditLocationModalProps = {
) => Promise<LocationWithRelations | null>
doesLocationCodeExist: (code: string) => Promise<boolean>
revalidateTable: () => Promise<void>
openConfirmArchiveLocationModal: () => void
}

export const EditLocationModal = ({
Expand All @@ -40,6 +41,7 @@ export const EditLocationModal = ({
updateLocation,
doesLocationCodeExist,
revalidateTable,
openConfirmArchiveLocationModal,
}: EditLocationModalProps) => {
const [isSaving, setIsSaving] = useState(false)
const [formData, setFormData] = useState<Partial<LocationWithRelations> | null>(null)
Expand Down Expand Up @@ -140,6 +142,11 @@ export const EditLocationModal = ({
}
}

const handleOpenArchive = () => {
openConfirmArchiveLocationModal()
onClose()
}

return (
<Modal open={open} onClose={onClose} size="xl">
<DialogHeader trailing={<CloseButton onClick={onClose} />}>
Expand Down Expand Up @@ -174,6 +181,9 @@ export const EditLocationModal = ({
<button type="button" className="tertiary" onClick={onClose}>
Cancel
</button>
<button type="button" className="secondary danger" onClick={handleOpenArchive}>
{isArchived ? "Unarchive" : "Archive"}
</button>
<button
type="button"
className="primary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { Counter, StaffUser } from "@/generated/prisma/client"
import { useDialog } from "@/hooks/useDialog"
import type { LocationWithRelations } from "@/lib/prisma/location/types"
import type { ServiceWithRelations } from "@/lib/prisma/service/types"
import { ConfirmArchiveLocationModal } from "../ConfirmArchiveLocationModal"
import { CreateLocationModal } from "../CreateLocationModal"
import { EditLocationModal } from "../EditLocationModal"
import { columns } from "./columns"
Expand Down Expand Up @@ -47,6 +48,11 @@ export const LocationTable = ({
openDialog: openCreateLocationModal,
closeDialog: closeCreateLocationModal,
} = useDialog()
const {
open: confirmArchiveLocationModalOpen,
openDialog: openConfirmArchiveLocationModal,
closeDialog: closeConfirmArchiveLocationModal,
} = useDialog()

const [showArchived, setShowArchived] = useState<boolean>(false)
const [selectedLocation, setSelectedLocation] = useState<LocationWithRelations | null>(null)
Expand Down Expand Up @@ -94,6 +100,7 @@ export const LocationTable = ({
updateLocation={updateLocation}
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
openConfirmArchiveLocationModal={openConfirmArchiveLocationModal}
/>
<CreateLocationModal
open={createLocationModalOpen}
Expand All @@ -105,6 +112,13 @@ export const LocationTable = ({
doesLocationCodeExist={doesLocationCodeExist}
revalidateTable={revalidateTable}
/>
<ConfirmArchiveLocationModal
open={confirmArchiveLocationModalOpen}
onClose={closeConfirmArchiveLocationModal}
location={selectedLocation}
updateLocation={updateLocation}
revalidateTable={revalidateTable}
/>
</>
)
}