Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add handler submit api exception, and add some description #56

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/ManagementSite/Alloy.ManagementSite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<PackageReference Include="EPiServer.CMS.UI.VisitorGroups" Version="12.23.0" />
<PackageReference Include="EPiServer.CMS.UI.AspNetIdentity" Version="12.23.0" />
<PackageReference Include="EPiServer.ImageLibrary.ImageSharp" Version="2.0.1" />
<PackageReference Include="Optimizely.Headless.Form.Service" Version="0.1.0--inte-173" />
<PackageReference Include="Optimizely.Headless.Form.Service" Version="0.1.0--inte-188" />
<PackageReference Include="Optimizely.Cms.Content.EPiServer" Version="0.3.1" />
<PackageReference Include="EPiServer.Forms" Version="5.8.0-ci-021201" />
<PackageReference Include="EPiServer.OpenIDConnect" Version="3.2.0"/>
Expand Down
10 changes: 5 additions & 5 deletions samples/sample-react-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import './App.css';
import { useFetch } from './hooks/useFetch';
import { Form, FormLogin } from '@episerver/forms-react';
import { extractParams } from './helpers/urlHelper';
import { FormCache, FormConstants, IdentityInfo, isNullOrEmpty } from '@episerver/forms-sdk';
import { useEffect, useState } from 'react';
import { BrowserRouter, useHistory, useLocation } from 'react-router-dom';
import { FormCache, FormConstants, IdentityInfo } from '@episerver/forms-sdk';
import { useState } from 'react';
import { useHistory, useLocation } from 'react-router-dom';

function App() {
const location = useLocation();
const { relativePath, language } = extractParams(window.location.pathname)
const { language } = extractParams(window.location.pathname)
const url = `${process.env.REACT_APP_ENDPOINT_GET_FORM_BY_PAGE_URL}${location.pathname}`;

const { data: pageData, loading } = useFetch(url);
Expand Down Expand Up @@ -44,7 +44,7 @@ function App() {
/>
))}
</div>
<div className={`right ${!isNullOrEmpty(identityInfo.accessToken) ? "hide" : ""}`}>
<div className={`right`}>
<h2>Login</h2>
<FormLogin
clientId='TestClient'
Expand Down
2 changes: 1 addition & 1 deletion src/@episerver/forms-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@episerver/forms-react",
"version": "1.0.0",
"version": "0.1.0",
"description": "Forms react components render a form from JSON data",
"author": "Optimizely",
"license": "ISC",
Expand Down
14 changes: 13 additions & 1 deletion src/@episerver/forms-react/src/FormLogin.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FormAuthenticate, FormAuthenticateConfig, FormCache, FormConstants, IdentityInfo, isNullOrEmpty } from "@episerver/forms-sdk";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";

