Skip to content

Commit

Permalink
Add name to site creation form, but autopopulate based on title input
Browse files Browse the repository at this point in the history
  • Loading branch information
mbertrand committed Jun 14, 2021
1 parent e32d103 commit 9553f09
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 4 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
"sass-loader": "^10.1.1",
"showdown": "^1.9.1",
"sinon": "^9.0.2",
"slugify": "^1.5.0",
"style-loader": "^1.2.1",
"ts-jest": "^27.0.2",
"ts-loader": "^8.0.14",
Expand Down
26 changes: 26 additions & 0 deletions static/js/components/forms/SiteForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,31 @@ describe("SiteForm", () => {
expect(error.errors).toStrictEqual(["Title is a required field"])
}
})
it("rejects an empty name", async () => {
try {
await expect(
await websiteValidation.validateAt("name", { name: "" })
).rejects.toThrow()
} catch (error) {
expect(error).toBeInstanceOf(ValidationError)
expect(error.errors).toStrictEqual(["URL is a required field"])
}
})
;["这是我的", "Test", "test!", "test_test", "test()", "test_test"].forEach(
name => {
it("rejects an invalid name", async () => {
try {
await expect(
await websiteValidation.validateAt("name", { name })
).rejects.toThrow()
} catch (error) {
expect(error).toBeInstanceOf(ValidationError)
expect(error.errors).toStrictEqual([
"Must be lowercase & only include letters (a-z), numbers, dashes"
])
}
})
}
)
})
})
33 changes: 31 additions & 2 deletions static/js/components/forms/SiteForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from "react"
import { Formik, Form, ErrorMessage, Field, FormikHelpers } from "formik"
import * as yup from "yup"
import slugify from "slugify"

import { FormError } from "./FormError"

Expand All @@ -9,6 +10,7 @@ import SelectField from "../widgets/SelectField"

export interface SiteFormValues {
title: string
name: string
starter: number | null
}

Expand All @@ -26,15 +28,32 @@ export const websiteValidation = yup.object().shape({
.label("Title")
.trim()
.required(),
name: yup
.string()
.label("URL")
.trim()
.matches(/^[a-z0-9-]*$/, {
message: "Must be lowercase & only include letters (a-z), numbers, dashes"
})
.required(),
starter: yup.number().required()
})

const handleTitleChange = (handler: any) => (e: any) => {
const { target } = e
const { value } = target
const computedValue = slugify(value, { strict: true }).toLowerCase()
handler({ target })
handler({ target: { name: "name", value: computedValue } })
}

export const SiteForm = ({
onSubmit,
websiteStarters
}: Props): JSX.Element | null => {
const initialValues: SiteFormValues = {
title: "",
name: "",
starter: websiteStarters.length > 0 ? websiteStarters[0].id : 0
}

Expand All @@ -44,13 +63,23 @@ export const SiteForm = ({
validationSchema={websiteValidation}
initialValues={initialValues}
>
{({ isSubmitting, status }) => (
{({ isSubmitting, handleChange, status }) => (
<Form>
<div className="form-group">
<label htmlFor="title">Title*</label>
<Field type="text" name="title" className="form-control" />
<Field
type="text"
name="title"
className="form-control"
onChange={handleTitleChange(handleChange)}
/>
<ErrorMessage name="title" component={FormError} />
</div>
<div className="form-group">
<label htmlFor="name">URL*</label>
<Field type="text" name="name" className="form-control" />
<ErrorMessage name="name" component="div" />
</div>
<div className="form-group">
<label htmlFor="starter">Starter*</label>
<Field
Expand Down
3 changes: 3 additions & 0 deletions static/js/pages/SiteCreationPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ describe("SiteCreationPage", () => {
onSubmit(
{
title: "My Title",
name: "my-title",
starter: 1
},
// @ts-ignore
Expand Down Expand Up @@ -122,6 +123,7 @@ describe("SiteCreationPage", () => {
onSubmit(
{
title: errorMsg,
name: "error-msg",
starter: 1
},
// @ts-ignore
Expand All @@ -131,6 +133,7 @@ describe("SiteCreationPage", () => {
sinon.assert.calledOnce(createWebsiteStub)
sinon.assert.calledOnceWithExactly(formikStubs.setErrors, {
...errorResp.errors,
name: undefined,
starter: undefined
})
sinon.assert.notCalled(historyPushStub)
Expand Down
5 changes: 3 additions & 2 deletions static/js/pages/SiteCreationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default function SiteCreationPage({
}
const response = await createWebsite({
title: values.title,
name: values.name,
starter: values.starter
})
if (!response) {
Expand All @@ -52,8 +53,8 @@ export default function SiteCreationPage({
setStatus(errors)
} else {
setErrors({
// Name is autogenerated, so if any errors come back for the "name" property, attach them to the title field
title: errors.title || errors.name,
title: errors.title,
name: errors.name,
starter: errors.starter
})
}
Expand Down
1 change: 1 addition & 0 deletions static/js/types/websites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export interface WebsiteStarter {

export interface NewWebsitePayload {
title: string
name: string
starter: number
}

Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9929,6 +9929,11 @@ slice-ansi@^4.0.0:
astral-regex "^2.0.0"
is-fullwidth-code-point "^3.0.0"

slugify@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.5.0.tgz#5f3c8e2a84105b54eb51486db1b468a599b3c9b8"
integrity sha512-Q2UPZ2udzquy1ElHfOLILMBMqBEXkiD3wE75qtBvV+FsDdZZjUqPZ44vqLTejAVq+wLLHacOMcENnP8+ZbzmIA==

snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
Expand Down

0 comments on commit 9553f09

Please sign in to comment.