Skip to content

Commit

Permalink
fix: updated validatortypes
Browse files Browse the repository at this point in the history
  • Loading branch information
KasperBaun committed Apr 12, 2024
1 parent 3b0e731 commit 4c8448d
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 17 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/components/question/Question.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const Question: React.FC<QuestionProps> = ({ model, style }) => {
questionModel={model}
{...model.inputProperties ?? {}}
/>
{model.validationResult?.message !== "" && <ErrorMessage message={model.validationResult?.message} />}
{typeof (model.validationResult?.message) !== "undefined" && model.validationResult?.message !== "" && <ErrorMessage message={model.validationResult?.message} />}
</div>
);
}
3 changes: 2 additions & 1 deletion packages/core/src/services/QuickFormServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { InputPropertiesTypes, QuestionModel, QuickFormModel } from "../model";
import { QuickFormDefinition } from "../model";
import { QuestionJsonModel } from "../model/json-definitions/JsonDataModels";
import { InputComponentType } from "./defaults/DefaultInputTypeResolver";
import { QuickformState } from "../state";

export type HeadingNumberDisplayProvider = () => boolean;
export type QuickFormModelTransformer = (data: QuickFormDefinition, payload: any) => QuickFormModel;
export type QuestionTransformer = (key: string, question: QuestionJsonModel, value?: any, visible?: { type: string; rule: string; }) => QuestionModel;
export type InputTypePropertiesTransformer = (questionJsonModel: QuestionJsonModel) => InputPropertiesTypes | undefined;
export type RegisterInputTypeComponent = (key: string, component: InputComponentType) => void;
export type InputValidator = <TProps extends InputPropertiesTypes>(questionModel: QuestionModel<TProps>) => Promise<ValidationResult>;
export type InputValidator = <TProps extends InputPropertiesTypes>(questionModel: QuestionModel<TProps>, state: QuickformState) => Promise<ValidationResult>;
export interface IQuickFormLogger {
log(body: string, ...args: any[]): void;
warn(body: string, ...args: any[]): void;
Expand Down
13 changes: 8 additions & 5 deletions packages/core/src/services/defaults/DefaultInputValidator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ValidationResult } from "../../model/ValidationResult";
import { InputPropertiesTypes, QuestionModel } from "../../model";
import { registerQuickFormService } from "../QuickFormServices";
import { QuickformState } from "../../state";

