fix(forms) Update styles of submit/confirm button and fix num input bug (#9797)

This commit is contained in:
Chris Collins 2024-02-08 11:42:02 -05:00 committed by GitHub
parent f6e96dc0d3
commit 33dc96bc24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 163 additions and 122 deletions

View File

@ -140,8 +140,6 @@ export function getCompletedPrompts(entityData: GenericEntityProperties | null)
completedPrompts = completedPrompts.concat(
forms?.completedForms?.flatMap((form) => (form.completedPrompts ? form.completedPrompts : [])) || [],
);
console.log('entityData', entityData);
console.log('getCompletedPrompts', completedPrompts);
return completedPrompts;
}

View File

@ -40,7 +40,9 @@ export default function MultiSelectInput({
allowedValues,
selectedValues,
}: Props) {
return allowedValues.length > 5 ? (
const shouldShowSelectDropdown = allowedValues.length > 5;
return shouldShowSelectDropdown ? (
<Select
style={DROPDOWN_STYLE as any}
placeholder="Select"
@ -65,7 +67,7 @@ export default function MultiSelectInput({
onChange={(value) => updateSelectedValues(value)}
/>
) : (
<>
<div>
{allowedValues.map((allowedValue) => (
<StyledCheckbox
key={getStructuredPropertyValue(allowedValue.value)}
@ -77,6 +79,6 @@ export default function MultiSelectInput({
{allowedValue.description && <ValueDescription description={allowedValue.description} />}
</StyledCheckbox>
))}
</>
</div>
);
}

View File

@ -53,7 +53,7 @@ export default function MultipleStringInput({ selectedValues, updateSelectedValu
}
return (
<>
<div>
{selectedValues.length > 1 &&
selectedValues.map((selectedValue, index) => {
const key = `${index}`;
@ -78,6 +78,6 @@ export default function MultipleStringInput({ selectedValues, updateSelectedValu
<StyledButton type="link" onClick={addNewValue}>
+ Add More
</StyledButton>
</>
</div>
);
}

View File

@ -19,5 +19,11 @@ export default function NumberInput({ selectedValues, updateSelectedValues }: Pr
updateSelectedValues([number]);
}
return <StyledInput type="number" value={selectedValues[0] || null} onChange={updateInput} />;
return (
<StyledInput
type="number"
value={selectedValues[0] !== undefined ? selectedValues[0] : null}
onChange={updateInput}
/>
);
}

View File

@ -2,7 +2,6 @@ import { Button } from 'antd';
import React from 'react';
import styled from 'styled-components';
import {
EntityType,
FormPrompt,
PropertyCardinality,
SchemaField,
@ -17,20 +16,9 @@ import RichTextInput from './RichTextInput';
import DateInput from './DateInput';
import NumberInput from './NumberInput';
import UrnInput from './UrnInput/UrnInput';
import { useEntityData } from '../../../EntityContext';
import {
findCompletedFieldPrompt,
findPromptAssociation,
getCompletedPrompts,
getIncompletePrompts,
isFieldPromptComplete,
isPromptComplete,
} from '../../../containers/profile/sidebar/FormInfo/utils';
import { useEntityRegistry } from '../../../../../useEntityRegistry';
import { getTimeFromNow } from '../../../../../shared/time/timeUtils';
import CompletedPromptAuditStamp from './CompletedPromptAuditStamp';
import { applyOpacity } from '../../../../../shared/styleUtils';
import { useUserContext } from '../../../../../context/useUserContext';
import usePromptCompletionInfo from '../usePromptCompletionInfo';
const PromptWrapper = styled.div<{ displayBulkStyles?: boolean }>`
display: flex;
@ -67,11 +55,11 @@ export const PromptSubTitle = styled.div`
const InputSection = styled.div`
margin-top: 8px;
display: flex;
`;
const StyledButton = styled(Button)`
align-self: end;
margin-left: 8px;
margin-top: 16px;
&:focus {
box-shadow: 0 0 3px 2px ${(props) => applyOpacity(props.theme.styles['primary-color'] || '', 50)};
@ -80,6 +68,7 @@ const StyledButton = styled(Button)`
const PromptInputWrapper = styled.div`
flex: 1;
margin-right: 8px;
`;
interface Props {
@ -98,110 +87,93 @@ export default function StructuredPropertyPrompt({
optimisticCompletedTimestamp,
}: Props) {
const {
isSaveVisible,
hasEditedPrompt,
selectedValues,
selectSingleValue,
toggleSelectedValue,
submitStructuredPropertyResponse,
updateSelectedValues,
} = useStructuredPropertyPrompt({ prompt, submitResponse, field });
const { entityData } = useEntityData();
const { user } = useUserContext();
const entityRegistry = useEntityRegistry();
const completedPrompts = getCompletedPrompts(entityData);
const incompletePrompts = getIncompletePrompts(entityData);
const promptAssociation = findPromptAssociation(prompt, completedPrompts.concat(incompletePrompts));
const completedFieldPrompt = findCompletedFieldPrompt(field, promptAssociation);
const { isComplete, completedByName, completedByTime } = usePromptCompletionInfo({
prompt,
field,
optimisticCompletedTimestamp,
});
const structuredProperty = prompt.structuredPropertyParams?.structuredProperty;
if (!structuredProperty) return null;
const { displayName, description, allowedValues, cardinality, valueType } = structuredProperty.definition;
function getCompletedByName() {
let actor = completedFieldPrompt?.lastModified?.actor || promptAssociation?.lastModified?.actor;
if (optimisticCompletedTimestamp) {
actor = user;
}
return actor ? entityRegistry.getDisplayName(EntityType.CorpUser, actor) : '';
}
function getCompletedByRelativeTime() {
let completedTimestamp = completedFieldPrompt?.lastModified?.time || promptAssociation?.lastModified?.time;
if (optimisticCompletedTimestamp) {
completedTimestamp = optimisticCompletedTimestamp;
}
return completedTimestamp ? getTimeFromNow(completedTimestamp) : '';
}
const showSaveButton = hasEditedPrompt && selectedValues.length > 0;
const showConfirmButton = !hasEditedPrompt && !isComplete && selectedValues.length > 0;
return (
<PromptWrapper>
<PromptInputWrapper>
<PromptTitle>
{promptNumber !== undefined && <>{promptNumber}. </>}
{displayName}
{prompt.required && <RequiredText>required</RequiredText>}
</PromptTitle>
{description && <PromptSubTitle>{description}</PromptSubTitle>}
<InputSection>
{allowedValues && allowedValues.length > 0 && (
<>
{cardinality === PropertyCardinality.Single && (
<SingleSelectInput
allowedValues={allowedValues}
selectedValues={selectedValues}
selectSingleValue={selectSingleValue}
/>
)}
{cardinality === PropertyCardinality.Multiple && (
<MultiSelectInput
allowedValues={allowedValues}
selectedValues={selectedValues}
toggleSelectedValue={toggleSelectedValue}
updateSelectedValues={updateSelectedValues}
/>
)}
</>
)}
{!allowedValues && valueType.info.type === StdDataType.String && (
<StringInput
selectedValues={selectedValues}
cardinality={cardinality}
updateSelectedValues={updateSelectedValues}
/>
)}
{!allowedValues && valueType.info.type === StdDataType.RichText && (
<RichTextInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
)}
{!allowedValues && valueType.info.type === StdDataType.Date && (
<DateInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
)}
{!allowedValues && valueType.info.type === StdDataType.Number && (
<NumberInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
)}
{!allowedValues && valueType.info.type === StdDataType.Urn && (
<UrnInput
structuredProperty={structuredProperty}
selectedValues={selectedValues}
updateSelectedValues={updateSelectedValues}
/>
)}
</InputSection>
</PromptInputWrapper>
{isSaveVisible && selectedValues.length > 0 && (
<>
<PromptWrapper>
<PromptInputWrapper>
<PromptTitle>
{promptNumber !== undefined && <>{promptNumber}. </>}
{displayName}
{prompt.required && <RequiredText>required</RequiredText>}
</PromptTitle>
{description && <PromptSubTitle>{description}</PromptSubTitle>}
<InputSection>
{allowedValues && allowedValues.length > 0 && (
<>
{cardinality === PropertyCardinality.Single && (
<SingleSelectInput
allowedValues={allowedValues}
selectedValues={selectedValues}
selectSingleValue={selectSingleValue}
/>
)}
{cardinality === PropertyCardinality.Multiple && (
<MultiSelectInput
allowedValues={allowedValues}
selectedValues={selectedValues}
toggleSelectedValue={toggleSelectedValue}
updateSelectedValues={updateSelectedValues}
/>
)}
</>
)}
{!allowedValues && valueType.info.type === StdDataType.String && (
<StringInput
selectedValues={selectedValues}
cardinality={cardinality}
updateSelectedValues={updateSelectedValues}
/>
)}
{!allowedValues && valueType.info.type === StdDataType.RichText && (
<RichTextInput
selectedValues={selectedValues}
updateSelectedValues={updateSelectedValues}
/>
)}
{!allowedValues && valueType.info.type === StdDataType.Date && (
<DateInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
)}
{!allowedValues && valueType.info.type === StdDataType.Number && (
<NumberInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
)}
{!allowedValues && valueType.info.type === StdDataType.Urn && (
<UrnInput
structuredProperty={structuredProperty}
selectedValues={selectedValues}
updateSelectedValues={updateSelectedValues}
/>
)}
</InputSection>
</PromptInputWrapper>
{isComplete && !hasEditedPrompt && (
<CompletedPromptAuditStamp completedByName={completedByName} completedByTime={completedByTime} />
)}
</PromptWrapper>
{(showSaveButton || showConfirmButton) && (
<StyledButton type="primary" onClick={submitStructuredPropertyResponse}>
Save
{showSaveButton ? 'Save' : 'Confirm'}
</StyledButton>
)}
{(isPromptComplete(prompt, completedPrompts) ||
isFieldPromptComplete(field, promptAssociation) ||
optimisticCompletedTimestamp) &&
!isSaveVisible && (
<CompletedPromptAuditStamp
completedByName={getCompletedByName()}
completedByTime={getCompletedByRelativeTime()}
/>
)}
</PromptWrapper>
</>
);
}

View File

@ -5,6 +5,7 @@ import { getInitialValues } from './utils';
import usePrevious from '../../../../../shared/usePrevious';
import { useGetEntityWithSchema } from '../../../tabs/Dataset/Schema/useGetEntitySchema';
import { FormView, useEntityFormContext } from '../../EntityFormContext';
import { SCHEMA_FIELD_PROMPT_TYPES } from '../../constants';
interface Props {
prompt: FormPrompt;
@ -13,10 +14,10 @@ interface Props {
}
export default function useStructuredPropertyPrompt({ prompt, submitResponse, field }: Props) {
const { refetch: refetchSchema } = useGetEntityWithSchema();
const { refetch: refetchSchema } = useGetEntityWithSchema(!SCHEMA_FIELD_PROMPT_TYPES.includes(prompt.type));
const { refetch, entityData } = useEntityContext();
const { selectedPromptId, formView } = useEntityFormContext();
const [isSaveVisible, setIsSaveVisible] = useState(false);
const [hasEditedPrompt, setHasEditedPrompt] = useState(false);
const initialValues = useMemo(
() => (formView === FormView.BY_ENTITY ? getInitialValues(prompt, entityData, field) : []),
[formView, entityData, prompt, field],
@ -35,19 +36,19 @@ export default function useStructuredPropertyPrompt({ prompt, submitResponse, fi
const previousSelectedPromptId = usePrevious(selectedPromptId);
useEffect(() => {
if (selectedPromptId !== previousSelectedPromptId) {
setIsSaveVisible(false);
setHasEditedPrompt(false);
setSelectedValues(initialValues || []);
}
}, [previousSelectedPromptId, selectedPromptId, initialValues]);
// respond to prompts
function selectSingleValue(value: string | number) {
setIsSaveVisible(true);
setHasEditedPrompt(true);
setSelectedValues([value as string]);
}
function toggleSelectedValue(value: string | number) {
setIsSaveVisible(true);
setHasEditedPrompt(true);
if (selectedValues.includes(value)) {
setSelectedValues((prev) => prev.filter((v) => v !== value));
} else {
@ -57,7 +58,7 @@ export default function useStructuredPropertyPrompt({ prompt, submitResponse, fi
function updateSelectedValues(values: any[]) {
setSelectedValues(values);
setIsSaveVisible(true);
setHasEditedPrompt(true);
}
// submit structured property prompt
@ -80,7 +81,7 @@ export default function useStructuredPropertyPrompt({ prompt, submitResponse, fi
},
() => {
refetch();
setIsSaveVisible(false);
setHasEditedPrompt(false);
if (field) {
refetchSchema();
}
@ -89,7 +90,7 @@ export default function useStructuredPropertyPrompt({ prompt, submitResponse, fi
}
return {
isSaveVisible,
hasEditedPrompt,
selectedValues,
selectSingleValue,
toggleSelectedValue,

View File

@ -0,0 +1,62 @@
import { useMemo } from 'react';
import { EntityType, FormPrompt, SchemaField } from '../../../../../types.generated';
import { useUserContext } from '../../../../context/useUserContext';
import { useEntityRegistry } from '../../../../useEntityRegistry';
import { useEntityData } from '../../EntityContext';
import {
findCompletedFieldPrompt,
findPromptAssociation,
getCompletedPrompts,
getIncompletePrompts,
isFieldPromptComplete,
isPromptComplete,
} from '../../containers/profile/sidebar/FormInfo/utils';
import { getTimeFromNow } from '../../../../shared/time/timeUtils';
interface CompletionProps {
prompt: FormPrompt;
field?: SchemaField;
optimisticCompletedTimestamp?: number | null;
}
export default function usePromptCompletionInfo({ prompt, field, optimisticCompletedTimestamp }: CompletionProps) {
const { entityData } = useEntityData();
const { user } = useUserContext();
const entityRegistry = useEntityRegistry();
const completedPrompts = getCompletedPrompts(entityData);
const incompletePrompts = getIncompletePrompts(entityData);
const promptAssociation = findPromptAssociation(prompt, completedPrompts.concat(incompletePrompts));
const completedFieldPrompt = findCompletedFieldPrompt(field, promptAssociation);
const isComplete =
isPromptComplete(prompt, completedPrompts) ||
isFieldPromptComplete(field, promptAssociation) ||
!!optimisticCompletedTimestamp;
const completedByName = useMemo(() => {
let actor = completedFieldPrompt?.lastModified?.actor || promptAssociation?.lastModified?.actor;
if (optimisticCompletedTimestamp) {
actor = user;
}
return actor ? entityRegistry.getDisplayName(EntityType.CorpUser, actor) : '';
}, [
completedFieldPrompt?.lastModified?.actor,
entityRegistry,
optimisticCompletedTimestamp,
promptAssociation?.lastModified?.actor,
user,
]);
const completedByTime = useMemo(() => {
let completedTimestamp = completedFieldPrompt?.lastModified?.time || promptAssociation?.lastModified?.time;
if (optimisticCompletedTimestamp) {
completedTimestamp = optimisticCompletedTimestamp;
}
return completedTimestamp ? getTimeFromNow(completedTimestamp) : '';
}, [completedFieldPrompt?.lastModified?.time, optimisticCompletedTimestamp, promptAssociation?.lastModified?.time]);
return {
completedByName,
completedByTime,
isComplete,
};
}

View File

@ -9,7 +9,7 @@ const shouldLoadSchema = (entityType, entityData) => {
return entityType === EntityType.Dataset && !entityData?.schemaMetadata;
};
export const useGetEntityWithSchema = () => {
export const useGetEntityWithSchema = (skip?: boolean) => {
const { urn, entityData, entityType } = useEntityData();
// Load the dataset schema lazily.
const {
@ -20,7 +20,7 @@ export const useGetEntityWithSchema = () => {
variables: {
urn,
},
skip: !shouldLoadSchema(entityType, entityData),
skip: skip || !shouldLoadSchema(entityType, entityData),
fetchPolicy: 'cache-first',
});
const isHideSiblingMode = useIsSeparateSiblingsMode();