@@ -52,15 +52,11 @@ let make = (
5252 -> Option .getOr ("" )
5353 let copy = values -> Dict .copy
5454
55- // Synchronize first_name and last_name to avoid different values during confirm call
56- // Case 1: If last_name exists but first_name is empty, use last_name as first_name
57- // (full name field uses first_name for tracking, so this ensures proper population)
58- if last_name -> String .length == 0 {
59- copy -> Dict .set (BillingAddress (FullName (LastName ))-> getPaymentMethodDataFieldKey , first_name )
60- } // Case 2: If first_name exists but last_name is empty, use first_name as last_name
55+ // If first_name exists but last_name is empty, use first_name as last_name
6156 // (since full name field is not rendered, we need this sync to maintain consistency)
62- else if first_name -> String .length == 0 {
57+ if first_name -> String .length == 0 {
6358 copy -> Dict .set (BillingAddress (FullName (FirstName ))-> getPaymentMethodDataFieldKey , last_name )
59+ copy -> Dict .set (BillingAddress (FullName (LastName ))-> getPaymentMethodDataFieldKey , "" )
6460 }
6561 setFormData (_ => copy )
6662 setValidityDict (_ => validity )
@@ -193,8 +189,6 @@ let make = (
193189 setFormData (firstNameKey , firstName )
194190 if lastName -> String .length > 0 {
195191 setFormData (lastNameKey , lastName )
196- } else {
197- setFormData (lastNameKey , firstName )
198192 }
199193 }
200194 | _ => ()
@@ -247,6 +241,62 @@ let make = (
247241 | _ => React .null
248242 }
249243 }
244+
245+ let getErrorStringAndClasses = (field : dynamicFieldType ) => {
246+ let key = field -> getPaymentMethodDataFieldKey
247+ let value = formData -> Dict .get (key )-> Option .getOr ("" )
248+ let isValid = validityDict -> Dict .get (key )-> Option .flatMap (key => key )
249+
250+ switch field {
251+ | BillingAddress (FullName (FirstName )) => {
252+ // Check both FirstName and LastName validity and merge error messages
253+ let firstNameKey = BillingAddress (FullName (FirstName ))-> getPaymentMethodDataFieldKey
254+ let lastNameKey = BillingAddress (FullName (LastName ))-> getPaymentMethodDataFieldKey
255+ let firstNameValue = formData -> Dict .get (firstNameKey )-> Option .getOr ("" )
256+ let lastNameValue = formData -> Dict .get (lastNameKey )-> Option .getOr ("" )
257+ let firstNameValid = validityDict -> Dict .get (firstNameKey )-> Option .flatMap (key => key )
258+ let lastNameValid = validityDict -> Dict .get (lastNameKey )-> Option .flatMap (key => key )
259+
260+ let firstNameError = switch firstNameValid {
261+ | Some (false ) =>
262+ BillingAddress (FullName (FirstName ))-> getPaymentMethodDataErrorString (
263+ firstNameValue ,
264+ localeString ,
265+ )
266+ | _ => ""
267+ }
268+
269+ let lastNameError = switch lastNameValid {
270+ | Some (false ) =>
271+ BillingAddress (FullName (LastName ))-> getPaymentMethodDataErrorString (
272+ lastNameValue ,
273+ localeString ,
274+ )
275+ | _ => ""
276+ }
277+
278+ let mergedError = switch (firstNameError , lastNameError ) {
279+ | ("" , "" ) => ""
280+ | (firstError , "" ) => firstError
281+ | ("" , lastError ) => lastError
282+ | (firstError , lastError ) => firstError ++ " " ++ lastError
283+ }
284+
285+ let hasError = mergedError !== ""
286+ (mergedError , hasError ? "text-xs text-red-950" : "" )
287+ }
288+ | _ =>
289+ // Default behavior for other fields
290+ switch isValid {
291+ | Some (false ) => (
292+ field -> getPaymentMethodDataErrorString (value , localeString ),
293+ "text-xs text-red-950" ,
294+ )
295+ | _ => ("" , "" )
296+ }
297+ }
298+ }
299+
250300 let renderInputTemplate = (field : dynamicFieldType ) => {
251301 let labelClasses = "text-sm mt-2.5 text-jp-gray-800"
252302 let inputClasses = "min-w-full border mt-1.5 px-2.5 py-2 rounded-md border-jp-gray-200"
@@ -277,14 +327,7 @@ let make = (
277327 -> Js .Re .source
278328 let key = field -> getPaymentMethodDataFieldKey
279329 let value = formData -> Dict .get (key )-> Option .getOr ("" )
280- let isValid = validityDict -> Dict .get (key )-> Option .flatMap (key => key )
281- let (errorString , errorStringClasses ) = switch isValid {
282- | Some (false ) => (
283- field -> getPaymentMethodDataErrorString (value , localeString ),
284- "text-xs text-red-950" ,
285- )
286- | _ => ("" , "" )
287- }
330+ let (errorString , errorStringClasses ) = getErrorStringAndClasses (field )
288331 <InputField
289332 id = key
290333 className = inputClasses
@@ -319,13 +362,29 @@ let make = (
319362 pattern
320363 />
321364 }
365+ let checkIfLastNameRequiredAndNone = (addressFields : array <dynamicFieldForAddress >) => {
366+ addressFields -> Array .reduce (false , (acc , field ) => {
367+ let condition = switch (field .fieldType , field .value ) {
368+ | (FullName (LastName ), None ) => true
369+ | _ => false
370+ }
371+ acc || condition
372+ })
373+ }
322374 let renderAddressForm = (addressFields : array <dynamicFieldForAddress >) =>
323375 addressFields
324376 -> Array .mapWithIndex ((field , index ) =>
325377 <React .Fragment key = {index -> Int .toString }>
326378 {switch (field .fieldType , field .value ) {
327379 | (Email , None ) => BillingAddress (Email )-> renderInputTemplate
328380 | (FullName (FirstName ), None ) => BillingAddress (FullName (FirstName ))-> renderInputTemplate
381+ | (FullName (FirstName ), Some (_ )) =>
382+ // If first_name exists, last_name is required and has null value, render first_name field to capture last_name
383+ if checkIfLastNameRequiredAndNone (addressFields ) {
384+ BillingAddress (FullName (FirstName ))-> renderInputTemplate
385+ } else {
386+ React .null
387+ }
329388 // first_name and last_name are stored in fullName
330389 | (FullName (LastName ), _ ) => React .null
331390 | (CountryCode , None ) => BillingAddress (CountryCode )-> renderInputTemplate
0 commit comments