Skip to content

Commit

Permalink
Check editorUserIds when rendering occurrence point form
Browse files Browse the repository at this point in the history
  • Loading branch information
gigxz committed Dec 24, 2024
1 parent dab8e61 commit 1508583
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 44 deletions.
13 changes: 8 additions & 5 deletions src/modules/client/components/ClientCustomDataElementsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
CommonDetailGridItem,
} from '@/components/elements/CommonDetailGrid';
import TitleCard from '@/components/elements/TitleCard';
import useAuth from '@/modules/auth/hooks/useAuth';
import OccurrencePointForm from '@/modules/form/components/OccurrencePointForm';
import { useClientDetailForms } from '@/modules/form/hooks/useClientDetailForms';
import { parseOccurrencePointFormDefinition } from '@/modules/form/util/formUtil';
Expand All @@ -15,12 +16,14 @@ interface Props {

const ClientCustomDataElementsCard: React.FC<Props> = ({ client }) => {
const { forms, loading } = useClientDetailForms();

const { user } = useAuth();
const rows = useMemo(
() =>
forms.map((form) => {
const { displayTitle, isEditable, readOnlyDefinition } =
parseOccurrencePointFormDefinition(form.definition);
// Determine whether this form has any fields that are editable.
// Pass the user because there might be fields that are only editable by some users.
const { displayTitle, isEditable, definitionForDisplay } =
parseOccurrencePointFormDefinition(form.definition, user);

return {
id: form.id,
Expand All @@ -29,14 +32,14 @@ const ClientCustomDataElementsCard: React.FC<Props> = ({ client }) => {
<OccurrencePointForm
record={client}
definition={form.definition}
readOnlyDefinition={readOnlyDefinition}
definitionForDisplay={definitionForDisplay}
editable={isEditable && client.access.canEditClient}
dialogTitle={displayTitle}
/>
),
};
}),
[client, forms]
[client, forms, user]
);

if (loading) return null;
Expand Down
12 changes: 8 additions & 4 deletions src/modules/enrollment/components/EnrollmentDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Loading from '@/components/elements/Loading';
import NotCollectedText from '@/components/elements/NotCollectedText';

import RouterLink from '@/components/elements/RouterLink';
import useAuth from '@/modules/auth/hooks/useAuth';
import { parseOccurrencePointFormDefinition } from '@/modules/form/util/formUtil';
import EnrollmentStatus from '@/modules/hmis/components/EnrollmentStatus';
import HmisEnum from '@/modules/hmis/components/HmisEnum';
Expand All @@ -27,6 +28,7 @@ const EnrollmentDetails = ({
}: {
enrollment: DashboardEnrollment;
}) => {
const { user } = useAuth();
const rows = useMemo(() => {
const content: Record<string, ReactNode> = {};
// If enrollment is incomplete, show that first
Expand Down Expand Up @@ -64,14 +66,16 @@ const EnrollmentDetails = ({

// Occurrence point values (move in date, date of engagement, etc.)
enrollment.occurrencePointForms.forEach(({ definition }) => {
const { displayTitle, isEditable, readOnlyDefinition } =
parseOccurrencePointFormDefinition(definition);
// Determine whether this form has any fields that are editable.
// Pass the user because there might be fields that are only editable by some users.
const { displayTitle, isEditable, definitionForDisplay } =
parseOccurrencePointFormDefinition(definition, user);

content[displayTitle] = (
<EnrollmentOccurrencePointForm
enrollment={enrollment}
definition={definition}
readOnlyDefinition={readOnlyDefinition}
definitionForDisplay={definitionForDisplay}
editable={isEditable && enrollment.access.canEditEnrollments}
dialogTitle={displayTitle}
/>
Expand Down Expand Up @@ -136,7 +140,7 @@ const EnrollmentDetails = ({
),
value,
}));
}, [enrollment]);
}, [enrollment, user]);

if (!enrollment || !rows) return <Loading />;

Expand Down
56 changes: 29 additions & 27 deletions src/modules/form/components/DynamicFormFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import DynamicField from './DynamicField';
import DynamicGroup from './DynamicGroup';

import SentryErrorBoundary from '@/modules/errors/components/SentryErrorBoundary';
import DynamicViewField from '@/modules/form/components/viewable/DynamicViewField';
import {
DisabledDisplay,
Expand Down Expand Up @@ -145,33 +146,34 @@ const DynamicFormFields: React.FC<Props> = ({
/>
</Grid>
) : (
<DynamicField
key={item.linkId}
item={item}
itemChanged={itemChanged}
value={
isDisabled &&
item.disabledDisplay !== DisabledDisplay.ProtectedWithValue
? undefined
: values[item.linkId]
}
errors={getFieldErrors(item)}
horizontal={horizontal}
pickListArgs={pickListArgs}
warnIfEmpty={warnIfEmpty}
// Needed to support referencing local constants in expression evaluation (DynamicDisplay)
localConstants={localConstants}
{...props}
inputProps={{
...props?.inputProps,
...buildCommonInputProps({
item,
values,
localConstants: localConstants || {},
}),
disabled: isDisabled || locked || undefined,
}}
/>
<SentryErrorBoundary key={item.linkId}>
<DynamicField
key={item.linkId}
item={item}
itemChanged={itemChanged}
value={
isDisabled &&
item.disabledDisplay !== DisabledDisplay.ProtectedWithValue
? undefined
: values[item.linkId]
}
errors={getFieldErrors(item)}
horizontal={horizontal}
pickListArgs={pickListArgs}
warnIfEmpty={warnIfEmpty}
localConstants={localConstants}
{...props}
inputProps={{
...props?.inputProps,
...buildCommonInputProps({
item,
values,
localConstants: localConstants || {},
}),
disabled: isDisabled || locked || undefined,
}}
/>
</SentryErrorBoundary>
);
if (renderFn) {
return renderFn(itemComponent);
Expand Down
11 changes: 7 additions & 4 deletions src/modules/form/components/OccurrencePointForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ import {

export interface OccurrencePointFormProps {
record: SubmitFormAllowedTypes;
definition: FormDefinitionFieldsFragment;
submitFormInputVariables?: SubmitFormInputVariables;
readOnlyDefinition: FormDefinitionJson;
/** Definition to use for displaying the occurrence point as a DynamicView */
definitionForDisplay: FormDefinitionJson;
/** Definition to use for editing the Occurrence Point form values (if allowed) */
definition: FormDefinitionFieldsFragment;
/** Whether the Occurence Point form is editable. Some Occurrence Point forms are always read-only (like 'number of units assigned'), and some are only editable by certain users (via editor_user_ids). */
editable?: boolean;
dialogTitle?: string;
localConstants?: LocalConstants;
Expand All @@ -52,7 +55,7 @@ const OccurrencePointForm: React.FC<OccurrencePointFormProps> = ({
localConstants: localConstantsProp,
definition,
editable,
readOnlyDefinition,
definitionForDisplay,
dialogTitle,
pickListArgs,
submitFormInputVariables,
Expand Down Expand Up @@ -114,7 +117,7 @@ const OccurrencePointForm: React.FC<OccurrencePointFormProps> = ({
<DynamicView
key={JSON.stringify(values)}
values={values}
definition={readOnlyDefinition}
definition={definitionForDisplay}
pickListArgs={pickListArgs}
/>
) : (
Expand Down
24 changes: 20 additions & 4 deletions src/modules/form/util/formUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
TypedObject,
} from '../types';

import { HmisUser } from '@/modules/auth/api/sessions';
import { evaluateFormula } from '@/modules/form/util/expressions/formula';
import { collectExpressionReferences } from '@/modules/form/util/expressions/references';
import {
Expand Down Expand Up @@ -1492,7 +1493,8 @@ export const getFieldOnAssessment = (
};

export const parseOccurrencePointFormDefinition = (
definition: FormDefinitionFieldsFragment
definition: FormDefinitionFieldsFragment,
user?: HmisUser
) => {
let displayTitle = definition.title;
let isEditable = false;
Expand All @@ -1503,21 +1505,35 @@ export const parseOccurrencePointFormDefinition = (
);
}

const readOnlyDefinition = modifyFormDefinition(
// Modify form definition into a "read only definition" by removing
const definitionForDisplay = modifyFormDefinition(
definition.definition,
(item) => {
// Delete the 'text' from the item IF the text matches the title of the form.
// This is a hacky way to hide redundant labels for tiny Occurrence Point forms like Move-in Date.
if (definition.title && matchesTitle(item, definition.title)) {
displayTitle = item.readonlyText || item.text || displayTitle;
delete item.text;
delete item.readonlyText;
}
if (isQuestionItem(item) && !item.readOnly) {
isEditable = true;
if (item.editorUserIds && user) {
isEditable = item.editorUserIds.includes(user.id);
} else {
isEditable = true;
}
}
}
);

return { displayTitle, isEditable, readOnlyDefinition };
return {
// Title to display in the left-hand column of the Enrollment/Client details card
displayTitle,
// Modified Form Definiton to use to display the form values as a DynamicView in the right-hand column of the Enrollment/Client details card
definitionForDisplay,
// Whether the form is editable by the current user
isEditable,
};
};

export const getFormStepperItems = (
Expand Down

0 comments on commit 1508583

Please sign in to comment.