From 9c4c673eb60454a723ee39219792a160f16a1152 Mon Sep 17 00:00:00 2001 From: Kanika Bansal Date: Thu, 12 Dec 2024 14:24:34 +0530 Subject: [PATCH] feat: new pill input type (#1901) --- src/components/form/PillInput.res | 181 ++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 src/components/form/PillInput.res diff --git a/src/components/form/PillInput.res b/src/components/form/PillInput.res new file mode 100644 index 000000000..98c1cab2d --- /dev/null +++ b/src/components/form/PillInput.res @@ -0,0 +1,181 @@ +@react.component +let make = (~name, ~initialItems: array=[], ~placeholder, ~duplicateCheck=true) => { + let form = ReactFinalForm.useForm() + let (items, setItems) = React.useState(_ => initialItems) + let (inputValue, setInputValue) = React.useState(_ => "") + let (editInput, setEditInput) = React.useState(_ => "") + let (editingItem, setEditingItem) = React.useState(_ => None) + let (error, setError) = React.useState(_ => "") + let (suggestion, setSuggestion) = React.useState(_ => None) + let enterKeyCode = 14 + + let handleInputChange = e => { + let value = ReactEvent.Form.target(e)["value"] + setInputValue(_ => value) + setError(_ => "") + + if !CommonAuthUtils.isValidEmail(value) { + setSuggestion(_ => Some(value)) + } else { + setSuggestion(_ => None) + } + } + + let handleEditChange = e => { + let value = ReactEvent.Form.target(e)["value"] + setEditInput(_ => value) + setError(_ => "") + } + + let addItem = elem => { + let trimmedItem = String.trim(elem) + if trimmedItem->LogicUtils.isEmptyString { + setInputValue(_ => "") + setError(_ => "") + setSuggestion(_ => None) + } + + if duplicateCheck && Array.some(items, existingItem => existingItem == trimmedItem) { + setError(_ => "Email already exists") + setSuggestion(_ => None) + } else if !CommonAuthUtils.isValidEmail(trimmedItem) { + setItems(prev => Array.concat(prev, [trimmedItem])) + form.change(name, [...items, elem]->Identity.genericTypeToJson) + setInputValue(_ => "") + setError(_ => "") + setSuggestion(_ => None) + } else { + setError(_ => "Invalid Email") + setSuggestion(_ => None) + } + } + + let handleSuggestionClick = () => { + switch suggestion { + | Some(suggestedEmail) => addItem(suggestedEmail) + | None => () + } + } + + let removeItem = itemToRemove => { + form.change(name, items->Array.filter(ele => ele !== itemToRemove)->Identity.genericTypeToJson) + setItems(prev => prev->Array.filter(item => item != itemToRemove)) + } + + let saveItem = itemToSave => { + let trimmedEditInput = String.trim(editInput) + let isDuplicate = + duplicateCheck && + trimmedEditInput != itemToSave && + Array.some(items, existingItem => existingItem == trimmedEditInput) + if isDuplicate { + setError(_ => "Email already exists") + setEditInput(_ => itemToSave) + } else if !CommonAuthUtils.isValidEmail(trimmedEditInput) { + setItems(prev => prev->Array.map(item => item == itemToSave ? trimmedEditInput : item)) + let updatedArray = + items + ->Array.filter(ele => ele !== itemToSave) + ->Array.concat([trimmedEditInput]) + form.change(name, updatedArray->Identity.genericTypeToJson) + setEditingItem(_ => None) + setEditInput(_ => "") + setError(_ => "") + } else { + setEditInput(_ => itemToSave) + setError(_ => "Invalid Email") + } + } + + let handleKeyDown = e => { + let key = e->ReactEvent.Keyboard.key + let keyCode = e->ReactEvent.Keyboard.keyCode + if key === "Enter" || keyCode === enterKeyCode { + ReactEvent.Keyboard.preventDefault(e) + switch suggestion { + | Some(suggestedEmail) => addItem(suggestedEmail) + | None => addItem(inputValue) + } + } + } + + let handleEditKeydown = (item, ev) => { + let key = ev->ReactEvent.Keyboard.key + let keyCode = ev->ReactEvent.Keyboard.keyCode + if key === "Enter" || keyCode === enterKeyCode { + ReactEvent.Keyboard.preventDefault(ev) + saveItem(item) + } + } + + let toggleEditingItem = item => { + setEditingItem(_ => Some(item)) + setEditInput(_ => item) + } + +
+
+ {items + ->Array.mapWithIndex((item, i) => + switch editingItem { + | Some(selected) => + +
+ saveItem(item)} + onInput=handleEditChange + onKeyDown={ev => handleEditKeydown(item, ev)} + className="rounded-md p-1 flex-grow" + /> + +
+
+ | None => +
+
toggleEditingItem(item)}> + {React.string(item)} +
+ +
+ } + ) + ->React.array} +
+ + Option.isSome}> +
handleSuggestionClick()} + className="absolute z-10 min-w-80 bg-white border rounded-md shadow-lg mt-1 cursor-pointer top-10 h-16"> +
+
+ user_icon + {React.string(suggestion->Option.getOr(""))} +
+
+
+
+
+
+ LogicUtils.isEmptyString)}> +
+ +

{React.string(error)}

+
+
+
+}