const validateText = (output: any): ValidationResult => {
const text = typeof output === 'string' ? output.trim() : '';
Expand Down Expand Up @@ -50,7 +51,7 @@ const validatePhone = async (output: any): Promise<ValidationResult> => {
};

type ValidatorMap = {
[inputType: string]: (output: any, properties?: any) => Promise<ValidationResult>;
[inputType: string]: ValidatorFunction<any, any, QuestionModel<any>, QuickformState>;
};

const validatorMap: ValidatorMap = {
Expand All @@ -60,7 +61,7 @@ const validatorMap: ValidatorMap = {
multilinetext: (output: any) => Promise.resolve(validateMultilineText(output))
};

const validateQuestionOutput = async <TProps extends InputPropertiesTypes>(questionModel: QuestionModel<TProps>): Promise<ValidationResult> => {
const validateQuestionOutput = async <TProps extends InputPropertiesTypes>(questionModel: QuestionModel<TProps>, state: QuickformState): Promise<ValidationResult> => {
const validator = validatorMap[questionModel.inputType];
if (!validator) {
// This is to support if no validation is created for inputtype.. defaults to validated..
Expand All @@ -73,11 +74,13 @@ const validateQuestionOutput = async <TProps extends InputPropertiesTypes>(quest
});
}

return await validator(questionModel.output, questionModel.inputProperties);
return await validator(questionModel.output, questionModel.inputProperties, questionModel,state);
};

export const registerInputTypeValidator = (key: string, validator: (output: any, properties?: any) => Promise<ValidationResult>) => {
validatorMap[key] = validator;
export type ValidatorFunction<TAnswer, TInputProps, TQuestionModel extends QuestionModel<TInputProps>, TQuickFormState extends QuickformState> = (output: TAnswer, properties: TInputProps, questionModel: TQuestionModel, state: TQuickFormState) => Promise<ValidationResult>;

export const registerInputTypeValidator = <TAnswer, TInputProps, TQuestionModel extends QuestionModel<TInputProps>, TQuickFormState extends QuickformState>(key: string, validator: ValidatorFunction<TAnswer, TInputProps, TQuestionModel, TQuickFormState>) => {
validatorMap[key] = validator as ValidatorFunction<any, any, QuestionModel<any>, QuickformState>;
};

registerQuickFormService("inputValidator", validateQuestionOutput);
6 changes: 2 additions & 4 deletions packages/core/src/state/QuickformProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { QuickFormTokens, defineQuickFormTokens } from "../style/quickFormTokens
import { QuickFormDefinition } from "../model";
import { resolveQuickFormService } from "../services/QuickFormServices";
import { kbaQuickFormTokens } from "../style/kbaQuickFormTokens";
import { isFirstQInCurrentSlide } from "../utils/isFirstQuestionInSlide";

type QuickFormProviderProps = {
children: React.ReactNode;
Expand Down Expand Up @@ -47,10 +48,7 @@ export const QuickFormProvider: React.FC<QuickFormProviderProps> = (
}
const setIntroVisited = () => { dispatch({ type: 'SET_INTRO_VISITED' }) };
const setErrorMsg = (msg: string) => { dispatch({ type: "SET_ERROR_MSG", msg: msg }) };
const isFirstQuestionInCurrentSlide = (questionLogicalName: string) => {
const currSlide = state.slides[state.currIdx];
return currSlide.questions && currSlide.questions.length > 0 && currSlide.questions[0].logicalName === questionLogicalName && currSlide.questions[0].visited !== true;
}
const isFirstQuestionInCurrentSlide = (questionLogicalName: string) => { return isFirstQInCurrentSlide(questionLogicalName, state); }
const getCurrentSlide = () => (state.slides[state.currIdx]);

return (
Expand Down
15 changes: 11 additions & 4 deletions packages/core/src/state/action-handlers/QuestionActionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,16 @@ export class QuestionActionHandler {
};

static startQuestionValidation = (state: QuickformState, logicalName: string, timestamp: number) => {
const currentValidationResult = findQuestionByLogicalName(logicalName, getAllQuestions(state.slides)).validationResult;
const currentValidationResult = findQuestionByLogicalName(logicalName, getAllQuestions(state.slides))?.validationResult;

return this.updateQuestionProperties(state, logicalName, {
validationResult: { ...currentValidationResult, timestamp: timestamp, isValidating: true, isValid: false }
});
};

static updateQuestionValidation = (state: QuickformState, logicalName: string, validationResult: ValidationResult, timestamp: number) => {
const currentValidationResult = findQuestionByLogicalName(logicalName, getAllQuestions(state.slides)).validationResult;
if (currentValidationResult.timestamp !== timestamp) {
const currentValidationResult = findQuestionByLogicalName(logicalName, getAllQuestions(state.slides))?.validationResult;
if (currentValidationResult?.timestamp !== timestamp) {
return state;
}
return this.updateQuestionProperties(state, logicalName, {
Expand All @@ -87,6 +87,13 @@ export class QuestionActionHandler {

static async validateInput(state: QuickformState, logicalName: string): Promise<ValidationResult> {
const questionRef = findQuestionByKey(logicalName, getAllQuestions(state.slides));
return await QuestionActionHandler.inputValidator(questionRef);
if (!questionRef) {
return {
isValid: false,
message: 'Question not valid',
validatedOutput: ''
}
}
return await QuestionActionHandler.inputValidator(questionRef, state);
}
}
17 changes: 17 additions & 0 deletions packages/core/src/utils/isFirstQuestionInSlide.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { QuickformState } from "../state";

/**
* Determines if the provided question is the first in the current slide and if it should receive autofocus.
* The method checks if any question on the slide has been visited, and if so, it will not autofocus the first question.
* @param questionLogicalName The logical name of the question to check.
* @returns boolean indicating if the question is the first and should be autofocused.
*/
export const isFirstQInCurrentSlide = (questionLogicalName: string, state: QuickformState): boolean => {
const currSlide = state.slides[state.currIdx];
if (currSlide.questions && currSlide.questions.length > 0) {
const isFirstQuestion = currSlide.questions[0].logicalName === questionLogicalName;
const anyQuestionVisited = currSlide.questions.some(q => q.visited);
return isFirstQuestion && !anyQuestionVisited;
}
return false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { MouseEventHandler, ReactNode } from "react";
import classNames from "classnames";
import styles from "./DropdownSelectOption.module.css";
import { makeStyles, mergeClasses } from "@griffel/react";
import { quickformtokens } from "@eavfw/quickform-core/src/style/quickformtokens";
import { Checkmark } from "@eavfw/quickform-core/src/components/icons";
import { shorthands } from "@fluentui/react-components";
import { quickformtokens } from "@eavfw/quickform-core/src/style/quickFormTokensDefinition";

type DropdownSelectOptionProps = {
readonly isSelected?: boolean;
Expand Down Expand Up @@ -35,7 +35,7 @@ const useDropDownSelectOptionStyles = makeStyles({
color: quickformtokens.onSurface,
backgroundColor: 'transparent',

...shorthands.border('1px', 'solid', quickformtokens.borderColor),
...shorthands.border('1px', 'solid', quickformtokens.primary),
...shorthands.borderRadius('5px'),
':hover': {
color: quickformtokens.onSurface,
Expand Down

0 comments on commit 4c8448d

Please sign in to comment.