Skip to content

Commit

Permalink
Merge pull request #761 from BIDMCDigitalPsychiatry/issue-759
Browse files Browse the repository at this point in the history
#761 - Survey duplicate and rjsf package changes
  • Loading branch information
sarithapillai8 authored Jun 8, 2023
2 parents 32ff80d + e7a5a38 commit 2e4bbac
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 119 deletions.
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@
"@material-ui/lab": "^4.0.0-alpha.61",
"@material-ui/pickers": "^3.3.10",
"@mui/material": "^5.0.0",
"@rjsf/core": "^3.2.1",
"@rjsf/material-ui": "^3.2.1",
"@rjsf/utils": "^5.0.0-beta.13",
"@rjsf/core": "^5.8.0",
"@rjsf/material-ui": "^5.8.1",
"@rjsf/utils": "^5.8.1",
"@rjsf/validator-ajv8": "^5.8.1",
"ajv": "^8.12.0",
"ajv-keywords": "^5.1.0",
"classnames": "^2.3.1",
"core-js": "^3.19.1",
"date-fns": "^2.26.0",
Expand Down
15 changes: 13 additions & 2 deletions src/components/Researcher/ActivityList/ActivityMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,15 @@ export const SchemaList = () => {
title: i18n.t("Survey Questions"),
description: i18n.t("Configure questions, parameters, and options."),
type: "array",
"ui:schema": {
copyable: true,
},
"ui:options": {
addable: true,
removable: true,
orderable: true,
copyable: true,
},
items: {
required: ["text", "type"],

Expand Down Expand Up @@ -1025,7 +1034,8 @@ export const SchemaList = () => {
title: i18n.t("Measure of Action"),
type: "string",
minLength: 1,
examples: [i18n.t("Times"), i18n.t("Hours"), i18n.t("Minutes"), i18n.t("Amount")],
enum: [i18n.t("Times"), i18n.t("Hours"), i18n.t("Minutes"), i18n.t("Amount")],
enumNames: [i18n.t("Times"), i18n.t("Hours"), i18n.t("Minutes"), i18n.t("Amount")],
},
},
},
Expand All @@ -1049,7 +1059,8 @@ export const SchemaList = () => {
title: i18n.t("Measure of action"),
type: "string",
minLength: 1,
examples: [i18n.t("Times"), i18n.t("Hours"), i18n.t("Minutes"), i18n.t("Amount")],
enum: [i18n.t("Times"), i18n.t("Hours"), i18n.t("Minutes"), i18n.t("Amount")],
enumNames: [i18n.t("Times"), i18n.t("Hours"), i18n.t("Minutes"), i18n.t("Amount")],
},
},
},
Expand Down
64 changes: 2 additions & 62 deletions src/components/shared/CustomFileWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from "react"
import { makeStyles, IconButton, Box, Icon, MuiThemeProvider, createTheme, Button } from "@material-ui/core"
import { Widgets } from "@rjsf/material-ui"
import { makeStyles, IconButton, Box, Icon, Button } from "@material-ui/core"
import { useTranslation } from "react-i18next"