interface FormLoginProps{
/**
Expand Down Expand Up @@ -43,6 +43,18 @@ export const FormLogin = (props: FormLoginProps) => {
});
}

useEffect(()=>{
let intervalId = setInterval(()=>{
let accessToken = formCache.get<string>(FormConstants.FormAccessToken);
if(isNullOrEmpty(accessToken)){
setIsAuthenticated(false);
}
},1000);
return ()=>{
clearInterval(intervalId);
}
},[]);

return (
<>
{isAuthenticated ? (<div className="Form__Authenticated">Authenticated</div>) : (
Expand Down
33 changes: 23 additions & 10 deletions src/@episerver/forms-react/src/components/FormBody.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useRef } from "react";
import { useForms } from "../context/store";
import { FormContainer, FormSubmitter, IdentityInfo, equals, isInArray, isNull, isNullOrEmpty, FormSubmitModel, FormSubmitResult, SubmitButton, FormValidationResult, FormCache, FormConstants } from "@episerver/forms-sdk";
import { FormContainer, FormSubmitter, IdentityInfo, equals, isInArray, isNull, isNullOrEmpty, FormSubmitModel, FormSubmitResult, SubmitButton, FormValidationResult, FormCache, FormConstants, ProblemDetail } from "@episerver/forms-sdk";
import { RenderElementInStep } from "./RenderElementInStep";
import { DispatchFunctions } from "../context/dispatchFunctions";
import { FormStepNavigation } from "./FormStepNavigation";
Expand Down Expand Up @@ -39,7 +39,7 @@ export const FormBody = (props: FormBodyProps) => {
isStepValidToDisplay = true;

if((isFormFinalized.current || isProgressiveSubmit.current) && isSuccess.current)
{
{
statusDisplay.current = "Form__Success__Message";
statusMessage.current = form.properties.submitSuccessMessage ?? message.current;
}
Expand All @@ -48,6 +48,10 @@ export const FormBody = (props: FormBodyProps) => {
statusDisplay.current = "Form__Warning__Message";
statusMessage.current = message.current;
}
else {
statusDisplay.current = "hide";
statusMessage.current = "";
}

const validationCssClass = validateFail.current ? "ValidationFail" : "ValidationSuccess";

Expand All @@ -66,6 +70,11 @@ export const FormBody = (props: FormBodyProps) => {
)[0]?.elementKey;
}

const showError = (error: string) => {
submissionWarning.current = !isNullOrEmpty(error);
message.current = error;
}

const handleSubmit = (e: any) => {
e.preventDefault();

Expand Down Expand Up @@ -114,9 +123,8 @@ export const FormBody = (props: FormBodyProps) => {
message.current = response.messages.map(m => m.message).join("<br>");
}
else {
submissionWarning.current = true;
//ignore validation message
message.current = response.messages.filter(m => isNullOrEmpty(m.identifier)).map(m => m.message).join("<br>");
showError(response.messages.filter(m => isNullOrEmpty(m.identifier)).map(m => m.message).join("<br>"));
}
//update validation message
if(response.validationFail){
Expand All @@ -141,26 +149,31 @@ export const FormBody = (props: FormBodyProps) => {
isSuccess.current = response.success;
isFormFinalized.current = isLastStep && response.success;
dispatchFunctions.updateSubmissionKey(response.submissionKey);
dispatchFunctions.updateIsSubmitting(false);

localFormCache.set(submissionStorageKey, response.submissionKey)

if (isFormFinalized.current) {
formCache.remove(submissionStorageKey)
localFormCache.remove(submissionStorageKey)
}
}).catch((e: ProblemDetail) => {
if(e.status === 401) {
//clear access token to ask login again
dispatchFunctions.updateIdentity({} as IdentityInfo);
formCache.remove(FormConstants.FormAccessToken);
showError(e.detail);
}
}).finally(()=>{
dispatchFunctions.updateIsSubmitting(false);
});
}

useEffect(() => {
dispatchFunctions.updateIdentity(props.identityInfo);
if (isNullOrEmpty(props.identityInfo?.accessToken) && !form.properties.allowAnonymousSubmission) {
statusDisplay.current = "Form__Warning__Message";
statusMessage.current = "You must be logged in to submit this form. If you are logged in and still cannot post, make sure \"Do not track\" in your browser settings is disabled.";
showError(form.localizations["allowAnonymousSubmissionErrorMessage"]);
}
else {
statusMessage.current = "";
statusDisplay.current = "hide";
showError("");
}
}, [props.identityInfo?.accessToken]);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useRef } from "react";
import { useForms, useFormsDispatch } from "../context/store";
import { useForms } from "../context/store";
import { FormCache, FormConstants, FormContainer, FormStep, StepDependCondition, SubmitButtonType, isNull } from "@episerver/forms-sdk";
import { DispatchFunctions } from "../context/dispatchFunctions";
import { useHistory } from "react-router-dom";

interface FormStepNavigationProps {
isFormFinalized: boolean
Expand Down
2 changes: 1 addition & 1 deletion src/@episerver/forms-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@episerver/forms-sdk",
"version": "1.0.0",
"version": "0.1.0",
"description": "Forms SDK with client validation, step navigation, submit form, element depends",
"author": "Optimizely",
"license": "ISC",
Expand Down
7 changes: 4 additions & 3 deletions src/@episerver/forms-sdk/src/form-submit/formSubmit.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FormStorage } from "../form-storage";
import { FormValidator } from "../form-validator";
import { equals, isNull } from "../helpers";
import { FormConstants, FormContainer, FormSubmission, FormValidationResult } from "../models";
import { FormConstants, FormContainer, FormSubmission, FormValidationResult, ProblemDetail } from "../models";
import { ApiConstant } from "../form-loader/apiConstant";

export interface FormSubmitModel {
Expand Down Expand Up @@ -149,16 +149,17 @@ export class FormSubmitter {

fetch(`${this._baseUrl}${ApiConstant.apiEndpoint}`, requestInit)
.then(async (response: Response) => {
let json = await response.json();
if(response.ok){
let result = (await response.json()) as FormSubmitResult;
let result = json as FormSubmitResult;
if(result.success && model.isFinalized){
//clear cache of form submission
formStorage.removeFormDataInStorage();
}
resolve(result);
}
else {
reject(response);
reject(json as ProblemDetail);
}
})
.catch((error: any) => {
Expand Down
3 changes: 3 additions & 0 deletions src/@episerver/forms-sdk/src/models/IdentityInfo.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* Represent type of object that is identity information
*/
export interface IdentityInfo {
username: string,
accessToken: string
Expand Down
11 changes: 11 additions & 0 deletions src/@episerver/forms-sdk/src/models/ProblemDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Represent type of API exception
*/
export interface ProblemDetail {
type: string;
title: string;
status: number;
detail: string;
instance: string;
traceId: string;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* How to combine result of all condition satisfy
*/
export enum ConditionCombinationType{
All = "All",
Any = "Any"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* enum represent a dependent condition Operator (in the Rule to evaluate depend value).
*/
export enum ConditionFunctionType {
MatchRegularExpression = "MatchRegularExpression",
Contains = "Contains",
Expand Down
3 changes: 3 additions & 0 deletions src/@episerver/forms-sdk/src/models/enums/FormConstants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* The list of constants is the keyword used for cached values
*/
export enum FormConstants {
FormAccessToken = "form_access_token",
FormFieldPrefix = "__field_",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* The action when condition is satisfied
*/
export enum SatisfiedActionType{
Show = "show",
Hide = "hide"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* Enum represent type name of step navigation
*/
export enum SubmitButtonType {
PreviousStep = "PreviousStep",
NextStep = "NextStep"
Expand Down
3 changes: 3 additions & 0 deletions src/@episerver/forms-sdk/src/models/enums/ValidatorType.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* The list of validator type
*/
export enum ValidatorType{
RequiredValidator = "RequiredValidator",
EmailValidator = "EmailValidator",
Expand Down
3 changes: 2 additions & 1 deletion src/@episerver/forms-sdk/src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from "./elements";
export * from "./validators";
export * from "./enums";
export * from "./states";
export * from "./IdentityInfo";
export * from "./IdentityInfo";
export * from "./ProblemDetail";
2 changes: 1 addition & 1 deletion src/@episerver/forms-sdk/src/models/states/FormState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { FormValidationResult } from "./FormValidation"
import { StepDependencies } from "./StepDependencies"

/**
* Interface to define type of object that is form context
* Represent type of object that is form context
*/
export interface FormState {
isReset: boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* Represent type of object that is form submission
*/
export interface FormSubmission {
elementKey: string
value: any
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Interface to define type of object that is form validation result
* Represent type of object that is form validation result
*/
export interface FormValidationResult
{
Expand All @@ -8,7 +8,7 @@ export interface FormValidationResult
}

/**
* Interface to define type of object that is element validation result
* Represent type of object that is element validation result
*/
export interface ElementValidationResult {
type: string
Expand Down