Skip to content

Commit

Permalink
refactor: reorg replacements to reflect form file hierarchy
Browse files Browse the repository at this point in the history
LoneRifle committed Mar 7, 2024
1 parent c33c6d1 commit ecb1a4d
Showing 18 changed files with 1,778 additions and 109 deletions.
14 changes: 2 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -29,18 +29,8 @@ jobs:
run: mv demos/* .
- name: Replace files with demo-specific ones
run: |
mv replacements/GovtMasthead/* frontend/src/components/GovtMasthead
mv replacements/FormLogo/* frontend/src/features/public-form/components/FormLogo
mv replacements/create/* frontend/src/features/admin-form/create
mv replacements/DesignDrawer/* frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/DesignDrawer
mv replacements/EditMobile/* frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditMobile
mv replacements/locales/* frontend/src/i18n/locales
mv replacements/Home/* frontend/src/pages/Landing/Home
mv replacements/login/* frontend/src/features/login/components
mv replacements/public-form/* frontend/src/features/public-form
mv replacements/express/* src/app/loaders/express
mv replacements/utils/* src/app/utils
mv replacements/field/* shared/types/field
cp -rf replacements/* .
rm -rf replacements
- name: Substitute index.html OG params (delivered by Fly's proxy)
run: |
97 changes: 0 additions & 97 deletions replacements/field/base.ts

This file was deleted.

File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { memo, useMemo } from 'react'

import {
BasicField,
FieldCreateDto,
MyInfoAttribute,
} from '~shared/types/field'

import {
BASICFIELD_TO_DRAWER_META,
MYINFO_FIELD_TO_DRAWER_META,
} from '~features/admin-form/create/constants'
import { isMyInfo } from '~features/myinfo/utils'
import { useUser } from '~features/user/queries'

import { useBuilderFields } from '../../BuilderAndDesignContent/useBuilderFields'
import {
FieldBuilderState,
stateDataSelector,
useFieldBuilderStore,
} from '../../useFieldBuilderStore'
import { BuilderDrawerContainer } from '../common/BuilderDrawerContainer'

import {
ChildrenCompoundFieldMyInfo,
EditMyInfoChildren,
} from './edit-fieldtype/EditMyInfoChildren'
import {
EditAttachment,
EditCheckbox,
EditCountryRegion,
EditDate,
EditDecimal,
EditDropdown,
EditEmail,
EditHeader,
EditHomeno,
EditImage,
EditLongText,
EditMobile,
EditMyInfo,
EditNric,
EditNumber,
EditParagraph,
EditRadio,
EditRating,
EditShortText,
EditTable,
EditUen,
EditYesNo,
} from './edit-fieldtype'

export const EditFieldDrawer = (): JSX.Element | null => {
const stateData = useFieldBuilderStore(stateDataSelector)

const fieldToEdit: FieldCreateDto | undefined = useMemo(() => {
if (
stateData.state === FieldBuilderState.EditingField ||
stateData.state === FieldBuilderState.CreatingField
) {
return stateData.field
}
}, [stateData])

const basicFieldText = useMemo(() => {
if (!fieldToEdit?.fieldType) return ''
if (isMyInfo(fieldToEdit)) {
return MYINFO_FIELD_TO_DRAWER_META[fieldToEdit.myInfo.attr].label
}
return BASICFIELD_TO_DRAWER_META[fieldToEdit?.fieldType].label
}, [fieldToEdit])

// Hacky method of determining when to rerender the drawer,
// i.e. when the user clicks into a different field.
// We pass `${fieldIndex}-${numFields}` as the key. If the
// user was creating a new field but clicked into an existing
// field, causing the new field to be discarded, then numFields
// changes. If the user was editing an existing field then clicked
// into another existing field, causing the edits to be discarded,
// then fieldIndex changes.
const { builderFields } = useBuilderFields()
const fieldIndex = useMemo(() => {
if (stateData.state === FieldBuilderState.CreatingField) {
return stateData.insertionIndex
} else if (stateData.state === FieldBuilderState.EditingField) {
return builderFields?.findIndex(
(field) => field._id === stateData.field._id,
)
}
}, [builderFields, stateData])
const numFields = useMemo(() => builderFields?.length, [builderFields])

if (!fieldToEdit) return null

return (
<BuilderDrawerContainer title={basicFieldText}>
<MemoFieldDrawerContent
field={fieldToEdit}
key={`${fieldIndex}-${numFields}`}
/>
</BuilderDrawerContainer>
)
}

interface MemoFieldDrawerContentProps {
field: FieldCreateDto
}

export const MemoFieldDrawerContent = memo<MemoFieldDrawerContentProps>(
({ field, ...props }) => {
const { user } = useUser()
if (isMyInfo(field)) {
if (
field?.myInfo?.attr === MyInfoAttribute.ChildrenBirthRecords &&
user?.betaFlags?.children
) {
return (
<EditMyInfoChildren
{...props}
field={field as ChildrenCompoundFieldMyInfo}
/>
)
}
return <EditMyInfo {...props} field={field} />
}

switch (field.fieldType) {
case BasicField.Attachment:
return <EditAttachment {...props} field={field} />
case BasicField.Checkbox:
return <EditCheckbox {...props} field={field} />
case BasicField.Dropdown:
return <EditDropdown {...props} field={field} />
case BasicField.CountryRegion:
return <EditCountryRegion {...props} field={field} />
case BasicField.Mobile:
return <EditMobile {...props} field={field} />
case BasicField.HomeNo:
return <EditHomeno {...props} field={field} />
case BasicField.Email:
return <EditEmail {...props} field={field} />
case BasicField.Nric:
return <EditNric {...props} field={field} />
case BasicField.Number:
return <EditNumber {...props} field={field} />
case BasicField.Date:
return <EditDate {...props} field={field} />
case BasicField.Decimal:
return <EditDecimal {...props} field={field} />
case BasicField.Section:
return <EditHeader {...props} field={field} />
case BasicField.Uen:
return <EditUen {...props} field={field} />
case BasicField.YesNo:
return <EditYesNo {...props} field={field} />
case BasicField.Radio:
return <EditRadio {...props} field={field} />
case BasicField.Rating:
return <EditRating {...props} field={field} />
case BasicField.ShortText:
return <EditShortText {...props} field={field} />
case BasicField.Table:
return <EditTable {...props} field={field} />
case BasicField.LongText:
return <EditLongText {...props} field={field} />
case BasicField.Statement:
return <EditParagraph {...props} field={field} />
// case BasicField.Image:
// return <EditImage {...props} field={field} />
default:
return <div>TODO: Insert field options here</div>
}
},
)
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import {
BasicField,
ChildrenCompoundFieldBase,
DateFieldBase,
DropdownFieldBase,
MobileFieldBase,
MyInfoAttribute,
MyInfoChildAttributes,
ShortTextFieldBase,
} from '~shared/types/field'

import { MyInfoFieldMeta } from '~features/myinfo/types'

import { MYINFO_FIELD_TO_DRAWER_META } from '../constants'

export const BASIC_FIELDS_ORDERED = [
BasicField.ShortText,
BasicField.LongText,
BasicField.Radio,
BasicField.Checkbox,
BasicField.Dropdown,
BasicField.CountryRegion,
BasicField.Section,
BasicField.Statement,
BasicField.YesNo,
BasicField.Rating,
BasicField.Email,
BasicField.Mobile,
BasicField.HomeNo,
BasicField.Date,
// BasicField.Image,
BasicField.Table,
BasicField.Attachment,
BasicField.Number,
BasicField.Decimal,
BasicField.Nric,
BasicField.Uen,
]

export const MYINFO_FIELDS_ORDERED: MyInfoAttribute[] = [
// Personal section
MyInfoAttribute.Name,
MyInfoAttribute.Sex,
MyInfoAttribute.DateOfBirth,
MyInfoAttribute.Race,
MyInfoAttribute.Nationality,
MyInfoAttribute.BirthCountry,
MyInfoAttribute.ResidentialStatus,
MyInfoAttribute.Dialect,
MyInfoAttribute.HousingType,
MyInfoAttribute.HdbType,
MyInfoAttribute.PassportNumber,
MyInfoAttribute.PassportExpiryDate,
MyInfoAttribute.VehicleNo,
// Contact section
MyInfoAttribute.RegisteredAddress,
MyInfoAttribute.MobileNo,
// Particulars section
MyInfoAttribute.Occupation,
MyInfoAttribute.Employment,
MyInfoAttribute.WorkpassStatus,
MyInfoAttribute.WorkpassExpiryDate,
// Family (Marriage) section
MyInfoAttribute.Marital,
MyInfoAttribute.CountryOfMarriage,
MyInfoAttribute.MarriageCertNo,
MyInfoAttribute.MarriageDate,
MyInfoAttribute.DivorceDate,
// Children section
MyInfoAttribute.ChildrenBirthRecords,
]

export const MYINFO_TEXTFIELD_META: MyInfoFieldMeta<ShortTextFieldBase> = {
ValidationOptions: {
selectedValidation: null,
customVal: null,
},
}

export const MYINFO_DROPDOWNFIELD_META: MyInfoFieldMeta<DropdownFieldBase> = {
fieldOptions: [],
}
export const MYINFO_MOBILEFIELD_META: MyInfoFieldMeta<MobileFieldBase> = {
allowIntlNumbers: false,
isVerifiable: false,
}

export const MYINFO_DATEFIELD_META: MyInfoFieldMeta<DateFieldBase> = {
dateValidation: {
customMaxDate: null,
customMinDate: null,
selectedDateValidation: null,
},
}

export const MYINFO_CHILDRENFIELD_META: MyInfoFieldMeta<ChildrenCompoundFieldBase> =
{
childrenSubFields: [MyInfoChildAttributes.ChildName],
allowMultiple: false,
}

export const CREATE_MYINFO_PERSONAL_FIELDS_ORDERED =
MYINFO_FIELDS_ORDERED.slice(0, 13)

export const CREATE_MYINFO_CONTACT_FIELDS_ORDERED = MYINFO_FIELDS_ORDERED.slice(
13,
15,
)

export const CREATE_MYINFO_PARTICULARS_FIELDS_ORDERED =
MYINFO_FIELDS_ORDERED.slice(15, 19)

export const CREATE_MYINFO_MARRIAGE_FIELDS_ORDERED =
MYINFO_FIELDS_ORDERED.slice(19, 24)

export const CREATE_MYINFO_CHILDREN_FIELDS_ORDERED =
MYINFO_FIELDS_ORDERED.slice(24, 25)

export const CREATE_FIELD_DROP_ID = 'create-fields-field'

export const CREATE_MYINFO_PERSONAL_DROP_ID = 'create-myinfo-personal'

export const CREATE_MYINFO_CONTACT_DROP_ID = 'create-myinfo-drop'

export const CREATE_MYINFO_PARTICULARS_DROP_ID = 'create-myinfo-particulars'

export const CREATE_MYINFO_MARRIAGE_DROP_ID = 'create-myinfo-marriage'

export const CREATE_MYINFO_CHILDREN_DROP_ID = 'create-myinfo-children'

export const FIELD_LIST_DROP_ID = 'formFieldList'
export const PENDING_CREATE_FIELD_ID = 'FIELD-PENDING-CREATION'

export enum FieldListTabIndex {
Basic = 0,
MyInfo,
Payments,
}

export const CREATE_MYINFO_CHILDREN_SUBFIELDS_OPTIONS: {
value: MyInfoChildAttributes
label: string
}[] = Object.values(MyInfoChildAttributes)
.filter((e) => e !== MyInfoChildAttributes.ChildName)
.map((value) => {
return {
value,
label: MYINFO_FIELD_TO_DRAWER_META[value].label,
}
})
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
148 changes: 148 additions & 0 deletions replacements/shared/constants/field/basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { BasicField } from '../../types/field'

type BasicFieldBlock = {
/** Type of field */
name: BasicField
/** Default name of field */
value: string
/** Whether field is to be submittable */
submitted: boolean
/** Whether field is multi-answer */
answerArray: boolean
}

