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

Feat/contact us page 2 #266

Merged
merged 40 commits into from
Dec 3, 2020
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
94a8624
fix: suppresses dropdown for Contact Us Folder Card dropdown options
gweiying Nov 26, 2020
9d9e41c
fix: removes hardcoded sectionId, passing sectionId as argument
gweiying Nov 26, 2020
edb5a7d
fix: updates displaySections to use locations, contacts as key values…
gweiying Nov 26, 2020
b1ece5b
fix: adds check if frontMatter.contacts or frontMatter.locations arra…
gweiying Nov 26, 2020
6388d58
fix: updates templates to use forwarded react references
gweiying Nov 26, 2020
66925f5
fix: updates scrollRefs to use React.createRef() and forward referenc…
gweiying Nov 26, 2020
c3b67eb
fix: fixes error in operatingHours validation, adds case for validati…
gweiying Nov 26, 2020
52d8b08
fix: clean up comments, whitespace
gweiying Nov 26, 2020
334d480
fix: checks whether content has been edited and shows navigate away w…
gweiying Nov 27, 2020
e0e96ab
fix: uses deep cloning to sanitise frontMatter
gweiying Nov 27, 2020
67a9b26
fix: sets background color for contactUs edit preview
gweiying Nov 27, 2020
067918b
fix: buffs up email validation
gweiying Nov 30, 2020
8ead0dd
fix: add packages for DOMPurify
gweiying Nov 30, 2020
e6eb0a9
fix: uses DOMPurify to prevent XSS scripts from rendering on Contacts…
gweiying Nov 30, 2020
294c4f4
fix: fixes paragraph stylistic formatting on Contacts description
gweiying Nov 30, 2020
98de2db
fix: fixes form field width for operating hours to not resize with er…
gweiying Nov 30, 2020
c2ec452
fix: resolves stylistic differences in links and span text
gweiying Nov 30, 2020
05c5e8b
fix: adds parent style around links in ContactSection Templates
gweiying Nov 30, 2020
4ce8529
fix: cleans up scrollIntoView
gweiying Nov 30, 2020
826cfb9
fix: adds key to dropdown options to resolve unique id warning
gweiying Nov 30, 2020
74d88c4
install: adds packages for react-input-mask
gweiying Nov 30, 2020
9566f14
feat: creates InputMaskFormField using react-input-mask for FormField…
gweiying Nov 30, 2020
71f9c81
feat: adds state hook to Contact Fields to support masked input styli…
gweiying Nov 30, 2020
5ca9353
fix: simplifies validation for Contact Fields phone number as masked …
gweiying Nov 30, 2020
4b648f0
fix: rectifies relative imports
gweiying Nov 30, 2020
92b301f
fix: cleans up warning errors in validation
gweiying Nov 30, 2020
340b296
fix: fix initialized state in state hook
gweiying Nov 30, 2020
3a18fc0
fix: filters dropdown before mapping to remove arrow function warning
gweiying Nov 30, 2020
1c0f79f
fix: sets font size for error and info messages since span has been s…
gweiying Dec 1, 2020
fd8e191
fix: uses info message style for notes
gweiying Dec 1, 2020
7399708
fix: removes extraneous terms from automated url generation and sets …
gweiying Dec 1, 2020
f35a46e
fix: adds Delete modal for each Location and Contact
gweiying Dec 1, 2020
61c16ea
feat: add styling for error cards
gweiying Dec 1, 2020
861a98d
feat: uses red border to highlight sections and cards that contain er…
gweiying Dec 1, 2020
68f5fa6
fix: fix title overflow bug
gweiying Dec 1, 2020
1abcf75
fix: removes default value if user does not select phone number field
gweiying Dec 1, 2020
4259037
fix: clean up dataSanitisers and add initial values for maps_links an…
gweiying Dec 1, 2020
8bb240c
fix: removes min length for title
gweiying Dec 1, 2020
eb4b82c
fix: sets min length of titles to 1
gweiying Dec 2, 2020
cac774b
fix: change Add button to singular form instead of plural as in Conta…
gweiying Dec 2, 2020
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
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"bootstrap": "^4.3.1",
"cheerio": "^1.0.0-rc.3",
"csp-parse": "0.0.2",
"dompurify": "^2.2.2",
"easymde": "^2.8.0",
"escape-string-regexp": "^4.0.0",
"immutability-helper": "^3.0.1",
Expand All @@ -22,6 +23,7 @@
"react-beautiful-dnd": "^12.0.0",
"react-color": "^2.17.3",
"react-dom": "^16.10.2",
"react-input-mask": "^2.0.4",
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.0",
"react-select": "^3.1.0",
Expand Down
10 changes: 5 additions & 5 deletions src/components/Dropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ const Dropdown = ({
onChange={onFieldChange}
>
{ defaultOption &&
<option value={ emptyDefault ? '' : slugifyLower(defaultOption) }>{ defaultOption }</option>
<option value={ emptyDefault ? '' : slugifyLower(defaultOption) } key={slugifyLower(defaultOption)}>{ defaultOption }</option>
}
{ options
.filter((option) => option !== defaultOption)
.map((option) => ( <option value={ slugifyLower(option) } key={slugifyLower(option)}>{ option }</option> ))
}
{ options.map((option) => {
if (option === defaultOption) return // skip option if already included in default option
return <option value={ slugifyLower(option) }>{ option }</option>
})}
</select>
</>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/FolderCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const FolderCard = ({
<i className={`bx bx-md text-dark ${generateImage(pageType)} ${contentStyles.componentIcon}`} />
<span className={`${contentStyles.componentFolderName} align-self-center ml-4 mr-auto`}>{displayText}</span>
{
pageType === 'homepage'
pageType === 'homepage' || pageType === 'contact-us'
? ''
: (
<div className={`position-relative`}>
Expand Down
61 changes: 61 additions & 0 deletions src/components/InputMaskFormField.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import PropTypes from 'prop-types';
import elementStyles from '../styles/isomer-cms/Elements.module.scss';
import InputMask from 'react-input-mask';

const InputMaskFormField = ({
title,
value,
mask,
maskChar,
alwaysShowMask,
id,
hasError,
errorMessage,
onFieldChange,
style,
disabled,
fixedMessage,
maxWidth,
}) => (
<>
{ title && <label className={elementStyles.formLabel}>{title}</label> }
<div className={`d-flex text-nowrap ${maxWidth ? 'w-100' : ''}`}>
{ fixedMessage && <p className={elementStyles.formFixedText}>{fixedMessage}</p> }
<InputMask
mask={mask}
maskChar={maskChar}
alwaysShowMask={alwaysShowMask}
id={id}
value={value}
style={style}
onChange={onFieldChange}
className={hasError || errorMessage ? `${elementStyles.error}` : null}
disabled={disabled}
/>
</div>
{ errorMessage && <span className={elementStyles.error}>{errorMessage}</span> }
</>
);

export default InputMaskFormField;

InputMaskFormField.propTypes = {
title: PropTypes.string,
value: PropTypes.string.isRequired,
mask: PropTypes.string.isRequired,
maskChar: PropTypes.string,
alwaysShowMask: PropTypes.bool,
id: PropTypes.string.isRequired,
hasError: PropTypes.bool,
errorMessage: PropTypes.string,
onFieldChange: PropTypes.func.isRequired,
isRequired: PropTypes.bool,
style: PropTypes.string,
maxWidth: PropTypes.bool,
};

InputMaskFormField.defaultProps = {
style: undefined,
errorMessage: null,
};
16 changes: 10 additions & 6 deletions src/components/contact-us/ContactCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import elementStyles from '../../styles/isomer-cms/Elements.module.scss';
import FormField from '../FormField';
import ContactFields from './ContactFields';
import { isEmpty } from '../../utils';

/* eslint
react/no-array-index-key: 0
Expand All @@ -17,15 +18,16 @@ const EditorContactCard = ({
shouldDisplay,
displayHandler,
cardErrors,
sectionId,
}) => {
return (
<div className={`${elementStyles.card} move`}>
<div className={`${elementStyles.card} ${!shouldDisplay && !isEmpty(cardErrors) ? elementStyles.error : ''} move`}>
<div className={elementStyles.cardHeader}>
<h2>
{title}
</h2>
<button type="button" id={`contact-${cardIndex}`} onClick={displayHandler}>
<i className={`bx ${shouldDisplay ? 'bx-chevron-down' : 'bx-chevron-right'}`} id={`contact-${cardIndex}-icon`} />
<button type="button" id={`${sectionId}-${cardIndex}`} onClick={displayHandler}>
<i className={`bx ${shouldDisplay ? 'bx-chevron-down' : 'bx-chevron-right'}`} id={`${sectionId}-${cardIndex}-icon`} />
</button>
</div>
{ shouldDisplay
Expand All @@ -34,7 +36,7 @@ const EditorContactCard = ({
<div className={elementStyles.cardContent}>
<FormField
title="Title"
id={`contact-${cardIndex}-title`}
id={`${sectionId}-${cardIndex}-title`}
value={title}
onFieldChange={onFieldChange}
errorMessage={cardErrors.title}
Expand All @@ -44,10 +46,11 @@ const EditorContactCard = ({
content={content}
onFieldChange={onFieldChange}
errors={cardErrors.content}
sectionId={sectionId}
/>
</div>
<div className={`${elementStyles.inputGroup} pt-5`}>
<button type="button" id={`contact-${cardIndex}`} className={`btn-block ${elementStyles.warning}`} onClick={deleteHandler}>Delete section</button>
<button type="button" id={`${sectionId}-${cardIndex}`} className={`btn-block ${elementStyles.warning}`} onClick={deleteHandler}>Delete section</button>
</div>
</>
)
Expand Down Expand Up @@ -88,5 +91,6 @@ EditorContactCard.propTypes = {
other: PropTypes.string,
}),
),
})
}),
sectionId: PropTypes.string,
};
26 changes: 21 additions & 5 deletions src/components/contact-us/ContactFields.jsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,47 @@
import React from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import FormField from '../FormField';
import InputMaskFormField from '../InputMaskFormField';
import Dropdown from '../Dropdown';
import _ from 'lodash';

const ContactFields = ({
cardIndex,
content,
onFieldChange,
errors,
sectionId,
}) => {
const [phoneFieldType, setPhoneFieldType] = useState(content[0].phone[0] === '1' ? 'tollfree' : 'local')

return (
<div className={`d-flex flex-column`}>
<FormField
<InputMaskFormField
title="Phone"
id={`contact-${cardIndex}-phone-0`}
mask={phoneFieldType === 'local' ? '+65 9999 9999': '1 800 999 9999'}
maskChar="_"
alwaysShowMask={false}
id={`${sectionId}-${cardIndex}-phone-0`}
value={content[0].phone}
onFieldChange={onFieldChange}
errorMessage={errors[0].phone}
/>
<Dropdown
options={["Local", "Tollfree"]}
defaultOption={_.upperFirst(phoneFieldType)}
id={"phone-field-type"}
onFieldChange={e => setPhoneFieldType(e.target.value)}
/>
<FormField
title="Email"
id={`contact-${cardIndex}-email-1`}
id={`${sectionId}-${cardIndex}-email-1`}
value={content[1].email}
onFieldChange={onFieldChange}
errorMessage={errors[1].email}
/>
<FormField
title="Others"
id={`contact-${cardIndex}-other-2`}
id={`${sectionId}-${cardIndex}-other-2`}
value={content[2].other}
onFieldChange={onFieldChange}
errorMessage={errors[2].other}
Expand Down Expand Up @@ -62,4 +77,5 @@ ContactFields.propTypes = {
other: PropTypes.string,
}),
),
sectionId: PropTypes.string,
};
23 changes: 16 additions & 7 deletions src/components/contact-us/LocationCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
import elementStyles from '../../styles/isomer-cms/Elements.module.scss';
import FormField from '../FormField';
import { LocationHoursFields, LocationAddressFields } from './LocationFields'
import { isEmpty } from '../../utils';

/* eslint
react/no-array-index-key: 0
*/
Expand All @@ -18,14 +20,15 @@ const EditorLocationSection = ({
shouldDisplay,
displayHandler,
cardErrors,
sectionId,
}) => (
<div className={`${elementStyles.card} move`}>
<div className={`${elementStyles.card} ${!shouldDisplay && !isEmpty(cardErrors) ? elementStyles.error : ''} move`}>
<div className={elementStyles.cardHeader}>
<h2>
{title}
</h2>
<button type="button" id={`location-${cardIndex}`} onClick={displayHandler}>
<i className={`bx ${shouldDisplay ? 'bx-chevron-down' : 'bx-chevron-right'}`} id={`location-${cardIndex}-icon`} />
<button type="button" id={`${sectionId}-${cardIndex}`} onClick={displayHandler}>
<i className={`bx ${shouldDisplay ? 'bx-chevron-down' : 'bx-chevron-right'}`} id={`${sectionId}-${cardIndex}-icon`} />
</button>
</div>
{ shouldDisplay
Expand All @@ -34,7 +37,7 @@ const EditorLocationSection = ({
<div className={elementStyles.cardContent}>
<FormField
title="Title"
id={`location-${cardIndex}-title`}
id={`${sectionId}-${cardIndex}-title`}
value={title}
onFieldChange={onFieldChange}
errorMessage={cardErrors.title}
Expand All @@ -45,23 +48,28 @@ const EditorLocationSection = ({
address={address}
onFieldChange={onFieldChange}
errors={cardErrors.address}
sectionId={sectionId}
/>
<FormField
title="Map url"
id={`location-${cardIndex}-maps_link`}
id={`${sectionId}-${cardIndex}-maps_link`}
value={mapUrl}
onFieldChange={onFieldChange}
errorMessage={cardErrors.maps_link}
/>
<span className={elementStyles.info}>
Note: If left blank, map url is automatically generated from Address fields
</span>
<LocationHoursFields
operatingHours={operatingHours}
onFieldChange={onFieldChange}
cardIndex={cardIndex}
errors={cardErrors.operating_hours}
sectionId={sectionId}
/>
</div>
<div className={`${elementStyles.inputGroup} pt-5`}>
<button type="button" id={`location-${cardIndex}`} className={`btn-block ${elementStyles.warning}`} onClick={deleteHandler}>Delete section</button>
<button type="button" id={`${sectionId}-${cardIndex}`} className={`btn-block ${elementStyles.warning}`} onClick={deleteHandler}>Delete section</button>
</div>
</>
)
Expand Down Expand Up @@ -98,5 +106,6 @@ EditorLocationSection.propTypes = {
}),
),
mapUrl: PropTypes.string,
})
}),
sectionId: PropTypes.string,
};
Loading