diff --git a/.changeset/orange-meals-mate.md b/.changeset/orange-meals-mate.md
new file mode 100644
index 000000000..a7811c0e8
--- /dev/null
+++ b/.changeset/orange-meals-mate.md
@@ -0,0 +1,5 @@
+---
+'@hashicorp/react-marketo-form': minor
+---
+
+Add support for htmltext fields
diff --git a/packages/marketo-form/docs.mdx b/packages/marketo-form/docs.mdx
index b89d74c6f..c51005026 100644
--- a/packages/marketo-form/docs.mdx
+++ b/packages/marketo-form/docs.mdx
@@ -158,11 +158,12 @@ Renders a form from Marketo.
},
{
id: "Consent_Privacy_Policy__c",
+ label: "Send me news about HashiCorp products, releases and events.",
dataType: "checkbox",
validationMessage: "This field is required.",
rowNumber: 6,
columnNumber: 0,
- required: true,
+ required: false,
formPrefill: true,
fieldMetaData: {
initiallyChecked: false,
@@ -171,6 +172,17 @@ Renders a form from Marketo.
ruleType: "alwaysShow",
},
},
+ {
+ id: "SHRtbFRleHRfMjAyMy0wNC0wNVQyMjo0NDo0Ny45OTZa",
+ labelWidth: 260,
+ dataType: "htmltext",
+ rowNumber: 9,
+ columnNumber: 0,
+ visibilityRules: {
+ ruleType: "alwaysShow"
+ },
+ text: "By submitting this form, you acknowledge and agree that HashiCorp will process your personal information in accordance with the Privacy Policy."
+ }
],
}}
submitTitle="Download Now"
diff --git a/packages/marketo-form/form/index.tsx b/packages/marketo-form/form/index.tsx
index e6a7ee780..2fc922d9d 100644
--- a/packages/marketo-form/form/index.tsx
+++ b/packages/marketo-form/form/index.tsx
@@ -155,7 +155,7 @@ const Form = ({
let errors: Record = {}
fields.result.forEach((field) => {
- if (field.required) {
+ if ('required' in field && field.required) {
if (
!(field.id in values) ||
values[field.id] === '' ||
diff --git a/packages/marketo-form/partials/field/index.tsx b/packages/marketo-form/partials/field/index.tsx
index 71533b3a2..3233459c6 100644
--- a/packages/marketo-form/partials/field/index.tsx
+++ b/packages/marketo-form/partials/field/index.tsx
@@ -9,8 +9,8 @@ import TelephoneField from '../fields/telephone-field'
import TextareaField from '../fields/textarea-field'
import SelectField from '../fields/select-field'
import CheckboxField from '../fields/checkbox-field'
-import PrivacyPolicyField from '../fields/privacy-policy-field'
import HiddenField from '../fields/hidden-field'
+import HtmltextField from '../fields/htmltext-field'
import FormPageUrlField from '../fields/form-page-url-field'
import type { MarketoFormField, MarketoFormComponents } from '../../types'
@@ -57,9 +57,6 @@ const Field = ({
const Component = components.checkbox!
return
}
- if (field.id === 'Consent_Privacy_Policy__c') {
- return
- }
return
case 'hidden':
if (components && 'hidden' in components) {
@@ -70,6 +67,12 @@ const Field = ({
return
}
return
+ case 'htmltext':
+ if (components && 'htmltext' in components) {
+ const Component = components.htmltext!
+ return
+ }
+ return
default:
console.error(`Unknown form field type: ${(field as any).Datatype}`)
}
diff --git a/packages/marketo-form/partials/fields/htmltext-field/index.tsx b/packages/marketo-form/partials/fields/htmltext-field/index.tsx
new file mode 100644
index 000000000..cbbe80573
--- /dev/null
+++ b/packages/marketo-form/partials/fields/htmltext-field/index.tsx
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import FieldWrapper from '../../field-wrapper'
+import type { MarketoFormHtmltextField } from '../../../types'
+import styles from './style.module.css'
+
+const Index = ({ field }: { field: MarketoFormHtmltextField }) => {
+ return (
+
+
+
+ )
+}
+
+export default Index
diff --git a/packages/marketo-form/partials/fields/htmltext-field/style.module.css b/packages/marketo-form/partials/fields/htmltext-field/style.module.css
new file mode 100644
index 000000000..afd5cda91
--- /dev/null
+++ b/packages/marketo-form/partials/fields/htmltext-field/style.module.css
@@ -0,0 +1,6 @@
+.htmltext {
+ composes: g-type-body-small from global;
+ color: var(--wpl-neutral-500);
+ margin-top: var(--wpl-spacing-02);
+ margin-bottom: var(--wpl-spacing-05);
+}
diff --git a/packages/marketo-form/partials/fields/privacy-policy-field/index.tsx b/packages/marketo-form/partials/fields/privacy-policy-field/index.tsx
deleted file mode 100644
index 56270c5a0..000000000
--- a/packages/marketo-form/partials/fields/privacy-policy-field/index.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: MPL-2.0
- */
-
-import { useContext } from 'react'
-import { useFormContext } from 'react-hook-form'
-import CheckboxInput from '@hashicorp/react-form-fields/checkbox'
-import FieldWrapper from '../../field-wrapper'
-import { FormMetadataContext } from '../../../contexts/FormMetadata'
-import type { MarketoFormCheckboxField } from '../../../types'
-import { useErrorMessage } from '../../../utils'
-import style from './style.module.css'
-
-const LABELS_BY_LANGUAGE = {
- English: (
- <>
- I agree to HashiCorp’s{' '}
-
- Privacy Policy
-
- *
- >
- ),
- French: (
- <>
- J'accepte la{' '}
-
- politique de confidentialité
- {' '}
- d'HashiCorp.*
- >
- ),
- Korean: (
- <>
- HashiCorp의{' '}
-
- 개인정보 처리방침
-
- 에 동의합니다*
- >
- ),
- Japanese: (
- <>
- HashiCorpの
-
- プライバシーポリシー
-
- に同意します。
- *
- >
- ),
- German: (
- <>
- Ich stimme den{' '}
-
- Datenschutzrichtlinien
- {' '}
- von HashiCorp zu.*
- >
- ),
- Spanish: (
- <>
- Estoy de acuerdo con la{' '}
-
- política de privacidad
- {' '}
- de HashiCorp.*
- >
- ),
- 'Portuguese (Brazil)': (
- <>
- Eu concordo com a{' '}
-
- Política de Privacidade
- {' '}
- da HashiCorp.*
- >
- ),
- Italian: (
- <>
- Accetto{' '}
-
- l'informativa sulla privacy
- {' '}
- di HashiCorp.
- *
- >
- ),
-}
-
-const PrivacyPolicyField = ({ field }: { field: MarketoFormCheckboxField }) => {
- const metadata = useContext(FormMetadataContext)
- const { register, watch } = useFormContext()
- const error = useErrorMessage(field.id)
- const checked = watch(field.id, false)
-
- return (
-
-
-
- )
-}
-
-export default PrivacyPolicyField
diff --git a/packages/marketo-form/partials/fields/privacy-policy-field/style.module.css b/packages/marketo-form/partials/fields/privacy-policy-field/style.module.css
deleted file mode 100644
index 1ba0758a3..000000000
--- a/packages/marketo-form/partials/fields/privacy-policy-field/style.module.css
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: MPL-2.0
- */
-
-.required {
- color: #e5242a;
-}
diff --git a/packages/marketo-form/partials/visibility-rule/index.tsx b/packages/marketo-form/partials/visibility-rule/index.tsx
index 1d75f007e..bb5df25a4 100644
--- a/packages/marketo-form/partials/visibility-rule/index.tsx
+++ b/packages/marketo-form/partials/visibility-rule/index.tsx
@@ -6,7 +6,28 @@
import { useMemo } from 'react'
import { useFormContext } from 'react-hook-form'
import Field from '../field'
-import type { MarketoFormField, MarketoFormComponents } from '../../types'
+import type {
+ MarketoFormField,
+ MarketoFormComponents,
+ VisibilityRule as VisibilityRuleType,
+} from '../../types'
+
+function ruleApplies(rule: VisibilityRuleType, value: any): boolean {
+ switch (rule.operator) {
+ case 'is':
+ return (
+ rule.values.includes(value) ||
+ (value === false && rule.values.includes('no')) ||
+ (value === true && rule.values.includes('yes'))
+ )
+ case 'isNot':
+ return !rule.values.includes(value)
+ case 'isEmpty':
+ return value === null || typeof value === 'undefined' || value === ''
+ default:
+ return false
+ }
+}
const FieldWithVisibilityRule = ({
field,
@@ -20,17 +41,26 @@ const FieldWithVisibilityRule = ({
// Currently we only support the first defined rule.
const value = watch(field.visibilityRules!.rules![0].subjectField)
- const show = useMemo(() => {
- const { operator, values } = field.visibilityRules!.rules![0]
- return (
- operator === 'is' &&
- (values.includes(value) ||
- (value === false && values.includes('no')) ||
- (value === true && values.includes('yes')))
+ const hasMatchingRule = useMemo(() => {
+ return field.visibilityRules!.rules!.some((rule) =>
+ ruleApplies(rule, value)
)
}, [field, value])
- return show ? : null
+ if (
+ hasMatchingRule &&
+ (field.visibilityRules!.ruleType === 'show' ||
+ field.visibilityRules!.ruleType === 'hide')
+ ) {
+ return field.visibilityRules!.ruleType === 'show' ? (
+
+ ) : null
+ }
+
+ // If the ruleType is show, that means the field is hidden by default.
+ return field.visibilityRules!.ruleType === 'show' ? null : (
+
+ )
}
const VisibilityRule = ({
@@ -40,7 +70,11 @@ const VisibilityRule = ({
field: MarketoFormField
components?: MarketoFormComponents
}) => {
- if (field.visibilityRules && field.visibilityRules.ruleType === 'show') {
+ if (
+ field.visibilityRules &&
+ (field.visibilityRules.ruleType === 'show' ||
+ field.visibilityRules.ruleType === 'hide')
+ ) {
return
}
diff --git a/packages/marketo-form/server/client.ts b/packages/marketo-form/server/client.ts
index 60a567b6c..282ee1bfc 100644
--- a/packages/marketo-form/server/client.ts
+++ b/packages/marketo-form/server/client.ts
@@ -57,6 +57,37 @@ export async function getForm(formId: number) {
return { fields, metadata }
}
+export async function getDraftFormProps(formId: number) {
+ const { access_token } = await getToken()
+
+ const fieldsResponse = await fetch(
+ `${process.env.MARKETO_ENDPOINT}/asset/v1/form/${formId}/fields.json?status=draft`,
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${access_token}`,
+ },
+ }
+ )
+
+ const metadataResponse = await fetch(
+ `${process.env.MARKETO_ENDPOINT}/asset/v1/form/${formId}.json?status=draft`,
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${access_token}`,
+ },
+ }
+ )
+
+ const [fields, metadata] = await Promise.all([
+ fieldsResponse.json(),
+ metadataResponse.json(),
+ ])
+
+ return { fields, metadata }
+}
+
export async function getFormProps(
id: number
): Promise {
diff --git a/packages/marketo-form/types.ts b/packages/marketo-form/types.ts
index 0a3702961..c358af22e 100644
--- a/packages/marketo-form/types.ts
+++ b/packages/marketo-form/types.ts
@@ -13,6 +13,7 @@ export type MarketoFormDatatype =
| 'select'
| 'checkbox'
| 'hidden'
+ | 'htmltext'
export interface Autofill {
value: string
@@ -22,19 +23,21 @@ export interface Autofill {
export interface VisibilityRule {
subjectField: string
- operator: 'is'
+ operator: 'is' | 'isNot' | 'isEmpty'
values: string[]
altLabel: string
}
export interface VisibilityRules {
rules?: VisibilityRule[]
- ruleType: 'alwaysShow' | 'show'
+ ruleType: 'alwaysShow' | 'show' | 'hide'
}
export interface MarketoBaseFormField {
id: string
dataType: MarketoFormDatatype
+ rowNumber: number
+ columnNumber: number
defaultValue?: string
label?: string
required: boolean
@@ -51,16 +54,19 @@ export interface MarketoFormTextField extends MarketoBaseFormField {
export interface MarketoFormEmailField extends MarketoBaseFormField {
dataType: 'email'
hintText?: string
+ formPrefill: boolean
}
export interface MarketoFormTelephoneField extends MarketoBaseFormField {
dataType: 'telephone'
hintText?: string
+ formPrefill: boolean
}
export interface MarketoFormTextAreaField extends MarketoBaseFormField {
dataType: 'textArea'
hintText?: string
+ formPrefill: boolean
}
export interface SelectValue {
@@ -77,6 +83,7 @@ export interface SelectFieldMetaData {
export interface MarketoFormSelectField extends MarketoBaseFormField {
dataType: 'select'
fieldMetaData: SelectFieldMetaData
+ formPrefill: boolean
}
export interface CheckboxFieldMetaData {
@@ -86,12 +93,23 @@ export interface CheckboxFieldMetaData {
export interface MarketoFormCheckboxField extends MarketoBaseFormField {
dataType: 'checkbox'
fieldMetaData: CheckboxFieldMetaData
+ formPrefill: boolean
}
export interface MarketoFormHiddenField extends MarketoBaseFormField {
dataType: 'hidden'
}
+export interface MarketoFormHtmltextField {
+ id: string
+ labelWidth: number
+ dataType: 'htmltext'
+ rowNumber: number
+ columnNumber: number
+ visibilityRules?: VisibilityRules
+ text: string
+}
+
export type MarketoFormField =
| MarketoFormTextField
| MarketoFormEmailField
@@ -100,6 +118,7 @@ export type MarketoFormField =
| MarketoFormSelectField
| MarketoFormCheckboxField
| MarketoFormHiddenField
+ | MarketoFormHtmltextField
export interface MarketoFormMetadata {
id: number
@@ -116,6 +135,20 @@ export interface MarketoFormMetadata {
labelPosition: string
fontFamily: string
fontSize: string
+ folder?: {
+ type: string
+ value: number
+ folderName: string
+ }
+ knownVisitor?: {
+ type: string
+ template: unknown
+ }
+ thankYouList?: {
+ followupType: string
+ followupValue: string
+ default: boolean
+ }[]
buttonLocation: number
buttonLabel: string
waitingLabel: string
@@ -150,6 +183,7 @@ export interface MarketoFormComponents {
select?: (props: { field: MarketoFormSelectField }) => JSX.Element
checkbox?: (props: { field: MarketoFormCheckboxField }) => JSX.Element
hidden?: (props: { field: MarketoFormHiddenField }) => JSX.Element
+ htmltext?: (props: { field: MarketoFormHtmltextField }) => JSX.Element
}
/**
diff --git a/packages/marketo-form/utils.ts b/packages/marketo-form/utils.ts
index d21f139a3..54bef1304 100644
--- a/packages/marketo-form/utils.ts
+++ b/packages/marketo-form/utils.ts
@@ -100,7 +100,7 @@ export function convertToRESTFields(
// Returns the label for a field.
export function formattedLabel(field: MarketoFormField): string {
- if (field.label) {
+ if ('label' in field && field.label) {
return field.label
}
@@ -162,7 +162,11 @@ export function calculateDefaultValues(
): Record {
const initialValues: Record = {}
fields.forEach((field) => {
- if (field.defaultValue && field.defaultValue !== '') {
+ if (
+ 'defaultValue' in field &&
+ field.defaultValue &&
+ field.defaultValue !== ''
+ ) {
if (field.dataType === 'select') {
// For some reason, the Marketo API returns the value for