Skip to content
This repository has been archived by the owner on Oct 28, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into FS-4382-duplicate-heading-upload-quotes-othe…
Browse files Browse the repository at this point in the history
…r-costs-v1
  • Loading branch information
Karunred authored May 8, 2024
2 parents fe620a7 + 55a13e2 commit 39253be
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 15 deletions.
2 changes: 2 additions & 0 deletions designer/client/ComponentTypeEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { MultilineTextFieldEdit } from "./multiline-text-field-edit";
import { FreeTextFieldEdit } from "./free-text-field-edit";
import { FileUploadFieldEdit } from "./file-upload-field-edit";
import { NumberFieldEdit } from "./components/FieldEditors/number-field-edit";
import { WebsiteFieldEdit } from "./components/FieldEditors/website-field-edit";
import { DateFieldEdit } from "./components/FieldEditors/date-field-edit";
import { ParaEdit } from "./components/FieldEditors/para-edit";
import DetailsEdit from "./components/FieldEditors/details-edit";
Expand All @@ -22,6 +23,7 @@ const componentTypeEditors = {
FreeTextField: FreeTextFieldEdit,
ClientSideFileUploadField: ClientSideFileUploadFieldEdit,
NumberField: NumberFieldEdit,
WebsiteField: WebsiteFieldEdit,
AutocompleteField: ListFieldEdit,
SelectField: SelectFieldEdit,
RadiosField: ListFieldEdit,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import { render } from "@testing-library/react";
import { WebsiteFieldEdit } from "../website-field-edit";
import { RenderWithContext } from "../../../__tests__/helpers/renderers";

describe("Website field edit", () => {
describe("Website field edit fields", () => {
let stateProps;
let textFieldEditPage;

beforeEach(() => {
stateProps = {
component: {
type: "websiteFieldEdit",
name: "websiteFieldEditClass",
options: {},
},
};

textFieldEditPage = render(
<RenderWithContext stateProps={stateProps}>
<WebsiteFieldEdit />
</RenderWithContext>
);
});

test("should display prefix help text ", () => {
const text = "Specifies the prefix of the field.";
expect(textFieldEditPage.getByText(text)).toBeInTheDocument();
});
});
});
56 changes: 56 additions & 0 deletions designer/client/components/FieldEditors/website-field-edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useContext } from "react";
import { ComponentContext } from "../../reducers/component/componentReducer";
import { Actions } from "../../reducers/component/types";

import { CssClasses } from "../CssClasses";
import { i18n } from "../../i18n";

type Props = {
context: any; // TODO
};

