Skip to content

Commit

Permalink
feat: introduce discard changes modal (#400)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcshzj authored Jul 31, 2024
1 parent 4f1290b commit 3058967
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,30 @@ import {
import { Button, IconButton } from "@opengovsg/design-system-react"
import { getComponentSchema } from "@opengovsg/isomer-components"
import Ajv from "ajv"
import _ from "lodash"
import { BiDollar, BiTrash, BiX } from "react-icons/bi"

import { useEditorDrawerContext } from "~/contexts/EditorDrawerContext"
import { useQueryParse } from "~/hooks/useQueryParse"
import { editPageSchema } from "~/pages/sites/[siteId]/pages/[pageId]"
import { trpc } from "~/utils/trpc"
import { DeleteBlockModal } from "./DeleteBlockModal"
import { DiscardChangesModal } from "./DiscardChangesModal"
import FormBuilder from "./form-builder/FormBuilder"

const ajv = new Ajv({ strict: false, logger: false })

export default function ComplexEditorStateDrawer(): JSX.Element {
const {
isOpen: isDeleteBlockModalOpen,
onOpen: onDeleteBlockModalOpen,
onClose: onDeleteBlockModalClose,
} = useDisclosure()
const {
isOpen: isDiscardChangesModalOpen,
onOpen: onDiscardChangesModalOpen,
onClose: onDiscardChangesModalClose,
} = useDisclosure()
const {
setDrawerState,
currActiveIdx,
Expand All @@ -30,6 +42,7 @@ export default function ComplexEditorStateDrawer(): JSX.Element {
previewPageState,
setPreviewPageState,
} = useEditorDrawerContext()

const { pageId, siteId } = useQueryParse(editPageSchema)
const [{ content: pageContent }] = trpc.page.readPageAndBlob.useSuspenseQuery(
{ siteId, pageId },
Expand All @@ -41,11 +54,6 @@ export default function ComplexEditorStateDrawer(): JSX.Element {
await utils.page.readPageAndBlob.invalidate({ pageId, siteId })
},
})
const {
isOpen: isDeleteBlockModalOpen,
onOpen: onDeleteBlockModalOpen,
onClose: onDeleteBlockModalClose,
} = useDisclosure()

if (
currActiveIdx === -1 ||
Expand Down Expand Up @@ -80,6 +88,12 @@ export default function ComplexEditorStateDrawer(): JSX.Element {
setDrawerState({ state: "root" })
}

const handleDiscardChanges = () => {
setPreviewPageState(savedPageState)
onDiscardChangesModalClose()
setDrawerState({ state: "root" })
}

const handleChange = (data: IsomerComponent) => {
const updatedBlocks = Array.from(previewPageState.content)
updatedBlocks[currActiveIdx] = data
Expand All @@ -99,6 +113,12 @@ export default function ComplexEditorStateDrawer(): JSX.Element {
onDelete={handleDeleteBlock}
/>

<DiscardChangesModal
isOpen={isDiscardChangesModalOpen}
onClose={onDiscardChangesModalClose}
onDiscard={handleDiscardChanges}
/>

<Flex
flexDir="column"
position="relative"
Expand Down Expand Up @@ -134,8 +154,11 @@ export default function ComplexEditorStateDrawer(): JSX.Element {
size="sm"
p="0.625rem"
onClick={() => {
setPreviewPageState(savedPageState)
setDrawerState({ state: "root" })
if (!_.isEqual(previewPageState, savedPageState)) {
onDiscardChangesModalOpen()
} else {
handleDiscardChanges()
}
}}
aria-label="Close drawer"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
HStack,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
} from "@chakra-ui/react"
import { Button, ModalCloseButton } from "@opengovsg/design-system-react"

interface DiscardChangesModalProps {
isOpen: boolean
onClose: () => void
onDiscard: () => void
}

export const DiscardChangesModal = ({
isOpen,
onClose,
onDiscard,
}: DiscardChangesModalProps): JSX.Element => {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>
Are you sure you want to discard your changes?
</ModalHeader>
<ModalCloseButton />

<ModalBody>
<Text textStyle="body-2">All edits will be lost.</Text>
</ModalBody>

<ModalFooter>
<HStack spacing="1rem">
<Button variant="clear" colorScheme="neutral" onClick={onClose}>
Go back to editing
</Button>
<Button variant="solid" colorScheme="critical" onClick={onDiscard}>
Yes, discard changes
</Button>
</HStack>
</ModalFooter>
</ModalContent>
</Modal>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./DiscardChangesModal"
Original file line number Diff line number Diff line change
@@ -1,20 +1,43 @@
import type { IsomerSchema, schema } from "@opengovsg/isomer-components"
import type { Static } from "@sinclair/typebox"
import { Box, Flex, Heading, HStack, Icon, IconButton } from "@chakra-ui/react"
import {
Box,
Flex,
Heading,
HStack,
Icon,
IconButton,
useDisclosure,
} from "@chakra-ui/react"
import { Button } from "@opengovsg/design-system-react"
import { getLayoutMetadataSchema } from "@opengovsg/isomer-components"
import Ajv from "ajv"
import _ from "lodash"
import { BiDollar, BiX } from "react-icons/bi"

import { useEditorDrawerContext } from "~/contexts/EditorDrawerContext"
import { useQueryParse } from "~/hooks/useQueryParse"
import { editPageSchema } from "~/pages/sites/[siteId]/pages/[pageId]"
import { trpc } from "~/utils/trpc"
import { DiscardChangesModal } from "./DiscardChangesModal"
import FormBuilder from "./form-builder/FormBuilder"

const ajv = new Ajv({ strict: false, logger: false })

export default function MetadataEditorStateDrawer(): JSX.Element {
const {
isOpen: isDiscardChangesModalOpen,
onOpen: onDiscardChangesModalOpen,
onClose: onDiscardChangesModalClose,
} = useDisclosure()
const {
setDrawerState,
savedPageState,
setSavedPageState,
previewPageState,
setPreviewPageState,
} = useEditorDrawerContext()

const { pageId, siteId } = useQueryParse(editPageSchema)
const utils = trpc.useUtils()
const [{ content: pageContent }] = trpc.page.readPageAndBlob.useSuspenseQuery(
Expand All @@ -25,13 +48,6 @@ export default function MetadataEditorStateDrawer(): JSX.Element {
await utils.page.readPageAndBlob.invalidate({ pageId, siteId })
},
})
const {
setDrawerState,
savedPageState,
setSavedPageState,
previewPageState,
setPreviewPageState,
} = useEditorDrawerContext()

if (!previewPageState) {
return <></>
Expand All @@ -50,8 +66,20 @@ export default function MetadataEditorStateDrawer(): JSX.Element {
setPreviewPageState(newPageState)
}

const handleDiscardChanges = () => {
setPreviewPageState(savedPageState)
onDiscardChangesModalClose()
setDrawerState({ state: "root" })
}

return (
<>
<DiscardChangesModal
isOpen={isDiscardChangesModalOpen}
onClose={onDiscardChangesModalClose}
onDiscard={handleDiscardChanges}
/>

<Flex
flexDir="column"
position="relative"
Expand Down Expand Up @@ -87,8 +115,11 @@ export default function MetadataEditorStateDrawer(): JSX.Element {
size="sm"
p="0.625rem"
onClick={() => {
setPreviewPageState(savedPageState)
setDrawerState({ state: "root" })
if (!_.isEqual(previewPageState, savedPageState)) {
onDiscardChangesModalOpen()
} else {
handleDiscardChanges()
}
}}
aria-label="Close drawer"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default function RootStateDrawer() {

const from = result.source.index
const to = result.destination.index
const contentLength = savedPageState?.content.length ?? 0
const contentLength = savedPageState.content.length ?? 0

if (from >= contentLength || to >= contentLength || from < 0 || to < 0)
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
VStack,
} from "@chakra-ui/react"
import { Button, IconButton } from "@opengovsg/design-system-react"
import _ from "lodash"
import { BiText, BiTrash, BiX } from "react-icons/bi"

import { PROSE_COMPONENT_NAME } from "~/constants/formBuilder"
Expand All @@ -18,13 +19,24 @@ import { useQueryParse } from "~/hooks/useQueryParse"
import { editPageSchema } from "~/pages/sites/[siteId]/pages/[pageId]"
import { trpc } from "~/utils/trpc"
import { DeleteBlockModal } from "./DeleteBlockModal"
import { DiscardChangesModal } from "./DiscardChangesModal"
import { TiptapEditor } from "./form-builder/renderers/TipTapEditor"

interface TipTapComponentProps {
content: ProseProps
}

function TipTapComponent({ content }: TipTapComponentProps) {
const {
isOpen: isDeleteBlockModalOpen,
onOpen: onDeleteBlockModalOpen,
onClose: onDeleteBlockModalClose,
} = useDisclosure()
const {
isOpen: isDiscardChangesModalOpen,
onOpen: onDiscardChangesModalOpen,
onClose: onDiscardChangesModalClose,
} = useDisclosure()
const {
savedPageState,
setDrawerState,
Expand All @@ -33,11 +45,6 @@ function TipTapComponent({ content }: TipTapComponentProps) {
setPreviewPageState,
currActiveIdx,
} = useEditorDrawerContext()
const {
isOpen: isDeleteBlockModalOpen,
onOpen: onDeleteBlockModalOpen,
onClose: onDeleteBlockModalClose,
} = useDisclosure()

const { pageId, siteId } = useQueryParse(editPageSchema)

Expand Down Expand Up @@ -67,6 +74,12 @@ function TipTapComponent({ content }: TipTapComponentProps) {
setDrawerState({ state: "root" })
}

const handleDiscardChanges = () => {
setPreviewPageState(savedPageState)
onDiscardChangesModalClose()
setDrawerState({ state: "root" })
}

const utils = trpc.useUtils()

const { mutate } = trpc.page.updatePageBlob.useMutation({
Expand All @@ -88,6 +101,12 @@ function TipTapComponent({ content }: TipTapComponentProps) {
onDelete={handleDeleteBlock}
/>

<DiscardChangesModal
isOpen={isDiscardChangesModalOpen}
onClose={onDiscardChangesModalClose}
onDiscard={handleDiscardChanges}
/>

<VStack bg="white" h="100%" gap="0">
<Flex
px="2rem"
Expand All @@ -106,11 +125,14 @@ function TipTapComponent({ content }: TipTapComponentProps) {
variant="clear"
colorScheme="neutral"
color="interaction.sub.default"
aria-label="Close add component"
aria-label="Close drawer"
icon={<BiX />}
onClick={() => {
setDrawerState({ state: "root" })
setPreviewPageState(savedPageState)
if (!_.isEqual(previewPageState, savedPageState)) {
onDiscardChangesModalOpen()
} else {
handleDiscardChanges()
}
}}
/>
</Flex>
Expand Down

0 comments on commit 3058967

Please sign in to comment.