const useStyles = makeStyles((theme) => ({
Expand Down Expand Up @@ -47,74 +46,15 @@ function processFile(files) {
reader.readAsDataURL(f)
})
}

import locale_lang from "../../locale_map.json"
import { zhCN, enUS, koKR, hiIN, deDE, daDK, frFR, itIT, esES, zhHK } from "@mui/material/locale"
const userLanguages = ["en-US", "es-ES", "hi-IN", "de-DE", "da-DK", "fr-FR", "ko-KR", "it-IT", "zh-CN", "zh-HK"]
const languageObjects = {
"en-US": enUS,
"es-ES": esES,
"hi-IN": hiIN,
"de-DE": deDE,
"da-DK": daDK,
"fr-FR": frFR,
"ko-KR": koKR,
"it-IT": itIT,
"zh-CN": zhCN,
"zh-HK": zhHK,
}

export default function CustomFileWidget(props) {
const classes = useStyles()
const ref = React.useRef(props.value)
const { t, i18n } = useTranslation()

const getSelectedLanguage = () => {
const matched_codes = Object.keys(locale_lang).filter((code) => code.startsWith(navigator.language))
const lang = matched_codes.length > 0 ? matched_codes[0] : "en-US"
return i18n.language ? i18n.language : userLanguages.includes(lang) ? lang : "en-US"
}
const { t } = useTranslation()

const onClick = () => {
ref.current.value = ""
props.onChange("")
}
const formTheme = createTheme(
{
props: {
MuiTextField: {
variant: "filled",
},
MuiPaper: {
variant: "outlined",
},
},

overrides: {
MuiFilledInput: {
root: {
border: 0,
backgroundColor: "#f4f4f4",
"& textarea": {
resize: "vertical",
},
},
underline: {
"&&&:before": {
borderBottom: "none",
},
"&&:after": {
borderBottom: "none",
},
},
},
MuiTypography: {
h5: { fontSize: 16, fontWeight: 600, marginBottom: 10 },
},
},
},
languageObjects[getSelectedLanguage()]
)

return (
<Box>
Expand Down
131 changes: 79 additions & 52 deletions src/components/shared/DynamicForm.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import React from "react"
import { Grid, Button, Icon, MuiThemeProvider, Box, Paper, makeStyles, createStyles, Theme } from "@material-ui/core"
import { Autocomplete } from "@material-ui/lab"
import Form, { Widgets } from "@rjsf/material-ui"
import { ObjectFieldTemplateProps, utils } from "@rjsf/core"
import Form from "@rjsf/material-ui"
import {
ObjectFieldTemplateProps,
TitleFieldProps,
DescriptionFieldProps,
ArrayFieldTemplateProps,
RegistryWidgetsType,
} from "@rjsf/utils"
import { useTranslation } from "react-i18next"
import CustomFileWidget from "./CustomFileWidget"
import { createTheme } from "@material-ui/core/styles"
import locale_lang from "../../locale_map.json"
import validator from "@rjsf/validator-ajv8"

import { zhCN, enUS, koKR, hiIN, deDE, daDK, frFR, itIT, esES, zhHK } from "@mui/material/locale"
const userLanguages = ["en-US", "es-ES", "hi-IN", "de-DE", "da-DK", "fr-FR", "ko-KR", "it-IT", "zh-CN", "zh-HK"]
const languageObjects = {
Expand All @@ -26,28 +33,56 @@ const languageObjects = {
// Supported container props: alignContent, alignItems, direction, justify, spacing, wrap
// Supported item props: lg, md, sm, xs, xl
// TODO: Does not support adding dividers or padding before/after the children items yet.

function TitleFieldTemplate(props: TitleFieldProps) {
const { id, required, title } = props
return (
<header id={id}>
{title}
{required && <mark>*</mark>}
</header>
)
}

function DescriptionFieldTemplate(props: DescriptionFieldProps) {
const { description, id } = props
return <small id={id}>{description}</small>
}

function AutoCompleteTemplate(props: DescriptionFieldProps) {
const { description, id } = props
return <small id={id}>{description}</small>
}

//TextWidget: AutocompleteTextWidget,
const widgets: RegistryWidgetsType = {
FileWidget: CustomFileWidget,
}

const ObjectFieldTemplate = ({
DescriptionField,
description,
TitleField,
title,
properties,
required,
disabled,
readonly,
uiSchema,
idSchema,
schema,
formData,
onAddClick,
registry,
}: ObjectFieldTemplateProps) => {
const { t } = useTranslation()
return (
<>
{!!properties && (properties || []).length > 0 && (uiSchema["ui:title"] || title) && (
<TitleField id={`${idSchema.$id}-title`} title={t(title)} required={required} />
{/* {!!properties && (properties || []).length > 0 && (uiSchema["ui:title"] || title) && (
<TitleFieldTemplate id={`${idSchema.$id}-title`} title={t(title)} required={required} registry={registry} schema={schema} />
)} */}
{description && (
<DescriptionFieldTemplate
id={`${idSchema.$id}-description`}
description={t(description)}
registry={registry}
schema={schema}
/>
)}
{description && <DescriptionField id={`${idSchema.$id}-description`} description={t(description)} />}
<Grid container={true} spacing={2} style={{ marginTop: 10 }} {...(uiSchema?.["ui:grid"] ?? {})}>
{properties.map((element: any, index: number) => (
<Grid
Expand All @@ -60,20 +95,6 @@ const ObjectFieldTemplate = ({
{element.content}
</Grid>
))}
{utils.canExpand(schema, uiSchema, formData) && (
<Grid container justifyContent="flex-end">
<Grid item={true}>
<Button
className="object-property-expand"
color="secondary"
onClick={onAddClick(schema)}
disabled={disabled || readonly}
>
<Icon>add</Icon> {t("ADD ITEM")}
</Button>
</Grid>
</Grid>
)}
</Grid>
</>
)
Expand All @@ -98,15 +119,30 @@ const useStyles = makeStyles((theme: Theme) =>
},
})
)
function ArrayFieldTemplate(props) {

function ArrayFieldTemplate(props: ArrayFieldTemplateProps) {
const { t } = useTranslation()
const classes = useStyles()

return (
<Grid container={true} alignItems="center" className={classes.toolbardashboard}>
<Box width={1}>
{props.schema.title && <props.TitleField title={t(props.schema.title)} required={props.required} />}
{props.schema.description && <props.DescriptionField description={t(props.schema.description)} />}
{props.schema.title && (
<TitleFieldTemplate
id={props.idSchema.$id}
title={t(props.schema.title)}
required={props.required}
schema={props.schema}
registry={props.registry}
/>
)}
{props.schema.description && (
<DescriptionFieldTemplate
description={t(props.schema.description)}
id={props.idSchema.$id}
schema={props.schema}
registry={props.registry}
/>
)}
</Box>
{props.items.map((element, index) => (
<Grid container={true} alignItems="center">
Expand All @@ -117,7 +153,6 @@ function ArrayFieldTemplate(props) {
</Paper>
</Box>
</Grid>

{element.hasToolbar && (
<Grid item={true}>
{(element.hasMoveUp || element.hasMoveDown) && (
Expand All @@ -138,6 +173,15 @@ function ArrayFieldTemplate(props) {
<Icon>arrow_downward</Icon>
</button>
)}
{element.hasCopy && (
<button
onClick={element.onCopyIndexClick(index)}
disabled={element.disabled || element.readonly}
className={classes.btnarrange}
>
<Icon>content_copy</Icon>
</button>
)}
{element.hasRemove && (
<button
onClick={element.onDropIndexClick(index)}
Expand Down Expand Up @@ -178,23 +222,6 @@ function _extract(schema) {
}
}

// Add support for the "examples" array for the property as an auto-complete menu.
function AutocompleteTextWidget(props) {
if (!Array.isArray(props.schema.examples)) {
return <Widgets.TextWidget {...props} />
}

return (
<Autocomplete
onChange={(_, data) => props.onChange(data)}
freeSolo
options={props.schema.examples ?? []}
renderInput={(params) => <Widgets.TextWidget {...params} {...props} />}
{...(props.uiSchema ?? {})}
value={props.value}
/>
)
}
// A wrapper Form component to add support for things not available out of the box in RJSF.
// NOTE: Do not keep resetting the value of `initialData`! Only set this once.
export default function DynamicForm({ schema, initialData, onChange, ...props }) {
Expand Down Expand Up @@ -246,17 +273,17 @@ export default function DynamicForm({ schema, initialData, onChange, ...props })
return (
<MuiThemeProvider theme={formTheme}>
<Form
// liveValidate
liveValidate
children={true}
schema={schema}
uiSchema={_extract(schema)}
formData={initialData}
onChange={(x) => {
onChange(x.formData)
}}
ArrayFieldTemplate={ArrayFieldTemplate}
ObjectFieldTemplate={ObjectFieldTemplate}
widgets={{ TextWidget: AutocompleteTextWidget, FileWidget: CustomFileWidget }}
validator={validator}
templates={{ ArrayFieldTemplate, ObjectFieldTemplate, TitleFieldTemplate }}
widgets={widgets}
/>
</MuiThemeProvider>
)
Expand Down

0 comments on commit 2e4bbac

Please sign in to comment.