export const types: BasicFieldBlock[] = [
{
name: BasicField.Section,
value: 'Header',
submitted: true,
answerArray: false,
},
{
name: BasicField.Statement,
value: 'Statement',
submitted: false,
answerArray: false,
},
{
name: BasicField.Email,
value: 'Email',
submitted: true,
answerArray: false,
},
{
name: BasicField.Mobile,
value: 'Mobile Number',
submitted: true,
answerArray: false,
},
{
name: BasicField.HomeNo,
value: 'Home Number',
submitted: true,
answerArray: false,
},
{
name: BasicField.Number,
value: 'Number',
submitted: true,
answerArray: false,
},
{
name: BasicField.Decimal,
value: 'Decimal',
submitted: true,
answerArray: false,
},
// {
// name: BasicField.Image,
// value: 'Image',
// submitted: false,
// answerArray: false,
// },
{
name: BasicField.ShortText,
value: 'Short Text',
submitted: true,
answerArray: false,
},
{
name: BasicField.LongText,
value: 'Long Text',
submitted: true,
answerArray: false,
},
{
name: BasicField.Dropdown,
value: 'Dropdown',
submitted: true,
answerArray: false,
},
{
name: BasicField.CountryRegion,
value: 'Country/Region',
submitted: true,
answerArray: false,
},
{
name: BasicField.YesNo,
value: 'Yes/No',
submitted: true,
answerArray: false,
},
{
name: BasicField.Checkbox,
value: 'Checkbox',
submitted: true,
answerArray: true,
},
{
name: BasicField.Radio,
value: 'Radio',
submitted: true,
answerArray: false,
},
{
name: BasicField.Attachment,
value: 'Attachment',
submitted: true,
answerArray: false,
},
{
name: BasicField.Date,
value: 'Date',
submitted: true,
answerArray: false,
},
{
name: BasicField.Rating,
value: 'Rating',
submitted: true,
answerArray: false,
},
{
name: BasicField.Nric,
value: 'NRIC',
submitted: true,
answerArray: false,
},
{
name: BasicField.Uen,
value: 'UEN',
submitted: true,
answerArray: false,
},
{
name: BasicField.Table,
value: 'Table',
submitted: true,
answerArray: true,
},
]

/**
* Array of BasicFields which are not included in the form response (e.g. statement)
*/
export const FIELDS_TO_REJECT: BasicField[] = types
.filter((f) => !f.submitted)
.map((f) => f.name)
File renamed without changes.
1,304 changes: 1,304 additions & 0 deletions replacements/src/app/models/form.server.model.ts

Large diffs are not rendered by default.

File renamed without changes.

0 comments on commit ecb1a4d

Please sign in to comment.