diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4966ef6..b7c7447 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @episerver/addons-developers @longle91 +* @episerver/cms-addons diff --git a/.gitignore b/.gitignore index c153578..05e1bca 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ coverage/ /samples/epiCloud/ /samples/musicfestival-frontend-react/build/ /samples/musicfestival-backend-dotnet/App_Data/ + +.env.local +appsettings.development.json \ No newline at end of file diff --git a/.npmrc b/.npmrc index e3d02e3..0833a30 100644 --- a/.npmrc +++ b/.npmrc @@ -7,4 +7,4 @@ always-auth=true //pkgs.dev.azure.com/EpiserverEngineering/netCore/_packaging/HeadlessForms/npm/:username=${AZURE_USERNAME} //pkgs.dev.azure.com/EpiserverEngineering/netCore/_packaging/HeadlessForms/npm/:_password=${AZURE_TOKEN} //pkgs.dev.azure.com/EpiserverEngineering/netCore/_packaging/HeadlessForms/npm/:email=${AZURE_EMAIL} -; end auth token \ No newline at end of file +; end auth token diff --git a/samples/musicfestival-backend-dotnet/Startup.cs b/samples/musicfestival-backend-dotnet/Startup.cs index eb3a653..e7537ee 100644 --- a/samples/musicfestival-backend-dotnet/Startup.cs +++ b/samples/musicfestival-backend-dotnet/Startup.cs @@ -1,5 +1,6 @@ using System.Runtime.InteropServices; using EPiServer.Cms.Shell; +using EPiServer.Cms.Shell.UI; using EPiServer.Cms.UI.AspNetIdentity; using EPiServer.ContentApi.Cms; using EPiServer.ContentApi.Core.DependencyInjection; @@ -59,7 +60,8 @@ public void ConfigureServices(IServiceCollection services) services .AddCmsAspNetIdentity() .AddCms() - .AddAdminUserRegistration() + .AddAdminUserRegistration(options => options.Behavior = RegisterAdminUserBehaviors.Enabled | + RegisterAdminUserBehaviors.LocalRequestsOnly) .AddEmbeddedLocalization() .ConfigureForExternalTemplates() .Configure(options => options.OptimizeForDelivery = true) diff --git a/samples/musicfestival-frontend-react/src/hooks/useHistoryCompatible.tsx b/samples/musicfestival-frontend-react/src/hooks/useHistoryCompatible.tsx new file mode 100644 index 0000000..2776e19 --- /dev/null +++ b/samples/musicfestival-frontend-react/src/hooks/useHistoryCompatible.tsx @@ -0,0 +1,14 @@ +import { useNavigate, useLocation } from 'react-router-dom'; + +export const useHistoryCompatible = () => { + const navigate = useNavigate(); + const location = useLocation(); + + return { + push: (path: any, state: any) => navigate(path, { state }), + replace: (path: any, state: any) => navigate(path, { replace: true, state }), + location: location, + goBack: () => navigate(-1), + goForward: () => navigate(1), + }; +}; \ No newline at end of file diff --git a/samples/musicfestival-frontend-react/src/pages/BuyTicketPage.tsx b/samples/musicfestival-frontend-react/src/pages/BuyTicketPage.tsx index c5f0249..4186316 100644 --- a/samples/musicfestival-frontend-react/src/pages/BuyTicketPage.tsx +++ b/samples/musicfestival-frontend-react/src/pages/BuyTicketPage.tsx @@ -1,11 +1,8 @@ import { Form, FormContainerBlock, FormLogin } from '@episerver/forms-react'; import { FormCache, FormConstants, IdentityInfo, extractParams } from '@episerver/forms-sdk'; import { useEffect, useState } from 'react'; -import { useNavigate, useLocation } from 'react-router-dom'; -import { useFetch } from '../useFetch'; +import { useHistoryCompatible } from '../hooks/useHistoryCompatible'; import SearchButton from '../components/SearchButton'; -import { getImageUrl } from '../helpers/urlHelper'; -import authService from '../authService'; type BuyTicketPageProps = { content: any, @@ -24,7 +21,7 @@ function BuyTicketPage({ content }: BuyTicketPageProps) { } as IdentityInfo) }, [formCache.get(FormConstants.FormAccessToken)]); - const history = useNavigate() + const history = useHistoryCompatible() return ( <> {content && @@ -59,7 +56,7 @@ function BuyTicketPage({ content }: BuyTicketPageProps) {
{ //update form state dispatchFuncs.resetFormDone(); } - },[formContext?.isReset]); + }, [formContext?.isReset]); //update visible - useEffect(()=>{ + useEffect(() => { const conditionProps = (element.properties as unknown) as ConditionProperties; - if (isNull(conditionProps.satisfiedAction)) { + if (isNull(conditionProps.satisfiedAction) || isNull(conditionProps.conditions)) { + // No conditions and satisfied actions to take, no need to update dependencies return; } //check form field dependencies - const checkConditions = formCondition.checkConditions(formContext?.formSubmissions as FormSubmission[]); + const checkConditions = formCondition.checkConditions(formContext?.formSubmissions as FormSubmission[], formContext?.elementDependencies); if (checkConditions) { //if isDependenciesSatisfied = true, and if SatisfiedAction = show, then show element. otherwise hide element. isVisible.current = equals(conditionProps.satisfiedAction, SatisfiedActionType.Show); @@ -102,16 +103,19 @@ export const useElement = (element: FormElementBase) => { //if isDependenciesSatisfied = false, and if SatisfiedAction = hide, then show element. otherwise hide element. isVisible.current = equals(conditionProps.satisfiedAction, SatisfiedActionType.Hide); } + var currentCondition = formContext?.elementDependencies.find(e => e.elementKey === element.key)?.isSatisfied; + + if (currentCondition != checkConditions) { + // Update element dependencies state + dispatchFuncs.UpdateElementDependencies(element.key, checkConditions); + } - // Update element dependencies state - dispatchFuncs.UpdateElementDependencies(element.key,checkConditions); - - },[formContext?.formSubmissions]); + }, [formContext?.formSubmissions, formContext?.elementDependencies]); //focus on element if validate fail before submitting - useEffect(()=>{ + useEffect(() => { let focusOn = formContext?.focusOn ?? ""; - if(equals(focusOn, element.key)){ + if (equals(focusOn, element.key)) { elementRef.current && elementRef.current.focus(); dispatchFuncs.updateFocusOn(""); } diff --git a/src/@episerver/forms-sdk/src/form-depend-conditions/formDependConditions.ts b/src/@episerver/forms-sdk/src/form-depend-conditions/formDependConditions.ts index 18ef905..27d63f7 100644 --- a/src/@episerver/forms-sdk/src/form-depend-conditions/formDependConditions.ts +++ b/src/@episerver/forms-sdk/src/form-depend-conditions/formDependConditions.ts @@ -1,5 +1,6 @@ import { equals, isNull } from "../helpers"; -import { ConditionCombinationType, ConditionProperties, FormElementBase, FormSubmission } from "../models"; +import { getValueOfDependeeElement } from "../helpers/dependencyHelper"; +import { Condition, ConditionCombinationType, ConditionProperties, ElementDependencies, FormElementBase, FormSubmission } from "../models"; import { ConditionFunctions } from "./ConditionFunctions"; /** * Class to check if a element conditions is met @@ -14,7 +15,7 @@ export class FormDependConditions { * @param formSubmissions * @returns */ - checkConditions = (formSubmissions: FormSubmission[]): boolean => { + checkConditions = (formSubmissions: FormSubmission[], elementDependencies: ElementDependencies[] = []): boolean => { if (!isNull(formSubmissions)) { const conditionProps = (this._element.properties as unknown) as ConditionProperties; if (isNull(conditionProps?.conditions)) { @@ -23,10 +24,10 @@ export class FormDependConditions { } for (let i = 0; i < conditionProps.conditions.length; i++) { const condition = conditionProps.conditions[i] - const fieldValue = formSubmissions.filter(s => equals(s.elementKey, condition.field))[0]?.value; + const dependeeFieldValue = getValueOfDependeeElement(condition,formSubmissions,elementDependencies); const conditionFunction = ConditionFunctions[condition.operator]; if (!isNull(conditionFunction)){ - let checkResult = conditionFunction(fieldValue == null? "":fieldValue.toString(), condition.fieldValue) + let checkResult = conditionFunction(dependeeFieldValue == null? "" : dependeeFieldValue.toString(), condition.fieldValue) if (conditionProps.conditionCombination === ConditionCombinationType.Any && checkResult) { return true } diff --git a/src/@episerver/forms-sdk/src/form-loader/formLoader.ts b/src/@episerver/forms-sdk/src/form-loader/formLoader.ts index df7674f..20751b3 100644 --- a/src/@episerver/forms-sdk/src/form-loader/formLoader.ts +++ b/src/@episerver/forms-sdk/src/form-loader/formLoader.ts @@ -87,7 +87,6 @@ export class FormLoader { if (response.ok) { let json = await response.json(); let formStr = json.data.FormContainer.items[0]; - console.log(formStr) let convertedFormStr = this.convertFirstLetterToLowerCase(formStr) as T resolve(convertedFormStr) } diff --git a/src/@episerver/forms-sdk/src/helpers/dependencyHelper.ts b/src/@episerver/forms-sdk/src/helpers/dependencyHelper.ts index 5d29bff..fc4b75b 100644 --- a/src/@episerver/forms-sdk/src/helpers/dependencyHelper.ts +++ b/src/@episerver/forms-sdk/src/helpers/dependencyHelper.ts @@ -1,3 +1,16 @@ +import { Condition, ElementDependencies, FormSubmission } from "../models"; +import { equals } from "./utils"; + export function getConcatString(srcObject: any, seperator: string): string { return (srcObject instanceof Array) ? srcObject.join(seperator) : srcObject as string; +} + +export function getValueOfDependeeElement(condition: Condition ,formSubmissions: FormSubmission[], elementDependencies: ElementDependencies[]) : any { + var dependeeFieldValue = formSubmissions.filter(s => equals(s.elementKey, condition.field))[0]?.value; + const dependeeElement = elementDependencies.find(e => e.elementKey === condition.field) + if (dependeeElement && !dependeeElement.isSatisfied ) { + // if element is in the inactive list, consider its value as undefined + dependeeFieldValue = undefined; + } + return dependeeFieldValue; } \ No newline at end of file