From 97cc9d91ae0f35967f7d2092940617631b7c4af7 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 19 Sep 2024 19:41:32 +0600 Subject: [PATCH 01/88] feat: implement action menu --- .../components/src/Action/Action.stories.tsx | 73 +++++++++++++++++++ packages/components/src/Action/Action.tsx | 51 +++++++++++++ packages/components/src/Action/index.ts | 11 +++ packages/components/src/Icon/all-icons.ts | 4 +- .../components/src/ToggleMenu/ToggleMenu.tsx | 27 ++++++- 5 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 packages/components/src/Action/Action.stories.tsx create mode 100644 packages/components/src/Action/Action.tsx create mode 100644 packages/components/src/Action/index.ts diff --git a/packages/components/src/Action/Action.stories.tsx b/packages/components/src/Action/Action.stories.tsx new file mode 100644 index 00000000000..7d4d62f3b77 --- /dev/null +++ b/packages/components/src/Action/Action.stories.tsx @@ -0,0 +1,73 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ +import { ComponentMeta, Story } from '@storybook/react' +import React from 'react' +import { Action } from './Action' +import { Icon } from '../Icon' + +export default { + title: 'Controls/Action', + component: Action, + parameters: { + docs: { + description: { + component: `This \`\` component lists all actions you have the scope for that can be applied on the current declaration / record. + \nAn action is disabled if you need to be assigned to perform the action.` + } + } + } +} as ComponentMeta + +const Template: Story = () => ( +
+ , + label: 'View record', + handler: () => alert('View record') + }, + { + icon: , + label: 'Print certified copy', + handler: () => alert('Print certified copy'), + isDisabled: true + }, + { + icon: , + label: 'Correct record', + handler: () => alert('Correct record'), + isDisabled: true + }, + { + icon: , + label: 'Revoke registration', + handler: () => alert('Revoke registration'), + isDisabled: true + }, + { + icon: , + label: 'Unassign', + handler: () => alert('Unassign') + } + ]} + headerText="Assigned to Felix Katongo at Ibombo District Office" + /> +
+) + +export const ActionView = Template.bind({}) +ActionView.args = { + recordStatus: 'Declared', + userScopes: ['declare', 'register'], + isAssigned: true +} diff --git a/packages/components/src/Action/Action.tsx b/packages/components/src/Action/Action.tsx new file mode 100644 index 00000000000..fde99747e58 --- /dev/null +++ b/packages/components/src/Action/Action.tsx @@ -0,0 +1,51 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ + +import React from 'react' +import { IToggleMenuItem, ToggleMenu } from '../ToggleMenu' +import { Icon } from '../Icon' +import styled from 'styled-components' + +const ActionButton = styled.div` + & > * { + margin: 10px; + } + display: flex; + justify-content: space-around; +` +const MenuHeader = styled.div` + white-space: normal; +` + +interface IProps { + id: string + menuItems: IToggleMenuItem[] + headerText?: string +} + +export const Action = ({ id, menuItems, headerText }: IProps) => { + return ( + +
Action
+ + + } + menuItems={menuItems} + menuHeader={ + headerText ? {headerText} : undefined + } + >
+ ) +} diff --git a/packages/components/src/Action/index.ts b/packages/components/src/Action/index.ts new file mode 100644 index 00000000000..89719b4b8a7 --- /dev/null +++ b/packages/components/src/Action/index.ts @@ -0,0 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ +export * from './Action' diff --git a/packages/components/src/Icon/all-icons.ts b/packages/components/src/Icon/all-icons.ts index 8ecc3a0f85f..743886fe183 100644 --- a/packages/components/src/Icon/all-icons.ts +++ b/packages/components/src/Icon/all-icons.ts @@ -67,6 +67,8 @@ export { WarningCircle, X, CircleWavyCheck, - CircleWavyQuestion + CircleWavyQuestion, + ArchiveBox, + ArrowCircleDown } from 'phosphor-react' export * from './custom-icons' diff --git a/packages/components/src/ToggleMenu/ToggleMenu.tsx b/packages/components/src/ToggleMenu/ToggleMenu.tsx index d66d17bf7e6..60d33f06b85 100644 --- a/packages/components/src/ToggleMenu/ToggleMenu.tsx +++ b/packages/components/src/ToggleMenu/ToggleMenu.tsx @@ -12,6 +12,7 @@ import styled from 'styled-components' import React, { useEffect, useRef, useState } from 'react' import { Button } from '../Button' import { noop } from 'lodash' +import { disabled } from '../Button/Button.styles' const ToggleMenuContainer = styled.nav` position: relative; @@ -47,7 +48,12 @@ const MenuHeader = styled.li` margin-bottom: 6px; border-bottom: 1px solid ${({ theme }) => theme.colors.grey300}; ` -const MenuItem = styled.li` + +interface MenuItemProps extends React.HTMLAttributes { + disabled?: boolean +} + +const MenuItem = styled.li` ${({ theme }) => theme.fonts.bold14}; color: ${({ theme }) => theme.colors.grey500}; display: flex; @@ -69,18 +75,31 @@ const MenuItem = styled.li` &:focus-visible { background-color: ${({ theme }) => theme.colors.yellow}; } + ${(props) => props.disabled && disabled} ` export interface IToggleMenuItem { label: string icon?: JSX.Element handler: () => void + isDisabled?: boolean } +type ButtonType = + | 'primary' + | 'secondary' + | 'tertiary' + | 'positive' + | 'negative' + | 'secondary_negative' + | 'icon' + | 'iconPrimary' + interface IProps { id: string menuHeader?: JSX.Element toggleButton: JSX.Element + toggleButtonType?: ButtonType menuItems: IToggleMenuItem[] hide?: boolean } @@ -89,6 +108,7 @@ export const ToggleMenu = ({ id, menuHeader, toggleButton, + toggleButtonType = 'icon', menuItems, hide }: IProps) => { @@ -131,7 +151,7 @@ export const ToggleMenu = ({ <> {showSubmenu && ( - + {menuHeader && {menuHeader}} {menuItems.map((mi: IToggleMenuItem, index) => ( (itemRefs.current[index] = el)} + onFocus={() => setFocusedIndex(index)} onClick={mi.handler} - onKeyUp={(e) => - e.key === 'Enter' || e.key === ' ' ? mi.handler() : noop - } tabIndex={mi.isDisabled ? -1 : 0} role="button" disabled={mi.isDisabled} From d7cc771e9f184b65a6dbc0beca7033bd6f66d7f1 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Mon, 23 Sep 2024 20:16:06 +0600 Subject: [PATCH 04/88] feat: implement `Dropdown` component --- .../src/Dropdown/Dropdown.stories.tsx | 78 ++++++++ packages/components/src/Dropdown/Dropdown.tsx | 175 ++++++++++++++++++ .../src/Dropdown/DropdownContext.tsx | 43 +++++ packages/components/src/Dropdown/index.ts | 11 ++ 4 files changed, 307 insertions(+) create mode 100644 packages/components/src/Dropdown/Dropdown.stories.tsx create mode 100644 packages/components/src/Dropdown/Dropdown.tsx create mode 100644 packages/components/src/Dropdown/DropdownContext.tsx create mode 100644 packages/components/src/Dropdown/index.ts diff --git a/packages/components/src/Dropdown/Dropdown.stories.tsx b/packages/components/src/Dropdown/Dropdown.stories.tsx new file mode 100644 index 00000000000..248891a3766 --- /dev/null +++ b/packages/components/src/Dropdown/Dropdown.stories.tsx @@ -0,0 +1,78 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ +import { Meta } from '@storybook/react' +import { DropdownMenu, IDropdownPosition } from './Dropdown' +import React from 'react' +import { PrimaryButton } from '../../src/buttons' + +const Template = (args: { + position: IDropdownPosition + offset_x: number + offset_y: number +}) => ( +
+ + + Click Me + + +
+ City + + alert('Dhaka is the capital of Bangladesh')} + > + Dhaka + + alert('Helsinki is the capital of Finland')} + > + Helsinki + +
+ +
+ Season + + alert('Winter is cold')} + disabled={true} + > + Winter + + alert('Summer is hot')}> + Summer + +
+
+
+
+) +export const DropdownView = Template.bind({}) +DropdownView.args = { + position: 'bottom-left', + offset_x: 0, + offset_y: 10 +} + +export default { + title: 'Controls/Dropdown', + component: DropdownView +} as Meta diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx new file mode 100644 index 00000000000..22b29229adf --- /dev/null +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -0,0 +1,175 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ + +import React, { ReactNode } from 'react' +import { disabled } from '../Button/Button.styles' +import styled from 'styled-components' +import { DropdownProvider, useDropdown } from './DropdownContext' + +const StyledWrapper = styled.nav` + position: relative; + height: 40px; + display: flex; + + button { + padding: 0; + height: auto; + } +` + +const StyledContent = styled.ul<{ + position: string + offset_x: number + offset_y: number +}>` + border-radius: 4px; + border: 1px solid ${({ theme }) => theme.colors.grey300}; + background-color: ${({ theme }) => theme.colors.white}; + ${({ theme }) => theme.shadows.light}; + text-align: left; + min-width: 200px; + width: auto; + white-space: nowrap; + position: absolute; + z-index: 2; + display: flex; + flex-direction: column; + padding: 8px 0; + margin: ${({ offset_x, offset_y }) => `${offset_x}px ${offset_y}px`}; + list-style: none; + + ${({ position }) => { + switch (position) { + case 'top': + return 'bottom: 100%; left: 50%; transform: translateX(-50%);' + case 'top-right': + return 'bottom: 100%; left: 0;' + case 'top-left': + return 'bottom: 100%; right: 0;' + case 'bottom': + return 'top: 100%; left: 50%; transform: translateX(-50%);' + case 'bottom-right': + return 'top: 100%; left: 0;' + case 'bottom-left': + return 'top: 100%; right: 0;' + case 'right': + return 'top: 50%; left: 100%; transform: translateY(-50%);' + case 'left': + return 'top: 50%; right: 100%; transform: translateY(-50%);' + default: + return '' + } + }} +` + +const Label = styled.li` + padding: 6px 12px; +` + +const Separator = styled.div<{ weight: number }>` + border-bottom: ${({ weight }) => `${weight}px solid `} + ${({ theme }) => theme.colors.grey300}; + margin: 4px 0; +` + +const MenuItem = styled.li<{ disabled?: boolean }>` + ${({ theme }) => theme.fonts.bold14}; + color: ${({ theme }) => theme.colors.grey500}; + display: flex; + align-items: center; + gap: 8px; + outline: none; + cursor: pointer; + margin: 0 6px; + border-radius: 4px; + padding: 8px 12px; + &:hover { + background: ${({ theme }) => theme.colors.grey100}; + color: ${({ theme }) => theme.colors.grey600}; + } + &:active { + background: ${({ theme }) => theme.colors.grey200}; + color: ${({ theme }) => theme.colors.grey600}; + } + &:focus-visible { + background-color: ${({ theme }) => theme.colors.yellow}; + } + ${(props) => props.disabled && disabled} +` + +export type IDropdownPosition = + | 'top' + | 'top-left' + | 'top-right' + | 'bottom' + | 'bottom-left' + | 'bottom-right' + | 'left' + | 'right' + +export const DropdownMenu = ({ children }: { children: ReactNode }) => { + return ( + + {children} + + ) +} + +const Trigger: React.FC<{ children: JSX.Element }> = ({ children }) => { + const { toggleDropdown } = useDropdown() + return React.cloneElement(children, { onClick: toggleDropdown }) +} +DropdownMenu.Trigger = Trigger + +const Content: React.FC<{ + position: string + offset_x: number + offset_y: number + children: ReactNode +}> = ({ position, offset_x, offset_y, children }) => { + const { isOpen } = useDropdown() + + return ( + isOpen && ( + + {children} + + ) + ) +} + +DropdownMenu.Content = Content + +DropdownMenu.Label = ({ children }: { children: string }) => ( + +) + +DropdownMenu.Item = ({ + onClick, + children, + disabled = false +}: { + onClick: () => void + children: ReactNode + disabled?: boolean +}) => ( + + {children} + +) + +DropdownMenu.Separator = ({ weight = 1 }: { weight?: number }) => ( + +) diff --git a/packages/components/src/Dropdown/DropdownContext.tsx b/packages/components/src/Dropdown/DropdownContext.tsx new file mode 100644 index 00000000000..e49b5264fb4 --- /dev/null +++ b/packages/components/src/Dropdown/DropdownContext.tsx @@ -0,0 +1,43 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ + +import React, { createContext, useContext, useState } from 'react' + +interface DropdownContextType { + isOpen: boolean + toggleDropdown: () => void +} + +const DropdownContext = createContext( + undefined +) + +export const useDropdown = () => { + const context = useContext(DropdownContext) + if (!context) { + throw new Error('useDropdown must be used within a DropdownProvider') + } + return context +} + +export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ + children +}) => { + const [isOpen, setIsOpen] = useState(false) + + const toggleDropdown = () => setIsOpen((prev) => !prev) + + return ( + + {children} + + ) +} diff --git a/packages/components/src/Dropdown/index.ts b/packages/components/src/Dropdown/index.ts new file mode 100644 index 00000000000..6ef906408a5 --- /dev/null +++ b/packages/components/src/Dropdown/index.ts @@ -0,0 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ +export * from './Dropdown' From 6dea8e310880a9b7cd2d7e8bbeee6fcffea43a91 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 24 Sep 2024 16:27:40 +0600 Subject: [PATCH 05/88] feat: make dropdownMenu keyboard accessible --- packages/components/src/Dropdown/Dropdown.tsx | 48 +++++++++------ .../src/Dropdown/DropdownContext.tsx | 60 ++++++++++++++++++- 2 files changed, 87 insertions(+), 21 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 22b29229adf..bd5231e0c01 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -137,17 +137,11 @@ const Content: React.FC<{ }> = ({ position, offset_x, offset_y, children }) => { const { isOpen } = useDropdown() - return ( - isOpen && ( - - {children} - - ) - ) + return isOpen ? ( + + {children} + + ) : null } DropdownMenu.Content = Content @@ -156,19 +150,37 @@ DropdownMenu.Label = ({ children }: { children: string }) => ( ) -DropdownMenu.Item = ({ - onClick, +const Item = ({ + onClick: onClickHandler, children, disabled = false }: { onClick: () => void children: ReactNode disabled?: boolean -}) => ( - - {children} - -) +}) => { + const { addItemRef, handleKeyDown, toggleDropdown } = useDropdown() + + const keyDownhandler = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + onClickHandler() + toggleDropdown() + } else handleKeyDown(e) + } + + return ( + addItemRef(item)} + onKeyDown={keyDownhandler} + > + {children} + + ) +} +DropdownMenu.Item = Item DropdownMenu.Separator = ({ weight = 1 }: { weight?: number }) => ( diff --git a/packages/components/src/Dropdown/DropdownContext.tsx b/packages/components/src/Dropdown/DropdownContext.tsx index e49b5264fb4..d438fe22006 100644 --- a/packages/components/src/Dropdown/DropdownContext.tsx +++ b/packages/components/src/Dropdown/DropdownContext.tsx @@ -1,3 +1,4 @@ +import * as F from 'fp-ts' /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -9,11 +10,19 @@ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import React, { createContext, useContext, useState } from 'react' +import React, { + createContext, + useContext, + useEffect, + useRef, + useState +} from 'react' interface DropdownContextType { isOpen: boolean toggleDropdown: () => void + addItemRef: (item: HTMLLIElement | null) => void + handleKeyDown: (e: React.KeyboardEvent) => void } const DropdownContext = createContext( @@ -33,10 +42,55 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ }) => { const [isOpen, setIsOpen] = useState(false) - const toggleDropdown = () => setIsOpen((prev) => !prev) + const [focusedIndex, setFocusedIndex] = useState(-1) + const itemRefs = useRef<(HTMLLIElement | null)[]>([]) + + const addItemRef = (item: HTMLLIElement | null) => { + if (item && item.tabIndex === 0 && !itemRefs.current.includes(item)) { + itemRefs.current.push(item) + if (itemRefs.current.length === 1) itemRefs.current[0]?.focus() + } + } + + const toggleDropdown = () => { + itemRefs.current = [] + if (!isOpen) { + setFocusedIndex(-1) + } + setIsOpen((prev) => !prev) + } + + const getNextIndex = (last: number) => { + return Math.min(last + 1, itemRefs.current.length - 1) + } + + const getPreviousIndex = (last: number) => { + return Math.max(last - 1, 0) + } + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'ArrowDown') { + setFocusedIndex(getNextIndex) + } else if (e.key === 'ArrowUp') { + setFocusedIndex(getPreviousIndex) + } + } + + useEffect(() => { + if (focusedIndex !== null && itemRefs.current[focusedIndex]) { + itemRefs.current[focusedIndex]?.focus() + } + }, [focusedIndex]) return ( - + {children} ) From bd370248998468cf32837922d8a01a09d624a0e1 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 24 Sep 2024 16:41:32 +0600 Subject: [PATCH 06/88] feat: make dropdownMenu close on click outside and esc --- packages/components/src/Dropdown/Dropdown.tsx | 34 ++++++++++++++++--- .../src/Dropdown/DropdownContext.tsx | 4 +++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index bd5231e0c01..019c54ae0c8 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -9,7 +9,7 @@ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import React, { ReactNode } from 'react' +import React, { ReactNode, useEffect, useRef } from 'react' import { disabled } from '../Button/Button.styles' import styled from 'styled-components' import { DropdownProvider, useDropdown } from './DropdownContext' @@ -135,10 +135,33 @@ const Content: React.FC<{ offset_y: number children: ReactNode }> = ({ position, offset_x, offset_y, children }) => { - const { isOpen } = useDropdown() + const { isOpen, closeDropdown } = useDropdown() + + const contentRef = useRef(null) + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + contentRef.current && + !contentRef.current.contains(event.target as Node) + ) { + closeDropdown() + } + } + + document.addEventListener('mousedown', handleClickOutside) + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, [closeDropdown]) return isOpen ? ( - + {children} ) : null @@ -159,12 +182,15 @@ const Item = ({ children: ReactNode disabled?: boolean }) => { - const { addItemRef, handleKeyDown, toggleDropdown } = useDropdown() + const { addItemRef, handleKeyDown, toggleDropdown, closeDropdown } = + useDropdown() const keyDownhandler = (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { onClickHandler() toggleDropdown() + } else if (e.key === 'Escape') { + closeDropdown() } else handleKeyDown(e) } diff --git a/packages/components/src/Dropdown/DropdownContext.tsx b/packages/components/src/Dropdown/DropdownContext.tsx index d438fe22006..2048d7f300c 100644 --- a/packages/components/src/Dropdown/DropdownContext.tsx +++ b/packages/components/src/Dropdown/DropdownContext.tsx @@ -21,6 +21,7 @@ import React, { interface DropdownContextType { isOpen: boolean toggleDropdown: () => void + closeDropdown: () => void addItemRef: (item: HTMLLIElement | null) => void handleKeyDown: (e: React.KeyboardEvent) => void } @@ -52,6 +53,8 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ } } + const closeDropdown = () => isOpen && toggleDropdown() + const toggleDropdown = () => { itemRefs.current = [] if (!isOpen) { @@ -87,6 +90,7 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ value={{ isOpen, toggleDropdown, + closeDropdown, addItemRef, handleKeyDown }} From 3bd63c278299b7cd5ad9b8ac40590e5510296100 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 24 Sep 2024 18:03:27 +0600 Subject: [PATCH 07/88] fix: make some props optional --- packages/components/src/Dropdown/Dropdown.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 019c54ae0c8..cf10274c882 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -43,7 +43,7 @@ const StyledContent = styled.ul<{ display: flex; flex-direction: column; padding: 8px 0; - margin: ${({ offset_x, offset_y }) => `${offset_x}px ${offset_y}px`}; + margin: ${({ offset_x, offset_y }) => `${offset_y}px ${offset_x}px`}; list-style: none; ${({ position }) => { @@ -130,11 +130,11 @@ const Trigger: React.FC<{ children: JSX.Element }> = ({ children }) => { DropdownMenu.Trigger = Trigger const Content: React.FC<{ - position: string - offset_x: number - offset_y: number + position?: string + offset_x?: number + offset_y?: number children: ReactNode -}> = ({ position, offset_x, offset_y, children }) => { +}> = ({ position = 'bottom-left', offset_x = 0, offset_y = 10, children }) => { const { isOpen, closeDropdown } = useDropdown() const contentRef = useRef(null) @@ -174,11 +174,11 @@ DropdownMenu.Label = ({ children }: { children: string }) => ( ) const Item = ({ - onClick: onClickHandler, + onClick: onClickHandler = () => {}, children, disabled = false }: { - onClick: () => void + onClick?: () => void children: ReactNode disabled?: boolean }) => { From 95e9b1002eed3f04dfd94e7ebbdfe666c7a166b9 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 24 Sep 2024 19:31:07 +0600 Subject: [PATCH 08/88] fix: close menu on ouside click --- packages/components/src/Dropdown/Dropdown.tsx | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index cf10274c882..d5e70ea2ab7 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -115,10 +115,28 @@ export type IDropdownPosition = | 'left' | 'right' +const DropdownWrapper: React.FC<{ children: ReactNode }> = ({ children }) => { + const { closeDropdown } = useDropdown() + const rootRef = useRef(null) + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (rootRef.current && !rootRef.current.contains(event.target as Node)) { + closeDropdown() + } + } + + document.addEventListener('mousedown', handleClickOutside) + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, [closeDropdown]) + return {children} +} + export const DropdownMenu = ({ children }: { children: ReactNode }) => { return ( - {children} + {children} ) } @@ -135,33 +153,10 @@ const Content: React.FC<{ offset_y?: number children: ReactNode }> = ({ position = 'bottom-left', offset_x = 0, offset_y = 10, children }) => { - const { isOpen, closeDropdown } = useDropdown() - - const contentRef = useRef(null) - - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - contentRef.current && - !contentRef.current.contains(event.target as Node) - ) { - closeDropdown() - } - } - - document.addEventListener('mousedown', handleClickOutside) - return () => { - document.removeEventListener('mousedown', handleClickOutside) - } - }, [closeDropdown]) + const { isOpen } = useDropdown() return isOpen ? ( - + {children} ) : null From 60e3bfe2b0efc9ec96382c2706fc1077523162d4 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 24 Sep 2024 20:33:40 +0600 Subject: [PATCH 09/88] feat: create actionMenu --- packages/client/src/i18n/messages/buttons.ts | 2 +- .../client/src/i18n/messages/views/action.ts | 31 ++++ .../src/views/RecordAudit/ActionMenu.tsx | 136 ++++++++++++++++++ .../src/views/RecordAudit/RecordAudit.tsx | 14 ++ packages/components/src/Icon/all-icons.ts | 4 +- 5 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 packages/client/src/i18n/messages/views/action.ts create mode 100644 packages/client/src/views/RecordAudit/ActionMenu.tsx diff --git a/packages/client/src/i18n/messages/buttons.ts b/packages/client/src/i18n/messages/buttons.ts index 9f2d75fd818..bee6fadb7e1 100644 --- a/packages/client/src/i18n/messages/buttons.ts +++ b/packages/client/src/i18n/messages/buttons.ts @@ -81,7 +81,7 @@ interface IButtonsMessages const messagesToDefine: IButtonsMessages = { archive: { id: 'buttons.archive', - defaultMessage: 'Archive', + defaultMessage: 'Archive declaration', description: 'Archive button text' }, approve: { diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts new file mode 100644 index 00000000000..91ab015ccfc --- /dev/null +++ b/packages/client/src/i18n/messages/views/action.ts @@ -0,0 +1,31 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ +import { defineMessages, MessageDescriptor } from 'react-intl' + +interface IActionMessages + extends Record { + view: MessageDescriptor + correctRecord: MessageDescriptor +} + +const messagesToDefine: IActionMessages = { + view: { + defaultMessage: 'View {recordOrDeclaration}', + description: 'Label for view button in dropdown menu', + id: 'action.view' + }, + correctRecord: { + defaultMessage: 'Correct Record', + description: 'Label for correct record button in dropdown menu', + id: 'action.correct' + } +} +export const messages: IActionMessages = defineMessages(messagesToDefine) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx new file mode 100644 index 00000000000..8c0e92b4fcd --- /dev/null +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -0,0 +1,136 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ + +import React from 'react' +import { DropdownMenu } from '@opencrvs/components/lib/Dropdown' +import { PrimaryButton } from '@opencrvs/components/lib/buttons' +import { CaretDown } from '@opencrvs/components/lib/Icon/all-icons' +import { useDispatch } from 'react-redux' +import { Icon } from '@opencrvs/components' +import { + goToCertificateCorrection, + goToPage, + goToViewRecordPage +} from '@client/navigation' +import { IntlShape } from 'react-intl' +import { Scope } from '@sentry/react' +import { IDeclarationData } from './utils' +import { + clearCorrectionAndPrintChanges, + IDeclaration, + SUBMISSION_STATUS +} from '@client/declarations' +import { CorrectionSection } from '@client/forms' +import { buttonMessages, constantsMessages } from '@client/i18n/messages' +import { UserDetails } from '@client/utils/userUtils' +import { EVENT_STATUS } from '@client/workqueue' +import { + REVIEW_CORRECTION, + REVIEW_EVENT_PARENT_FORM_PAGE +} from '@client/navigation/routes' +import { messages } from '@client/i18n/messages/views/action' + +export const ActionMenu: React.FC<{ + declaration: IDeclarationData + intl: IntlShape + scope: Scope | null + draft: IDeclaration | null + userDetails: UserDetails | null + toggleDisplayDialog: () => void + goToPage: typeof goToPage +}> = ({ + declaration, + intl, + scope, + draft, + userDetails, + toggleDisplayDialog, + goToPage +}) => { + const dispatch = useDispatch() + + const recordOrDeclaration = [ + SUBMISSION_STATUS.REGISTERED, + SUBMISSION_STATUS.CORRECTION_REQUESTED, + SUBMISSION_STATUS.CERTIFIED + ].includes(declaration.status as any as SUBMISSION_STATUS) + ? 'record' + : 'declaration' + + const ViewAction = () => ( + { + dispatch(goToViewRecordPage(declaration.id as string)) + }} + > + + {intl.formatMessage(messages.view, { recordOrDeclaration })} + + ) + + const CorrectRecordAction = () => ( + { + clearCorrectionAndPrintChanges(declaration.id) + goToCertificateCorrection(declaration.id, CorrectionSection.Corrector) + }} + > + + {intl.formatMessage(messages.correctRecord)} + + ) + + const ArchiveAction = () => ( + + + {intl.formatMessage(buttonMessages.archive)} + + ) + + const ReinstateAction = () => ( + + + {intl.formatMessage(buttonMessages.reinstate)} + + ) + + const ReviewAction = () => { + const { id, type } = declaration + return ( + { + if (declaration.status === EVENT_STATUS.CORRECTION_REQUESTED) { + goToPage(REVIEW_CORRECTION, id, 'review', type!) + } else { + goToPage(REVIEW_EVENT_PARENT_FORM_PAGE, id, 'review', type!) + } + }} + > + + {intl.formatMessage(constantsMessages.review)} + + ) + } + return ( + + + }> Action + + + + + + + + + + ) +} diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index 87d0da4c2c1..ca5a7795a69 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -126,6 +126,7 @@ import { Icon } from '@opencrvs/components/lib/Icon' import { UserDetails } from '@client/utils/userUtils' import { client } from '@client/utils/apolloClient' import { IReviewFormState } from '@client/forms/register/reviewReducer' +import { ActionMenu } from './ActionMenu' const DesktopHeader = styled(Header)` @media (max-width: ${({ theme }) => theme.grid.breakpoints.lg}px) { @@ -522,6 +523,19 @@ function RecordAuditBody({ ) } + actions.push( + + ) + desktopActionsView.push(actions[actions.length - 1]) + if (!isDownloaded) { actions.push( ShowDownloadButton({ diff --git a/packages/components/src/Icon/all-icons.ts b/packages/components/src/Icon/all-icons.ts index 743886fe183..4a8f7fb6b4f 100644 --- a/packages/components/src/Icon/all-icons.ts +++ b/packages/components/src/Icon/all-icons.ts @@ -69,6 +69,8 @@ export { CircleWavyCheck, CircleWavyQuestion, ArchiveBox, - ArrowCircleDown + ArrowCircleDown, + FileArrowUp, + PencilLine } from 'phosphor-react' export * from './custom-icons' From e46dc9479c3bfb26e9c09d2575af920e743d50b3 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 25 Sep 2024 15:34:56 +0600 Subject: [PATCH 10/88] feat: add `Update`, `Print`, `Issue`, `Delete` items --- .../client/src/i18n/messages/views/action.ts | 6 ++ .../src/views/RecordAudit/ActionMenu.tsx | 102 ++++++++++++++++-- .../src/views/RecordAudit/RecordAudit.tsx | 1 + packages/components/src/Icon/all-icons.ts | 4 +- 4 files changed, 104 insertions(+), 9 deletions(-) diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts index 91ab015ccfc..fab4905617f 100644 --- a/packages/client/src/i18n/messages/views/action.ts +++ b/packages/client/src/i18n/messages/views/action.ts @@ -12,11 +12,17 @@ import { defineMessages, MessageDescriptor } from 'react-intl' interface IActionMessages extends Record { + action: MessageDescriptor view: MessageDescriptor correctRecord: MessageDescriptor } const messagesToDefine: IActionMessages = { + action: { + defaultMessage: 'Action', + description: 'Label for action button in dropdown menu', + id: 'action.action' + }, view: { defaultMessage: 'View {recordOrDeclaration}', description: 'Label for view button in dropdown menu', diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 8c0e92b4fcd..af624b2ae49 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -17,7 +17,9 @@ import { useDispatch } from 'react-redux' import { Icon } from '@opencrvs/components' import { goToCertificateCorrection, + goToIssueCertificate, goToPage, + goToPrintCertificate, goToViewRecordPage } from '@client/navigation' import { IntlShape } from 'react-intl' @@ -25,6 +27,7 @@ import { Scope } from '@sentry/react' import { IDeclarationData } from './utils' import { clearCorrectionAndPrintChanges, + DOWNLOAD_STATUS, IDeclaration, SUBMISSION_STATUS } from '@client/declarations' @@ -33,6 +36,9 @@ import { buttonMessages, constantsMessages } from '@client/i18n/messages' import { UserDetails } from '@client/utils/userUtils' import { EVENT_STATUS } from '@client/workqueue' import { + DRAFT_BIRTH_PARENT_FORM_PAGE, + DRAFT_DEATH_FORM_PAGE, + DRAFT_MARRIAGE_FORM_PAGE, REVIEW_CORRECTION, REVIEW_EVENT_PARENT_FORM_PAGE } from '@client/navigation/routes' @@ -46,6 +52,7 @@ export const ActionMenu: React.FC<{ userDetails: UserDetails | null toggleDisplayDialog: () => void goToPage: typeof goToPage + goToPrintCertificate: typeof goToPrintCertificate }> = ({ declaration, intl, @@ -53,9 +60,14 @@ export const ActionMenu: React.FC<{ draft, userDetails, toggleDisplayDialog, - goToPage + goToPage, + goToPrintCertificate }) => { const dispatch = useDispatch() + const { id, type } = declaration + const isDownloaded = + draft?.downloadStatus === DOWNLOAD_STATUS.DOWNLOADED || + draft?.submissionStatus === SUBMISSION_STATUS.DRAFT const recordOrDeclaration = [ SUBMISSION_STATUS.REGISTERED, @@ -68,7 +80,7 @@ export const ActionMenu: React.FC<{ const ViewAction = () => ( { - dispatch(goToViewRecordPage(declaration.id as string)) + dispatch(goToViewRecordPage(id as string)) }} > @@ -79,9 +91,10 @@ export const ActionMenu: React.FC<{ const CorrectRecordAction = () => ( { - clearCorrectionAndPrintChanges(declaration.id) - goToCertificateCorrection(declaration.id, CorrectionSection.Corrector) + clearCorrectionAndPrintChanges(id) + goToCertificateCorrection(id, CorrectionSection.Corrector) }} + disabled={!isDownloaded} > {intl.formatMessage(messages.correctRecord)} @@ -89,21 +102,20 @@ export const ActionMenu: React.FC<{ ) const ArchiveAction = () => ( - + {intl.formatMessage(buttonMessages.archive)} ) const ReinstateAction = () => ( - + {intl.formatMessage(buttonMessages.reinstate)} ) const ReviewAction = () => { - const { id, type } = declaration return ( { @@ -113,16 +125,86 @@ export const ActionMenu: React.FC<{ goToPage(REVIEW_EVENT_PARENT_FORM_PAGE, id, 'review', type!) } }} + disabled={!isDownloaded} > {intl.formatMessage(constantsMessages.review)} ) } + + const DeleteAction = () => { + return ( + {}}> + + {intl.formatMessage(buttonMessages.deleteDeclaration)} + + ) + } + + const UpdateAction = () => { + let PAGE_ROUTE: string, PAGE_ID: string + + if (declaration?.status === SUBMISSION_STATUS.DRAFT) { + PAGE_ID = 'preview' + if (type === 'birth') { + PAGE_ROUTE = DRAFT_BIRTH_PARENT_FORM_PAGE + } else if (type === 'death') { + PAGE_ROUTE = DRAFT_DEATH_FORM_PAGE + } else if (type === 'marriage') { + PAGE_ROUTE = DRAFT_MARRIAGE_FORM_PAGE + } + } else { + PAGE_ROUTE = REVIEW_EVENT_PARENT_FORM_PAGE + PAGE_ID = 'review' + } + return ( + { + goToPage && goToPage(PAGE_ROUTE, id, PAGE_ID, type) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(buttonMessages.update)} + + ) + } + + const PrintAction = () => ( + { + clearCorrectionAndPrintChanges && + clearCorrectionAndPrintChanges(declaration.id) + goToPrintCertificate && + goToPrintCertificate(id, type.toLocaleLowerCase()) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(buttonMessages.print)} + + ) + + const IssueAction = () => ( + { + dispatch(clearCorrectionAndPrintChanges(id)) + dispatch(goToIssueCertificate(id)) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(buttonMessages.issue)} + + ) + return ( - }> Action + }> + {intl.formatMessage(messages.action)} + @@ -130,6 +212,10 @@ export const ActionMenu: React.FC<{ + + + + ) diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index ca5a7795a69..0025143a852 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -532,6 +532,7 @@ function RecordAuditBody({ userDetails={userDetails} toggleDisplayDialog={toggleDisplayDialog} goToPage={goToPage} + goToPrintCertificate={goToPrintCertificate} /> ) desktopActionsView.push(actions[actions.length - 1]) diff --git a/packages/components/src/Icon/all-icons.ts b/packages/components/src/Icon/all-icons.ts index 4a8f7fb6b4f..924ce8a5c1c 100644 --- a/packages/components/src/Icon/all-icons.ts +++ b/packages/components/src/Icon/all-icons.ts @@ -71,6 +71,8 @@ export { ArchiveBox, ArrowCircleDown, FileArrowUp, - PencilLine + PencilLine, + PencilCircle, + Handshake } from 'phosphor-react' export * from './custom-icons' From 48a0c3b8ab88b273ec2cf9c8c292af422c886aef Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 25 Sep 2024 16:18:16 +0600 Subject: [PATCH 11/88] feat: implement delete declaration --- .../src/views/RecordAudit/ActionMenu.tsx | 27 ++++++- .../src/views/RegisterForm/RegisterForm.tsx | 80 ++++++++++--------- 2 files changed, 66 insertions(+), 41 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index af624b2ae49..72e22d7c705 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -27,6 +27,7 @@ import { Scope } from '@sentry/react' import { IDeclarationData } from './utils' import { clearCorrectionAndPrintChanges, + deleteDeclaration, DOWNLOAD_STATUS, IDeclaration, SUBMISSION_STATUS @@ -43,6 +44,9 @@ import { REVIEW_EVENT_PARENT_FORM_PAGE } from '@client/navigation/routes' import { messages } from '@client/i18n/messages/views/action' +import { useModal } from '@client/hooks/useModal' +import { DeleteModal } from '@client/views/RegisterForm/RegisterForm' +import { client } from '@client/utils/apolloClient' export const ActionMenu: React.FC<{ declaration: IDeclarationData @@ -134,11 +138,26 @@ export const ActionMenu: React.FC<{ } const DeleteAction = () => { + const [modal, openModal] = useModal() + const dispatch = useDispatch() + return ( - {}}> - - {intl.formatMessage(buttonMessages.deleteDeclaration)} - + <> + { + const deleteConfirm = await openModal((close) => ( + + )) + + deleteConfirm && dispatch(deleteDeclaration(declaration.id, client)) + return + }} + > + + {intl.formatMessage(buttonMessages.deleteDeclaration)} + + {modal} + ) } diff --git a/packages/client/src/views/RegisterForm/RegisterForm.tsx b/packages/client/src/views/RegisterForm/RegisterForm.tsx index 46f9b09b4f8..c00550401a0 100644 --- a/packages/client/src/views/RegisterForm/RegisterForm.tsx +++ b/packages/client/src/views/RegisterForm/RegisterForm.tsx @@ -11,6 +11,7 @@ import * as React from 'react' import { FormikTouched, FormikValues } from 'formik' import { + IntlShape, WrappedComponentProps as IntlShapeProps, injectIntl, useIntl @@ -207,6 +208,47 @@ function getDeclarationIconColor(declaration: IDeclaration): string { : 'orange' } +export const DeleteModal: React.FC<{ + intl: IntlShape + close: (result: boolean | null) => void +}> = ({ intl, close }) => ( + { + close(null) + }} + > + {intl.formatMessage(buttonMessages.cancel)} + , + + ]} + show={true} + handleClose={() => close(null)} + > + + + {intl.formatMessage(messages.deleteDeclarationConfirmModalDescription)} + + + +) + function FormAppBar({ section, declaration, @@ -384,43 +426,7 @@ function FormAppBar({ const handleDelete = async () => { const deleteConfirm = await openModal((close) => ( - { - close(null) - }} - > - {intl.formatMessage(buttonMessages.cancel)} - , - - ]} - show={true} - handleClose={() => close(null)} - > - - - {intl.formatMessage( - messages.deleteDeclarationConfirmModalDescription - )} - - - + )) deleteConfirm && deleteDeclarationMethod(declaration) From c8723449d02c757ae18eb4f6a5571780cd0b87a7 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 25 Sep 2024 16:43:35 +0600 Subject: [PATCH 12/88] feat: redirect to home after deleting draft --- .../src/views/RecordAudit/ActionMenu.tsx | 81 ++++++++++--------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 72e22d7c705..b41fb25b1b3 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -17,6 +17,7 @@ import { useDispatch } from 'react-redux' import { Icon } from '@opencrvs/components' import { goToCertificateCorrection, + goToHome, goToIssueCertificate, goToPage, goToPrintCertificate, @@ -68,7 +69,10 @@ export const ActionMenu: React.FC<{ goToPrintCertificate }) => { const dispatch = useDispatch() + const [modal, openModal] = useModal() + const { id, type } = declaration + const isDownloaded = draft?.downloadStatus === DOWNLOAD_STATUS.DOWNLOADED || draft?.submissionStatus === SUBMISSION_STATUS.DRAFT @@ -138,26 +142,22 @@ export const ActionMenu: React.FC<{ } const DeleteAction = () => { - const [modal, openModal] = useModal() - const dispatch = useDispatch() - return ( - <> - { - const deleteConfirm = await openModal((close) => ( - - )) - - deleteConfirm && dispatch(deleteDeclaration(declaration.id, client)) - return - }} - > - - {intl.formatMessage(buttonMessages.deleteDeclaration)} - - {modal} - + { + const deleteConfirm = await openModal((close) => ( + + )) + if (deleteConfirm) { + dispatch(deleteDeclaration(declaration.id, client)) + dispatch(goToHome()) + } + return + }} + > + + {intl.formatMessage(buttonMessages.deleteDeclaration)} + ) } @@ -180,7 +180,7 @@ export const ActionMenu: React.FC<{ return ( { - goToPage && goToPage(PAGE_ROUTE, id, PAGE_ID, type) + goToPage && goToPage(PAGE_ROUTE, id, PAGE_ID, type as string) }} disabled={!isDownloaded} > @@ -196,7 +196,7 @@ export const ActionMenu: React.FC<{ clearCorrectionAndPrintChanges && clearCorrectionAndPrintChanges(declaration.id) goToPrintCertificate && - goToPrintCertificate(id, type.toLocaleLowerCase()) + goToPrintCertificate(id, (type as string).toLocaleLowerCase()) }} disabled={!isDownloaded} > @@ -219,23 +219,26 @@ export const ActionMenu: React.FC<{ ) return ( - - - }> - {intl.formatMessage(messages.action)} - - - - - - - - - - - - - - + <> + + + }> + {intl.formatMessage(messages.action)} + + + + + + + + + + + + + + + {modal} + ) } From a6ff23454c35abb473bd68846e4639d5a1b49a93 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 25 Sep 2024 17:24:11 +0600 Subject: [PATCH 13/88] feat: add label for assigned to someone else --- packages/client/src/i18n/messages/views/action.ts | 6 ++++++ .../client/src/views/RecordAudit/ActionMenu.tsx | 13 ++++++++++++- packages/components/src/Dropdown/Dropdown.tsx | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts index fab4905617f..6f700304000 100644 --- a/packages/client/src/i18n/messages/views/action.ts +++ b/packages/client/src/i18n/messages/views/action.ts @@ -13,6 +13,7 @@ import { defineMessages, MessageDescriptor } from 'react-intl' interface IActionMessages extends Record { action: MessageDescriptor + assignedTo: MessageDescriptor view: MessageDescriptor correctRecord: MessageDescriptor } @@ -23,6 +24,11 @@ const messagesToDefine: IActionMessages = { description: 'Label for action button in dropdown menu', id: 'action.action' }, + assignedTo: { + defaultMessage: 'Assigned to {name} at {officeName}', + description: 'Label for assignee', + id: 'action.assignee' + }, view: { defaultMessage: 'View {recordOrDeclaration}', description: 'Label for view button in dropdown menu', diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index b41fb25b1b3..91f51d4bf30 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -71,7 +71,7 @@ export const ActionMenu: React.FC<{ const dispatch = useDispatch() const [modal, openModal] = useModal() - const { id, type } = declaration + const { id, type, assignment } = declaration const isDownloaded = draft?.downloadStatus === DOWNLOAD_STATUS.DOWNLOADED || @@ -227,6 +227,17 @@ export const ActionMenu: React.FC<{ + {!isDownloaded && assignment && ( + <> + + {intl.formatMessage(messages.assignedTo, { + name: assignment.firstName + ' ' + assignment.lastName, + officeName: assignment.officeName + })} + + + + )} diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index d5e70ea2ab7..c53c9d6f2fa 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -72,6 +72,7 @@ const StyledContent = styled.ul<{ const Label = styled.li` padding: 6px 12px; + white-space: normal; ` const Separator = styled.div<{ weight: number }>` From 0071b8f16750dc28ccc7e0c913ae26440ee53208 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 25 Sep 2024 20:53:04 +0600 Subject: [PATCH 14/88] refactor: move actionItems --- .../src/views/RecordAudit/ActionMenu.tsx | 373 ++++++++++++------ 1 file changed, 244 insertions(+), 129 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 91f51d4bf30..aab962fa308 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -71,145 +71,283 @@ export const ActionMenu: React.FC<{ const dispatch = useDispatch() const [modal, openModal] = useModal() - const { id, type, assignment } = declaration + const { id, type, assignment, status } = declaration const isDownloaded = draft?.downloadStatus === DOWNLOAD_STATUS.DOWNLOADED || draft?.submissionStatus === SUBMISSION_STATUS.DRAFT + const handleDelete = async () => { + const deleteConfirm = await openModal((close) => ( + + )) + if (deleteConfirm) { + dispatch(deleteDeclaration(id, client)) + dispatch(goToHome()) + } + return + } + + return ( + <> + + + }> + {intl.formatMessage(messages.action)} + + + + {!isDownloaded && assignment && ( + <> + + {intl.formatMessage(messages.assignedTo, { + name: assignment.firstName + ' ' + assignment.lastName, + officeName: assignment.officeName + })} + + + + )} + + + + + + + + + + + + {modal} + + ) +} + +interface ActionItemProps { + declarationId?: string + type?: string + declarationStatus?: string + declaration?: IDeclarationData + intl: IntlShape + scope?: Scope | null + draft?: IDeclaration | null + userDetails?: UserDetails | null + toggleDisplayDialog?: () => void + goToPage?: typeof goToPage + goToPrintCertificate?: typeof goToPrintCertificate + isDownloaded?: boolean +} + +const ViewAction: React.FC = ({ + declarationStatus, + declarationId, + intl +}) => { + const dispatch = useDispatch() + const recordOrDeclaration = [ SUBMISSION_STATUS.REGISTERED, SUBMISSION_STATUS.CORRECTION_REQUESTED, SUBMISSION_STATUS.CERTIFIED - ].includes(declaration.status as any as SUBMISSION_STATUS) + ].includes(declarationStatus as any as SUBMISSION_STATUS) ? 'record' : 'declaration' - const ViewAction = () => ( + return ( { - dispatch(goToViewRecordPage(id as string)) + dispatch(goToViewRecordPage(declarationId as string)) }} > {intl.formatMessage(messages.view, { recordOrDeclaration })} ) +} - const CorrectRecordAction = () => ( +const CorrectRecordAction: React.FC = ({ + declarationId, + isDownloaded, + intl +}) => ( + { + clearCorrectionAndPrintChanges(declarationId as string) + goToCertificateCorrection( + declarationId as string, + CorrectionSection.Corrector + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.correctRecord)} + +) +const ArchiveAction: React.FC = ({ + toggleDisplayDialog, + intl, + isDownloaded +}) => ( + + + {intl.formatMessage(buttonMessages.archive)} + +) + +const ReinstateAction: React.FC = ({ + toggleDisplayDialog, + isDownloaded, + intl +}) => ( + + + {intl.formatMessage(buttonMessages.reinstate)} + +) + +const ReviewAction: React.FC = ({ + declarationId, + declarationStatus, + type, + isDownloaded, + intl +}) => { + return ( { - clearCorrectionAndPrintChanges(id) - goToCertificateCorrection(id, CorrectionSection.Corrector) + if (declarationStatus === EVENT_STATUS.CORRECTION_REQUESTED) { + goToPage( + REVIEW_CORRECTION, + declarationId as string, + 'review', + type as string + ) + } else { + goToPage( + REVIEW_EVENT_PARENT_FORM_PAGE, + declarationId as string, + 'review', + type as string + ) + } }} disabled={!isDownloaded} > - - {intl.formatMessage(messages.correctRecord)} + + {intl.formatMessage(constantsMessages.review)} ) +} - const ArchiveAction = () => ( - - - {intl.formatMessage(buttonMessages.archive)} - - ) - - const ReinstateAction = () => ( - - - {intl.formatMessage(buttonMessages.reinstate)} - - ) - - const ReviewAction = () => { - return ( - { - if (declaration.status === EVENT_STATUS.CORRECTION_REQUESTED) { - goToPage(REVIEW_CORRECTION, id, 'review', type!) - } else { - goToPage(REVIEW_EVENT_PARENT_FORM_PAGE, id, 'review', type!) - } - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(constantsMessages.review)} - - ) - } - - const DeleteAction = () => { - return ( - { - const deleteConfirm = await openModal((close) => ( - - )) - if (deleteConfirm) { - dispatch(deleteDeclaration(declaration.id, client)) - dispatch(goToHome()) - } - return - }} - > - - {intl.formatMessage(buttonMessages.deleteDeclaration)} - - ) - } +const UpdateAction: React.FC = ({ + declarationId, + declarationStatus, + type, + isDownloaded, + intl +}) => { + let PAGE_ROUTE: string, PAGE_ID: string - const UpdateAction = () => { - let PAGE_ROUTE: string, PAGE_ID: string - - if (declaration?.status === SUBMISSION_STATUS.DRAFT) { - PAGE_ID = 'preview' - if (type === 'birth') { - PAGE_ROUTE = DRAFT_BIRTH_PARENT_FORM_PAGE - } else if (type === 'death') { - PAGE_ROUTE = DRAFT_DEATH_FORM_PAGE - } else if (type === 'marriage') { - PAGE_ROUTE = DRAFT_MARRIAGE_FORM_PAGE - } - } else { - PAGE_ROUTE = REVIEW_EVENT_PARENT_FORM_PAGE - PAGE_ID = 'review' + if (declarationStatus === SUBMISSION_STATUS.DRAFT) { + PAGE_ID = 'preview' + if (type === 'birth') { + PAGE_ROUTE = DRAFT_BIRTH_PARENT_FORM_PAGE + } else if (type === 'death') { + PAGE_ROUTE = DRAFT_DEATH_FORM_PAGE + } else if (type === 'marriage') { + PAGE_ROUTE = DRAFT_MARRIAGE_FORM_PAGE } - return ( - { - goToPage && goToPage(PAGE_ROUTE, id, PAGE_ID, type as string) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(buttonMessages.update)} - - ) + } else { + PAGE_ROUTE = REVIEW_EVENT_PARENT_FORM_PAGE + PAGE_ID = 'review' } - - const PrintAction = () => ( + return ( { - clearCorrectionAndPrintChanges && - clearCorrectionAndPrintChanges(declaration.id) - goToPrintCertificate && - goToPrintCertificate(id, (type as string).toLocaleLowerCase()) + goToPage && + goToPage(PAGE_ROUTE, declarationId as string, PAGE_ID, type as string) }} disabled={!isDownloaded} > - - {intl.formatMessage(buttonMessages.print)} + + {intl.formatMessage(buttonMessages.update)} ) +} - const IssueAction = () => ( +const PrintAction: React.FC = ({ + declarationId, + type, + isDownloaded, + intl +}) => ( + { + clearCorrectionAndPrintChanges && + clearCorrectionAndPrintChanges(declarationId as string) + goToPrintCertificate && + goToPrintCertificate( + declarationId as string, + (type as string).toLocaleLowerCase() + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(buttonMessages.print)} + +) + +const IssueAction: React.FC = ({ + declarationId, + isDownloaded, + intl +}) => { + const dispatch = useDispatch() + return ( { - dispatch(clearCorrectionAndPrintChanges(id)) - dispatch(goToIssueCertificate(id)) + dispatch(clearCorrectionAndPrintChanges(declarationId as string)) + dispatch(goToIssueCertificate(declarationId as string)) }} disabled={!isDownloaded} > @@ -217,39 +355,16 @@ export const ActionMenu: React.FC<{ {intl.formatMessage(buttonMessages.issue)} ) +} +const DeleteAction: React.FC<{ + intl: IntlShape + handleDelete: () => void +}> = ({ intl, handleDelete }) => { return ( - <> - - - }> - {intl.formatMessage(messages.action)} - - - - {!isDownloaded && assignment && ( - <> - - {intl.formatMessage(messages.assignedTo, { - name: assignment.firstName + ' ' + assignment.lastName, - officeName: assignment.officeName - })} - - - - )} - - - - - - - - - - - - {modal} - + + + {intl.formatMessage(buttonMessages.deleteDeclaration)} + ) } From 1820f6f09bdb936d024c2791f414894a82e64945 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 14:32:00 +0600 Subject: [PATCH 15/88] amend: add missing props --- .../src/views/RecordAudit/ActionMenu.tsx | 138 ++++++++++-------- .../src/views/RecordAudit/RecordAudit.tsx | 3 + 2 files changed, 81 insertions(+), 60 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index aab962fa308..d1a4fa8f065 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -21,6 +21,7 @@ import { goToIssueCertificate, goToPage, goToPrintCertificate, + goToUserProfile, goToViewRecordPage } from '@client/navigation' import { IntlShape } from 'react-intl' @@ -56,8 +57,11 @@ export const ActionMenu: React.FC<{ draft: IDeclaration | null userDetails: UserDetails | null toggleDisplayDialog: () => void + clearCorrectionAndPrintChanges: typeof clearCorrectionAndPrintChanges goToPage: typeof goToPage goToPrintCertificate: typeof goToPrintCertificate + goToIssueCertificate: typeof goToIssueCertificate + goToUserProfile: typeof goToUserProfile }> = ({ declaration, intl, @@ -66,7 +70,9 @@ export const ActionMenu: React.FC<{ userDetails, toggleDisplayDialog, goToPage, - goToPrintCertificate + clearCorrectionAndPrintChanges, + goToPrintCertificate, + goToIssueCertificate }) => { const dispatch = useDispatch() const [modal, openModal] = useModal() @@ -134,6 +140,7 @@ export const ActionMenu: React.FC<{ type={type} isDownloaded={isDownloaded} intl={intl} + goToPage={goToPage} /> void - goToPage?: typeof goToPage - goToPrintCertificate?: typeof goToPrintCertificate - isDownloaded?: boolean } -const ViewAction: React.FC = ({ - declarationStatus, - declarationId, - intl -}) => { +const ViewAction: React.FC<{ + intl: IntlShape + declarationStatus?: string + declarationId: string +}> = ({ declarationStatus, declarationId, intl }) => { const dispatch = useDispatch() const recordOrDeclaration = [ @@ -203,53 +209,56 @@ const ViewAction: React.FC = ({ ) } -const CorrectRecordAction: React.FC = ({ - declarationId, - isDownloaded, - intl -}) => ( - { - clearCorrectionAndPrintChanges(declarationId as string) - goToCertificateCorrection( - declarationId as string, - CorrectionSection.Corrector - ) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(messages.correctRecord)} - -) -const ArchiveAction: React.FC = ({ - toggleDisplayDialog, - intl, - isDownloaded -}) => ( +const CorrectRecordAction: React.FC< + IActionItemCommonProps & IDeclarationProps +> = ({ declarationId, isDownloaded, intl }) => { + const dispatch = useDispatch() + return ( + { + dispatch(clearCorrectionAndPrintChanges(declarationId as string)) + + dispatch( + goToCertificateCorrection( + declarationId as string, + CorrectionSection.Corrector + ) + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.correctRecord)} + + ) +} +const ArchiveAction: React.FC< + IActionItemCommonProps & { toggleDisplayDialog?: () => void } +> = ({ toggleDisplayDialog, intl, isDownloaded }) => ( {intl.formatMessage(buttonMessages.archive)} ) -const ReinstateAction: React.FC = ({ - toggleDisplayDialog, - isDownloaded, - intl -}) => ( +const ReinstateAction: React.FC< + IActionItemCommonProps & { toggleDisplayDialog?: () => void } +> = ({ toggleDisplayDialog, isDownloaded, intl }) => ( {intl.formatMessage(buttonMessages.reinstate)} ) -const ReviewAction: React.FC = ({ +const ReviewAction: React.FC< + IActionItemCommonProps & IDeclarationProps & { goToPage: typeof goToPage } +> = ({ declarationId, declarationStatus, type, isDownloaded, - intl + intl, + goToPage }) => { return ( = ({ ) } -const UpdateAction: React.FC = ({ +const UpdateAction: React.FC< + IActionItemCommonProps & IDeclarationProps & { goToPage: typeof goToPage } +> = ({ declarationId, declarationStatus, type, isDownloaded, - intl + intl, + goToPage }) => { let PAGE_ROUTE: string, PAGE_ID: string @@ -314,21 +326,27 @@ const UpdateAction: React.FC = ({ ) } -const PrintAction: React.FC = ({ +const PrintAction: React.FC< + IActionItemCommonProps & + IDeclarationProps & { + clearCorrectionAndPrintChanges: typeof clearCorrectionAndPrintChanges + goToPrintCertificate: typeof goToPrintCertificate + } +> = ({ declarationId, type, isDownloaded, - intl + intl, + clearCorrectionAndPrintChanges, + goToPrintCertificate }) => ( { - clearCorrectionAndPrintChanges && - clearCorrectionAndPrintChanges(declarationId as string) - goToPrintCertificate && - goToPrintCertificate( - declarationId as string, - (type as string).toLocaleLowerCase() - ) + clearCorrectionAndPrintChanges(declarationId as string) + goToPrintCertificate( + declarationId as string, + (type as string).toLocaleLowerCase() + ) }} disabled={!isDownloaded} > @@ -337,7 +355,7 @@ const PrintAction: React.FC = ({ ) -const IssueAction: React.FC = ({ +const IssueAction: React.FC = ({ declarationId, isDownloaded, intl diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index 0025143a852..944cf92a231 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -533,6 +533,9 @@ function RecordAuditBody({ toggleDisplayDialog={toggleDisplayDialog} goToPage={goToPage} goToPrintCertificate={goToPrintCertificate} + clearCorrectionAndPrintChanges={clearCorrectionAndPrintChanges} + goToIssueCertificate={goToIssueCertificate} + goToUserProfile={goToUserProfile} /> ) desktopActionsView.push(actions[actions.length - 1]) From 92f2b2802e22cb36e3d456dbbe0d930c027dd49b Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 15:06:27 +0600 Subject: [PATCH 16/88] feat: add scope and other checks for: correct record --- .../src/views/RecordAudit/ActionMenu.tsx | 69 ++++++++++++++----- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index d1a4fa8f065..321eb57d6cd 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -49,11 +49,12 @@ import { messages } from '@client/i18n/messages/views/action' import { useModal } from '@client/hooks/useModal' import { DeleteModal } from '@client/views/RegisterForm/RegisterForm' import { client } from '@client/utils/apolloClient' +import { Event } from '@client/utils/gateway' export const ActionMenu: React.FC<{ declaration: IDeclarationData intl: IntlShape - scope: Scope | null + scope: Scope draft: IDeclaration | null userDetails: UserDetails | null toggleDisplayDialog: () => void @@ -121,18 +122,23 @@ export const ActionMenu: React.FC<{ /> @@ -162,8 +171,9 @@ export const ActionMenu: React.FC<{ declarationId={id} isDownloaded={isDownloaded} intl={intl} + scope={scope} /> - + {modal} @@ -174,6 +184,7 @@ export const ActionMenu: React.FC<{ interface IActionItemCommonProps { isDownloaded: boolean intl: IntlShape + scope: Scope } interface IDeclarationProps { @@ -211,25 +222,44 @@ const ViewAction: React.FC<{ const CorrectRecordAction: React.FC< IActionItemCommonProps & IDeclarationProps -> = ({ declarationId, isDownloaded, intl }) => { +> = ({ declarationId, declarationStatus, type, isDownloaded, intl, scope }) => { const dispatch = useDispatch() - return ( - { - dispatch(clearCorrectionAndPrintChanges(declarationId as string)) - dispatch( - goToCertificateCorrection( - declarationId as string, - CorrectionSection.Corrector + const isBirthOrDeathEvent = + type && [Event.Birth, Event.Death].includes(type.toLowerCase() as Event) + + const canBeCorrected = + declarationStatus && + [ + SUBMISSION_STATUS.REGISTERED, + SUBMISSION_STATUS.CERTIFIED, + SUBMISSION_STATUS.ISSUED + ].includes(declarationStatus as SUBMISSION_STATUS) + + // @ToDo use: `record.registration-correct` after configurable role pr is merged + const userHasRegisterScope = + scope && (scope as any as string[]).includes('register') + + return ( + isBirthOrDeathEvent && + canBeCorrected && + userHasRegisterScope && ( + { + dispatch(clearCorrectionAndPrintChanges(declarationId as string)) + dispatch( + goToCertificateCorrection( + declarationId as string, + CorrectionSection.Corrector + ) ) - ) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(messages.correctRecord)} - + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.correctRecord)} + + ) ) } const ArchiveAction: React.FC< @@ -378,7 +408,8 @@ const IssueAction: React.FC = ({ const DeleteAction: React.FC<{ intl: IntlShape handleDelete: () => void -}> = ({ intl, handleDelete }) => { + scope: Scope +}> = ({ intl, handleDelete, scope }) => { return ( From 07ecc4e3600b08043d81cd4a278cf8af9857d8b5 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 15:33:56 +0600 Subject: [PATCH 17/88] feat: add scope and other checks for: archive declaration --- .../src/views/RecordAudit/ActionMenu.tsx | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 321eb57d6cd..bc968f7628c 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -133,6 +133,8 @@ export const ActionMenu: React.FC<{ isDownloaded={isDownloaded} intl={intl} scope={scope} + declarationId={id} + declarationStatus={status} /> void } -> = ({ toggleDisplayDialog, intl, isDownloaded }) => ( - - - {intl.formatMessage(buttonMessages.archive)} - -) + IActionItemCommonProps & + IDeclarationProps & { toggleDisplayDialog?: () => void } +> = ({ toggleDisplayDialog, intl, isDownloaded, declarationStatus, scope }) => { + const isArchivable = + declarationStatus && + [ + SUBMISSION_STATUS.IN_PROGRESS, + SUBMISSION_STATUS.DECLARED, + SUBMISSION_STATUS.VALIDATED, + SUBMISSION_STATUS.REJECTED + ].includes(declarationStatus as SUBMISSION_STATUS) + + // @ToDo use: `record.registration-archive` after configurable role pr is merged + // @Question: If user has archive scope but not register scope, + // can he archive validated record? + const userHasArchiveScope = + scope && + ((scope as any as string[]).includes('register') || + ((scope as any as string[]).includes('validated') && + declarationStatus !== SUBMISSION_STATUS.VALIDATED)) + + return ( + isArchivable && + userHasArchiveScope && ( + + + {intl.formatMessage(buttonMessages.archive)} + + ) + ) +} const ReinstateAction: React.FC< IActionItemCommonProps & { toggleDisplayDialog?: () => void } From ec229b0ad2d84dd3b1970ad86dfc86cc283ec63a Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 15:46:18 +0600 Subject: [PATCH 18/88] feat: add scope and other checks for: reinstate declaration --- .../client/src/i18n/messages/views/action.ts | 12 +++++++ .../src/views/RecordAudit/ActionMenu.tsx | 33 ++++++++++++++----- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts index 6f700304000..bd66208cf07 100644 --- a/packages/client/src/i18n/messages/views/action.ts +++ b/packages/client/src/i18n/messages/views/action.ts @@ -16,6 +16,8 @@ interface IActionMessages assignedTo: MessageDescriptor view: MessageDescriptor correctRecord: MessageDescriptor + archiveRecord: MessageDescriptor + reinstateRecord: MessageDescriptor } const messagesToDefine: IActionMessages = { @@ -38,6 +40,16 @@ const messagesToDefine: IActionMessages = { defaultMessage: 'Correct Record', description: 'Label for correct record button in dropdown menu', id: 'action.correct' + }, + archiveRecord: { + defaultMessage: 'Archive Record', + description: 'Label for archive record button in dropdown menu', + id: 'action.archive' + }, + reinstateRecord: { + defaultMessage: 'Reinstate Record', + description: 'Label for reinstate record button in dropdown menu', + id: 'action.reinstate' } } export const messages: IActionMessages = defineMessages(messagesToDefine) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index bc968f7628c..27593836753 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -141,6 +141,8 @@ export const ActionMenu: React.FC<{ isDownloaded={isDownloaded} intl={intl} scope={scope} + declarationId={id} + declarationStatus={status} /> - {intl.formatMessage(buttonMessages.archive)} + {intl.formatMessage(messages.archiveRecord)} ) ) } const ReinstateAction: React.FC< - IActionItemCommonProps & { toggleDisplayDialog?: () => void } -> = ({ toggleDisplayDialog, isDownloaded, intl }) => ( - - - {intl.formatMessage(buttonMessages.reinstate)} - -) + IActionItemCommonProps & + IDeclarationProps & { toggleDisplayDialog?: () => void } +> = ({ toggleDisplayDialog, isDownloaded, intl, declarationStatus, scope }) => { + const isArchived = declarationStatus === SUBMISSION_STATUS.ARCHIVED + + // @ToDo use: `record.registration-reinstate` after configurable role pr is merged + // @Question: If user has reinstate scope but not register scope, + // can he reinstate validated record? + const userHasReinstateScope = + scope && + ((scope as any as string[]).includes('register') || + (scope as any as string[]).includes('validated')) + return ( + isArchived && + userHasReinstateScope && ( + + + {intl.formatMessage(messages.reinstateRecord)} + + ) + ) +} const ReviewAction: React.FC< IActionItemCommonProps & IDeclarationProps & { goToPage: typeof goToPage } From bca7d50d442a121f814b041c08dee7c1f39bffa6 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 15:49:52 +0600 Subject: [PATCH 19/88] refactor: restructure types --- packages/client/src/views/RecordAudit/ActionMenu.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 27593836753..b93e7cae547 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -133,7 +133,6 @@ export const ActionMenu: React.FC<{ isDownloaded={isDownloaded} intl={intl} scope={scope} - declarationId={id} declarationStatus={status} /> void } + IActionItemCommonProps & { toggleDisplayDialog?: () => void } > = ({ toggleDisplayDialog, intl, isDownloaded, declarationStatus, scope }) => { const isArchivable = declarationStatus && @@ -301,8 +300,7 @@ const ArchiveAction: React.FC< } const ReinstateAction: React.FC< - IActionItemCommonProps & - IDeclarationProps & { toggleDisplayDialog?: () => void } + IActionItemCommonProps & { toggleDisplayDialog?: () => void } > = ({ toggleDisplayDialog, isDownloaded, intl, declarationStatus, scope }) => { const isArchived = declarationStatus === SUBMISSION_STATUS.ARCHIVED From 371b26b9b3c1c6c850edfdae3563e778767c9d03 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 16:39:51 +0600 Subject: [PATCH 20/88] feat: add scope and other checks for: review --- .../client/src/i18n/messages/views/action.ts | 13 ++++ .../src/views/RecordAudit/ActionMenu.tsx | 64 +++++++++++++------ .../src/views/RecordAudit/RecordAudit.tsx | 1 + packages/components/src/Icon/all-icons.ts | 2 +- 4 files changed, 61 insertions(+), 19 deletions(-) diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts index bd66208cf07..2782da049ed 100644 --- a/packages/client/src/i18n/messages/views/action.ts +++ b/packages/client/src/i18n/messages/views/action.ts @@ -18,6 +18,8 @@ interface IActionMessages correctRecord: MessageDescriptor archiveRecord: MessageDescriptor reinstateRecord: MessageDescriptor + reviewCorrection: MessageDescriptor + reviewDeclaration: MessageDescriptor } const messagesToDefine: IActionMessages = { @@ -50,6 +52,17 @@ const messagesToDefine: IActionMessages = { defaultMessage: 'Reinstate Record', description: 'Label for reinstate record button in dropdown menu', id: 'action.reinstate' + }, + reviewCorrection: { + defaultMessage: 'Review correction request', + description: 'Label for review correction request button in dropdown menu', + id: 'action.review.correction' + }, + reviewDeclaration: { + defaultMessage: + 'Review {isDuplicate, select, true{potential duplicate} other{declaration}}', + description: 'Label for review record button in dropdown menu', + id: 'action.review.declaration' } } export const messages: IActionMessages = defineMessages(messagesToDefine) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index b93e7cae547..99c074fa83e 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -57,6 +57,7 @@ export const ActionMenu: React.FC<{ scope: Scope draft: IDeclaration | null userDetails: UserDetails | null + duplicates?: string[] toggleDisplayDialog: () => void clearCorrectionAndPrintChanges: typeof clearCorrectionAndPrintChanges goToPage: typeof goToPage @@ -73,7 +74,8 @@ export const ActionMenu: React.FC<{ goToPage, clearCorrectionAndPrintChanges, goToPrintCertificate, - goToIssueCertificate + goToIssueCertificate, + duplicates }) => { const dispatch = useDispatch() const [modal, openModal] = useModal() @@ -84,6 +86,8 @@ export const ActionMenu: React.FC<{ draft?.downloadStatus === DOWNLOAD_STATUS.DOWNLOADED || draft?.submissionStatus === SUBMISSION_STATUS.DRAFT + const isDuplicate = (duplicates ?? []).length > 0 + const handleDelete = async () => { const deleteConfirm = await openModal((close) => ( @@ -150,6 +154,7 @@ export const ActionMenu: React.FC<{ intl={intl} scope={scope} goToPage={goToPage} + isDuplicate={isDuplicate} /> = ({ declarationId, declarationStatus, type, + scope, isDownloaded, + isDuplicate, intl, goToPage }) => { - return ( + const isPendingCorrection = + declarationStatus === EVENT_STATUS.CORRECTION_REQUESTED + + const isReviewableDeclaration = + declarationStatus && + [EVENT_STATUS.DECLARED, EVENT_STATUS.VALIDATED].includes(declarationStatus) + + const userHasReviewScope = + scope && + ((scope as any as string[]).includes('register') || + (scope as any as string[]).includes('validated')) + + return isPendingCorrection && userHasReviewScope ? ( { - if (declarationStatus === EVENT_STATUS.CORRECTION_REQUESTED) { - goToPage( - REVIEW_CORRECTION, - declarationId as string, - 'review', - type as string - ) - } else { + goToPage( + REVIEW_CORRECTION, + declarationId as string, + 'review', + type as string + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.reviewCorrection)} + + ) : ( + isReviewableDeclaration && userHasReviewScope && ( + { goToPage( REVIEW_EVENT_PARENT_FORM_PAGE, declarationId as string, 'review', type as string ) - } - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(constantsMessages.review)} - + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.reviewDeclaration, { isDuplicate })} + + ) ) } diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index 944cf92a231..e96a73f8c4b 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -526,6 +526,7 @@ function RecordAuditBody({ actions.push( Date: Thu, 26 Sep 2024 16:41:34 +0600 Subject: [PATCH 21/88] chore: add todo --- packages/client/src/views/RecordAudit/ActionMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 99c074fa83e..6644f1a54c5 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -347,6 +347,7 @@ const ReviewAction: React.FC< declarationStatus && [EVENT_STATUS.DECLARED, EVENT_STATUS.VALIDATED].includes(declarationStatus) + // @ToDo use: `record.declaration-review` or other appropriate scope after configurable role pr is merged const userHasReviewScope = scope && ((scope as any as string[]).includes('register') || From e774d6233c649e0f0f2547b09d154b5c86021877 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 17:34:38 +0600 Subject: [PATCH 22/88] feat: add scope and other checks for: update declaration --- .../client/src/i18n/messages/views/action.ts | 6 +++ .../src/views/RecordAudit/ActionMenu.tsx | 51 ++++++++++++++----- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts index 2782da049ed..e700adf69aa 100644 --- a/packages/client/src/i18n/messages/views/action.ts +++ b/packages/client/src/i18n/messages/views/action.ts @@ -20,6 +20,7 @@ interface IActionMessages reinstateRecord: MessageDescriptor reviewCorrection: MessageDescriptor reviewDeclaration: MessageDescriptor + updateDeclaration: MessageDescriptor } const messagesToDefine: IActionMessages = { @@ -63,6 +64,11 @@ const messagesToDefine: IActionMessages = { 'Review {isDuplicate, select, true{potential duplicate} other{declaration}}', description: 'Label for review record button in dropdown menu', id: 'action.review.declaration' + }, + updateDeclaration: { + defaultMessage: 'Update declaration', + description: 'Label for update record button in dropdown menu', + id: 'action.update.declaration' } } export const messages: IActionMessages = defineMessages(messagesToDefine) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 6644f1a54c5..c73e6752cf9 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -290,7 +290,7 @@ const ArchiveAction: React.FC< const userHasArchiveScope = scope && ((scope as any as string[]).includes('register') || - ((scope as any as string[]).includes('validated') && + ((scope as any as string[]).includes('validate') && declarationStatus !== SUBMISSION_STATUS.VALIDATED)) return ( @@ -315,7 +315,7 @@ const ReinstateAction: React.FC< const userHasReinstateScope = scope && ((scope as any as string[]).includes('register') || - (scope as any as string[]).includes('validated')) + (scope as any as string[]).includes('validate')) return ( isArchived && userHasReinstateScope && ( @@ -351,7 +351,7 @@ const ReviewAction: React.FC< const userHasReviewScope = scope && ((scope as any as string[]).includes('register') || - (scope as any as string[]).includes('validated')) + (scope as any as string[]).includes('validate')) return isPendingCorrection && userHasReviewScope ? ( { + const isUpdatableDeclaration = + declarationStatus && + [ + SUBMISSION_STATUS.DRAFT, + EVENT_STATUS.IN_PROGRESS, + EVENT_STATUS.REJECTED + ].includes(declarationStatus) + + // @ToDo use: appropriate scope after configurable role pr is merged + const userHasUpdateScope = + scope && + ((scope as any as string[]).includes('register') || + (scope as any as string[]).includes('validate') || + ((scope as any as string[]).includes('validate') && + declarationStatus === SUBMISSION_STATUS.DRAFT)) + let PAGE_ROUTE: string, PAGE_ID: string if (declarationStatus === SUBMISSION_STATUS.DRAFT) { @@ -414,16 +431,24 @@ const UpdateAction: React.FC< PAGE_ID = 'review' } return ( - { - goToPage && - goToPage(PAGE_ROUTE, declarationId as string, PAGE_ID, type as string) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(buttonMessages.update)} - + isUpdatableDeclaration && + userHasUpdateScope && ( + { + goToPage && + goToPage( + PAGE_ROUTE, + declarationId as string, + PAGE_ID, + type as string + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.updateDeclaration)} + + ) ) } From 6f600391c1eaade33905bd4167f66fc7e62d945c Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 17:51:00 +0600 Subject: [PATCH 23/88] feat: add scope and other checks for: print declaration --- .../client/src/i18n/messages/views/action.ts | 8 ++- .../src/views/RecordAudit/ActionButtons.tsx | 6 +++ .../src/views/RecordAudit/ActionMenu.tsx | 49 +++++++++++++------ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts index e700adf69aa..e4286c17621 100644 --- a/packages/client/src/i18n/messages/views/action.ts +++ b/packages/client/src/i18n/messages/views/action.ts @@ -21,6 +21,7 @@ interface IActionMessages reviewCorrection: MessageDescriptor reviewDeclaration: MessageDescriptor updateDeclaration: MessageDescriptor + printDeclaration: MessageDescriptor } const messagesToDefine: IActionMessages = { @@ -68,7 +69,12 @@ const messagesToDefine: IActionMessages = { updateDeclaration: { defaultMessage: 'Update declaration', description: 'Label for update record button in dropdown menu', - id: 'action.update.declaration' + id: 'action.update' + }, + printDeclaration: { + defaultMessage: 'Print certified copy', + description: 'Label for print certified copy in dropdown menu', + id: 'action.print' } } export const messages: IActionMessages = defineMessages(messagesToDefine) diff --git a/packages/client/src/views/RecordAudit/ActionButtons.tsx b/packages/client/src/views/RecordAudit/ActionButtons.tsx index e01353e2e45..8946967499c 100644 --- a/packages/client/src/views/RecordAudit/ActionButtons.tsx +++ b/packages/client/src/views/RecordAudit/ActionButtons.tsx @@ -249,6 +249,12 @@ export const ShowPrintButton = ({ ] } + console.log({ + systemRole, + type, + showActionButton + }) + if ( systemRole && type && diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index c73e6752cf9..f905ab3a910 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -460,26 +460,45 @@ const PrintAction: React.FC< } > = ({ declarationId, + declarationStatus, + scope, type, isDownloaded, intl, clearCorrectionAndPrintChanges, goToPrintCertificate -}) => ( - { - clearCorrectionAndPrintChanges(declarationId as string) - goToPrintCertificate( - declarationId as string, - (type as string).toLocaleLowerCase() - ) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(buttonMessages.print)} - -) +}) => { + const isPrintable = + declarationStatus && + [SUBMISSION_STATUS.REGISTERED, SUBMISSION_STATUS.ISSUED].includes( + declarationStatus as SUBMISSION_STATUS + ) + + // @ToDo use: `record.print-records` or other appropriate scope after configurable role pr is merged + const userHasPrintScope = + scope && + ((scope as any as string[]).includes('register') || + (scope as any as string[]).includes('validate')) + + return ( + isPrintable && + userHasPrintScope && ( + { + clearCorrectionAndPrintChanges(declarationId as string) + goToPrintCertificate( + declarationId as string, + (type as string).toLocaleLowerCase() + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.printDeclaration)} + + ) + ) +} const IssueAction: React.FC = ({ declarationId, From 7a81c0146d4ebfcded8d04ca4889d12347dea493 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 17:51:51 +0600 Subject: [PATCH 24/88] chore: remove console.log --- packages/client/src/views/RecordAudit/ActionButtons.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionButtons.tsx b/packages/client/src/views/RecordAudit/ActionButtons.tsx index 8946967499c..e01353e2e45 100644 --- a/packages/client/src/views/RecordAudit/ActionButtons.tsx +++ b/packages/client/src/views/RecordAudit/ActionButtons.tsx @@ -249,12 +249,6 @@ export const ShowPrintButton = ({ ] } - console.log({ - systemRole, - type, - showActionButton - }) - if ( systemRole && type && From 0cb3f3f7199697121b95ce4d1847c0e3ce88236d Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 17:59:28 +0600 Subject: [PATCH 25/88] feat: add scope and other checks for: issue certificate --- .../client/src/i18n/messages/views/action.ts | 6 ++++ .../src/views/RecordAudit/ActionMenu.tsx | 34 +++++++++++++------ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts index e4286c17621..1181ac49645 100644 --- a/packages/client/src/i18n/messages/views/action.ts +++ b/packages/client/src/i18n/messages/views/action.ts @@ -22,6 +22,7 @@ interface IActionMessages reviewDeclaration: MessageDescriptor updateDeclaration: MessageDescriptor printDeclaration: MessageDescriptor + issueCertificate: MessageDescriptor } const messagesToDefine: IActionMessages = { @@ -75,6 +76,11 @@ const messagesToDefine: IActionMessages = { defaultMessage: 'Print certified copy', description: 'Label for print certified copy in dropdown menu', id: 'action.print' + }, + issueCertificate: { + defaultMessage: 'Issue certificate', + description: 'Label for issue certificate in dropdown menu', + id: 'action.issue' } } export const messages: IActionMessages = defineMessages(messagesToDefine) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index f905ab3a910..0b29a6fbe4f 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -503,20 +503,34 @@ const PrintAction: React.FC< const IssueAction: React.FC = ({ declarationId, isDownloaded, + declarationStatus, + scope, intl }) => { const dispatch = useDispatch() + + const isCertified = declarationStatus === SUBMISSION_STATUS.CERTIFIED + + // @ToDo use: `record.print-issue-certified-copies` or other appropriate scope after configurable role pr is merged + const userHasIssueScope = + scope && + ((scope as any as string[]).includes('register') || + (scope as any as string[]).includes('validate')) + return ( - { - dispatch(clearCorrectionAndPrintChanges(declarationId as string)) - dispatch(goToIssueCertificate(declarationId as string)) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(buttonMessages.issue)} - + isCertified && + userHasIssueScope && ( + { + dispatch(clearCorrectionAndPrintChanges(declarationId as string)) + dispatch(goToIssueCertificate(declarationId as string)) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.issueCertificate)} + + ) ) } From 8cdc58a01e9621a0c5897dcbd3d0d0619047f2a6 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 18:28:42 +0600 Subject: [PATCH 26/88] feat: add scope and other checks for: delete declaration --- .../client/src/views/RecordAudit/ActionMenu.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 0b29a6fbe4f..64d037b3a03 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -182,7 +182,11 @@ export const ActionMenu: React.FC<{ intl={intl} scope={scope} /> - + {modal} @@ -537,12 +541,11 @@ const IssueAction: React.FC = ({ const DeleteAction: React.FC<{ intl: IntlShape handleDelete: () => void - scope: Scope -}> = ({ intl, handleDelete, scope }) => { - return ( + declarationStatus?: string +}> = ({ intl, handleDelete, declarationStatus }) => + declarationStatus === SUBMISSION_STATUS.DRAFT && ( {intl.formatMessage(buttonMessages.deleteDeclaration)} ) -} From fd6de0955329d8a167e28f8d6b6018fb095eaef0 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 26 Sep 2024 18:35:54 +0600 Subject: [PATCH 27/88] refactor: change order of items --- .../src/views/RecordAudit/ActionMenu.tsx | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 64d037b3a03..02a2a39b81f 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -124,46 +124,38 @@ export const ActionMenu: React.FC<{ declarationStatus={status} intl={intl} /> - - - - - + Date: Fri, 27 Sep 2024 12:57:25 +0600 Subject: [PATCH 28/88] wip --- .../components/interface/DownloadButton.tsx | 33 +++++++++++++- .../client/src/i18n/messages/views/action.ts | 6 +++ .../src/views/RecordAudit/ActionMenu.tsx | 44 ++++++++++++++++++- packages/components/src/Dropdown/Dropdown.tsx | 4 +- 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/interface/DownloadButton.tsx b/packages/client/src/components/interface/DownloadButton.tsx index fd7d61fa747..292a5cfc4ce 100644 --- a/packages/client/src/components/interface/DownloadButton.tsx +++ b/packages/client/src/components/interface/DownloadButton.tsx @@ -44,6 +44,8 @@ import { conflictsMessages } from '@client/i18n/messages/views/conflicts' import { ConnectionError } from '@opencrvs/components/lib/icons/ConnectionError' import { useOnlineStatus } from '@client/utils' import ReactTooltip from 'react-tooltip' +import { DropdownMenu } from '@opencrvs/components/lib/Dropdown' +import { messages } from '@client/i18n/messages/views/action' const { useState, useCallback, useMemo } = React interface IDownloadConfig { @@ -60,6 +62,7 @@ interface DownloadButtonProps { className?: string downloadConfigs: IDownloadConfig status?: DOWNLOAD_STATUS + isActionItem?: boolean } interface IConnectProps { @@ -220,7 +223,8 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { downloadDeclaration, userRole, practitionerId, - unassignDeclaration + unassignDeclaration, + isActionItem } = props const { assignment, compositionId } = downloadConfigs const [assignModal, setAssignModal] = useState( @@ -260,6 +264,8 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { const onClickDownload = useCallback( (e: React.MouseEvent) => { + console.log('onClickDownload triggered') + if ( (assignment?.practitionerId !== practitionerId || status === DOWNLOAD_STATUS.DOWNLOADED) && @@ -332,6 +338,31 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { ) } + if (isActionItem) + return ( + <> + + {intl.formatMessage(messages.unassign)} + + {assignModal !== null && ( + + renderModalAction(action, intl) + )} + autoHeight + responsive={false} + preventClickOnParent + handleClose={hideModal} + > + {intl.formatMessage(assignModal.content, assignModal.contentArgs)} + + )} + + ) + return ( <> + {modal} @@ -549,3 +557,35 @@ const DeleteAction: React.FC<{ {intl.formatMessage(buttonMessages.deleteDeclaration)} ) + +const UnassignAction: React.FC<{ + declaration: IDeclarationData + intl: IntlShape + scope: Scope + isDownloaded: boolean +}> = ({ intl, isDownloaded, declaration, scope }) => { + const { id, type, status } = declaration + const refetchQueries = [ + { query: FETCH_DECLARATION_SHORT_INFO, variables: { id: declaration.id } } + ] + const downLoadConfig = { + event: type as string, + compositionId: id, + action: DownloadAction.LOAD_REVIEW_DECLARATION, + assignment: declaration?.assignment, + declarationStatus: declaration.status, + refetchQueries + } + return ( + !isDownloaded && + declaration.assignment && + (scope as any as string[]).includes('register') && ( + + ) + ) +} diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index c53c9d6f2fa..936a16022e3 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -174,7 +174,9 @@ const Item = ({ children, disabled = false }: { - onClick?: () => void + onClick?: + | (() => void) + | ((e: React.MouseEvent) => void) children: ReactNode disabled?: boolean }) => { From 537712910de2e3a784be7571f8afba5b16a703fd Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 15:39:09 +0600 Subject: [PATCH 29/88] Revert "wip" This reverts commit b25bfa16ee9863b3eb62922f6df1e06d7c1caa9c. --- .../components/interface/DownloadButton.tsx | 33 +------------- .../client/src/i18n/messages/views/action.ts | 6 --- .../src/views/RecordAudit/ActionMenu.tsx | 44 +------------------ packages/components/src/Dropdown/Dropdown.tsx | 4 +- 4 files changed, 4 insertions(+), 83 deletions(-) diff --git a/packages/client/src/components/interface/DownloadButton.tsx b/packages/client/src/components/interface/DownloadButton.tsx index 292a5cfc4ce..fd7d61fa747 100644 --- a/packages/client/src/components/interface/DownloadButton.tsx +++ b/packages/client/src/components/interface/DownloadButton.tsx @@ -44,8 +44,6 @@ import { conflictsMessages } from '@client/i18n/messages/views/conflicts' import { ConnectionError } from '@opencrvs/components/lib/icons/ConnectionError' import { useOnlineStatus } from '@client/utils' import ReactTooltip from 'react-tooltip' -import { DropdownMenu } from '@opencrvs/components/lib/Dropdown' -import { messages } from '@client/i18n/messages/views/action' const { useState, useCallback, useMemo } = React interface IDownloadConfig { @@ -62,7 +60,6 @@ interface DownloadButtonProps { className?: string downloadConfigs: IDownloadConfig status?: DOWNLOAD_STATUS - isActionItem?: boolean } interface IConnectProps { @@ -223,8 +220,7 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { downloadDeclaration, userRole, practitionerId, - unassignDeclaration, - isActionItem + unassignDeclaration } = props const { assignment, compositionId } = downloadConfigs const [assignModal, setAssignModal] = useState( @@ -264,8 +260,6 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { const onClickDownload = useCallback( (e: React.MouseEvent) => { - console.log('onClickDownload triggered') - if ( (assignment?.practitionerId !== practitionerId || status === DOWNLOAD_STATUS.DOWNLOADED) && @@ -338,31 +332,6 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { ) } - if (isActionItem) - return ( - <> - - {intl.formatMessage(messages.unassign)} - - {assignModal !== null && ( - - renderModalAction(action, intl) - )} - autoHeight - responsive={false} - preventClickOnParent - handleClose={hideModal} - > - {intl.formatMessage(assignModal.content, assignModal.contentArgs)} - - )} - - ) - return ( <> - {modal} @@ -557,35 +549,3 @@ const DeleteAction: React.FC<{ {intl.formatMessage(buttonMessages.deleteDeclaration)} ) - -const UnassignAction: React.FC<{ - declaration: IDeclarationData - intl: IntlShape - scope: Scope - isDownloaded: boolean -}> = ({ intl, isDownloaded, declaration, scope }) => { - const { id, type, status } = declaration - const refetchQueries = [ - { query: FETCH_DECLARATION_SHORT_INFO, variables: { id: declaration.id } } - ] - const downLoadConfig = { - event: type as string, - compositionId: id, - action: DownloadAction.LOAD_REVIEW_DECLARATION, - assignment: declaration?.assignment, - declarationStatus: declaration.status, - refetchQueries - } - return ( - !isDownloaded && - declaration.assignment && - (scope as any as string[]).includes('register') && ( - - ) - ) -} diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 936a16022e3..c53c9d6f2fa 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -174,9 +174,7 @@ const Item = ({ children, disabled = false }: { - onClick?: - | (() => void) - | ((e: React.MouseEvent) => void) + onClick?: () => void children: ReactNode disabled?: boolean }) => { From 79915be8afba64025589ff358bb0fea3bf05452a Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 15:52:07 +0600 Subject: [PATCH 30/88] feat: implement unassign button --- .../src/views/RecordAudit/ActionMenu.tsx | 98 ++++++++++++++++++- 1 file changed, 94 insertions(+), 4 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 02a2a39b81f..b8bc4388800 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -11,10 +11,14 @@ import React from 'react' import { DropdownMenu } from '@opencrvs/components/lib/Dropdown' -import { PrimaryButton } from '@opencrvs/components/lib/buttons' +import { + DangerButton, + PrimaryButton, + TertiaryButton +} from '@opencrvs/components/lib/buttons' import { CaretDown } from '@opencrvs/components/lib/Icon/all-icons' import { useDispatch } from 'react-redux' -import { Icon } from '@opencrvs/components' +import { Icon, ResponsiveModal } from '@opencrvs/components' import { goToCertificateCorrection, goToHome, @@ -32,10 +36,11 @@ import { deleteDeclaration, DOWNLOAD_STATUS, IDeclaration, - SUBMISSION_STATUS + SUBMISSION_STATUS, + unassignDeclaration } from '@client/declarations' import { CorrectionSection } from '@client/forms' -import { buttonMessages, constantsMessages } from '@client/i18n/messages' +import { buttonMessages } from '@client/i18n/messages' import { UserDetails } from '@client/utils/userUtils' import { EVENT_STATUS } from '@client/workqueue' import { @@ -50,6 +55,8 @@ import { useModal } from '@client/hooks/useModal' import { DeleteModal } from '@client/views/RegisterForm/RegisterForm' import { client } from '@client/utils/apolloClient' import { Event } from '@client/utils/gateway' +import { conflictsMessages } from '@client/i18n/messages/views/conflicts' +import { GQLAssignmentData } from '@client/utils/gateway-deprecated-do-not-use' export const ActionMenu: React.FC<{ declaration: IDeclarationData @@ -98,6 +105,19 @@ export const ActionMenu: React.FC<{ } return } + const handleUnassign = async () => { + const unassignConfirm = await openModal((close) => ( + + )) + if (unassignConfirm) { + dispatch(unassignDeclaration(id, client)) + } + return + } return ( <> @@ -187,6 +207,13 @@ export const ActionMenu: React.FC<{ intl={intl} declarationStatus={status} /> + {modal} @@ -549,3 +576,66 @@ const DeleteAction: React.FC<{ {intl.formatMessage(buttonMessages.deleteDeclaration)} ) +const UnassignAction: React.FC<{ + intl: IntlShape + handleUnassign: () => void + isDownloaded: boolean + assignment?: GQLAssignmentData + scope: Scope +}> = ({ intl, handleUnassign, isDownloaded, assignment, scope }) => { + const isAssignedToSomeoneElse = !isDownloaded && assignment + + // @ToDo use: appropriate scope after configurable role pr is merged + const userHasUnassignScope = + scope && (scope as any as string[]).includes('register') + + return ( + isAssignedToSomeoneElse && + userHasUnassignScope && ( + + + {intl.formatMessage(buttonMessages.unassign)} + + ) + ) +} + +const UnassignModal: React.FC<{ + intl: IntlShape + close: (result: boolean | null) => void + assignment?: GQLAssignmentData +}> = ({ intl, close, assignment }) => + assignment && ( + { + close(null) + }} + > + {intl.formatMessage(buttonMessages.cancel)} + , + { + close(true) + }} + > + {intl.formatMessage(buttonMessages.unassign)} + + ]} + show={true} + handleClose={() => close(null)} + > + {intl.formatMessage(conflictsMessages.regUnassignDesc, { + name: assignment.firstName + ' ' + assignment.lastName, + officeName: assignment.officeName + })} + + ) From 70fafcdaca0c6c96715783a9ca811898f6241152 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 15:55:23 +0600 Subject: [PATCH 31/88] fix: font and color --- packages/components/src/Dropdown/Dropdown.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index c53c9d6f2fa..6521a8d8448 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -71,6 +71,7 @@ const StyledContent = styled.ul<{ ` const Label = styled.li` + ${({ theme }) => theme.fonts.reg14}; padding: 6px 12px; white-space: normal; ` @@ -83,7 +84,7 @@ const Separator = styled.div<{ weight: number }>` const MenuItem = styled.li<{ disabled?: boolean }>` ${({ theme }) => theme.fonts.bold14}; - color: ${({ theme }) => theme.colors.grey500}; + color: ${({ theme }) => theme.colors.grey600}; display: flex; align-items: center; gap: 8px; From fc9dd1752e536210af9b86543a14e2902c5e4cce Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 15:57:47 +0600 Subject: [PATCH 32/88] fix: keyDown behaviour --- packages/components/src/Dropdown/DropdownContext.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/src/Dropdown/DropdownContext.tsx b/packages/components/src/Dropdown/DropdownContext.tsx index 2048d7f300c..2c92dcfbb0f 100644 --- a/packages/components/src/Dropdown/DropdownContext.tsx +++ b/packages/components/src/Dropdown/DropdownContext.tsx @@ -72,6 +72,7 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ } const handleKeyDown = (e: React.KeyboardEvent) => { + e.preventDefault() if (e.key === 'ArrowDown') { setFocusedIndex(getNextIndex) } else if (e.key === 'ArrowUp') { From 6349d183e93826db4c5b769427aee202bea8af4b Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 16:03:10 +0600 Subject: [PATCH 33/88] chore: remove record audit buttons --- .../src/views/RecordAudit/RecordAudit.tsx | 184 ------------------ .../src/Dropdown/DropdownContext.tsx | 1 - 2 files changed, 185 deletions(-) diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index e96a73f8c4b..b474558a941 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -331,9 +331,6 @@ function RecordAuditBody({ } const toggleDisplayDialog = () => setShowDialog((prevValue) => !prevValue) - const userHasRegisterScope = scope && scope.includes('register') - const userHasValidateScope = scope && scope.includes('validate') - const actions: React.ReactElement[] = [] const mobileActions: React.ReactElement[] = [] const desktopActionsView: React.ReactElement[] = [] @@ -342,187 +339,6 @@ function RecordAuditBody({ draft?.downloadStatus === DOWNLOAD_STATUS.DOWNLOADED || draft?.submissionStatus === SUBMISSION_STATUS.DRAFT - if ( - isDownloaded && - declaration.type !== Event.Marriage && - (userHasRegisterScope || userHasValidateScope) && - (declaration.status === SUBMISSION_STATUS.REGISTERED || - declaration.status === SUBMISSION_STATUS.CERTIFIED || - declaration.status === SUBMISSION_STATUS.ISSUED) - ) { - actions.push( - } - onClick={() => { - clearCorrectionAndPrintChanges(declaration.id) - goToCertificateCorrection(declaration.id, CorrectionSection.Corrector) - }} - > - {intl.formatMessage(correctionMessages.title)} - - ) - desktopActionsView.push(actions[actions.length - 1]) - } - - if ( - isDownloaded && - declaration.status && - ARCHIVABLE_STATUSES.includes(declaration.status) && - (userHasRegisterScope || - (userHasValidateScope && declaration.status !== VALIDATED)) - ) { - actions.push( - - ) - desktopActionsView.push(actions[actions.length - 1]) - } - - if ( - isDownloaded && - (userHasValidateScope || userHasRegisterScope) && - declaration.status && - ARCHIVED.includes(declaration.status) - ) { - actions.push( - - ) - desktopActionsView.push(actions[actions.length - 1]) - } - - if ( - declaration.status !== SUBMISSION_STATUS.DRAFT && - (userHasRegisterScope || userHasValidateScope) - ) { - actions.push( - - ) - mobileActions.push(actions[actions.length - 1]) - desktopActionsView.push( - - {actions[actions.length - 1]} - - ) - } - - if ( - [ - SUBMISSION_STATUS.DECLARED, - SUBMISSION_STATUS.VALIDATED, - SUBMISSION_STATUS.CORRECTION_REQUESTED - ].includes(declaration.status as SUBMISSION_STATUS) && - userDetails?.systemRole && - !FIELD_AGENT_ROLES.includes(userDetails.systemRole) - ) { - actions.push( - ShowReviewButton({ - declaration, - intl, - userDetails, - draft, - goToPage - }) - ) - - mobileActions.push(actions[actions.length - 1]) - desktopActionsView.push( - - {actions[actions.length - 1]} - - ) - } - if ( - declaration.status === SUBMISSION_STATUS.DRAFT || - ((declaration.status === SUBMISSION_STATUS.IN_PROGRESS || - declaration.status === SUBMISSION_STATUS.REJECTED) && - userDetails?.systemRole && - !FIELD_AGENT_ROLES.includes(userDetails.systemRole)) - ) { - actions.push( - ShowUpdateButton({ - declaration, - intl, - userDetails, - draft, - goToPage - }) - ) - mobileActions.push(actions[actions.length - 1]) - desktopActionsView.push( - - {actions[actions.length - 1]} - - ) - } - - if ( - declaration.status === SUBMISSION_STATUS.REGISTERED || - declaration.status === SUBMISSION_STATUS.ISSUED - ) { - actions.push( - ShowPrintButton({ - declaration, - intl, - userDetails, - draft, - goToPrintCertificate, - goToTeamUserList, - clearCorrectionAndPrintChanges - }) - ) - mobileActions.push(actions[actions.length - 1]) - desktopActionsView.push( - - {actions[actions.length - 1]} - - ) - } - if (declaration.status === SUBMISSION_STATUS.CERTIFIED) { - actions.push( - ShowIssueButton({ - declaration, - intl, - userDetails, - draft, - goToIssueCertificate - }) - ) - mobileActions.push(actions[actions.length - 1]) - desktopActionsView.push( - - {actions[actions.length - 1]} - - ) - } - actions.push( Date: Fri, 27 Sep 2024 16:38:35 +0600 Subject: [PATCH 34/88] refactor: use dropdownMenu to refactor toggleMenu --- packages/components/src/Dropdown/Dropdown.tsx | 2 +- .../components/src/ToggleMenu/ToggleMenu.tsx | 208 ++---------------- 2 files changed, 15 insertions(+), 195 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 6521a8d8448..b5235a97625 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -166,7 +166,7 @@ const Content: React.FC<{ DropdownMenu.Content = Content -DropdownMenu.Label = ({ children }: { children: string }) => ( +DropdownMenu.Label = ({ children }: { children: string | JSX.Element }) => ( ) diff --git a/packages/components/src/ToggleMenu/ToggleMenu.tsx b/packages/components/src/ToggleMenu/ToggleMenu.tsx index 80a879f99b9..97866f4e09a 100644 --- a/packages/components/src/ToggleMenu/ToggleMenu.tsx +++ b/packages/components/src/ToggleMenu/ToggleMenu.tsx @@ -8,97 +8,18 @@ * * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import styled from 'styled-components' -import React, { useEffect, useRef, useState } from 'react' -import { Button } from '../Button' -import { disabled } from '../Button/Button.styles' - -const ToggleMenuContainer = styled.nav` - position: relative; - height: 40px; - display: flex; - button { - padding: 0; - height: auto; - } -` -const MenuContainer = styled.ul` - border-radius: 4px; - border: 1px solid ${({ theme }) => theme.colors.grey300}; - background-color: ${({ theme }) => theme.colors.white}; - ${({ theme }) => theme.shadows.light}; - text-align: left; - min-width: 200px; - width: auto; - white-space: nowrap; - position: absolute; - z-index: 999999; - display: flex; - flex-direction: column; - top: 100%; - right: 0; - padding: 8px 0; - margin: 0; - list-style: none; -` - -const MenuHeader = styled.li` - padding: 8px 16px; - margin-bottom: 6px; - border-bottom: 1px solid ${({ theme }) => theme.colors.grey300}; -` - -interface MenuItemProps extends React.HTMLAttributes { - disabled?: boolean -} - -const MenuItem = styled.li` - ${({ theme }) => theme.fonts.bold14}; - color: ${({ theme }) => theme.colors.grey500}; - display: flex; - align-items: center; - gap: 8px; - outline: none; - cursor: pointer; - margin: 0 6px; - border-radius: 4px; - padding: 8px 12px; - &:hover { - background: ${({ theme }) => theme.colors.grey100}; - color: ${({ theme }) => theme.colors.grey600}; - } - &:active { - background: ${({ theme }) => theme.colors.grey200}; - color: ${({ theme }) => theme.colors.grey600}; - } - &:focus-visible { - background-color: ${({ theme }) => theme.colors.yellow}; - } - ${(props) => props.disabled && disabled} -` +import React from 'react' +import { DropdownMenu } from '../Dropdown' export interface IToggleMenuItem { label: string icon?: JSX.Element handler: () => void - isDisabled?: boolean } - -type ButtonType = - | 'primary' - | 'secondary' - | 'tertiary' - | 'positive' - | 'negative' - | 'secondary_negative' - | 'icon' - | 'iconPrimary' - interface IProps { id: string menuHeader?: JSX.Element toggleButton: JSX.Element - toggleButtonType?: ButtonType menuItems: IToggleMenuItem[] hide?: boolean } @@ -107,121 +28,20 @@ export const ToggleMenu = ({ id, menuHeader, toggleButton, - toggleButtonType = 'icon', menuItems, hide }: IProps) => { - const [showSubmenu, setShowSubmenu] = useState(false) - const [focusedIndex, setFocusedIndex] = useState(null) - const menuRef = useRef(null) - const itemRefs = useRef<(HTMLLIElement | null)[]>([]) - - const closeMenuRef = useRef(() => { - setShowSubmenu(false) - }) - - const closeMenuOnEscapeRef = useRef((e: KeyboardEvent) => { - if (e.key === 'Escape') { - closeMenuRef.current() - } - }) - - const getNextIndex = (last: number) => { - let nextIndex = (last ?? -1) + 1 - while (nextIndex < menuItems.length && menuItems[nextIndex].isDisabled) { - nextIndex++ - } - return nextIndex < menuItems.length ? nextIndex : last - } - - const getPreviousIndex = (last: number) => { - let prevIndex = (last ?? menuItems.length) - 1 - while (prevIndex >= 0 && menuItems[prevIndex].isDisabled) { - prevIndex-- - } - return prevIndex >= 0 ? prevIndex : last - } - - const handleKeyUp = (e: React.KeyboardEvent) => { - if (e.key === 'ArrowDown') { - setFocusedIndex(getNextIndex) - } else if (e.key === 'ArrowUp') { - setFocusedIndex(getPreviousIndex) - } else if ((e.key === 'Enter' || e.key === ' ') && focusedIndex !== null) { - menuItems[focusedIndex].handler() - setShowSubmenu(false) - } - } - - useEffect(() => { - const closeMenu = closeMenuRef.current - const closeMenuOnEscape = closeMenuOnEscapeRef.current - if (showSubmenu) { - menuRef.current?.focus() - //https://github.com/facebook/react/issues/24657#issuecomment-1150119055 - setTimeout(() => document.addEventListener('click', closeMenu), 0) - setTimeout(() => document.addEventListener('keyup', closeMenuOnEscape), 0) - } else { - setFocusedIndex(null) - } - - return () => { - document.removeEventListener('click', closeMenu) - document.removeEventListener('keyup', closeMenuOnEscape) - } - }, [showSubmenu]) - - useEffect(() => { - if (focusedIndex !== null && itemRefs.current[focusedIndex]) { - itemRefs.current[focusedIndex]?.focus() - } - }, [focusedIndex]) - - const toggleMenu = () => { - setShowSubmenu(!showSubmenu) - } - - if (hide) { - return null - } - - return ( - <> - - - {showSubmenu && ( - - {menuHeader && {menuHeader}} - {menuItems.map((mi: IToggleMenuItem, index) => ( - (itemRefs.current[index] = el)} - onFocus={() => setFocusedIndex(index)} - onClick={mi.handler} - tabIndex={mi.isDisabled ? -1 : 0} - role="button" - disabled={mi.isDisabled} - > - {mi.icon && mi.icon} - {mi.label} - - ))} - - )} - - + return hide ? null : ( + + {toggleButton} + + {menuHeader && {menuHeader}} + {menuItems.map((item) => ( + + {item.icon} {item.label} + + ))} + + ) } From 12a0b2ea964263b82fb40e5c870a153e68d0cffc Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 16:41:27 +0600 Subject: [PATCH 35/88] chore: remove action from component --- .../components/src/Action/Action.stories.tsx | 73 ------------------- packages/components/src/Action/Action.tsx | 51 ------------- packages/components/src/Action/index.ts | 11 --- 3 files changed, 135 deletions(-) delete mode 100644 packages/components/src/Action/Action.stories.tsx delete mode 100644 packages/components/src/Action/Action.tsx delete mode 100644 packages/components/src/Action/index.ts diff --git a/packages/components/src/Action/Action.stories.tsx b/packages/components/src/Action/Action.stories.tsx deleted file mode 100644 index 7d4d62f3b77..00000000000 --- a/packages/components/src/Action/Action.stories.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * OpenCRVS is also distributed under the terms of the Civil Registration - * & Healthcare Disclaimer located at http://opencrvs.org/license. - * - * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. - */ -import { ComponentMeta, Story } from '@storybook/react' -import React from 'react' -import { Action } from './Action' -import { Icon } from '../Icon' - -export default { - title: 'Controls/Action', - component: Action, - parameters: { - docs: { - description: { - component: `This \`\` component lists all actions you have the scope for that can be applied on the current declaration / record. - \nAn action is disabled if you need to be assigned to perform the action.` - } - } - } -} as ComponentMeta - -const Template: Story = () => ( -
- , - label: 'View record', - handler: () => alert('View record') - }, - { - icon: , - label: 'Print certified copy', - handler: () => alert('Print certified copy'), - isDisabled: true - }, - { - icon: , - label: 'Correct record', - handler: () => alert('Correct record'), - isDisabled: true - }, - { - icon: , - label: 'Revoke registration', - handler: () => alert('Revoke registration'), - isDisabled: true - }, - { - icon: , - label: 'Unassign', - handler: () => alert('Unassign') - } - ]} - headerText="Assigned to Felix Katongo at Ibombo District Office" - /> -
-) - -export const ActionView = Template.bind({}) -ActionView.args = { - recordStatus: 'Declared', - userScopes: ['declare', 'register'], - isAssigned: true -} diff --git a/packages/components/src/Action/Action.tsx b/packages/components/src/Action/Action.tsx deleted file mode 100644 index 4b832d5c664..00000000000 --- a/packages/components/src/Action/Action.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * OpenCRVS is also distributed under the terms of the Civil Registration - * & Healthcare Disclaimer located at http://opencrvs.org/license. - * - * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. - */ - -import React from 'react' -import { IToggleMenuItem, ToggleMenu } from '../ToggleMenu' -import { Icon } from '../Icon' -import styled from 'styled-components' - -const ActionButton = styled.div` - & > * { - margin: 10px; - } - display: flex; - justify-content: space-around; -` -const MenuHeader = styled.div` - white-space: normal; -` - -export interface IProps { - id: string - menuItems: IToggleMenuItem[] - headerText?: string -} - -export const Action = ({ id, menuItems, headerText }: IProps) => { - return ( - -
Action
- - - } - menuItems={menuItems} - menuHeader={ - headerText ? {headerText} : undefined - } - >
- ) -} diff --git a/packages/components/src/Action/index.ts b/packages/components/src/Action/index.ts deleted file mode 100644 index 89719b4b8a7..00000000000 --- a/packages/components/src/Action/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * OpenCRVS is also distributed under the terms of the Civil Registration - * & Healthcare Disclaimer located at http://opencrvs.org/license. - * - * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. - */ -export * from './Action' From 916febb35a54464a0b34af7e8a7bed57474ceaef Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 17:23:14 +0600 Subject: [PATCH 36/88] chore: deprecate toggleMenu --- .../components/src/ToggleMenu/ToggleMenu.stories.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/components/src/ToggleMenu/ToggleMenu.stories.tsx b/packages/components/src/ToggleMenu/ToggleMenu.stories.tsx index 59b73f0ae07..ef04b996876 100644 --- a/packages/components/src/ToggleMenu/ToggleMenu.stories.tsx +++ b/packages/components/src/ToggleMenu/ToggleMenu.stories.tsx @@ -65,6 +65,13 @@ ToggleMenuView.args = { } export default { - title: 'Controls/Toggle menu', - component: ToggleMenu + title: 'Deprecated/Toggle menu', + component: ToggleMenu, + parameters: { + docs: { + description: { + component: `Note! Deprecated in favor of \`\` component.` + } + } + } } as Meta From 2fb782e85b01d704892ef6f1e05e6ffcd1467308 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 17:36:31 +0600 Subject: [PATCH 37/88] feat: move self unassign to actionMenu --- .../client/src/views/RecordAudit/ActionMenu.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index b8bc4388800..5af28f4f1fb 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -111,6 +111,7 @@ export const ActionMenu: React.FC<{ intl={intl} assignment={assignment} close={close} + isDownloaded={isDownloaded} > )) if (unassignConfirm) { @@ -590,8 +591,7 @@ const UnassignAction: React.FC<{ scope && (scope as any as string[]).includes('register') return ( - isAssignedToSomeoneElse && - userHasUnassignScope && ( + ((isAssignedToSomeoneElse && userHasUnassignScope) || isDownloaded) && ( {intl.formatMessage(buttonMessages.unassign)} @@ -604,7 +604,8 @@ const UnassignModal: React.FC<{ intl: IntlShape close: (result: boolean | null) => void assignment?: GQLAssignmentData -}> = ({ intl, close, assignment }) => + isDownloaded: boolean +}> = ({ intl, close, assignment, isDownloaded }) => assignment && ( close(null)} > - {intl.formatMessage(conflictsMessages.regUnassignDesc, { - name: assignment.firstName + ' ' + assignment.lastName, - officeName: assignment.officeName - })} + {isDownloaded + ? intl.formatMessage(conflictsMessages.selfUnassignDesc) + : intl.formatMessage(conflictsMessages.regUnassignDesc, { + name: assignment.firstName + ' ' + assignment.lastName, + officeName: assignment.officeName + })} ) From d5a37c6d1e9c42ae37e6e1b3bffa3a28933f2c96 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 17:41:25 +0600 Subject: [PATCH 38/88] chore: dont unassign from download button --- .../client/src/components/interface/DownloadButton.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/client/src/components/interface/DownloadButton.tsx b/packages/client/src/components/interface/DownloadButton.tsx index fd7d61fa747..f444b815fc8 100644 --- a/packages/client/src/components/interface/DownloadButton.tsx +++ b/packages/client/src/components/interface/DownloadButton.tsx @@ -337,7 +337,12 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { {} + : onClickDownload + } className={className} aria-label={intl.formatMessage(constantsMessages.assignRecord)} > From aa1b02283f9c09b9635485701d447fb32e322d10 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 17:53:25 +0600 Subject: [PATCH 39/88] chore: remove unused imports --- .../src/views/RecordAudit/RecordAudit.tsx | 44 ++----------------- 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index b474558a941..5546a24aad5 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -18,7 +18,6 @@ import { import styled from 'styled-components' import { DeclarationIcon, - Edit, BackArrow, Duplicate } from '@opencrvs/components/lib/icons' @@ -31,7 +30,6 @@ import { goToPrintCertificate, goToUserProfile, goToTeamUserList, - goToViewRecordPage, goToIssueCertificate } from '@client/navigation' import { @@ -61,24 +59,16 @@ import { Scope, hasRegisterScope } from '@client/utils/authUtils' import { PrimaryButton, TertiaryButton, - ICON_ALIGNMENT, DangerButton, CircleButton } from '@opencrvs/components/lib/buttons' -import { - ARCHIVED, - DECLARED, - VALIDATED, - REJECTED, - FIELD_AGENT_ROLES, - IN_PROGRESS -} from '@client/utils/constants' +import { ARCHIVED } from '@client/utils/constants' import { IQueryData } from '@client/workqueue' import { Query } from '@client/components/Query' import { FETCH_DECLARATION_SHORT_INFO } from '@client/views/RecordAudit/queries' import { HOME } from '@client/navigation/routes' import { recordAuditMessages } from '@client/i18n/messages/views/recordAudit' -import { CorrectionSection, IForm } from '@client/forms' +import { IForm } from '@client/forms' import { buttonMessages, constantsMessages } from '@client/i18n/messages' import { getLanguage } from '@client/i18n/selectors' import { @@ -87,7 +77,6 @@ import { Event, History } from '@client/utils/gateway' -import { messages as correctionMessages } from '@client/i18n/messages/views/correction' import { get } from 'lodash' import { IRegisterFormState } from '@client/forms/register/reducer' import { goBack } from 'connected-react-router' @@ -98,13 +87,7 @@ import { getWQDeclarationData } from './utils' import { GetDeclarationInfo } from './DeclarationInfo' -import { - ShowDownloadButton, - ShowReviewButton, - ShowUpdateButton, - ShowPrintButton, - ShowIssueButton -} from './ActionButtons' +import { ShowDownloadButton } from './ActionButtons' import { GetHistory } from './History' import { ActionDetailsModal } from './ActionDetailsModal' import { DuplicateWarning } from '@client/views/Duplicates/DuplicateWarning' @@ -119,9 +102,6 @@ import { useDeclaration } from '@client/declarations/selectors' import { errorMessages } from '@client/i18n/messages/errors' import { Frame } from '@opencrvs/components/lib/Frame' import { AppBar, IAppBarProps } from '@opencrvs/components/lib/AppBar' -import { useOnlineStatus } from '@client/utils' -import { Button } from '@opencrvs/components/lib/Button' -import { Icon } from '@opencrvs/components/lib/Icon' import { UserDetails } from '@client/utils/userUtils' import { client } from '@client/utils/apolloClient' @@ -140,10 +120,6 @@ const MobileHeader = styled(AppBar)` } ` -const StyledTertiaryButton = styled(TertiaryButton)` - align-self: center; -` - const BackButtonDiv = styled.div` display: inline; ` @@ -163,12 +139,6 @@ const StyledDuplicateWarning = styled(DuplicateWarning)` } ` -const DesktopDiv = styled.div` - @media (max-width: ${({ theme }) => theme.grid.breakpoints.md}px) { - display: none; - } -` - interface IStateProps { userDetails: UserDetails | null language: string @@ -220,8 +190,6 @@ export const STATUSTOCOLOR: { [key: string]: string } = { ISSUED: 'blue' } -const ARCHIVABLE_STATUSES = [IN_PROGRESS, DECLARED, VALIDATED, REJECTED] - function ReinstateButton({ toggleDisplayDialog, refetchDeclarationInfo @@ -250,7 +218,7 @@ function ReinstateButton({ : REINSTATE_DEATH_DECLARATION } // update the store and indexDb with the latest status of the declaration - onCompleted={(data) => { + onCompleted={() => { refetchDeclarationInfo?.() dispatch(deleteDeclaration(declaration.id, client)) }} @@ -287,7 +255,6 @@ function RecordAuditBody({ draft, duplicates, intl, - goToCertificateCorrection, goToPrintCertificate, goToPage, goToHomeTab, @@ -319,9 +286,6 @@ function RecordAuditBody({ const [actionDetailsData, setActionDetailsData] = React.useState() - const isOnline = useOnlineStatus() - const dispatch = useDispatch() - if (!registerForm.registerForm || !declaration.type) return <> const toggleActionDetails = (actionItem: History | null, itemIndex = -1) => { From ee1cc112a0dc9df6916db487dcb05275d314fae7 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 27 Sep 2024 17:56:21 +0600 Subject: [PATCH 40/88] chore: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23678098bbc..add96f74d65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Two new statuses of record are added: `Validated` and `Correction Requested` for advanced search parameters [#6365](https://github.com/opencrvs/opencrvs-core/issues/6365) - A new field: `Time Period` is added to advanced search [#6365](https://github.com/opencrvs/opencrvs-core/issues/6365) - Deploy UI-Kit Storybook to [opencrvs.pages.dev](https://opencrvs.pages.dev) to allow extending OpenCRVS using the component library +- Record audit action buttons are moved into action menu [#7390](https://github.com/opencrvs/opencrvs-core/issues/7390) ## Bug fixes From 610a7023a5b7b353dcd9453ebcbc116b493a2f09 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Mon, 30 Sep 2024 12:43:29 +0600 Subject: [PATCH 41/88] fix: RA will see "correct record" button --- packages/client/src/views/RecordAudit/ActionMenu.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 5af28f4f1fb..aec52dc936e 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -279,7 +279,9 @@ const CorrectRecordAction: React.FC< // @ToDo use: `record.registration-correct` after configurable role pr is merged const userHasRegisterScope = - scope && (scope as any as string[]).includes('register') + scope && + ((scope as any as string[]).includes('register') || + (scope as any as string[]).includes('validate')) return ( isBirthOrDeathEvent && From 30465774f522ff9ff728f67c2f959576193a2d10 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Mon, 30 Sep 2024 15:05:08 +0600 Subject: [PATCH 42/88] fix: add id in dropdown menu --- .../src/views/RecordAudit/ActionMenu.tsx | 2 +- packages/components/src/Dropdown/Dropdown.tsx | 21 +++++++++++++++---- .../components/src/ToggleMenu/ToggleMenu.tsx | 13 ++++++++++-- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index aec52dc936e..fc7ecc613ca 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -122,7 +122,7 @@ export const ActionMenu: React.FC<{ return ( <> - + }> {intl.formatMessage(messages.action)} diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index b5235a97625..ea32b0acf42 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -117,7 +117,10 @@ export type IDropdownPosition = | 'left' | 'right' -const DropdownWrapper: React.FC<{ children: ReactNode }> = ({ children }) => { +const DropdownWrapper: React.FC<{ children: ReactNode; id?: string }> = ({ + children, + id +}) => { const { closeDropdown } = useDropdown() const rootRef = useRef(null) useEffect(() => { @@ -132,13 +135,23 @@ const DropdownWrapper: React.FC<{ children: ReactNode }> = ({ children }) => { document.removeEventListener('mousedown', handleClickOutside) } }, [closeDropdown]) - return {children} + return ( + + {children} + + ) } -export const DropdownMenu = ({ children }: { children: ReactNode }) => { +export const DropdownMenu = ({ + children, + id +}: { + children: ReactNode + id?: string +}) => { return ( - {children} + {children} ) } diff --git a/packages/components/src/ToggleMenu/ToggleMenu.tsx b/packages/components/src/ToggleMenu/ToggleMenu.tsx index 97866f4e09a..28948fd3a40 100644 --- a/packages/components/src/ToggleMenu/ToggleMenu.tsx +++ b/packages/components/src/ToggleMenu/ToggleMenu.tsx @@ -10,6 +10,13 @@ */ import React from 'react' import { DropdownMenu } from '../Dropdown' +import styled from 'styled-components' + +const TriggerWrapper = styled.div` + height: 40px; + display: flex; + align-items: center; +` export interface IToggleMenuItem { label: string @@ -32,8 +39,10 @@ export const ToggleMenu = ({ hide }: IProps) => { return hide ? null : ( - - {toggleButton} + + + {toggleButton} + {menuHeader && {menuHeader}} {menuItems.map((item) => ( From 3fb579c9cda8f447f6d89fac5844c99fd3992fdf Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 8 Oct 2024 14:33:23 +0600 Subject: [PATCH 43/88] refactor: `isDownloadable` logic --- .../src/components/interface/DownloadButton.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/client/src/components/interface/DownloadButton.tsx b/packages/client/src/components/interface/DownloadButton.tsx index f444b815fc8..6ef4dc87c7d 100644 --- a/packages/client/src/components/interface/DownloadButton.tsx +++ b/packages/client/src/components/interface/DownloadButton.tsx @@ -258,7 +258,11 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { // field agents can only retrieve declarations const isNotFieldAgent = !FIELD_AGENT_ROLES.includes(String(userRole)) - const onClickDownload = useCallback( + const isDownloadable = + status !== DOWNLOAD_STATUS.DOWNLOADED && + (!assignment || assignment.practitionerId === practitionerId) + + const onDownloadClick = useCallback( (e: React.MouseEvent) => { if ( (assignment?.practitionerId !== practitionerId || @@ -337,12 +341,7 @@ function DownloadButtonComponent(props: DownloadButtonProps & HOCProps) { {} - : onClickDownload - } + onClick={isDownloadable ? onDownloadClick : undefined} className={className} aria-label={intl.formatMessage(constantsMessages.assignRecord)} > From fe52196c7038d9002c44cfbb16bbed060ee275fc Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 8 Oct 2024 14:52:31 +0600 Subject: [PATCH 44/88] refactor: remove types from actionMessages --- .../client/src/i18n/messages/views/action.ts | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/packages/client/src/i18n/messages/views/action.ts b/packages/client/src/i18n/messages/views/action.ts index 1181ac49645..8024f911ae1 100644 --- a/packages/client/src/i18n/messages/views/action.ts +++ b/packages/client/src/i18n/messages/views/action.ts @@ -8,24 +8,9 @@ * * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import { defineMessages, MessageDescriptor } from 'react-intl' +import { defineMessages } from 'react-intl' -interface IActionMessages - extends Record { - action: MessageDescriptor - assignedTo: MessageDescriptor - view: MessageDescriptor - correctRecord: MessageDescriptor - archiveRecord: MessageDescriptor - reinstateRecord: MessageDescriptor - reviewCorrection: MessageDescriptor - reviewDeclaration: MessageDescriptor - updateDeclaration: MessageDescriptor - printDeclaration: MessageDescriptor - issueCertificate: MessageDescriptor -} - -const messagesToDefine: IActionMessages = { +const messagesToDefine = { action: { defaultMessage: 'Action', description: 'Label for action button in dropdown menu', @@ -83,4 +68,4 @@ const messagesToDefine: IActionMessages = { id: 'action.issue' } } -export const messages: IActionMessages = defineMessages(messagesToDefine) +export const messages = defineMessages(messagesToDefine) From 2bb9fe4dee596bdf0df0c5d06ce79eca3d7cbe98 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 8 Oct 2024 15:20:48 +0600 Subject: [PATCH 45/88] refactor: use `useIntl` and `useDispatch` hooks instead of props drilling --- .../src/views/RecordAudit/ActionMenu.tsx | 237 ++++++++---------- .../src/views/RecordAudit/RecordAudit.tsx | 13 +- 2 files changed, 105 insertions(+), 145 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index fc7ecc613ca..b5b187aec3c 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -25,10 +25,9 @@ import { goToIssueCertificate, goToPage, goToPrintCertificate, - goToUserProfile, goToViewRecordPage } from '@client/navigation' -import { IntlShape } from 'react-intl' +import { useIntl } from 'react-intl' import { Scope } from '@sentry/react' import { IDeclarationData } from './utils' import { @@ -41,7 +40,6 @@ import { } from '@client/declarations' import { CorrectionSection } from '@client/forms' import { buttonMessages } from '@client/i18n/messages' -import { UserDetails } from '@client/utils/userUtils' import { EVENT_STATUS } from '@client/workqueue' import { DRAFT_BIRTH_PARENT_FORM_PAGE, @@ -60,33 +58,16 @@ import { GQLAssignmentData } from '@client/utils/gateway-deprecated-do-not-use' export const ActionMenu: React.FC<{ declaration: IDeclarationData - intl: IntlShape scope: Scope draft: IDeclaration | null - userDetails: UserDetails | null duplicates?: string[] toggleDisplayDialog: () => void - clearCorrectionAndPrintChanges: typeof clearCorrectionAndPrintChanges - goToPage: typeof goToPage - goToPrintCertificate: typeof goToPrintCertificate - goToIssueCertificate: typeof goToIssueCertificate - goToUserProfile: typeof goToUserProfile -}> = ({ - declaration, - intl, - scope, - draft, - userDetails, - toggleDisplayDialog, - goToPage, - clearCorrectionAndPrintChanges, - goToPrintCertificate, - goToIssueCertificate, - duplicates -}) => { +}> = ({ declaration, scope, draft, toggleDisplayDialog, duplicates }) => { const dispatch = useDispatch() const [modal, openModal] = useModal() + const intl = useIntl() + const { id, type, assignment, status } = declaration const isDownloaded = @@ -108,7 +89,6 @@ export const ActionMenu: React.FC<{ const handleUnassign = async () => { const unassignConfirm = await openModal((close) => ( )} - + @@ -183,16 +153,12 @@ export const ActionMenu: React.FC<{ declarationId={id} type={type} isDownloaded={isDownloaded} - intl={intl} scope={scope} - clearCorrectionAndPrintChanges={clearCorrectionAndPrintChanges} - goToPrintCertificate={goToPrintCertificate} /> = ({ declarationStatus, declarationId, intl }) => { +}> = ({ declarationStatus, declarationId }) => { + const intl = useIntl() const dispatch = useDispatch() const recordOrDeclaration = [ @@ -263,8 +225,9 @@ const ViewAction: React.FC<{ const CorrectRecordAction: React.FC< IActionItemCommonProps & IDeclarationProps -> = ({ declarationId, declarationStatus, type, isDownloaded, intl, scope }) => { +> = ({ declarationId, declarationStatus, type, isDownloaded, scope }) => { const dispatch = useDispatch() + const intl = useIntl() const isBirthOrDeathEvent = type && [Event.Birth, Event.Death].includes(type.toLowerCase() as Event) @@ -308,7 +271,8 @@ const CorrectRecordAction: React.FC< const ArchiveAction: React.FC< IActionItemCommonProps & { toggleDisplayDialog?: () => void } -> = ({ toggleDisplayDialog, intl, isDownloaded, declarationStatus, scope }) => { +> = ({ toggleDisplayDialog, isDownloaded, declarationStatus, scope }) => { + const intl = useIntl() const isArchivable = declarationStatus && [ @@ -340,7 +304,8 @@ const ArchiveAction: React.FC< const ReinstateAction: React.FC< IActionItemCommonProps & { toggleDisplayDialog?: () => void } -> = ({ toggleDisplayDialog, isDownloaded, intl, declarationStatus, scope }) => { +> = ({ toggleDisplayDialog, isDownloaded, declarationStatus, scope }) => { + const intl = useIntl() const isArchived = declarationStatus === SUBMISSION_STATUS.ARCHIVED // @ToDo use: `record.registration-reinstate` after configurable role pr is merged @@ -362,18 +327,18 @@ const ReinstateAction: React.FC< } const ReviewAction: React.FC< - IActionItemCommonProps & - IDeclarationProps & { isDuplicate: boolean; goToPage: typeof goToPage } + IActionItemCommonProps & IDeclarationProps & { isDuplicate: boolean } > = ({ declarationId, declarationStatus, type, scope, isDownloaded, - isDuplicate, - intl, - goToPage + isDuplicate }) => { + const intl = useIntl() + const dispatch = useDispatch() + const isPendingCorrection = declarationStatus === EVENT_STATUS.CORRECTION_REQUESTED @@ -390,11 +355,13 @@ const ReviewAction: React.FC< return isPendingCorrection && userHasReviewScope ? ( { - goToPage( - REVIEW_CORRECTION, - declarationId as string, - 'review', - type as string + dispatch( + goToPage( + REVIEW_CORRECTION, + declarationId as string, + 'review', + type as string + ) ) }} disabled={!isDownloaded} @@ -406,11 +373,13 @@ const ReviewAction: React.FC< isReviewableDeclaration && userHasReviewScope && ( { - goToPage( - REVIEW_EVENT_PARENT_FORM_PAGE, - declarationId as string, - 'review', - type as string + dispatch( + goToPage( + REVIEW_EVENT_PARENT_FORM_PAGE, + declarationId as string, + 'review', + type as string + ) ) }} disabled={!isDownloaded} @@ -422,17 +391,16 @@ const ReviewAction: React.FC< ) } -const UpdateAction: React.FC< - IActionItemCommonProps & IDeclarationProps & { goToPage: typeof goToPage } -> = ({ +const UpdateAction: React.FC = ({ declarationId, declarationStatus, type, scope, - isDownloaded, - intl, - goToPage + isDownloaded }) => { + const intl = useIntl() + const dispatch = useDispatch() + const isUpdatableDeclaration = declarationStatus && [ @@ -469,13 +437,14 @@ const UpdateAction: React.FC< userHasUpdateScope && ( { - goToPage && + dispatch( goToPage( PAGE_ROUTE, declarationId as string, PAGE_ID, type as string ) + ) }} disabled={!isDownloaded} > @@ -486,22 +455,16 @@ const UpdateAction: React.FC< ) } -const PrintAction: React.FC< - IActionItemCommonProps & - IDeclarationProps & { - clearCorrectionAndPrintChanges: typeof clearCorrectionAndPrintChanges - goToPrintCertificate: typeof goToPrintCertificate - } -> = ({ +const PrintAction: React.FC = ({ declarationId, declarationStatus, scope, type, - isDownloaded, - intl, - clearCorrectionAndPrintChanges, - goToPrintCertificate + isDownloaded }) => { + const intl = useIntl() + const dispatch = useDispatch() + const isPrintable = declarationStatus && [SUBMISSION_STATUS.REGISTERED, SUBMISSION_STATUS.ISSUED].includes( @@ -519,10 +482,12 @@ const PrintAction: React.FC< userHasPrintScope && ( { - clearCorrectionAndPrintChanges(declarationId as string) - goToPrintCertificate( - declarationId as string, - (type as string).toLocaleLowerCase() + dispatch(clearCorrectionAndPrintChanges(declarationId as string)) + dispatch( + goToPrintCertificate( + declarationId as string, + (type as string).toLocaleLowerCase() + ) ) }} disabled={!isDownloaded} @@ -538,9 +503,9 @@ const IssueAction: React.FC = ({ declarationId, isDownloaded, declarationStatus, - scope, - intl + scope }) => { + const intl = useIntl() const dispatch = useDispatch() const isCertified = declarationStatus === SUBMISSION_STATUS.CERTIFIED @@ -569,23 +534,26 @@ const IssueAction: React.FC = ({ } const DeleteAction: React.FC<{ - intl: IntlShape handleDelete: () => void declarationStatus?: string -}> = ({ intl, handleDelete, declarationStatus }) => - declarationStatus === SUBMISSION_STATUS.DRAFT && ( - - - {intl.formatMessage(buttonMessages.deleteDeclaration)} - +}> = ({ handleDelete, declarationStatus }) => { + const intl = useIntl() + return ( + declarationStatus === SUBMISSION_STATUS.DRAFT && ( + + + {intl.formatMessage(buttonMessages.deleteDeclaration)} + + ) ) +} const UnassignAction: React.FC<{ - intl: IntlShape handleUnassign: () => void isDownloaded: boolean assignment?: GQLAssignmentData scope: Scope -}> = ({ intl, handleUnassign, isDownloaded, assignment, scope }) => { +}> = ({ handleUnassign, isDownloaded, assignment, scope }) => { + const intl = useIntl() const isAssignedToSomeoneElse = !isDownloaded && assignment // @ToDo use: appropriate scope after configurable role pr is merged @@ -603,44 +571,47 @@ const UnassignAction: React.FC<{ } const UnassignModal: React.FC<{ - intl: IntlShape close: (result: boolean | null) => void assignment?: GQLAssignmentData isDownloaded: boolean -}> = ({ intl, close, assignment, isDownloaded }) => - assignment && ( - { - close(null) - }} - > - {intl.formatMessage(buttonMessages.cancel)} - , - { - close(true) - }} - > - {intl.formatMessage(buttonMessages.unassign)} - - ]} - show={true} - handleClose={() => close(null)} - > - {isDownloaded - ? intl.formatMessage(conflictsMessages.selfUnassignDesc) - : intl.formatMessage(conflictsMessages.regUnassignDesc, { - name: assignment.firstName + ' ' + assignment.lastName, - officeName: assignment.officeName - })} - +}> = ({ close, assignment, isDownloaded }) => { + const intl = useIntl() + return ( + assignment && ( + { + close(null) + }} + > + {intl.formatMessage(buttonMessages.cancel)} + , + { + close(true) + }} + > + {intl.formatMessage(buttonMessages.unassign)} + + ]} + show={true} + handleClose={() => close(null)} + > + {isDownloaded + ? intl.formatMessage(conflictsMessages.selfUnassignDesc) + : intl.formatMessage(conflictsMessages.regUnassignDesc, { + name: assignment.firstName + ' ' + assignment.lastName, + officeName: assignment.officeName + })} + + ) ) +} diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index 5546a24aad5..b1db30f134b 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -29,8 +29,7 @@ import { goToCertificateCorrection, goToPrintCertificate, goToUserProfile, - goToTeamUserList, - goToIssueCertificate + goToTeamUserList } from '@client/navigation' import { injectIntl, @@ -250,13 +249,10 @@ function ReinstateButton({ function RecordAuditBody({ archiveDeclaration, - clearCorrectionAndPrintChanges, declaration, draft, duplicates, intl, - goToPrintCertificate, - goToPage, goToHomeTab, scope, refetchDeclarationInfo, @@ -307,16 +303,9 @@ function RecordAuditBody({ ) desktopActionsView.push(actions[actions.length - 1]) From 08f121337eda30ff12f5e4e741ab5a468060628c Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 8 Oct 2024 18:57:57 +0600 Subject: [PATCH 46/88] refactor: dont pass assignment to unassign comp --- .../src/views/RecordAudit/ActionMenu.tsx | 94 ++++++++++--------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index b5b187aec3c..b7107b3dcb9 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -87,13 +87,18 @@ export const ActionMenu: React.FC<{ return } const handleUnassign = async () => { - const unassignConfirm = await openModal((close) => ( - - )) + const { firstName, lastName, officeName } = assignment || {} + const unassignConfirm = await openModal( + (close) => + assignment && ( + + ) + ) if (unassignConfirm) { dispatch(unassignDeclaration(id, client)) } @@ -572,46 +577,45 @@ const UnassignAction: React.FC<{ const UnassignModal: React.FC<{ close: (result: boolean | null) => void - assignment?: GQLAssignmentData isDownloaded: boolean -}> = ({ close, assignment, isDownloaded }) => { + name: string + officeName?: string +}> = ({ close, isDownloaded, name, officeName }) => { const intl = useIntl() return ( - assignment && ( - { - close(null) - }} - > - {intl.formatMessage(buttonMessages.cancel)} - , - { - close(true) - }} - > - {intl.formatMessage(buttonMessages.unassign)} - - ]} - show={true} - handleClose={() => close(null)} - > - {isDownloaded - ? intl.formatMessage(conflictsMessages.selfUnassignDesc) - : intl.formatMessage(conflictsMessages.regUnassignDesc, { - name: assignment.firstName + ' ' + assignment.lastName, - officeName: assignment.officeName - })} - - ) + { + close(null) + }} + > + {intl.formatMessage(buttonMessages.cancel)} + , + { + close(true) + }} + > + {intl.formatMessage(buttonMessages.unassign)} + + ]} + show={true} + handleClose={() => close(null)} + > + {isDownloaded + ? intl.formatMessage(conflictsMessages.selfUnassignDesc) + : intl.formatMessage(conflictsMessages.regUnassignDesc, { + name, + officeName + })} + ) } From 3d700d3482a3ef6f18102bf85181d605853ca02e Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 8 Oct 2024 19:00:54 +0600 Subject: [PATCH 47/88] refactor: use `offsetX` and `offsetY` instead of `offset_x` and `offset_y` --- .../components/src/Dropdown/Dropdown.stories.tsx | 8 ++++---- packages/components/src/Dropdown/Dropdown.tsx | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.stories.tsx b/packages/components/src/Dropdown/Dropdown.stories.tsx index 248891a3766..fd9bb19ddd7 100644 --- a/packages/components/src/Dropdown/Dropdown.stories.tsx +++ b/packages/components/src/Dropdown/Dropdown.stories.tsx @@ -15,8 +15,8 @@ import { PrimaryButton } from '../../src/buttons' const Template = (args: { position: IDropdownPosition - offset_x: number - offset_y: number + offsetX: number + offsetY: number }) => (
` border-radius: 4px; border: 1px solid ${({ theme }) => theme.colors.grey300}; @@ -43,7 +43,7 @@ const StyledContent = styled.ul<{ display: flex; flex-direction: column; padding: 8px 0; - margin: ${({ offset_x, offset_y }) => `${offset_y}px ${offset_x}px`}; + margin: ${({ offsetX, offsetY }) => `${offsetY}px ${offsetX}px`}; list-style: none; ${({ position }) => { @@ -164,14 +164,14 @@ DropdownMenu.Trigger = Trigger const Content: React.FC<{ position?: string - offset_x?: number - offset_y?: number + offsetX?: number + offsetY?: number children: ReactNode -}> = ({ position = 'bottom-left', offset_x = 0, offset_y = 10, children }) => { +}> = ({ position = 'bottom-left', offsetX = 0, offsetY = 10, children }) => { const { isOpen } = useDropdown() return isOpen ? ( - + {children} ) : null From 33ef0bf24e57c1abc299ed5e281ae94094c76542 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 8 Oct 2024 19:20:52 +0600 Subject: [PATCH 48/88] refactor: use `
diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index d0c368a1f18..627eebc749f 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -20,7 +20,6 @@ const StyledWrapper = styled.nav` display: flex; button { - padding: 0; height: auto; } ` From 62836f654fa0ce80c2eb7bc5a3f64d78c7c20392 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 8 Oct 2024 19:29:06 +0600 Subject: [PATCH 49/88] refactor: remove unnecessary `
`s --- .../src/Dropdown/Dropdown.stories.tsx | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.stories.tsx b/packages/components/src/Dropdown/Dropdown.stories.tsx index 56412c409b8..3c1a93eb6ff 100644 --- a/packages/components/src/Dropdown/Dropdown.stories.tsx +++ b/packages/components/src/Dropdown/Dropdown.stories.tsx @@ -33,34 +33,30 @@ const Template = (args: { -
- City - - alert('Dhaka is the capital of Bangladesh')} - > - Dhaka - - alert('Helsinki is the capital of Finland')} - > - Helsinki - -
+ City + + alert('Dhaka is the capital of Bangladesh')} + > + Dhaka + + alert('Helsinki is the capital of Finland')} + > + Helsinki + -
- Season - - alert('Winter is cold')} - disabled={true} - > - Winter - - alert('Summer is hot')}> - Summer - -
+ Season + + alert('Winter is cold')} + disabled={true} + > + Winter + + alert('Summer is hot')}> + Summer +
From 80671a0c14a450009bb97ec43877bc96da6e5e76 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 11 Oct 2024 14:49:14 +0600 Subject: [PATCH 50/88] feat: use `anchor` and `popover` api to toggle the dropdown visivility --- .../src/Dropdown/Dropdown.stories.tsx | 2 +- packages/components/src/Dropdown/Dropdown.tsx | 79 ++++++++++--------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.stories.tsx b/packages/components/src/Dropdown/Dropdown.stories.tsx index 3c1a93eb6ff..ac1e35001cb 100644 --- a/packages/components/src/Dropdown/Dropdown.stories.tsx +++ b/packages/components/src/Dropdown/Dropdown.stories.tsx @@ -63,7 +63,7 @@ const Template = (args: { ) export const DropdownView = Template.bind({}) DropdownView.args = { - position: 'bottom-left', + position: 'bottom span-left', offsetX: 0, offsetY: 10 } diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 627eebc749f..a79b9cc43b0 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -24,11 +24,29 @@ const StyledWrapper = styled.nav` } ` -const StyledContent = styled.ul<{ +const StyledTrigger = styled.button.withConfig({ + shouldForwardProp: (prop, defaultValidatorFn) => + ['popovertarget'].includes(prop) || defaultValidatorFn(prop) + // Forward popovertarget prop directly +})<{ popovertarget: string }>` + anchor-name: --Dropdown-Anchor; + margin: 0; + padding: 0; + border: 0; + height: fit-content !important; +` + +type StyledContentProp = { position: string offsetX: number offsetY: number -}>` + popover: string +} +const StyledContent = styled.ul.withConfig({ + shouldForwardProp: (prop, defaultValidatorFn) => + ['popover'].includes(prop) || defaultValidatorFn(prop) + // Forward popover prop directly +})` border-radius: 4px; border: 1px solid ${({ theme }) => theme.colors.grey300}; background-color: ${({ theme }) => theme.colors.white}; @@ -37,36 +55,13 @@ const StyledContent = styled.ul<{ min-width: 200px; width: auto; white-space: nowrap; - position: absolute; - z-index: 2; - display: flex; - flex-direction: column; padding: 8px 0; + position: fixed; + position-anchor: --Dropdown-Anchor; + inset-area: ${({ position }) => position}; + margin: 0; margin: ${({ offsetX, offsetY }) => `${offsetY}px ${offsetX}px`}; list-style: none; - - ${({ position }) => { - switch (position) { - case 'top': - return 'bottom: 100%; left: 50%; transform: translateX(-50%);' - case 'top-right': - return 'bottom: 100%; left: 0;' - case 'top-left': - return 'bottom: 100%; right: 0;' - case 'bottom': - return 'top: 100%; left: 50%; transform: translateX(-50%);' - case 'bottom-right': - return 'top: 100%; left: 0;' - case 'bottom-left': - return 'top: 100%; right: 0;' - case 'right': - return 'top: 50%; left: 100%; transform: translateY(-50%);' - case 'left': - return 'top: 50%; right: 100%; transform: translateY(-50%);' - default: - return '' - } - }} ` const Label = styled.li` @@ -156,8 +151,9 @@ export const DropdownMenu = ({ } const Trigger: React.FC<{ children: JSX.Element }> = ({ children }) => { - const { toggleDropdown } = useDropdown() - return React.cloneElement(children, { onClick: toggleDropdown }) + return ( + {children} + ) } DropdownMenu.Trigger = Trigger @@ -166,14 +162,23 @@ const Content: React.FC<{ offsetX?: number offsetY?: number children: ReactNode -}> = ({ position = 'bottom-left', offsetX = 0, offsetY = 10, children }) => { - const { isOpen } = useDropdown() - - return isOpen ? ( - +}> = ({ + position = 'bottom span-left', + offsetX = 0, + offsetY = 10, + children +}) => { + return ( + {children} - ) : null + ) } DropdownMenu.Content = Content From 8773dc86f49fb71fd135a480dbeaf1a140287138 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 11 Oct 2024 17:38:59 +0600 Subject: [PATCH 51/88] fix: focus --- packages/components/src/Dropdown/Dropdown.tsx | 44 ++++++++-------- .../src/Dropdown/DropdownContext.tsx | 50 +++++++------------ 2 files changed, 42 insertions(+), 52 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index a79b9cc43b0..7effde15429 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -18,10 +18,6 @@ const StyledWrapper = styled.nav` position: relative; height: 40px; display: flex; - - button { - height: auto; - } ` const StyledTrigger = styled.button.withConfig({ @@ -56,9 +52,9 @@ const StyledContent = styled.ul.withConfig({ width: auto; white-space: nowrap; padding: 8px 0; - position: fixed; position-anchor: --Dropdown-Anchor; inset-area: ${({ position }) => position}; + position-area: ${({ position }) => position}; margin: 0; margin: ${({ offsetX, offsetY }) => `${offsetY}px ${offsetX}px`}; list-style: none; @@ -115,20 +111,8 @@ const DropdownWrapper: React.FC<{ children: ReactNode; id?: string }> = ({ children, id }) => { - const { closeDropdown } = useDropdown() const rootRef = useRef(null) - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if (rootRef.current && !rootRef.current.contains(event.target as Node)) { - closeDropdown() - } - } - document.addEventListener('mousedown', handleClickOutside) - return () => { - document.removeEventListener('mousedown', handleClickOutside) - } - }, [closeDropdown]) return ( {children} @@ -168,12 +152,31 @@ const Content: React.FC<{ offsetY = 10, children }) => { + const { setFocusedIndex } = useDropdown() + + useEffect(() => { + const popover = document.getElementById('Dropdown-Content') + const onTogglePopover = (event: Event & { newState: string }) => { + if (event.newState === 'open') { + setFocusedIndex(0) + } else { + setFocusedIndex(-1) + } + } + + popover?.addEventListener('toggle', onTogglePopover) + + return () => { + popover?.removeEventListener('toggle', onTogglePopover) + } + }, [setFocusedIndex]) + return ( {children} @@ -196,13 +199,12 @@ const Item = ({ children: ReactNode disabled?: boolean }) => { - const { addItemRef, handleKeyDown, toggleDropdown, closeDropdown } = - useDropdown() + const { addItemRef, handleKeyDown, closeDropdown } = useDropdown() const keyDownhandler = (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { onClickHandler() - toggleDropdown() + closeDropdown() } else if (e.key === 'Escape') { closeDropdown() } else handleKeyDown(e) diff --git a/packages/components/src/Dropdown/DropdownContext.tsx b/packages/components/src/Dropdown/DropdownContext.tsx index 1132d2dc05f..646db16084e 100644 --- a/packages/components/src/Dropdown/DropdownContext.tsx +++ b/packages/components/src/Dropdown/DropdownContext.tsx @@ -9,20 +9,13 @@ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import React, { - createContext, - useContext, - useEffect, - useRef, - useState -} from 'react' +import React, { createContext, useContext, useRef, useState } from 'react' interface DropdownContextType { - isOpen: boolean - toggleDropdown: () => void - closeDropdown: () => void addItemRef: (item: HTMLLIElement | null) => void handleKeyDown: (e: React.KeyboardEvent) => void + setFocusedIndex: (e: number) => void + closeDropdown: () => void } const DropdownContext = createContext( @@ -40,8 +33,6 @@ export const useDropdown = () => { export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const [isOpen, setIsOpen] = useState(false) - const [focusedIndex, setFocusedIndex] = useState(-1) const itemRefs = useRef<(HTMLLIElement | null)[]>([]) @@ -52,16 +43,6 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ } } - const closeDropdown = () => isOpen && toggleDropdown() - - const toggleDropdown = () => { - itemRefs.current = [] - if (!isOpen) { - setFocusedIndex(-1) - } - setIsOpen((prev) => !prev) - } - const getNextIndex = (last: number) => { return Math.min(last + 1, itemRefs.current.length - 1) } @@ -70,29 +51,36 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ return Math.max(last - 1, 0) } + const closeDropdown = () => + document.getElementById('Dropdown-Content')?.togglePopover() + const handleKeyDown = (e: React.KeyboardEvent) => { e.preventDefault() if (e.key === 'ArrowDown') { setFocusedIndex(getNextIndex) } else if (e.key === 'ArrowUp') { setFocusedIndex(getPreviousIndex) + } else if (e.key === 'Tab') { + if (e.shiftKey) setFocusedIndex(getPreviousIndex) + else setFocusedIndex(getNextIndex) } } - useEffect(() => { - if (focusedIndex !== null && itemRefs.current[focusedIndex]) { - itemRefs.current[focusedIndex]?.focus() - } - }, [focusedIndex]) + if ( + focusedIndex !== null && + itemRefs.current[focusedIndex] && + document.activeElement !== itemRefs.current[focusedIndex] + ) { + itemRefs.current[focusedIndex]?.focus() + } return ( {children} From c5453f6e7e18bc9755a10156ef7f8ae7f6dc2454 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 11 Oct 2024 17:39:41 +0600 Subject: [PATCH 52/88] chore: remove as string --- packages/client/src/views/RecordAudit/ActionMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index b7107b3dcb9..b0dea47c6cd 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -219,7 +219,7 @@ const ViewAction: React.FC<{ return ( { - dispatch(goToViewRecordPage(declarationId as string)) + dispatch(goToViewRecordPage(declarationId)) }} > From ce74d44155933fa1337bd218127d573a22bc02eb Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 11 Oct 2024 18:17:45 +0600 Subject: [PATCH 53/88] refactor: early return if condition fails --- .../src/views/RecordAudit/ActionMenu.tsx | 173 +++++++++--------- 1 file changed, 84 insertions(+), 89 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index b0dea47c6cd..f166bb1fc79 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -251,26 +251,26 @@ const CorrectRecordAction: React.FC< ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) + if (!isBirthOrDeathEvent || !canBeCorrected || !userHasRegisterScope) { + return null + } + return ( - isBirthOrDeathEvent && - canBeCorrected && - userHasRegisterScope && ( - { - dispatch(clearCorrectionAndPrintChanges(declarationId as string)) - dispatch( - goToCertificateCorrection( - declarationId as string, - CorrectionSection.Corrector - ) + { + dispatch(clearCorrectionAndPrintChanges(declarationId as string)) + dispatch( + goToCertificateCorrection( + declarationId as string, + CorrectionSection.Corrector ) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(messages.correctRecord)} - - ) + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.correctRecord)} + ) } @@ -296,14 +296,13 @@ const ArchiveAction: React.FC< ((scope as any as string[]).includes('validate') && declarationStatus !== SUBMISSION_STATUS.VALIDATED)) + if (!isArchivable || !userHasArchiveScope) return null + return ( - isArchivable && - userHasArchiveScope && ( - - - {intl.formatMessage(messages.archiveRecord)} - - ) + + + {intl.formatMessage(messages.archiveRecord)} + ) } @@ -320,14 +319,14 @@ const ReinstateAction: React.FC< scope && ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) + + if (!isArchived || !userHasReinstateScope) return null + return ( - isArchived && - userHasReinstateScope && ( - - - {intl.formatMessage(messages.reinstateRecord)} - - ) + + + {intl.formatMessage(messages.reinstateRecord)} + ) } @@ -357,7 +356,9 @@ const ReviewAction: React.FC< ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) - return isPendingCorrection && userHasReviewScope ? ( + if (!userHasReviewScope) return null + + return isPendingCorrection ? ( { dispatch( @@ -375,7 +376,7 @@ const ReviewAction: React.FC< {intl.formatMessage(messages.reviewCorrection)} ) : ( - isReviewableDeclaration && userHasReviewScope && ( + isReviewableDeclaration && ( { dispatch( @@ -437,26 +438,21 @@ const UpdateAction: React.FC = ({ PAGE_ROUTE = REVIEW_EVENT_PARENT_FORM_PAGE PAGE_ID = 'review' } + + if (!isUpdatableDeclaration || !userHasUpdateScope) return null + return ( - isUpdatableDeclaration && - userHasUpdateScope && ( - { - dispatch( - goToPage( - PAGE_ROUTE, - declarationId as string, - PAGE_ID, - type as string - ) - ) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(messages.updateDeclaration)} - - ) + { + dispatch( + goToPage(PAGE_ROUTE, declarationId as string, PAGE_ID, type as string) + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.updateDeclaration)} + ) } @@ -482,25 +478,24 @@ const PrintAction: React.FC = ({ ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) + if (!isPrintable || !userHasPrintScope) return null + return ( - isPrintable && - userHasPrintScope && ( - { - dispatch(clearCorrectionAndPrintChanges(declarationId as string)) - dispatch( - goToPrintCertificate( - declarationId as string, - (type as string).toLocaleLowerCase() - ) + { + dispatch(clearCorrectionAndPrintChanges(declarationId as string)) + dispatch( + goToPrintCertificate( + declarationId as string, + (type as string).toLocaleLowerCase() ) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(messages.printDeclaration)} - - ) + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.printDeclaration)} + ) } @@ -521,20 +516,19 @@ const IssueAction: React.FC = ({ ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) + if (!isCertified || !userHasIssueScope) return null + return ( - isCertified && - userHasIssueScope && ( - { - dispatch(clearCorrectionAndPrintChanges(declarationId as string)) - dispatch(goToIssueCertificate(declarationId as string)) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(messages.issueCertificate)} - - ) + { + dispatch(clearCorrectionAndPrintChanges(declarationId as string)) + dispatch(goToIssueCertificate(declarationId as string)) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.issueCertificate)} + ) } @@ -565,13 +559,14 @@ const UnassignAction: React.FC<{ const userHasUnassignScope = scope && (scope as any as string[]).includes('register') + if (!isDownloaded && (!isAssignedToSomeoneElse || !userHasUnassignScope)) + return null + return ( - ((isAssignedToSomeoneElse && userHasUnassignScope) || isDownloaded) && ( - - - {intl.formatMessage(buttonMessages.unassign)} - - ) + + + {intl.formatMessage(buttonMessages.unassign)} + ) } From fbff2c41939e102fa6125493a6f4f6650bad3fdc Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 11 Oct 2024 18:45:31 +0600 Subject: [PATCH 54/88] refactor: move declaration status logic into declarations/utils --- packages/client/src/declarations/utils.ts | 65 ++++++++++++++ .../src/views/RecordAudit/ActionMenu.tsx | 86 ++++++------------- 2 files changed, 92 insertions(+), 59 deletions(-) create mode 100644 packages/client/src/declarations/utils.ts diff --git a/packages/client/src/declarations/utils.ts b/packages/client/src/declarations/utils.ts new file mode 100644 index 00000000000..691e439fab2 --- /dev/null +++ b/packages/client/src/declarations/utils.ts @@ -0,0 +1,65 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ + +import { EVENT_STATUS } from '@client/workqueue' +import { SUBMISSION_STATUS } from '.' + +export const isPendingCorrection = (status?: string) => + status === EVENT_STATUS.CORRECTION_REQUESTED + +export const isReviewableDeclaration = (status?: string) => + status && [EVENT_STATUS.DECLARED, EVENT_STATUS.VALIDATED].includes(status) + +export const isUpdatableDeclaration = (status?: string) => + status && + [ + SUBMISSION_STATUS.DRAFT, + EVENT_STATUS.IN_PROGRESS, + EVENT_STATUS.REJECTED + ].includes(status) + +export const isPrintable = (status?: string) => + status && + [SUBMISSION_STATUS.REGISTERED, SUBMISSION_STATUS.ISSUED].includes( + status as SUBMISSION_STATUS + ) + +export const isCertified = (status?: string) => + status === SUBMISSION_STATUS.CERTIFIED + +export const isRecordOrDeclaration = (status?: string) => + [ + SUBMISSION_STATUS.REGISTERED, + SUBMISSION_STATUS.CORRECTION_REQUESTED, + SUBMISSION_STATUS.CERTIFIED + ].includes(status as any as SUBMISSION_STATUS) + ? 'record' + : 'declaration' + +export const canBeCorrected = (status?: string) => + status && + [ + SUBMISSION_STATUS.REGISTERED, + SUBMISSION_STATUS.CERTIFIED, + SUBMISSION_STATUS.ISSUED + ].includes(status as SUBMISSION_STATUS) + +export const isArchivable = (status?: string) => + status && + [ + SUBMISSION_STATUS.IN_PROGRESS, + SUBMISSION_STATUS.DECLARED, + SUBMISSION_STATUS.VALIDATED, + SUBMISSION_STATUS.REJECTED + ].includes(status as SUBMISSION_STATUS) + +export const isArchived = (status?: string) => + status === SUBMISSION_STATUS.ARCHIVED diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index f166bb1fc79..a4e5c2b6f50 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -40,7 +40,6 @@ import { } from '@client/declarations' import { CorrectionSection } from '@client/forms' import { buttonMessages } from '@client/i18n/messages' -import { EVENT_STATUS } from '@client/workqueue' import { DRAFT_BIRTH_PARENT_FORM_PAGE, DRAFT_DEATH_FORM_PAGE, @@ -55,6 +54,17 @@ import { client } from '@client/utils/apolloClient' import { Event } from '@client/utils/gateway' import { conflictsMessages } from '@client/i18n/messages/views/conflicts' import { GQLAssignmentData } from '@client/utils/gateway-deprecated-do-not-use' +import { + canBeCorrected, + isArchivable, + isArchived, + isCertified, + isPendingCorrection, + isPrintable, + isRecordOrDeclaration, + isReviewableDeclaration, + isUpdatableDeclaration +} from '@client/declarations/utils' export const ActionMenu: React.FC<{ declaration: IDeclarationData @@ -208,14 +218,6 @@ const ViewAction: React.FC<{ const intl = useIntl() const dispatch = useDispatch() - const recordOrDeclaration = [ - SUBMISSION_STATUS.REGISTERED, - SUBMISSION_STATUS.CORRECTION_REQUESTED, - SUBMISSION_STATUS.CERTIFIED - ].includes(declarationStatus as any as SUBMISSION_STATUS) - ? 'record' - : 'declaration' - return ( { @@ -223,7 +225,9 @@ const ViewAction: React.FC<{ }} > - {intl.formatMessage(messages.view, { recordOrDeclaration })} + {intl.formatMessage(messages.view, { + recordOrDeclaration: isRecordOrDeclaration(declarationStatus) + })} ) } @@ -237,21 +241,17 @@ const CorrectRecordAction: React.FC< const isBirthOrDeathEvent = type && [Event.Birth, Event.Death].includes(type.toLowerCase() as Event) - const canBeCorrected = - declarationStatus && - [ - SUBMISSION_STATUS.REGISTERED, - SUBMISSION_STATUS.CERTIFIED, - SUBMISSION_STATUS.ISSUED - ].includes(declarationStatus as SUBMISSION_STATUS) - // @ToDo use: `record.registration-correct` after configurable role pr is merged const userHasRegisterScope = scope && ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) - if (!isBirthOrDeathEvent || !canBeCorrected || !userHasRegisterScope) { + if ( + !isBirthOrDeathEvent || + !canBeCorrected(declarationStatus) || + !userHasRegisterScope + ) { return null } @@ -278,14 +278,6 @@ const ArchiveAction: React.FC< IActionItemCommonProps & { toggleDisplayDialog?: () => void } > = ({ toggleDisplayDialog, isDownloaded, declarationStatus, scope }) => { const intl = useIntl() - const isArchivable = - declarationStatus && - [ - SUBMISSION_STATUS.IN_PROGRESS, - SUBMISSION_STATUS.DECLARED, - SUBMISSION_STATUS.VALIDATED, - SUBMISSION_STATUS.REJECTED - ].includes(declarationStatus as SUBMISSION_STATUS) // @ToDo use: `record.registration-archive` after configurable role pr is merged // @Question: If user has archive scope but not register scope, @@ -296,7 +288,7 @@ const ArchiveAction: React.FC< ((scope as any as string[]).includes('validate') && declarationStatus !== SUBMISSION_STATUS.VALIDATED)) - if (!isArchivable || !userHasArchiveScope) return null + if (!isArchivable(declarationStatus) || !userHasArchiveScope) return null return ( @@ -310,7 +302,6 @@ const ReinstateAction: React.FC< IActionItemCommonProps & { toggleDisplayDialog?: () => void } > = ({ toggleDisplayDialog, isDownloaded, declarationStatus, scope }) => { const intl = useIntl() - const isArchived = declarationStatus === SUBMISSION_STATUS.ARCHIVED // @ToDo use: `record.registration-reinstate` after configurable role pr is merged // @Question: If user has reinstate scope but not register scope, @@ -320,7 +311,7 @@ const ReinstateAction: React.FC< ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) - if (!isArchived || !userHasReinstateScope) return null + if (!isArchived(declarationStatus) || !userHasReinstateScope) return null return ( @@ -343,14 +334,6 @@ const ReviewAction: React.FC< const intl = useIntl() const dispatch = useDispatch() - const isPendingCorrection = - declarationStatus === EVENT_STATUS.CORRECTION_REQUESTED - - const isReviewableDeclaration = - declarationStatus && - [EVENT_STATUS.DECLARED, EVENT_STATUS.VALIDATED].includes(declarationStatus) - - // @ToDo use: `record.declaration-review` or other appropriate scope after configurable role pr is merged const userHasReviewScope = scope && ((scope as any as string[]).includes('register') || @@ -358,7 +341,7 @@ const ReviewAction: React.FC< if (!userHasReviewScope) return null - return isPendingCorrection ? ( + return isPendingCorrection(declarationStatus) ? ( { dispatch( @@ -376,7 +359,7 @@ const ReviewAction: React.FC< {intl.formatMessage(messages.reviewCorrection)} ) : ( - isReviewableDeclaration && ( + isReviewableDeclaration(declarationStatus) && ( { dispatch( @@ -407,14 +390,6 @@ const UpdateAction: React.FC = ({ const intl = useIntl() const dispatch = useDispatch() - const isUpdatableDeclaration = - declarationStatus && - [ - SUBMISSION_STATUS.DRAFT, - EVENT_STATUS.IN_PROGRESS, - EVENT_STATUS.REJECTED - ].includes(declarationStatus) - // @ToDo use: appropriate scope after configurable role pr is merged const userHasUpdateScope = scope && @@ -439,7 +414,8 @@ const UpdateAction: React.FC = ({ PAGE_ID = 'review' } - if (!isUpdatableDeclaration || !userHasUpdateScope) return null + if (!isUpdatableDeclaration(declarationStatus) || !userHasUpdateScope) + return null return ( = ({ const intl = useIntl() const dispatch = useDispatch() - const isPrintable = - declarationStatus && - [SUBMISSION_STATUS.REGISTERED, SUBMISSION_STATUS.ISSUED].includes( - declarationStatus as SUBMISSION_STATUS - ) - // @ToDo use: `record.print-records` or other appropriate scope after configurable role pr is merged const userHasPrintScope = scope && ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) - if (!isPrintable || !userHasPrintScope) return null + if (!isPrintable(declarationStatus) || !userHasPrintScope) return null return ( = ({ const intl = useIntl() const dispatch = useDispatch() - const isCertified = declarationStatus === SUBMISSION_STATUS.CERTIFIED - // @ToDo use: `record.print-issue-certified-copies` or other appropriate scope after configurable role pr is merged const userHasIssueScope = scope && ((scope as any as string[]).includes('register') || (scope as any as string[]).includes('validate')) - if (!isCertified || !userHasIssueScope) return null + if (!isCertified(declarationStatus) || !userHasIssueScope) return null return ( Date: Fri, 11 Oct 2024 18:55:52 +0600 Subject: [PATCH 55/88] refactor: change type of status to `SUBMISSION_STATUS` --- packages/client/src/declarations/utils.ts | 42 +++++++++---------- .../src/views/RecordAudit/ActionMenu.tsx | 6 +-- .../src/views/RecordAudit/RecordAudit.tsx | 6 ++- .../client/src/views/RecordAudit/utils.ts | 9 ++-- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/packages/client/src/declarations/utils.ts b/packages/client/src/declarations/utils.ts index 691e439fab2..9c5ea68ad85 100644 --- a/packages/client/src/declarations/utils.ts +++ b/packages/client/src/declarations/utils.ts @@ -12,13 +12,13 @@ import { EVENT_STATUS } from '@client/workqueue' import { SUBMISSION_STATUS } from '.' -export const isPendingCorrection = (status?: string) => +export const isPendingCorrection = (status?: SUBMISSION_STATUS) => status === EVENT_STATUS.CORRECTION_REQUESTED -export const isReviewableDeclaration = (status?: string) => +export const isReviewableDeclaration = (status?: SUBMISSION_STATUS) => status && [EVENT_STATUS.DECLARED, EVENT_STATUS.VALIDATED].includes(status) -export const isUpdatableDeclaration = (status?: string) => +export const isUpdatableDeclaration = (status?: SUBMISSION_STATUS) => status && [ SUBMISSION_STATUS.DRAFT, @@ -26,40 +26,40 @@ export const isUpdatableDeclaration = (status?: string) => EVENT_STATUS.REJECTED ].includes(status) -export const isPrintable = (status?: string) => +export const isPrintable = (status?: SUBMISSION_STATUS) => status && - [SUBMISSION_STATUS.REGISTERED, SUBMISSION_STATUS.ISSUED].includes( - status as SUBMISSION_STATUS - ) + [SUBMISSION_STATUS.REGISTERED, SUBMISSION_STATUS.ISSUED].includes(status) -export const isCertified = (status?: string) => +export const isCertified = (status?: SUBMISSION_STATUS) => status === SUBMISSION_STATUS.CERTIFIED -export const isRecordOrDeclaration = (status?: string) => - [ - SUBMISSION_STATUS.REGISTERED, - SUBMISSION_STATUS.CORRECTION_REQUESTED, - SUBMISSION_STATUS.CERTIFIED - ].includes(status as any as SUBMISSION_STATUS) - ? 'record' - : 'declaration' +export const isRecordOrDeclaration = (status?: SUBMISSION_STATUS) => + status + ? [ + SUBMISSION_STATUS.REGISTERED, + SUBMISSION_STATUS.CORRECTION_REQUESTED, + SUBMISSION_STATUS.CERTIFIED + ].includes(status) + ? 'record' + : 'declaration' + : '' -export const canBeCorrected = (status?: string) => +export const canBeCorrected = (status?: SUBMISSION_STATUS) => status && [ SUBMISSION_STATUS.REGISTERED, SUBMISSION_STATUS.CERTIFIED, SUBMISSION_STATUS.ISSUED - ].includes(status as SUBMISSION_STATUS) + ].includes(status) -export const isArchivable = (status?: string) => +export const isArchivable = (status?: SUBMISSION_STATUS) => status && [ SUBMISSION_STATUS.IN_PROGRESS, SUBMISSION_STATUS.DECLARED, SUBMISSION_STATUS.VALIDATED, SUBMISSION_STATUS.REJECTED - ].includes(status as SUBMISSION_STATUS) + ].includes(status) -export const isArchived = (status?: string) => +export const isArchived = (status?: SUBMISSION_STATUS) => status === SUBMISSION_STATUS.ARCHIVED diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index a4e5c2b6f50..a2e4577f1ac 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -203,7 +203,7 @@ export const ActionMenu: React.FC<{ interface IActionItemCommonProps { isDownloaded: boolean scope: Scope - declarationStatus?: string + declarationStatus?: SUBMISSION_STATUS } interface IDeclarationProps { @@ -212,7 +212,7 @@ interface IDeclarationProps { } const ViewAction: React.FC<{ - declarationStatus?: string + declarationStatus?: SUBMISSION_STATUS declarationId: string }> = ({ declarationStatus, declarationId }) => { const intl = useIntl() @@ -502,7 +502,7 @@ const IssueAction: React.FC = ({ const DeleteAction: React.FC<{ handleDelete: () => void - declarationStatus?: string + declarationStatus?: SUBMISSION_STATUS }> = ({ handleDelete, declarationStatus }) => { const intl = useIntl() return ( diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index b1db30f134b..7fb7220d94b 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -550,7 +550,8 @@ const BodyContent = ({ ) declaration = { ...declaration, - status: data.fetchRegistration?.registration?.status[0].type, + status: data.fetchRegistration?.registration?.status[0] + .type as SUBMISSION_STATUS, assignment: data.fetchRegistration?.registration?.assignment } } else { @@ -594,7 +595,8 @@ const BodyContent = ({ language, trackingId ) - const wqStatus = workqueueDeclaration?.registration?.status + const wqStatus = workqueueDeclaration?.registration + ?.status as SUBMISSION_STATUS const draftStatus = draft?.submissionStatus?.toString() || draft?.registrationStatus?.toString() || diff --git a/packages/client/src/views/RecordAudit/utils.ts b/packages/client/src/views/RecordAudit/utils.ts index 4cc34f0c10e..3dd649a3c1f 100644 --- a/packages/client/src/views/RecordAudit/utils.ts +++ b/packages/client/src/views/RecordAudit/utils.ts @@ -12,7 +12,7 @@ import { IFormField, IRadioGroupFormField, ISelectOption } from '@client/forms' import { IOfflineData } from '@client/offline/reducer' import { get, has, PropertyPath } from 'lodash' import { IntlShape } from 'react-intl' -import { IDeclaration } from '@client/declarations' +import { IDeclaration, SUBMISSION_STATUS } from '@client/declarations' import { generateLocationName, generateFullLocation @@ -54,7 +54,7 @@ import { getDeclarationFullName } from '@client/utils/draftUtils' export interface IDeclarationData { id: string name?: string - status?: string + status?: SUBMISSION_STATUS trackingId?: string type?: string dateOfBirth?: string @@ -406,7 +406,8 @@ export const getWQDeclarationData = ( name, type: (workqueueDeclaration?.type && workqueueDeclaration.type) || EMPTY_STRING, - status: workqueueDeclaration?.registration?.status || EMPTY_STRING, + status: (workqueueDeclaration?.registration?.status || + EMPTY_STRING) as SUBMISSION_STATUS, assignment: workqueueDeclaration?.registration?.assignment, trackingId: trackingId, dateOfBirth: EMPTY_STRING, @@ -443,7 +444,7 @@ export const getGQLDeclaration = ( id: data?.id, name, type: data?.registration?.type, - status: data?.registration?.status[0].type, + status: data?.registration?.status[0].type as SUBMISSION_STATUS, trackingId: data?.registration?.trackingId, assignment: data?.registration?.assignment, dateOfBirth: EMPTY_STRING, From f393b16a22da93e6eb0b6631eeb782d44d4a2d95 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 11 Oct 2024 19:28:01 +0600 Subject: [PATCH 56/88] fix: handle multiple dropdown --- .../src/Dropdown/Dropdown.stories.tsx | 2 +- packages/components/src/Dropdown/Dropdown.tsx | 40 +++++++++++-------- .../src/Dropdown/DropdownContext.tsx | 11 ++++- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.stories.tsx b/packages/components/src/Dropdown/Dropdown.stories.tsx index ac1e35001cb..9b014ea6863 100644 --- a/packages/components/src/Dropdown/Dropdown.stories.tsx +++ b/packages/components/src/Dropdown/Dropdown.stories.tsx @@ -28,7 +28,7 @@ const Template = (args: { alignItems: 'center' }} > - + diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 7effde15429..185c7fe9621 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -9,7 +9,7 @@ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import React, { ReactNode, useEffect, useRef } from 'react' +import React, { ReactNode, useEffect } from 'react' import { disabled } from '../Button/Button.styles' import styled from 'styled-components' import { DropdownProvider, useDropdown } from './DropdownContext' @@ -24,8 +24,8 @@ const StyledTrigger = styled.button.withConfig({ shouldForwardProp: (prop, defaultValidatorFn) => ['popovertarget'].includes(prop) || defaultValidatorFn(prop) // Forward popovertarget prop directly -})<{ popovertarget: string }>` - anchor-name: --Dropdown-Anchor; +})<{ popovertarget: string; dropdownName: string }>` + anchor-name: ${({ dropdownName }) => `--Dropdown-Anchor-${dropdownName}`}; margin: 0; padding: 0; border: 0; @@ -37,6 +37,7 @@ type StyledContentProp = { offsetX: number offsetY: number popover: string + dropdownName: string } const StyledContent = styled.ul.withConfig({ shouldForwardProp: (prop, defaultValidatorFn) => @@ -52,7 +53,7 @@ const StyledContent = styled.ul.withConfig({ width: auto; white-space: nowrap; padding: 8px 0; - position-anchor: --Dropdown-Anchor; + position-anchor: ${({ dropdownName }) => `--Dropdown-Anchor-${dropdownName}`}; inset-area: ${({ position }) => position}; position-area: ${({ position }) => position}; margin: 0; @@ -107,17 +108,15 @@ export type IDropdownPosition = | 'left' | 'right' -const DropdownWrapper: React.FC<{ children: ReactNode; id?: string }> = ({ +const DropdownWrapper: React.FC<{ children: ReactNode; id: string }> = ({ children, id }) => { - const rootRef = useRef(null) + const { setDropdownName } = useDropdown() - return ( - - {children} - - ) + setDropdownName(id) + + return {children} } export const DropdownMenu = ({ @@ -125,7 +124,7 @@ export const DropdownMenu = ({ id }: { children: ReactNode - id?: string + id: string }) => { return ( @@ -135,8 +134,14 @@ export const DropdownMenu = ({ } const Trigger: React.FC<{ children: JSX.Element }> = ({ children }) => { + const { dropdownName } = useDropdown() return ( - {children} + + {children} + ) } DropdownMenu.Trigger = Trigger @@ -152,10 +157,10 @@ const Content: React.FC<{ offsetY = 10, children }) => { - const { setFocusedIndex } = useDropdown() + const { dropdownName, setFocusedIndex } = useDropdown() useEffect(() => { - const popover = document.getElementById('Dropdown-Content') + const popover = document.getElementById(dropdownName + '-Dropdown-Content') const onTogglePopover = (event: Event & { newState: string }) => { if (event.newState === 'open') { setFocusedIndex(0) @@ -169,7 +174,7 @@ const Content: React.FC<{ return () => { popover?.removeEventListener('toggle', onTogglePopover) } - }, [setFocusedIndex]) + }, [setFocusedIndex, dropdownName]) return ( {children} diff --git a/packages/components/src/Dropdown/DropdownContext.tsx b/packages/components/src/Dropdown/DropdownContext.tsx index 646db16084e..c2031e0d149 100644 --- a/packages/components/src/Dropdown/DropdownContext.tsx +++ b/packages/components/src/Dropdown/DropdownContext.tsx @@ -15,6 +15,8 @@ interface DropdownContextType { addItemRef: (item: HTMLLIElement | null) => void handleKeyDown: (e: React.KeyboardEvent) => void setFocusedIndex: (e: number) => void + setDropdownName: (name: string) => void + dropdownName: string closeDropdown: () => void } @@ -33,6 +35,7 @@ export const useDropdown = () => { export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [dropdownName, setDropdownName] = useState('') const [focusedIndex, setFocusedIndex] = useState(-1) const itemRefs = useRef<(HTMLLIElement | null)[]>([]) @@ -52,7 +55,11 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ } const closeDropdown = () => - document.getElementById('Dropdown-Content')?.togglePopover() + ( + document.getElementById( + dropdownName + '-Dropdown-Content' + ) as HTMLElement & { togglePopover: () => void } + )?.togglePopover() const handleKeyDown = (e: React.KeyboardEvent) => { e.preventDefault() @@ -77,9 +84,11 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ return ( From 916eb6d1d16aa94b4943ce39551dd3b6498ba7ad Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 11 Oct 2024 19:35:01 +0600 Subject: [PATCH 57/88] fix: styles --- packages/components/src/Dropdown/Dropdown.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 185c7fe9621..9eb4ea08b99 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -16,7 +16,6 @@ import { DropdownProvider, useDropdown } from './DropdownContext' const StyledWrapper = styled.nav` position: relative; - height: 40px; display: flex; ` @@ -29,7 +28,7 @@ const StyledTrigger = styled.button.withConfig({ margin: 0; padding: 0; border: 0; - height: fit-content !important; + background: transparent; ` type StyledContentProp = { @@ -65,6 +64,7 @@ const Label = styled.li` ${({ theme }) => theme.fonts.reg14}; padding: 6px 12px; white-space: normal; + max-width: 250px; ` const Separator = styled.div<{ weight: number }>` From f308a59b1fb2d6112b89e8d3018c8726456eacce Mon Sep 17 00:00:00 2001 From: jamil314 Date: Fri, 11 Oct 2024 20:05:29 +0600 Subject: [PATCH 58/88] fix: position options and story --- .../src/Dropdown/Dropdown.stories.tsx | 39 ++++++++++++++++--- packages/components/src/Dropdown/Dropdown.tsx | 25 ++++++++---- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.stories.tsx b/packages/components/src/Dropdown/Dropdown.stories.tsx index 9b014ea6863..6376cc92512 100644 --- a/packages/components/src/Dropdown/Dropdown.stories.tsx +++ b/packages/components/src/Dropdown/Dropdown.stories.tsx @@ -62,13 +62,40 @@ const Template = (args: {
) export const DropdownView = Template.bind({}) -DropdownView.args = { - position: 'bottom span-left', - offsetX: 0, - offsetY: 10 -} export default { title: 'Controls/Dropdown', - component: DropdownView + component: DropdownView, + argTypes: { + position: { + options: [ + 'none', + 'top left', + 'start end', + 'block-start center', + 'inline-start block-end', + 'x-start y-end', + 'center y-self-end', + 'top span-left', + 'center span-start', + 'inline-start span-block-end', + 'y-start span-x-end', + 'top span-all', + 'block-end span-all', + 'x-self-start span-all', + 'top', + 'inline-start', + 'center', + 'span-all', + 'end' + ] as IDropdownPosition[], + control: { type: 'radio' } + }, + offsetX: { + control: { default: 0, type: 'number' } + }, + offsetY: { + control: { default: 0, type: 'number' } + } + } } as Meta diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 9eb4ea08b99..650aa434ace 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -99,14 +99,25 @@ const MenuItem = styled.li<{ disabled?: boolean }>` ` export type IDropdownPosition = + | 'none' + | 'top left' + | 'start end' + | 'block-start center' + | 'inline-start block-end' + | 'x-start y-end' + | 'center y-self-end' + | 'top span-left' + | 'center span-start' + | 'inline-start span-block-end' + | 'y-start span-x-end' + | 'top span-all' + | 'block-end span-all' + | 'x-self-start span-all' | 'top' - | 'top-left' - | 'top-right' - | 'bottom' - | 'bottom-left' - | 'bottom-right' - | 'left' - | 'right' + | 'inline-start' + | 'center' + | 'span-all' + | 'end' const DropdownWrapper: React.FC<{ children: ReactNode; id: string }> = ({ children, From 42b38df4a5b9f7d7e82877239787a78154ae650d Mon Sep 17 00:00:00 2001 From: jamil314 Date: Mon, 14 Oct 2024 15:01:26 +0600 Subject: [PATCH 59/88] fix: close dropdown on action click --- packages/components/src/Dropdown/Dropdown.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index 650aa434ace..beec2093333 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -229,7 +229,10 @@ const Item = ({ return ( { + onClickHandler() + closeDropdown() + }} disabled={disabled} tabIndex={disabled ? -1 : 0} ref={(item) => addItemRef(item)} From 0b773138494592f3292cad5b6be3b55bb1619423 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Mon, 14 Oct 2024 19:32:40 +0600 Subject: [PATCH 60/88] refactor: align EVENT in common with Event in client --- packages/client/src/search/transformer.ts | 9 +++++---- packages/client/src/views/RecordAudit/ActionMenu.tsx | 2 +- packages/client/src/views/RecordAudit/RecordAudit.tsx | 2 +- packages/client/src/views/RecordAudit/utils.ts | 8 ++++---- packages/commons/src/search.ts | 6 +++--- packages/gateway/src/features/search/type-resolvers.ts | 7 ++++--- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/client/src/search/transformer.ts b/packages/client/src/search/transformer.ts index 6fd59bad33f..6470821252b 100644 --- a/packages/client/src/search/transformer.ts +++ b/packages/client/src/search/transformer.ts @@ -21,7 +21,8 @@ import { formatLongDate } from '@client/utils/date-formatting' import { HumanName, EventSearchSet, - SearchEventsQuery + SearchEventsQuery, + Event } from '@client/utils/gateway' import { EMPTY_STRING, LANG_EN } from '@client/utils/constants' import { ITaskHistory } from '@client/declarations' @@ -29,19 +30,19 @@ import { ITaskHistory } from '@client/declarations' export const isBirthEvent = ( req: EventSearchSet ): req is GQLBirthEventSearchSet => { - return req.type === 'Birth' + return req.type === Event.Birth } export const isDeathEvent = ( req: EventSearchSet ): req is GQLDeathEventSearchSet => { - return req.type === 'Death' + return req.type === Event.Death } export const isMarriageEvent = ( reg: EventSearchSet ): reg is GQLMarriageEventSearchSet => { - return reg.type === 'Marriage' + return reg.type === Event.Marriage } export const transformData = ( diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index a2e4577f1ac..91f2c04d395 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -239,7 +239,7 @@ const CorrectRecordAction: React.FC< const intl = useIntl() const isBirthOrDeathEvent = - type && [Event.Birth, Event.Death].includes(type.toLowerCase() as Event) + type && [Event.Birth, Event.Death].includes(type as Event) // @ToDo use: `record.registration-correct` after configurable role pr is merged const userHasRegisterScope = diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index 7fb7220d94b..3b19ab2d0ae 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -338,7 +338,7 @@ function RecordAuditBody({ const eventType = declaration.type if (eventType in registerForm.registerForm) regForm = get(registerForm.registerForm, eventType) - else regForm = registerForm.registerForm['birth'] + else regForm = registerForm.registerForm[Event.Birth] const actionDetailsModalProps = { show: showActionDetails, diff --git a/packages/client/src/views/RecordAudit/utils.ts b/packages/client/src/views/RecordAudit/utils.ts index 3dd649a3c1f..a2f58737fe1 100644 --- a/packages/client/src/views/RecordAudit/utils.ts +++ b/packages/client/src/views/RecordAudit/utils.ts @@ -318,19 +318,19 @@ export const removeUnderscore = (word: string): string => { const isBirthDeclaration = ( declaration: GQLEventSearchSet | null ): declaration is GQLBirthEventSearchSet => { - return (declaration && declaration.type === 'Birth') || false + return (declaration && declaration.type === Event.Birth) || false } const isDeathDeclaration = ( declaration: GQLEventSearchSet | null ): declaration is GQLDeathEventSearchSet => { - return (declaration && declaration.type === 'Death') || false + return (declaration && declaration.type === Event.Death) || false } const isMarriageDeclaration = ( declaration: GQLEventSearchSet | null ): declaration is GQLMarriageEventSearchSet => { - return (declaration && declaration.type === 'Marriage') || false + return (declaration && declaration.type === Event.Marriage) || false } export const getName = (names: (HumanName | null)[], language: string) => { @@ -347,7 +347,7 @@ export const getDraftDeclarationData = ( return { id: declaration.id, name: getDeclarationFullName(declaration), - type: declaration.event || EMPTY_STRING, + type: declaration.event, registrationNo: declaration.data?.registration?.registrationNumber?.toString() || EMPTY_STRING, diff --git a/packages/commons/src/search.ts b/packages/commons/src/search.ts index f3816041912..c134b97b029 100644 --- a/packages/commons/src/search.ts +++ b/packages/commons/src/search.ts @@ -10,9 +10,9 @@ */ export const enum EVENT { - BIRTH = 'Birth', - DEATH = 'Death', - MARRIAGE = 'Marriage' + BIRTH = 'birth', + DEATH = 'death', + MARRIAGE = 'marriage' } export const IN_PROGRESS_STATUS = 'IN_PROGRESS' diff --git a/packages/gateway/src/features/search/type-resolvers.ts b/packages/gateway/src/features/search/type-resolvers.ts index aefb683d7f6..cfb4264bae9 100644 --- a/packages/gateway/src/features/search/type-resolvers.ts +++ b/packages/gateway/src/features/search/type-resolvers.ts @@ -19,6 +19,7 @@ import { GQLResolver } from '@gateway/graphql/schema' import { getFullName } from '@gateway/features/user/utils' +import { EVENT } from '@opencrvs/commons' interface ISearchEventDataTemplate { _type: string @@ -191,13 +192,13 @@ const getGroomName = (source: ISearchDataTemplate) => { export const searchTypeResolvers: GQLResolver = { EventSearchSet: { __resolveType(obj: ISearchEventDataTemplate) { - if (obj._source.event === 'Birth') { + if (obj._source.event === EVENT.BIRTH) { return 'BirthEventSearchSet' } - if (obj._source.event === 'Death') { + if (obj._source.event === EVENT.DEATH) { return 'DeathEventSearchSet' } - if (obj._source.event === 'Marriage') { + if (obj._source.event === EVENT.MARRIAGE) { return 'MarriageEventSearchSet' } return null as never From b41b5f65b8ceab0f766ed82bd13a3227589affd1 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Tue, 15 Oct 2024 18:33:24 +0600 Subject: [PATCH 61/88] refactor: pass id directly to provider --- .../components/src/Dropdown/Dropdown.stories.tsx | 2 +- packages/components/src/Dropdown/Dropdown.tsx | 15 ++------------- .../components/src/Dropdown/DropdownContext.tsx | 12 ++++++------ 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/packages/components/src/Dropdown/Dropdown.stories.tsx b/packages/components/src/Dropdown/Dropdown.stories.tsx index 6376cc92512..fb4c0853823 100644 --- a/packages/components/src/Dropdown/Dropdown.stories.tsx +++ b/packages/components/src/Dropdown/Dropdown.stories.tsx @@ -88,7 +88,7 @@ export default { 'center', 'span-all', 'end' - ] as IDropdownPosition[], + ] satisfies IDropdownPosition[], control: { type: 'radio' } }, offsetX: { diff --git a/packages/components/src/Dropdown/Dropdown.tsx b/packages/components/src/Dropdown/Dropdown.tsx index beec2093333..46ef2f48679 100644 --- a/packages/components/src/Dropdown/Dropdown.tsx +++ b/packages/components/src/Dropdown/Dropdown.tsx @@ -119,17 +119,6 @@ export type IDropdownPosition = | 'span-all' | 'end' -const DropdownWrapper: React.FC<{ children: ReactNode; id: string }> = ({ - children, - id -}) => { - const { setDropdownName } = useDropdown() - - setDropdownName(id) - - return {children} -} - export const DropdownMenu = ({ children, id @@ -138,8 +127,8 @@ export const DropdownMenu = ({ id: string }) => { return ( - - {children} + + {children} ) } diff --git a/packages/components/src/Dropdown/DropdownContext.tsx b/packages/components/src/Dropdown/DropdownContext.tsx index c2031e0d149..a2e1df18ed5 100644 --- a/packages/components/src/Dropdown/DropdownContext.tsx +++ b/packages/components/src/Dropdown/DropdownContext.tsx @@ -15,7 +15,6 @@ interface DropdownContextType { addItemRef: (item: HTMLLIElement | null) => void handleKeyDown: (e: React.KeyboardEvent) => void setFocusedIndex: (e: number) => void - setDropdownName: (name: string) => void dropdownName: string closeDropdown: () => void } @@ -32,13 +31,15 @@ export const useDropdown = () => { return context } -export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ - children -}) => { - const [dropdownName, setDropdownName] = useState('') +export const DropdownProvider: React.FC<{ + children: React.ReactNode + id: string +}> = ({ children, id }) => { const [focusedIndex, setFocusedIndex] = useState(-1) const itemRefs = useRef<(HTMLLIElement | null)[]>([]) + const dropdownName = id + const addItemRef = (item: HTMLLIElement | null) => { if (item && item.tabIndex === 0 && !itemRefs.current.includes(item)) { itemRefs.current.push(item) @@ -88,7 +89,6 @@ export const DropdownProvider: React.FC<{ children: React.ReactNode }> = ({ addItemRef, handleKeyDown, setFocusedIndex, - setDropdownName, closeDropdown }} > From a103589449f2e1ca23a2550782a42ec9223c6200 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 16 Oct 2024 16:11:45 +0600 Subject: [PATCH 62/88] test: add unit test for view action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 147 ++++++++++++++++++ .../src/views/RecordAudit/ActionMenu.tsx | 10 +- 2 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 packages/client/src/views/RecordAudit/ActionMenu.test.tsx diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx new file mode 100644 index 00000000000..6b19a3fb120 --- /dev/null +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -0,0 +1,147 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * OpenCRVS is also distributed under the terms of the Civil Registration + * & Healthcare Disclaimer located at http://opencrvs.org/license. + * + * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. + */ + +import * as React from 'react' +import { createTestComponent } from '@client/tests/util' +import { createStore } from '@client/store' +import { ReactWrapper } from 'enzyme' +import { + DOWNLOAD_STATUS, + IDeclaration, + storeDeclaration, + SUBMISSION_STATUS +} from '@client/declarations' +import { ActionMenu } from './ActionMenu' +import { Scope } from '@sentry/react' +import { Event } from '@client/utils/gateway' + +const defaultDeclaration = { + id: '65c48a2b-68dd-4a7e-8868-d2bb1fd27844', + name: 'Elissabe Sandrava', + type: Event.Birth, + status: SUBMISSION_STATUS.REGISTERED, + assignment: { + practitionerId: '73da21a1-4b8b-4174-83ca-122d829cb6ec', + firstName: 'Kennedy', + lastName: 'Mweene', + officeName: 'Ibombo District Office', + avatarURL: + 'https://eu.ui-avatars.com/api/?background=DEE5F2&color=222&name=Kennedy Mweene', + __typename: 'AssignmentData' + }, + trackingId: 'BYSQC5A', + dateOfBirth: '', + placeOfBirth: '' +} as unknown as IDeclaration + +const draftBirthDownloaded = { + id: '65c48a2b-68dd-4a7e-8868-d2bb1fd27844', + data: {}, + event: Event.Birth, + action: 'load declaration data for review', + downloadStatus: DOWNLOAD_STATUS.DOWNLOADED +} as unknown as IDeclaration + +const draftDeathDownloaded = { + id: '65c48a2b-68dd-4a7e-8868-d2bb1fd27844', + data: {}, + event: Event.Death, + action: 'load declaration data for review', + downloadStatus: DOWNLOAD_STATUS.DOWNLOADED +} as unknown as IDeclaration + +const draftBirthNotDownloaded = { + id: '65c48a2b-68dd-4a7e-8868-d2bb1fd27844', + data: {}, + event: Event.Birth, + action: 'load declaration data for review', + downloadStatus: DOWNLOAD_STATUS.READY_TO_DOWNLOAD +} as unknown as IDeclaration + +const draftDeathNotDownloaded = { + id: '65c48a2b-68dd-4a7e-8868-d2bb1fd27844', + data: {}, + event: Event.Death, + action: 'load declaration data for review', + downloadStatus: DOWNLOAD_STATUS.READY_TO_DOWNLOAD +} as unknown as IDeclaration + +const scopes = ['validate'] as any as Scope + +enum ACTION_STATUS { + HIDDEN = 'Hidden', + ENABLED = 'Enabled', + DISABLED = 'Disabled' +} + +enum ACTION { + VIEW_RECORD = 'View record', + VIEW_DECLARATION = 'View declaration' +} + +const actionStatus = ( + component: ReactWrapper<{}, {}>, + targetAction: string +): ACTION_STATUS => { + const target = component + .find('li') + .map((a) => a) + .filter((a) => a.text() === targetAction) + + if (target.length === 0) return ACTION_STATUS.HIDDEN + + return target[0].prop('disabled') + ? ACTION_STATUS.DISABLED + : ACTION_STATUS.ENABLED +} + +describe('View action', () => { + it('Can view record', async () => { + const { store, history } = createStore() + store.dispatch(storeDeclaration(defaultDeclaration)) + const component = await createTestComponent( + , + { store, history } + ) + expect(actionStatus(component, ACTION.VIEW_RECORD)).toBe( + ACTION_STATUS.ENABLED + ) + }) + + it('Can view declaration', async () => { + const { store, history } = createStore() + store.dispatch(storeDeclaration(defaultDeclaration)) + const component = await createTestComponent( + , + { store, history } + ) + expect(actionStatus(component, ACTION.VIEW_DECLARATION)).toBe( + ACTION_STATUS.ENABLED + ) + }) +}) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index 91f2c04d395..beb9ddd6449 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -344,14 +344,8 @@ const ReviewAction: React.FC< return isPendingCorrection(declarationStatus) ? ( { - dispatch( - goToPage( - REVIEW_CORRECTION, - declarationId as string, - 'review', - type as string - ) - ) + type && + dispatch(goToPage(REVIEW_CORRECTION, declarationId, 'review', type)) }} disabled={!isDownloaded} > From d9c53a448778758a1f8ed591a7122246db8f8cce Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 16 Oct 2024 18:07:59 +0600 Subject: [PATCH 63/88] test: cover all statuses for view action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 245 ++++++++++++++++-- 1 file changed, 227 insertions(+), 18 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 6b19a3fb120..b26b0c9f866 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -16,7 +16,6 @@ import { ReactWrapper } from 'enzyme' import { DOWNLOAD_STATUS, IDeclaration, - storeDeclaration, SUBMISSION_STATUS } from '@client/declarations' import { ActionMenu } from './ActionMenu' @@ -90,42 +89,72 @@ enum ACTION { const actionStatus = ( component: ReactWrapper<{}, {}>, targetAction: string -): ACTION_STATUS => { +): { status: ACTION_STATUS; node?: ReactWrapper<{}, {}> } => { const target = component .find('li') .map((a) => a) .filter((a) => a.text() === targetAction) - if (target.length === 0) return ACTION_STATUS.HIDDEN + if (target.length === 0) return { status: ACTION_STATUS.HIDDEN } return target[0].prop('disabled') - ? ACTION_STATUS.DISABLED - : ACTION_STATUS.ENABLED + ? { status: ACTION_STATUS.DISABLED } + : { status: ACTION_STATUS.ENABLED, node: target[0] } } describe('View action', () => { - it('Can view record', async () => { + it('Draft', async () => { const { store, history } = createStore() - store.dispatch(storeDeclaration(defaultDeclaration)) const component = await createTestComponent( {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' + ) + }) + + it('In progress', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} />, { store, history } ) - expect(actionStatus(component, ACTION.VIEW_RECORD)).toBe( - ACTION_STATUS.ENABLED + + const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' ) }) - it('Can view declaration', async () => { + it('In review', async () => { const { store, history } = createStore() - store.dispatch(storeDeclaration(defaultDeclaration)) const component = await createTestComponent( { status: SUBMISSION_STATUS.DECLARED }} scope={scopes} + draft={draftBirthNotDownloaded} + toggleDisplayDialog={() => {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' + ) + }) + + it('Potential duplicate', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' + ) + }) + + it('Requires update', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' + ) + }) + + it('Validated', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' + ) + }) + + it('Archived', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' + ) + }) + + it('Registered', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, ACTION.VIEW_RECORD) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' + ) + }) + + it('Registered + Printed in advance', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} />, { store, history } ) - expect(actionStatus(component, ACTION.VIEW_DECLARATION)).toBe( - ACTION_STATUS.ENABLED + + const { status, node } = actionStatus(component, ACTION.VIEW_RECORD) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' + ) + }) + + it('Pending correction', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, ACTION.VIEW_RECORD) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + expect(window.location.href).toContain( + defaultDeclaration.id + '/viewRecord' ) }) }) From a7391bbe52f565e38146791780cf23483ded8d63 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 16 Oct 2024 18:46:02 +0600 Subject: [PATCH 64/88] test: add tests for review action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 397 ++++++++++++++++-- 1 file changed, 369 insertions(+), 28 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index b26b0c9f866..740a0b0f481 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -10,7 +10,7 @@ */ import * as React from 'react' -import { createTestComponent } from '@client/tests/util' +import { createTestComponent, flushPromises } from '@client/tests/util' import { createStore } from '@client/store' import { ReactWrapper } from 'enzyme' import { @@ -73,29 +73,38 @@ const draftDeathNotDownloaded = { downloadStatus: DOWNLOAD_STATUS.READY_TO_DOWNLOAD } as unknown as IDeclaration -const scopes = ['validate'] as any as Scope +const SCOPES = { + FA: ['declare'] as any as Scope, + RA: ['validate'] as any as Scope, + REGISTRAR: ['register'] as any as Scope +} enum ACTION_STATUS { HIDDEN = 'Hidden', ENABLED = 'Enabled', - DISABLED = 'Disabled' + DISABLED = 'Disabled', + MULTIPLE = 'Multiple' } enum ACTION { VIEW_RECORD = 'View record', - VIEW_DECLARATION = 'View declaration' + VIEW_DECLARATION = 'View declaration', + REVIEW_DECLARATION = 'Review declaration', + REVIEW_POTENTIAL_DUPLICATE = 'Review potential duplicate', + REVIEW_CORRECTION_REQUEST = 'Review correction request' } const actionStatus = ( component: ReactWrapper<{}, {}>, - targetAction: string + targetAction: string[] ): { status: ACTION_STATUS; node?: ReactWrapper<{}, {}> } => { const target = component .find('li') .map((a) => a) - .filter((a) => a.text() === targetAction) + .filter((a) => targetAction.includes(a.text())) if (target.length === 0) return { status: ACTION_STATUS.HIDDEN } + if (target.length > 1) return { status: ACTION_STATUS.MULTIPLE } return target[0].prop('disabled') ? { status: ACTION_STATUS.DISABLED } @@ -111,14 +120,14 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DRAFT }} - scope={scopes} + scope={SCOPES.RA} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + const { status, node } = actionStatus(component, [ACTION.VIEW_DECLARATION]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -136,14 +145,14 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={scopes} + scope={SCOPES.RA} draft={draftDeathDownloaded} toggleDisplayDialog={() => {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + const { status, node } = actionStatus(component, [ACTION.VIEW_DECLARATION]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -161,14 +170,14 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={scopes} + scope={SCOPES.RA} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + const { status, node } = actionStatus(component, [ACTION.VIEW_DECLARATION]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -184,9 +193,9 @@ describe('View action', () => { {}} @@ -194,7 +203,7 @@ describe('View action', () => { { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + const { status, node } = actionStatus(component, [ACTION.VIEW_DECLARATION]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -210,16 +219,16 @@ describe('View action', () => { {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + const { status, node } = actionStatus(component, [ACTION.VIEW_DECLARATION]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -237,14 +246,14 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={scopes} + scope={SCOPES.RA} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + const { status, node } = actionStatus(component, [ACTION.VIEW_DECLARATION]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -262,14 +271,14 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={scopes} + scope={SCOPES.RA} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_DECLARATION) + const { status, node } = actionStatus(component, [ACTION.VIEW_DECLARATION]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -287,14 +296,14 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={scopes} + scope={SCOPES.RA} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_RECORD) + const { status, node } = actionStatus(component, [ACTION.VIEW_RECORD]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -312,14 +321,14 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CERTIFIED }} - scope={scopes} + scope={SCOPES.RA} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_RECORD) + const { status, node } = actionStatus(component, [ACTION.VIEW_RECORD]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -337,14 +346,14 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CORRECTION_REQUESTED }} - scope={scopes} + scope={SCOPES.RA} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, { store, history } ) - const { status, node } = actionStatus(component, ACTION.VIEW_RECORD) + const { status, node } = actionStatus(component, [ACTION.VIEW_RECORD]) expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') @@ -354,3 +363,335 @@ describe('View action', () => { ) }) }) + +describe('Review action', () => { + it('Draft', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_DECLARATION, + ACTION.REVIEW_CORRECTION_REQUEST, + ACTION.REVIEW_POTENTIAL_DUPLICATE + ]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In progress', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_DECLARATION, + ACTION.REVIEW_CORRECTION_REQUEST, + ACTION.REVIEW_POTENTIAL_DUPLICATE + ]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In review - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.REVIEW_DECLARATION + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + await flushPromises() + + expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) + }) + + it('In review - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REVIEW_DECLARATION]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Potential duplicate - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_POTENTIAL_DUPLICATE + ]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + it('Potential duplicate - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.REVIEW_POTENTIAL_DUPLICATE + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + await flushPromises() + + expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) + }) + + it('Requires update - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.REVIEW_DECLARATION + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + await flushPromises() + + expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) + }) + + it('Requires update - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REVIEW_DECLARATION]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Validated - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.REVIEW_DECLARATION + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + await flushPromises() + + expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) + }) + + it('Validated - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REVIEW_DECLARATION]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Archived', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_DECLARATION, + ACTION.REVIEW_CORRECTION_REQUEST, + ACTION.REVIEW_POTENTIAL_DUPLICATE + ]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_DECLARATION, + ACTION.REVIEW_CORRECTION_REQUEST, + ACTION.REVIEW_POTENTIAL_DUPLICATE + ]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered + Printed in advance', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_DECLARATION, + ACTION.REVIEW_CORRECTION_REQUEST, + ACTION.REVIEW_POTENTIAL_DUPLICATE + ]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Pending correction - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.REVIEW_CORRECTION_REQUEST + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + await flushPromises() + + expect(window.location.href).toContain( + 'review-correction/' + defaultDeclaration.id + ) + }) +}) From 8a346de5cd7b8ffee919c6d8326cb2fb5caf7568 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 16 Oct 2024 19:08:52 +0600 Subject: [PATCH 65/88] test: add tests for update action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 311 ++++++++++++++++-- 1 file changed, 279 insertions(+), 32 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 740a0b0f481..405be66dda1 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -91,7 +91,8 @@ enum ACTION { VIEW_DECLARATION = 'View declaration', REVIEW_DECLARATION = 'Review declaration', REVIEW_POTENTIAL_DUPLICATE = 'Review potential duplicate', - REVIEW_CORRECTION_REQUEST = 'Review correction request' + REVIEW_CORRECTION_REQUEST = 'Review correction request', + UPDATE_DECLARATION = 'Update declaration' } const actionStatus = ( @@ -219,7 +220,7 @@ describe('View action', () => { { expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) }) - it('Requires update - Downloaded', async () => { + it('Requires update', async () => { const { store, history } = createStore() const component = await createTestComponent( { { store, history } ) - const { status, node } = actionStatus(component, [ - ACTION.REVIEW_DECLARATION - ]) - expect(status).toBe(ACTION_STATUS.ENABLED) - - node?.simulate('click') - - await flushPromises() - - expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) - }) - - it('Requires update - Not downloaded', async () => { - const { store, history } = createStore() - const component = await createTestComponent( - {}} - />, - { store, history } - ) - const { status } = actionStatus(component, [ACTION.REVIEW_DECLARATION]) - expect(status).toBe(ACTION_STATUS.DISABLED) + expect(status).toBe(ACTION_STATUS.HIDDEN) }) it('Validated - Downloaded', async () => { @@ -694,4 +668,277 @@ describe('Review action', () => { 'review-correction/' + defaultDeclaration.id ) }) + it('Pending correction - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_CORRECTION_REQUEST + ]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) +}) + +describe('Update action', () => { + it('Draft', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.UPDATE_DECLARATION + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + await flushPromises() + + expect(window.location.href).toContain('drafts/' + defaultDeclaration.id) + }) + + it('In progress - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.UPDATE_DECLARATION + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + await flushPromises() + + expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) + }) + + it('In progress - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('In review', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Potential duplicate', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Requires update - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.UPDATE_DECLARATION + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + await flushPromises() + + expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) + }) + + it('Requires update - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Validated - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Archived', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered + Printed in advance', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Pending correction - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) }) From 4c190bfcf8cb069eaf6987fb6afed2ea5cf3d221 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Wed, 16 Oct 2024 19:28:18 +0600 Subject: [PATCH 66/88] test: add tests for archive action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 270 +++++++++++++++++- 1 file changed, 269 insertions(+), 1 deletion(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 405be66dda1..60afe24b7e5 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -21,6 +21,7 @@ import { import { ActionMenu } from './ActionMenu' import { Scope } from '@sentry/react' import { Event } from '@client/utils/gateway' +import { vi } from 'vitest' const defaultDeclaration = { id: '65c48a2b-68dd-4a7e-8868-d2bb1fd27844', @@ -92,7 +93,9 @@ enum ACTION { REVIEW_DECLARATION = 'Review declaration', REVIEW_POTENTIAL_DUPLICATE = 'Review potential duplicate', REVIEW_CORRECTION_REQUEST = 'Review correction request', - UPDATE_DECLARATION = 'Update declaration' + UPDATE_DECLARATION = 'Update declaration', + ARCHIVE_RECORD = 'Archive Record', + REINSTATE_RECORD = 'Reinstate Record' } const actionStatus = ( @@ -942,3 +945,268 @@ describe('Update action', () => { expect(status).toBe(ACTION_STATUS.HIDDEN) }) }) + +describe('Archive action', () => { + it('Draft', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In progress - Downloaded', async () => { + const { store, history } = createStore() + const toggleDisplayDialogMock = vi.fn() + const component = await createTestComponent( + , + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.ENABLED) + node?.simulate('click') + + expect(toggleDisplayDialogMock).toHaveBeenCalled() + }) + + it('In progress - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('In review - Downloaded', async () => { + const { store, history } = createStore() + const toggleDisplayDialogMock = vi.fn() + const component = await createTestComponent( + , + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.ENABLED) + node?.simulate('click') + + expect(toggleDisplayDialogMock).toHaveBeenCalled() + }) + + it('In review - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Requires update - Downloaded', async () => { + const { store, history } = createStore() + const toggleDisplayDialogMock = vi.fn() + const component = await createTestComponent( + , + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.ENABLED) + node?.simulate('click') + + expect(toggleDisplayDialogMock).toHaveBeenCalled() + }) + + it('Requires update - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Validated - Downloaded', async () => { + const { store, history } = createStore() + const toggleDisplayDialogMock = vi.fn() + const component = await createTestComponent( + , + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.ENABLED) + node?.simulate('click') + + expect(toggleDisplayDialogMock).toHaveBeenCalled() + }) + + it('Validated - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Archived', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered + Printed in advance', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Pending correction - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) +}) From 173ca9dfaca0d58cab6c30882ef536195513b76a Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 12:28:47 +0600 Subject: [PATCH 67/88] test: add tests for reinstate action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 83 ++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 60afe24b7e5..06ca78d3b53 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -1191,7 +1191,7 @@ describe('Archive action', () => { expect(status).toBe(ACTION_STATUS.HIDDEN) }) - it('Pending correction - Not downloaded', async () => { + it('Pending correction', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(status).toBe(ACTION_STATUS.HIDDEN) }) }) + +describe('Reinstate action', () => { + it('Draft', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REINSTATE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Archived - Downloaded', async () => { + const { store, history } = createStore() + const toggleDisplayDialogMock = vi.fn() + const component = await createTestComponent( + , + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.REINSTATE_RECORD]) + expect(status).toBe(ACTION_STATUS.ENABLED) + node?.simulate('click') + expect(toggleDisplayDialogMock).toHaveBeenCalled() + }) + + it('Archived - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REINSTATE_RECORD]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Registered', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REINSTATE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) +}) From 3c7ed136d1e9a95c05705dd502717015b5108ce1 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 12:44:53 +0600 Subject: [PATCH 68/88] test: add tests for print action --- packages/client/src/declarations/index.ts | 2 +- .../src/views/RecordAudit/ActionMenu.test.tsx | 217 +++++++++++++++++- 2 files changed, 217 insertions(+), 2 deletions(-) diff --git a/packages/client/src/declarations/index.ts b/packages/client/src/declarations/index.ts index def8d74a770..de3e7fc5436 100644 --- a/packages/client/src/declarations/index.ts +++ b/packages/client/src/declarations/index.ts @@ -1373,7 +1373,7 @@ export const declarationsReducer: LoopReducer = ( const orignalAppliation: IDeclaration = { ...correction, data: { - ...correction.originalData + ...correction?.originalData } } diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 06ca78d3b53..fbb7c5a59ff 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -95,7 +95,8 @@ enum ACTION { REVIEW_CORRECTION_REQUEST = 'Review correction request', UPDATE_DECLARATION = 'Update declaration', ARCHIVE_RECORD = 'Archive Record', - REINSTATE_RECORD = 'Reinstate Record' + REINSTATE_RECORD = 'Reinstate Record', + PRINT_RECORD = 'Print certified copy' } const actionStatus = ( @@ -1291,3 +1292,217 @@ describe('Reinstate action', () => { expect(status).toBe(ACTION_STATUS.HIDDEN) }) }) + +describe('Print action', () => { + it('Draft', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In progress', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In review', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Potential duplicate', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Requires update', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Validated', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Archived', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + }) + + it('Registered - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Registered + Printed in advance', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Pending correction', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) +}) From 9627f7ee4070e492cf3c9de8c368d9ea1be5bc1a Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 12:52:51 +0600 Subject: [PATCH 69/88] test: add tests for issue action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 225 +++++++++++++++++- 1 file changed, 224 insertions(+), 1 deletion(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index fbb7c5a59ff..99831aee91c 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -96,7 +96,8 @@ enum ACTION { UPDATE_DECLARATION = 'Update declaration', ARCHIVE_RECORD = 'Archive Record', REINSTATE_RECORD = 'Reinstate Record', - PRINT_RECORD = 'Print certified copy' + PRINT_RECORD = 'Print certified copy', + ISSUE_CERTIFICATE = 'Issue certificate' } const actionStatus = ( @@ -1447,6 +1448,11 @@ describe('Print action', () => { expect(status).toBe(ACTION_STATUS.ENABLED) node?.simulate('click') + + await flushPromises() + expect(window.location.href).toContain( + 'cert/collector/' + defaultDeclaration.id + ) }) it('Registered - Not downloaded', async () => { @@ -1506,3 +1512,220 @@ describe('Print action', () => { expect(status).toBe(ACTION_STATUS.HIDDEN) }) }) + +describe('Issue action', () => { + it('Draft', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In progress', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In review', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Potential duplicate', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Requires update', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Validated', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Archived', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered + Printed in advance - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + await flushPromises() + expect(window.location.href).toContain('issue/' + defaultDeclaration.id) + }) + + it('Registered + Printed in advance - Not downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Pending correction', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) +}) From 5d11be2c5c764d7ab4467d746cb40fca8bfc4817 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 13:07:20 +0600 Subject: [PATCH 70/88] test: refactor: centralize scoeps --- .../src/views/RecordAudit/ActionMenu.test.tsx | 157 +++++++++--------- 1 file changed, 82 insertions(+), 75 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 99831aee91c..ea3db34d194 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -118,6 +118,7 @@ const actionStatus = ( } describe('View action', () => { + const VIEW_SCOPES = SCOPES.RA it('Draft', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -126,7 +127,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DRAFT }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -151,7 +152,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={() => {}} />, @@ -176,7 +177,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -201,7 +202,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftDeathNotDownloaded} duplicates={['duplicate1']} toggleDisplayDialog={() => {}} @@ -227,7 +228,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REJECTED }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -252,7 +253,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -277,7 +278,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -302,7 +303,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -327,7 +328,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CERTIFIED }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -352,7 +353,7 @@ describe('View action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CORRECTION_REQUESTED }} - scope={SCOPES.RA} + scope={VIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -371,6 +372,7 @@ describe('View action', () => { }) describe('Review action', () => { + const REVIEW_SCOPES = SCOPES.RA it('Draft', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -379,7 +381,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DRAFT }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -402,7 +404,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={() => {}} />, @@ -425,7 +427,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -452,7 +454,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -471,7 +473,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftDeathNotDownloaded} duplicates={['duplicate1']} toggleDisplayDialog={() => {}} @@ -492,7 +494,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftDeathDownloaded} duplicates={['duplicate1']} toggleDisplayDialog={() => {}} @@ -520,7 +522,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REJECTED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -539,7 +541,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -566,7 +568,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -585,7 +587,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -608,7 +610,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -631,7 +633,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CERTIFIED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -654,7 +656,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CORRECTION_REQUESTED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -681,7 +683,7 @@ describe('Review action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CORRECTION_REQUESTED }} - scope={SCOPES.RA} + scope={REVIEW_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -696,6 +698,7 @@ describe('Review action', () => { }) describe('Update action', () => { + const UPDATE_SCOPES = SCOPES.RA it('Draft', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -704,7 +707,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DRAFT }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -730,7 +733,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={() => {}} />, @@ -756,7 +759,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftDeathNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -775,7 +778,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -794,7 +797,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftDeathNotDownloaded} duplicates={['duplicate1']} toggleDisplayDialog={() => {}} @@ -814,7 +817,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REJECTED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -841,7 +844,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REJECTED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -860,7 +863,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -879,7 +882,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -898,7 +901,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -917,7 +920,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CERTIFIED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -936,7 +939,7 @@ describe('Update action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CORRECTION_REQUESTED }} - scope={SCOPES.RA} + scope={UPDATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -949,6 +952,7 @@ describe('Update action', () => { }) describe('Archive action', () => { + const ARCHIVE_SCOPES = ['validate', 'register'] as any as Scope it('Draft', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -957,7 +961,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DRAFT }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -977,7 +981,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={toggleDisplayDialogMock} />, @@ -999,7 +1003,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftDeathNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1019,7 +1023,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={toggleDisplayDialogMock} />, @@ -1041,7 +1045,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftDeathNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1061,7 +1065,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REJECTED }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={toggleDisplayDialogMock} />, @@ -1083,7 +1087,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REJECTED }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftDeathNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1103,7 +1107,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={SCOPES.REGISTRAR} + scope={ARCHIVE_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={toggleDisplayDialogMock} />, @@ -1125,7 +1129,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={SCOPES.REGISTRAR} + scope={ARCHIVE_SCOPES} draft={draftDeathNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1144,7 +1148,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1163,7 +1167,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1182,7 +1186,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CERTIFIED }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1201,7 +1205,7 @@ describe('Archive action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CORRECTION_REQUESTED }} - scope={SCOPES.RA} + scope={ARCHIVE_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1214,6 +1218,7 @@ describe('Archive action', () => { }) describe('Reinstate action', () => { + const REINSTATE_SCOPES = SCOPES.RA it('Draft', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -1222,7 +1227,7 @@ describe('Reinstate action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DRAFT }} - scope={SCOPES.RA} + scope={REINSTATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1242,7 +1247,7 @@ describe('Reinstate action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={SCOPES.RA} + scope={REINSTATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={toggleDisplayDialogMock} />, @@ -1263,7 +1268,7 @@ describe('Reinstate action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={SCOPES.RA} + scope={REINSTATE_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1282,7 +1287,7 @@ describe('Reinstate action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={SCOPES.RA} + scope={REINSTATE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1295,6 +1300,7 @@ describe('Reinstate action', () => { }) describe('Print action', () => { + const PRINT_SCOPES = SCOPES.RA it('Draft', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -1303,7 +1309,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DRAFT }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1322,7 +1328,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={() => {}} />, @@ -1341,7 +1347,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1360,7 +1366,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftDeathNotDownloaded} duplicates={['duplicate1']} toggleDisplayDialog={() => {}} @@ -1380,7 +1386,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REJECTED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1399,7 +1405,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1418,7 +1424,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1437,7 +1443,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1463,7 +1469,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1482,7 +1488,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CERTIFIED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1501,7 +1507,7 @@ describe('Print action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CORRECTION_REQUESTED }} - scope={SCOPES.RA} + scope={PRINT_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1514,6 +1520,7 @@ describe('Print action', () => { }) describe('Issue action', () => { + const ISSUE_SCOPES = SCOPES.RA it('Draft', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -1522,7 +1529,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DRAFT }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1541,7 +1548,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.IN_PROGRESS }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftDeathDownloaded} toggleDisplayDialog={() => {}} />, @@ -1560,7 +1567,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1579,7 +1586,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.DECLARED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftDeathNotDownloaded} duplicates={['duplicate1']} toggleDisplayDialog={() => {}} @@ -1599,7 +1606,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REJECTED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1618,7 +1625,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.VALIDATED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1637,7 +1644,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.ARCHIVED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1656,7 +1663,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.REGISTERED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1675,7 +1682,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CERTIFIED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, @@ -1699,7 +1706,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CERTIFIED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthNotDownloaded} toggleDisplayDialog={() => {}} />, @@ -1718,7 +1725,7 @@ describe('Issue action', () => { ...defaultDeclaration, status: SUBMISSION_STATUS.CORRECTION_REQUESTED }} - scope={SCOPES.RA} + scope={ISSUE_SCOPES} draft={draftBirthDownloaded} toggleDisplayDialog={() => {}} />, From efad86c9f594a30ba7c97f178032608d0c79415d Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 14:25:38 +0600 Subject: [PATCH 71/88] test: add test for not having scope --- .../src/views/RecordAudit/ActionMenu.test.tsx | 287 +++++++++++++++++- 1 file changed, 271 insertions(+), 16 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index ea3db34d194..739f0d42408 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -77,7 +77,8 @@ const draftDeathNotDownloaded = { const SCOPES = { FA: ['declare'] as any as Scope, RA: ['validate'] as any as Scope, - REGISTRAR: ['register'] as any as Scope + REGISTRAR: ['register'] as any as Scope, + NONE: [] as any as Scope } enum ACTION_STATUS { @@ -118,7 +119,7 @@ const actionStatus = ( } describe('View action', () => { - const VIEW_SCOPES = SCOPES.RA + const VIEW_SCOPES = SCOPES.NONE it('Draft', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -446,7 +447,7 @@ describe('Review action', () => { expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) }) - it('In review - Not downloaded', async () => { + it('In review - Not downloaded - Has Scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(status).toBe(ACTION_STATUS.DISABLED) }) - it('Potential duplicate - Not downloaded', async () => { + it('In review - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REVIEW_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Potential duplicate - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_POTENTIAL_DUPLICATE + ]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Potential duplicate - Not downloaded - Has Scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { ]) expect(status).toBe(ACTION_STATUS.DISABLED) }) + it('Potential duplicate - Downloaded', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -560,7 +603,7 @@ describe('Review action', () => { expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) }) - it('Validated - Not downloaded', async () => { + it('Validated - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(status).toBe(ACTION_STATUS.DISABLED) }) + it('Validated - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REVIEW_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + it('Archived', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -675,7 +737,8 @@ describe('Review action', () => { 'review-correction/' + defaultDeclaration.id ) }) - it('Pending correction - Not downloaded', async () => { + + it('Pending correction - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { ]) expect(status).toBe(ACTION_STATUS.DISABLED) }) + + it('Pending correction - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ + ACTION.REVIEW_CORRECTION_REQUEST + ]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) }) describe('Update action', () => { @@ -751,7 +835,26 @@ describe('Update action', () => { expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) }) - it('In progress - Not downloaded', async () => { + it('In progress - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In progress - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(window.location.href).toContain('reviews/' + defaultDeclaration.id) }) - it('Requires update - Not downloaded', async () => { + it('Requires update - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UPDATE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Requires update - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(status).toBe(ACTION_STATUS.DISABLED) }) - it('Validated - Not downloaded', async () => { + it('Validated', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(toggleDisplayDialogMock).toHaveBeenCalled() }) - it('In progress - Not downloaded', async () => { + it('In progress - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In progress - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(toggleDisplayDialogMock).toHaveBeenCalled() }) - it('In review - Not downloaded', async () => { + it('In review - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In review - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(toggleDisplayDialogMock).toHaveBeenCalled() }) - it('Requires update - Not downloaded', async () => { + it('Requires update - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Requires update - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(toggleDisplayDialogMock).toHaveBeenCalled() }) - it('Validated - Not downloaded', async () => { + it('Validated - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ARCHIVE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Validated - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(toggleDisplayDialogMock).toHaveBeenCalled() }) - it('Archived - Not downloaded', async () => { + it('Archived - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.REINSTATE_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Archived - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { ) }) - it('Registered - Not downloaded', async () => { + it('Registered - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.PRINT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( { expect(window.location.href).toContain('issue/' + defaultDeclaration.id) }) - it('Registered + Printed in advance - Not downloaded', async () => { + it('Registered + Printed in advance - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.ISSUE_CERTIFICATE]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered + Printed in advance - Not downloaded - Has scope', async () => { const { store, history } = createStore() const component = await createTestComponent( Date: Thu, 17 Oct 2024 14:33:30 +0600 Subject: [PATCH 72/88] test: add tests for correct action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 287 +++++++++++++++++- 1 file changed, 286 insertions(+), 1 deletion(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 739f0d42408..4b81f3dd9b7 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -98,7 +98,8 @@ enum ACTION { ARCHIVE_RECORD = 'Archive Record', REINSTATE_RECORD = 'Reinstate Record', PRINT_RECORD = 'Print certified copy', - ISSUE_CERTIFICATE = 'Issue certificate' + ISSUE_CERTIFICATE = 'Issue certificate', + CORRECT_RECORD = 'Correct Record' } const actionStatus = ( @@ -1991,3 +1992,287 @@ describe('Issue action', () => { expect(status).toBe(ACTION_STATUS.HIDDEN) }) }) + +describe('Correct action', () => { + const CORRECTION_SCOPES = SCOPES.RA + it('Draft', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In progress', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In review', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Potential duplicate', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Requires update', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Validated', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Archived', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + await flushPromises() + expect(window.location.href).toContain( + 'correction/' + defaultDeclaration.id + ) + }) + + it('Registered - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered - Not downloaded - Has scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Registered + Printed in advance - Does not have scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Registered + Printed in advance - Not downloaded - Has scope', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.DISABLED) + }) + + it('Registered + Printed in advance - Downloaded', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + + await flushPromises() + expect(window.location.href).toContain( + 'correction/' + defaultDeclaration.id + ) + }) + + it('Pending correction', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.CORRECT_RECORD]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) +}) From 49435212d8ed999e423cdf6c3f1955f5b28917a5 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 14:56:56 +0600 Subject: [PATCH 73/88] test: add tests for delete action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 67 ++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 4b81f3dd9b7..bed48eb4e86 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -99,7 +99,8 @@ enum ACTION { REINSTATE_RECORD = 'Reinstate Record', PRINT_RECORD = 'Print certified copy', ISSUE_CERTIFICATE = 'Issue certificate', - CORRECT_RECORD = 'Correct Record' + CORRECT_RECORD = 'Correct Record', + DELETE_DECLARATION = 'Delete Declaration' } const actionStatus = ( @@ -2276,3 +2277,67 @@ describe('Correct action', () => { expect(status).toBe(ACTION_STATUS.HIDDEN) }) }) + +describe('Delete declaration action', () => { + it('Draft', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ + ACTION.DELETE_DECLARATION + ]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + expect(component.find('h1').hostNodes().text()).toEqual('Delete draft?') + }) + + it('In progress', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.DELETE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('In review', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.DELETE_DECLARATION]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) +}) From 417ccca77c8f9bfaab1a238bc7845c0c5f5a95fe Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 15:06:12 +0600 Subject: [PATCH 74/88] test: add tests for unassign action --- .../src/views/RecordAudit/ActionMenu.test.tsx | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index bed48eb4e86..09e50701566 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -100,7 +100,8 @@ enum ACTION { PRINT_RECORD = 'Print certified copy', ISSUE_CERTIFICATE = 'Issue certificate', CORRECT_RECORD = 'Correct Record', - DELETE_DECLARATION = 'Delete Declaration' + DELETE_DECLARATION = 'Delete Declaration', + UNASSIGN = 'Unassign' } const actionStatus = ( @@ -2341,3 +2342,87 @@ describe('Delete declaration action', () => { expect(status).toBe(ACTION_STATUS.HIDDEN) }) }) + +describe('Unassign action', () => { + const UNASSIGN_SCOPES = SCOPES.REGISTRAR + it('Has scope - assigned to someone else', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status, node } = actionStatus(component, [ACTION.UNASSIGN]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + expect(component.find('h1').hostNodes().text()).toEqual('Unassign record?') + }) + + it('Does not have scope - assigned to someone else', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + + const { status } = actionStatus(component, [ACTION.UNASSIGN]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) + + it('Assigned to self', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + const { status, node } = actionStatus(component, [ACTION.UNASSIGN]) + expect(status).toBe(ACTION_STATUS.ENABLED) + + node?.simulate('click') + expect(component.find('h1').hostNodes().text()).toEqual('Unassign record?') + }) + + it('Not assigned', async () => { + const { store, history } = createStore() + const component = await createTestComponent( + {}} + />, + { store, history } + ) + const { status } = actionStatus(component, [ACTION.UNASSIGN]) + expect(status).toBe(ACTION_STATUS.HIDDEN) + }) +}) From e4403eb49b5253b33261b838f4dd181a7e4204d8 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 15:14:19 +0600 Subject: [PATCH 75/88] test: add tests for assignment text --- .../src/views/RecordAudit/ActionMenu.test.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx index 09e50701566..da5890834d0 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.test.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.test.tsx @@ -2345,6 +2345,7 @@ describe('Delete declaration action', () => { describe('Unassign action', () => { const UNASSIGN_SCOPES = SCOPES.REGISTRAR + const Assignment = 'Assigned to Kennedy Mweene at Ibombo District Office' it('Has scope - assigned to someone else', async () => { const { store, history } = createStore() const component = await createTestComponent( @@ -2360,6 +2361,9 @@ describe('Unassign action', () => { { store, history } ) + const { status: assignmentStatus } = actionStatus(component, [Assignment]) + expect(assignmentStatus).toBe(ACTION_STATUS.ENABLED) + const { status, node } = actionStatus(component, [ACTION.UNASSIGN]) expect(status).toBe(ACTION_STATUS.ENABLED) @@ -2382,6 +2386,9 @@ describe('Unassign action', () => { { store, history } ) + const { status: assignmentStatus } = actionStatus(component, [Assignment]) + expect(assignmentStatus).toBe(ACTION_STATUS.ENABLED) + const { status } = actionStatus(component, [ACTION.UNASSIGN]) expect(status).toBe(ACTION_STATUS.HIDDEN) }) @@ -2400,6 +2407,10 @@ describe('Unassign action', () => { />, { store, history } ) + + const { status: assignmentStatus } = actionStatus(component, [Assignment]) + expect(assignmentStatus).toBe(ACTION_STATUS.HIDDEN) + const { status, node } = actionStatus(component, [ACTION.UNASSIGN]) expect(status).toBe(ACTION_STATUS.ENABLED) @@ -2422,6 +2433,10 @@ describe('Unassign action', () => { />, { store, history } ) + + const { status: assignmentStatus } = actionStatus(component, [Assignment]) + expect(assignmentStatus).toBe(ACTION_STATUS.HIDDEN) + const { status } = actionStatus(component, [ACTION.UNASSIGN]) expect(status).toBe(ACTION_STATUS.HIDDEN) }) From 2ad81cfc4c90dbcfbe9599189aeff43c59c23c9b Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 15:24:15 +0600 Subject: [PATCH 76/88] fix: unhandled errors --- .../src/views/RecordAudit/ActionMenu.tsx | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/packages/client/src/views/RecordAudit/ActionMenu.tsx b/packages/client/src/views/RecordAudit/ActionMenu.tsx index beb9ddd6449..b4ef62628f5 100644 --- a/packages/client/src/views/RecordAudit/ActionMenu.tsx +++ b/packages/client/src/views/RecordAudit/ActionMenu.tsx @@ -352,26 +352,24 @@ const ReviewAction: React.FC< {intl.formatMessage(messages.reviewCorrection)} - ) : ( - isReviewableDeclaration(declarationStatus) && ( - { - dispatch( - goToPage( - REVIEW_EVENT_PARENT_FORM_PAGE, - declarationId as string, - 'review', - type as string - ) + ) : isReviewableDeclaration(declarationStatus) ? ( + { + dispatch( + goToPage( + REVIEW_EVENT_PARENT_FORM_PAGE, + declarationId as string, + 'review', + type as string ) - }} - disabled={!isDownloaded} - > - - {intl.formatMessage(messages.reviewDeclaration, { isDuplicate })} - - ) - ) + ) + }} + disabled={!isDownloaded} + > + + {intl.formatMessage(messages.reviewDeclaration, { isDuplicate })} + + ) : null } const UpdateAction: React.FC = ({ @@ -499,13 +497,12 @@ const DeleteAction: React.FC<{ declarationStatus?: SUBMISSION_STATUS }> = ({ handleDelete, declarationStatus }) => { const intl = useIntl() + if (declarationStatus !== SUBMISSION_STATUS.DRAFT) return null return ( - declarationStatus === SUBMISSION_STATUS.DRAFT && ( - - - {intl.formatMessage(buttonMessages.deleteDeclaration)} - - ) + + + {intl.formatMessage(buttonMessages.deleteDeclaration)} + ) } const UnassignAction: React.FC<{ From 6a77319ecb38c642a6db4f7ed2055d988753939b Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 15:59:39 +0600 Subject: [PATCH 77/88] chore: remove old tests --- .../views/RecordAudit/RecordAudit.test.tsx | 151 +----------------- 1 file changed, 2 insertions(+), 149 deletions(-) diff --git a/packages/client/src/views/RecordAudit/RecordAudit.test.tsx b/packages/client/src/views/RecordAudit/RecordAudit.test.tsx index d17cbdbdf8b..78eff975f4f 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.test.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.test.tsx @@ -14,8 +14,6 @@ import { createTestComponent, mockDeclarationData, createRouterProps, - registerScopeToken, - getItem, flushPromises, mockDeathDeclarationData, mockMarriageDeclarationData, @@ -27,22 +25,14 @@ import { ReactWrapper } from 'enzyme' import { createDeclaration, storeDeclaration, - IDeclaration, - SUBMISSION_STATUS, - DOWNLOAD_STATUS + IDeclaration } from '@client/declarations' import { Event } from '@client/utils/gateway' import { formatUrl } from '@client/navigation' import { DECLARATION_RECORD_AUDIT } from '@client/navigation/routes' import type { GQLBirthEventSearchSet } from '@client/utils/gateway-deprecated-do-not-use' -import { checkAuth } from '@client/profile/profileActions' import { FETCH_DECLARATION_SHORT_INFO } from './queries' import { waitForElement } from '@client/tests/wait-for-element' -import { - getCurrentUserWorkqueuSuccess, - IWorkqueue, - workqueueInitialState -} from '@client/workqueue' const declaration: IDeclaration = createDeclaration( Event.Birth, @@ -75,24 +65,6 @@ declaration.data.history = [ } ] -const workqueue: IWorkqueue = { - ...workqueueInitialState.workqueue, - data: { - inProgressTab: {}, - notificationTab: {}, - reviewTab: { - results: [{ id: declaration.id, registration: {} }], - totalItems: 1 - }, - rejectTab: {}, - approvalTab: {}, - printTab: {}, - issueTab: {}, - externalValidationTab: {} - }, - initialSyncDone: true -} - describe('Record audit summary for a draft birth declaration', () => { let component: ReactWrapper<{}, {}> @@ -244,7 +216,7 @@ describe('Record audit summary for WorkQueue declarations', () => { store.getState().workqueueState.workqueue.data.inProgressTab.results = [ { id: 'db097901-feba-4f71-a1ae-d3d46289d2d5', - type: 'Birth', + type: Event.Birth, registration: { status: 'DRAFT', contactNumber: '+8801622688231', @@ -341,69 +313,6 @@ describe('Record audit summary for WorkQueue declarations', () => { }) }) -describe('Record audit for a draft declaration', () => { - let component: ReactWrapper<{}, {}> - - beforeEach(async () => { - const { store, history } = createStore() - - getItem.mockReturnValue(registerScopeToken) - - store.dispatch(checkAuth()) - - await flushPromises() - - declaration.submissionStatus = SUBMISSION_STATUS.DECLARED - declaration.downloadStatus = DOWNLOAD_STATUS.DOWNLOADED - - store.dispatch(storeDeclaration(declaration)) - store.dispatch(getCurrentUserWorkqueuSuccess(JSON.stringify(workqueue))) - - component = await createTestComponent( - , - { store, history } - ) - }) - - it('should show the archive button', async () => { - expect(component.exists('#archive_button')).toBeTruthy() - }) - - it('should show the confirmation modal when archive button is clicked', async () => { - component.find('#archive_button').hostNodes().simulate('click') - - component.update() - - expect(component.find('ResponsiveModal').prop('show')).toBeTruthy() - }) - - it('should close the confirmation modal when cancel button is clicked', async () => { - component.find('#archive_button').hostNodes().simulate('click') - - component.update() - - component.find('#cancel-btn').hostNodes().simulate('click') - - component.update() - - expect(component.find('ResponsiveModal').prop('show')).toBe(false) - }) -}) - describe('Record audit summary for GQLQuery', () => { let component: ReactWrapper<{}, {}> @@ -544,59 +453,3 @@ describe('Record audit summary for unsuccesful GQLQuery', () => { expect(window.location.href).not.toContain('/record-audit') }) }) - -describe('Record audit for a reinstate declaration', () => { - let component: ReactWrapper<{}, {}> - - beforeEach(async () => { - const { store, history } = createStore() - - getItem.mockReturnValue(registerScopeToken) - - store.dispatch(checkAuth()) - - await flushPromises() - - declaration.submissionStatus = SUBMISSION_STATUS.ARCHIVED - declaration.downloadStatus = DOWNLOAD_STATUS.DOWNLOADED - store.dispatch(storeDeclaration(declaration)) - store.dispatch(getCurrentUserWorkqueuSuccess(JSON.stringify(workqueue))) - - component = await createTestComponent( - , - { store, history } - ) - }) - - it('should show the reinstate button', async () => { - expect(component.exists('#reinstate_button')).toBeTruthy() - }) - - it('should show the confirmation modal when reinstate button is clicked', async () => { - component.find('#reinstate_button').hostNodes().simulate('click') - component.update() - expect(component.find('ResponsiveModal').prop('show')).toBeTruthy() - }) - - it('should close the confirmation modal when cancel button is clicked', async () => { - component.find('#reinstate_button').hostNodes().simulate('click') - component.update() - component.find('#cancel-btn').hostNodes().simulate('click') - component.update() - expect(component.find('ResponsiveModal').prop('show')).toBe(false) - }) -}) From 3c055bb49989087ef893a74d9917ddd06f80555d Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 16:43:00 +0600 Subject: [PATCH 78/88] fix: use EVENT.Birth instead of "Birth" --- .../features/search/type-resolvers.test.ts | 63 ++++++++++--------- .../src/features/search/type-resolvers.ts | 8 +-- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/packages/gateway/src/features/search/type-resolvers.test.ts b/packages/gateway/src/features/search/type-resolvers.test.ts index 31266bf8fe2..3189156b662 100644 --- a/packages/gateway/src/features/search/type-resolvers.test.ts +++ b/packages/gateway/src/features/search/type-resolvers.test.ts @@ -10,6 +10,7 @@ */ import { searchTypeResolvers as resolvers } from '@gateway/features/search/type-resolvers' import { TestResolvers } from '@gateway/utils/testUtils' +import { EVENT } from '@opencrvs/commons' import * as fetchAny from 'jest-fetch-mock' const searchTypeResolvers = resolvers as unknown as TestResolvers const fetch = fetchAny as any @@ -22,7 +23,7 @@ describe('Search type resolvers', () => { it('return BirthEventSearchSet type', () => { const mock = { _source: { - event: 'Birth' + event: EVENT.BIRTH } } const res = searchTypeResolvers.EventSearchSet!.__resolveType(mock) @@ -31,7 +32,7 @@ describe('Search type resolvers', () => { it('return DeathEventSearchSet type', () => { const mock = { _source: { - event: 'Death' + event: EVENT.DEATH } } const res = searchTypeResolvers.EventSearchSet!.__resolveType(mock) @@ -48,16 +49,16 @@ describe('Search type resolvers', () => { const type = searchTypeResolvers.BirthEventSearchSet!.type({ _id: '123', _source: { - event: 'Birth' + event: EVENT.BIRTH } }) - expect(type).toBe('Birth') + expect(type).toBe(EVENT.BIRTH) }) it('returns childName from birth event search set', () => { const name = searchTypeResolvers.BirthEventSearchSet!.childName({ _id: '123', _source: { - event: 'Birth', + event: EVENT.BIRTH, childFirstNames: 'Bishal', childMiddleName: 'Bashak', childFamilyName: 'Papon', @@ -87,7 +88,7 @@ describe('Search type resolvers', () => { const name = searchTypeResolvers.BirthEventSearchSet!.childName({ _id: '123', _source: { - event: 'Birth' + event: EVENT.BIRTH } }) expect(name).toEqual([ @@ -107,7 +108,7 @@ describe('Search type resolvers', () => { const dob = searchTypeResolvers.BirthEventSearchSet!.dateOfBirth({ _id: '123', _source: { - event: 'Birth', + event: EVENT.BIRTH, childFirstNames: 'Anik', childFamilyName: 'Hoque', childFirstNamesLocal: 'অনিক', @@ -121,7 +122,7 @@ describe('Search type resolvers', () => { const dob = searchTypeResolvers.BirthEventSearchSet!.dateOfBirth({ _id: '123', _source: { - event: 'Birth', + event: EVENT.BIRTH, childFirstNames: 'Anik', childFamilyName: 'Hoque', childFirstNamesLocal: 'অনিক', @@ -135,7 +136,7 @@ describe('Search type resolvers', () => { searchTypeResolvers.BirthEventSearchSet!.registration({ _id: '123', _source: { - event: 'Birth', + event: EVENT.BIRTH, childFirstNames: 'Anik', childFamilyName: 'Hoque', childFirstNamesLocal: 'অনিক', @@ -144,7 +145,7 @@ describe('Search type resolvers', () => { } }) expect(registration).toEqual({ - event: 'Birth', + event: EVENT.BIRTH, childFirstNames: 'Anik', childFamilyName: 'Hoque', childFirstNamesLocal: 'অনিক', @@ -236,16 +237,16 @@ describe('Search type resolvers', () => { const type = searchTypeResolvers.DeathEventSearchSet!.type({ _id: '123', _source: { - event: 'Death' + event: EVENT.DEATH } }) - expect(type).toBe('Death') + expect(type).toBe(EVENT.DEATH) }) it('returns deceassedName from Death event search set', () => { const name = searchTypeResolvers.DeathEventSearchSet!.deceasedName({ _id: '123', _source: { - event: 'Death', + event: EVENT.DEATH, deceasedFirstNames: 'Bishal', deceasedMiddleName: 'Bashak', deceasedFamilyName: 'Papon', @@ -275,7 +276,7 @@ describe('Search type resolvers', () => { const name = searchTypeResolvers.DeathEventSearchSet!.deceasedName({ _id: '123', _source: { - event: 'Death' + event: EVENT.DEATH } }) expect(name).toEqual([ @@ -295,7 +296,7 @@ describe('Search type resolvers', () => { const dod = searchTypeResolvers.DeathEventSearchSet!.dateOfDeath({ _id: '123', _source: { - event: 'Death', + event: EVENT.DEATH, deceasedFirstNames: 'Anik', deceasedFamilyName: 'Hoque', deceasedFirstNamesLocal: 'অনিক', @@ -309,7 +310,7 @@ describe('Search type resolvers', () => { const dod = searchTypeResolvers.DeathEventSearchSet!.dateOfDeath({ _id: '123', _source: { - event: 'Death', + event: EVENT.DEATH, deceasedFirstNames: 'Anik', deceasedFamilyName: 'Hoque', deceasedFirstNamesLocal: 'অনিক', @@ -323,7 +324,7 @@ describe('Search type resolvers', () => { searchTypeResolvers.DeathEventSearchSet!.registration({ _id: '123', _source: { - event: 'Death', + event: EVENT.DEATH, deceasedFirstNames: 'Anik', deceasedFamilyName: 'Hoque', deceasedFirstNamesLocal: 'অনিক', @@ -332,7 +333,7 @@ describe('Search type resolvers', () => { } }) expect(registration).toEqual({ - event: 'Death', + event: EVENT.DEATH, deceasedFirstNames: 'Anik', deceasedFamilyName: 'Hoque', deceasedFirstNamesLocal: 'অনিক', @@ -416,7 +417,7 @@ describe('Search type resolvers', () => { describe('type resolvers for event registration', () => { it('returns status from search set', () => { const status = searchTypeResolvers.RegistrationSearchSet!.status({ - event: 'Death', + event: EVENT.DEATH, type: 'DECLARED', deceasedFirstNames: 'Anik', deceasedFamilyName: 'Hoque', @@ -429,7 +430,7 @@ describe('Search type resolvers', () => { it('returns locationid from search set', () => { const locationid = searchTypeResolvers.RegistrationSearchSet!.registeredLocationId({ - event: 'Death', + event: EVENT.DEATH, type: 'DECLARED', deceasedFirstNames: 'Anik', deceasedFamilyName: 'Hoque', @@ -443,7 +444,7 @@ describe('Search type resolvers', () => { it('returns eventLocationId from search set', () => { const eventLocationId = searchTypeResolvers.RegistrationSearchSet!.eventLocationId({ - event: 'Death', + event: EVENT.DEATH, type: 'DECLARED', deceasedFirstNames: 'Anik', deceasedFamilyName: 'Hoque', @@ -457,7 +458,7 @@ describe('Search type resolvers', () => { }) it('returns duplicates from search set', () => { const duplicates = searchTypeResolvers.RegistrationSearchSet!.duplicates({ - event: 'Death', + event: EVENT.DEATH, type: 'DECLARED', deceasedFirstNames: 'Anik', deceasedFamilyName: 'Hoque', @@ -481,16 +482,16 @@ describe('Search type resolvers', () => { it('returns event type', () => { const type = searchTypeResolvers.EventProgressSet!.type({ _source: { - event: 'Birth' + event: EVENT.BIRTH } }) - expect(type).toEqual('Birth') + expect(type).toEqual(EVENT.BIRTH) }) it('returns child name', () => { const childName = searchTypeResolvers.EventProgressSet!.name({ _source: { - event: 'Birth', + event: EVENT.BIRTH, childFirstNames: 'Jon', childMiddleName: 'C.', childFamilyName: 'Doe', @@ -515,7 +516,7 @@ describe('Search type resolvers', () => { it('returns deceased name', () => { const deceasedName = searchTypeResolvers.EventProgressSet!.name({ _source: { - event: 'Death', + event: EVENT.DEATH, deceasedFirstNames: 'Jon', deceasedMiddleName: 'C.', deceasedFamilyName: 'Doe', @@ -540,7 +541,7 @@ describe('Search type resolvers', () => { it('returns date of birth', () => { const dateOfBirth = searchTypeResolvers.EventProgressSet!.dateOfEvent({ _source: { - event: 'Birth', + event: EVENT.BIRTH, childDoB: '01-01-2019' } }) @@ -549,7 +550,7 @@ describe('Search type resolvers', () => { it('returns date of death', () => { const dateOfDeath = searchTypeResolvers.EventProgressSet!.dateOfEvent({ _source: { - event: 'Death', + event: EVENT.DEATH, deathDate: '01-01-2019' } }) @@ -559,18 +560,18 @@ describe('Search type resolvers', () => { const registration = searchTypeResolvers.EventProgressSet!.registration({ _id: 'dummy_id', _source: { - event: 'Birth' + event: EVENT.BIRTH } }) expect(registration).toEqual({ - event: 'Birth' + event: EVENT.BIRTH }) }) it('return the startedAt from operationalHistories', () => { const startedAt = searchTypeResolvers.EventProgressSet!.startedAt({ _id: 'dummy_id', _source: { - event: 'Birth', + event: EVENT.BIRTH, operationHistories: [ { operatedOn: '2019-12-12T15:21:51.355Z', diff --git a/packages/gateway/src/features/search/type-resolvers.ts b/packages/gateway/src/features/search/type-resolvers.ts index cfb4264bae9..dbaa14e1bb9 100644 --- a/packages/gateway/src/features/search/type-resolvers.ts +++ b/packages/gateway/src/features/search/type-resolvers.ts @@ -384,17 +384,17 @@ export const searchTypeResolvers: GQLResolver = { return searchData._source.event }, name(searchData: ISearchEventDataTemplate) { - if (searchData._source.event === 'Birth') { + if (searchData._source.event === EVENT.BIRTH) { return getChildName(searchData._source) - } else if (searchData._source.event === 'Death') { + } else if (searchData._source.event === EVENT.DEATH) { return getDeceasedName(searchData._source) } return null }, dateOfEvent(searchData: ISearchEventDataTemplate) { - if (searchData._source.event === 'Birth') { + if (searchData._source.event === EVENT.BIRTH) { return (searchData._source && searchData._source.childDoB) || null - } else if (searchData._source.event === 'Death') { + } else if (searchData._source.event === EVENT.DEATH) { return (searchData._source && searchData._source.deathDate) || null } return null From 0df9bf2b30e6cf4f9a9022062d549c97eb756130 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 17:00:01 +0600 Subject: [PATCH 79/88] fix: use EVENT.Birth instead of "Birth" --- .../AdvancedSearchResult.test.tsx | 2 +- .../inExternalValidationTab.test.tsx | 2 +- .../OfficeHome/inProgress/inProgress.test.tsx | 14 ++++++------ .../readyForReview/readyForReview.test.tsx | 18 +++++++-------- .../readyToPrint/readyToPrint.test.tsx | 10 ++++----- .../requiresUpdate/requiresUpdate.test.tsx | 14 ++++++------ .../sentForReview/SentForReview.test.tsx | 15 +++++++------ .../views/SearchResult/SearchResult.test.tsx | 22 +++++++++---------- .../Performance/WorkflowStatus.test.tsx | 4 ++-- 9 files changed, 51 insertions(+), 50 deletions(-) diff --git a/packages/client/src/views/AdvancedSearch/AdvancedSearchResult.test.tsx b/packages/client/src/views/AdvancedSearch/AdvancedSearchResult.test.tsx index 3a235b3c9e2..65db53f17dc 100644 --- a/packages/client/src/views/AdvancedSearch/AdvancedSearchResult.test.tsx +++ b/packages/client/src/views/AdvancedSearch/AdvancedSearchResult.test.tsx @@ -54,7 +54,7 @@ const graphqlMock = [ results: [ { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, __typename: 'X', registration: { __typename: 'X', diff --git a/packages/client/src/views/OfficeHome/inExternalValidation/inExternalValidationTab.test.tsx b/packages/client/src/views/OfficeHome/inExternalValidation/inExternalValidationTab.test.tsx index 337807939df..3f3799070d7 100644 --- a/packages/client/src/views/OfficeHome/inExternalValidation/inExternalValidationTab.test.tsx +++ b/packages/client/src/views/OfficeHome/inExternalValidation/inExternalValidationTab.test.tsx @@ -42,7 +42,7 @@ const getItem = window.localStorage.getItem as Mock const birthEventSearchSet: GQLBirthEventSearchSet = { id: '956281c9-1f47-4c26-948a-970dd23c4094', - type: 'Birth', + type: Event.Birth, registration: { status: 'WAITING_VALIDATION', contactNumber: '01622688231', diff --git a/packages/client/src/views/OfficeHome/inProgress/inProgress.test.tsx b/packages/client/src/views/OfficeHome/inProgress/inProgress.test.tsx index 440a1d856ba..33b8b91e638 100644 --- a/packages/client/src/views/OfficeHome/inProgress/inProgress.test.tsx +++ b/packages/client/src/views/OfficeHome/inProgress/inProgress.test.tsx @@ -474,7 +474,7 @@ describe('In Progress tab', () => { results: [ { id: '956281c9-1f47-4c26-948a-970dd23c4094', - type: 'Death', + type: Event.Death, registration: { status: 'IN_PROGRESS', contactNumber: undefined, @@ -610,7 +610,7 @@ describe('In Progress tab', () => { results: [ { id: '956281c9-1f47-4c26-948a-970dd23c4094', - type: 'Death', + type: Event.Death, registration: { status: 'IN_PROGRESS', contactNumber: undefined, @@ -706,7 +706,7 @@ describe('In Progress tab', () => { results: [ { id: declarationId, - type: 'Birth', + type: Event.Birth, registration: { trackingId: 'BQ2IDOP', modifiedAt: TIME_STAMP @@ -797,7 +797,7 @@ describe('In Progress tab', () => { formatUrl(REVIEW_EVENT_PARENT_FORM_PAGE, { declarationId, pageId: 'review', - event: 'birth' + event: Event.Birth }) ) }) @@ -836,7 +836,7 @@ describe('In Progress tab', () => { results: [ { id: 'f0a1ca2c-6a14-4b9e-a627-c3e2e110587e', - type: 'Birth', + type: Event.Birth, registration: { trackingId: 'BQ2IDOP', modifiedAt: TIME_STAMP @@ -872,7 +872,7 @@ describe('In Progress tab', () => { } as GQLBirthEventSearchSet, { id: '2f7828fd-24ac-49fd-a1fd-53cda4777aa0', - type: 'Death', + type: Event.Death, registration: { trackingId: 'DZECJZC', modifiedAt: TIME_STAMP @@ -951,7 +951,7 @@ describe('In Progress tab', () => { results: [ { id: declarationId, - type: 'Birth', + type: Event.Birth, registration: { trackingId: 'BQ2IDOP', modifiedAt: TIME_STAMP diff --git a/packages/client/src/views/OfficeHome/readyForReview/readyForReview.test.tsx b/packages/client/src/views/OfficeHome/readyForReview/readyForReview.test.tsx index f0c8d69ed9c..24c4f231e72 100644 --- a/packages/client/src/views/OfficeHome/readyForReview/readyForReview.test.tsx +++ b/packages/client/src/views/OfficeHome/readyForReview/readyForReview.test.tsx @@ -72,7 +72,7 @@ const mockListSyncController = vi.fn() const mockSearchData = { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'DECLARED', contactNumber: '01622688231', @@ -153,7 +153,7 @@ const mockReviewTabData = { results: [ { id: '9a55d213-ad9f-4dcd-9418-340f3a7f6269', - type: 'Birth', + type: Event.Birth, registration: { status: 'DECLARED', contactNumber: '01622688231', @@ -201,7 +201,7 @@ const mockReviewTabData = { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'VALIDATED', trackingId: 'DW0UTHR', @@ -352,7 +352,7 @@ describe('OfficeHome sent for review tab related tests', () => { results: [ { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'DECLARED', contactNumber: '01622688231', @@ -380,7 +380,7 @@ describe('OfficeHome sent for review tab related tests', () => { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'VALIDATED', trackingId: 'DW0UTHR', @@ -555,7 +555,7 @@ describe('OfficeHome sent for review tab related tests', () => { results: [ { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'VALIDATED', contactNumber: '01622688231', @@ -580,7 +580,7 @@ describe('OfficeHome sent for review tab related tests', () => { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'DECLARED', trackingId: 'DW0UTHR', @@ -750,7 +750,7 @@ describe('Tablet tests', () => { results: [ { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'VALIDATED', contactNumber: '01622688231', @@ -778,7 +778,7 @@ describe('Tablet tests', () => { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'DECLARED', trackingId: 'DW0UTHR', diff --git a/packages/client/src/views/OfficeHome/readyToPrint/readyToPrint.test.tsx b/packages/client/src/views/OfficeHome/readyToPrint/readyToPrint.test.tsx index 66180fa6cde..4aa1773c424 100644 --- a/packages/client/src/views/OfficeHome/readyToPrint/readyToPrint.test.tsx +++ b/packages/client/src/views/OfficeHome/readyToPrint/readyToPrint.test.tsx @@ -73,7 +73,7 @@ const nameObj = { const mockUserData = { id: '956281c9-1f47-4c26-948a-970dd23c4094', - type: 'Birth', + type: Event.Birth, registration: { status: 'REGISTERED', contactNumber: '01622688231', @@ -155,7 +155,7 @@ const mockPrintTabData = { results: [ { id: '956281c9-1f47-4c26-948a-970dd23c4094', - type: 'Death', + type: Event.Death, registration: { status: 'REGISTERED', contactNumber: undefined, @@ -204,7 +204,7 @@ const mockPrintTabData = { } as GQLDeathEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'REGISTERED', trackingId: 'DW0UTHR', @@ -252,7 +252,7 @@ describe('RegistrarHome ready to print tab related tests', () => { const birthEventRegisteredDate = '2019-10-20T11:03:20.660Z' const birthEventSearchSet: GQLBirthEventSearchSet = { id: '956281c9-1f47-4c26-948a-970dd23c4094', - type: 'Birth', + type: Event.Birth, registration: { status: 'REGISTERED', contactNumber: '01622688231', @@ -302,7 +302,7 @@ describe('RegistrarHome ready to print tab related tests', () => { const deathEventSearchSet: GQLDeathEventSearchSet = { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'REGISTERED', trackingId: 'DW0UTHR', diff --git a/packages/client/src/views/OfficeHome/requiresUpdate/requiresUpdate.test.tsx b/packages/client/src/views/OfficeHome/requiresUpdate/requiresUpdate.test.tsx index 788be23bfab..1b88a7f5b46 100644 --- a/packages/client/src/views/OfficeHome/requiresUpdate/requiresUpdate.test.tsx +++ b/packages/client/src/views/OfficeHome/requiresUpdate/requiresUpdate.test.tsx @@ -78,7 +78,7 @@ const TIME_STAMP = '1544188309380' const mockUserData = { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'REJECTED', contactNumber: '01622688231', @@ -181,7 +181,7 @@ describe('OfficeHome sent for update tab related tests', () => { results: [ { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'REJECTED', contactNumber: '01622688231', @@ -230,7 +230,7 @@ describe('OfficeHome sent for update tab related tests', () => { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'REJECTED', trackingId: 'DW0UTHR', @@ -338,7 +338,7 @@ describe('OfficeHome sent for update tab related tests', () => { results: [ { id: '9a55d213-ad9f-4dcd-9418-340f3a7f6269', - type: 'Birth', + type: Event.Birth, registration: { status: 'REJECTED', contactNumber: '01622688231', @@ -369,7 +369,7 @@ describe('OfficeHome sent for update tab related tests', () => { }, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'REJECTED', trackingId: 'DW0UTHR', @@ -510,7 +510,7 @@ describe('Tablet tests', () => { results: [ { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'REJECTED', contactNumber: '01622688231', @@ -538,7 +538,7 @@ describe('Tablet tests', () => { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'REJECTED', trackingId: 'DW0UTHR', diff --git a/packages/client/src/views/OfficeHome/sentForReview/SentForReview.test.tsx b/packages/client/src/views/OfficeHome/sentForReview/SentForReview.test.tsx index f0e76420f3e..d16cc4f651e 100644 --- a/packages/client/src/views/OfficeHome/sentForReview/SentForReview.test.tsx +++ b/packages/client/src/views/OfficeHome/sentForReview/SentForReview.test.tsx @@ -29,6 +29,7 @@ import type { import { formattedDuration } from '@client/utils/date-formatting' import { History } from 'history' import { vi, Mock } from 'vitest' +import { Event } from '@client/utils/gateway' const validateScopeToken = jwt.sign( { scope: ['validate'] }, @@ -59,7 +60,7 @@ const nameObj = { const mockUserData = { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'DECLARED', contactNumber: '01622688231', @@ -158,7 +159,7 @@ describe('RegistrationHome sent for approval tab related tests', () => { results: [ { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'VALIDATED', contactNumber: '01622688231', @@ -207,7 +208,7 @@ describe('RegistrationHome sent for approval tab related tests', () => { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'VALIDATED', trackingId: 'DW0UTHR', @@ -355,7 +356,7 @@ describe('RegistrationHome sent for approval tab related tests', () => { results: [ { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'VALIDATED', contactNumber: '01622688231', @@ -383,7 +384,7 @@ describe('RegistrationHome sent for approval tab related tests', () => { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'VALIDATED', trackingId: 'DW0UTHR', @@ -483,7 +484,7 @@ describe('Tablet tests', () => { results: [ { id: 'e302f7c5-ad87-4117-91c1-35eaf2ea7be8', - type: 'Birth', + type: Event.Birth, registration: { status: 'VALIDATED', contactNumber: '01622688231', @@ -511,7 +512,7 @@ describe('Tablet tests', () => { } as GQLBirthEventSearchSet, { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, registration: { status: 'VALIDATED', trackingId: 'DW0UTHR', diff --git a/packages/client/src/views/SearchResult/SearchResult.test.tsx b/packages/client/src/views/SearchResult/SearchResult.test.tsx index 856e4b2ff76..07b4553e220 100644 --- a/packages/client/src/views/SearchResult/SearchResult.test.tsx +++ b/packages/client/src/views/SearchResult/SearchResult.test.tsx @@ -100,7 +100,7 @@ describe('SearchResult tests', () => { results: [ { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, __typename: 'X', registration: { __typename: 'X', @@ -131,7 +131,7 @@ describe('SearchResult tests', () => { }, { id: 'c7e83060-4db9-4057-8b14-71841243b05f', - type: 'Death', + type: Event.Death, __typename: 'X', registration: { __typename: 'X', @@ -166,7 +166,7 @@ describe('SearchResult tests', () => { }, { id: '150dd4ca-6822-4f94-ad92-b9be037dec2f', - type: 'Birth', + type: Event.Birth, __typename: 'X', registration: { __typename: 'X', @@ -197,7 +197,7 @@ describe('SearchResult tests', () => { }, { id: '150dd4ca-6822-4f94-ad92-brbe037dec2f', - type: 'Birth', + type: Event.Birth, __typename: 'X', registration: { __typename: 'X', @@ -228,7 +228,7 @@ describe('SearchResult tests', () => { }, { id: '150dd4ca-6822-4f94-ad92-b9beee7dec2f', - type: 'Birth', + type: Event.Birth, __typename: 'X', registration: { __typename: 'X', @@ -259,7 +259,7 @@ describe('SearchResult tests', () => { }, { id: 'fd60a75e-314e-4231-aab7-e6b71fb1106a', - type: 'Birth', + type: Event.Birth, __typename: 'X', registration: { __typename: 'X', @@ -414,7 +414,7 @@ describe('SearchResult tests', () => { results: [ { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e95', - type: 'Death', + type: Event.Death, __typename: 'X', registration: { __typename: 'X', @@ -508,7 +508,7 @@ describe('SearchResult tests', () => { results: [ { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e92', - type: 'Death', + type: Event.Death, __typename: 'X', registration: { __typename: 'X', @@ -610,7 +610,7 @@ describe('SearchResult tests', () => { results: [ { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e91', - type: 'Death', + type: Event.Death, __typename: 'X', registration: { __typename: 'X', @@ -717,7 +717,7 @@ describe('SearchResult downloadButton tests', () => { results: [ { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e91', - type: 'Death', + type: Event.Death, __typename: 'X', registration: { __typename: 'X', @@ -814,7 +814,7 @@ describe('SearchResult downloadButton tests', () => { results: [ { id: 'bc09200d-0160-43b4-9e2b-5b9e90424e92', - type: 'Death', + type: Event.Death, __typename: 'X', registration: { __typename: 'X', diff --git a/packages/client/src/views/SysAdmin/Performance/WorkflowStatus.test.tsx b/packages/client/src/views/SysAdmin/Performance/WorkflowStatus.test.tsx index 2d343233ba8..406584d8e3e 100644 --- a/packages/client/src/views/SysAdmin/Performance/WorkflowStatus.test.tsx +++ b/packages/client/src/views/SysAdmin/Performance/WorkflowStatus.test.tsx @@ -114,7 +114,7 @@ describe('Workflow status tests', () => { }, { id: 'd78d29a1-8521-4582-9f4e-902907ca369a', - type: 'Birth', + type: Event.Birth, name: [ { use: 'en', @@ -168,7 +168,7 @@ describe('Workflow status tests', () => { }, { id: '8a1d92b8-18a6-4074-83fb-cc57134e6dbf', - type: 'Birth', + type: Event.Birth, name: [ { use: 'en', From 15616808c58e6577e838097db984888e30b0cdf3 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 17:03:25 +0600 Subject: [PATCH 80/88] fix: eventToggle id in test --- .../views/RegisterForm/DeclarationForm.test.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/client/src/views/RegisterForm/DeclarationForm.test.tsx b/packages/client/src/views/RegisterForm/DeclarationForm.test.tsx index 9b1a41be742..25eb56f03a1 100644 --- a/packages/client/src/views/RegisterForm/DeclarationForm.test.tsx +++ b/packages/client/src/views/RegisterForm/DeclarationForm.test.tsx @@ -143,24 +143,30 @@ describe('when user has starts a new declaration', () => { expect(window.location.href).toContain('/') }) it('check toggle menu toggle button handler', async () => { - app.find('#eventToggleMenuToggleButton').hostNodes().simulate('click') + app + .find('#eventToggleMenu-Dropdown-Content') + .hostNodes() + .simulate('click') await flushPromises() app.update() expect( - app.find('#eventToggleMenuToggleButton').hostNodes().length + app.find('#eventToggleMenu-Dropdown-Content').hostNodes().length ).toEqual(1) }) it('check toggle menu item handler', async () => { const menuLink = await waitForElement( app, - '#eventToggleMenuToggleButton' + '#eventToggleMenu-Dropdown-Content' ) menuLink.hostNodes().simulate('click') await flushPromises() app.update() - await waitForElement(app, '#eventToggleMenuItem0') - app.find('#eventToggleMenuItem0').hostNodes().simulate('click') + await waitForElement(app, '#eventToggleMenu-Dropdown-Content') + app + .find('#eventToggleMenu-Dropdown-Content') + .hostNodes() + .simulate('click') await flushPromises() app.update() From 3c75d6ce399eee4b5f02b127db90eea57cab0d9e Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 17:22:26 +0600 Subject: [PATCH 81/88] fix: eventToggle id in test --- .../SysAdmin/Config/Systems/Systems.test.tsx | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/client/src/views/SysAdmin/Config/Systems/Systems.test.tsx b/packages/client/src/views/SysAdmin/Config/Systems/Systems.test.tsx index fb8831a1222..28783b890bf 100644 --- a/packages/client/src/views/SysAdmin/Config/Systems/Systems.test.tsx +++ b/packages/client/src/views/SysAdmin/Config/Systems/Systems.test.tsx @@ -267,12 +267,18 @@ describe('render toggle settings', () => { it('should delete system successfully', async () => { component - .find('#toggleMenuToggleButton') + .find('#toggleMenu-dropdownMenu') .hostNodes() .first() .simulate('click') - component.find('#toggleMenuItem3').hostNodes().simulate('click') + component + .find('#toggleMenu-Dropdown-Content') + .find('li') + .hostNodes() + .at(3) + .simulate('click') + component.find('#delete').hostNodes().simulate('click') component.update() const modal = await waitForElement(component, '#systemToDeleteSuccess') @@ -315,12 +321,17 @@ describe('render toggle settings', () => { it('should deactivated system successfully', async () => { component - .find('#toggleMenuToggleButton') + .find('#toggleMenu-dropdownMenu') .hostNodes() .first() .simulate('click') - component.find('#toggleMenuItem2').hostNodes().simulate('click') + component + .find('#toggleMenu-Dropdown-Content') + .find('li') + .hostNodes() + .at(2) + .simulate('click') component.find('#confirm').hostNodes().simulate('click') component.update() const modal = await waitForElement( @@ -365,12 +376,20 @@ describe('render toggle settings', () => { it('should active system successfully', async () => { component - .find('#toggleMenuToggleButton') + .find('#toggleMenu-dropdownMenu') .hostNodes() .last() .simulate('click') - component.find('#toggleMenuItem1').hostNodes().simulate('click') + component + .find('#toggleMenu-Dropdown-Content') + .hostNodes() + .last() + .find('li') + .hostNodes() + .at(1) + .simulate('click') + component.find('#confirm').hostNodes().simulate('click') component.update() const modal = await waitForElement( From 4db832d2799b0f8d9d69655fabb3c6b8baf64981 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 18:05:17 +0600 Subject: [PATCH 82/88] fix: ids in UserList.test --- .../SysAdmin/Team/user/UserList.test.tsx | 147 +++++++++++------- 1 file changed, 89 insertions(+), 58 deletions(-) diff --git a/packages/client/src/views/SysAdmin/Team/user/UserList.test.tsx b/packages/client/src/views/SysAdmin/Team/user/UserList.test.tsx index beadadb8ed5..8002a5aad41 100644 --- a/packages/client/src/views/SysAdmin/Team/user/UserList.test.tsx +++ b/packages/client/src/views/SysAdmin/Team/user/UserList.test.tsx @@ -361,28 +361,32 @@ describe('User list tests', () => { it('clicking on toggleMenu pops up menu options', async () => { const toggleButtonElement = await waitForElement( component, - '#user-item-0-menuToggleButton' + '#user-item-0-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-0-menuItem0' + const menuOptionButton = ( + await waitForElement(component, '#user-item-0-menu-Dropdown-Content') ) + .find('li') + .hostNodes() + .at(0) expect(menuOptionButton.hostNodes()).toHaveLength(1) }) it('clicking on menu options takes to user review page', async () => { const toggleButtonElement = await waitForElement( component, - '#user-item-0-menuToggleButton' + '#user-item-0-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-0-menuItem0' + const menuOptionButton = ( + await waitForElement(component, '#user-item-0-menu-Dropdown-Content') ) + .find('li') + .hostNodes() + .at(0) menuOptionButton.hostNodes().simulate('click') await flushPromises() expect(history.location.pathname).toMatch(/.user\/(\w)+\/preview\/*/) @@ -394,15 +398,18 @@ describe('User list tests', () => { }) const toggleButtonElement = await waitForElement( component, - '#user-item-2-menuToggleButton' + '#user-item-2-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-2-menuItem3' + const menuOptionButton = ( + await waitForElement(component, '#user-item-2-menu-Dropdown-Content') ) - expect(menuOptionButton.hostNodes().text()).toBe('Resend invite') + .find('li') + .hostNodes() + .at(3) + + expect(menuOptionButton.hostNodes().text().trim()).toBe('Resend invite') menuOptionButton.hostNodes().simulate('click') await flushPromises() component.update() @@ -415,15 +422,17 @@ describe('User list tests', () => { ) const toggleButtonElement = await waitForElement( component, - '#user-item-2-menuToggleButton' + '#user-item-2-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-2-menuItem3' + const menuOptionButton = ( + await waitForElement(component, '#user-item-2-menu-Dropdown-Content') ) - expect(menuOptionButton.hostNodes().text()).toBe('Resend invite') + .find('li') + .hostNodes() + .at(3) + expect(menuOptionButton.hostNodes().text().trim()).toBe('Resend invite') menuOptionButton.hostNodes().simulate('click') await flushPromises() component.update() @@ -433,15 +442,17 @@ describe('User list tests', () => { it('clicking on menu options deactivate to user pops up audit action modal', async () => { const toggleButtonElement = await waitForElement( component, - '#user-item-1-menuToggleButton' + '#user-item-1-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-1-menuItem3' + const menuOptionButton = ( + await waitForElement(component, '#user-item-1-menu-Dropdown-Content') ) - expect(menuOptionButton.hostNodes().text()).toBe('Deactivate') + .find('li') + .hostNodes() + .at(3) + expect(menuOptionButton.hostNodes().text().trim()).toBe('Deactivate') menuOptionButton.first().simulate('click') component.update() expect(component.exists('#user-audit-modal')).toBeTruthy() @@ -450,16 +461,18 @@ describe('User list tests', () => { it('clicking on menu options Send username reminder pop up confirmation modal', async () => { const toggleButtonElement = await waitForElement( component, - '#user-item-1-menuToggleButton' + '#user-item-1-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-1-menuItem1' + const menuOptionButton = ( + await waitForElement(component, '#user-item-1-menu-Dropdown-Content') ) + .find('li') + .hostNodes() + .at(1) - expect(menuOptionButton.hostNodes().text()).toBe( + expect(menuOptionButton.hostNodes().text().trim()).toBe( 'Send username reminder' ) menuOptionButton.hostNodes().simulate('click') @@ -474,15 +487,17 @@ describe('User list tests', () => { }) const toggleButtonElement = await waitForElement( component, - '#user-item-1-menuToggleButton' + '#user-item-1-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-1-menuItem1' + const menuOptionButton = ( + await waitForElement(component, '#user-item-1-menu-Dropdown-Content') ) - expect(menuOptionButton.hostNodes().text()).toBe( + .find('li') + .hostNodes() + .at(1) + expect(menuOptionButton.hostNodes().text().trim()).toBe( 'Send username reminder' ) menuOptionButton.hostNodes().simulate('click') @@ -503,15 +518,17 @@ describe('User list tests', () => { ) const toggleButtonElement = await waitForElement( component, - '#user-item-1-menuToggleButton' + '#user-item-1-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-1-menuItem1' + const menuOptionButton = ( + await waitForElement(component, '#user-item-1-menu-Dropdown-Content') ) - expect(menuOptionButton.hostNodes().text()).toBe( + .find('li') + .hostNodes() + .at(1) + expect(menuOptionButton.hostNodes().text().trim()).toBe( 'Send username reminder' ) menuOptionButton.hostNodes().simulate('click') @@ -529,15 +546,17 @@ describe('User list tests', () => { it('clicking on menu options reactivate to user pops up audit action modal', async () => { const toggleButtonElement = await waitForElement( component, - '#user-item-3-menuToggleButton' + '#user-item-3-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-3-menuItem1' + const menuOptionButton = ( + await waitForElement(component, '#user-item-3-menu-Dropdown-Content') ) - expect(menuOptionButton.hostNodes().text()).toBe('Reactivate') + .find('li') + .hostNodes() + .at(1) + expect(menuOptionButton.hostNodes().text().trim()).toBe('Reactivate') menuOptionButton.first().simulate('click') component.update() expect(component.exists('#user-audit-modal')).toBeTruthy() @@ -546,15 +565,19 @@ describe('User list tests', () => { it('clicking on menu options Reset Password pop up confirmation modal', async () => { const toggleButtonElement = await waitForElement( component, - '#user-item-1-menuToggleButton' + '#user-item-1-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-1-menuItem2' + const menuOptionButton = ( + await waitForElement(component, '#user-item-1-menu-Dropdown-Content') + ) + .find('li') + .hostNodes() + .at(2) + expect(menuOptionButton.hostNodes().text().trim()).toBe( + 'Reset Password' ) - expect(menuOptionButton.hostNodes().text()).toBe('Reset Password') menuOptionButton.hostNodes().simulate('click') await flushPromises() component.update() @@ -567,16 +590,20 @@ describe('User list tests', () => { }) const toggleButtonElement = await waitForElement( component, - '#user-item-1-menuToggleButton' + '#user-item-1-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-1-menuItem2' + const menuOptionButton = ( + await waitForElement(component, '#user-item-1-menu-Dropdown-Content') ) + .find('li') + .hostNodes() + .at(2) - expect(menuOptionButton.hostNodes().text()).toBe('Reset Password') + expect(menuOptionButton.hostNodes().text().trim()).toBe( + 'Reset Password' + ) menuOptionButton.hostNodes().simulate('click') component.update() expect(component.exists('#user-reset-password-modal')).toBeTruthy() @@ -595,15 +622,19 @@ describe('User list tests', () => { ) const toggleButtonElement = await waitForElement( component, - '#user-item-1-menuToggleButton' + '#user-item-1-menu-dropdownMenu' ) toggleButtonElement.hostNodes().first().simulate('click') - const menuOptionButton = await waitForElement( - component, - '#user-item-1-menuItem2' + const menuOptionButton = ( + await waitForElement(component, '#user-item-1-menu-Dropdown-Content') + ) + .find('li') + .hostNodes() + .at(2) + expect(menuOptionButton.hostNodes().text().trim()).toBe( + 'Reset Password' ) - expect(menuOptionButton.hostNodes().text()).toBe('Reset Password') menuOptionButton.hostNodes().simulate('click') component.update() expect(component.exists('#user-reset-password-modal')).toBeTruthy() From 2ad338cb411e0bd69e7eba40f5d8e29126055aef Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 18:13:38 +0600 Subject: [PATCH 83/88] fix: ids in UserAudit.test --- .../client/src/views/UserAudit/UserAudit.test.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/client/src/views/UserAudit/UserAudit.test.tsx b/packages/client/src/views/UserAudit/UserAudit.test.tsx index 03fd1fd791e..ede3e4c2872 100644 --- a/packages/client/src/views/UserAudit/UserAudit.test.tsx +++ b/packages/client/src/views/UserAudit/UserAudit.test.tsx @@ -169,13 +169,18 @@ describe('User audit list tests for sys admin', () => { const menuLink = await waitForElement( component, - '#sub-page-header-munu-buttonToggleButton' + '#sub-page-header-munu-button-dropdownMenu' ) menuLink.hostNodes().simulate('click') - const editUserLink = await waitForElement( - component, - '#sub-page-header-munu-buttonItem0' + const editUserLink = ( + await waitForElement( + component, + '#sub-page-header-munu-button-Dropdown-Content' + ) ) + .find('li') + .hostNodes() + .at(0) editUserLink.hostNodes().simulate('click') // wait for mocked data to load mockedProvider From 07c6d121fbadb88c442442bd05f6ffbe690c0833 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 18:15:15 +0600 Subject: [PATCH 84/88] fix: import Event --- .../inExternalValidation/inExternalValidationTab.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client/src/views/OfficeHome/inExternalValidation/inExternalValidationTab.test.tsx b/packages/client/src/views/OfficeHome/inExternalValidation/inExternalValidationTab.test.tsx index 3f3799070d7..39dbe0bb5f3 100644 --- a/packages/client/src/views/OfficeHome/inExternalValidation/inExternalValidationTab.test.tsx +++ b/packages/client/src/views/OfficeHome/inExternalValidation/inExternalValidationTab.test.tsx @@ -25,6 +25,7 @@ import { waitForElement } from '@client/tests/wait-for-element' import { Workqueue } from '@opencrvs/components/lib/Workqueue' import { History } from 'history' import { vi, Mock } from 'vitest' +import { Event } from '@client/utils/gateway' const EVENT_CREATION_TIME = 1583322631424 // Wed Mar 04 2020 13:50:31 GMT+0200 (Eastern European Standard Time) const SEND_FOR_VALIDATION_TIME = 1582912800000 // Fri Feb 28 2020 20:00:00 GMT+0200 (Eastern European Standard Time) From fa209e9b376d446fa6f84dedaeb47dde4ee6087c Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 18:20:18 +0600 Subject: [PATCH 85/88] fix: remove unassign test from download button --- .../interface/DownloadButton.test.tsx | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/packages/client/src/components/interface/DownloadButton.test.tsx b/packages/client/src/components/interface/DownloadButton.test.tsx index 176c337ea3d..61f39cf5529 100644 --- a/packages/client/src/components/interface/DownloadButton.test.tsx +++ b/packages/client/src/components/interface/DownloadButton.test.tsx @@ -16,36 +16,15 @@ import * as React from 'react' import { DownloadAction } from '@client/forms' import { ReactWrapper } from 'enzyme' import * as declarationReducer from '@client/declarations' -import { vi, SpyInstance } from 'vitest' import { ApolloClient } from '@apollo/client' import { createClient } from '@client/utils/apolloClient' const { DOWNLOAD_STATUS } = declarationReducer -function getAssignmentModal( - testComponent: ReactWrapper<{}, {}> -): ReactWrapper<{}, {}> { - const button = testComponent.find('button') - button.simulate('click') - testComponent.update() - return testComponent.find('#assignment').hostNodes() -} - -function clickOnModalAction( - testComponent: ReactWrapper<{}, {}>, - selector: string -) { - const modal = getAssignmentModal(testComponent) - const action = modal.find(selector).hostNodes() - action.simulate('click') - testComponent.update() -} - describe('download button tests', () => { let store: AppStore let history: History let testComponent: ReactWrapper<{}, {}> - let unassignSpy: SpyInstance let client: ApolloClient<{}> describe('for download status downloaded', () => { @@ -73,15 +52,9 @@ describe('download button tests', () => { it('download button renders', () => { expect(testComponent).toBeDefined() }) - - it('clicking download button pops up unassign modal', () => { - const modal = getAssignmentModal(testComponent) - expect(modal.text()).toContain('Unassign record?') - }) }) describe('when assignment object is defined in props', () => { beforeEach(async () => { - unassignSpy = vi.spyOn(declarationReducer, 'unassignDeclaration') const testStore = await createTestStore() store = testStore.store history = testStore.history @@ -110,16 +83,6 @@ describe('download button tests', () => { it('download button renders', () => { expect(testComponent).toBeDefined() }) - - it('clicking download button pops up unassign modal', () => { - const modal = getAssignmentModal(testComponent) - expect(modal.text()).toContain('Unassign record?') - }) - - it('clicking on unassign button triggers unassignDeclaration action', () => { - clickOnModalAction(testComponent, '#unassign') - expect(unassignSpy).toBeCalled() - }) }) }) }) From 1769f0e78d4099f9ebf754360d7187443d090119 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 18:22:46 +0600 Subject: [PATCH 86/88] fix: ids in ProfileMenu.test --- .../src/components/ProfileMenu.test.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/client/src/components/ProfileMenu.test.tsx b/packages/client/src/components/ProfileMenu.test.tsx index 1ead825260d..f99af6da039 100644 --- a/packages/client/src/components/ProfileMenu.test.tsx +++ b/packages/client/src/components/ProfileMenu.test.tsx @@ -27,9 +27,11 @@ describe('when user opens profile menu without user details', () => { }) it('open menu', () => { - component.find('#ProfileMenuToggleButton').hostNodes().simulate('click') + component.find('#ProfileMenu-dropdownMenu').hostNodes().simulate('click') - expect(component.find('#ProfileMenuSubMenu').hostNodes()).toHaveLength(1) + expect( + component.find('#ProfileMenu-Dropdown-Content').hostNodes() + ).toHaveLength(1) }) }) @@ -53,27 +55,31 @@ describe('when user opens profile menu with user details', () => { }) it('open menu', () => { - component.find('#ProfileMenuToggleButton').hostNodes().simulate('click') + component.find('#ProfileMenu-dropdownMenu').hostNodes().simulate('click') - expect(component.find('#ProfileMenuSubMenu').hostNodes()).toHaveLength(1) + expect( + component.find('#ProfileMenu-Dropdown-Content').hostNodes() + ).toHaveLength(1) }) it('handle clicks', () => { - component.find('#ProfileMenuToggleButton').hostNodes().simulate('click') + component.find('#ProfileMenu-dropdownMenu').hostNodes().simulate('click') // Settings click component - .find('#ProfileMenuSubMenu') + .find('#ProfileMenu-Dropdown-Content') .hostNodes() .childAt(1) .simulate('click') component - .find('#ProfileMenuSubMenu') + .find('#ProfileMenu-Dropdown-Content') .hostNodes() .childAt(2) .simulate('click') - expect(component.find('#ProfileMenuSubMenu').hostNodes()).toHaveLength(1) + expect( + component.find('#ProfileMenu-Dropdown-Content').hostNodes() + ).toHaveLength(1) }) }) From feaf386f162db5f8fc139e0222f2836eb2b80e70 Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 18:34:05 +0600 Subject: [PATCH 87/88] fix: import Event --- .../src/views/SysAdmin/Performance/WorkflowStatus.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client/src/views/SysAdmin/Performance/WorkflowStatus.test.tsx b/packages/client/src/views/SysAdmin/Performance/WorkflowStatus.test.tsx index 406584d8e3e..c9f746fa265 100644 --- a/packages/client/src/views/SysAdmin/Performance/WorkflowStatus.test.tsx +++ b/packages/client/src/views/SysAdmin/Performance/WorkflowStatus.test.tsx @@ -23,6 +23,7 @@ import { FETCH_EVENTS_WITH_PROGRESS } from './queries' import { GraphQLError } from 'graphql' import { match } from 'react-router' import { vi } from 'vitest' +import { Event } from '@client/utils/gateway' describe('Workflow status tests', () => { let store: AppStore From dff7eb05b04953637beaac0737818abc552a4f0c Mon Sep 17 00:00:00 2001 From: jamil314 Date: Thu, 17 Oct 2024 18:51:29 +0600 Subject: [PATCH 88/88] fix: import Event --- .../src/views/AdvancedSearch/AdvancedSearchResult.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client/src/views/AdvancedSearch/AdvancedSearchResult.test.tsx b/packages/client/src/views/AdvancedSearch/AdvancedSearchResult.test.tsx index 65db53f17dc..352b644ffd6 100644 --- a/packages/client/src/views/AdvancedSearch/AdvancedSearchResult.test.tsx +++ b/packages/client/src/views/AdvancedSearch/AdvancedSearchResult.test.tsx @@ -31,6 +31,7 @@ import { REMOVE_ADVANCED_SEARCH_RESULT_BOOKMARK_MUTATION } from '@client/profile/mutations' import { getStorageUserDetailsSuccess } from '@client/profile/profileActions' +import { Event } from '@client/utils/gateway' const graphqlMock = [ {