Skip to content

Commit

Permalink
feat: add formik field for adding key values
Browse files Browse the repository at this point in the history
  • Loading branch information
mainawycliffe committed Oct 12, 2023
1 parent 6162be8 commit d1a6b8c
Showing 1 changed file with 104 additions and 0 deletions.
104 changes: 104 additions & 0 deletions src/components/Forms/Formik/FormikKeyValueMapField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { useFormikContext } from "formik";
import { Button } from "../../Button";
import { TextInput } from "../../TextInput";
import { get, set } from "lodash";
import { useEffect, useState } from "react";
import { FaPlus, FaTrash } from "react-icons/fa";

type LocalStateValue = {
key: string;
value: string;
};

type Props = {
name: string;
label: string;
};

export default function FormikKeyValueMapField({ name, label }: Props) {
const [localValues, setLocalValue] = useState<LocalStateValue[]>([
{ key: "", value: "" }
]);

const { values, setFieldValue } =
useFormikContext<Record<string, Record<string, string>>>();

// on mount, set the local values to the formik values and set the formik
// values to the local values on change
useEffect(() => {
const localValues = Object.entries(get(values, name, {})).map(
([key, value]) => ({ key, value })
);
setLocalValue(localValues);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
const formValue = {};
localValues.forEach(({ key, value }) => {
set(formValue, key, value);
});
setFieldValue(name, formValue);
}, [localValues, name, setFieldValue]);

const handleRemove = (index: number) => {
setLocalValue((prev) => prev.filter((_, i) => i !== index));
};

const handleAdd = () => {
setLocalValue((prev) => [...prev, { key: "", value: "" }]);
};

return (
<div className="flex flex-col gap-2">
<label className="text-sm font-medium text-gray-700">{label}</label>
<div className="flex flex-col gap-2">
{localValues.map(({ value, key }, index: number) => (
<div className="flex flex-row gap-2" key={index}>
<TextInput
value={key}
onChange={(event) => {
const newLocalValues = localValues.map((localValue, i) => {
if (i === index) {
return { ...localValue, key: event.target.value };
}
return localValue;
});
setLocalValue(newLocalValues);
}}
id={""}
/>
:
<TextInput
value={value}
onChange={(event) => {
// find the key that matches the index
const newLocalValues = localValues.map((localValue, i) => {
if (i === index) {
return { ...localValue, value: event.target.value };
}
return localValue;
});
setLocalValue(newLocalValues);
}}
id={""}
/>
<Button
className="btn-white"
onClick={() => handleRemove(index)}
icon={<FaTrash />}
/>
</div>
))}
</div>
<div className="flex flex-row gap-2 justify-end">
<Button
className="btn-white"
onClick={handleAdd}
text="Add"
icon={<FaPlus />}
/>
</div>
</div>
);
}

0 comments on commit d1a6b8c

Please sign in to comment.