diff --git a/package.json b/package.json index ae5e5faf..966adb1d 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,7 @@ "exports": { ".": null, "./components": "./dist/components/index.js", + "./uberComponents": "./dist/uberComponents/index.js", "./containers": "./dist/containers/index.js", "./services": "./dist/services/index.js", "./hooks": "./dist/hooks/index.js", diff --git a/src/components/BaseLayout/BaseLayout.module.scss b/src/components/BaseLayout/BaseLayout.module.scss deleted file mode 100644 index f566b4a6..00000000 --- a/src/components/BaseLayout/BaseLayout.module.scss +++ /dev/null @@ -1,35 +0,0 @@ -.content { - background: 0; - position: relative; - padding-bottom: 64px; -} - -.pageHeader { - flex: 1; - display: flex; - flex-direction: column; - padding: 24px 20px; - - @media screen and (min-width: 1281px) { - max-width: 1120px; - } -} - -.pageContentWrapper { - @media screen and (min-width: 1281px) { - display: flex; - justify-content: center; - } -} - -.pageContent { - flex: 1; - display: flex; - flex-direction: column; - padding: 40px 20px; - gap: 40px; - - @media screen and (min-width: 1281px) { - max-width: 1120px; - } -} diff --git a/src/components/BaseLayout/BaseLayout.styles.ts b/src/components/BaseLayout/BaseLayout.styles.ts index 5b9101f5..dc004dfe 100644 --- a/src/components/BaseLayout/BaseLayout.styles.ts +++ b/src/components/BaseLayout/BaseLayout.styles.ts @@ -1,5 +1,26 @@ import { Layout } from 'antd'; -import styled from 'styled-components'; +import { isNumber, isString } from 'lodash'; +import styled, { css } from 'styled-components'; + +const maxWidthStyles = css<{ $maxWidth?: number | string }>` + ${({ $maxWidth }) => { + if (isNumber($maxWidth)) { + return css` + max-width: ${() => `${$maxWidth}px`}; + `; + } + + if (isString($maxWidth)) { + return css` + max-width: ${() => `${$maxWidth}`}; + `; + } + + return css` + max-width: 1080px; + `; + }} +`; export const S = { Container: styled(Layout)` @@ -10,9 +31,42 @@ export const S = { padding-top: 50px; } `, - PageWrapper: styled.div` - background-color: ${({ theme }) => theme.primaryPalette.bcp_1}; + Layout: styled(Layout)` + background: 0; + position: relative; + padding-bottom: 64px; + `, + PageHeaderContainer: styled.div` + background-color: ${({ theme }) => theme.neutralPalette.gray_1}; display: flex; - justify-content: center; + flex-direction: column; + align-items: center; + padding: 0 24px; + `, + PageHeader: styled.div<{ $maxWidth?: number | string }>` + flex: 1; + display: flex; + flex-direction: column; + padding: 24px 0; + gap: 32px 0; + width: 100%; + + ${maxWidthStyles} + `, + PageContentContainer: styled.div` + padding: 0 24px; + display: flex; + flex-direction: column; + align-items: center; + `, + PageContent: styled.div<{ $maxWidth?: number | string }>` + flex: 1; + display: flex; + flex-direction: column; + padding: 32px 0; + gap: 24px 0; + width: 100%; + + ${maxWidthStyles} `, }; diff --git a/src/components/BaseLayout/Footer/index.tsx b/src/components/BaseLayout/Footer/index.tsx index 43bc610d..99ab8418 100644 --- a/src/components/BaseLayout/Footer/index.tsx +++ b/src/components/BaseLayout/Footer/index.tsx @@ -10,10 +10,7 @@ export function AppFooter(props: Props) { return ( - Made with ❤️ by{' '} - - Beda Software - + Testing - Ferrer Pulmonary ); diff --git a/src/components/BaseLayout/PageContainer/PageContainer.stories.tsx b/src/components/BaseLayout/PageContainer/PageContainer.stories.tsx new file mode 100644 index 00000000..4a43d292 --- /dev/null +++ b/src/components/BaseLayout/PageContainer/PageContainer.stories.tsx @@ -0,0 +1,172 @@ +import { CalendarOutlined, MailOutlined, PhoneOutlined, PlusOutlined } from '@ant-design/icons'; +import { Meta, StoryObj } from '@storybook/react'; +import { Button, Input } from 'antd'; +import styled from 'styled-components'; + +import { Table } from 'src/components/Table'; +import { Tabs } from 'src/components/Tabs'; +import { Text } from 'src/components/Typography'; +import { withColorSchemeDecorator } from 'src/storybook/decorators'; + +import { PageContainer, PageContainerProps } from './index'; + +const content = ( + <> + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. In suscipit magna sed pretium maximus. Duis + bibendum a lacus ut commodo. Nam eget justo tristique, tincidunt ligula vel, accumsan odio. Morbi purus + ante, bibendum vitae arcu eget, ultrices faucibus dolor. Sed fermentum blandit malesuada. Duis fringilla ac + tortor ut convallis. Fusce iaculis arcu dui. Ut non neque rhoncus, tincidunt ipsum in, lobortis magna. Donec + aliquet leo tellus. Proin pulvinar lacus sodales tortor eleifend rhoncus. Praesent varius maximus pulvinar. + + +); + +const table = ( + '-', + }, + { + title: 'Practitioner', + dataIndex: 'practitioner', + key: 'practitioner', + width: '50%', + render: () => '-', + }, + ]} + /> +); + +const tabs = ( + +); + +const S = { + Container: styled.div` + background-color: ${({ theme }) => theme.neutralPalette.gray_2}; + `, + CustomRightColumn: styled.div` + display: flex; + align-items: center; + gap: 0 16px; + `, + Item: styled.div` + display: flex; + align-items: center; + gap: 0 4px; + color: ${({ theme }) => theme.neutral.secondaryText}; + `, +}; + +const rightColumn1 = ( + + + + 05/12/1955 • 66 y.o. + + + + +972-222-3333 + + + + cooper@gmail.com + + +); + +const rightColumn2 = ( + <> + + + +); + +const meta: Meta = { + title: 'Layout / PageContainer', + component: PageContainer, + // @ts-ignore + decorators: [withColorSchemeDecorator], + args: { + title: 'Patients', + children: content, + }, + render: (args) => { + return ( + + + + ); + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + title: 'Madison Cooper', + headerRightColumn: rightColumn1, + }, +}; + +export const WithTable: Story = { + args: { + variant: 'with-table', + children: table, + headerRightColumn: rightColumn2, + }, +}; + +export const WithTabs: Story = { + args: { + variant: 'with-tabs', + header: { + children: tabs, + }, + }, +}; + +export const FullWidth: Story = { + args: { + maxWidth: '100%', + }, +}; + +export const CustomWidth: Story = { + args: { + maxWidth: 500, + }, +}; diff --git a/src/components/BaseLayout/PageContainer/index.tsx b/src/components/BaseLayout/PageContainer/index.tsx new file mode 100644 index 00000000..739701b2 --- /dev/null +++ b/src/components/BaseLayout/PageContainer/index.tsx @@ -0,0 +1,52 @@ +import { S } from './styles'; +import { BasePageContentProps, BasePageHeaderProps } from '..'; + +export interface PageContainerProps { + variant?: 'default' | 'with-table' | 'with-tabs'; + maxWidth?: number | string; + title?: React.ReactNode; + headerLeftColumn?: React.ReactNode; + headerRightColumn?: React.ReactNode; + children?: React.ReactNode; + + header?: BasePageHeaderProps; + content?: BasePageContentProps; +} + +export function PageContainer(props: PageContainerProps = {}) { + const { + variant = 'default', + title, + header, + content, + children, + maxWidth, + headerLeftColumn, + headerRightColumn, + } = props; + + return ( + <> + + + + {headerLeftColumn ? ( + headerLeftColumn + ) : ( + <>{title && {title}} + )} + + {headerRightColumn && {headerRightColumn}} + + {header?.children} + + + {content?.children ?? children} + + + ); +} + +export function PageContainerTitle(props: React.HTMLAttributes) { + return ; +} diff --git a/src/components/BaseLayout/PageContainer/styles.ts b/src/components/BaseLayout/PageContainer/styles.ts new file mode 100644 index 00000000..b942f4cb --- /dev/null +++ b/src/components/BaseLayout/PageContainer/styles.ts @@ -0,0 +1,57 @@ +import styled, { css } from 'styled-components'; + +import { BasePageContent, BasePageHeader } from '..'; +import { Title } from 'src/components/Typography'; +import { mobileWidth } from 'src/theme/utils'; + +export const S = { + HeaderContainer: styled(BasePageHeader)<{ $variant?: 'default' | 'with-table' | 'with-tabs' }>` + display: flex; + flex-direction: column; + + ${({ $variant }) => + $variant === 'with-table' && + css` + padding-bottom: 79px; + `} + + ${({ $variant }) => + $variant === 'with-tabs' && + css` + padding-bottom: 0; + `} + `, + Header: styled.div` + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 16px 40px; + position: relative; + + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + padding-right: 48px; + } + `, + Title: styled(Title)` + margin-bottom: 0 !important; + `, + HeaderLeftColumn: styled.div` + display: flex; + align-items: center; + gap: 0 8px; + `, + HeaderRightColumn: styled.div` + display: flex; + align-items: center; + gap: 0 40px; + `, + ContentContainer: styled(BasePageContent)<{ $variant?: 'default' | 'with-table' | 'with-tabs' }>` + ${({ $variant }) => + $variant === 'with-table' && + css` + padding-top: 0; + margin-top: -47px; + `} + `, +}; diff --git a/src/components/BaseLayout/index.tsx b/src/components/BaseLayout/index.tsx index 591222aa..3154f315 100644 --- a/src/components/BaseLayout/index.tsx +++ b/src/components/BaseLayout/index.tsx @@ -1,8 +1,5 @@ -import { Layout } from 'antd'; -import classNames from 'classnames'; import { ReactNode } from 'react'; -import s from './BaseLayout.module.scss'; import { S } from './BaseLayout.styles'; import { AppFooter } from './Footer'; import { AppSidebar } from './Sidebar'; @@ -11,49 +8,58 @@ import { AppTabBar } from './TabBar'; interface Props { children: ReactNode; style?: React.CSSProperties; + className?: string | undefined; } -export function BaseLayout({ children, style }: Props) { +export function BaseLayout({ children, style, className }: Props) { return ( - + - + {children} - + ); } -export function AnonymousLayout({ children, style }: Props) { +export function AnonymousLayout({ children, style, className }: Props) { return ( - + - + {children} - + ); } -export function BasePageHeader(props: React.HTMLAttributes) { - const { className, ...rest } = props; +export type BasePageHeaderProps = React.HTMLAttributes & { + maxWidth?: number | string; +}; + +export function BasePageHeader(props: BasePageHeaderProps) { + const { maxWidth, ...rest } = props; return ( - -
- + + + ); } -export function BasePageContent(props: React.HTMLAttributes) { - const { className, ...rest } = props; +export type BasePageContentProps = React.HTMLAttributes & { + maxWidth?: number | string; +}; + +export function BasePageContent(props: BasePageContentProps) { + const { maxWidth, ...rest } = props; return ( -
-
-
+ + + ); } diff --git a/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/context.tsx b/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/context.tsx deleted file mode 100644 index aee79923..00000000 --- a/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/context.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { RealmPlugin } from '@mdxeditor/editor'; -import React, { createContext } from 'react'; -import { ItemContext } from 'sdc-qrf'; - -export type MarkDownEditorContextProps = { - MarkdownEditorWrapper?: React.ComponentType; - initPlugins?: (context?: ItemContext) => RealmPlugin[]; - initToolbarPlugins?: (context?: ItemContext) => React.ReactNode[]; -}; - -export const MarkDownEditorContext = createContext({}); diff --git a/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/index.tsx b/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/index.tsx index c464c8e0..d22fe5e1 100644 --- a/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/index.tsx +++ b/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/index.tsx @@ -1,35 +1,29 @@ import { - BoldItalicUnderlineToggles, CodeToggle, - headingsPlugin, - linkPlugin, - listsPlugin, ListsToggle, markdownShortcutPlugin, MDXEditor, - MDXEditorMethods, + headingsPlugin, + listsPlugin, quotePlugin, + linkPlugin, toolbarPlugin, UndoRedo, + BoldItalicUnderlineToggles, + MDXEditorMethods, } from '@mdxeditor/editor'; -import { Fragment, useContext, useEffect, useMemo, useRef } from 'react'; +import { useEffect, useRef } from 'react'; import { useTheme } from 'styled-components'; import '@mdxeditor/editor/style.css'; -import { Divider } from 'antd'; -import { MarkDownEditorContext } from './context'; -import { S } from './styles'; -import { ItemContext } from 'sdc-qrf'; interface MarkDownEditorProps { markdownString: string; onChange?: (markdown: string) => void; readOnly?: boolean; - context?: ItemContext; } -export function MarkDownEditor(props: MarkDownEditorProps) { - const { markdownString = '', readOnly = false, onChange, context } = props; +export function MarkDownEditor({ markdownString = '', readOnly = false, onChange }: MarkDownEditorProps) { const mdxEditorRef = useRef(null); useEffect(() => { @@ -40,59 +34,48 @@ export function MarkDownEditor(props: MarkDownEditorProps) { const theme = useTheme(); - const pluginsContext = useContext(MarkDownEditorContext); - // TODO Add a button to add link and make a custom modal to enter the link // https://mdxeditor.dev/editor/api/functions/linkDialogPlugin - const plugins = useMemo(() => { - const commonPlugins = pluginsContext.initPlugins - ? pluginsContext.initPlugins(context) - : [headingsPlugin(), listsPlugin(), quotePlugin(), linkPlugin(), markdownShortcutPlugin()]; - - const toolbarPlugins = pluginsContext.initToolbarPlugins - ? pluginsContext.initToolbarPlugins(context) - : [ - , - , - , - , - , - , - ]; + const plugins = [ + headingsPlugin(), + listsPlugin(), + quotePlugin(), + linkPlugin(), + markdownShortcutPlugin(), + ]; - const plugins = readOnly - ? commonPlugins - : [ - ...commonPlugins, - toolbarPlugin({ - toolbarContents: () => { - return ( -
- {toolbarPlugins.map((Plugin, index) => ( - {Plugin} - ))} -
- ); - }, - }), - ]; - - return plugins; - }, [pluginsContext.initPlugins, pluginsContext.initToolbarPlugins, readOnly, context]); - - const MDXEditorWrapper = pluginsContext.MarkdownEditorWrapper || S.MDXEditorWrapper; + if (!readOnly) { + plugins.push( + toolbarPlugin({ + toolbarContents: () => { + return ( +
+ + + + + + +
+ ); + }, + }), + ); + } return ( - - - + ); } + +function Separator() { + return
; +} diff --git a/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/styles.ts b/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/styles.ts deleted file mode 100644 index a4026f40..00000000 --- a/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/MarkDownEditor/styles.ts +++ /dev/null @@ -1,30 +0,0 @@ -import styled from 'styled-components'; - -export const S = { - MDXEditorWrapper: styled.div` - transition: all 0.2s; - - .mdxeditor { - border: 1px solid ${({ theme }) => theme.neutralPalette.gray_5}; - border-radius: 8px; - } - - .mdxeditor:hover { - border-color: ${({ theme }) => theme.primary}cc; - } - - .mdxeditor:focus-within { - border-color: ${({ theme }) => theme.primary}; - box-shadow: 0 0 0 2px ${({ theme }) => theme.primary}0d; - } - - .mdxeditor-toolbar { - z-index: 0; - position: unset; - } - - .mdxeditor-popup-container { - z-index: 1000; - } - `, -}; diff --git a/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/index.tsx b/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/index.tsx index 24265302..aa9ba6e6 100644 --- a/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/index.tsx +++ b/src/components/BaseQuestionnaireResponseForm/widgets/MDEditorControl/index.tsx @@ -3,21 +3,11 @@ import { QuestionItemProps } from 'sdc-qrf'; import { useFieldController } from 'src/components/BaseQuestionnaireResponseForm/hooks'; import { MarkDownEditor } from './MarkDownEditor'; -import { Form } from 'antd'; -export function MDEditorControl({ parentPath, questionItem, context }: QuestionItemProps) { +export function MDEditorControl({ parentPath, questionItem }: QuestionItemProps) { const { linkId } = questionItem; const fieldName = [...parentPath, linkId, 0, 'value', 'string']; - const { value, onChange, formItem } = useFieldController(fieldName, questionItem); + const { value, onChange } = useFieldController(fieldName, questionItem); - return ( - - - - ); + return ; } diff --git a/src/components/DashboardCard/DashboardCard.styles.ts b/src/components/DashboardCard/DashboardCard.styles.ts index 424b44a2..e77f6f09 100644 --- a/src/components/DashboardCard/DashboardCard.styles.ts +++ b/src/components/DashboardCard/DashboardCard.styles.ts @@ -6,7 +6,7 @@ export const S = { `, Card: styled.div` border-radius: 10px; - background-color: ${({ theme }) => theme.neutralPalette.gray_2}; + background-color: ${({ theme }) => theme.neutralPalette.gray_1}; color: ${({ theme }) => theme.neutralPalette.gray_13}; border: 1px solid ${({ theme }) => theme.antdTheme?.colorBorderSecondary}; min-width: fit-content; diff --git a/src/components/PageContainer/index.tsx b/src/components/PageContainer/index.tsx deleted file mode 100644 index b5c7f03a..00000000 --- a/src/components/PageContainer/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Col, Row } from 'antd'; - -import { BasePageHeader, BasePageContent } from '../BaseLayout'; -import { Title } from '../Typography'; - -interface PageContainerProps { - title: string; - titleRightContent?: React.ReactElement; - headerContent?: React.ReactElement; - content?: React.ReactElement; -} - -export function PageContainer(props: PageContainerProps) { - const { title, titleRightContent, headerContent, content } = props; - return ( - <> - - -
- {title} - - {titleRightContent} - - {headerContent} - - {content} - - ); -} diff --git a/src/components/PatientEncounter/index.tsx b/src/components/PatientEncounter/index.tsx index c8c6a412..3b368111 100644 --- a/src/components/PatientEncounter/index.tsx +++ b/src/components/PatientEncounter/index.tsx @@ -1,4 +1,4 @@ -import { t, Trans } from '@lingui/macro'; +import { Trans } from '@lingui/macro'; import { Col, Row } from 'antd'; import { ColumnsType } from 'antd/lib/table'; import { Patient } from 'fhir/r4b'; @@ -11,7 +11,6 @@ import { EncounterData } from 'src/components/EncountersTable/types'; import { StatusBadge } from 'src/components/EncounterStatusBadge'; import { ModalNewEncounter } from 'src/components/ModalNewEncounter'; import { useEncounterList } from 'src/containers/EncounterList/hooks'; -import { usePatientHeaderLocationTitle } from 'src/containers/PatientDetails/PatientHeader/hooks'; import { formatPeriodDateTime } from 'src/utils/date'; import { renderHumanName } from 'src/utils/fhir'; @@ -76,8 +75,6 @@ export const PatientEncounter = ({ patient, searchParams, hideCreateButton }: Pr ...searchParams, }); - usePatientHeaderLocationTitle({ title: t`Encounters` }); - return ( <> {hideCreateButton ? null : ( diff --git a/src/components/QuestionnaireResponseForm/index.tsx b/src/components/QuestionnaireResponseForm/index.tsx index 0aa4f39e..b2f30f04 100644 --- a/src/components/QuestionnaireResponseForm/index.tsx +++ b/src/components/QuestionnaireResponseForm/index.tsx @@ -25,7 +25,7 @@ import { saveFHIRResource, updateFHIRResource } from 'src/services/fhir'; import { FormFooterComponentProps } from '../BaseQuestionnaireResponseForm/FormFooter'; import { Spinner } from '../Spinner'; -interface Props extends QuestionnaireResponseFormProps { +export interface QRFProps extends QuestionnaireResponseFormProps { onSuccess?: (response: QuestionnaireResponseFormSaveResponse) => void; onFailure?: (error: any) => void; readOnly?: boolean; @@ -126,7 +126,7 @@ export function onFormResponse(props: { } } -export function useQuestionnaireResponseForm(props: Props) { +export function useQuestionnaireResponseForm(props: QRFProps) { // TODO find what cause rerender and fix it // remove this temporary hack const memoizedProps = useMemo(() => props, [JSON.stringify(props)]); @@ -152,7 +152,7 @@ export function useQuestionnaireResponseForm(props: Props) { return { response, onSubmit, readOnly, onCancel }; } -export function QuestionnaireResponseForm(props: Props) { +export function QuestionnaireResponseForm(props: QRFProps) { const { response, onSubmit, readOnly, onCancel } = useQuestionnaireResponseForm(props); return ( diff --git a/src/components/ResourceTable/index.tsx b/src/components/ResourceTable/index.tsx index a5aa4130..f349d171 100644 --- a/src/components/ResourceTable/index.tsx +++ b/src/components/ResourceTable/index.tsx @@ -33,7 +33,7 @@ interface ResourceTableProps extends ResourceTableHookProps< export function useResourceTable(props: ResourceTableHookProps) { const { resourceType, params = {} } = props; const queryParameters = { - _sort: ['-_lastUpdated', '_id'], + _sort: '-_lastUpdated', ...params, }; diff --git a/src/components/SearchBar/SearchBar.styles.ts b/src/components/SearchBar/SearchBar.styles.ts deleted file mode 100644 index 119c53ef..00000000 --- a/src/components/SearchBar/SearchBar.styles.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Layout } from 'antd'; -import styled from 'styled-components'; - -export const S = { - Container: styled(Layout)` - position: relative; - padding: 16px; - border-radius: 10px; - background-color: ${({ theme }) => theme.primaryPalette.bcp_3}; - display: flex; - flex-direction: row; - justify-content: space-between; - gap: 16px 32px; - flex-wrap: wrap; - - .ant-input-search, - .ant-picker { - width: 264px; - } - `, -}; diff --git a/src/components/SearchBar/SearchBarColumn/ChoiceColumn/SelectChoiceColumn/index.tsx b/src/components/SearchBar/SearchBarColumn/ChoiceColumn/SelectChoiceColumn/index.tsx index 6fb9b945..39e0fa52 100644 --- a/src/components/SearchBar/SearchBarColumn/ChoiceColumn/SelectChoiceColumn/index.tsx +++ b/src/components/SearchBar/SearchBarColumn/ChoiceColumn/SelectChoiceColumn/index.tsx @@ -1,5 +1,3 @@ -import { Col } from 'antd'; - import { Select } from 'src/components/Select'; import { ValueSetOption } from 'src/services'; @@ -7,23 +5,23 @@ import { SearchBarColumnChoiceTypeProps } from '../../types'; import { useChoiceColumn } from '../hooks'; export function SelectChoiceColumn(props: SearchBarColumnChoiceTypeProps) { - const { columnFilterValue } = props; + const { columnFilterValue, defaultOpen } = props; const { options, placeholder, repeats } = columnFilterValue.column; const { onSelect, getOptionLabel, isOptionSelected } = useChoiceColumn(props); return ( - - - value={columnFilterValue.value} - options={options} - onChange={onSelect} - isOptionSelected={isOptionSelected} - isMulti={repeats} - getOptionLabel={getOptionLabel} - classNamePrefix="react-select" - placeholder={placeholder} - /> - + + value={columnFilterValue.value} + options={options} + onChange={onSelect} + isOptionSelected={isOptionSelected} + isMulti={repeats} + getOptionLabel={getOptionLabel} + classNamePrefix="react-select" + placeholder={placeholder} + defaultMenuIsOpen={defaultOpen} + isClearable + /> ); } diff --git a/src/components/SearchBar/SearchBarColumn/ChoiceColumn/ValueSetColumn/index.tsx b/src/components/SearchBar/SearchBarColumn/ChoiceColumn/ValueSetColumn/index.tsx index dfe87d67..b157bd8d 100644 --- a/src/components/SearchBar/SearchBarColumn/ChoiceColumn/ValueSetColumn/index.tsx +++ b/src/components/SearchBar/SearchBarColumn/ChoiceColumn/ValueSetColumn/index.tsx @@ -1,28 +1,26 @@ -import { Col } from 'antd'; - import { AsyncSelect } from 'src/components/Select'; import { SearchBarColumnChoiceTypeProps } from '../../types'; import { useChoiceColumn } from '../hooks'; export function ValueSetColumn(props: SearchBarColumnChoiceTypeProps) { - const { columnFilterValue } = props; + const { columnFilterValue, defaultOpen } = props; const { placeholder, repeats } = columnFilterValue.column; const { onSelect, isOptionSelected, getOptionLabel, debouncedLoadOptions } = useChoiceColumn(props); return ( - - - + ); } diff --git a/src/components/SearchBar/SearchBarColumn/DateColumn/hooks.ts b/src/components/SearchBar/SearchBarColumn/DateColumn/hooks.ts index bd29d41d..78d22e69 100644 --- a/src/components/SearchBar/SearchBarColumn/DateColumn/hooks.ts +++ b/src/components/SearchBar/SearchBarColumn/DateColumn/hooks.ts @@ -15,6 +15,8 @@ export function useDateColumn(props: SearchBarColumnDateTypeProps) { const momentValues = values.map((value) => moment(value!.format())) as DateColumnFilterValue; onChange(momentValues, columnFilterValue.column.id); + } else { + onChange(undefined, columnFilterValue.column.id); } }, [onChange, columnFilterValue], diff --git a/src/components/SearchBar/SearchBarColumn/DateColumn/index.tsx b/src/components/SearchBar/SearchBarColumn/DateColumn/index.tsx index d41283cd..69333087 100644 --- a/src/components/SearchBar/SearchBarColumn/DateColumn/index.tsx +++ b/src/components/SearchBar/SearchBarColumn/DateColumn/index.tsx @@ -1,5 +1,3 @@ -import { Col } from 'antd'; - import { DatePicker } from 'src/components/DatePicker'; import { useDateColumn } from './hooks'; @@ -8,17 +6,17 @@ import { SearchBarColumnDateTypeProps } from '../types'; const { RangePicker } = DatePicker; export function DateColumn(props: SearchBarColumnDateTypeProps) { - const { columnFilterValue } = props; + const { columnFilterValue, defaultOpen } = props; const { onColumnChange } = useDateColumn(props); return ( - - - + ); } diff --git a/src/components/SearchBar/SearchBarColumn/DateSingleColumn/hooks.ts b/src/components/SearchBar/SearchBarColumn/DateSingleColumn/hooks.ts new file mode 100644 index 00000000..ced889fa --- /dev/null +++ b/src/components/SearchBar/SearchBarColumn/DateSingleColumn/hooks.ts @@ -0,0 +1,21 @@ +import moment from 'moment'; +import { useCallback } from 'react'; + +import { SearchBarColumnSingleDateTypeProps } from '../types'; + +export function useDateColumn(props: SearchBarColumnSingleDateTypeProps) { + const { onChange, columnFilterValue } = props; + + const onColumnChange = useCallback( + (value: moment.Moment | null) => { + if (value) { + onChange(value, columnFilterValue.column.id); + } else { + onChange(undefined, columnFilterValue.column.id); + } + }, + [onChange, columnFilterValue], + ); + + return { onColumnChange }; +} diff --git a/src/components/SearchBar/SearchBarColumn/DateSingleColumn/index.tsx b/src/components/SearchBar/SearchBarColumn/DateSingleColumn/index.tsx new file mode 100644 index 00000000..5572fd54 --- /dev/null +++ b/src/components/SearchBar/SearchBarColumn/DateSingleColumn/index.tsx @@ -0,0 +1,21 @@ +import { DatePicker } from 'src/components/DatePicker'; + +import { useDateColumn } from './hooks'; +import { SearchBarColumnSingleDateTypeProps } from '../types'; + +export function DateSingleColumn(props: SearchBarColumnSingleDateTypeProps) { + const { columnFilterValue, defaultOpen } = props; + const { placeholder } = columnFilterValue.column; + const { onColumnChange } = useDateColumn(props); + + return ( + + ); +} diff --git a/src/components/SearchBar/SearchBarColumn/DateSingleColumn/types.ts b/src/components/SearchBar/SearchBarColumn/DateSingleColumn/types.ts new file mode 100644 index 00000000..c2e504b6 --- /dev/null +++ b/src/components/SearchBar/SearchBarColumn/DateSingleColumn/types.ts @@ -0,0 +1,4 @@ +import { RangePickerProps } from 'antd/lib/date-picker/generatePicker'; +import moment from 'moment'; + +export type RangePickerOnChange = Exclude['onChange'], undefined>; diff --git a/src/components/SearchBar/SearchBarColumn/ReferenceColumn/index.tsx b/src/components/SearchBar/SearchBarColumn/ReferenceColumn/index.tsx index 84b05fc6..ad9e856d 100644 --- a/src/components/SearchBar/SearchBarColumn/ReferenceColumn/index.tsx +++ b/src/components/SearchBar/SearchBarColumn/ReferenceColumn/index.tsx @@ -1,5 +1,3 @@ -import { Col } from 'antd'; - import { AsyncSelect } from 'src/components/Select'; import { getAnswerCode, getAnswerDisplay } from 'src/utils/questionnaire'; @@ -7,22 +5,22 @@ import { useReferenceColumn } from './hooks'; import { SearchBarColumnReferenceTypeProps } from '../types'; export function ReferenceColumn(props: SearchBarColumnReferenceTypeProps) { - const { columnFilterValue } = props; + const { columnFilterValue, defaultOpen } = props; const { debouncedLoadOptions, onOptionChange } = useReferenceColumn(props); return ( - - getAnswerDisplay(option.value)} - getOptionValue={(option) => getAnswerCode(option.value)} - isMulti={false} - placeholder={columnFilterValue.column.placeholder} - /> - + getAnswerDisplay(option.value)} + getOptionValue={(option) => getAnswerCode(option.value)} + isMulti={false} + placeholder={columnFilterValue.column.placeholder} + defaultMenuIsOpen={defaultOpen} + isClearable + /> ); } diff --git a/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/hooks.ts b/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/hooks.ts new file mode 100644 index 00000000..cf96f44e --- /dev/null +++ b/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/hooks.ts @@ -0,0 +1,43 @@ +import _ from 'lodash'; +import { useCallback } from 'react'; + +import { ValueSetOption } from 'src/services'; + +import { ChoiceColumnOption } from './types'; +import { SearchBarColumnSolidChoiceTypeProps } from '../types'; + +export function useSolidChoiceColumn(props: SearchBarColumnSolidChoiceTypeProps) { + const { columnFilterValue, onChange } = props; + const { id, options } = columnFilterValue.column; + + const onSelect = useCallback( + (code: string) => { + if (!code) { + return onChange(null, id); + } + + const option = options.find((o) => o.code === code); + + if (!option) { + return onChange(null, id); + } + + onChange([option], id); + }, + [id, options, onChange], + ); + + const isOptionSelected = (option: ChoiceColumnOption) => { + return !!columnFilterValue.value && columnFilterValue.value?.findIndex((v) => _.isEqual(v, option)) !== -1; + }; + + const getOptionLabel = (option: ValueSetOption) => { + return option?.value?.Coding?.display || ''; + }; + + return { + onSelect, + isOptionSelected, + getOptionLabel, + }; +} diff --git a/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/index.tsx b/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/index.tsx new file mode 100644 index 00000000..9a29a6bb --- /dev/null +++ b/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/index.tsx @@ -0,0 +1,23 @@ +import { Radio } from 'antd'; + +import { useSolidChoiceColumn } from './hooks'; +import { SearchBarColumnSolidChoiceTypeProps } from '../types'; + +export function SolidChoiceColumn(props: SearchBarColumnSolidChoiceTypeProps) { + const { columnFilterValue } = props; + const { value } = columnFilterValue; + const { options } = columnFilterValue.column; + + const { onSelect } = useSolidChoiceColumn(props); + + return ( + // NOTE: Radio.Button defaultChecked and checked cannot be applied properly to check Coding value. + onSelect(e.target.value)}> + {options.map((coding) => ( + + {coding.display} + + ))} + + ); +} diff --git a/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/types.ts b/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/types.ts new file mode 100644 index 00000000..32e4deca --- /dev/null +++ b/src/components/SearchBar/SearchBarColumn/SolidChoiceColumn/types.ts @@ -0,0 +1,7 @@ +import { PropsValue } from 'react-select'; + +import { ValueSetOption } from 'src/services'; + +import { SolidChoiceTypeColumnFilterValue } from '../../types'; + +export type ChoiceColumnOption = PropsValue; diff --git a/src/components/SearchBar/SearchBarColumn/StringColumn/index.tsx b/src/components/SearchBar/SearchBarColumn/StringColumn/index.tsx index 78fe9821..d11628c6 100644 --- a/src/components/SearchBar/SearchBarColumn/StringColumn/index.tsx +++ b/src/components/SearchBar/SearchBarColumn/StringColumn/index.tsx @@ -1,4 +1,4 @@ -import { Col, Input } from 'antd'; +import { Input } from 'antd'; import { useStringColumn } from './hooks'; import { SearchBarColumnStringTypeProps } from '../types'; @@ -9,12 +9,11 @@ export function StringColumn(props: SearchBarColumnStringTypeProps) { const { onColumnChange } = useStringColumn(props); return ( - - - + ); } diff --git a/src/components/SearchBar/SearchBarColumn/index.tsx b/src/components/SearchBar/SearchBarColumn/index.tsx index a0387f64..b772d4c2 100644 --- a/src/components/SearchBar/SearchBarColumn/index.tsx +++ b/src/components/SearchBar/SearchBarColumn/index.tsx @@ -1,6 +1,8 @@ import { ChoiceColumn } from './ChoiceColumn'; import { DateColumn } from './DateColumn'; +import { DateSingleColumn } from './DateSingleColumn'; import { ReferenceColumn } from './ReferenceColumn'; +import { SolidChoiceColumn } from './SolidChoiceColumn'; import { StringColumn } from './StringColumn'; import { SearchBarColumnProps } from './types'; import { @@ -8,10 +10,12 @@ import { isDateColumnFilterValue, isReferenceColumnFilterValue, isChoiceColumnFilterValue, + isSolidChoiceColumnFilterValue, + isSingleDateColumnFilterValue, } from '../types'; export function SearchBarColumn(props: SearchBarColumnProps) { - const { columnFilterValue } = props; + const { columnFilterValue, defaultOpen } = props; if (isStringColumnFilterValue(columnFilterValue)) { const stringProps = { @@ -26,7 +30,15 @@ export function SearchBarColumn(props: SearchBarColumnProps) { ...props, columnFilterValue, }; - return ; + return ; + } + + if (isSingleDateColumnFilterValue(columnFilterValue)) { + const dateProps = { + ...props, + columnFilterValue, + }; + return ; } if (isReferenceColumnFilterValue(columnFilterValue)) { @@ -34,7 +46,7 @@ export function SearchBarColumn(props: SearchBarColumnProps) { ...props, columnFilterValue, }; - return ; + return ; } if (isChoiceColumnFilterValue(columnFilterValue)) { @@ -42,7 +54,16 @@ export function SearchBarColumn(props: SearchBarColumnProps) { ...props, columnFilterValue, }; - return ; + return ; + } + + if (isSolidChoiceColumnFilterValue(columnFilterValue)) { + const choiceProps = { + ...props, + columnFilterValue, + }; + + return ; } return null; diff --git a/src/components/SearchBar/SearchBarColumn/types.ts b/src/components/SearchBar/SearchBarColumn/types.ts index 23791a9f..fb4d2d02 100644 --- a/src/components/SearchBar/SearchBarColumn/types.ts +++ b/src/components/SearchBar/SearchBarColumn/types.ts @@ -1,14 +1,17 @@ import { ChoiceTypeColumnFilterValue, + SolidChoiceTypeColumnFilterValue, ColumnFilterValue, DateTypeColumnFilterValue, ReferenceTypeColumnFilterValue, StringTypeColumnFilterValue, + SingleDateTypeColumnFilterValue, } from '../types'; export type SearchBarColumnProps = { columnFilterValue: ColumnFilterValue; onChange: (value: ColumnFilterValue['value'], key: string) => void; + defaultOpen?: boolean; }; export interface SearchBarColumnStringTypeProps { @@ -19,14 +22,28 @@ export interface SearchBarColumnStringTypeProps { export interface SearchBarColumnDateTypeProps { columnFilterValue: DateTypeColumnFilterValue; onChange: (value: DateTypeColumnFilterValue['value'], key: string) => void; + defaultOpen?: boolean; +} + +export interface SearchBarColumnSingleDateTypeProps { + columnFilterValue: SingleDateTypeColumnFilterValue; + onChange: (value: SingleDateTypeColumnFilterValue['value'], key: string) => void; + defaultOpen?: boolean; } export interface SearchBarColumnReferenceTypeProps { columnFilterValue: ReferenceTypeColumnFilterValue; onChange: (value: ReferenceTypeColumnFilterValue['value'], key: string) => void; + defaultOpen?: boolean; } export interface SearchBarColumnChoiceTypeProps { columnFilterValue: ChoiceTypeColumnFilterValue; onChange: (value: ChoiceTypeColumnFilterValue['value'], key: string) => void; + defaultOpen?: boolean; +} + +export interface SearchBarColumnSolidChoiceTypeProps { + columnFilterValue: SolidChoiceTypeColumnFilterValue; + onChange: (value: SolidChoiceTypeColumnFilterValue['value'], key: string) => void; } diff --git a/src/components/SearchBar/SearchBarMobile/index.tsx b/src/components/SearchBar/SearchBarMobile/index.tsx new file mode 100644 index 00000000..f536593b --- /dev/null +++ b/src/components/SearchBar/SearchBarMobile/index.tsx @@ -0,0 +1,57 @@ +import { Trans } from '@lingui/macro'; +import { Button } from 'antd'; + +import { SearchBarColumn } from '../SearchBarColumn'; +import { S } from './styles'; +import { SearchBarData } from '../types'; +import { CloseOutlined, FilterFilled } from '@ant-design/icons'; +import { useState } from 'react'; +import { Title } from 'src/components/Typography'; +import _ from 'lodash'; + +export function SearchBarMobile(props: SearchBarData) { + const { columnsFilterValues, onChangeColumnFilter, onResetFilters } = props; + const [filtersOpened, toggleFiltersOpened] = useState(false); + const appliedFiltersCount = _.compact(columnsFilterValues.map((f) => f.value)).length; + + return ( + + + + + + + + ); +} diff --git a/src/components/SearchBar/SearchBarMobile/styles.ts b/src/components/SearchBar/SearchBarMobile/styles.ts new file mode 100644 index 00000000..9fd65048 --- /dev/null +++ b/src/components/SearchBar/SearchBarMobile/styles.ts @@ -0,0 +1,77 @@ +import { Badge, Button, Drawer } from 'antd'; +import styled from 'styled-components'; + +export const S = { + Container: styled.div``, + FiltersButton: styled.div` + position: relative; + `, + Badge: styled(Badge)` + position: absolute; + right: -3px; + top: -3px; + + .ant-badge-count { + background-color: ${({ theme }) => theme.primaryPalette.bcp_2}; + color: ${({ theme }) => theme.primary}; + } + `, + CloseIcon: styled(Button)` + height: 56px; + width: 48px !important; + color: ${({ theme }) => theme.neutralPalette.gray_7} !important; + + &:hover { + background: 0 !important; + } + `, + Drawer: styled(Drawer)` + padding-top: 56px; + padding-bottom: 129px; + background-color: ${({ theme }) => theme.neutralPalette.gray_1}; + + .ant-drawer-body { + padding: 0; + display: flex; + flex-direction: column; + justify-content: space-between; + } + + .ant-input-search, + .ant-picker, + .react-select__control { + width: 100%; + max-width: 450px; + } + `, + DrawerHeader: styled.div` + position: absolute; + left: 0; + right: 0; + top: 0; + height: 56px; + padding-left: 16px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid ${({ theme }) => theme.neutralPalette.gray_4}; + `, + DrawerContent: styled.div` + padding: 16px; + display: flex; + flex-direction: column; + gap: 16px; + flex: 1; + `, + DrawerFooter: styled.div` + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 16px; + display: flex; + flex-direction: column; + gap: 16px; + border-top: 1px solid ${({ theme }) => theme.neutralPalette.gray_4}; + `, +}; diff --git a/src/components/SearchBar/hooks.ts b/src/components/SearchBar/hooks.ts index f9a51f9f..4a1bcc58 100644 --- a/src/components/SearchBar/hooks.ts +++ b/src/components/SearchBar/hooks.ts @@ -1,4 +1,3 @@ -import _ from 'lodash'; import { useCallback, useMemo, useState } from 'react'; import { @@ -13,12 +12,18 @@ import { SearchBarProps, isChoiceColumn, isChoiceColumnFilterValue, + isSolidChoiceColumn, + isSolidChoiceColumnFilterValue, + isSingleDateColumn, + isSingleDateColumnFilterValue, } from './types'; import { validateStringColumnFilterValue, validateDateColumnFilterValue, validateReferenceColumnFilterValue, validateChoiceColumnFilterValue, + validateSolidChoiceColumnFilterValue, + validateSingleDateColumnFilterValue, } from './validate'; export function useSearchBar(props: SearchBarProps): SearchBarData { @@ -34,12 +39,29 @@ export function useSearchBar(props: SearchBarProps): SearchBarData { return { column, value: undefined }; } + if (isSingleDateColumn(column)) { + return { column, value: column.defaultValue ?? undefined }; + } + if (isReferenceColumn(column)) { - return { column, value: null }; + return { + column, + value: column.defaultValue + ? { + value: { + Reference: column.defaultValue, + }, + } + : null, + }; } if (isChoiceColumn(column)) { - return { column, value: null }; + return { column, value: column.defaultValue ? [column.defaultValue] : null }; + } + + if (isSolidChoiceColumn(column)) { + return { column, value: column.defaultValue ? [column.defaultValue] : null }; } throw new Error('Unsupported column type'); @@ -72,6 +94,13 @@ export function useSearchBar(props: SearchBarProps): SearchBarData { } } + if (isSingleDateColumnFilterValue(newFilterValue)) { + if (validateSingleDateColumnFilterValue(value)) { + newFilterValue.value = value; + return newFilterValue; + } + } + if (isReferenceColumnFilterValue(newFilterValue)) { if (validateReferenceColumnFilterValue(value)) { newFilterValue.value = value; @@ -86,6 +115,13 @@ export function useSearchBar(props: SearchBarProps): SearchBarData { } } + if (isSolidChoiceColumnFilterValue(newFilterValue)) { + if (validateSolidChoiceColumnFilterValue(value)) { + newFilterValue.value = value; + return newFilterValue; + } + } + throw new Error('Unsupported column type'); }); }); diff --git a/src/components/SearchBar/index.tsx b/src/components/SearchBar/index.tsx index d05ed73d..ef63bb04 100644 --- a/src/components/SearchBar/index.tsx +++ b/src/components/SearchBar/index.tsx @@ -1,28 +1,44 @@ import { Trans } from '@lingui/macro'; -import { Button, Row } from 'antd'; +import { Button } from 'antd'; -import { S } from './SearchBar.styles'; import { SearchBarColumn } from './SearchBarColumn'; +import { S } from './styles'; import { SearchBarData } from './types'; +import { SearchBarMobile } from './SearchBarMobile'; +import { isSearchBarFilter } from './utils'; +import { useMemo } from 'react'; -export function SearchBar(props: SearchBarData) { - const { columnsFilterValues, onChangeColumnFilter, onResetFilters } = props; +interface SearchBarProps extends SearchBarData { + showInDrawerOnMobile?: boolean; +} + +export function SearchBar(props: SearchBarProps) { + const { columnsFilterValues, onChangeColumnFilter, onResetFilters, showInDrawerOnMobile = true } = props; + const searchBarFilterValues = useMemo( + () => columnsFilterValues.filter((filter) => isSearchBarFilter(filter)), + [JSON.stringify(columnsFilterValues)], + ); return ( - - - {columnsFilterValues.map((columnFilterValue) => ( - - ))} - + <> + + + {searchBarFilterValues.map((columnFilterValue) => ( + + ))} + - - + + + + + + ); } diff --git a/src/components/SearchBar/styles.ts b/src/components/SearchBar/styles.ts new file mode 100644 index 00000000..ec486fad --- /dev/null +++ b/src/components/SearchBar/styles.ts @@ -0,0 +1,48 @@ +import { mobileWidth } from 'src/theme/utils'; +import styled, { css } from 'styled-components'; + +export const S = { + SearchBar: styled.div<{ $showInDrawerOnMobile?: boolean }>` + position: relative; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + gap: 16px; + flex-wrap: wrap; + + .ant-input-search, + .ant-picker, + .react-select__control { + width: 270px; + } + + ${({ $showInDrawerOnMobile }) => + $showInDrawerOnMobile && + css` + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + display: none; + } + `} + `, + MobileFilters: styled.div<{ $showInDrawerOnMobile?: boolean }>` + position: absolute; + right: 24px; + top: 24px; + + ${({ $showInDrawerOnMobile }) => + $showInDrawerOnMobile && + css` + @media screen and (min-width: ${() => `${mobileWidth}px`}) { + display: none; + } + `} + `, + LeftColumn: styled.div` + display: flex; + flex-direction: row; + align-items: center; + flex-wrap: wrap; + gap: 10px 8px; + `, +}; diff --git a/src/components/SearchBar/types.ts b/src/components/SearchBar/types.ts index 51c65868..dbd394f2 100644 --- a/src/components/SearchBar/types.ts +++ b/src/components/SearchBar/types.ts @@ -1,4 +1,12 @@ -import { Expression, Resource, QuestionnaireItemChoiceColumn, ValueSet } from '@beda.software/aidbox-types'; +import { Coding } from 'fhir/r4b'; + +import { + Expression, + Resource, + QuestionnaireItemChoiceColumn, + ValueSet, + AidboxReference, +} from '@beda.software/aidbox-types'; import { ValueSetOption } from 'src/services'; import { LoadResourceOption } from 'src/services/questionnaire'; @@ -6,65 +14,97 @@ import { LoadResourceOption } from 'src/services/questionnaire'; export enum SearchBarColumnType { STRING = 'string', DATE = 'date', + SINGLEDATE = 'singleDate', REFERENCE = 'reference', CHOICE = 'choice', + SOLIDCHOICE = 'solidChoice', } export interface SearchBarProps { columns: SearchBarColumn[]; } -export type SearchBarStringColumn = { + +type SearchBarColumnBase = { + // if placement is table then id should be matched with table column key id: string; + searchParam?: string; + // placement = 'search-bar' by default + placement?: Array<'search-bar' | 'table'>; +}; + +export type SearchBarStringColumn = SearchBarColumnBase & { type: SearchBarColumnType.STRING; placeholder: string; }; -export type SearchBarDateColumn = { - id: string; +export type SearchBarDateColumn = SearchBarColumnBase & { type: SearchBarColumnType.DATE; placeholder: [string, string]; }; -export type SearchBarReferenceColumn = { - id: string; +export type SearchBarSingleDateColumn = SearchBarColumnBase & { + type: SearchBarColumnType.SINGLEDATE; + placeholder: string; + defaultValue?: moment.Moment; +}; +export type SearchBarReferenceColumn = SearchBarColumnBase & { type: SearchBarColumnType.REFERENCE; expression: Expression['expression']; path: QuestionnaireItemChoiceColumn['path']; placeholder: string; + defaultValue?: AidboxReference; }; -export type SearchBarChoiceColumn = { - id: string; +export type SearchBarChoiceColumn = SearchBarColumnBase & { type: SearchBarColumnType.CHOICE; repeats?: boolean; placeholder: string; + defaultValue?: ValueSetOption; } & ( - | { - options: ValueSetOption[]; - valueSet?: never; - } - | { - options?: never; - valueSet: ValueSet['id']; - } -); + | { + options: ValueSetOption[]; + valueSet?: never; + } + | { + options?: never; + valueSet: ValueSet['id']; + } + ); + +export type SearchBarSolidChoiceColumn = SearchBarColumnBase & { + type: SearchBarColumnType.SOLIDCHOICE; + repeats?: boolean; + placeholder: string; + options: Coding[]; + valueSet?: never; + defaultValue?: Coding; +}; export type SearchBarColumn = | SearchBarStringColumn | SearchBarDateColumn + | SearchBarSingleDateColumn | SearchBarReferenceColumn - | SearchBarChoiceColumn; + | SearchBarChoiceColumn + | SearchBarSolidChoiceColumn; export function isStringColumn(column: SearchBarColumn): column is SearchBarStringColumn { return column.type === SearchBarColumnType.STRING; } export function isDateColumn(column: SearchBarColumn): column is SearchBarDateColumn { return column.type === SearchBarColumnType.DATE; } +export function isSingleDateColumn(column: SearchBarColumn): column is SearchBarSingleDateColumn { + return column.type === SearchBarColumnType.SINGLEDATE; +} export function isReferenceColumn(column: SearchBarColumn): column is SearchBarReferenceColumn { return column.type === SearchBarColumnType.REFERENCE; } export function isChoiceColumn(column: SearchBarColumn): column is SearchBarChoiceColumn { return column.type === SearchBarColumnType.CHOICE; } +export function isSolidChoiceColumn(column: SearchBarColumn): column is SearchBarSolidChoiceColumn { + return column.type === SearchBarColumnType.SOLIDCHOICE; +} export type DateColumnFilterValue = [moment.Moment, moment.Moment]; +export type SingleDateColumnFilterValue = moment.Moment; export interface StringTypeColumnFilterValue { column: SearchBarStringColumn; @@ -74,6 +114,11 @@ export interface DateTypeColumnFilterValue { column: SearchBarDateColumn; value?: DateColumnFilterValue; } + +export interface SingleDateTypeColumnFilterValue { + column: SearchBarSingleDateColumn; + value?: SingleDateColumnFilterValue; +} export interface ReferenceTypeColumnFilterValue { column: SearchBarReferenceColumn; value?: LoadResourceOption | null; @@ -83,17 +128,29 @@ export interface ChoiceTypeColumnFilterValue { value?: ValueSetOption[] | null; } +export interface SolidChoiceTypeColumnFilterValue { + column: SearchBarSolidChoiceColumn; + value?: Coding[] | null; +} + export type ColumnFilterValue = | StringTypeColumnFilterValue | DateTypeColumnFilterValue + | SingleDateTypeColumnFilterValue | ReferenceTypeColumnFilterValue - | ChoiceTypeColumnFilterValue; + | ChoiceTypeColumnFilterValue + | SolidChoiceTypeColumnFilterValue; export function isStringColumnFilterValue(filterValue: ColumnFilterValue): filterValue is StringTypeColumnFilterValue { return isStringColumn(filterValue.column); } export function isDateColumnFilterValue(filterValue: ColumnFilterValue): filterValue is DateTypeColumnFilterValue { return isDateColumn(filterValue.column); } +export function isSingleDateColumnFilterValue( + filterValue: ColumnFilterValue, +): filterValue is SingleDateTypeColumnFilterValue { + return isSingleDateColumn(filterValue.column); +} export function isReferenceColumnFilterValue( filterValue: ColumnFilterValue, ): filterValue is ReferenceTypeColumnFilterValue { @@ -102,6 +159,11 @@ export function isReferenceColumnFilterValue( export function isChoiceColumnFilterValue(filterValue: ColumnFilterValue): filterValue is ChoiceTypeColumnFilterValue { return isChoiceColumn(filterValue.column); } +export function isSolidChoiceColumnFilterValue( + filterValue: ColumnFilterValue, +): filterValue is SolidChoiceTypeColumnFilterValue { + return isSolidChoiceColumn(filterValue.column); +} export interface SearchBarData { columnsFilterValues: ColumnFilterValue[]; diff --git a/src/components/SearchBar/utils.ts b/src/components/SearchBar/utils.ts index f799c8ee..db468b01 100644 --- a/src/components/SearchBar/utils.ts +++ b/src/components/SearchBar/utils.ts @@ -1,10 +1,12 @@ -import { formatFHIRDateTime } from '@beda.software/fhir-react'; +import { formatFHIRDate, formatFHIRDateTime } from '@beda.software/fhir-react'; import { ColumnFilterValue, isChoiceColumnFilterValue, isDateColumnFilterValue, isReferenceColumnFilterValue, + isSingleDateColumnFilterValue, + isSolidChoiceColumnFilterValue, isStringColumnFilterValue, SearchBarColumn, } from './types'; @@ -19,6 +21,10 @@ export function getSearchBarFilterValue(filterValues: ColumnFilterValue[] | unde throw new Error('Filter value not found'); } + return getSearchBarColumnFilterValue(filterValue); +} + +export function getSearchBarColumnFilterValue(filterValue: ColumnFilterValue) { if (isStringColumnFilterValue(filterValue)) { return filterValue.value; } @@ -29,6 +35,10 @@ export function getSearchBarFilterValue(filterValues: ColumnFilterValue[] | unde : undefined; } + if (isSingleDateColumnFilterValue(filterValue)) { + return filterValue.value ? formatFHIRDate(filterValue.value) : undefined; + } + if (isReferenceColumnFilterValue(filterValue)) { return filterValue.value?.value.Reference.id; } @@ -37,5 +47,21 @@ export function getSearchBarFilterValue(filterValues: ColumnFilterValue[] | unde return filterValue.value?.map((option) => option.value.Coding.code!); } + if (isSolidChoiceColumnFilterValue(filterValue)) { + return filterValue.value?.map((option) => option.code!); + } + throw new Error('Unsupported column type'); } + +export function isSearchBarFilter(filter: ColumnFilterValue) { + const { placement = ['search-bar'] } = filter.column; + + return placement.includes('search-bar'); +} + +export function isTableFilter(filter: ColumnFilterValue) { + const { placement = ['search-bar'] } = filter.column; + + return placement.includes('table'); +} diff --git a/src/components/SearchBar/validate.ts b/src/components/SearchBar/validate.ts index 17c96f8f..9435c7dc 100644 --- a/src/components/SearchBar/validate.ts +++ b/src/components/SearchBar/validate.ts @@ -6,6 +6,8 @@ import { ColumnFilterValue, DateTypeColumnFilterValue, ReferenceTypeColumnFilterValue, + SingleDateTypeColumnFilterValue, + SolidChoiceTypeColumnFilterValue, StringTypeColumnFilterValue, } from './types'; @@ -32,6 +34,16 @@ export function validateDateColumnFilterValue( throw new Error('Invalid date column filter value'); } +export function validateSingleDateColumnFilterValue( + value?: ColumnFilterValue['value'], +): value is SingleDateTypeColumnFilterValue['value'] { + if (_.isUndefined(value) || moment.isMoment(value)) { + return true; + } + + throw new Error('Invalid single date column filter value'); +} + export function validateReferenceColumnFilterValue( value?: ColumnFilterValue['value'], ): value is ReferenceTypeColumnFilterValue['value'] { @@ -63,3 +75,17 @@ export function validateChoiceColumnFilterValue( throw new Error('Invalid choice column filter value'); } + +export function validateSolidChoiceColumnFilterValue( + value?: ColumnFilterValue['value'], +): value is SolidChoiceTypeColumnFilterValue['value'] { + if ( + _.isUndefined(value) || + _.isNull(value) || + (_.isArray(value) && value.length > 0 && _.isObject(value[0]) && 'code' in value[0] && 'display' in value[0]) + ) { + return true; + } + + throw new Error('Invalid solid choice column filter value'); +} diff --git a/src/components/Select/styles.ts b/src/components/Select/styles.ts index f5b4a188..1481af21 100644 --- a/src/components/Select/styles.ts +++ b/src/components/Select/styles.ts @@ -14,6 +14,10 @@ export const S = { } } + .react-select__menu { + z-index: 10; + } + .react-select__control--menu-is-open, .react-select__control--is-focused { border-color: ${({ theme }) => theme.antdTheme?.colorPrimary}; @@ -32,6 +36,11 @@ export const S = { color: ${({ theme }) => theme.antdTheme?.colorTextPlaceholder}; } + .react-select__loading-indicator { + justify-content: center; + align-items: center; + } + .react-select__placeholder { margin: 0; color: ${({ theme }) => theme.antdTheme?.colorTextDisabled}; @@ -40,6 +49,10 @@ export const S = { .react-select__input-container { margin: 0; padding: 0; + + input { + color: ${({ theme }) => theme.antdTheme?.colorText} !important; + } } .react-select__indicator-separator { diff --git a/src/components/Table/Table.module.scss b/src/components/Table/Table.module.scss deleted file mode 100644 index b47f340c..00000000 --- a/src/components/Table/Table.module.scss +++ /dev/null @@ -1,21 +0,0 @@ -.container { - overflow: auto; -} - -:local .table { - :global .ant-spin-container { - min-width: fit-content; - } - - :global .ant-table { - min-width: fit-content; - } - - :global .ant-table-container { - min-width: fit-content; - } - - :global .ant-table-content { - min-width: fit-content; - } -} diff --git a/src/components/Table/TableCards/index.tsx b/src/components/Table/TableCards/index.tsx new file mode 100644 index 00000000..2deba08d --- /dev/null +++ b/src/components/Table/TableCards/index.tsx @@ -0,0 +1,105 @@ +import { TableProps } from 'antd/lib/table'; + +import { S } from './styles'; +import { Checkbox, Empty, Pagination, TablePaginationConfig } from 'antd'; +import { ColumnTitle, SorterResult, TableCurrentDataSource } from 'antd/lib/table/interface'; +import _ from 'lodash'; + +export function TableCards(props: TableProps) { + const { pagination, onChange, dataSource = [], columns = [], rowKey, rowSelection } = props; + + const renderTitle = (title: ColumnTitle) => { + if (typeof title === 'function') { + return {title({})}; + } + + return {title}; + }; + + const getCardKey = (resource: T) => { + if (typeof rowKey === 'function') { + return rowKey(resource) as string; + } + + return rowKey as string; + }; + + if (dataSource.length === 0) { + return ; + } + + return ( + + {dataSource.map((resource, index) => { + const key = getCardKey(resource); + const selectedRowKeys = rowSelection?.selectedRowKeys ?? []; + + return ( + + + {columns.map((column) => ( + + {column?.title ? renderTitle(column.title) : null} + + { + // @ts-ignore + column?.render + ? (column?.render( + // @ts-ignore + column.dataIndex ? _.get(resource, column.dataIndex) : null, + resource, + index, + ) as React.ReactNode) + : // @ts-ignore + _.get(resource, column.dataIndex) + } + + + ))} + + {rowSelection ? ( + + { + const checked = e.target.checked; + + if (checked) { + rowSelection.onChange?.([...selectedRowKeys, key], [], { + type: 'single', + }); + } else { + const filteredKeys = selectedRowKeys.filter((k) => k !== key); + rowSelection.onChange?.(filteredKeys, [], { + type: 'single', + }); + } + }} + /> + + ) : null} + + ); + })} + + { + const paginationConfig: TablePaginationConfig = { + ...(pagination ?? {}), + current: page, + pageSize, + }; + const filtersConfig: Record = {}; + const sorterConfig: SorterResult = {}; + const extraConfig: TableCurrentDataSource = {} as any; + + // @ts-ignore + onChange(paginationConfig, filtersConfig, sorterConfig, extraConfig); + }} + /> + + + ); +} diff --git a/src/components/Table/TableCards/styles.ts b/src/components/Table/TableCards/styles.ts new file mode 100644 index 00000000..3de92a2c --- /dev/null +++ b/src/components/Table/TableCards/styles.ts @@ -0,0 +1,39 @@ +import styled from 'styled-components'; +import { Text } from 'src/components/Typography'; + +export const S = { + Container: styled.div` + display: flex; + flex-direction: column; + gap: 10px 0; + color: ${({ theme }) => theme.neutral.primaryText}; + `, + Card: styled.div` + display: flex; + gap: 0 24px; + padding: 16px; + border: 1px solid ${({ theme }) => theme.neutralPalette.gray_4}; + border-radius: 6px; + background-color: ${({ theme }) => theme.neutralPalette.gray_1}; + `, + Columns: styled.div` + flex: 1; + display: flex; + flex-direction: column; + gap: 16px 0; + `, + RowSelection: styled.div``, + Column: styled.div` + display: flex; + flex-direction: column; + gap: 4px 0; + `, + Title: styled(Text)` + font-weight: 700; + `, + Content: styled.div``, + Pagination: styled.div` + display: flex; + justify-content: flex-end; + `, +}; diff --git a/src/components/Table/TableFilter/index.tsx b/src/components/Table/TableFilter/index.tsx new file mode 100644 index 00000000..de429c17 --- /dev/null +++ b/src/components/Table/TableFilter/index.tsx @@ -0,0 +1,45 @@ +import { ColumnFilterValue, isSingleDateColumn, isStringColumn } from 'src/components/SearchBar/types'; +import { SearchBarColumn } from 'src/components/SearchBar/SearchBarColumn'; +import { S } from './styles'; +import { FilterDropdownProps } from 'antd/lib/table/interface'; +import _ from 'lodash'; + +interface Props { + filter: ColumnFilterValue; + onChange: (value: ColumnFilterValue['value'], key: string) => void; +} + +interface TableFilterProps extends FilterDropdownProps, Props {} + +export function TableFilter(props: TableFilterProps) { + const { filter, onChange: onInitialChange, close, visible } = props; + + const onChange = (value: ColumnFilterValue['value'], key: string) => { + if (isStringColumn(filter.column)) { + onInitialChange(value, key); + + return; + } + + onInitialChange(value, key); + close(); + }; + + if (isSingleDateColumn(filter.column)) { + return ( + + + + + + ); + } + + return ( + + + + + + ); +} diff --git a/src/components/Table/TableFilter/styles.ts b/src/components/Table/TableFilter/styles.ts new file mode 100644 index 00000000..f6a8f9f4 --- /dev/null +++ b/src/components/Table/TableFilter/styles.ts @@ -0,0 +1,67 @@ +import styled, { css } from 'styled-components'; + +const shadows = css` + ${({ theme }) => + theme.mode === 'light' && + css` + box-shadow: + 0px 6px 16px 0px ${({ theme }) => theme.neutral.dividers}, + 0px 3px 6px -4px ${({ theme }) => theme.neutral.border}, + 0px 9px 28px 8px ${({ theme }) => theme.neutral.background}; + `} + + ${({ theme }) => + theme.mode === 'dark' && + css` + box-shadow: + 0 6px 16px 0 rgba(0, 0, 0, 0.08), + 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 9px 28px 8px rgba(0, 0, 0, 0.05); + `} +`; + +export const S = { + Container: styled.div` + .ant-input-search, + .ant-picker, + .react-select__control { + width: 100%; + } + + .react-select__menu { + position: static; + } + + .react-select__menu { + box-shadow: none; + padding: 8px 4px 4px; + margin: 8px -8px -8px; + border-top: 1px solid ${({ theme }) => theme.neutral.dividers}; + border-radius: 0; + width: auto; + } + + .react-select__menu-list { + padding: 0; + } + `, + DatePickerFilter: styled.div` + width: 288px; + + .ant-picker { + ${shadows} + } + `, + Filter: styled.div` + display: flex; + flex-direction: column; + padding: 8px; + border-radius: 8px; + min-width: 240px; + background-color: ${({ theme }) => theme.neutralPalette.gray_1}; + border-radius: 6px; + overflow: hidden; + + ${shadows} + `, +}; diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx index cf7c7658..e8d25420 100644 --- a/src/components/Table/index.tsx +++ b/src/components/Table/index.tsx @@ -1,12 +1,25 @@ import { Table as ANTDTable } from 'antd'; -import { TableProps } from 'antd/lib/table'; +import { TableProps as ANTDTableProps } from 'antd/lib/table'; -import s from './Table.module.scss'; +import { S } from './styles'; +import { TableCards } from './TableCards'; +import './table.scss'; + +interface TableProps extends ANTDTableProps { + showCardsOnMobile?: boolean; +} export function Table(props: TableProps) { + const { showCardsOnMobile = true } = props; + return ( -
- className={s.table} bordered {...props} /> -
+ <> + + bordered size="middle" {...props} /> + + + + + ); } diff --git a/src/components/Table/styles.ts b/src/components/Table/styles.ts new file mode 100644 index 00000000..68a4cd28 --- /dev/null +++ b/src/components/Table/styles.ts @@ -0,0 +1,45 @@ +import { mobileWidth } from 'src/theme/utils'; +import styled, { css } from 'styled-components'; + +export const S = { + Table: styled.div<{ $showCardsOnMobile?: boolean }>` + overflow: auto; + + ${({ $showCardsOnMobile }) => + $showCardsOnMobile && + css` + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + display: none; + } + `} + + .ant-spin-container { + min-width: fit-content; + } + + .ant-table { + min-width: fit-content; + } + + .ant-table-container { + min-width: fit-content; + } + + .ant-table-content { + min-width: fit-content; + } + + .ant-table-thead .ant-table-cell { + background-color: ${({ theme }) => theme.neutralPalette.gray_3}; + } + `, + Cards: styled.div<{ $showCardsOnMobile?: boolean }>` + ${({ $showCardsOnMobile }) => + $showCardsOnMobile && + css` + @media screen and (min-width: ${() => `${mobileWidth}px`}) { + display: none; + } + `} + `, +}; diff --git a/src/components/Table/table.scss b/src/components/Table/table.scss new file mode 100644 index 00000000..fe8ee153 --- /dev/null +++ b/src/components/Table/table.scss @@ -0,0 +1,7 @@ +.ant-dropdown .ant-table-filter-dropdown { + border: 0; + background: none; + box-shadow: none; + position: relative; + overflow: visible; +} diff --git a/src/components/Table/utils.tsx b/src/components/Table/utils.tsx new file mode 100644 index 00000000..900666f1 --- /dev/null +++ b/src/components/Table/utils.tsx @@ -0,0 +1,35 @@ +import { Bundle, Resource } from 'fhir/r4b'; +import { ColumnsType, ColumnType } from 'antd/lib/table'; +import { ColumnFilterValue } from 'src/components/SearchBar/types'; +import { TableFilter } from './TableFilter'; +import { FilterDropdownProps } from 'antd/lib/table/interface'; +import _ from 'lodash'; + +export type RecordType = { resource: R; bundle: Bundle }; + +interface Props { + tableColumns: ColumnsType>; + filters: ColumnFilterValue[]; + onChange: (value: ColumnFilterValue['value'], key: string) => void; +} + +export function populateTableColumnsWithFiltersAndSorts( + props: Props, +): ColumnsType> { + const { tableColumns, filters, onChange } = props; + const result = tableColumns.map((column) => { + const filter = filters.find((f) => f.column.id === column.key); + + const updatedColumn: ColumnType> = { + ...column, + filtered: !_.isUndefined(filter?.value) && !_.isNull(filter?.value) && filter?.value !== '', + filterDropdown: filter + ? (props: FilterDropdownProps) => + : undefined, + }; + + return updatedColumn; + }); + + return result; +} diff --git a/src/components/Tabs/Tabs.stories.tsx b/src/components/Tabs/Tabs.stories.tsx new file mode 100644 index 00000000..4190bb97 --- /dev/null +++ b/src/components/Tabs/Tabs.stories.tsx @@ -0,0 +1,46 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { withColorSchemeDecorator } from 'src/storybook/decorators'; + +import { Tabs, TabsProps } from './index'; + +const args: TabsProps = { + items: [ + { + label: 'Tab', + key: 'tab1', + }, + { + label: 'Tab', + key: 'tab2', + }, + { + label: 'Tab', + key: 'tab3', + }, + { + label: 'Tab', + key: 'tab4', + }, + ], + activeKey: 'tab2', +}; + +const meta: Meta = { + title: 'components / Tabs', + component: Tabs, + decorators: [withColorSchemeDecorator], + args, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; + +export const NoDivider: Story = { + args: { + boxShadow: false, + }, +}; diff --git a/src/components/Tabs/index.tsx b/src/components/Tabs/index.tsx new file mode 100644 index 00000000..9726bb69 --- /dev/null +++ b/src/components/Tabs/index.tsx @@ -0,0 +1,17 @@ +import { Tabs as ANTDTabs, TabsProps as ANTDTabsProps } from 'antd'; + +import { S } from './styles'; + +export interface TabsProps extends ANTDTabsProps { + boxShadow?: boolean; +} + +export function Tabs(props: TabsProps) { + const { boxShadow = true, ...rest } = props; + + return ( + + + + ); +} diff --git a/src/components/Tabs/styles.ts b/src/components/Tabs/styles.ts new file mode 100644 index 00000000..0b3bff95 --- /dev/null +++ b/src/components/Tabs/styles.ts @@ -0,0 +1,28 @@ +import styled, { css } from 'styled-components'; + +export const S = { + Tabs: styled.div<{ $boxShadow?: boolean }>` + .ant-tabs-nav { + margin-bottom: 0; + + &:before { + border-bottom-width: 0; + + ${({ $boxShadow }) => + $boxShadow && + css` + border-bottom-width: 1px; + `} + } + } + + .ant-tabs-tab { + font-weight: 400; + position: relative; + + a { + color: inherit; + } + } + `, +}; diff --git a/src/components/index.ts b/src/components/index.ts index 8f12f3b2..fa495c91 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -18,11 +18,11 @@ export * from './ModalNewEncounter'; export * from './ModalNewHealthcareService'; export * from './ModalNewPatient'; export * from './ModalTrigger'; -export * from './PageContainer'; export * from './PatientEncounter'; export * from './QuestionnaireResponseForm'; export * from './QuestionnairesWizard'; export * from './ResourceTable'; +export * from '../uberComponents/ResourceListPage'; export * from './SearchBar'; export * from './SearchBar/hooks'; export * from './Select'; @@ -31,4 +31,6 @@ export * from './Table'; export * from './TextWithMacroFill'; export * from './TimePicker'; export * from './Typography'; +export * from './BaseLayout/PageContainer'; +export * from './Tabs'; export * from './Report'; diff --git a/src/containers/App/DefaultUserWithNoRoles.tsx b/src/containers/App/DefaultUserWithNoRoles.tsx deleted file mode 100644 index f4961d14..00000000 --- a/src/containers/App/DefaultUserWithNoRoles.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Trans } from '@lingui/macro'; -import { BasePageContent, BasePageHeader, Title, Text } from 'src/components'; -import { sharedAuthorizedUser } from 'src/sharedState'; - -export function DefaultUserWithNoRoles() { - const user = sharedAuthorizedUser.getSharedState()!; - const { email, phoneNumber } = user; - - return ( - <> - - - <Trans>User with no roles in the system</Trans> - - - - - Please ask administrator to add a role for your user - -
- {email && ( - - Email: {email} - - )} -
- {email && ( - - Phone number: {phoneNumber} - - )} -
- - ); -} diff --git a/src/containers/App/index.tsx b/src/containers/App/index.tsx index 061588f6..cbfb7798 100644 --- a/src/containers/App/index.tsx +++ b/src/containers/App/index.tsx @@ -36,17 +36,14 @@ import { OrganizationScheduling } from '../OrganizationScheduling'; import { DocumentPrint } from '../PatientDetails/DocumentPrint'; import { Prescriptions } from '../Prescriptions'; import { SetPassword } from '../SetPassword'; -import { DefaultUserWithNoRoles } from './DefaultUserWithNoRoles'; interface AppProps { authenticatedRoutes?: ReactElement; anonymousRoutes?: ReactElement; populateUserInfoSharedState?: (user: User) => Promise; - UserWithNoRolesComponent?: () => ReactElement; } -export function App(props: AppProps) { - const { authenticatedRoutes, anonymousRoutes, populateUserInfoSharedState, UserWithNoRolesComponent } = props; +export function App({ authenticatedRoutes, anonymousRoutes, populateUserInfoSharedState }: AppProps) { const menuLayout = useContext(MenuLayout); const [userResponse] = useService(async () => { const appToken = getToken(); @@ -55,12 +52,6 @@ export function App(props: AppProps) { const renderRoutes = (user: User | null) => { if (user) { - if ((user.role?.length ?? 0) === 0) { - const UserWithNoRoles = UserWithNoRolesComponent ?? DefaultUserWithNoRoles; - - return ; - } - const layout = menuLayout(); const defaultRoute = layout[0]?.path ?? '/encounters'; return ; diff --git a/src/containers/Appointment/PublicAppointment.styles.ts b/src/containers/Appointment/PublicAppointment.styles.ts index 559e43d6..ef43d551 100644 --- a/src/containers/Appointment/PublicAppointment.styles.ts +++ b/src/containers/Appointment/PublicAppointment.styles.ts @@ -1,9 +1,6 @@ import styled from 'styled-components'; -import { BasePageHeader } from 'src/components/BaseLayout'; - export const S = { - Header: styled(BasePageHeader)``, Content: styled.div` width: 540px; background-color: ${({ theme }) => theme.antdTheme?.colorBgContainer}; diff --git a/src/containers/Appointment/PublicAppointment.tsx b/src/containers/Appointment/PublicAppointment.tsx index 17e9f405..ab593c29 100644 --- a/src/containers/Appointment/PublicAppointment.tsx +++ b/src/containers/Appointment/PublicAppointment.tsx @@ -6,11 +6,10 @@ import { axiosInstance as axiosAidboxInstance } from 'aidbox-react/lib/services/ import { uuid4 } from '@beda.software/fhir-react'; -import { BasePageContent } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { DateTimeSlotPicker } from 'src/components/BaseQuestionnaireResponseForm/widgets'; import { QuestionnaireResponseForm } from 'src/components/QuestionnaireResponseForm'; import { Spinner } from 'src/components/Spinner'; -import { Title } from 'src/components/Typography'; import { questionnaireIdLoader } from 'src/hooks/questionnaire-response-form-data'; import { getToken } from 'src/services/auth'; import { axiosInstance as axiosFHIRInstance } from 'src/services/fhir'; @@ -42,47 +41,39 @@ export function PublicAppointment() { }, [isAnonymousUser]); return ( - <> - - - <Trans>Appointment booking</Trans> - - - - - - {isLoading ? ( - - ) : ( - { - notification.success({ - message: t`Appointment successfully created`, - }); - history.replace('/'); - }} - itemControlQuestionItemComponents={{ - 'date-time-slot': (props) => ( - - ), - }} - initialQuestionnaireResponse={{ - questionnaire: 'public-appointment', - }} - launchContextParameters={[ - { - name: 'Patient', - resource: { - resourceType: 'Patient', - id: uuid4(), - }, + Appointment booking} content={{ style: { alignItems: 'center' } }}> + + {isLoading ? ( + + ) : ( + { + notification.success({ + message: t`Appointment successfully created`, + }); + history.replace('/'); + }} + itemControlQuestionItemComponents={{ + 'date-time-slot': (props) => ( + + ), + }} + initialQuestionnaireResponse={{ + questionnaire: 'public-appointment', + }} + launchContextParameters={[ + { + name: 'Patient', + resource: { + resourceType: 'Patient', + id: uuid4(), }, - ]} - /> - )} - - - + }, + ]} + /> + )} + + ); } diff --git a/src/containers/DocumentsList/ChooseDocumentToCreateModal/index.tsx b/src/containers/DocumentsList/ChooseDocumentToCreateModal/index.tsx index 7c5f0b77..383d8fd0 100644 --- a/src/containers/DocumentsList/ChooseDocumentToCreateModal/index.tsx +++ b/src/containers/DocumentsList/ChooseDocumentToCreateModal/index.tsx @@ -34,7 +34,6 @@ export const ChooseDocumentToCreateModal = (props: Props) => { await getFHIRResources('Questionnaire', { 'subject-type': subjectType ? [subjectType] : [], _sort: 'title', - status: 'active', ...(context ? { context } : {}), }), (bundle) => extractBundleResources(bundle).Questionnaire, diff --git a/src/containers/EncounterDetails/index.tsx b/src/containers/EncounterDetails/index.tsx index fe902e7c..12c20dd8 100644 --- a/src/containers/EncounterDetails/index.tsx +++ b/src/containers/EncounterDetails/index.tsx @@ -15,7 +15,6 @@ import { Spinner } from 'src/components/Spinner'; import { Text } from 'src/components/Typography'; import { DocumentsList } from 'src/containers/DocumentsList'; import { ChooseDocumentToCreateModal } from 'src/containers/DocumentsList/ChooseDocumentToCreateModal'; -import { usePatientHeaderLocationTitle } from 'src/containers/PatientDetails/PatientHeader/hooks'; import { questionnaireIdLoader } from 'src/hooks/questionnaire-response-form-data'; import { AIScribe, useAIScribe } from './AIScribe'; @@ -45,8 +44,6 @@ export const EncounterDetails = (props: EncounterDetailsProps) => { const [documentListKey, setDocumentListKey] = useState(0); const reload = useCallback(() => setDocumentListKey((k) => k + 1), [setDocumentListKey]); - usePatientHeaderLocationTitle({ title: t`Consultation` }); - const [showScriber, setShowScriber] = useState(false); const { recorderControls } = useAIScribe(); diff --git a/src/containers/EncounterList/hooks.ts b/src/containers/EncounterList/hooks.ts index 29b948f5..081d05f0 100644 --- a/src/containers/EncounterList/hooks.ts +++ b/src/containers/EncounterList/hooks.ts @@ -44,7 +44,7 @@ export function useEncounterList( 'participant-display': practitionerFilterValue, 'subject:Patient.id': patientFilterValue, date: dateFilterValue, - _sort: ['-_date', '_id'], + _sort: '-_date', }; const { resourceResponse, pagerManager, handleTableChange, pagination } = usePagerExtended< diff --git a/src/containers/EncounterList/index.tsx b/src/containers/EncounterList/index.tsx index 8bf32ce2..fcd7bad4 100644 --- a/src/containers/EncounterList/index.tsx +++ b/src/containers/EncounterList/index.tsx @@ -2,13 +2,12 @@ import { Trans } from '@lingui/macro'; import { Col, Row } from 'antd'; import { Link } from 'react-router-dom'; -import { BasePageContent, BasePageHeader } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { EncountersTable } from 'src/components/EncountersTable'; import { EncounterData } from 'src/components/EncountersTable/types'; import { StatusBadge } from 'src/components/EncounterStatusBadge'; import { SearchBar } from 'src/components/SearchBar'; import { useSearchBar } from 'src/components/SearchBar/hooks'; -import { Title } from 'src/components/Typography'; import { formatPeriodDateTime } from 'src/utils/date'; import { renderHumanName } from 'src/utils/fhir'; import { matchCurrentUserRole, Role } from 'src/utils/role'; @@ -97,27 +96,25 @@ export function EncounterList() { ]; return ( - <> - - - <Trans>Encounters</Trans> - - - - - - - - - + Encounters} + header={{ + children: ( + + ), + }} + > + + ); } diff --git a/src/containers/HealthcareServiceList/hooks.ts b/src/containers/HealthcareServiceList/hooks.ts index dd48afb8..8e239776 100644 --- a/src/containers/HealthcareServiceList/hooks.ts +++ b/src/containers/HealthcareServiceList/hooks.ts @@ -14,7 +14,7 @@ export function useHealthcareServiceList(filterValues: ColumnFilterValue[]) { const healthcareServiceFilterValue = getSearchBarFilterValue(filterValues, 'service'); const queryParameters = { - _sort: ['-_lastUpdated', '_id'], + _sort: '-_lastUpdated', ilike: healthcareServiceFilterValue, }; diff --git a/src/containers/HealthcareServiceList/index.tsx b/src/containers/HealthcareServiceList/index.tsx index 812824cc..58fbab9b 100644 --- a/src/containers/HealthcareServiceList/index.tsx +++ b/src/containers/HealthcareServiceList/index.tsx @@ -1,16 +1,16 @@ import { Trans } from '@lingui/macro'; -import { Col, Empty, Row, Table } from 'antd'; +import { Col, Empty, Row } from 'antd'; import { isLoading, isSuccess } from '@beda.software/remote-data'; -import { BasePageHeader, BasePageContent } from 'src/components/BaseLayout'; +import { Table } from 'src/components'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { ModalChangeActiveHealthcareService } from 'src/components/ModalChangeActiveHealthcareService'; import { ModalEditHealthcareService } from 'src/components/ModalEditHealthcareService'; import { ModalNewHealthcareService } from 'src/components/ModalNewHealthcareService'; import { SearchBar } from 'src/components/SearchBar'; import { useSearchBar } from 'src/components/SearchBar/hooks'; import { SpinIndicator } from 'src/components/Spinner'; -import { Title } from 'src/components/Typography'; import { useHealthcareServiceList } from './hooks'; import { getHealthcareServiceListSearchBarColumns } from './searchBarUtils'; @@ -24,89 +24,82 @@ export function HealthcareServiceList() { useHealthcareServiceList(columnsFilterValues); return ( - <> - - -
- - <Trans>Healthcare Services</Trans> - - - - - - - - - - -
- No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> - + Healthcare Services} + headerRightColumn={} + header={{ + children: ( + + ), + }} + > +
+ No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> + + ), + }} + dataSource={isSuccess(healthcareServiceResponse) ? healthcareServiceResponse.data : []} + columns={[ + { + title: Type, + dataIndex: 'type', + key: 'type', + width: '20%', + render: (_text, resource) => resource.name, + }, + { + title: Duration (minutes), + dataIndex: 'duration', + key: 'duration', + width: '20%', + render: (_text, resource) => + resource.extension?.find( + (extension) => extension.url === 'urn:extensions:healthcare-service-duration', + )?.valueInteger, + }, + { + title: Status, + dataIndex: 'active', + key: 'active', + width: '20%', + render: (_text, resource) => (resource.active ? 'Active' : 'Inactive'), + }, + { + title: Actions, + dataIndex: 'actions', + key: 'actions', + width: '20%', + render: (_text, resource) => ( + + + + + + + + ), - }} - dataSource={isSuccess(healthcareServiceResponse) ? healthcareServiceResponse.data : []} - columns={[ - { - title: Type, - dataIndex: 'type', - key: 'type', - width: '20%', - render: (_text, resource) => resource.name, - }, - { - title: Duration (minutes), - dataIndex: 'duration', - key: 'duration', - width: '20%', - render: (_text, resource) => - resource.extension?.find( - (extension) => extension.url === 'urn:extensions:healthcare-service-duration', - )?.valueInteger, - }, - { - title: Status, - dataIndex: 'active', - key: 'active', - width: '20%', - render: (_text, resource) => (resource.active ? 'Active' : 'Inactive'), - }, - { - title: Actions, - dataIndex: 'actions', - key: 'actions', - width: '20%', - render: (_text, resource) => ( - - - - - - - - - ), - }, - ]} - loading={isLoading(healthcareServiceResponse) && { indicator: SpinIndicator }} - /> - - + }, + ]} + loading={isLoading(healthcareServiceResponse) && { indicator: SpinIndicator }} + /> + ); } diff --git a/src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx b/src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx index 6435b3a1..f8231e7a 100644 --- a/src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx +++ b/src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx @@ -1,20 +1,17 @@ +import { t } from '@lingui/macro'; import { Col, Row, Statistic } from 'antd'; -import { BasePageHeader } from 'src/components/BaseLayout'; -import { Title } from 'src/components/Typography'; import { getInvoiceStatusHumanized } from 'src/containers/InvoiceList/tableUtils'; import { formatHumanDateTime } from 'src/utils/date'; import { renderHumanName } from 'src/utils/fhir'; import { InvoiceDetailsHeaderProps } from './types'; -import { t, Trans } from '@lingui/macro'; export function InvoiceDetailsHeader(props: InvoiceDetailsHeaderProps) { const { invoice, patient, practitioner } = props; return ( - - <Trans>Medical Services Invoice</Trans> + <> @@ -29,6 +26,6 @@ export function InvoiceDetailsHeader(props: InvoiceDetailsHeaderProps) { - + ); } diff --git a/src/containers/InvoiceDetails/index.tsx b/src/containers/InvoiceDetails/index.tsx index 0b3f5826..762db0d2 100644 --- a/src/containers/InvoiceDetails/index.tsx +++ b/src/containers/InvoiceDetails/index.tsx @@ -1,11 +1,11 @@ import { Trans, t } from '@lingui/macro'; -import { Table } from 'antd'; import _ from 'lodash'; import { Outlet, Route, Routes, useParams } from 'react-router-dom'; import { RenderRemoteData } from 'aidbox-react/lib/components/RenderRemoteData'; -import { BasePageContent } from 'src/components/BaseLayout'; +import { Table } from 'src/components'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { Spinner } from 'src/components/Spinner'; import { getFHIRReferenceResourceId } from 'src/utils/reference'; @@ -22,23 +22,28 @@ export function InvoiceDetails() { return ( {({ invoice, patient, practitioner }) => ( - <> - - - - - - - } - > - } /> - - - - + Medical Services Invoice} + header={{ + children: ( + + ), + }} + > + + + + + } + > + } /> + + + )} ); diff --git a/src/containers/InvoiceList/components/InvoiceListSearchBar/InvoiceListSearchBar.styles.ts b/src/containers/InvoiceList/components/InvoiceListSearchBar/InvoiceListSearchBar.styles.ts deleted file mode 100644 index c562d85a..00000000 --- a/src/containers/InvoiceList/components/InvoiceListSearchBar/InvoiceListSearchBar.styles.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Layout } from 'antd'; -import styled from 'styled-components'; - -export const S = { - Container: styled(Layout)` - position: relative; - padding: 16px; - border-radius: 10px; - background-color: ${({ theme }) => theme.primaryPalette.bcp_3}; - display: flex; - flex-direction: row; - justify-content: space-between; - gap: 16px 32px; - flex-wrap: wrap; - - .ant-input-search, - .ant-picker { - width: 264px; - } - `, - SelectContainer: styled.div` - margin-left: 16px; - display: flex; - flex-direction: row; - gap: 32px; - flex-wrap: wrap; - `, -}; diff --git a/src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx b/src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx index 2dfba9c0..a1d59f19 100644 --- a/src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx +++ b/src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx @@ -1,11 +1,11 @@ import { t } from '@lingui/macro'; -import { Row, Button } from 'antd'; +import { Button } from 'antd'; +import { S } from 'src/components/SearchBar/styles'; import { AsyncDropdown } from 'src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect'; import { OptionType } from 'src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/types'; import { Role, matchCurrentUserRole } from 'src/utils/role'; -import { S } from './InvoiceListSearchBar.styles'; import { InvoiceListSearchBarSelectProps } from '../../types'; export function InvoiceListSearchBar(props: InvoiceListSearchBarSelectProps) { @@ -23,37 +23,35 @@ export function InvoiceListSearchBar(props: InvoiceListSearchBarSelectProps) { } = props; return ( - - - - - - + + + + - + ); } diff --git a/src/containers/InvoiceList/hooks.ts b/src/containers/InvoiceList/hooks.ts index 4369dfe0..83875bc8 100644 --- a/src/containers/InvoiceList/hooks.ts +++ b/src/containers/InvoiceList/hooks.ts @@ -7,7 +7,7 @@ import { usePagerExtended } from 'src/hooks/pager'; export function useInvoicesList(practitionerId?: string, patientId?: string, status?: string) { const queryParameters = { - _sort: ['-_lastUpdated', '_id'], + _sort: '-_lastUpdated', status: status, subject: patientId, participant: practitionerId, diff --git a/src/containers/InvoiceList/index.tsx b/src/containers/InvoiceList/index.tsx index facbe0b9..2c45f114 100644 --- a/src/containers/InvoiceList/index.tsx +++ b/src/containers/InvoiceList/index.tsx @@ -1,10 +1,11 @@ import { Trans, t } from '@lingui/macro'; -import { Empty, Table } from 'antd'; +import { Empty } from 'antd'; import { RenderRemoteData } from '@beda.software/fhir-react'; import { isLoading } from '@beda.software/remote-data'; -import { PageContainer } from 'src/components/PageContainer'; +import { Table } from 'src/components'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { SpinIndicator, Spinner } from 'src/components/Spinner'; import { Role, matchCurrentUserRole, selectCurrentUserRoleResource } from 'src/utils/role'; @@ -42,45 +43,44 @@ export function InvoiceList() { return ( onChange(selectedOption, 'patient')} - onChangePractitionerRole={(selectedOption) => onChange(selectedOption, 'practitionerRole')} - onChangeStatus={(selectedOption) => onChange(selectedOption, 'status')} - reset={resetFilter} - /> - } - content={ - - {({ invoices, practitioners, practitionerRoles, patients }) => ( -
- No data} - image={Empty.PRESENTED_IMAGE_SIMPLE} - /> - - ), - }} - dataSource={invoices} - columns={getInvoiceTableColumns(practitioners, practitionerRoles, patients, pagerManager)} - loading={isLoading(invoiceResponse) && { indicator: SpinIndicator }} - scroll={{ x: 'max-content' }} - /> - )} - - } - /> + variant="with-table" + header={{ + children: ( + onChange(selectedOption, 'patient')} + onChangePractitionerRole={(selectedOption) => onChange(selectedOption, 'practitionerRole')} + onChangeStatus={(selectedOption) => onChange(selectedOption, 'status')} + reset={resetFilter} + /> + ), + }} + > + + {({ invoices, practitioners, practitionerRoles, patients }) => ( +
+ No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> + + ), + }} + dataSource={invoices} + columns={getInvoiceTableColumns(practitioners, practitionerRoles, patients, pagerManager)} + loading={isLoading(invoiceResponse) && { indicator: SpinIndicator }} + scroll={{ x: 'max-content' }} + /> + )} + + ); } diff --git a/src/containers/MedicationManagement/components/MedicationsSearchBar/MedicationsSearchBar.styles.ts b/src/containers/MedicationManagement/components/MedicationsSearchBar/MedicationsSearchBar.styles.ts deleted file mode 100644 index 66c51f4d..00000000 --- a/src/containers/MedicationManagement/components/MedicationsSearchBar/MedicationsSearchBar.styles.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Layout } from 'antd'; -import styled from 'styled-components'; - -export const S = { - Container: styled(Layout)` - position: relative; - padding: 16px; - border-radius: 10px; - background-color: ${({ theme }) => theme.primaryPalette.bcp_3}; - display: flex; - flex-direction: row; - justify-content: space-between; - gap: 16px 32px; - flex-wrap: wrap; - - .ant-input-search, - .ant-picker { - width: 264px; - } - `, - SelectContainer: styled.div` - margin-left: 16px; - display: flex; - flex-direction: row; - gap: 32px; - `, -}; diff --git a/src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx b/src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx index 351d36a7..45d8f8ca 100644 --- a/src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx +++ b/src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx @@ -1,14 +1,13 @@ import { t } from '@lingui/macro'; -import { Row, Button } from 'antd'; +import { Button } from 'antd'; +import { S } from 'src/components/SearchBar/styles'; import { AsyncDropdown } from 'src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect'; import { OptionType, SelectOption, } from 'src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/types'; -import { S } from './MedicationsSearchBar.styles'; - export interface MedicationsSearchBarSelectProps { selectedMedication: SelectOption; loadMedicationOptions: (search: string) => void; @@ -20,19 +19,17 @@ export function MedicationsSearchBar(props: MedicationsSearchBarSelectProps) { const { onChangeMedication, loadMedicationOptions, selectedMedication, reset } = props; return ( - - - - - - + + + + - + ); } diff --git a/src/containers/MedicationManagement/index.tsx b/src/containers/MedicationManagement/index.tsx index 22093e7e..585b7096 100644 --- a/src/containers/MedicationManagement/index.tsx +++ b/src/containers/MedicationManagement/index.tsx @@ -1,11 +1,12 @@ import { t, Trans } from '@lingui/macro'; -import { Typography, Table } from 'antd'; +import { Typography } from 'antd'; import { MedicationKnowledge } from 'fhir/r4b'; import { RenderRemoteData } from '@beda.software/fhir-react'; import { isLoading, isSuccess } from '@beda.software/remote-data'; -import { PageContainer } from 'src/components/PageContainer'; +import { Table } from 'src/components'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { SpinIndicator } from 'src/components/Spinner'; import { formatHumanDate } from 'src/utils/date'; @@ -26,59 +27,58 @@ export function MedicationManagement() { return ( } - headerContent={ - onChange(selectedOption, 'medication')} - reset={resetFilter} - /> - } - content={ -
{ - return { ...{ key: resourceData.id }, ...resourceData }; - }) - : [] - } - expandable={{ - expandedRowRender: (record) => , - }} - columns={[ - { - title: Name, - dataIndex: 'name', - key: 'name', - render: (_text, resource) => resource.code?.coding?.[0]?.display, - }, - { - title: Cost, - dataIndex: 'cost', - key: 'cost', - render: (_text, resource) => - `${resource.cost?.[0]?.cost.value} ${resource.cost?.[0]?.cost.currency}`, - }, - { - title: Actions, - dataIndex: 'actions', - key: 'actions', - render: (_text, resource) => ( - - ), - }, - ]} - loading={isLoading(medicationKnowledgeResponse) && { indicator: SpinIndicator }} - /> - } - /> + variant="with-table" + headerRightColumn={} + header={{ + children: ( + onChange(selectedOption, 'medication')} + reset={resetFilter} + /> + ), + }} + > +
{ + return { ...{ key: resourceData.id }, ...resourceData }; + }) + : [] + } + expandable={{ + expandedRowRender: (record) => , + }} + columns={[ + { + title: Name, + dataIndex: 'name', + key: 'name', + render: (_text, resource) => resource.code?.coding?.[0]?.display, + }, + { + title: Cost, + dataIndex: 'cost', + key: 'cost', + render: (_text, resource) => + `${resource.cost?.[0]?.cost.value} ${resource.cost?.[0]?.cost.currency}`, + }, + { + title: Actions, + dataIndex: 'actions', + key: 'actions', + render: (_text, resource) => ( + + ), + }, + ]} + loading={isLoading(medicationKnowledgeResponse) && { indicator: SpinIndicator }} + /> + ); } diff --git a/src/containers/OrganizationScheduling/Calendar.styles.ts b/src/containers/OrganizationScheduling/Calendar.styles.ts index d77dd09d..378a5012 100644 --- a/src/containers/OrganizationScheduling/Calendar.styles.ts +++ b/src/containers/OrganizationScheduling/Calendar.styles.ts @@ -1,23 +1,6 @@ -import { Layout } from 'antd'; import styled from 'styled-components'; export const S = { - SearchBarContainer: styled(Layout)` - position: relative; - padding: 16px; - border-radius: 10px; - background-color: ${({ theme }) => theme.primaryPalette.bcp_3}; - display: flex; - flex-direction: row; - justify-content: space-between; - gap: 16px 32px; - flex-wrap: wrap; - - .ant-input-search, - .ant-picker { - width: 264px; - } - `, Wrapper: styled.div` overflow-x: auto; `, diff --git a/src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/HealthcareServicePractitionerSelect.styles.ts b/src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/HealthcareServicePractitionerSelect.styles.ts index 16f76e7e..6ac1b0c5 100644 --- a/src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/HealthcareServicePractitionerSelect.styles.ts +++ b/src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/HealthcareServicePractitionerSelect.styles.ts @@ -6,7 +6,4 @@ export const S = { flex-direction: row; gap: 10px; `, - SelectWrapper: styled.div` - width: 250px; - `, }; diff --git a/src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/index.tsx b/src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/index.tsx index a7bea7a5..27f660ea 100644 --- a/src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/index.tsx +++ b/src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/index.tsx @@ -52,17 +52,15 @@ export function AsyncDropdown(props: AsyncDropdownProps) { } return ( - - - + ); } diff --git a/src/containers/OrganizationScheduling/index.tsx b/src/containers/OrganizationScheduling/index.tsx index 7cd03ae2..a10fb34b 100644 --- a/src/containers/OrganizationScheduling/index.tsx +++ b/src/containers/OrganizationScheduling/index.tsx @@ -1,11 +1,11 @@ import { Trans, t } from '@lingui/macro'; -import { Button, Row, notification } from 'antd'; +import { Button, notification } from 'antd'; import { RenderRemoteData } from '@beda.software/fhir-react'; -import { BasePageHeader, BasePageContent } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { Calendar } from 'src/components/Calendar'; -import { Title } from 'src/components/Typography'; +import { S as SearchBarStyles } from 'src/components/SearchBar/styles'; import { S } from './Calendar.styles'; import { HealthcareServicePractitionerSelect } from './HealthcareServicePractitionerSelect'; @@ -65,84 +65,85 @@ export function OrganizationScheduling() { ]; return ( - <> - - - <Trans>Scheduling</Trans> - - - - - onChange(selectedOption, 'healthcareService') - } - onChangePractitionerRole={(selectedOption) => onChange(selectedOption, 'practitionerRole')} + Scheduling} + header={{ + children: ( + + + + onChange(selectedOption, 'healthcareService') + } + onChangePractitionerRole={(selectedOption) => + onChange(selectedOption, 'practitionerRole') + } + /> + + + + ), + }} + > + + {({ slots, businessHours, allPractitionersAndPractitionerRoles, healthcareServices }) => ( + + - - - - - - - {({ slots, businessHours, allPractitionersAndPractitionerRoles, healthcareServices }) => ( - - openEditAppointment(id)} + onClose={closeAppointmentDetails} /> - {appointmentDetails && ( - openEditAppointment(id)} - onClose={closeAppointmentDetails} - /> - )} - {editingAppointmentId && ( - + )} + {newAppointmentData && + isAppointmentCreatingAvailable( + newAppointmentData, + selectedHealthcareService, + selectedPractitionerRole, + ) && ( + )} - {newAppointmentData && - isAppointmentCreatingAvailable( - newAppointmentData, - selectedHealthcareService, - selectedPractitionerRole, - ) && ( - - )} - - )} - - - + + )} + + ); } diff --git a/src/containers/PatientDetails/PatientDetailsTabs/index.tsx b/src/containers/PatientDetails/PatientDetailsTabs/index.tsx new file mode 100644 index 00000000..f2f17546 --- /dev/null +++ b/src/containers/PatientDetails/PatientDetailsTabs/index.tsx @@ -0,0 +1,53 @@ +import { t } from '@lingui/macro'; +import { useEffect, useMemo, useState } from 'react'; +import { useParams, useLocation, Link, useNavigate } from 'react-router-dom'; + +import { RouteItem } from 'src/components/BaseLayout/Sidebar/SidebarTop'; +import { Tabs } from 'src/components/Tabs'; + +export function PatientDetailsTabs(props: { extraMenuItems?: RouteItem[]; isDefaultRoutesDisabled?: boolean }) { + const location = useLocation(); + const params = useParams<{ id: string }>(); + const { extraMenuItems = [] } = props; + const navigate = useNavigate(); + + const menuItems: RouteItem[] = useMemo( + () => + (!props.isDefaultRoutesDisabled + ? [ + { label: t`Overview`, path: `/patients/${params.id}` }, + { label: t`Encounters`, path: `/patients/${params.id}/encounters` }, + { label: t`Documents`, path: `/patients/${params.id}/documents` }, + { label: t`Wearables`, path: `/patients/${params.id}/wearables` }, + { label: t`Orders`, path: `/patients/${params.id}/orders` }, + { label: t`Smart Apps`, path: `/patients/${params.id}/apps` }, + { label: t`Resources`, path: `/patients/${params.id}/resources` }, + ] + : [] + ).concat( + extraMenuItems.map(({ label, path }) => ({ + label, + path: `/patients/${params.id}` + path, + })), + ), + [props.isDefaultRoutesDisabled, params.id, extraMenuItems], + ); + + const [currentPath, setCurrentPath] = useState(location?.pathname); + + useEffect(() => { + setCurrentPath(location?.pathname); + }, [location]); + + return ( + ({ + key: route.path, + label: {route.label}, + }))} + onTabClick={(path) => navigate(path)} + /> + ); +} diff --git a/src/containers/PatientDetails/PatientDocument/index.tsx b/src/containers/PatientDetails/PatientDocument/index.tsx index c0352088..079565c8 100644 --- a/src/containers/PatientDetails/PatientDocument/index.tsx +++ b/src/containers/PatientDetails/PatientDocument/index.tsx @@ -8,7 +8,6 @@ import { RemoteData, isSuccess, notAsked } from '@beda.software/remote-data'; import { BaseQuestionnaireResponseForm } from 'src/components/BaseQuestionnaireResponseForm'; import { AnxietyScore, DepressionScore } from 'src/components/BaseQuestionnaireResponseForm/readonly-widgets/score'; import { Spinner } from 'src/components/Spinner'; -import { usePatientHeaderLocationTitle } from 'src/containers/PatientDetails/PatientHeader/hooks'; import s from './PatientDocument.module.scss'; import { S } from './PatientDocument.styles'; @@ -40,10 +39,6 @@ export function PatientDocument(props: PatientDocumentProps) { const { savedMessage } = useSavedMessage(draftSaveResponse); - usePatientHeaderLocationTitle({ - title: isSuccess(response) ? response.data.formData.context.questionnaire?.name ?? '' : '', - }); - return (
diff --git a/src/containers/PatientDetails/PatientDocumentDetails/index.tsx b/src/containers/PatientDetails/PatientDocumentDetails/index.tsx index be2ffe5f..5cf0f188 100644 --- a/src/containers/PatientDetails/PatientDocumentDetails/index.tsx +++ b/src/containers/PatientDetails/PatientDocumentDetails/index.tsx @@ -19,7 +19,6 @@ import { PatientDocumentData, usePatientDocument, } from 'src/containers/PatientDetails/PatientDocument/usePatientDocument'; -import { usePatientHeaderLocationTitle } from 'src/containers/PatientDetails/PatientHeader/hooks'; import { forceDeleteFHIRResource, getFHIRResources, patchFHIRResource } from 'src/services/fhir'; import { selectCurrentUserRoleResource } from 'src/utils/role'; import { isExternalQuestionnaire } from 'src/utils/smart-apps'; @@ -115,8 +114,6 @@ function PatientDocumentDetailsReadonly(props: { const navigate = useNavigate(); const { formData, reload, provenance, hideControls } = props; - usePatientHeaderLocationTitle({ title: formData.context.questionnaire?.name ?? '' }); - const patientId = location.pathname.split('/')[2]; const qrCompleted = formData.context.questionnaireResponse.status === 'completed'; const qrId = formData.context.questionnaireResponse.id; diff --git a/src/containers/PatientDetails/PatientDocuments/index.tsx b/src/containers/PatientDetails/PatientDocuments/index.tsx index db106298..6a39ee7b 100644 --- a/src/containers/PatientDetails/PatientDocuments/index.tsx +++ b/src/containers/PatientDetails/PatientDocuments/index.tsx @@ -1,12 +1,11 @@ import { PlusOutlined } from '@ant-design/icons'; -import { t, Trans } from '@lingui/macro'; +import { Trans } from '@lingui/macro'; import { Button } from 'antd'; import { Patient } from 'fhir/r4b'; import { useState } from 'react'; import { DocumentsList } from 'src/containers/DocumentsList'; import { ChooseDocumentToCreateModal } from 'src/containers/DocumentsList/ChooseDocumentToCreateModal'; -import { usePatientHeaderLocationTitle } from 'src/containers/PatientDetails/PatientHeader/hooks'; interface Props { patient: Patient; @@ -20,9 +19,6 @@ interface Props { export const PatientDocuments = (props: Props) => { const [modalOpened, setModalOpened] = useState(false); const { patient, hideCreateButton } = props; - const title = props.title ?? t`Documents`; - - usePatientHeaderLocationTitle({ title }); return ( <> diff --git a/src/containers/PatientDetails/PatientHeader/PatientHeader.module.scss b/src/containers/PatientDetails/PatientHeader/PatientHeader.module.scss deleted file mode 100644 index fda4c063..00000000 --- a/src/containers/PatientDetails/PatientHeader/PatientHeader.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -.menu { - position: relative; - background: 0; - display: flex; - margin: 0 -20px; - border-bottom: 0; - padding-bottom: 1px; -} \ No newline at end of file diff --git a/src/containers/PatientDetails/PatientHeader/context.ts b/src/containers/PatientDetails/PatientHeader/context.ts deleted file mode 100644 index 947e6d0b..00000000 --- a/src/containers/PatientDetails/PatientHeader/context.ts +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -export interface BreadCrumb { - name: string; - path?: string; -} - -interface PatientHeaderContextProps { - title: string; - breadcrumbs: BreadCrumb[]; - setBreadcrumbs?: (v: { [x: string]: string }) => void; -} - -export const PatientHeaderContext = React.createContext({ - title: '', - breadcrumbs: [], - setBreadcrumbs: undefined, -}); diff --git a/src/containers/PatientDetails/PatientHeader/hooks.ts b/src/containers/PatientDetails/PatientHeader/hooks.ts deleted file mode 100644 index 6376c5ce..00000000 --- a/src/containers/PatientDetails/PatientHeader/hooks.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { useContext, useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; - -import { PatientHeaderContext } from './context'; - -export function usePatientHeaderLocationTitle(config: { title: string }) { - const { setBreadcrumbs } = useContext(PatientHeaderContext); - const { title } = config; - const location = useLocation(); - - useEffect(() => { - setBreadcrumbs?.({ [location?.pathname]: title }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [title]); -} diff --git a/src/containers/PatientDetails/PatientHeader/index.tsx b/src/containers/PatientDetails/PatientHeader/index.tsx deleted file mode 100644 index 9adb34a7..00000000 --- a/src/containers/PatientDetails/PatientHeader/index.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import { t } from '@lingui/macro'; -import { Menu } from 'antd'; -import { Patient } from 'fhir/r4b'; -import _ from 'lodash'; -import { useContext, useEffect, useMemo, useState } from 'react'; -import { useParams, useLocation, Link } from 'react-router-dom'; - -import { BasePageHeader } from 'src/components/BaseLayout'; -import { RouteItem } from 'src/components/BaseLayout/Sidebar/SidebarTop'; -import { Breadcrumbs } from 'src/components/Breadcrumbs'; -import { Title } from 'src/components/Typography'; -import { renderHumanName } from 'src/utils/fhir'; -import { matchCurrentUserRole, Role } from 'src/utils/role'; - -import { BreadCrumb, PatientHeaderContext } from './context'; -import s from './PatientHeader.module.scss'; - -export function PatientHeaderContextProvider(props: React.HTMLAttributes & { patient: Patient }) { - const { children, patient } = props; - const [pageTitle] = useState(renderHumanName(patient.name?.[0])); - const params = useParams<{ id: string }>(); - const location = useLocation(); - const rootPath = useMemo(() => `/patients/${params.id}`, [params.id]); - - const [breadcrumbsMap, setBreadcrumbs] = useState({ - '/patients': t`Patients`, - [rootPath]: renderHumanName(patient.name?.[0]), - }); - - const breadcrumbs: BreadCrumb[] = useMemo(() => { - const isRoot = rootPath === location?.pathname; - const paths = _.toPairs(breadcrumbsMap); - - const result = _.chain(paths) - .map(([path, name]) => (location?.pathname.includes(path) ? [path, name] : undefined)) - .compact() - .sortBy(([path]) => path) - .map(([path, name]) => ({ path, name })) - .value() as BreadCrumb[]; - - return isRoot ? [...result, { name: t`Overview` }] : result; - }, [location?.pathname, breadcrumbsMap, rootPath]); - - return ( - { - const pathNames = breadcrumbs.map((b) => b.name); - const newPathName = _.toPairs(newPath)[0]?.[1]; - if (newPathName && pathNames.includes(newPathName)) { - return; - } - - setBreadcrumbs((prevValue) => ({ - ...prevValue, - ...newPath, - })); - }, - }} - > - {children} - - ); -} - -export function PatientHeader(props: { extraMenuItems?: RouteItem[]; isDefaultRoutesDisabled?: boolean }) { - const location = useLocation(); - const params = useParams<{ id: string }>(); - const { title, breadcrumbs } = useContext(PatientHeaderContext); - const { extraMenuItems = [] } = props; - - const menuItems: RouteItem[] = useMemo( - () => - (!props.isDefaultRoutesDisabled - ? [ - { label: t`Overview`, path: `/patients/${params.id}` }, - { label: t`Encounters`, path: `/patients/${params.id}/encounters` }, - { label: t`Documents`, path: `/patients/${params.id}/documents` }, - { label: t`Wearables`, path: `/patients/${params.id}/wearables` }, - { label: t`Orders`, path: `/patients/${params.id}/orders` }, - { label: t`Smart Apps`, path: `/patients/${params.id}/apps` }, - { label: t`Resources`, path: `/patients/${params.id}/resources` }, - ] - : [] - ).concat( - extraMenuItems.map(({ label, path }) => ({ - label, - path: `/patients/${params.id}` + path, - })), - ), - [props.isDefaultRoutesDisabled, params.id, extraMenuItems], - ); - - const [currentPath, setCurrentPath] = useState(location?.pathname); - - useEffect(() => { - setCurrentPath(location?.pathname); - }, [location]); - - const renderMenu = () => { - return ( - ({ - key: route.path, - label: {route.label}, - }))} - /> - ); - }; - - return ( - - breadcrumbs, - [Role.Patient]: () => breadcrumbs.slice(1), - [Role.Practitioner]: () => breadcrumbs, - [Role.Receptionist]: () => breadcrumbs, - })} - /> - {title} - {renderMenu()} - - ); -} diff --git a/src/containers/PatientDetails/PatientOrders/index.tsx b/src/containers/PatientDetails/PatientOrders/index.tsx index 924e675c..f33542a7 100644 --- a/src/containers/PatientDetails/PatientOrders/index.tsx +++ b/src/containers/PatientDetails/PatientOrders/index.tsx @@ -214,7 +214,7 @@ export function PatientOrders({ patient }: Props) { patient: patient.id, category: 'laboratory', status: 'final', - _sort: ['-_lastUpdated', '_id'], + _sort: ['-_lastUpdated'], _revinclude: ['Provenance:target'], _ilike: search, }} diff --git a/src/containers/PatientDetails/PatientResources/utils.tsx b/src/containers/PatientDetails/PatientResources/utils.tsx index e5c9458b..6e3575d0 100644 --- a/src/containers/PatientDetails/PatientResources/utils.tsx +++ b/src/containers/PatientDetails/PatientResources/utils.tsx @@ -39,7 +39,7 @@ export function getOptions(patient: WithId): Option[] { resourceType="MedicationStatement" params={{ patient: patient.id, - _sort: ['-_lastUpdated', '_id'], + _sort: ['-_lastUpdated'], _revinclude: ['Provenance:target'], }} getTableColumns={option.getTableColumns} @@ -74,7 +74,7 @@ export function getOptions(patient: WithId): Option[] { resourceType="Condition" params={{ patient: patient.id, - _sort: ['-_recorded-date', '_id'], + _sort: ['-_recorded-date'], _revinclude: ['Provenance:target'], }} getTableColumns={option.getTableColumns} @@ -113,7 +113,7 @@ export function getOptions(patient: WithId): Option[] { resourceType="AllergyIntolerance" params={{ patient: patient.id, - _sort: ['-_date', '_id'], + _sort: ['-_date'], _revinclude: ['Provenance:target'], }} getTableColumns={option.getTableColumns} @@ -152,7 +152,7 @@ export function getOptions(patient: WithId): Option[] { resourceType="Immunization" params={{ patient: patient.id, - _sort: ['-_date', '_id'], + _sort: ['-_date'], _revinclude: ['Provenance:target'], }} getTableColumns={option.getTableColumns} @@ -188,7 +188,7 @@ export function getOptions(patient: WithId): Option[] { params={{ patient: patient.id, status: 'active', - _sort: ['-_lastUpdated', '_id'], + _sort: ['-_lastUpdated'], _revinclude: ['Provenance:target'], }} getTableColumns={option.getTableColumns} @@ -235,7 +235,7 @@ export function getOptions(patient: WithId): Option[] { params={{ patient: patient.id, status: 'final', - _sort: ['-_lastUpdated', '_id'], + _sort: ['-_lastUpdated'], _revinclude: ['Provenance:target'], }} getTableColumns={option.getTableColumns} @@ -310,7 +310,7 @@ export function getOptions(patient: WithId): Option[] { resourceType="ServiceRequest" params={{ patient: patient.id, - _sort: ['-_lastUpdated', '_id'], + _sort: ['-_lastUpdated'], }} getTableColumns={option.getTableColumns} /> diff --git a/src/containers/PatientDetails/PatientWearables/index.tsx b/src/containers/PatientDetails/PatientWearables/index.tsx index f8f3a1fe..beb324dc 100644 --- a/src/containers/PatientDetails/PatientWearables/index.tsx +++ b/src/containers/PatientDetails/PatientWearables/index.tsx @@ -8,7 +8,6 @@ import { isFailure, isLoading } from '@beda.software/remote-data'; import { SpinIndicator, Spinner } from 'src/components/Spinner'; import { Table } from 'src/components/Table'; -import { usePatientHeaderLocationTitle } from 'src/containers/PatientDetails/PatientHeader/hooks'; import { usePatientWearablesData, WearablesDataRecord } from './hooks'; @@ -61,8 +60,6 @@ function getColumns(): ColumnsType { export function PatientWearables(props: PatientWearablesProps) { const [wearablesData] = usePatientWearablesData(props.patient); - usePatientHeaderLocationTitle({ title: t`Wearables` }); - if (isFailure(wearablesData)) { console.log('status', wearablesData.status); console.log('error', wearablesData.error); diff --git a/src/containers/PatientDetails/index.tsx b/src/containers/PatientDetails/index.tsx index f27e83eb..d6e768e8 100644 --- a/src/containers/PatientDetails/index.tsx +++ b/src/containers/PatientDetails/index.tsx @@ -5,20 +5,21 @@ import { useParams, Outlet, Route, Routes } from 'react-router-dom'; import { RenderRemoteData } from '@beda.software/fhir-react'; import { isSuccess } from '@beda.software/remote-data'; -import { BasePageContent } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { RouteItem } from 'src/components/BaseLayout/Sidebar/SidebarTop'; import { PatientEncounter } from 'src/components/PatientEncounter'; import { Spinner } from 'src/components/Spinner'; import { PatientReloadProvider } from 'src/containers/PatientDetails/Dashboard/contexts'; import { sharedAuthorizedPractitionerRoles } from 'src/sharedState'; +import { renderHumanName } from 'src/utils'; import { matchCurrentUserRole, selectCurrentUserRoleResource, Role } from 'src/utils/role'; import { usePatientResource } from './hooks'; import { PatientApps } from './PatientApps'; +import { PatientDetailsTabs } from './PatientDetailsTabs'; import { PatientDocument } from './PatientDocument'; import { PatientDocumentDetails } from './PatientDocumentDetails'; import { PatientDocuments } from './PatientDocuments'; -import { PatientHeader, PatientHeaderContextProvider } from './PatientHeader'; import { PatientOrders } from './PatientOrders'; import { PatientOverview } from './PatientOverviewDynamic'; import { PatientResources } from './PatientResources'; @@ -50,98 +51,89 @@ export const PatientDetails = (props: PatientDetailsProps) => { {({ patient }) => { return ( - - - - - - - - } - > - {!props.isDefaultRoutesDisabled && ( - <> - } /> - { - return {}; - }, - [Role.Practitioner]: (practitioner) => { - return { - participant: ( - sharedAuthorizedPractitionerRoles.getSharedState() || - [] - ) - .map((pr) => `PractitionerRole/${pr.id}`) - .join(','), - }; - }, - [Role.Patient]: () => { - return {}; - }, - [Role.Receptionist]: () => { - return {}; - }, - })} - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } /> - } /> - - )} - {embeddedPages?.flatMap(({ routes }) => routes)} - - - - + , + }} + > + + + + + } + > + {!props.isDefaultRoutesDisabled && ( + <> + } /> + { + return {}; + }, + [Role.Practitioner]: (practitioner) => { + return { + participant: ( + sharedAuthorizedPractitionerRoles.getSharedState() || + [] + ) + .map((pr) => `PractitionerRole/${pr.id}`) + .join(','), + }; + }, + [Role.Patient]: () => { + return {}; + }, + [Role.Receptionist]: () => { + return {}; + }, + })} + /> + } + /> + } + /> + } + /> + } + /> + } /> + } + /> + } + /> + } /> + } + /> + } /> + } /> + } /> + + )} + {embeddedPages?.flatMap(({ routes }) => routes)} + + + ); }} diff --git a/src/containers/PatientList/hooks.ts b/src/containers/PatientList/hooks.ts index 926d8a50..2d5b2db8 100644 --- a/src/containers/PatientList/hooks.ts +++ b/src/containers/PatientList/hooks.ts @@ -20,7 +20,7 @@ export function usePatientList(filterValues: ColumnFilterValue[], searchParams: : { name: patientFilterValue }; const defaultQueryParameters = { - _sort: ['-_lastUpdated', '_id'], + _sort: '-_lastUpdated', ...(patientFilterValue ? searchParamKeyForPatientName : {}), }; diff --git a/src/containers/PatientList/index.tsx b/src/containers/PatientList/index.tsx index 0d76d2fc..6be31ace 100644 --- a/src/containers/PatientList/index.tsx +++ b/src/containers/PatientList/index.tsx @@ -5,7 +5,7 @@ import { useNavigate } from 'react-router-dom'; import { isLoading, isSuccess } from '@beda.software/remote-data'; -import { BasePageContent, BasePageHeader } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { ModalNewPatient } from 'src/components/ModalNewPatient'; import { ModalTrigger } from 'src/components/ModalTrigger'; import { QuestionnaireResponseForm } from 'src/components/QuestionnaireResponseForm'; @@ -13,7 +13,6 @@ import { SearchBar } from 'src/components/SearchBar'; import { useSearchBar } from 'src/components/SearchBar/hooks'; import { SpinIndicator } from 'src/components/Spinner'; import { Table } from 'src/components/Table'; -import { Title } from 'src/components/Typography'; import { questionnaireIdLoader } from 'src/hooks/questionnaire-response-form-data'; import { formatHumanDate } from 'src/utils/date'; import { renderHumanName } from 'src/utils/fhir'; @@ -51,116 +50,108 @@ export function PatientList() { ); return ( - <> - - -
- - <Trans>Patients</Trans> - - - - - - - - - - - - pagination={pagination} - onChange={handleTableChange} - locale={{ - emptyText: ( - <> - No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> - - ), - }} - rowKey={(p) => p.id!} - dataSource={isSuccess(patientsResponse) ? patientsResponse.data : []} - columns={[ - { - title: Name, - dataIndex: 'name', - key: 'name', - render: (_text, resource) => renderHumanName(resource.name?.[0]), - }, - { - title: Birth date, - dataIndex: 'birthDate', - key: 'birthDate', - render: (_text, resource) => - resource.birthDate ? formatHumanDate(resource.birthDate) : null, - width: '25%', - }, - { - title: SSN, - dataIndex: 'identifier', - key: 'identifier', - render: (_text, resource) => - resource.identifier?.find(({ system }) => system === 'http://hl7.org/fhir/sid/us-ssn') - ?.value, - width: '25%', - }, - { - title: Actions, - dataIndex: 'actions', - key: 'actions', - render: (_text, resource) => { - return ( - - - - - - - Edit - - } - > - {({ closeModal }) => ( - { - notification.success({ - message: t`Patient saved`, - }); - pagerManager.reload(); - closeModal(); - }} - onCancel={closeModal} - /> - )} - - - - ); - }, - width: 200, + Patients} + headerRightColumn={} + header={{ + children: ( + + ), + }} + > + + pagination={pagination} + onChange={handleTableChange} + locale={{ + emptyText: ( + <> + No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> + + ), + }} + rowKey={(p) => p.id!} + dataSource={isSuccess(patientsResponse) ? patientsResponse.data : []} + columns={[ + { + title: Name, + dataIndex: 'name', + key: 'name', + render: (_text, resource) => renderHumanName(resource.name?.[0]), + }, + { + title: Birth date, + dataIndex: 'birthDate', + key: 'birthDate', + render: (_text, resource) => (resource.birthDate ? formatHumanDate(resource.birthDate) : null), + width: '25%', + }, + { + title: SSN, + dataIndex: 'identifier', + key: 'identifier', + render: (_text, resource) => + resource.identifier?.find(({ system }) => system === 'http://hl7.org/fhir/sid/us-ssn') + ?.value, + width: '25%', + }, + { + title: Actions, + dataIndex: 'actions', + key: 'actions', + render: (_text, resource) => { + return ( + + + + + + + Edit + + } + > + {({ closeModal }) => ( + { + notification.success({ + message: t`Patient saved`, + }); + pagerManager.reload(); + closeModal(); + }} + onCancel={closeModal} + /> + )} + + + + ); }, - ]} - loading={isLoading(patientsResponse) && { indicator: SpinIndicator }} - /> - - + width: 200, + }, + ]} + loading={isLoading(patientsResponse) && { indicator: SpinIndicator }} + /> + ); } diff --git a/src/containers/PatientQuestionnaire/index.tsx b/src/containers/PatientQuestionnaire/index.tsx index 76b43c77..5ef8b302 100644 --- a/src/containers/PatientQuestionnaire/index.tsx +++ b/src/containers/PatientQuestionnaire/index.tsx @@ -7,9 +7,9 @@ import { axiosInstance as axiosAidboxInstance } from 'aidbox-react/lib/services/ import { RenderRemoteData, WithId, useService } from '@beda.software/fhir-react'; -import { BasePageContent, BasePageHeader } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { Spinner } from 'src/components/Spinner'; -import { Paragraph, Title } from 'src/components/Typography'; +import { Paragraph } from 'src/components/Typography'; import { getToken } from 'src/services/auth'; import { axiosInstance as axiosFHIRInstance, getFHIRResource } from 'src/services/fhir'; import { selectCurrentUserRoleResource } from 'src/utils/role'; @@ -67,17 +67,9 @@ export function PatientQuestionnaire({ onSuccess }: { onSuccess?: () => void }) }, [isAnonymousUser]); return ( - <> - - - <Trans>Questionnaire</Trans> - - - - - {isLoading ? : } - - + Questionnaire} content={{ style: { alignItems: 'center' } }}> + {isLoading ? : } + ); } diff --git a/src/containers/PatientResourceListExample/index.tsx b/src/containers/PatientResourceListExample/index.tsx new file mode 100644 index 00000000..23f310bd --- /dev/null +++ b/src/containers/PatientResourceListExample/index.tsx @@ -0,0 +1,128 @@ +import { PlusOutlined } from '@ant-design/icons'; +import { t, Trans } from '@lingui/macro'; +import { Patient } from 'fhir/r4b'; + +import { SearchBarColumnType } from 'src/components/SearchBar/types'; +import { ResourceListPage } from 'src/uberComponents'; +import { customAction, navigationAction, questionnaireAction } from 'src/uberComponents/ResourceListPage/actions'; +import { formatHumanDate } from 'src/utils/date'; +import { renderHumanName } from 'src/utils/fhir'; +import { matchCurrentUserRole, Role } from 'src/utils/role'; + +import { getPatientSearchParamsForPractitioner } from './utils'; +import { S } from './styles'; + +export function PatientResourceListExample() { + /* + This page is just an example how the page can be constructed using ResourceList + */ + const searchParams = matchCurrentUserRole({ + [Role.Admin]: () => { + return {}; + }, + [Role.Practitioner]: (practitioner) => { + return getPatientSearchParamsForPractitioner(practitioner.id); + }, + [Role.Receptionist]: () => { + return {}; + }, + [Role.Patient]: () => { + return {}; + }, + }); + + return ( + + headerTitle={t`Patients`} + resourceType="Patient" + searchParams={searchParams} + getTableColumns={() => [ + { + title: Name, + dataIndex: 'name', + key: 'name', + render: (_text, { resource }) => renderHumanName(resource.name?.[0]), + width: 300, + }, + { + title: Birth date, + dataIndex: 'birthDate', + key: 'birthDate', + render: (_text, { resource }) => (resource.birthDate ? formatHumanDate(resource.birthDate) : null), + width: 150, + }, + { + title: Gender, + dataIndex: 'gender', + key: 'gender', + render: (_text, { resource }) => resource.gender, + width: 150, + }, + { + title: SSN, + dataIndex: 'identifier', + key: 'identifier', + render: (_text, { resource }) => + resource.identifier?.find(({ system }) => system === 'http://hl7.org/fhir/sid/us-ssn')?.value, + width: 250, + }, + ]} + getFilters={() => [ + { + id: 'name', + searchParam: 'name', + type: SearchBarColumnType.STRING, + placeholder: t`Find patient`, + placement: ['search-bar', 'table'], + }, + { + id: 'birthDate', + searchParam: 'birthdate', + type: SearchBarColumnType.SINGLEDATE, + placeholder: t`Birth date`, + placement: ['table'], + }, + { + id: 'gender', + searchParam: 'gender', + type: SearchBarColumnType.CHOICE, + placeholder: t`Choose gender`, + options: [ + { + value: { + Coding: { + code: 'male', + display: 'Male', + }, + }, + }, + { + value: { + Coding: { + code: 'female', + display: 'Female', + }, + }, + }, + ], + placement: ['table'], + }, + ]} + getRecordActions={(record) => [ + navigationAction('Open', `/patients/${record.resource.id}`), + questionnaireAction('Edit', 'patient-edit'), + customAction(Custom action), + ]} + getHeaderActions={() => [ + questionnaireAction(Add patient, 'patient-create', { icon: }), + ]} + getBatchActions={() => [questionnaireAction(Delete patients, 'patients-batch-delete')]} + getReportColumns={(bundle) => [ + { + title: t`Number of Patients`, + value: bundle.total, + }, + ]} + > + ); +} diff --git a/src/containers/PatientResourceListExample/styles.ts b/src/containers/PatientResourceListExample/styles.ts new file mode 100644 index 00000000..f1d09a89 --- /dev/null +++ b/src/containers/PatientResourceListExample/styles.ts @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +import { Button } from 'antd'; + +export const S = { + LinkButton: styled(Button)` + padding: 0; + `, +}; diff --git a/src/containers/PatientResourceListExample/utils.ts b/src/containers/PatientResourceListExample/utils.ts new file mode 100644 index 00000000..64291fce --- /dev/null +++ b/src/containers/PatientResourceListExample/utils.ts @@ -0,0 +1,13 @@ +import { formatFHIRDate } from 'aidbox-react/lib/utils/date'; + +import { SearchParams } from '@beda.software/fhir-react'; + +export function getPatientSearchParamsForPractitioner(practitionerId: string): SearchParams { + return { + status: 'active', + category: 'data-sharing', + period: formatFHIRDate(new Date()), + actor: practitionerId, + _include: ['Consent:patient:Patient'], + }; +} diff --git a/src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx b/src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx new file mode 100644 index 00000000..14263d78 --- /dev/null +++ b/src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx @@ -0,0 +1,48 @@ +import { t } from '@lingui/macro'; +import { Practitioner, PractitionerRole } from 'fhir/r4b'; +import { useEffect, useMemo, useState } from 'react'; +import { useParams, useLocation, Link, useNavigate } from 'react-router-dom'; + +import { WithId } from '@beda.software/fhir-react'; + +import { RouteItem } from 'src/components/BaseLayout/Sidebar/SidebarTop'; +import { Tabs } from 'src/components/Tabs'; + +interface Props { + practitioner: WithId; + practitionerRole?: WithId; +} + +export function PractitionerDetailsTabs(props: Props) { + const { practitionerRole } = props; + const location = useLocation(); + const params = useParams<{ id: string }>(); + const navigate = useNavigate(); + + const menuItems: RouteItem[] = useMemo( + () => [ + { label: t`Overview`, path: `/practitioners/${params.id}` }, + { label: t`Scheduling`, path: `/practitioners/${params.id}/scheduling`, disabled: !practitionerRole }, + { label: t`Availability`, path: `/practitioners/${params.id}/availability`, disabled: !practitionerRole }, + ], + [params.id, practitionerRole], + ); + + const [currentPath, setCurrentPath] = useState(location?.pathname); + + useEffect(() => { + setCurrentPath(location?.pathname); + }, [location]); + + return ( + ({ + key: route.path, + label: {route.label}, + }))} + onTabClick={(path) => navigate(path)} + /> + ); +} diff --git a/src/containers/PractitionerDetails/PractitionerHeader/PractitionerHeader.module.scss b/src/containers/PractitionerDetails/PractitionerHeader/PractitionerHeader.module.scss deleted file mode 100644 index fda4c063..00000000 --- a/src/containers/PractitionerDetails/PractitionerHeader/PractitionerHeader.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -.menu { - position: relative; - background: 0; - display: flex; - margin: 0 -20px; - border-bottom: 0; - padding-bottom: 1px; -} \ No newline at end of file diff --git a/src/containers/PractitionerDetails/PractitionerHeader/index.tsx b/src/containers/PractitionerDetails/PractitionerHeader/index.tsx deleted file mode 100644 index daef0a0b..00000000 --- a/src/containers/PractitionerDetails/PractitionerHeader/index.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { t } from '@lingui/macro'; -import { Menu } from 'antd'; -import { Practitioner, PractitionerRole } from 'fhir/r4b'; -import _ from 'lodash'; -import { useEffect, useMemo, useState } from 'react'; -import { useParams, useLocation, Link } from 'react-router-dom'; - -import { WithId } from '@beda.software/fhir-react'; - -import { BasePageHeader } from 'src/components/BaseLayout'; -import { RouteItem } from 'src/components/BaseLayout/Sidebar/SidebarTop'; -import { Breadcrumbs } from 'src/components/Breadcrumbs'; -import { Title } from 'src/components/Typography'; -import { renderHumanName } from 'src/utils/fhir'; - -import s from './PractitionerHeader.module.scss'; - -interface BreadCrumb { - name: string; - path?: string; -} - -interface Props { - practitioner: WithId; - practitionerRole?: WithId; -} - -function usePractitionerHeader(props: Props) { - const { practitioner } = props; - const pageTitle = useMemo(() => renderHumanName(practitioner.name?.[0]), [practitioner]); - const params = useParams<{ id: string }>(); - const location = useLocation(); - const rootPath = useMemo(() => `/practitioners/${params.id}`, [params.id]); - - const breadcrumbsMap = useMemo( - () => ({ - '/practitioners': t`Practitioners`, - [rootPath]: pageTitle, - [`${rootPath}/scheduling`]: t`Scheduling`, - [`${rootPath}/availability`]: t`Availability`, - }), - [pageTitle, rootPath], - ); - - const breadcrumbs: BreadCrumb[] = useMemo(() => { - const isRoot = rootPath === location?.pathname; - const paths = _.toPairs(breadcrumbsMap); - - const result = _.chain(paths) - .map(([path, name]) => (location?.pathname.includes(path) ? [path, name] : undefined)) - .compact() - .sortBy(([path]) => path) - .map(([path, name]) => ({ path, name })) - .value() as BreadCrumb[]; - - return isRoot ? [...result, { name: t`Overview` }] : result; - }, [location?.pathname, breadcrumbsMap, rootPath]); - - return { pageTitle, breadcrumbs }; -} - -export function PractitionerHeader(props: Props) { - const { practitionerRole } = props; - const location = useLocation(); - const params = useParams<{ id: string }>(); - const { pageTitle, breadcrumbs } = usePractitionerHeader(props); - - const menuItems: RouteItem[] = useMemo( - () => [ - { label: t`Overview`, path: `/practitioners/${params.id}` }, - { label: t`Scheduling`, path: `/practitioners/${params.id}/scheduling`, disabled: !practitionerRole }, - { label: t`Availability`, path: `/practitioners/${params.id}/availability`, disabled: !practitionerRole }, - ], - [params.id, practitionerRole], - ); - - const [currentPath, setCurrentPath] = useState(location?.pathname); - - useEffect(() => { - setCurrentPath(location?.pathname); - }, [location]); - - const renderMenu = () => { - return ( - ({ - key: route.path, - label: route.disabled ? route.label : {route.label}, - disabled: route.disabled, - }))} - /> - ); - }; - - return ( - - - {pageTitle} - {renderMenu()} - - ); -} diff --git a/src/containers/PractitionerDetails/index.tsx b/src/containers/PractitionerDetails/index.tsx index 8fafe275..0a30dcc1 100644 --- a/src/containers/PractitionerDetails/index.tsx +++ b/src/containers/PractitionerDetails/index.tsx @@ -4,11 +4,12 @@ import { Outlet, Route, Routes, useNavigate, useParams } from 'react-router-dom' import { RenderRemoteData, WithId, extractBundleResources, useService } from '@beda.software/fhir-react'; import { mapSuccess } from '@beda.software/remote-data'; -import { BasePageContent } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { Spinner } from 'src/components/Spinner'; import { getFHIRResources } from 'src/services/fhir'; +import { renderHumanName } from 'src/utils'; -import { PractitionerHeader } from './PractitionerHeader'; +import { PractitionerDetailsTabs } from './PractitionerDetailsTabs'; import { PractitionerOverview } from './PractitionerOverview'; import { Availability } from '../Scheduling/Availability'; import { ScheduleCalendar } from '../Scheduling/ScheduleCalendar'; @@ -40,57 +41,65 @@ export const PractitionerDetails = () => { {({ practitioner, practitionerRole, healthcareServices }) => { return ( - <> - - - + + ), + }} + > + + + + + } + > - - + } - > - - } - /> - {practitionerRole ? ( - <> - } - /> - ) => { - navigate(`/practitioners/${practitioner.id}/scheduling`); - manager.set({ - practitioner, - practitionerRole: updatedPR, - healthcareServices, - }); - }} - /> - } - /> - - ) : null} - - - - + /> + {practitionerRole ? ( + <> + } + /> + ) => { + navigate(`/practitioners/${practitioner.id}/scheduling`); + manager.set({ + practitioner, + practitionerRole: updatedPR, + healthcareServices, + }); + }} + /> + } + /> + + ) : null} + + + ); }} diff --git a/src/containers/PractitionerList/hooks.ts b/src/containers/PractitionerList/hooks.ts index 9ba205d3..9982b8ee 100644 --- a/src/containers/PractitionerList/hooks.ts +++ b/src/containers/PractitionerList/hooks.ts @@ -25,7 +25,7 @@ export function usePractitionersList(filterValues: ColumnFilterValue[] | undefin const practitionerFilterValue = getSearchBarFilterValue(filterValues, 'practitioner'); const queryParameters = { - _sort: ['-_lastUpdated', '_id'], + _sort: '-_lastUpdated', name: practitionerFilterValue, }; diff --git a/src/containers/PractitionerList/index.tsx b/src/containers/PractitionerList/index.tsx index 29cc4d17..922965c6 100644 --- a/src/containers/PractitionerList/index.tsx +++ b/src/containers/PractitionerList/index.tsx @@ -1,12 +1,12 @@ import { PlusOutlined } from '@ant-design/icons'; import { t, Trans } from '@lingui/macro'; -import { Button, Col, Empty, notification, Row } from 'antd'; +import { Button, Empty, notification } from 'antd'; import { Practitioner } from 'fhir/r4b'; import { useNavigate } from 'react-router-dom'; import { isLoading, isSuccess } from '@beda.software/remote-data'; -import { BasePageContent, BasePageHeader } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { ModalTrigger } from 'src/components/ModalTrigger'; import { QuestionnaireResponseForm } from 'src/components/QuestionnaireResponseForm'; import { SearchBar } from 'src/components/SearchBar'; @@ -14,7 +14,6 @@ import { useSearchBar } from 'src/components/SearchBar/hooks'; import { StringTypeColumnFilterValue } from 'src/components/SearchBar/types'; import { SpinIndicator } from 'src/components/Spinner'; import { Table } from 'src/components/Table'; -import { Title } from 'src/components/Typography'; import { questionnaireIdLoader } from 'src/hooks/questionnaire-response-form-data'; import { usePractitionersList } from './hooks'; @@ -69,84 +68,79 @@ export function PractitionerList(props: PractitionerListProps) { ); return ( - <> - - - - - <Trans>Practitioners</Trans> - - - - { - practitionerListReload(); - notification.success({ - message: t`Practitioner successfully created`, - }); - }} - /> - - - - - - -
- No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> - - ), + Practitioners} + headerRightColumn={ + { + practitionerListReload(); + notification.success({ + message: t`Practitioner successfully created`, + }); }} - dataSource={isSuccess(practitionerDataListRD) ? practitionerDataListRD.data : []} - columns={[ - { - title: Name, - dataIndex: 'practitionerName', - key: 'practitionerName', - width: '20%', - }, - { - title: Specialty, - dataIndex: 'practitionerRoleList', - key: 'practitionerRoleList', - width: '30%', - render: (specialties: string[]) => specialties.join(', '), - }, - { - title: Actions, - dataIndex: 'practitionerResource', - key: 'actions', - width: '5%', - render: (practitioner: Practitioner) => { - return ( - - ); - }, - }, - ]} - loading={isLoading(practitionerDataListRD) && { indicator: SpinIndicator }} /> - - + } + header={{ + children: ( + + ), + }} + > +
+ No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> + + ), + }} + dataSource={isSuccess(practitionerDataListRD) ? practitionerDataListRD.data : []} + columns={[ + { + title: Name, + dataIndex: 'practitionerName', + key: 'practitionerName', + width: '20%', + }, + { + title: Specialty, + dataIndex: 'practitionerRoleList', + key: 'practitionerRoleList', + width: '30%', + render: (specialties: string[]) => specialties.join(', '), + }, + { + title: Actions, + dataIndex: 'practitionerResource', + key: 'actions', + width: '5%', + render: (practitioner: Practitioner) => { + return ( + + ); + }, + }, + ]} + loading={isLoading(practitionerDataListRD) && { indicator: SpinIndicator }} + /> + ); } diff --git a/src/containers/Prescriptions/components/PrescriptionsSearchBar/PrescriptionsSearchBar.styles.ts b/src/containers/Prescriptions/components/PrescriptionsSearchBar/PrescriptionsSearchBar.styles.ts deleted file mode 100644 index 66c51f4d..00000000 --- a/src/containers/Prescriptions/components/PrescriptionsSearchBar/PrescriptionsSearchBar.styles.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Layout } from 'antd'; -import styled from 'styled-components'; - -export const S = { - Container: styled(Layout)` - position: relative; - padding: 16px; - border-radius: 10px; - background-color: ${({ theme }) => theme.primaryPalette.bcp_3}; - display: flex; - flex-direction: row; - justify-content: space-between; - gap: 16px 32px; - flex-wrap: wrap; - - .ant-input-search, - .ant-picker { - width: 264px; - } - `, - SelectContainer: styled.div` - margin-left: 16px; - display: flex; - flex-direction: row; - gap: 32px; - `, -}; diff --git a/src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx b/src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx index fa2b7207..613afcfe 100644 --- a/src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx +++ b/src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx @@ -1,6 +1,7 @@ import { t } from '@lingui/macro'; -import { Row, Button } from 'antd'; +import { Button } from 'antd'; +import { S } from 'src/components/SearchBar/styles'; import { AsyncDropdown } from 'src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect'; import { OptionType, @@ -8,8 +9,6 @@ import { } from 'src/containers/OrganizationScheduling/HealthcareServicePractitionerSelect/types'; import { Role, matchCurrentUserRole } from 'src/utils/role'; -import { S } from './PrescriptionsSearchBar.styles'; - export interface PrescriptionsSearchBarSelectProps { selectedPatient: SelectOption; selectedPractitionerRole: SelectOption; @@ -38,37 +37,35 @@ export function PrescriptionsSearchBar(props: PrescriptionsSearchBarSelectProps) } = props; return ( - - - - - + + + - + ); } diff --git a/src/containers/Prescriptions/hooks.ts b/src/containers/Prescriptions/hooks.ts index 88b681b5..3d693d31 100644 --- a/src/containers/Prescriptions/hooks.ts +++ b/src/containers/Prescriptions/hooks.ts @@ -16,7 +16,7 @@ export function useMedicationRequest(requesterId?: string, subjectId?: string, s 'MedicationRequest:requester', 'MedicationRequest:medication:Medication', ], - _sort: ['-_createdAt', '_id'], + _sort: '-_createdAt', }; const { resourceResponse, pagerManager, handleTableChange, pagination } = usePagerExtended< diff --git a/src/containers/Prescriptions/index.tsx b/src/containers/Prescriptions/index.tsx index 336de714..4878c5dc 100644 --- a/src/containers/Prescriptions/index.tsx +++ b/src/containers/Prescriptions/index.tsx @@ -1,11 +1,11 @@ import { t, Trans } from '@lingui/macro'; -import { Table } from 'antd'; import { Medication, MedicationRequest } from 'fhir/r4b'; import { extractExtension } from 'sdc-qrf'; import { RenderRemoteData } from '@beda.software/fhir-react'; -import { PageContainer } from 'src/components/PageContainer'; +import { Table } from 'src/components'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { Spinner } from 'src/components/Spinner'; import { formatHumanDate } from 'src/utils/date'; import { renderHumanName } from 'src/utils/fhir'; @@ -46,136 +46,132 @@ export function Prescriptions() { return ( onChange(selectedOption, 'patient')} - onChangePractitionerRole={(selectedOption) => onChange(selectedOption, 'practitionerRole')} - onChangeStatus={(selectedOption) => onChange(selectedOption, 'status')} - reset={resetFilter} - /> - } - content={ - - {({ patients, organizations, practitioners, medications, medicationRequests }) => { - return ( -
Patient, - dataIndex: 'name', - key: 'name', - render: (_text, resource) => - renderHumanName( - patients.find( - (patient) => - patient.id === resource.subject.reference?.split('/')?.[1], - )?.name?.[0], - ), - }, - { - title: Requester, - dataIndex: 'requester', - key: 'requester', - render: (_text, resource) => { - const requesterId = resource.requester?.reference?.split('/')?.[1]; - const requesterResourceType = - resource.requester?.reference?.split('/')?.[0]; - if (requesterResourceType === 'Organization') { - const currentOrganization = organizations.find( - (organization) => organization.id === requesterId, - ); - return currentOrganization?.name; - } + variant="with-table" + header={{ + children: ( + onChange(selectedOption, 'patient')} + onChangePractitionerRole={(selectedOption) => onChange(selectedOption, 'practitionerRole')} + onChangeStatus={(selectedOption) => onChange(selectedOption, 'status')} + reset={resetFilter} + /> + ), + }} + > + + {({ patients, organizations, practitioners, medications, medicationRequests }) => { + return ( +
Patient, + dataIndex: 'name', + key: 'name', + render: (_text, resource) => + renderHumanName( + patients.find( + (patient) => patient.id === resource.subject.reference?.split('/')?.[1], + )?.name?.[0], + ), + }, + { + title: Requester, + dataIndex: 'requester', + key: 'requester', + render: (_text, resource) => { + const requesterId = resource.requester?.reference?.split('/')?.[1]; + const requesterResourceType = resource.requester?.reference?.split('/')?.[0]; + if (requesterResourceType === 'Organization') { + const currentOrganization = organizations.find( + (organization) => organization.id === requesterId, + ); + return currentOrganization?.name; + } - if (requesterResourceType === 'Practitioner') { - const currentPractitioner = practitioners.find( - (practitioner) => practitioner.id === requesterId, - ); - return renderHumanName(currentPractitioner?.name?.[0]); - } + if (requesterResourceType === 'Practitioner') { + const currentPractitioner = practitioners.find( + (practitioner) => practitioner.id === requesterId, + ); + return renderHumanName(currentPractitioner?.name?.[0]); + } - return resource.id; - }, - }, - { - title: Medication, - dataIndex: 'medication', - key: 'medication', - render: (_text, resource) => { - const medicationResource = findCurrentMedication(medications, resource); - const medicationName = medicationResource - ? medicationResource.code?.coding?.[0]?.display - : resource?.medicationCodeableConcept?.coding?.[0]?.display; - return medicationName ?? 'Unknown'; - }, + return resource.id; }, - { - title: Batch Number, - dataIndex: 'batchNumber', - key: 'batchNumber', - render: (_text, resource) => - findCurrentMedication(medications, resource)?.batch?.lotNumber ?? 'Unknown', + }, + { + title: Medication, + dataIndex: 'medication', + key: 'medication', + render: (_text, resource) => { + const medicationResource = findCurrentMedication(medications, resource); + const medicationName = medicationResource + ? medicationResource.code?.coding?.[0]?.display + : resource?.medicationCodeableConcept?.coding?.[0]?.display; + return medicationName ?? 'Unknown'; }, - { - title: Status, - dataIndex: 'status', - key: 'status', - render: (_text, resource) => mapPrescriptionStatus(resource), - }, - { - title: Date, - dataIndex: 'date', - key: 'date', - render: (_text, resource) => { - const createdAt = extractExtension( - resource.meta?.extension, - 'ex:createdAt', - ); + }, + { + title: Batch Number, + dataIndex: 'batchNumber', + key: 'batchNumber', + render: (_text, resource) => + findCurrentMedication(medications, resource)?.batch?.lotNumber ?? 'Unknown', + }, + { + title: Status, + dataIndex: 'status', + key: 'status', + render: (_text, resource) => mapPrescriptionStatus(resource), + }, + { + title: Date, + dataIndex: 'date', + key: 'date', + render: (_text, resource) => { + const createdAt = extractExtension(resource.meta?.extension, 'ex:createdAt'); - return createdAt ? formatHumanDate(createdAt) : null; - }, + return createdAt ? formatHumanDate(createdAt) : null; }, - { - title: Actions, - dataIndex: 'actions', - key: 'actions', - render: (_text, resource) => { - const currentMedication = findCurrentMedication(medications, resource); - return ( -
- - -
- ); - }, + }, + { + title: Actions, + dataIndex: 'actions', + key: 'actions', + render: (_text, resource) => { + const currentMedication = findCurrentMedication(medications, resource); + return ( +
+ + +
+ ); }, - ]} - /> - ); - }} - - } - /> + }, + ]} + /> + ); + }} + + ); } diff --git a/src/containers/QuestionnaireBuilder/index.tsx b/src/containers/QuestionnaireBuilder/index.tsx index 6148f96a..f403b58b 100644 --- a/src/containers/QuestionnaireBuilder/index.tsx +++ b/src/containers/QuestionnaireBuilder/index.tsx @@ -1,6 +1,6 @@ import { CloseOutlined } from '@ant-design/icons'; import { t, Trans } from '@lingui/macro'; -import { Button, Col, Row } from 'antd'; +import { Button } from 'antd'; import { Questionnaire } from 'fhir/r4b'; import React, { useState } from 'react'; import { GroupItemProps, QuestionItemProps } from 'sdc-qrf/lib/types'; @@ -8,9 +8,8 @@ import { GroupItemProps, QuestionItemProps } from 'sdc-qrf/lib/types'; import { RenderRemoteData } from '@beda.software/fhir-react'; import { isLoading } from '@beda.software/remote-data'; -import { BasePageContent, BasePageHeader } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { ModalTrigger } from 'src/components/ModalTrigger'; -import { Title } from 'src/components/Typography'; import { Builder } from './Builder'; import { useQuestionnaireBuilder } from './hooks'; @@ -40,106 +39,98 @@ export function QuestionnaireBuilder() { const [groupItem, setGroupItem] = useState(); return ( - <> - -
- -
- - <Trans>Build your form</Trans> - - - - - {(questionnaire: Questionnaire) => { - return questionnaire.item ? ( - {t`Save questionnaire`}} - > - {({ closeModal }) => { - return ( - - ); - }} - - ) : ( - + Build your form} + headerRightColumn={ + + {(questionnaire: Questionnaire) => { + return questionnaire.item ? ( + {t`Save questionnaire`}} + > + {({ closeModal }) => { + return ( + ); }} - - - + + ) : ( + + ); + }} + + } + content={{ + className: s.container, + }} + > + +
+ { + if (item?.questionItem.type === 'group') { + setGroupItem(item as GroupItemProps); + setQuestionnaireItem(undefined); + } else { + setQuestionnaireItem(item as QuestionItemProps); + setGroupItem(undefined); + } + }} + onItemDrag={onItemDrag} + />
- - - -
- { - if (item?.questionItem.type === 'group') { - setGroupItem(item as GroupItemProps); + + {questionnaireItem || groupItem ? ( +
+ { setQuestionnaireItem(undefined); - } else { - setQuestionnaireItem(item as QuestionItemProps); setGroupItem(undefined); - } - }} - onItemDrag={onItemDrag} - /> -
- - {questionnaireItem || groupItem ? ( -
- { - setQuestionnaireItem(undefined); - setGroupItem(undefined); - }} - > - - - { - setQuestionnaireItem(undefined); - setGroupItem(undefined); - onItemChange(item); - }} - onDelete={(item) => { - setQuestionnaireItem(undefined); - setGroupItem(undefined); - onItemDelete(item); - }} - /> -
- ) : null} - onSubmitPrompt(prompt)} - onUploadFile={onUploadFile} - onPromptSelect={(prompt) => onPromptSelect(prompt)} - selectedPrompt={selectedPrompt} - isLoading={isLoading(response) || isLoading(updateResponse)} - editHistory={editHistory} - onPromptDelete={onPromptDelete} - /> -
- - - + + + { + setQuestionnaireItem(undefined); + setGroupItem(undefined); + onItemChange(item); + }} + onDelete={(item) => { + setQuestionnaireItem(undefined); + setGroupItem(undefined); + onItemDelete(item); + }} + /> +
+ ) : null} + onSubmitPrompt(prompt)} + onUploadFile={onUploadFile} + onPromptSelect={(prompt) => onPromptSelect(prompt)} + selectedPrompt={selectedPrompt} + isLoading={isLoading(response) || isLoading(updateResponse)} + editHistory={editHistory} + onPromptDelete={onPromptDelete} + /> + +
+ ); } diff --git a/src/containers/QuestionnaireList/hooks.ts b/src/containers/QuestionnaireList/hooks.ts index d5216c7d..d82f89c1 100644 --- a/src/containers/QuestionnaireList/hooks.ts +++ b/src/containers/QuestionnaireList/hooks.ts @@ -14,7 +14,7 @@ export function useQuestionnaireList(filterValues: ColumnFilterValue[]) { const questionnaireFilterValue = getSearchBarFilterValue(filterValues, 'questionnaire'); const queryParameters = { - _sort: ['-_lastUpdated', '_id'], + _sort: '-_lastUpdated', name: questionnaireFilterValue, }; diff --git a/src/containers/QuestionnaireList/index.tsx b/src/containers/QuestionnaireList/index.tsx index 7589ea4e..d2bbc628 100644 --- a/src/containers/QuestionnaireList/index.tsx +++ b/src/containers/QuestionnaireList/index.tsx @@ -8,12 +8,11 @@ import { Link } from 'react-router-dom'; import config from '@beda.software/emr-config'; import { isLoading, isSuccess } from '@beda.software/remote-data'; -import { BasePageContent, BasePageHeader } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { SearchBar } from 'src/components/SearchBar'; import { useSearchBar } from 'src/components/SearchBar/hooks'; import { SpinIndicator } from 'src/components/Spinner'; import { Table } from 'src/components/Table'; -import { Title } from 'src/components/Typography'; import { useQuestionnaireList } from './hooks'; import { getQuestionnaireListSearchBarColumns } from './searchBarUtils'; @@ -72,48 +71,43 @@ export function QuestionnaireList() { const { pagination, questionnaireListRD, handleTableChange } = useQuestionnaireList(columnsFilterValues); return ( - <> - - -
- - <Trans>Questionnaires</Trans> - - - - - - - - - - - - - - pagination={pagination} - onChange={handleTableChange} - locale={{ - emptyText: ( - <> - No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> - - ), - }} - rowKey={(p) => p.id!} - dataSource={isSuccess(questionnaireListRD) ? questionnaireListRD.data : []} - columns={columns} - loading={isLoading(questionnaireListRD) && { indicator: SpinIndicator }} - /> - - + Questionnaires} + headerRightColumn={ + + + + } + header={{ + children: ( + + ), + }} + > + + pagination={pagination} + onChange={handleTableChange} + locale={{ + emptyText: ( + <> + No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> + + ), + }} + rowKey={(p) => p.id!} + dataSource={isSuccess(questionnaireListRD) ? questionnaireListRD.data : []} + columns={columns} + loading={isLoading(questionnaireListRD) && { indicator: SpinIndicator }} + /> + ); } diff --git a/src/containers/VideoCall/index.tsx b/src/containers/VideoCall/index.tsx index 86ca19b0..0cf1b5e9 100644 --- a/src/containers/VideoCall/index.tsx +++ b/src/containers/VideoCall/index.tsx @@ -1,13 +1,12 @@ import { JitsiMeeting } from '@jitsi/react-sdk'; -import { Col, Row } from 'antd'; +import { Trans } from '@lingui/macro'; import { ContactPoint } from 'fhir/r4b'; import { useLocation, useNavigate } from 'react-router-dom'; import config from '@beda.software/emr-config'; -import { BasePageContent, BasePageHeader } from 'src/components/BaseLayout'; +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; import { EncounterData } from 'src/components/EncountersTable/types'; -import { Title } from 'src/components/Typography'; import { sharedJitsiAuthToken } from 'src/sharedState'; import { renderHumanName } from 'src/utils/fhir'; @@ -26,42 +25,33 @@ export function VideoCall() { const jwtAuthToken = sharedJitsiAuthToken.getSharedState(); return ( - <> - - - - Video call - - - - - - - { - iframeRef.style.height = '500px'; - }} - onReadyToClose={() => { - navigate(`/patients/${encounter.patient?.id}/encounters/${encounter.id}`); - }} - /> - - - + Video call}> + + + { + iframeRef.style.height = '500px'; + }} + onReadyToClose={() => { + navigate(`/patients/${encounter.patient?.id}/encounters/${encounter.id}`); + }} + /> + + ); } diff --git a/src/locale/en/messages.po b/src/locale/en/messages.po index a7870507..79d3fd6e 100644 --- a/src/locale/en/messages.po +++ b/src/locale/en/messages.po @@ -13,24 +13,25 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" -#: src/components/BaseQuestionnaireResponseForm/index.tsx:247 -#~ msgid "{0}" -#~ msgstr "" +#: src/uberComponents/ResourceListPage/BatchActions.tsx:57 +msgid "{0, plural, one {Selected # item} other {Selected # items}}" +msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/NoteList/index.tsx:55 msgid "Action" msgstr "" -#: src/components/PatientEncounter/index.tsx:47 +#: src/components/PatientEncounter/index.tsx:46 #: src/containers/DocumentsList/index.tsx:69 -#: src/containers/EncounterList/index.tsx:71 -#: src/containers/HealthcareServiceList/index.tsx:85 +#: src/containers/EncounterList/index.tsx:70 +#: src/containers/HealthcareServiceList/index.tsx:79 #: src/containers/InvoiceList/tableUtils.tsx:150 #: src/containers/InvoiceList/tableUtils.tsx:157 -#: src/containers/MedicationManagement/index.tsx:67 -#: src/containers/PatientList/index.tsx:111 -#: src/containers/PractitionerList/index.tsx:126 -#: src/containers/Prescriptions/index.tsx:151 +#: src/containers/MedicationManagement/index.tsx:71 +#: src/containers/PatientList/index.tsx:103 +#: src/containers/PractitionerList/index.tsx:121 +#: src/containers/Prescriptions/index.tsx:148 +#: src/uberComponents/ResourceListPage/index.tsx:273 msgid "Actions" msgstr "" @@ -43,7 +44,7 @@ msgid "Activate healthcare service" msgstr "" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:97 -#: src/containers/Prescriptions/index.tsx:191 +#: src/containers/Prescriptions/index.tsx:187 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:82 msgid "Active" msgstr "" @@ -57,7 +58,7 @@ msgstr "" msgid "Activities" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:22 +#: src/containers/PatientDetails/PatientWearables/index.tsx:21 msgid "Activity" msgstr "" @@ -86,7 +87,7 @@ msgstr "" msgid "Add Medication Batch" msgstr "" -#: src/containers/PractitionerList/index.tsx:34 +#: src/containers/PractitionerList/index.tsx:33 msgid "Add new practitioner" msgstr "" @@ -109,10 +110,11 @@ msgstr "" #: src/components/ModalNewPatient/index.tsx:16 #: src/components/ModalNewPatient/index.tsx:20 +#: src/containers/PatientResourceListExample/index.tsx:78 msgid "Add patient" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:87 +#: src/containers/QuestionnaireList/index.tsx:81 msgid "Add questionnaire" msgstr "" @@ -120,11 +122,11 @@ msgstr "" msgid "Adjust Last Option Right" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:40 +#: src/containers/QuestionnaireList/index.tsx:39 msgid "AI builder" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:57 +#: src/containers/QuestionnaireList/index.tsx:56 msgid "Aidbox Forms Builder" msgstr "" @@ -133,11 +135,11 @@ msgstr "" msgid "Allergies" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:154 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:151 msgid "Amend" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:97 +#: src/containers/InvoiceDetails/index.tsx:102 #: src/containers/InvoiceList/tableUtils.tsx:143 #: src/containers/MedicationManagement/utils.tsx:36 msgid "Amount" @@ -147,29 +149,29 @@ msgstr "" msgid "Appointment" msgstr "" -#: src/containers/Appointment/PublicAppointment.tsx:48 +#: src/containers/Appointment/PublicAppointment.tsx:44 msgid "Appointment booking" msgstr "" -#: src/containers/OrganizationScheduling/index.tsx:223 +#: src/containers/OrganizationScheduling/index.tsx:224 #: src/containers/Scheduling/ScheduleCalendar/index.tsx:93 msgid "Appointment successfully added" msgstr "" -#: src/containers/Appointment/PublicAppointment.tsx:61 +#: src/containers/Appointment/PublicAppointment.tsx:53 msgid "Appointment successfully created" msgstr "" -#: src/containers/OrganizationScheduling/index.tsx:176 +#: src/containers/OrganizationScheduling/index.tsx:177 #: src/containers/Scheduling/ScheduleCalendar/index.tsx:76 msgid "Appointment successfully rescheduled" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:149 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:146 msgid "Are you sure you want to amend the document?" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:174 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:171 msgid "Are you sure you want to delete the document?" msgstr "" @@ -177,8 +179,7 @@ msgstr "" msgid "Are you sure you want to delete this item?" msgstr "" -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:40 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:72 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:26 #: src/containers/Scheduling/Availability/index.tsx:54 msgid "Availability" msgstr "" @@ -205,7 +206,8 @@ msgid "Batch Number" msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/containers/GeneralIInformationDashboardContainer/hooks.ts:31 -#: src/containers/PatientList/index.tsx:94 +#: src/containers/PatientList/index.tsx:87 +#: src/containers/PatientResourceListExample/index.tsx:48 msgid "Birth date" msgstr "" @@ -217,11 +219,11 @@ msgstr "" msgid "Break" msgstr "" -#: src/containers/QuestionnaireBuilder/index.tsx:49 +#: src/containers/QuestionnaireBuilder/index.tsx:43 msgid "Build your form" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:47 +#: src/containers/PatientDetails/PatientWearables/index.tsx:46 msgid "Calories" msgstr "" @@ -243,7 +245,7 @@ msgstr "" #: src/containers/InvoiceList/tableUtils.tsx:28 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:101 -#: src/containers/Prescriptions/index.tsx:193 +#: src/containers/Prescriptions/index.tsx:189 msgid "Cancelled" msgstr "" @@ -256,6 +258,11 @@ msgstr "" msgid "Characteristics" msgstr "" +#: src/components/SearchBar/index.tsx:36 +#: src/components/SearchBar/SearchBarMobile/index.tsx:51 +msgid "Clear filters" +msgstr "" + #: src/components/BaseQuestionnaireResponseForm/widgets/UploadFileControl/index.tsx:29 msgid "Click or drag file to this area to upload" msgstr "" @@ -281,8 +288,8 @@ msgstr "" msgid "Complete" msgstr "" -#: src/containers/EncounterDetails/index.tsx:176 -#: src/containers/EncounterDetails/index.tsx:180 +#: src/containers/EncounterDetails/index.tsx:173 +#: src/containers/EncounterDetails/index.tsx:177 msgid "Complete encounter" msgstr "" @@ -292,7 +299,7 @@ msgid "completed" msgstr "" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:105 -#: src/containers/Prescriptions/index.tsx:194 +#: src/containers/Prescriptions/index.tsx:190 msgid "Completed" msgstr "" @@ -318,16 +325,15 @@ msgstr "" msgid "Consents" msgstr "" -#: src/containers/EncounterDetails/index.tsx:48 -#: src/containers/EncounterDetails/index.tsx:61 +#: src/containers/EncounterDetails/index.tsx:58 msgid "Consultation" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:92 +#: src/containers/PatientDetails/PatientWearables/index.tsx:89 msgid "Contact the patient to obtain their consent for accessing activity data" msgstr "" -#: src/containers/MedicationManagement/index.tsx:60 +#: src/containers/MedicationManagement/index.tsx:64 #: src/containers/MedicationManagement/utils.tsx:39 msgid "Cost" msgstr "" @@ -338,7 +344,7 @@ msgstr "" #: src/containers/DocumentsList/ChooseDocumentToCreateModal/index.tsx:52 #: src/containers/EncounterDetails/hooks.ts:31 -#: src/containers/PatientDetails/PatientDocuments/index.tsx:33 +#: src/containers/PatientDetails/PatientDocuments/index.tsx:29 msgid "Create document" msgstr "" @@ -348,7 +354,7 @@ msgstr "" msgid "Create Encounter" msgstr "" -#: src/containers/PractitionerList/index.tsx:30 +#: src/containers/PractitionerList/index.tsx:29 msgid "Create practitioner" msgstr "" @@ -369,15 +375,15 @@ msgstr "" msgid "CRP" msgstr "" -#: src/components/PatientEncounter/index.tsx:40 -#: src/containers/EncounterList/index.tsx:64 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:26 +#: src/components/PatientEncounter/index.tsx:39 +#: src/containers/EncounterList/index.tsx:63 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:23 #: src/containers/InvoiceList/tableUtils.tsx:129 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:55 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:95 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:142 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:216 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:283 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:271 #: src/containers/PatientDetails/PatientResources/utils.tsx:96 #: src/containers/PatientDetails/PatientResources/utils.tsx:135 #: src/containers/PatientDetails/PatientResources/utils.tsx:174 @@ -419,11 +425,15 @@ msgstr "" msgid "Default" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:179 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:176 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:140 msgid "Delete" msgstr "" +#: src/containers/PatientResourceListExample/index.tsx:80 +msgid "Delete patients" +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:133 msgid "Delete Questionnaire Item" msgstr "" @@ -448,8 +458,7 @@ msgstr "" msgid "Display" msgstr "" -#: src/containers/PatientDetails/PatientDocuments/index.tsx:23 -#: src/containers/PatientDetails/PatientHeader/index.tsx:80 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:20 msgid "Documents" msgstr "" @@ -472,28 +481,28 @@ msgstr "" #: src/containers/InvoiceList/tableUtils.tsx:30 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:121 -#: src/containers/Prescriptions/index.tsx:197 +#: src/containers/Prescriptions/index.tsx:193 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:81 msgid "Draft" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:47 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:46 msgid "Draft successfully deleted" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:28 +#: src/containers/PatientDetails/PatientWearables/index.tsx:27 msgid "Duration (min)" msgstr "" -#: src/containers/HealthcareServiceList/index.tsx:68 +#: src/containers/HealthcareServiceList/index.tsx:62 msgid "Duration (minutes)" msgstr "" #: src/components/ModalEditHealthcareService/index.tsx:21 #: src/containers/EncounterDetails/AIScribe/index.tsx:197 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:187 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:184 #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:23 -#: src/containers/PatientList/index.tsx:135 +#: src/containers/PatientList/index.tsx:127 #: src/containers/PractitionerDetails/PractitionerOverview/index.tsx:67 #: src/containers/Scheduling/ScheduleCalendar/components/AppointmentDetailsModal/index.tsx:87 msgid "Edit" @@ -507,7 +516,7 @@ msgstr "" msgid "Edit Healthcare Service" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:30 +#: src/containers/QuestionnaireList/index.tsx:29 msgid "Edit in" msgstr "" @@ -516,7 +525,7 @@ msgstr "" #~ msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:20 -#: src/containers/PatientList/index.tsx:132 +#: src/containers/PatientList/index.tsx:124 msgid "Edit patient" msgstr "" @@ -532,7 +541,7 @@ msgstr "" msgid "Encounter" msgstr "" -#: src/containers/EncounterDetails/index.tsx:127 +#: src/containers/EncounterDetails/index.tsx:124 msgid "Encounter completed" msgstr "" @@ -540,19 +549,18 @@ msgstr "" msgid "Encounter successfully created" msgstr "" -#: src/containers/EncounterDetails/index.tsx:196 +#: src/containers/EncounterDetails/index.tsx:193 msgid "Encounter was successfully completed" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:28 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:34 -#: src/components/PatientEncounter/index.tsx:79 -#: src/containers/EncounterList/index.tsx:103 -#: src/containers/PatientDetails/PatientHeader/index.tsx:79 +#: src/containers/EncounterList/index.tsx:101 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:19 msgid "Encounters" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:41 +#: src/containers/PatientDetails/PatientWearables/index.tsx:40 msgid "End" msgstr "" @@ -562,11 +570,11 @@ msgstr "" #: src/containers/InvoiceList/tableUtils.tsx:31 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:113 -#: src/containers/Prescriptions/index.tsx:195 +#: src/containers/Prescriptions/index.tsx:191 msgid "Entered in error" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:53 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:52 msgid "Error deleting a draft" msgstr "" @@ -574,7 +582,7 @@ msgstr "" msgid "Error saving a draft:" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:77 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:76 msgid "Error while amending the document" msgstr "" @@ -607,7 +615,12 @@ msgstr "" msgid "Fill" msgstr "" +#: src/components/SearchBar/SearchBarMobile/index.tsx:33 +msgid "Filters" +msgstr "" + #: src/containers/PatientList/searchBarUtils.ts:10 +#: src/containers/PatientResourceListExample/index.tsx:68 msgid "Find patient" msgstr "" @@ -657,7 +670,7 @@ msgstr "" msgid "Healthcare service successfully updated" msgstr "" -#: src/containers/HealthcareServiceList/index.tsx:32 +#: src/containers/HealthcareServiceList/index.tsx:29 msgid "Healthcare Services" msgstr "" @@ -669,7 +682,7 @@ msgstr "" msgid "Here will be your questionnaire" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:163 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:160 msgid "History" msgstr "" @@ -698,7 +711,7 @@ msgstr "" msgid "Inline options?" msgstr "" -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:317 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:313 msgid "Intent" msgstr "" @@ -713,7 +726,7 @@ msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:26 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:40 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:44 -#: src/containers/InvoiceList/index.tsx:44 +#: src/containers/InvoiceList/index.tsx:45 msgid "Invoices" msgstr "" @@ -721,7 +734,7 @@ msgstr "" msgid "Issued" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:67 +#: src/containers/InvoiceDetails/index.tsx:72 msgid "Item" msgstr "" @@ -765,11 +778,11 @@ msgstr "" msgid "Max" msgstr "" -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:17 +#: src/containers/InvoiceDetails/index.tsx:27 msgid "Medical Services Invoice" msgstr "" -#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:30 +#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:28 #: src/containers/Prescriptions/index.tsx:113 msgid "Medication" msgstr "" @@ -791,7 +804,7 @@ msgid "Medication request successfully confirmed" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:45 -#: src/containers/MedicationManagement/index.tsx:28 +#: src/containers/MedicationManagement/index.tsx:29 msgid "Medications" msgstr "" @@ -807,25 +820,26 @@ msgstr "" msgid "Monday" msgstr "" -#: src/containers/MedicationManagement/index.tsx:54 +#: src/containers/MedicationManagement/index.tsx:58 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:43 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:83 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:123 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:204 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:240 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:312 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:308 #: src/containers/PatientDetails/PatientResources/utils.tsx:50 #: src/containers/PatientDetails/PatientResources/utils.tsx:85 #: src/containers/PatientDetails/PatientResources/utils.tsx:124 #: src/containers/PatientDetails/PatientResources/utils.tsx:163 #: src/containers/PatientDetails/PatientResources/utils.tsx:199 -#: src/containers/PatientList/index.tsx:88 -#: src/containers/PractitionerList/index.tsx:113 +#: src/containers/PatientList/index.tsx:81 +#: src/containers/PatientResourceListExample/index.tsx:41 +#: src/containers/PractitionerList/index.tsx:108 msgid "Name" msgstr "" #. js-lingui-explicit-id -#: src/containers/QuestionnaireList/index.tsx:23 +#: src/containers/QuestionnaireList/index.tsx:22 msgid "msg.QuestionnaireName" msgstr "Name" @@ -834,8 +848,8 @@ msgstr "Name" msgid "New Appointment" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:151 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:176 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:148 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:173 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:137 #: src/utils/questionnaire.ts:63 msgid "No" @@ -843,13 +857,14 @@ msgstr "" #: src/components/EncountersTable/index.tsx:30 #: src/components/ResourceTable/index.tsx:67 -#: src/containers/HealthcareServiceList/index.tsx:54 -#: src/containers/InvoiceList/index.tsx:70 -#: src/containers/PatientDetails/PatientWearables/index.tsx:88 -#: src/containers/PatientList/index.tsx:80 -#: src/containers/PractitionerList/index.tsx:106 +#: src/containers/HealthcareServiceList/index.tsx:48 +#: src/containers/InvoiceList/index.tsx:73 +#: src/containers/PatientDetails/PatientWearables/index.tsx:85 +#: src/containers/PatientList/index.tsx:73 +#: src/containers/PractitionerList/index.tsx:101 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:500 -#: src/containers/QuestionnaireList/index.tsx:107 +#: src/containers/QuestionnaireList/index.tsx:102 +#: src/uberComponents/ResourceListPage/index.tsx:214 msgid "No data" msgstr "" @@ -873,12 +888,16 @@ msgstr "" msgid "Number (default)" msgstr "" +#: src/containers/PatientResourceListExample/index.tsx:83 +msgid "Number of Patients" +msgstr "" + #: src/containers/PatientDetails/PatientResources/utils.tsx:230 msgid "Observations" msgstr "" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:109 -#: src/containers/Prescriptions/index.tsx:192 +#: src/containers/Prescriptions/index.tsx:188 msgid "On Hold" msgstr "" @@ -891,13 +910,13 @@ msgstr "" #~ msgid "On the next page, please, use the following credentials" #~ msgstr "" -#: src/components/PatientEncounter/index.tsx:58 +#: src/components/PatientEncounter/index.tsx:57 #: src/containers/DocumentsList/index.tsx:79 -#: src/containers/EncounterList/index.tsx:82 +#: src/containers/EncounterList/index.tsx:81 #: src/containers/InvoiceList/tableUtils.tsx:82 #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/ModalNoteOpen/index.tsx:22 -#: src/containers/PatientList/index.tsx:127 -#: src/containers/PractitionerList/index.tsx:141 +#: src/containers/PatientList/index.tsx:119 +#: src/containers/PractitionerList/index.tsx:136 msgid "Open" msgstr "" @@ -912,7 +931,7 @@ msgstr "" msgid "Option {index}" msgstr "" -#: src/containers/EncounterDetails/index.tsx:102 +#: src/containers/EncounterDetails/index.tsx:99 msgid "or" msgstr "" @@ -920,15 +939,13 @@ msgstr "" msgid "Order added" msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:82 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:304 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:22 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:300 msgid "Orders" msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:41 -#: src/containers/PatientDetails/PatientHeader/index.tsx:78 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:56 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:70 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:18 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:24 msgid "Overview" msgstr "" @@ -942,22 +959,22 @@ msgid "Password" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:39 -#: src/containers/EncounterList/index.tsx:46 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:20 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:39 +#: src/containers/EncounterList/index.tsx:45 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:17 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:38 #: src/containers/InvoiceList/tableUtils.tsx:122 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:48 -#: src/containers/Prescriptions/index.tsx:76 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:46 +#: src/containers/Prescriptions/index.tsx:78 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:69 msgid "Patient" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:93 +#: src/containers/PatientDetails/PatientWearables/index.tsx:90 msgid "Patient consent is required" msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:33 -#: src/containers/PatientList/index.tsx:145 +#: src/containers/PatientList/index.tsx:137 msgid "Patient saved" msgstr "" @@ -967,8 +984,8 @@ msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:29 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:35 -#: src/containers/PatientDetails/PatientHeader/index.tsx:26 -#: src/containers/PatientList/index.tsx:59 +#: src/containers/PatientList/index.tsx:55 +#: src/containers/PatientResourceListExample/index.tsx:36 msgid "Patients" msgstr "" @@ -989,28 +1006,26 @@ msgstr "" msgid "Phone widget" msgstr "" -#: src/components/PatientEncounter/index.tsx:26 -#: src/containers/EncounterList/index.tsx:52 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:23 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:33 +#: src/components/PatientEncounter/index.tsx:25 +#: src/containers/EncounterList/index.tsx:51 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:20 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:32 #: src/containers/InvoiceList/tableUtils.tsx:114 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:152 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:275 #: src/containers/PatientDetails/PatientResources/utils.tsx:221 msgid "Practitioner" msgstr "" -#: src/containers/PractitionerList/index.tsx:85 +#: src/containers/PractitionerList/index.tsx:79 msgid "Practitioner successfully created" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:30 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:37 -#: src/containers/PractitionerList/index.tsx:77 +#: src/containers/PractitionerList/index.tsx:73 msgid "Practitioners" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:141 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:138 msgid "Prepare for print" msgstr "" @@ -1023,16 +1038,16 @@ msgstr "" msgid "Properties" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:53 +#: src/containers/PatientDetails/PatientWearables/index.tsx:52 msgid "Provider" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:76 +#: src/containers/InvoiceDetails/index.tsx:81 msgid "Quantity" msgstr "" #: src/containers/DocumentsList/index.tsx:46 -#: src/containers/PatientQuestionnaire/index.tsx:73 +#: src/containers/PatientQuestionnaire/index.tsx:70 msgid "Questionnaire" msgstr "" @@ -1042,11 +1057,11 @@ msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:31 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:36 -#: src/containers/QuestionnaireList/index.tsx:80 +#: src/containers/QuestionnaireList/index.tsx:76 msgid "Questionnaires" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:83 +#: src/containers/InvoiceDetails/index.tsx:88 msgid "Rate" msgstr "" @@ -1062,8 +1077,8 @@ msgstr "" msgid "Request Appointment" msgstr "" -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:60 -#: src/containers/Prescriptions/index.tsx:88 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:58 +#: src/containers/Prescriptions/index.tsx:89 msgid "Requester" msgstr "" @@ -1071,11 +1086,10 @@ msgstr "" msgid "Required" msgstr "" -#: src/components/SearchBar/index.tsx:24 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:56 -#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:35 -#: src/containers/OrganizationScheduling/index.tsx:87 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:71 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:54 +#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:32 +#: src/containers/OrganizationScheduling/index.tsx:88 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:68 msgid "Reset" msgstr "" @@ -1083,7 +1097,11 @@ msgstr "" #~ msgid "Reset password" #~ msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:84 +#: src/uberComponents/ResourceListPage/BatchActions.tsx:48 +msgid "Reset selection" +msgstr "" + +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:24 msgid "Resources" msgstr "" @@ -1108,8 +1126,8 @@ msgstr "" msgid "Save as draft" msgstr "" -#: src/containers/QuestionnaireBuilder/index.tsx:57 -#: src/containers/QuestionnaireBuilder/index.tsx:58 +#: src/containers/QuestionnaireBuilder/index.tsx:49 +#: src/containers/QuestionnaireBuilder/index.tsx:50 msgid "Save questionnaire" msgstr "" @@ -1126,9 +1144,8 @@ msgid "Schedule calendar" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:43 -#: src/containers/OrganizationScheduling/index.tsx:71 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:39 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:71 +#: src/containers/OrganizationScheduling/index.tsx:69 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:25 msgid "Scheduling" msgstr "" @@ -1136,7 +1153,7 @@ msgstr "" msgid "Scribe results" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:51 +#: src/containers/QuestionnaireList/index.tsx:50 msgid "SDC IDE" msgstr "" @@ -1153,6 +1170,10 @@ msgstr "" msgid "Search by practitioner" msgstr "" +#: src/containers/EncounterList/searchBarUtils.ts:22 +#~ msgid "Search by status" +#~ msgstr "" + #: src/containers/PatientDetails/PatientOrders/index.tsx:177 msgid "Search orders" msgstr "" @@ -1169,6 +1190,10 @@ msgstr "" msgid "Select (default)" msgstr "" +#: src/uberComponents/ResourceListPage/BatchActions.tsx:69 +msgid "Select all" +msgstr "" + #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:30 #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:55 msgid "Select..." @@ -1179,8 +1204,8 @@ msgid "Serum creatinin" msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:279 -msgid "Service" -msgstr "" +#~ msgid "Service" +#~ msgstr "" #: src/containers/PatientDetails/PatientResources/utils.tsx:306 msgid "Service Requests" @@ -1202,11 +1227,15 @@ msgstr "" msgid "Share link" msgstr "" +#: src/components/SearchBar/SearchBarMobile/index.tsx:48 +msgid "Show results" +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:53 msgid "Slider" msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:83 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:23 msgid "Smart Apps" msgstr "" @@ -1215,15 +1244,16 @@ msgid "Solid radio button" msgstr "" #: src/containers/PractitionerDetails/PractitionerOverview/index.tsx:40 -#: src/containers/PractitionerList/index.tsx:119 +#: src/containers/PractitionerList/index.tsx:114 msgid "Specialty" msgstr "" -#: src/containers/PatientList/index.tsx:102 +#: src/containers/PatientList/index.tsx:94 +#: src/containers/PatientResourceListExample/index.tsx:55 msgid "SSN" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:35 +#: src/containers/PatientDetails/PatientWearables/index.tsx:34 msgid "Start" msgstr "" @@ -1232,7 +1262,7 @@ msgid "Start date" msgstr "" #: src/components/BaseQuestionnaireResponseForm/widgets/AudioRecorderUploader/index.tsx:72 -#: src/containers/EncounterDetails/index.tsx:114 +#: src/containers/EncounterDetails/index.tsx:111 msgid "Start scribe" msgstr "" @@ -1245,19 +1275,19 @@ msgstr "" msgid "Start value" msgstr "" -#: src/containers/EncounterDetails/index.tsx:94 +#: src/containers/EncounterDetails/index.tsx:91 msgid "Start video call" msgstr "" -#: src/components/PatientEncounter/index.tsx:32 +#: src/components/PatientEncounter/index.tsx:31 #: src/containers/DocumentsList/index.tsx:63 -#: src/containers/EncounterList/index.tsx:58 -#: src/containers/HealthcareServiceList/index.tsx:78 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:29 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:51 +#: src/containers/EncounterList/index.tsx:57 +#: src/containers/HealthcareServiceList/index.tsx:72 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:26 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:50 #: src/containers/InvoiceList/tableUtils.tsx:136 #: src/containers/PatientDetails/PatientResources/utils.tsx:343 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:66 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:64 #: src/containers/Prescriptions/index.tsx:132 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:77 msgid "Status" @@ -1276,7 +1306,7 @@ msgid "Stop value" msgstr "" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:117 -#: src/containers/Prescriptions/index.tsx:196 +#: src/containers/Prescriptions/index.tsx:192 msgid "Stopped" msgstr "" @@ -1289,9 +1319,24 @@ msgid "Subject Type" msgstr "" #: src/containers/QuestionnaireBuilder/PromptForm.tsx:104 +#: src/uberComponents/ResourceListPage/actions.tsx:97 +#: src/uberComponents/ResourceListPage/actions.tsx:131 +#: src/uberComponents/ResourceListPage/actions.tsx:177 msgid "Submit" msgstr "" +#: src/uberComponents/ResourceListPage/actions.tsx:78 +#: src/uberComponents/ResourceListPage/actions.tsx:105 +#: src/uberComponents/ResourceListPage/actions.tsx:146 +#~ msgid "Successfully saved" +#~ msgstr "" + +#: src/uberComponents/ResourceListPage/actions.tsx:91 +#: src/uberComponents/ResourceListPage/actions.tsx:126 +#: src/uberComponents/ResourceListPage/actions.tsx:173 +msgid "Successfully submitted" +msgstr "" + #: src/containers/Scheduling/Availability/index.tsx:43 msgid "Successfully updated" msgstr "" @@ -1304,7 +1349,7 @@ msgstr "" msgid "System" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:90 +#: src/containers/InvoiceDetails/index.tsx:95 msgid "Tax" msgstr "" @@ -1321,19 +1366,19 @@ msgstr "" msgid "Text with macro" msgstr "" -#: src/containers/App/index.tsx:129 +#: src/containers/App/index.tsx:130 msgid "Thank you for filling out the questionnaire. Now you can close this page." msgstr "" -#: src/containers/App/index.tsx:128 +#: src/containers/App/index.tsx:129 msgid "Thank you!" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:99 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:98 msgid "The document does not exist" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:71 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:70 msgid "The document successfully amended" msgstr "" @@ -1362,7 +1407,7 @@ msgstr "" msgid "Thursday" msgstr "" -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:287 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:275 #: src/containers/Scheduling/Availability/index.tsx:129 msgid "Time" msgstr "" @@ -1375,7 +1420,7 @@ msgstr "" msgid "Title" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:111 +#: src/containers/PatientDetails/PatientWearables/index.tsx:108 msgid "To obtain this information, you need to authorize your account in the mobile application and link it with your health data providers." msgstr "" @@ -1383,7 +1428,7 @@ msgstr "" msgid "Today" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:117 +#: src/containers/InvoiceDetails/index.tsx:122 msgid "Total" msgstr "" @@ -1395,7 +1440,7 @@ msgstr "" msgid "Tuesday" msgstr "" -#: src/containers/HealthcareServiceList/index.tsx:61 +#: src/containers/HealthcareServiceList/index.tsx:55 msgid "Type" msgstr "" @@ -1408,7 +1453,7 @@ msgstr "" #: src/containers/InvoiceList/tableUtils.tsx:34 #: src/containers/PatientDetails/PatientDocumentDetails/ExternalDocumentView/index.tsx:53 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:125 -#: src/containers/Prescriptions/index.tsx:198 +#: src/containers/Prescriptions/index.tsx:194 #: src/containers/Scheduling/available-time.ts:22 msgid "Unknown" msgstr "" @@ -1447,13 +1492,13 @@ msgstr "" msgid "ValueSet url" msgstr "" -#: src/components/PatientEncounter/index.tsx:63 -#: src/containers/EncounterList/index.tsx:91 +#: src/components/PatientEncounter/index.tsx:62 +#: src/containers/EncounterList/index.tsx:90 +#: src/containers/VideoCall/index.tsx:28 msgid "Video call" msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:81 -#: src/containers/PatientDetails/PatientWearables/index.tsx:64 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:21 msgid "Wearables" msgstr "" @@ -1469,14 +1514,14 @@ msgstr "" msgid "Welcome to" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:150 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:175 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:147 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:172 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:136 #: src/utils/questionnaire.ts:63 msgid "Yes" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:110 +#: src/containers/PatientDetails/PatientWearables/index.tsx:107 msgid "You currently lack access to the patient's data. To obtain it, you must secure the patient's signed consent authorizing the release of their activity data." msgstr "" diff --git a/src/locale/es/messages.po b/src/locale/es/messages.po index 9d63d42d..b7ea52e9 100644 --- a/src/locale/es/messages.po +++ b/src/locale/es/messages.po @@ -13,20 +13,25 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" +#: src/uberComponents/ResourceListPage/BatchActions.tsx:57 +msgid "{0, plural, one {Selected # item} other {Selected # items}}" +msgstr "" + #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/NoteList/index.tsx:55 msgid "Action" msgstr "Acción" -#: src/components/PatientEncounter/index.tsx:47 +#: src/components/PatientEncounter/index.tsx:46 #: src/containers/DocumentsList/index.tsx:69 -#: src/containers/EncounterList/index.tsx:71 -#: src/containers/HealthcareServiceList/index.tsx:85 +#: src/containers/EncounterList/index.tsx:70 +#: src/containers/HealthcareServiceList/index.tsx:79 #: src/containers/InvoiceList/tableUtils.tsx:150 #: src/containers/InvoiceList/tableUtils.tsx:157 -#: src/containers/MedicationManagement/index.tsx:67 -#: src/containers/PatientList/index.tsx:111 -#: src/containers/PractitionerList/index.tsx:126 -#: src/containers/Prescriptions/index.tsx:151 +#: src/containers/MedicationManagement/index.tsx:71 +#: src/containers/PatientList/index.tsx:103 +#: src/containers/PractitionerList/index.tsx:121 +#: src/containers/Prescriptions/index.tsx:148 +#: src/uberComponents/ResourceListPage/index.tsx:273 msgid "Actions" msgstr "Acciones" @@ -39,7 +44,7 @@ msgid "Activate healthcare service" msgstr "Activar servicio clínico" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:97 -#: src/containers/Prescriptions/index.tsx:191 +#: src/containers/Prescriptions/index.tsx:187 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:82 msgid "Active" msgstr "Activo" @@ -53,7 +58,7 @@ msgstr "Medicamentos Activos" msgid "Activities" msgstr "Actividades" -#: src/containers/PatientDetails/PatientWearables/index.tsx:22 +#: src/containers/PatientDetails/PatientWearables/index.tsx:21 msgid "Activity" msgstr "Actividad" @@ -82,7 +87,7 @@ msgstr "Añadir Medicamento" msgid "Add Medication Batch" msgstr "Añadir Lote de Medicamento" -#: src/containers/PractitionerList/index.tsx:34 +#: src/containers/PractitionerList/index.tsx:33 msgid "Add new practitioner" msgstr "Añadir nuevo profesional" @@ -105,10 +110,11 @@ msgstr "Añadir Orden" #: src/components/ModalNewPatient/index.tsx:16 #: src/components/ModalNewPatient/index.tsx:20 +#: src/containers/PatientResourceListExample/index.tsx:78 msgid "Add patient" msgstr "Añadir paciente" -#: src/containers/QuestionnaireList/index.tsx:87 +#: src/containers/QuestionnaireList/index.tsx:81 msgid "Add questionnaire" msgstr "Añadir cuestionario" @@ -116,11 +122,11 @@ msgstr "Añadir cuestionario" msgid "Adjust Last Option Right" msgstr "Ajustar última opción a la derecha" -#: src/containers/QuestionnaireList/index.tsx:40 +#: src/containers/QuestionnaireList/index.tsx:39 msgid "AI builder" msgstr "Creador de IA" -#: src/containers/QuestionnaireList/index.tsx:57 +#: src/containers/QuestionnaireList/index.tsx:56 msgid "Aidbox Forms Builder" msgstr "Constructor de Formularios Aidbox" @@ -129,11 +135,11 @@ msgstr "Constructor de Formularios Aidbox" msgid "Allergies" msgstr "Alergias" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:154 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:151 msgid "Amend" msgstr "Modificar" -#: src/containers/InvoiceDetails/index.tsx:97 +#: src/containers/InvoiceDetails/index.tsx:102 #: src/containers/InvoiceList/tableUtils.tsx:143 #: src/containers/MedicationManagement/utils.tsx:36 msgid "Amount" @@ -143,29 +149,29 @@ msgstr "Cantidad" msgid "Appointment" msgstr "Cita" -#: src/containers/Appointment/PublicAppointment.tsx:48 +#: src/containers/Appointment/PublicAppointment.tsx:44 msgid "Appointment booking" msgstr "Reserva de cita" -#: src/containers/OrganizationScheduling/index.tsx:223 +#: src/containers/OrganizationScheduling/index.tsx:224 #: src/containers/Scheduling/ScheduleCalendar/index.tsx:93 msgid "Appointment successfully added" msgstr "Cita añadida con éxito" -#: src/containers/Appointment/PublicAppointment.tsx:61 +#: src/containers/Appointment/PublicAppointment.tsx:53 msgid "Appointment successfully created" msgstr "Agendamiento creado exitosamente" -#: src/containers/OrganizationScheduling/index.tsx:176 +#: src/containers/OrganizationScheduling/index.tsx:177 #: src/containers/Scheduling/ScheduleCalendar/index.tsx:76 msgid "Appointment successfully rescheduled" msgstr "Cita reprogramada con éxito" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:149 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:146 msgid "Are you sure you want to amend the document?" msgstr "¿Estás seguro de que quieres modificar el documento?" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:174 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:171 msgid "Are you sure you want to delete the document?" msgstr "¿Estás seguro de que quieres eliminar el documento?" @@ -173,8 +179,7 @@ msgstr "¿Estás seguro de que quieres eliminar el documento?" msgid "Are you sure you want to delete this item?" msgstr "¿Estás seguro que deseas eliminar este ítem?" -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:40 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:72 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:26 #: src/containers/Scheduling/Availability/index.tsx:54 msgid "Availability" msgstr "Disponibilidad" @@ -201,7 +206,8 @@ msgid "Batch Number" msgstr "Número de lote" #: src/containers/PatientDetails/PatientOverviewDynamic/containers/GeneralIInformationDashboardContainer/hooks.ts:31 -#: src/containers/PatientList/index.tsx:94 +#: src/containers/PatientList/index.tsx:87 +#: src/containers/PatientResourceListExample/index.tsx:48 msgid "Birth date" msgstr "Fecha de nacimiento" @@ -213,11 +219,11 @@ msgstr "IMC" msgid "Break" msgstr "Pausa" -#: src/containers/QuestionnaireBuilder/index.tsx:49 +#: src/containers/QuestionnaireBuilder/index.tsx:43 msgid "Build your form" msgstr "Construye tu formulario" -#: src/containers/PatientDetails/PatientWearables/index.tsx:47 +#: src/containers/PatientDetails/PatientWearables/index.tsx:46 msgid "Calories" msgstr "Calorías" @@ -239,7 +245,7 @@ msgstr "Cancelar solicitud de medicamento" #: src/containers/InvoiceList/tableUtils.tsx:28 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:101 -#: src/containers/Prescriptions/index.tsx:193 +#: src/containers/Prescriptions/index.tsx:189 msgid "Cancelled" msgstr "Cancelado" @@ -252,6 +258,11 @@ msgstr "Ejecución en curso" msgid "Characteristics" msgstr "Características" +#: src/components/SearchBar/index.tsx:36 +#: src/components/SearchBar/SearchBarMobile/index.tsx:51 +msgid "Clear filters" +msgstr "" + #: src/components/BaseQuestionnaireResponseForm/widgets/UploadFileControl/index.tsx:29 msgid "Click or drag file to this area to upload" msgstr "" @@ -277,8 +288,8 @@ msgstr "Columna (predeterminado)" msgid "Complete" msgstr "Completado" -#: src/containers/EncounterDetails/index.tsx:176 -#: src/containers/EncounterDetails/index.tsx:180 +#: src/containers/EncounterDetails/index.tsx:173 +#: src/containers/EncounterDetails/index.tsx:177 msgid "Complete encounter" msgstr "Completar cita" @@ -288,7 +299,7 @@ msgid "completed" msgstr "Completado" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:105 -#: src/containers/Prescriptions/index.tsx:194 +#: src/containers/Prescriptions/index.tsx:190 msgid "Completed" msgstr "Completado" @@ -314,16 +325,15 @@ msgstr "Confirmar solicitud de medicamento" msgid "Consents" msgstr "Consentimientos" -#: src/containers/EncounterDetails/index.tsx:48 -#: src/containers/EncounterDetails/index.tsx:61 +#: src/containers/EncounterDetails/index.tsx:58 msgid "Consultation" msgstr "Consulta" -#: src/containers/PatientDetails/PatientWearables/index.tsx:92 +#: src/containers/PatientDetails/PatientWearables/index.tsx:89 msgid "Contact the patient to obtain their consent for accessing activity data" msgstr "Contactar al paciente para obtener su consentimiento para acceder a los datos de esta prestación" -#: src/containers/MedicationManagement/index.tsx:60 +#: src/containers/MedicationManagement/index.tsx:64 #: src/containers/MedicationManagement/utils.tsx:39 msgid "Cost" msgstr "Costo" @@ -334,7 +344,7 @@ msgstr "Crear" #: src/containers/DocumentsList/ChooseDocumentToCreateModal/index.tsx:52 #: src/containers/EncounterDetails/hooks.ts:31 -#: src/containers/PatientDetails/PatientDocuments/index.tsx:33 +#: src/containers/PatientDetails/PatientDocuments/index.tsx:29 msgid "Create document" msgstr "Crear documento" @@ -344,7 +354,7 @@ msgstr "Crear documento" msgid "Create Encounter" msgstr "Crear un encuentro" -#: src/containers/PractitionerList/index.tsx:30 +#: src/containers/PractitionerList/index.tsx:29 msgid "Create practitioner" msgstr "Crear un profesional" @@ -365,15 +375,15 @@ msgstr "Fecha de creación" msgid "CRP" msgstr "" -#: src/components/PatientEncounter/index.tsx:40 -#: src/containers/EncounterList/index.tsx:64 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:26 +#: src/components/PatientEncounter/index.tsx:39 +#: src/containers/EncounterList/index.tsx:63 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:23 #: src/containers/InvoiceList/tableUtils.tsx:129 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:55 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:95 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:142 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:216 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:283 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:271 #: src/containers/PatientDetails/PatientResources/utils.tsx:96 #: src/containers/PatientDetails/PatientResources/utils.tsx:135 #: src/containers/PatientDetails/PatientResources/utils.tsx:174 @@ -415,11 +425,15 @@ msgstr "Desactivar servicio clínico" msgid "Default" msgstr "Predeterminado" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:179 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:176 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:140 msgid "Delete" msgstr "Eliminar" +#: src/containers/PatientResourceListExample/index.tsx:80 +msgid "Delete patients" +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:133 msgid "Delete Questionnaire Item" msgstr "Eliminar ítem del cuestionario" @@ -440,8 +454,7 @@ msgstr "Descripción:" msgid "Display" msgstr "Mostrar" -#: src/containers/PatientDetails/PatientDocuments/index.tsx:23 -#: src/containers/PatientDetails/PatientHeader/index.tsx:80 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:20 msgid "Documents" msgstr "Documentos" @@ -464,28 +477,28 @@ msgstr "" #: src/containers/InvoiceList/tableUtils.tsx:30 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:121 -#: src/containers/Prescriptions/index.tsx:197 +#: src/containers/Prescriptions/index.tsx:193 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:81 msgid "Draft" msgstr "Borrador" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:47 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:46 msgid "Draft successfully deleted" msgstr "Borrador eliminado exitosamente" -#: src/containers/PatientDetails/PatientWearables/index.tsx:28 +#: src/containers/PatientDetails/PatientWearables/index.tsx:27 msgid "Duration (min)" msgstr "Duración (min)" -#: src/containers/HealthcareServiceList/index.tsx:68 +#: src/containers/HealthcareServiceList/index.tsx:62 msgid "Duration (minutes)" msgstr "Duración (minutos)" #: src/components/ModalEditHealthcareService/index.tsx:21 #: src/containers/EncounterDetails/AIScribe/index.tsx:197 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:187 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:184 #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:23 -#: src/containers/PatientList/index.tsx:135 +#: src/containers/PatientList/index.tsx:127 #: src/containers/PractitionerDetails/PractitionerOverview/index.tsx:67 #: src/containers/Scheduling/ScheduleCalendar/components/AppointmentDetailsModal/index.tsx:87 msgid "Edit" @@ -499,7 +512,7 @@ msgstr "Editar agendamiento" msgid "Edit Healthcare Service" msgstr "Editar Servicio Clínico" -#: src/containers/QuestionnaireList/index.tsx:30 +#: src/containers/QuestionnaireList/index.tsx:29 msgid "Edit in" msgstr "Editar en" @@ -508,7 +521,7 @@ msgstr "Editar en" #~ msgstr "Editar en SDC IDE" #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:20 -#: src/containers/PatientList/index.tsx:132 +#: src/containers/PatientList/index.tsx:124 msgid "Edit patient" msgstr "Editar paciente" @@ -524,7 +537,7 @@ msgstr "Correo electrónico" msgid "Encounter" msgstr "Encuentro" -#: src/containers/EncounterDetails/index.tsx:127 +#: src/containers/EncounterDetails/index.tsx:124 msgid "Encounter completed" msgstr "Encuentro completado" @@ -532,19 +545,18 @@ msgstr "Encuentro completado" msgid "Encounter successfully created" msgstr "Encuentro creado exitosamente" -#: src/containers/EncounterDetails/index.tsx:196 +#: src/containers/EncounterDetails/index.tsx:193 msgid "Encounter was successfully completed" msgstr "El encuentro se completó con éxito" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:28 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:34 -#: src/components/PatientEncounter/index.tsx:79 -#: src/containers/EncounterList/index.tsx:103 -#: src/containers/PatientDetails/PatientHeader/index.tsx:79 +#: src/containers/EncounterList/index.tsx:101 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:19 msgid "Encounters" msgstr "Encuentros" -#: src/containers/PatientDetails/PatientWearables/index.tsx:41 +#: src/containers/PatientDetails/PatientWearables/index.tsx:40 msgid "End" msgstr "Fin" @@ -554,11 +566,11 @@ msgstr "Fecha de finalización" #: src/containers/InvoiceList/tableUtils.tsx:31 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:113 -#: src/containers/Prescriptions/index.tsx:195 +#: src/containers/Prescriptions/index.tsx:191 msgid "Entered in error" msgstr "Ingresado erróneamente" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:53 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:52 msgid "Error deleting a draft" msgstr "Error al eliminar un borrador" @@ -566,7 +578,7 @@ msgstr "Error al eliminar un borrador" msgid "Error saving a draft:" msgstr "Error al guardar el borrador:" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:77 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:76 msgid "Error while amending the document" msgstr "Error mientras se modifica el documento" @@ -599,7 +611,12 @@ msgstr "Falso" msgid "Fill" msgstr "Rellenar" +#: src/components/SearchBar/SearchBarMobile/index.tsx:33 +msgid "Filters" +msgstr "" + #: src/containers/PatientList/searchBarUtils.ts:10 +#: src/containers/PatientResourceListExample/index.tsx:68 msgid "Find patient" msgstr "Buscar paciente" @@ -649,7 +666,7 @@ msgstr "Servicio de salud creado con éxito" msgid "Healthcare service successfully updated" msgstr "Servicio de salud actualizado con éxito" -#: src/containers/HealthcareServiceList/index.tsx:32 +#: src/containers/HealthcareServiceList/index.tsx:29 msgid "Healthcare Services" msgstr "Servicios de Salud" @@ -661,7 +678,7 @@ msgstr "Texto de ayuda" msgid "Here will be your questionnaire" msgstr "Aquí estará su cuestionario" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:163 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:160 msgid "History" msgstr "Historial" @@ -690,7 +707,7 @@ msgstr "Elección en línea" msgid "Inline options?" msgstr "¿Opciones en línea?" -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:317 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:313 msgid "Intent" msgstr "Intención" @@ -705,7 +722,7 @@ msgstr "La factura fue pagada con éxito" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:26 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:40 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:44 -#: src/containers/InvoiceList/index.tsx:44 +#: src/containers/InvoiceList/index.tsx:45 msgid "Invoices" msgstr "Facturas" @@ -713,7 +730,7 @@ msgstr "Facturas" msgid "Issued" msgstr "Agendado" -#: src/containers/InvoiceDetails/index.tsx:67 +#: src/containers/InvoiceDetails/index.tsx:72 msgid "Item" msgstr "Ítem" @@ -753,11 +770,11 @@ msgstr "Texto macro" msgid "Max" msgstr "Máximo" -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:17 +#: src/containers/InvoiceDetails/index.tsx:27 msgid "Medical Services Invoice" msgstr "Recibo de servicios médicos" -#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:30 +#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:28 #: src/containers/Prescriptions/index.tsx:113 msgid "Medication" msgstr "Medicación" @@ -779,7 +796,7 @@ msgid "Medication request successfully confirmed" msgstr "Solicitud de medicamento confirmada con éxito" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:45 -#: src/containers/MedicationManagement/index.tsx:28 +#: src/containers/MedicationManagement/index.tsx:29 msgid "Medications" msgstr "Medicaciones" @@ -795,25 +812,26 @@ msgstr "Mínimo" msgid "Monday" msgstr "Lunes" -#: src/containers/MedicationManagement/index.tsx:54 +#: src/containers/MedicationManagement/index.tsx:58 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:43 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:83 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:123 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:204 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:240 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:312 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:308 #: src/containers/PatientDetails/PatientResources/utils.tsx:50 #: src/containers/PatientDetails/PatientResources/utils.tsx:85 #: src/containers/PatientDetails/PatientResources/utils.tsx:124 #: src/containers/PatientDetails/PatientResources/utils.tsx:163 #: src/containers/PatientDetails/PatientResources/utils.tsx:199 -#: src/containers/PatientList/index.tsx:88 -#: src/containers/PractitionerList/index.tsx:113 +#: src/containers/PatientList/index.tsx:81 +#: src/containers/PatientResourceListExample/index.tsx:41 +#: src/containers/PractitionerList/index.tsx:108 msgid "Name" msgstr "Nombre" #. js-lingui-explicit-id -#: src/containers/QuestionnaireList/index.tsx:23 +#: src/containers/QuestionnaireList/index.tsx:22 msgid "msg.QuestionnaireName" msgstr "Nombre del cuestionario" @@ -822,8 +840,8 @@ msgstr "Nombre del cuestionario" msgid "New Appointment" msgstr "Nuevo agendamiento" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:151 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:176 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:148 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:173 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:137 #: src/utils/questionnaire.ts:63 msgid "No" @@ -831,13 +849,14 @@ msgstr "No" #: src/components/EncountersTable/index.tsx:30 #: src/components/ResourceTable/index.tsx:67 -#: src/containers/HealthcareServiceList/index.tsx:54 -#: src/containers/InvoiceList/index.tsx:70 -#: src/containers/PatientDetails/PatientWearables/index.tsx:88 -#: src/containers/PatientList/index.tsx:80 -#: src/containers/PractitionerList/index.tsx:106 +#: src/containers/HealthcareServiceList/index.tsx:48 +#: src/containers/InvoiceList/index.tsx:73 +#: src/containers/PatientDetails/PatientWearables/index.tsx:85 +#: src/containers/PatientList/index.tsx:73 +#: src/containers/PractitionerList/index.tsx:101 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:500 -#: src/containers/QuestionnaireList/index.tsx:107 +#: src/containers/QuestionnaireList/index.tsx:102 +#: src/uberComponents/ResourceListPage/index.tsx:214 msgid "No data" msgstr "Sin datos" @@ -861,12 +880,16 @@ msgstr "Notas" msgid "Number (default)" msgstr "Número (predeterminado)" +#: src/containers/PatientResourceListExample/index.tsx:83 +msgid "Number of Patients" +msgstr "" + #: src/containers/PatientDetails/PatientResources/utils.tsx:230 msgid "Observations" msgstr "Resultados" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:109 -#: src/containers/Prescriptions/index.tsx:192 +#: src/containers/Prescriptions/index.tsx:188 msgid "On Hold" msgstr "Guardado" @@ -875,13 +898,13 @@ msgstr "Guardado" msgid "On the next page, please, use one of the following credentials" msgstr "En la siguiente página, por favor, utilice una de las siguientes credenciales" -#: src/components/PatientEncounter/index.tsx:58 +#: src/components/PatientEncounter/index.tsx:57 #: src/containers/DocumentsList/index.tsx:79 -#: src/containers/EncounterList/index.tsx:82 +#: src/containers/EncounterList/index.tsx:81 #: src/containers/InvoiceList/tableUtils.tsx:82 #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/ModalNoteOpen/index.tsx:22 -#: src/containers/PatientList/index.tsx:127 -#: src/containers/PractitionerList/index.tsx:141 +#: src/containers/PatientList/index.tsx:119 +#: src/containers/PractitionerList/index.tsx:136 msgid "Open" msgstr "Abrir" @@ -896,7 +919,7 @@ msgstr "Opción {0}" msgid "Option {index}" msgstr "Opción {índice}" -#: src/containers/EncounterDetails/index.tsx:102 +#: src/containers/EncounterDetails/index.tsx:99 msgid "or" msgstr "o" @@ -904,15 +927,13 @@ msgstr "o" msgid "Order added" msgstr "Orden añadida" -#: src/containers/PatientDetails/PatientHeader/index.tsx:82 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:304 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:22 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:300 msgid "Orders" msgstr "Resultados" -#: src/containers/PatientDetails/PatientHeader/index.tsx:41 -#: src/containers/PatientDetails/PatientHeader/index.tsx:78 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:56 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:70 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:18 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:24 msgid "Overview" msgstr "Descripción general" @@ -926,22 +947,22 @@ msgid "Password" msgstr "Contraseña" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:39 -#: src/containers/EncounterList/index.tsx:46 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:20 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:39 +#: src/containers/EncounterList/index.tsx:45 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:17 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:38 #: src/containers/InvoiceList/tableUtils.tsx:122 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:48 -#: src/containers/Prescriptions/index.tsx:76 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:46 +#: src/containers/Prescriptions/index.tsx:78 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:69 msgid "Patient" msgstr "Paciente" -#: src/containers/PatientDetails/PatientWearables/index.tsx:93 +#: src/containers/PatientDetails/PatientWearables/index.tsx:90 msgid "Patient consent is required" msgstr "El consentimiento del paciente es necesario" #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:33 -#: src/containers/PatientList/index.tsx:145 +#: src/containers/PatientList/index.tsx:137 msgid "Patient saved" msgstr "Paciente guardado" @@ -951,8 +972,8 @@ msgstr "Paciente creado con éxito" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:29 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:35 -#: src/containers/PatientDetails/PatientHeader/index.tsx:26 -#: src/containers/PatientList/index.tsx:59 +#: src/containers/PatientList/index.tsx:55 +#: src/containers/PatientResourceListExample/index.tsx:36 msgid "Patients" msgstr "Pacientes" @@ -973,28 +994,26 @@ msgstr "Número telefónico" msgid "Phone widget" msgstr "Widget de teléfono" -#: src/components/PatientEncounter/index.tsx:26 -#: src/containers/EncounterList/index.tsx:52 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:23 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:33 +#: src/components/PatientEncounter/index.tsx:25 +#: src/containers/EncounterList/index.tsx:51 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:20 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:32 #: src/containers/InvoiceList/tableUtils.tsx:114 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:152 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:275 #: src/containers/PatientDetails/PatientResources/utils.tsx:221 msgid "Practitioner" msgstr "Profesional" -#: src/containers/PractitionerList/index.tsx:85 +#: src/containers/PractitionerList/index.tsx:79 msgid "Practitioner successfully created" msgstr "Profesional creado con éxito" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:30 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:37 -#: src/containers/PractitionerList/index.tsx:77 +#: src/containers/PractitionerList/index.tsx:73 msgid "Practitioners" msgstr "Profesionales" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:141 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:138 msgid "Prepare for print" msgstr "Preparar para imprimir" @@ -1007,16 +1026,16 @@ msgstr "Prescripciones" msgid "Properties" msgstr "Propiedades" -#: src/containers/PatientDetails/PatientWearables/index.tsx:53 +#: src/containers/PatientDetails/PatientWearables/index.tsx:52 msgid "Provider" msgstr "Proveedor" -#: src/containers/InvoiceDetails/index.tsx:76 +#: src/containers/InvoiceDetails/index.tsx:81 msgid "Quantity" msgstr "Cantidad" #: src/containers/DocumentsList/index.tsx:46 -#: src/containers/PatientQuestionnaire/index.tsx:73 +#: src/containers/PatientQuestionnaire/index.tsx:70 msgid "Questionnaire" msgstr "Cuestionario" @@ -1026,11 +1045,11 @@ msgstr "Propiedades del cuestionario" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:31 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:36 -#: src/containers/QuestionnaireList/index.tsx:80 +#: src/containers/QuestionnaireList/index.tsx:76 msgid "Questionnaires" msgstr "Cuestionarios" -#: src/containers/InvoiceDetails/index.tsx:83 +#: src/containers/InvoiceDetails/index.tsx:88 msgid "Rate" msgstr "Tasa" @@ -1046,8 +1065,8 @@ msgstr "Repite" msgid "Request Appointment" msgstr "Solicitar cita" -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:60 -#: src/containers/Prescriptions/index.tsx:88 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:58 +#: src/containers/Prescriptions/index.tsx:89 msgid "Requester" msgstr "Solicitante" @@ -1055,15 +1074,18 @@ msgstr "Solicitante" msgid "Required" msgstr "Requerido" -#: src/components/SearchBar/index.tsx:24 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:56 -#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:35 -#: src/containers/OrganizationScheduling/index.tsx:87 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:71 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:54 +#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:32 +#: src/containers/OrganizationScheduling/index.tsx:88 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:68 msgid "Reset" msgstr "Restablecer" -#: src/containers/PatientDetails/PatientHeader/index.tsx:84 +#: src/uberComponents/ResourceListPage/BatchActions.tsx:48 +msgid "Reset selection" +msgstr "" + +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:24 msgid "Resources" msgstr "Recursos" @@ -1088,8 +1110,8 @@ msgstr "Guardar" msgid "Save as draft" msgstr "" -#: src/containers/QuestionnaireBuilder/index.tsx:57 -#: src/containers/QuestionnaireBuilder/index.tsx:58 +#: src/containers/QuestionnaireBuilder/index.tsx:49 +#: src/containers/QuestionnaireBuilder/index.tsx:50 msgid "Save questionnaire" msgstr "Guardar cuestionario" @@ -1106,9 +1128,8 @@ msgid "Schedule calendar" msgstr "Calendario de programación" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:43 -#: src/containers/OrganizationScheduling/index.tsx:71 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:39 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:71 +#: src/containers/OrganizationScheduling/index.tsx:69 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:25 msgid "Scheduling" msgstr "Programación" @@ -1116,7 +1137,7 @@ msgstr "Programación" msgid "Scribe results" msgstr "Resultados de escritura" -#: src/containers/QuestionnaireList/index.tsx:51 +#: src/containers/QuestionnaireList/index.tsx:50 msgid "SDC IDE" msgstr "IDE SDC" @@ -1149,6 +1170,10 @@ msgstr "Ver detalles de ValueSet" msgid "Select (default)" msgstr "Seleccionar (predeterminado)" +#: src/uberComponents/ResourceListPage/BatchActions.tsx:69 +msgid "Select all" +msgstr "" + #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:30 #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:55 msgid "Select..." @@ -1159,8 +1184,8 @@ msgid "Serum creatinin" msgstr "Creatinina sérica" #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:279 -msgid "Service" -msgstr "Servicio" +#~ msgid "Service" +#~ msgstr "Servicio" #: src/containers/PatientDetails/PatientResources/utils.tsx:306 msgid "Service Requests" @@ -1182,11 +1207,15 @@ msgstr "Sexo" msgid "Share link" msgstr "Compartir enlace" +#: src/components/SearchBar/SearchBarMobile/index.tsx:48 +msgid "Show results" +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:53 msgid "Slider" msgstr "Deslizador" -#: src/containers/PatientDetails/PatientHeader/index.tsx:83 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:23 msgid "Smart Apps" msgstr "Aplicaciones Inteligentes" @@ -1195,15 +1224,16 @@ msgid "Solid radio button" msgstr "Botón de opción sólido" #: src/containers/PractitionerDetails/PractitionerOverview/index.tsx:40 -#: src/containers/PractitionerList/index.tsx:119 +#: src/containers/PractitionerList/index.tsx:114 msgid "Specialty" msgstr "Especialidad" -#: src/containers/PatientList/index.tsx:102 +#: src/containers/PatientList/index.tsx:94 +#: src/containers/PatientResourceListExample/index.tsx:55 msgid "SSN" msgstr "NSS" -#: src/containers/PatientDetails/PatientWearables/index.tsx:35 +#: src/containers/PatientDetails/PatientWearables/index.tsx:34 msgid "Start" msgstr "Comenzar" @@ -1212,7 +1242,7 @@ msgid "Start date" msgstr "Fecha de inicio" #: src/components/BaseQuestionnaireResponseForm/widgets/AudioRecorderUploader/index.tsx:72 -#: src/containers/EncounterDetails/index.tsx:114 +#: src/containers/EncounterDetails/index.tsx:111 msgid "Start scribe" msgstr "Iniciar escritura" @@ -1225,19 +1255,19 @@ msgstr "Comenzar el encuentro" msgid "Start value" msgstr "Valor inicial" -#: src/containers/EncounterDetails/index.tsx:94 +#: src/containers/EncounterDetails/index.tsx:91 msgid "Start video call" msgstr "Iniciar videollamada" -#: src/components/PatientEncounter/index.tsx:32 +#: src/components/PatientEncounter/index.tsx:31 #: src/containers/DocumentsList/index.tsx:63 -#: src/containers/EncounterList/index.tsx:58 -#: src/containers/HealthcareServiceList/index.tsx:78 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:29 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:51 +#: src/containers/EncounterList/index.tsx:57 +#: src/containers/HealthcareServiceList/index.tsx:72 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:26 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:50 #: src/containers/InvoiceList/tableUtils.tsx:136 #: src/containers/PatientDetails/PatientResources/utils.tsx:343 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:66 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:64 #: src/containers/Prescriptions/index.tsx:132 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:77 msgid "Status" @@ -1256,7 +1286,7 @@ msgid "Stop value" msgstr "Valor de parada" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:117 -#: src/containers/Prescriptions/index.tsx:196 +#: src/containers/Prescriptions/index.tsx:192 msgid "Stopped" msgstr "Detenido" @@ -1269,9 +1299,24 @@ msgid "Subject Type" msgstr "Tipo de sujeto" #: src/containers/QuestionnaireBuilder/PromptForm.tsx:104 +#: src/uberComponents/ResourceListPage/actions.tsx:97 +#: src/uberComponents/ResourceListPage/actions.tsx:131 +#: src/uberComponents/ResourceListPage/actions.tsx:177 msgid "Submit" msgstr "Enviar" +#: src/uberComponents/ResourceListPage/actions.tsx:78 +#: src/uberComponents/ResourceListPage/actions.tsx:105 +#: src/uberComponents/ResourceListPage/actions.tsx:146 +#~ msgid "Successfully saved" +#~ msgstr "" + +#: src/uberComponents/ResourceListPage/actions.tsx:91 +#: src/uberComponents/ResourceListPage/actions.tsx:126 +#: src/uberComponents/ResourceListPage/actions.tsx:173 +msgid "Successfully submitted" +msgstr "" + #: src/containers/Scheduling/Availability/index.tsx:43 msgid "Successfully updated" msgstr "Actualizado exitosamente" @@ -1284,7 +1329,7 @@ msgstr "Domingo" msgid "System" msgstr "Sistema" -#: src/containers/InvoiceDetails/index.tsx:90 +#: src/containers/InvoiceDetails/index.tsx:95 msgid "Tax" msgstr "Impuesto" @@ -1301,19 +1346,19 @@ msgstr "Texto (por defecto)" msgid "Text with macro" msgstr "Texto con macro" -#: src/containers/App/index.tsx:129 +#: src/containers/App/index.tsx:130 msgid "Thank you for filling out the questionnaire. Now you can close this page." msgstr "Gracias por completar el cuestionario. Ahora puedes cerrar esta página." -#: src/containers/App/index.tsx:128 +#: src/containers/App/index.tsx:129 msgid "Thank you!" msgstr "¡Gracias!" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:99 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:98 msgid "The document does not exist" msgstr "El documento no existe" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:71 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:70 msgid "The document successfully amended" msgstr "El documento fue modificado exitosamente" @@ -1342,7 +1387,7 @@ msgstr "" msgid "Thursday" msgstr "Jueves" -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:287 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:275 #: src/containers/Scheduling/Availability/index.tsx:129 msgid "Time" msgstr "Hora" @@ -1355,7 +1400,7 @@ msgstr "Hora" msgid "Title" msgstr "Título" -#: src/containers/PatientDetails/PatientWearables/index.tsx:111 +#: src/containers/PatientDetails/PatientWearables/index.tsx:108 msgid "To obtain this information, you need to authorize your account in the mobile application and link it with your health data providers." msgstr "Para obtener esta información, necesitas autorizar tu cuenta en la aplicación móvil y enlazarla con tus proveedores de datos clínicos" @@ -1363,7 +1408,7 @@ msgstr "Para obtener esta información, necesitas autorizar tu cuenta en la apli msgid "Today" msgstr "Hoy" -#: src/containers/InvoiceDetails/index.tsx:117 +#: src/containers/InvoiceDetails/index.tsx:122 msgid "Total" msgstr "Total" @@ -1375,7 +1420,7 @@ msgstr "Verdadero" msgid "Tuesday" msgstr "Martes" -#: src/containers/HealthcareServiceList/index.tsx:61 +#: src/containers/HealthcareServiceList/index.tsx:55 msgid "Type" msgstr "Tipo" @@ -1388,7 +1433,7 @@ msgstr "Unidades" #: src/containers/InvoiceList/tableUtils.tsx:34 #: src/containers/PatientDetails/PatientDocumentDetails/ExternalDocumentView/index.tsx:53 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:125 -#: src/containers/Prescriptions/index.tsx:198 +#: src/containers/Prescriptions/index.tsx:194 #: src/containers/Scheduling/available-time.ts:22 msgid "Unknown" msgstr "Desconocido" @@ -1427,13 +1472,13 @@ msgstr "Detalles de ValueSet" msgid "ValueSet url" msgstr "URL de ValueSet" -#: src/components/PatientEncounter/index.tsx:63 -#: src/containers/EncounterList/index.tsx:91 +#: src/components/PatientEncounter/index.tsx:62 +#: src/containers/EncounterList/index.tsx:90 +#: src/containers/VideoCall/index.tsx:28 msgid "Video call" msgstr "Videollamada" -#: src/containers/PatientDetails/PatientHeader/index.tsx:81 -#: src/containers/PatientDetails/PatientWearables/index.tsx:64 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:21 msgid "Wearables" msgstr "Dispositivos" @@ -1449,14 +1494,14 @@ msgstr "Semana" msgid "Welcome to" msgstr "Bienvenido a" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:150 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:175 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:147 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:172 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:136 #: src/utils/questionnaire.ts:63 msgid "Yes" msgstr "Sí" -#: src/containers/PatientDetails/PatientWearables/index.tsx:110 +#: src/containers/PatientDetails/PatientWearables/index.tsx:107 msgid "You currently lack access to the patient's data. To obtain it, you must secure the patient's signed consent authorizing the release of their activity data." msgstr "Actualmente no tienes acceso a los datos del paciente. Para obtenerlos, debes conseguir el consentimiento firmado del paciente que autorice la liberación de sus datos de actividad." diff --git a/src/locale/ru/messages.po b/src/locale/ru/messages.po index 9300ab0c..cbbc5d0f 100644 --- a/src/locale/ru/messages.po +++ b/src/locale/ru/messages.po @@ -13,24 +13,25 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" -#: src/components/BaseQuestionnaireResponseForm/index.tsx:247 -#~ msgid "{0}" -#~ msgstr "" +#: src/uberComponents/ResourceListPage/BatchActions.tsx:57 +msgid "{0, plural, one {Selected # item} other {Selected # items}}" +msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/NoteList/index.tsx:55 msgid "Action" msgstr "" -#: src/components/PatientEncounter/index.tsx:47 +#: src/components/PatientEncounter/index.tsx:46 #: src/containers/DocumentsList/index.tsx:69 -#: src/containers/EncounterList/index.tsx:71 -#: src/containers/HealthcareServiceList/index.tsx:85 +#: src/containers/EncounterList/index.tsx:70 +#: src/containers/HealthcareServiceList/index.tsx:79 #: src/containers/InvoiceList/tableUtils.tsx:150 #: src/containers/InvoiceList/tableUtils.tsx:157 -#: src/containers/MedicationManagement/index.tsx:67 -#: src/containers/PatientList/index.tsx:111 -#: src/containers/PractitionerList/index.tsx:126 -#: src/containers/Prescriptions/index.tsx:151 +#: src/containers/MedicationManagement/index.tsx:71 +#: src/containers/PatientList/index.tsx:103 +#: src/containers/PractitionerList/index.tsx:121 +#: src/containers/Prescriptions/index.tsx:148 +#: src/uberComponents/ResourceListPage/index.tsx:273 msgid "Actions" msgstr "Действия" @@ -43,7 +44,7 @@ msgid "Activate healthcare service" msgstr "" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:97 -#: src/containers/Prescriptions/index.tsx:191 +#: src/containers/Prescriptions/index.tsx:187 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:82 msgid "Active" msgstr "Активный" @@ -57,7 +58,7 @@ msgstr "" msgid "Activities" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:22 +#: src/containers/PatientDetails/PatientWearables/index.tsx:21 msgid "Activity" msgstr "" @@ -86,7 +87,7 @@ msgstr "" msgid "Add Medication Batch" msgstr "" -#: src/containers/PractitionerList/index.tsx:34 +#: src/containers/PractitionerList/index.tsx:33 msgid "Add new practitioner" msgstr "" @@ -109,10 +110,11 @@ msgstr "" #: src/components/ModalNewPatient/index.tsx:16 #: src/components/ModalNewPatient/index.tsx:20 +#: src/containers/PatientResourceListExample/index.tsx:78 msgid "Add patient" msgstr "Добавить пациенда" -#: src/containers/QuestionnaireList/index.tsx:87 +#: src/containers/QuestionnaireList/index.tsx:81 msgid "Add questionnaire" msgstr "Добавить опросник" @@ -120,11 +122,11 @@ msgstr "Добавить опросник" msgid "Adjust Last Option Right" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:40 +#: src/containers/QuestionnaireList/index.tsx:39 msgid "AI builder" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:57 +#: src/containers/QuestionnaireList/index.tsx:56 msgid "Aidbox Forms Builder" msgstr "" @@ -133,11 +135,11 @@ msgstr "" msgid "Allergies" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:154 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:151 msgid "Amend" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:97 +#: src/containers/InvoiceDetails/index.tsx:102 #: src/containers/InvoiceList/tableUtils.tsx:143 #: src/containers/MedicationManagement/utils.tsx:36 msgid "Amount" @@ -147,29 +149,29 @@ msgstr "" msgid "Appointment" msgstr "" -#: src/containers/Appointment/PublicAppointment.tsx:48 +#: src/containers/Appointment/PublicAppointment.tsx:44 msgid "Appointment booking" msgstr "" -#: src/containers/OrganizationScheduling/index.tsx:223 +#: src/containers/OrganizationScheduling/index.tsx:224 #: src/containers/Scheduling/ScheduleCalendar/index.tsx:93 msgid "Appointment successfully added" msgstr "" -#: src/containers/Appointment/PublicAppointment.tsx:61 +#: src/containers/Appointment/PublicAppointment.tsx:53 msgid "Appointment successfully created" msgstr "" -#: src/containers/OrganizationScheduling/index.tsx:176 +#: src/containers/OrganizationScheduling/index.tsx:177 #: src/containers/Scheduling/ScheduleCalendar/index.tsx:76 msgid "Appointment successfully rescheduled" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:149 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:146 msgid "Are you sure you want to amend the document?" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:174 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:171 msgid "Are you sure you want to delete the document?" msgstr "" @@ -177,8 +179,7 @@ msgstr "" msgid "Are you sure you want to delete this item?" msgstr "" -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:40 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:72 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:26 #: src/containers/Scheduling/Availability/index.tsx:54 msgid "Availability" msgstr "" @@ -205,7 +206,8 @@ msgid "Batch Number" msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/containers/GeneralIInformationDashboardContainer/hooks.ts:31 -#: src/containers/PatientList/index.tsx:94 +#: src/containers/PatientList/index.tsx:87 +#: src/containers/PatientResourceListExample/index.tsx:48 msgid "Birth date" msgstr "Дата рождения" @@ -217,11 +219,11 @@ msgstr "" msgid "Break" msgstr "" -#: src/containers/QuestionnaireBuilder/index.tsx:49 +#: src/containers/QuestionnaireBuilder/index.tsx:43 msgid "Build your form" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:47 +#: src/containers/PatientDetails/PatientWearables/index.tsx:46 msgid "Calories" msgstr "" @@ -243,7 +245,7 @@ msgstr "" #: src/containers/InvoiceList/tableUtils.tsx:28 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:101 -#: src/containers/Prescriptions/index.tsx:193 +#: src/containers/Prescriptions/index.tsx:189 msgid "Cancelled" msgstr "" @@ -256,6 +258,11 @@ msgstr "" msgid "Characteristics" msgstr "" +#: src/components/SearchBar/index.tsx:36 +#: src/components/SearchBar/SearchBarMobile/index.tsx:51 +msgid "Clear filters" +msgstr "" + #: src/components/BaseQuestionnaireResponseForm/widgets/UploadFileControl/index.tsx:29 msgid "Click or drag file to this area to upload" msgstr "" @@ -281,8 +288,8 @@ msgstr "" msgid "Complete" msgstr "" -#: src/containers/EncounterDetails/index.tsx:176 -#: src/containers/EncounterDetails/index.tsx:180 +#: src/containers/EncounterDetails/index.tsx:173 +#: src/containers/EncounterDetails/index.tsx:177 msgid "Complete encounter" msgstr "" @@ -292,7 +299,7 @@ msgid "completed" msgstr "" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:105 -#: src/containers/Prescriptions/index.tsx:194 +#: src/containers/Prescriptions/index.tsx:190 msgid "Completed" msgstr "" @@ -318,16 +325,15 @@ msgstr "" msgid "Consents" msgstr "" -#: src/containers/EncounterDetails/index.tsx:48 -#: src/containers/EncounterDetails/index.tsx:61 +#: src/containers/EncounterDetails/index.tsx:58 msgid "Consultation" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:92 +#: src/containers/PatientDetails/PatientWearables/index.tsx:89 msgid "Contact the patient to obtain their consent for accessing activity data" msgstr "" -#: src/containers/MedicationManagement/index.tsx:60 +#: src/containers/MedicationManagement/index.tsx:64 #: src/containers/MedicationManagement/utils.tsx:39 msgid "Cost" msgstr "" @@ -338,7 +344,7 @@ msgstr "" #: src/containers/DocumentsList/ChooseDocumentToCreateModal/index.tsx:52 #: src/containers/EncounterDetails/hooks.ts:31 -#: src/containers/PatientDetails/PatientDocuments/index.tsx:33 +#: src/containers/PatientDetails/PatientDocuments/index.tsx:29 msgid "Create document" msgstr "" @@ -348,7 +354,7 @@ msgstr "" msgid "Create Encounter" msgstr "" -#: src/containers/PractitionerList/index.tsx:30 +#: src/containers/PractitionerList/index.tsx:29 msgid "Create practitioner" msgstr "" @@ -369,15 +375,15 @@ msgstr "" msgid "CRP" msgstr "" -#: src/components/PatientEncounter/index.tsx:40 -#: src/containers/EncounterList/index.tsx:64 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:26 +#: src/components/PatientEncounter/index.tsx:39 +#: src/containers/EncounterList/index.tsx:63 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:23 #: src/containers/InvoiceList/tableUtils.tsx:129 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:55 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:95 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:142 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:216 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:283 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:271 #: src/containers/PatientDetails/PatientResources/utils.tsx:96 #: src/containers/PatientDetails/PatientResources/utils.tsx:135 #: src/containers/PatientDetails/PatientResources/utils.tsx:174 @@ -419,11 +425,15 @@ msgstr "" msgid "Default" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:179 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:176 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:140 msgid "Delete" msgstr "" +#: src/containers/PatientResourceListExample/index.tsx:80 +msgid "Delete patients" +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:133 msgid "Delete Questionnaire Item" msgstr "" @@ -448,8 +458,7 @@ msgstr "" msgid "Display" msgstr "" -#: src/containers/PatientDetails/PatientDocuments/index.tsx:23 -#: src/containers/PatientDetails/PatientHeader/index.tsx:80 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:20 msgid "Documents" msgstr "Документы" @@ -472,28 +481,28 @@ msgstr "" #: src/containers/InvoiceList/tableUtils.tsx:30 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:121 -#: src/containers/Prescriptions/index.tsx:197 +#: src/containers/Prescriptions/index.tsx:193 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:81 msgid "Draft" msgstr "Черновик" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:47 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:46 msgid "Draft successfully deleted" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:28 +#: src/containers/PatientDetails/PatientWearables/index.tsx:27 msgid "Duration (min)" msgstr "" -#: src/containers/HealthcareServiceList/index.tsx:68 +#: src/containers/HealthcareServiceList/index.tsx:62 msgid "Duration (minutes)" msgstr "" #: src/components/ModalEditHealthcareService/index.tsx:21 #: src/containers/EncounterDetails/AIScribe/index.tsx:197 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:187 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:184 #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:23 -#: src/containers/PatientList/index.tsx:135 +#: src/containers/PatientList/index.tsx:127 #: src/containers/PractitionerDetails/PractitionerOverview/index.tsx:67 #: src/containers/Scheduling/ScheduleCalendar/components/AppointmentDetailsModal/index.tsx:87 msgid "Edit" @@ -507,7 +516,7 @@ msgstr "" msgid "Edit Healthcare Service" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:30 +#: src/containers/QuestionnaireList/index.tsx:29 msgid "Edit in" msgstr "" @@ -516,7 +525,7 @@ msgstr "" #~ msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:20 -#: src/containers/PatientList/index.tsx:132 +#: src/containers/PatientList/index.tsx:124 msgid "Edit patient" msgstr "Редактировать пациента" @@ -532,7 +541,7 @@ msgstr "" msgid "Encounter" msgstr "" -#: src/containers/EncounterDetails/index.tsx:127 +#: src/containers/EncounterDetails/index.tsx:124 msgid "Encounter completed" msgstr "" @@ -540,19 +549,18 @@ msgstr "" msgid "Encounter successfully created" msgstr "" -#: src/containers/EncounterDetails/index.tsx:196 +#: src/containers/EncounterDetails/index.tsx:193 msgid "Encounter was successfully completed" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:28 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:34 -#: src/components/PatientEncounter/index.tsx:79 -#: src/containers/EncounterList/index.tsx:103 -#: src/containers/PatientDetails/PatientHeader/index.tsx:79 +#: src/containers/EncounterList/index.tsx:101 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:19 msgid "Encounters" msgstr "Приемы" -#: src/containers/PatientDetails/PatientWearables/index.tsx:41 +#: src/containers/PatientDetails/PatientWearables/index.tsx:40 msgid "End" msgstr "" @@ -562,11 +570,11 @@ msgstr "Конец периода" #: src/containers/InvoiceList/tableUtils.tsx:31 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:113 -#: src/containers/Prescriptions/index.tsx:195 +#: src/containers/Prescriptions/index.tsx:191 msgid "Entered in error" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:53 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:52 msgid "Error deleting a draft" msgstr "" @@ -574,7 +582,7 @@ msgstr "" msgid "Error saving a draft:" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:77 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:76 msgid "Error while amending the document" msgstr "" @@ -607,7 +615,12 @@ msgstr "" msgid "Fill" msgstr "" +#: src/components/SearchBar/SearchBarMobile/index.tsx:33 +msgid "Filters" +msgstr "" + #: src/containers/PatientList/searchBarUtils.ts:10 +#: src/containers/PatientResourceListExample/index.tsx:68 msgid "Find patient" msgstr "Найти пациента" @@ -657,7 +670,7 @@ msgstr "" msgid "Healthcare service successfully updated" msgstr "" -#: src/containers/HealthcareServiceList/index.tsx:32 +#: src/containers/HealthcareServiceList/index.tsx:29 msgid "Healthcare Services" msgstr "" @@ -669,7 +682,7 @@ msgstr "" msgid "Here will be your questionnaire" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:163 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:160 msgid "History" msgstr "" @@ -698,7 +711,7 @@ msgstr "" msgid "Inline options?" msgstr "" -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:317 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:313 msgid "Intent" msgstr "" @@ -713,7 +726,7 @@ msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:26 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:40 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:44 -#: src/containers/InvoiceList/index.tsx:44 +#: src/containers/InvoiceList/index.tsx:45 msgid "Invoices" msgstr "" @@ -721,7 +734,7 @@ msgstr "" msgid "Issued" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:67 +#: src/containers/InvoiceDetails/index.tsx:72 msgid "Item" msgstr "" @@ -765,11 +778,11 @@ msgstr "" msgid "Max" msgstr "" -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:17 +#: src/containers/InvoiceDetails/index.tsx:27 msgid "Medical Services Invoice" msgstr "" -#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:30 +#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:28 #: src/containers/Prescriptions/index.tsx:113 msgid "Medication" msgstr "" @@ -791,7 +804,7 @@ msgid "Medication request successfully confirmed" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:45 -#: src/containers/MedicationManagement/index.tsx:28 +#: src/containers/MedicationManagement/index.tsx:29 msgid "Medications" msgstr "" @@ -807,25 +820,26 @@ msgstr "" msgid "Monday" msgstr "" -#: src/containers/MedicationManagement/index.tsx:54 +#: src/containers/MedicationManagement/index.tsx:58 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:43 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:83 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:123 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:204 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:240 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:312 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:308 #: src/containers/PatientDetails/PatientResources/utils.tsx:50 #: src/containers/PatientDetails/PatientResources/utils.tsx:85 #: src/containers/PatientDetails/PatientResources/utils.tsx:124 #: src/containers/PatientDetails/PatientResources/utils.tsx:163 #: src/containers/PatientDetails/PatientResources/utils.tsx:199 -#: src/containers/PatientList/index.tsx:88 -#: src/containers/PractitionerList/index.tsx:113 +#: src/containers/PatientList/index.tsx:81 +#: src/containers/PatientResourceListExample/index.tsx:41 +#: src/containers/PractitionerList/index.tsx:108 msgid "Name" msgstr "Имя" #. js-lingui-explicit-id -#: src/containers/QuestionnaireList/index.tsx:23 +#: src/containers/QuestionnaireList/index.tsx:22 msgid "msg.QuestionnaireName" msgstr "Название" @@ -834,8 +848,8 @@ msgstr "Название" msgid "New Appointment" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:151 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:176 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:148 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:173 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:137 #: src/utils/questionnaire.ts:63 msgid "No" @@ -843,13 +857,14 @@ msgstr "" #: src/components/EncountersTable/index.tsx:30 #: src/components/ResourceTable/index.tsx:67 -#: src/containers/HealthcareServiceList/index.tsx:54 -#: src/containers/InvoiceList/index.tsx:70 -#: src/containers/PatientDetails/PatientWearables/index.tsx:88 -#: src/containers/PatientList/index.tsx:80 -#: src/containers/PractitionerList/index.tsx:106 +#: src/containers/HealthcareServiceList/index.tsx:48 +#: src/containers/InvoiceList/index.tsx:73 +#: src/containers/PatientDetails/PatientWearables/index.tsx:85 +#: src/containers/PatientList/index.tsx:73 +#: src/containers/PractitionerList/index.tsx:101 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:500 -#: src/containers/QuestionnaireList/index.tsx:107 +#: src/containers/QuestionnaireList/index.tsx:102 +#: src/uberComponents/ResourceListPage/index.tsx:214 msgid "No data" msgstr "Нет данных" @@ -873,12 +888,16 @@ msgstr "" msgid "Number (default)" msgstr "" +#: src/containers/PatientResourceListExample/index.tsx:83 +msgid "Number of Patients" +msgstr "" + #: src/containers/PatientDetails/PatientResources/utils.tsx:230 msgid "Observations" msgstr "" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:109 -#: src/containers/Prescriptions/index.tsx:192 +#: src/containers/Prescriptions/index.tsx:188 msgid "On Hold" msgstr "" @@ -891,13 +910,13 @@ msgstr "" #~ msgid "On the next page, please, use the following credentials" #~ msgstr "" -#: src/components/PatientEncounter/index.tsx:58 +#: src/components/PatientEncounter/index.tsx:57 #: src/containers/DocumentsList/index.tsx:79 -#: src/containers/EncounterList/index.tsx:82 +#: src/containers/EncounterList/index.tsx:81 #: src/containers/InvoiceList/tableUtils.tsx:82 #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/ModalNoteOpen/index.tsx:22 -#: src/containers/PatientList/index.tsx:127 -#: src/containers/PractitionerList/index.tsx:141 +#: src/containers/PatientList/index.tsx:119 +#: src/containers/PractitionerList/index.tsx:136 msgid "Open" msgstr "Открыть" @@ -912,7 +931,7 @@ msgstr "" msgid "Option {index}" msgstr "" -#: src/containers/EncounterDetails/index.tsx:102 +#: src/containers/EncounterDetails/index.tsx:99 msgid "or" msgstr "" @@ -920,15 +939,13 @@ msgstr "" msgid "Order added" msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:82 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:304 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:22 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:300 msgid "Orders" msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:41 -#: src/containers/PatientDetails/PatientHeader/index.tsx:78 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:56 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:70 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:18 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:24 msgid "Overview" msgstr "" @@ -942,22 +959,22 @@ msgid "Password" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:39 -#: src/containers/EncounterList/index.tsx:46 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:20 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:39 +#: src/containers/EncounterList/index.tsx:45 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:17 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:38 #: src/containers/InvoiceList/tableUtils.tsx:122 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:48 -#: src/containers/Prescriptions/index.tsx:76 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:46 +#: src/containers/Prescriptions/index.tsx:78 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:69 msgid "Patient" msgstr "Пациент" -#: src/containers/PatientDetails/PatientWearables/index.tsx:93 +#: src/containers/PatientDetails/PatientWearables/index.tsx:90 msgid "Patient consent is required" msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/components/EditPatient/index.tsx:33 -#: src/containers/PatientList/index.tsx:145 +#: src/containers/PatientList/index.tsx:137 msgid "Patient saved" msgstr "Пациент сохранен" @@ -967,8 +984,8 @@ msgstr "Пациент успешно создан" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:29 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:35 -#: src/containers/PatientDetails/PatientHeader/index.tsx:26 -#: src/containers/PatientList/index.tsx:59 +#: src/containers/PatientList/index.tsx:55 +#: src/containers/PatientResourceListExample/index.tsx:36 msgid "Patients" msgstr "Пациенты" @@ -989,28 +1006,26 @@ msgstr "" msgid "Phone widget" msgstr "" -#: src/components/PatientEncounter/index.tsx:26 -#: src/containers/EncounterList/index.tsx:52 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:23 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:33 +#: src/components/PatientEncounter/index.tsx:25 +#: src/containers/EncounterList/index.tsx:51 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:20 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:32 #: src/containers/InvoiceList/tableUtils.tsx:114 #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:152 -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:275 #: src/containers/PatientDetails/PatientResources/utils.tsx:221 msgid "Practitioner" msgstr "Врач" -#: src/containers/PractitionerList/index.tsx:85 +#: src/containers/PractitionerList/index.tsx:79 msgid "Practitioner successfully created" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:30 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:37 -#: src/containers/PractitionerList/index.tsx:77 +#: src/containers/PractitionerList/index.tsx:73 msgid "Practitioners" msgstr "Врачи" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:141 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:138 msgid "Prepare for print" msgstr "" @@ -1023,16 +1038,16 @@ msgstr "" msgid "Properties" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:53 +#: src/containers/PatientDetails/PatientWearables/index.tsx:52 msgid "Provider" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:76 +#: src/containers/InvoiceDetails/index.tsx:81 msgid "Quantity" msgstr "" #: src/containers/DocumentsList/index.tsx:46 -#: src/containers/PatientQuestionnaire/index.tsx:73 +#: src/containers/PatientQuestionnaire/index.tsx:70 msgid "Questionnaire" msgstr "Опросник" @@ -1042,11 +1057,11 @@ msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:31 #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:36 -#: src/containers/QuestionnaireList/index.tsx:80 +#: src/containers/QuestionnaireList/index.tsx:76 msgid "Questionnaires" msgstr "Опросники" -#: src/containers/InvoiceDetails/index.tsx:83 +#: src/containers/InvoiceDetails/index.tsx:88 msgid "Rate" msgstr "" @@ -1062,8 +1077,8 @@ msgstr "" msgid "Request Appointment" msgstr "" -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:60 -#: src/containers/Prescriptions/index.tsx:88 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:58 +#: src/containers/Prescriptions/index.tsx:89 msgid "Requester" msgstr "" @@ -1071,11 +1086,10 @@ msgstr "" msgid "Required" msgstr "" -#: src/components/SearchBar/index.tsx:24 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:56 -#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:35 -#: src/containers/OrganizationScheduling/index.tsx:87 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:71 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:54 +#: src/containers/MedicationManagement/components/MedicationsSearchBar/index.tsx:32 +#: src/containers/OrganizationScheduling/index.tsx:88 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:68 msgid "Reset" msgstr "Сбросить" @@ -1083,7 +1097,11 @@ msgstr "Сбросить" #~ msgid "Reset password" #~ msgstr "Сбросить пароль" -#: src/containers/PatientDetails/PatientHeader/index.tsx:84 +#: src/uberComponents/ResourceListPage/BatchActions.tsx:48 +msgid "Reset selection" +msgstr "" + +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:24 msgid "Resources" msgstr "" @@ -1108,8 +1126,8 @@ msgstr "Сохранить" msgid "Save as draft" msgstr "" -#: src/containers/QuestionnaireBuilder/index.tsx:57 -#: src/containers/QuestionnaireBuilder/index.tsx:58 +#: src/containers/QuestionnaireBuilder/index.tsx:49 +#: src/containers/QuestionnaireBuilder/index.tsx:50 msgid "Save questionnaire" msgstr "" @@ -1126,9 +1144,8 @@ msgid "Schedule calendar" msgstr "" #: src/components/BaseLayout/Sidebar/SidebarTop/context.tsx:43 -#: src/containers/OrganizationScheduling/index.tsx:71 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:39 -#: src/containers/PractitionerDetails/PractitionerHeader/index.tsx:71 +#: src/containers/OrganizationScheduling/index.tsx:69 +#: src/containers/PractitionerDetails/PractitionerDetailsTabs/index.tsx:25 msgid "Scheduling" msgstr "" @@ -1136,7 +1153,7 @@ msgstr "" msgid "Scribe results" msgstr "" -#: src/containers/QuestionnaireList/index.tsx:51 +#: src/containers/QuestionnaireList/index.tsx:50 msgid "SDC IDE" msgstr "" @@ -1153,6 +1170,10 @@ msgstr "Поиск по пациенту" msgid "Search by practitioner" msgstr "Поиск по врачу" +#: src/containers/EncounterList/searchBarUtils.ts:22 +#~ msgid "Search by status" +#~ msgstr "" + #: src/containers/PatientDetails/PatientOrders/index.tsx:177 msgid "Search orders" msgstr "" @@ -1169,6 +1190,10 @@ msgstr "" msgid "Select (default)" msgstr "" +#: src/uberComponents/ResourceListPage/BatchActions.tsx:69 +msgid "Select all" +msgstr "" + #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:30 #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:55 msgid "Select..." @@ -1179,8 +1204,8 @@ msgid "Serum creatinin" msgstr "" #: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:279 -msgid "Service" -msgstr "" +#~ msgid "Service" +#~ msgstr "" #: src/containers/PatientDetails/PatientResources/utils.tsx:306 msgid "Service Requests" @@ -1202,11 +1227,15 @@ msgstr "" msgid "Share link" msgstr "" +#: src/components/SearchBar/SearchBarMobile/index.tsx:48 +msgid "Show results" +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:53 msgid "Slider" msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:83 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:23 msgid "Smart Apps" msgstr "" @@ -1215,15 +1244,16 @@ msgid "Solid radio button" msgstr "" #: src/containers/PractitionerDetails/PractitionerOverview/index.tsx:40 -#: src/containers/PractitionerList/index.tsx:119 +#: src/containers/PractitionerList/index.tsx:114 msgid "Specialty" msgstr "" -#: src/containers/PatientList/index.tsx:102 +#: src/containers/PatientList/index.tsx:94 +#: src/containers/PatientResourceListExample/index.tsx:55 msgid "SSN" msgstr "СНИЛС" -#: src/containers/PatientDetails/PatientWearables/index.tsx:35 +#: src/containers/PatientDetails/PatientWearables/index.tsx:34 msgid "Start" msgstr "" @@ -1232,7 +1262,7 @@ msgid "Start date" msgstr "Начало периода" #: src/components/BaseQuestionnaireResponseForm/widgets/AudioRecorderUploader/index.tsx:72 -#: src/containers/EncounterDetails/index.tsx:114 +#: src/containers/EncounterDetails/index.tsx:111 msgid "Start scribe" msgstr "" @@ -1245,19 +1275,19 @@ msgstr "" msgid "Start value" msgstr "" -#: src/containers/EncounterDetails/index.tsx:94 +#: src/containers/EncounterDetails/index.tsx:91 msgid "Start video call" msgstr "" -#: src/components/PatientEncounter/index.tsx:32 +#: src/components/PatientEncounter/index.tsx:31 #: src/containers/DocumentsList/index.tsx:63 -#: src/containers/EncounterList/index.tsx:58 -#: src/containers/HealthcareServiceList/index.tsx:78 -#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:29 -#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:51 +#: src/containers/EncounterList/index.tsx:57 +#: src/containers/HealthcareServiceList/index.tsx:72 +#: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:26 +#: src/containers/InvoiceList/components/InvoiceListSearchBar/index.tsx:50 #: src/containers/InvoiceList/tableUtils.tsx:136 #: src/containers/PatientDetails/PatientResources/utils.tsx:343 -#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:66 +#: src/containers/Prescriptions/components/PrescriptionsSearchBar/index.tsx:64 #: src/containers/Prescriptions/index.tsx:132 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:77 msgid "Status" @@ -1276,7 +1306,7 @@ msgid "Stop value" msgstr "" #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:117 -#: src/containers/Prescriptions/index.tsx:196 +#: src/containers/Prescriptions/index.tsx:192 msgid "Stopped" msgstr "" @@ -1289,9 +1319,24 @@ msgid "Subject Type" msgstr "" #: src/containers/QuestionnaireBuilder/PromptForm.tsx:104 +#: src/uberComponents/ResourceListPage/actions.tsx:97 +#: src/uberComponents/ResourceListPage/actions.tsx:131 +#: src/uberComponents/ResourceListPage/actions.tsx:177 msgid "Submit" msgstr "" +#: src/uberComponents/ResourceListPage/actions.tsx:78 +#: src/uberComponents/ResourceListPage/actions.tsx:105 +#: src/uberComponents/ResourceListPage/actions.tsx:146 +#~ msgid "Successfully saved" +#~ msgstr "" + +#: src/uberComponents/ResourceListPage/actions.tsx:91 +#: src/uberComponents/ResourceListPage/actions.tsx:126 +#: src/uberComponents/ResourceListPage/actions.tsx:173 +msgid "Successfully submitted" +msgstr "" + #: src/containers/Scheduling/Availability/index.tsx:43 msgid "Successfully updated" msgstr "" @@ -1304,7 +1349,7 @@ msgstr "" msgid "System" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:90 +#: src/containers/InvoiceDetails/index.tsx:95 msgid "Tax" msgstr "" @@ -1321,19 +1366,19 @@ msgstr "" msgid "Text with macro" msgstr "" -#: src/containers/App/index.tsx:129 +#: src/containers/App/index.tsx:130 msgid "Thank you for filling out the questionnaire. Now you can close this page." msgstr "" -#: src/containers/App/index.tsx:128 +#: src/containers/App/index.tsx:129 msgid "Thank you!" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:99 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:98 msgid "The document does not exist" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:71 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:70 msgid "The document successfully amended" msgstr "" @@ -1362,7 +1407,7 @@ msgstr "" msgid "Thursday" msgstr "" -#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:287 +#: src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx:275 #: src/containers/Scheduling/Availability/index.tsx:129 msgid "Time" msgstr "" @@ -1375,7 +1420,7 @@ msgstr "" msgid "Title" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:111 +#: src/containers/PatientDetails/PatientWearables/index.tsx:108 msgid "To obtain this information, you need to authorize your account in the mobile application and link it with your health data providers." msgstr "" @@ -1383,7 +1428,7 @@ msgstr "" msgid "Today" msgstr "" -#: src/containers/InvoiceDetails/index.tsx:117 +#: src/containers/InvoiceDetails/index.tsx:122 msgid "Total" msgstr "" @@ -1395,7 +1440,7 @@ msgstr "" msgid "Tuesday" msgstr "" -#: src/containers/HealthcareServiceList/index.tsx:61 +#: src/containers/HealthcareServiceList/index.tsx:55 msgid "Type" msgstr "" @@ -1408,7 +1453,7 @@ msgstr "" #: src/containers/InvoiceList/tableUtils.tsx:34 #: src/containers/PatientDetails/PatientDocumentDetails/ExternalDocumentView/index.tsx:53 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:125 -#: src/containers/Prescriptions/index.tsx:198 +#: src/containers/Prescriptions/index.tsx:194 #: src/containers/Scheduling/available-time.ts:22 msgid "Unknown" msgstr "" @@ -1447,13 +1492,13 @@ msgstr "" msgid "ValueSet url" msgstr "" -#: src/components/PatientEncounter/index.tsx:63 -#: src/containers/EncounterList/index.tsx:91 +#: src/components/PatientEncounter/index.tsx:62 +#: src/containers/EncounterList/index.tsx:90 +#: src/containers/VideoCall/index.tsx:28 msgid "Video call" msgstr "" -#: src/containers/PatientDetails/PatientHeader/index.tsx:81 -#: src/containers/PatientDetails/PatientWearables/index.tsx:64 +#: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:21 msgid "Wearables" msgstr "" @@ -1469,14 +1514,14 @@ msgstr "" msgid "Welcome to" msgstr "" -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:150 -#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:175 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:147 +#: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:172 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:136 #: src/utils/questionnaire.ts:63 msgid "Yes" msgstr "" -#: src/containers/PatientDetails/PatientWearables/index.tsx:110 +#: src/containers/PatientDetails/PatientWearables/index.tsx:107 msgid "You currently lack access to the patient's data. To obtain it, you must secure the patient's signed consent authorizing the release of their activity data." msgstr "" diff --git a/src/theme/antd-theme.ts b/src/theme/antd-theme.ts index 4502acfb..4778d951 100644 --- a/src/theme/antd-theme.ts +++ b/src/theme/antd-theme.ts @@ -24,8 +24,13 @@ export function getANTDTheme({ dark }: { dark?: boolean }): ThemeConfig { }, algorithm: dark ? ANTDTheme.darkAlgorithm : ANTDTheme.defaultAlgorithm, components: { + Typography: { + titleMarginBottom: 0, + titleMarginTop: 0, + }, Layout: { colorBgHeader: palette.neutral.sidebarBackground, + colorBgBody: palette.neutralPalette.gray_2, }, Result: { colorSuccess: palette.secondary, diff --git a/src/theme/utils.ts b/src/theme/utils.ts new file mode 100644 index 00000000..a4d775ca --- /dev/null +++ b/src/theme/utils.ts @@ -0,0 +1 @@ +export const mobileWidth = 768; diff --git a/src/uberComponents/ResourceListPage/BatchActions.tsx b/src/uberComponents/ResourceListPage/BatchActions.tsx new file mode 100644 index 00000000..f4dc4359 --- /dev/null +++ b/src/uberComponents/ResourceListPage/BatchActions.tsx @@ -0,0 +1,89 @@ +import { plural, Trans } from '@lingui/macro'; +import { Button, Checkbox } from 'antd'; +import { Bundle, ParametersParameter, Resource } from 'fhir/r4b'; + +import { Text } from 'src/components/Typography'; + +import { QuestionnaireActionType, BatchQuestionnaireAction } from './actions'; +import { S } from './styles'; +export { navigationAction, customAction, questionnaireAction } from './actions'; + +interface BatchActionsProps { + batchActions: QuestionnaireActionType[]; + selectedRowKeys: React.Key[]; + allKeys: React.Key[]; + setSelectedRowKeys: (keys: React.Key[]) => void; + reload: () => void; + selectedResourcesBundle: Bundle; + defaultLaunchContext?: ParametersParameter[]; +} + +export function BatchActions(props: BatchActionsProps) { + const { + batchActions, + selectedRowKeys, + setSelectedRowKeys, + reload, + selectedResourcesBundle, + defaultLaunchContext, + allKeys, + } = props; + + return ( + + + {batchActions.map((action, index) => ( + + key={index} + action={action} + reload={reload} + bundle={selectedResourcesBundle} + disabled={!selectedRowKeys.length} + defaultLaunchContext={defaultLaunchContext ?? []} + /> + ))} + {selectedRowKeys.length ? ( + + + + ) : null} + + + {selectedRowKeys.length ? ( + + {selectedRowKeys.length + ? plural(selectedRowKeys.length, { + one: 'Selected # item', + other: 'Selected # items', + }) + : null} + + ) : ( +
+ )} + + + + Select all + + 0 && selectedRowKeys.length === allKeys.length} + indeterminate={selectedRowKeys.length > 0 && selectedRowKeys.length !== allKeys.length} + onChange={(e) => { + const checked = e.target.checked; + + if (checked) { + setSelectedRowKeys(allKeys); + } else { + setSelectedRowKeys([]); + } + }} + > + + + + + ); +} diff --git a/src/uberComponents/ResourceListPage/actions.tsx b/src/uberComponents/ResourceListPage/actions.tsx new file mode 100644 index 00000000..88c5bd48 --- /dev/null +++ b/src/uberComponents/ResourceListPage/actions.tsx @@ -0,0 +1,208 @@ +import { t } from '@lingui/macro'; +import { Button, notification } from 'antd'; +import { Bundle, ParametersParameter, Resource } from 'fhir/r4b'; +import { useNavigate } from 'react-router-dom'; + +import { ModalTrigger } from 'src/components/ModalTrigger'; +import { QuestionnaireResponseForm, QRFProps } from 'src/components/QuestionnaireResponseForm'; +import { questionnaireIdLoader } from 'src/hooks/questionnaire-response-form-data'; +import { S } from './styles'; + +export interface NavigationActionType { + type: 'navigation'; + title: React.ReactNode; + link: string; + icon?: React.ReactNode; +} + +export interface CustomActionType { + type: 'custom'; + control: React.ReactNode; +} + +export interface QuestionnaireActionType { + type: 'questionnaire'; + title: React.ReactNode; + questionnaireId: string; + icon?: React.ReactNode; + qrfProps?: Partial; +} + +export function navigationAction( + title: React.ReactNode, + link: string, + options?: { icon?: React.ReactNode }, +): NavigationActionType { + return { type: 'navigation', title, link, icon: options?.icon }; +} +export function customAction(control: React.ReactNode): CustomActionType { + return { + type: 'custom', + control, + }; +} +export function questionnaireAction( + title: React.ReactNode, + questionnaireId: string, + options?: { icon?: React.ReactNode; qrfProps?: Partial }, +): QuestionnaireActionType { + return { + type: 'questionnaire', + title, + icon: options?.icon, + qrfProps: options?.qrfProps, + questionnaireId, + }; +} + +export type ActionType = QuestionnaireActionType | NavigationActionType | CustomActionType; +export function isQuestionnaireAction(action: ActionType): action is QuestionnaireActionType { + return action.type === 'questionnaire'; +} +export function isNavigationAction(action: ActionType): action is NavigationActionType { + return action.type === 'navigation'; +} +export function isCustomAction(action: ActionType): action is CustomActionType { + return action.type === 'custom'; +} + +export function RecordQuestionnaireAction({ + action, + resource, + reload, + defaultLaunchContext, +}: { + action: QuestionnaireActionType; + resource: R; + reload: () => void; + defaultLaunchContext: ParametersParameter[]; +}) { + return ( + {action.title}}> + {({ closeModal }) => ( + { + notification.success({ + message: t`Successfully submitted`, + }); + reload(); + closeModal(); + }} + onCancel={closeModal} + saveButtonTitle={t`Submit`} + {...(action.qrfProps ?? {})} + /> + )} + + ); +} + +interface HeaderQuestionnaireActionProps { + action: QuestionnaireActionType; + reload: () => void; + defaultLaunchContext: ParametersParameter[]; +} + +export function HeaderQuestionnaireAction({ action, reload, defaultLaunchContext }: HeaderQuestionnaireActionProps) { + return ( + + {action.title} + + } + > + {({ closeModal }) => ( + { + closeModal(); + notification.success({ message: t`Successfully submitted` }); + reload(); + }} + launchContextParameters={defaultLaunchContext} + onCancel={closeModal} + saveButtonTitle={t`Submit`} + {...(action.qrfProps ?? {})} + /> + )} + + ); +} + +export function BatchQuestionnaireAction({ + action, + bundle, + reload, + disabled, + defaultLaunchContext, +}: { + action: QuestionnaireActionType; + bundle: Bundle; + reload: () => void; + disabled?: boolean; + defaultLaunchContext: ParametersParameter[]; +}) { + return ( + + {action.title} + + } + > + {({ closeModal }) => ( + { + closeModal(); + notification.success({ message: t`Successfully submitted` }); + reload(); + }} + onCancel={closeModal} + saveButtonTitle={t`Submit`} + {...(action.qrfProps ?? {})} + /> + )} + + ); +} + +export function NavigationAction({ + action, + resource, +}: { + action: NavigationActionType; + resource: R; +}) { + const navigate = useNavigate(); + + return ( + + navigate(action.link, { + state: { resource }, + }) + } + icon={action.icon} + > + {action.title} + + ); +} diff --git a/src/uberComponents/ResourceListPage/hooks.ts b/src/uberComponents/ResourceListPage/hooks.ts new file mode 100644 index 00000000..29d75484 --- /dev/null +++ b/src/uberComponents/ResourceListPage/hooks.ts @@ -0,0 +1,99 @@ +import { TablePaginationConfig } from 'antd'; +import { Bundle, Resource } from 'fhir/r4b'; +import { useEffect, useMemo, useState } from 'react'; + +import { SearchParams } from '@beda.software/fhir-react'; +import { isSuccess, mapSuccess } from '@beda.software/remote-data'; + +import { ColumnFilterValue } from 'src/components/SearchBar/types'; +import { getSearchBarColumnFilterValue } from 'src/components/SearchBar/utils'; +import { usePagerExtended } from 'src/hooks/pager'; +import { useDebounce } from 'src/utils/debounce'; + +export function useResourceListPage( + resourceType: R['resourceType'], + extractPrimaryResources: ((bundle: Bundle) => R[]) | undefined, + filterValues: ColumnFilterValue[], + defaultSearchParams: SearchParams, +) { + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + + const debouncedFilterValues = useDebounce(filterValues, 300); + + const searchBarSearchParams = { + ...Object.fromEntries( + debouncedFilterValues.map((filterValue) => [ + filterValue.column.searchParam ?? filterValue.column.id, + getSearchBarColumnFilterValue(filterValue), + ]), + ), + }; + const searchParams = { _sort: '-_lastUpdated', ...defaultSearchParams, ...searchBarSearchParams }; + + const { + resourceResponse, + pagerManager, + handleTableChange: pagerHandleTableChange, + pagination, + } = usePagerExtended(resourceType, searchParams); + + const handleTableChange = async (pagination: TablePaginationConfig) => { + // Handle pagination only + if (typeof pagination.current !== 'number') { + return; + } + + pagerHandleTableChange(pagination); + setSelectedRowKeys([]); + }; + + useEffect(() => { + setSelectedRowKeys([]); + }, [JSON.stringify(searchParams)]); + + const reload = () => { + setSelectedRowKeys([]); + pagerManager.reload(); + }; + + const extractPrimaryResourcesMemoized = useMemo(() => { + return extractPrimaryResources ?? extractPrimaryResourcesFactory(resourceType); + }, [resourceType, extractPrimaryResources]); + + const recordResponse = mapSuccess(resourceResponse, (bundle) => + extractPrimaryResourcesMemoized(bundle as Bundle).map((resource) => ({ + resource: resource as R, + bundle: bundle as Bundle, + })), + ); + const selectedResourcesBundle: Bundle = { + resourceType: 'Bundle', + type: 'collection', + entry: isSuccess(recordResponse) + ? recordResponse.data + .filter( + ({ resource }) => + resource.resourceType === resourceType && selectedRowKeys.includes(resource.id!), + ) + .map(({ resource }) => ({ resource: resource as R })) + : [], + }; + + return { + pagination, + recordResponse, + handleTableChange, + selectedRowKeys, + setSelectedRowKeys, + selectedResourcesBundle, + reload, + }; +} + +function extractPrimaryResourcesFactory(resourceType: R['resourceType']) { + return (bundle: Bundle) => { + return (bundle.entry ?? []) + .filter((entry) => entry.resource?.resourceType === resourceType) + .map((entry) => entry.resource as R); + }; +} diff --git a/src/uberComponents/ResourceListPage/index.tsx b/src/uberComponents/ResourceListPage/index.tsx new file mode 100644 index 00000000..faabfd13 --- /dev/null +++ b/src/uberComponents/ResourceListPage/index.tsx @@ -0,0 +1,301 @@ +import { Trans } from '@lingui/macro'; +import { Empty } from 'antd'; +import { ColumnsType } from 'antd/lib/table'; +import { Bundle, ParametersParameter, Resource } from 'fhir/r4b'; +import React, { useMemo } from 'react'; + +import { formatError, SearchParams } from '@beda.software/fhir-react'; +import { isFailure, isLoading, isSuccess, RemoteData } from '@beda.software/remote-data'; + +import { PageContainer } from 'src/components/BaseLayout/PageContainer'; +import { SearchBar } from 'src/components/SearchBar'; +import { useSearchBar } from 'src/components/SearchBar/hooks'; +import { isTableFilter } from 'src/components/SearchBar/utils'; +import { SpinIndicator } from 'src/components/Spinner'; +import { Table } from 'src/components/Table'; +import { populateTableColumnsWithFiltersAndSorts } from 'src/components/Table/utils'; +import { Text } from 'src/components/Typography'; + +import { + NavigationActionType, + CustomActionType, + QuestionnaireActionType, + isNavigationAction, + isQuestionnaireAction, + NavigationAction, + RecordQuestionnaireAction, + HeaderQuestionnaireAction, + isCustomAction, +} from './actions'; +export { navigationAction, customAction, questionnaireAction } from './actions'; +import { useResourceListPage } from './hooks'; +import { SearchBarColumn } from '../../components/SearchBar/types'; +import { S } from './styles'; +import { Report } from 'src/components/Report'; +import { BatchActions } from './BatchActions'; + +type RecordType = { resource: R; bundle: Bundle }; + +interface TableManager { + reload: () => void; +} + +interface ReportColumn { + title: React.ReactNode; + value: React.ReactNode; +} + +interface ResourceListPageProps { + /* Page header title (for example, Organizations) */ + headerTitle: string; + + /* Page content max width */ + maxWidth?: number | string; + + /* Primary resource type (for example, Organization) */ + resourceType: R['resourceType']; + + /** + * Custom primary resources extractor, might be used when the same resource type included + * e.g. Organizations included via part-of + * + * Default - extract all resources matching `resourceType` + */ + extractPrimaryResources?: (bundle: Bundle) => R[]; + + /* Default search params */ + searchParams?: SearchParams; + + /* Filter that are displayed in the search bar and inside table columns */ + getFilters?: () => SearchBarColumn[]; + + /* Table columns without action column - action column is generated based on `getRecordActions` */ + getTableColumns: (manager: TableManager) => ColumnsType>; + + /** + * Record actions list that is displayed in the table per record + * (for example, edit organization) + */ + getRecordActions?: ( + record: RecordType, + manager: TableManager, + ) => Array; + + /** + * Header actions (for example, new organization) + * + * NOTE: Theoretically getHeaderActions can accept all resources Bundle + */ + getHeaderActions?: () => Array; + + /** + * Batch actions that are available when rows are selected + * (for example, delete multiple organizations) + * + * NOTE: Theoretically getHeaderActions can accept selected resources Bundle + */ + getBatchActions?: () => Array; + + /** + * Default launch context that will be added to all questionnaires + */ + defaultLaunchContext?: ParametersParameter[]; + + /** + * EXPERIMENTAL FEATURE. The interface might be changed + * TODO: https://github.com/beda-software/fhir-emr/issues/414 + */ + // loadReportBundle?: (searchParams: SearchParams) => Promise> + + /** + * EXPERIMENTAL FEATURE. The interface might be changed + * TODO: https://github.com/beda-software/fhir-emr/issues/414 + */ + getReportColumns?: (bundle: Bundle, reportBundle?: Bundle) => Array; +} + +export function ResourceListPage({ + headerTitle: title, + maxWidth, + resourceType, + extractPrimaryResources, + searchParams, + getRecordActions, + getHeaderActions, + getBatchActions, + getFilters, + getTableColumns, + defaultLaunchContext, + getReportColumns, +}: ResourceListPageProps) { + const allFilters = getFilters?.() ?? []; + + const { columnsFilterValues, onChangeColumnFilter, onResetFilters } = useSearchBar({ + columns: allFilters ?? [], + }); + const tableFilterValues = useMemo( + () => columnsFilterValues.filter((filter) => isTableFilter(filter)), + [JSON.stringify(columnsFilterValues)], + ); + + const { + recordResponse, + reload, + pagination, + handleTableChange, + selectedRowKeys, + setSelectedRowKeys, + selectedResourcesBundle, + } = useResourceListPage(resourceType, extractPrimaryResources, columnsFilterValues, searchParams ?? {}); + + // TODO: move to hooks + const initialTableColumns = getTableColumns({ reload }); + const tableColumns = populateTableColumnsWithFiltersAndSorts({ + tableColumns: initialTableColumns, + filters: tableFilterValues, + onChange: onChangeColumnFilter, + }); + const headerActions = getHeaderActions?.() ?? []; + const batchActions = getBatchActions?.() ?? []; + + return ( + ( + + + + ))} + header={{ + children: columnsFilterValues.length ? ( + + ) : null, + }} + > + {getReportColumns ? ( + + ) : null} + + {batchActions.length ? ( + d.resource.id!) : []} + setSelectedRowKeys={setSelectedRowKeys} + reload={reload} + selectedResourcesBundle={selectedResourcesBundle} + defaultLaunchContext={defaultLaunchContext} + /> + ) : null} + + > + pagination={pagination} + onChange={handleTableChange} + rowSelection={batchActions.length ? { selectedRowKeys, onChange: setSelectedRowKeys } : undefined} + locale={{ + emptyText: isFailure(recordResponse) ? ( + <> + + + ) : ( + <> + No data} image={Empty.PRESENTED_IMAGE_SIMPLE} /> + + ), + }} + rowKey={(p) => p.resource.id!} + dataSource={isSuccess(recordResponse) ? recordResponse.data : []} + columns={[ + ...tableColumns, + ...(getRecordActions + ? [ + getRecordActionsColumn({ + getRecordActions, + reload, + defaultLaunchContext: defaultLaunchContext ?? [], + }), + ] + : []), + ]} + loading={isLoading(recordResponse) && { indicator: SpinIndicator }} + /> + + ); +} + +interface ResourcesListPageReportProps { + recordResponse: RemoteData< + { + resource: R; + bundle: Bundle; + }[], + any + >; + getReportColumns: (bundle: Bundle, reportBundle?: Bundle) => Array; +} + +function ResourcesListPageReport(props: ResourcesListPageReportProps) { + const { recordResponse, getReportColumns } = props; + const emptyBundle: Bundle = { resourceType: 'Bundle', entry: [], type: 'searchset' }; + const items = + isSuccess(recordResponse) && recordResponse.data?.[0]?.bundle + ? getReportColumns(recordResponse.data[0].bundle) + : getReportColumns(emptyBundle); + + return ; +} + +function getRecordActionsColumn({ + getRecordActions, + defaultLaunchContext, + reload, +}: { + getRecordActions: ( + record: RecordType, + manager: TableManager, + ) => Array; + defaultLaunchContext?: ParametersParameter[]; + reload: () => void; +}) { + return { + title: Actions, + dataIndex: 'actions', + key: 'actions', + render: (_text: any, record: { resource: R; bundle: Bundle }) => { + return ( + + {getRecordActions(record, { reload }).map((action, index) => ( + + {isQuestionnaireAction(action) ? ( + + ) : isNavigationAction(action) ? ( + + ) : isCustomAction(action) ? ( + action.control + ) : ( + Unsupported action + )} + + ))} + + ); + }, + }; +} diff --git a/src/uberComponents/ResourceListPage/styles.ts b/src/uberComponents/ResourceListPage/styles.ts new file mode 100644 index 00000000..95d76394 --- /dev/null +++ b/src/uberComponents/ResourceListPage/styles.ts @@ -0,0 +1,77 @@ +import styled from 'styled-components'; + +import { Button } from 'antd'; +import { mobileWidth } from 'src/theme/utils'; + +export const S = { + Actions: styled.div` + display: flex; + gap: 8px 16px; + + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + gap: 2px 16px; + flex-wrap: wrap; + } + `, + LinkButton: styled(Button)` + padding: 0; + `, + BatchActionsContainer: styled.div` + display: flex; + flex-direction: row; + gap: 10px 16px; + align-items: center; + flex-wrap: wrap; + + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + flex-direction: column; + align-items: stretch; + } + `, + BatchActions: styled.div` + display: flex; + gap: 10px 8px; + flex-wrap: wrap; + + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + gap: 10px 16px; + + & > * { + width: calc(50% - 8px); + } + } + `, + ResetSelection: styled.div` + margin-left: 8px; + + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + margin-left: 0; + + & > * { + width: 100%; + } + } + `, + SelectAll: styled.div` + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + height: 32px; + padding: 0 16px; + } + `, + CheckboxAll: styled.div` + display: none; + + @media screen and (max-width: ${() => `${mobileWidth - 1}px`}) { + display: block; + } + `, + Label: styled.div` + display: flex; + gap: 0 8px; + align-items: center; + `, +}; diff --git a/src/uberComponents/index.ts b/src/uberComponents/index.ts new file mode 100644 index 00000000..d8102b5b --- /dev/null +++ b/src/uberComponents/index.ts @@ -0,0 +1 @@ +export * from './ResourceListPage'; diff --git a/src/utils/reference.ts b/src/utils/reference.ts index a5eaac83..a4ee9d6b 100644 --- a/src/utils/reference.ts +++ b/src/utils/reference.ts @@ -1,4 +1,4 @@ -import { Reference } from 'fhir/r4b'; +import { Bundle, Reference, Resource } from 'fhir/r4b'; export function getFHIRReferenceData(reference?: Reference) { const splittedReference = reference?.reference?.split('/'); @@ -15,3 +15,8 @@ export function getFHIRReferenceResourceType(reference?: Reference) { export function getFHIRReferenceResourceId(reference?: Reference) { return getFHIRReferenceData(reference).id; } + +export function resolveReference(bundle: Bundle, reference: Reference): R | undefined { + return bundle.entry?.find((entry) => reference.reference && entry.fullUrl?.endsWith(reference.reference)) + ?.resource as R | undefined; +} diff --git a/src/utils/role.ts b/src/utils/role.ts index aefa84ea..13552084 100644 --- a/src/utils/role.ts +++ b/src/utils/role.ts @@ -15,6 +15,8 @@ export enum Role { Admin = 'admin', Practitioner = 'practitioner', Receptionist = 'receptionist', + Census = 'census', + Scriber = 'scriber' } export function selectUserRole(user: User, options: { [role in Role]: T }): T { @@ -28,12 +30,16 @@ export function matchCurrentUserRole(options: { [Role.Admin]: (organization: WithId) => T; [Role.Practitioner]: (practitioner: WithId) => T; [Role.Receptionist]: (practitioner: WithId) => T; + [Role.Census]: (practitioner: WithId) => T; + [Role.Scriber]: (practitioner: WithId) => T; }): T { return selectUserRole(sharedAuthorizedUser.getSharedState()!, { [Role.Patient]: () => options[Role.Patient](sharedAuthorizedPatient.getSharedState()!), [Role.Admin]: () => options[Role.Admin](sharedAuthorizedOrganization.getSharedState()!), [Role.Practitioner]: () => options[Role.Practitioner](sharedAuthorizedPractitioner.getSharedState()!), [Role.Receptionist]: () => options[Role.Receptionist](sharedAuthorizedPractitioner.getSharedState()!), + [Role.Census]: () => options[Role.Census](sharedAuthorizedPractitioner.getSharedState()!), + [Role.Scriber]: () => options[Role.Scriber](sharedAuthorizedPractitioner.getSharedState()!), })(); } @@ -43,5 +49,7 @@ export function selectCurrentUserRoleResource(): WithId | WithId organization, [Role.Practitioner]: (practitioner) => practitioner, [Role.Receptionist]: (practitioner) => practitioner, + [Role.Census]: (practitioner) => practitioner, + [Role.Scriber]: (practitioner) => practitioner, }); } diff --git a/vite.lib.config.ts b/vite.lib.config.ts index 711a1ec1..47388f78 100644 --- a/vite.lib.config.ts +++ b/vite.lib.config.ts @@ -37,6 +37,7 @@ export default defineConfig({ entry: [ path.resolve(__dirname, 'src/index.ts'), path.resolve(__dirname, 'src/components/index.ts'), + path.resolve(__dirname, 'src/uberComponents/index.ts'), path.resolve(__dirname, 'src/containers/index.ts'), path.resolve(__dirname, 'src/hooks/index.ts'), path.resolve(__dirname, 'src/utils/index.ts'),