Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 44 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"react": "^18.2.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ New dependency react-final-form@^7.0.0 - verify no duplicate final-form peer dependency in bundle.

"react-datepicker": "^8.4.0",
"react-dom": "^18.2.0",
"react-final-form": "^7.0.0",
"recoil": "^0.7.7",
"webpack-merge": "^6.0.1"
},
Expand Down
56 changes: 35 additions & 21 deletions src/Components/CryptoCurrencyNetworks.res
Original file line number Diff line number Diff line change
@@ -1,40 +1,54 @@
open SuperpositionTypes

@react.component
let make = () => {
open DropdownField
let currencyVal = Recoil.useRecoilValueFromAtom(RecoilAtoms.userCurrency)
let make = (~networkField: fieldConfig, ~currencyField: fieldConfig) => {
let networkPath = networkField.confirmRequestWritePath
let currencyFieldPath = currencyField.confirmRequestWritePath
let {config, localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)
let (cryptoCurrencyNetworks, setCryptoCurrencyNetworks) = Recoil.useRecoilState(
RecoilAtoms.cryptoCurrencyNetworks,
let {label} = DynamicFieldsUtils.resolveFieldTexts(
~field=networkField,
~localeObject=localeString,
)
let validate = DynamicFieldsUtils.resolveValidator(
~field=networkField,
~localeObject=localeString,
)

let currencyFieldProps = ReactFinalForm.useField(currencyFieldPath)
let currencyVal = currencyFieldProps.input.value->Option.getOr("")

let dropdownOptions =
Utils.currencyNetworksDict
->Dict.get(currencyVal)
->Option.getOr([])
->Array.map(item => {
label: Utils.toSpacedUpperCase(~str=item, ~delimiter="_"),
value: item,
->Array.map((item): DropdownField.optionType => {
{
label: Utils.toSpacedUpperCase(~str=item, ~delimiter="_"),
value: item,
}
})

let initialValue = (
dropdownOptions
->Array.get(0)
->Option.getOr({
label: "",
value: "",
})
).value
let initialNetwork = dropdownOptions->Array.get(0)->Option.map(opt => opt.value)->Option.getOr("")

let field = ReactFinalForm.useField(
networkPath,
~config={validate, initialValue: Some(initialNetwork)},
)

React.useEffect(() => {
setCryptoCurrencyNetworks(_ => initialValue)
if initialNetwork !== "" {
field.input.onChange(initialNetwork)
}
None
}, [initialValue])
}, [initialNetwork])

let value = field.input.value->Option.getOr(initialNetwork)

<DropdownField
appearance=config.appearance
fieldName=localeString.currencyNetwork
value=cryptoCurrencyNetworks
setValue=setCryptoCurrencyNetworks
fieldName={label}
value
setValue={setter => field.input.onChange(setter(value))}
disabled=false
options=dropdownOptions
/>
Expand Down
129 changes: 129 additions & 0 deletions src/Components/DynamicFieldInput.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
open SuperpositionTypes

// Groups fields by layoutRowId.
// Fields with no layoutRowId each form their own singleton row.
let groupFieldsByRow = (fields: array<fieldConfig>): array<array<fieldConfig>> => {
let rows: array<array<fieldConfig>> = []
let rowMap: Dict.t<array<fieldConfig>> = Dict.make()

fields->Array.forEach(field => {
switch field.layoutRowId {
| None => rows->Array.push([field])
| Some(rowId) =>
switch rowMap->Dict.get(rowId) {
| Some(row) => row->Array.push(field)
| None =>
let row = [field]
rowMap->Dict.set(rowId, row)
rows->Array.push(row)
}
}
})

rows
}

// Renders a single fieldConfig entry as a RFF-connected input.
let renderSingleField = (
field: fieldConfig,
~allFields: array<fieldConfig>,
~globalEmailFields: option<array<fieldConfig>>=?,
~globalCardHolderNameFields: option<array<fieldConfig>>=?,
) => {
switch field.fieldRenderType {
| CardNumber
| Cvc
| CardExpiryMonth
| CardExpiryYear
| CardNetwork => React.null

| Email =>
let allEmailFields = globalEmailFields->Option.getOr([])
let firstEmailPath = allEmailFields->Array.get(0)->Option.map(f => f.confirmRequestWritePath)
<RenderIf condition={firstEmailPath === Some(field.confirmRequestWritePath)}>
<EmailField fields=allEmailFields />
</RenderIf>

| CardHolderName =>
let allCardHolderNameFields = switch globalCardHolderNameFields {
| Some(nameFields) => nameFields
| None => []
}
let firstCardHolderNamePath =
allCardHolderNameFields->Array.get(0)->Option.map(field => field.confirmRequestWritePath)
<RenderIf condition={firstCardHolderNamePath === Some(field.confirmRequestWritePath)}>
<CardHolderNameField fields=allCardHolderNameFields />
</RenderIf>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

render a single component here and move the rendering logic inside the react component

| CardHolderName => <CardHolderNameField ... />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do same for all other cases


| Date
| DateOfBirth =>
<DateOfBirth fieldConfig=field />

| Phone => <PhoneField fieldConfig=field />

| PhoneCountryCode => <PhoneCountryCodeDropdownField fieldConfig=field />

| State => <StateDropdownField fieldConfig=field />

| Country =>
let isoCodes = field.dropdownOptions->Option.getOr([])
let options =
isoCodes
->Utils.isoOptionsToCountryNames
->DropdownField.updateArrayOfStringToOptionsTypeArray
<RenderIf condition={options->Array.length > 0}>
<CountryDropdownField fieldConfig=field options />
</RenderIf>

| CryptoNetwork =>
switch DynamicFieldsUtils.findCryptoCurrencyField(~allFields) {
| None => React.null
| Some(currencyField) => <CryptoCurrencyNetworks networkField=field currencyField />
}

| CryptoCurrency
| Dropdown =>
let options =
field.dropdownOptions->Option.getOr([])->DropdownField.updateArrayOfStringToOptionsTypeArray
<RenderIf condition={options->Array.length > 0}>
<GenericDropdownField fieldConfig=field options />
</RenderIf>

| FirstName
| LastName
| Generic =>
<GenericInputField fieldConfig=field />
}
}

// Renders a row of fields side-by-side using flex layout.
@react.component
let makeRow = (
~items: array<fieldConfig>,
~allFields: array<fieldConfig>,
~globalEmailFields: option<array<fieldConfig>>=?,
~globalCardHolderNameFields: option<array<fieldConfig>>=?,
) => {
switch items->Array.length {
| 0 => React.null
| 1 =>
switch items->Array.get(0) {
| None => React.null
| Some(field) =>
renderSingleField(field, ~allFields, ~globalEmailFields?, ~globalCardHolderNameFields?)
}
| _ =>
<div className="flex gap-4 w-full">
{items
->Array.mapWithIndex((field, i) => {
let flex = field.layoutWidthRatio->Option.getOr(1.0)
<div
key={field.confirmRequestWritePath ++ "-" ++ i->Int.toString}
style={flexGrow: flex->Float.toString, flexShrink: "1", flexBasis: "0%"}>
{renderSingleField(field, ~allFields, ~globalEmailFields?, ~globalCardHolderNameFields?)}
</div>
})
->React.array}
</div>
}
}
Loading
Loading