export function WebsiteFieldEdit({ context = ComponentContext }: Props) {
// If you are editing a component, the default context will be ComponentContext because props.context is undefined,
// but if you editing a component which is a children of a list based component, then the props.context is the ListContext.
const { state, dispatch } = useContext(context);
const { selectedComponent } = state;
const { options = {} } = selectedComponent;

return (
<details className="govuk-details">
<summary className="govuk-details__summary">
<span className="govuk-details__summary-text">
{i18n("common.detailsLink.title")}
</span>
</summary>

<div className="govuk-form-group">
<label
className="govuk-label govuk-label--s"
htmlFor="field-options-prefix"
>
{i18n("websiteFieldEditComponent.prefixField.title")}
</label>
<span className="govuk-hint">
{i18n("websiteFieldEditComponent.prefixField.helpText")}
</span>
<input
className="govuk-input govuk-input--width-3"
data-cast="string"
id="field-options-prefix"
name="opions.prefix"
value={options.prefix}
type="string"
onBlur={(e) =>
dispatch({
type: Actions.EDIT_OPTIONS_PREFIX,
payload: e.target.value,
})
}
/>
</div>

<CssClasses />
</details>
);
}
6 changes: 6 additions & 0 deletions designer/client/i18n/translations/en.translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -435,5 +435,11 @@
"downloadCrashReport": "download your crash report",
"createIssue": "create an issue on GitHub",
"createIssueHint": "with details of what you were doing when this error occurred, and your crash report as an attachment"
},
"websiteFieldEditComponent": {
"prefixField": {
"helpText": "Specifies the prefix of the field.",
"title": "Prefix"
}
}
}
4 changes: 3 additions & 1 deletion fsd_config/form_jsons/hsra_r1/total-expected-cost-hsra.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
{
"name": "lfXuaP",
"options": {
"hideTitle": true
"hideTitle": true,
"prefix": "£",
"classes": "govuk-!-width-one-quarter"
},
"type": "NumberField",
"hint": "This includes any costs you expect to recover from the tenant or through matched funding",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,12 @@
"acceptedFiles": "image/jpeg,image/png,application/pdf,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.text,text/csv,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet"
},
"showNoScriptWarning": false,
"minimumRequiredFiles": 1
"minimumRequiredFiles": 1,
"hideTitle": true
},
"type": "ClientSideFileUploadField",
"title": "Upload the initial notice you served the landlord",
"hint": "Tell us about all attempts to make contact, even if they were unsuccessful"
"hint": "Upload a file"
}
],
"next": [
Expand Down
1 change: 1 addition & 0 deletions model/src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ interface TextFieldBase {
allow?: string;
autocomplete?: string;
noReturnUrlOnSummaryPage?: boolean;
prefix?: string;
};
schema: {
max?: number;
Expand Down
17 changes: 14 additions & 3 deletions runner/src/server/plugins/engine/components/WebsiteField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { FormModel } from "../models";
import { TextField } from "./TextField";
import { addClassOptionIfNone } from "./helpers";
import { FormData, FormSubmissionErrors } from "../types";
import { tr } from "date-fns/locale";

export class WebsiteField extends TextField {
private defaultMessage =
"Enter website address in the correct format, starting with 'https://'";
"Enter website address in the correct format, e.g. 'www.gov.uk'";

formSchema: StringSchema;
options: WebsiteFieldComponent["options"];
Expand All @@ -31,7 +32,9 @@ export class WebsiteField extends TextField {

this.formSchema = this.formSchema
.label(def.title)
.uri()
.pattern(
/^(www\.)?[a-zA-Z0-9]{2,}(\.[a-zA-Z0-9]{2,})(\.[a-zA-Z0-9]{2,})?/
)
.message(def.options?.customValidationMessage ?? this.defaultMessage);

if (schema.max) {
Expand Down Expand Up @@ -59,8 +62,16 @@ export class WebsiteField extends TextField {

getViewModel(formData: FormData, errors: FormSubmissionErrors) {
const options: any = this.options;
const { prefix } = options;
const viewModelPrefix = { prefix: { text: prefix } };
const schema: any = this.schema;
const viewModel = super.getViewModel(formData, errors);
const viewModel = {
...super.getViewModel(formData, errors),
type: "website",
// ...False returns nothing, so only adds content when
// the given options are present.
...(options.prefix && viewModelPrefix),
};

if (options.hideTitle) {
viewModel.label = { text: "", html: viewModel.hint?.html!, classes: "" };
Expand Down
2 changes: 1 addition & 1 deletion runner/src/server/views/partials/summary-row.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{% for itemValue in item.value%}
{{itemValue}}<br>
{% endfor %}
{% elif item.type == 'NumberField' %}
{% elif item.type == 'NumberField' or item.type == 'WebsiteField' %}
{{item.prefix}}{{item.value}}
{% elif item.type == 'ClientSideFileUploadField' %}
{% if item.value.files|length == 0 %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ suite("Website field", () => {

const { formSchema } = new WebsiteField(def, model);

expect(formSchema.validate("https://www.gov.uk").error).to.be.undefined();
expect(formSchema.validate("www.gov.uk").error).to.be.undefined();
expect(
formSchema.validate("http://www.gov.uk/test?id=ABC").error
formSchema.validate("www.gov.uk/test?id=ABC").error
).to.be.undefined();
expect(formSchema.validate("1").error!.message).to.contain(
`Enter website address in the correct format`
Expand All @@ -66,7 +66,7 @@ suite("Website field", () => {

const { formSchema } = new WebsiteField(def, model);

expect(formSchema.validate("www.gov.uk").error?.message).to.contain(
expect(formSchema.validate("gov").error?.message).to.contain(
"Invalid address entered"
);
});
Expand All @@ -85,9 +85,11 @@ suite("Website field", () => {

const { formSchema } = new WebsiteField(def, model);

expect(formSchema.validate("http://www.gov.uk").error).to.be.undefined();
expect(formSchema.validate("www.gov.uk").error).to.be.undefined();

expect(formSchema.validate("https://www.gov.uk").error?.message).to.contain(
expect(
formSchema.validate("www.legislation.gov.uk").error?.message
).to.contain(
`"My component" length must be less than or equal to 17 characters long`
);
});
Expand All @@ -106,9 +108,11 @@ suite("Website field", () => {

const { formSchema } = new WebsiteField(def, model);

expect(formSchema.validate("https://www.gov.uk").error).to.be.undefined();
expect(
formSchema.validate("www.legislation.gov.uk").error
).to.be.undefined();

expect(formSchema.validate("http://www.gov.uk").error?.message).to.contain(
expect(formSchema.validate("www.gov.uk").error?.message).to.contain(
`"My component" length must be at least 18 characters long`
);
});
Expand Down Expand Up @@ -153,3 +157,19 @@ suite("Website field", () => {
expect(formSchema.validate(null).error).to.be.undefined();
});
});

test("Prefix are passed to view model", () => {
const def = {
name: "myComponent",
title: "My component",
schema: {},
type: "WebsiteField",
options: { prefix: "@£%" },
};
const websiteFieldPrefix = new WebsiteField(def);
const { schema } = websiteFieldPrefix;

expect(websiteFieldPrefix.getViewModel({})).to.contain({
prefix: { text: "@£%" },
});
});
2 changes: 1 addition & 1 deletion version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION=0.1.265
VERSION=0.1.265

0 comments on commit 39253be

Please sign in to comment.