Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce discard changes modal #400

Merged
merged 1 commit into from
Jul 31, 2024
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
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
Loading