diff --git a/components/InstitutionContainer/InstitutionContainer.jsx b/components/InstitutionContainer/InstitutionContainer.jsx index 2310ca9..1e91211 100644 --- a/components/InstitutionContainer/InstitutionContainer.jsx +++ b/components/InstitutionContainer/InstitutionContainer.jsx @@ -23,6 +23,7 @@ import { FormHeader } from "~/FormHeader"; // TODO Fix keyboard openLayout // TODO Update stories to suit use-form export function InstitutionContainer({ institutionName, isInstitutionOpen }) { + // console.log("InstitutionContainer Rendered"); const { getValues, handlers: formHandlers } = useFormContext(); return ( @@ -109,6 +110,7 @@ const ExpandedHeader = () => { const AssetsList = ({ isInstitutionOpen, institutionName }) => { const arrayName = `${institutionName}.assets`; + // console.log("AssetsList rendered"); const { fields: assets, remove, @@ -118,12 +120,8 @@ const AssetsList = ({ isInstitutionOpen, institutionName }) => { }); const { resetField, - getValues, - formState: { isDirty, dirtyFields, defaultValues }, + formState: { dirtyFields, defaultValues }, } = useFormContext(); - // const { fields: institutionFields } = useFieldArray({ - // name: "institutions.0.assets.0", - // }); return ( { - const { formState, getValues, control } = useFormContext(); + const { formState, getValues, control, institutionsFieldArray } = + useFormContext(); + const institutionFields = + institutionsFieldArray.fields[getInstitutionIndex(institutionName)]; const institutionDefaultValues = formState.defaultValues.institutions[ getInstitutionIndex(institutionName) @@ -16,11 +19,13 @@ export const InstitutionTab = forwardRef( const isChanged = JSON.stringify(institutionDefaultValues) !== JSON.stringify(institutionCurrentValues); - const state = isChanged ? "updated" : null; - const name = useWatch({ - control, - name: `${institutionName}.name`, - }); + const isNew = institutionFields.name === ""; + const state = isNew ? "new" : isChanged ? "updated" : null; + const name = + useWatch({ + control, + name: `${institutionName}.name`, + }) || "New Institution"; return ( existing -existing --> updated : prop changed -updated --> existing : prop changed +existing --> updated : defaultValues.institution[id] != getvalues(institution.id) +updated --> existing : defaultValues.institution[id] == getvalues(institution.id) updated --> deleted : prop changed existing --> deleted : prop changed deleted --> updated : BUTTON_PRESS
Do / setState @@ -44,15 +42,16 @@ I want to minimize states number. By somehow derive from existing use-hook-form Probably can be known via comparison between institution value and defaultValues(which are retrieved) For this scenario probably the simplest reliable way is to generate unique ID for institution and store it in db. -*defaultValues* can be retrieved from `fields` https://react-hook-form.com/docs/usefieldarray#:~:text=Description-,fields,-object%20%26%20%7B%20id +Field values can be retrieved from `fields` https://react-hook-form.com/docs/usefieldarray#:~:text=Description-,fields,-object%20%26%20%7B%20id if `institutions.ID.name` from `fields` === '' than institution is new #### Deleted state -can be set by disabling institution fields +can be set by disabling institution fields?? #### Updated state -can be retrived from `isDirty` +~~can be retrived from `isDirty`~~ +Retrieved by comparison between `defaulValues.institutions[id]` and current values of `institutions[id]` ### Text prop -`text`(`InstitutionName`) can be retrieved by `getValues()`, **but there is problem of retreiving value from disabled inputs**(which i planned to use for deleted state) https://github.com/orgs/react-hook-form/discussions/11533 +`text`(`InstitutionName`) retrieved by `useWatch()`, **but there is problem of retreiving value from disabled inputs**(which i planned to use for deleted state) https://github.com/orgs/react-hook-form/discussions/11533 diff --git a/components/InstitutionsList/InstitutionsList.jsx b/components/InstitutionsList/InstitutionsList.jsx index aedf69e..13ffe35 100644 --- a/components/InstitutionsList/InstitutionsList.jsx +++ b/components/InstitutionsList/InstitutionsList.jsx @@ -5,45 +5,45 @@ import { InstitutionContainer } from "../InstitutionContainer"; import { Tabs, TabPanels, TabPanel } from "@chakra-ui/react"; import { useVisualViewportSize } from "../../app/hooks"; import classes from "./InstitutionsList.module.css"; -import { useFieldArray } from "react-hook-form"; +import { useFormContext } from "react-hook-form"; -function InstitutionsList({ simulateKeyboard = false, isIntitutionOpen }) { +function InstitutionsList({ + simulateKeyboard = false, + isInstitutionOpen, + selectedInstitution, +}) { const { height } = useVisualViewportSize(); const isKeyboardOpened = simulateKeyboard || height < 650; - - const arrayName = `institutions`; - const { fields: institutions, remove } = useFieldArray({ - name: arrayName, - }); + const { + institutionsFieldArray: { fields: institutions }, + handlers: { handleInstitutionCreate, handleTabsChange }, + } = useFormContext(); return ( {institutions.map((institution, index) => ( ))} - {isIntitutionOpen || ( + {isInstitutionOpen || ( )} diff --git a/components/InstitutionsList/docs.md b/components/InstitutionsList/docs.md new file mode 100644 index 0000000..c8a5c4b --- /dev/null +++ b/components/InstitutionsList/docs.md @@ -0,0 +1,33 @@ +## InstitutionsList +### Props +```diff +// Props +- isCompact (bool) +- isOpenedInstitution (bool) +- institutions (array) ++ isInstitutionOpen (bool) + +// Context ++ selectedInstitution (int) ++ { institutionsFieldArray: {fields: institutions}, handlers } = ++ useFormContext(); +``` + +### States +- selectedInstitutionId (number) + +```mermaid +--- +title: InstitutionsList +--- +stateDiagram-v2 + direction LR + +[*] --> compact +[*] --> expanded +compact --> openedInstitution : BUTTON_PRESS do / setIsOpenInstitution +compact --> expanded : window.visualViewport.height > 650px + +expanded --> compact : window.visualViewport.height < 650px +openedInstitution --> compact : BUTTON_PRESS do / setIsOpenInstitution +``` \ No newline at end of file diff --git a/components/InstitutionsTabsList/InstitutionsTabsList.jsx b/components/InstitutionsTabsList/InstitutionsTabsList.jsx index 8920d82..6397e50 100644 --- a/components/InstitutionsTabsList/InstitutionsTabsList.jsx +++ b/components/InstitutionsTabsList/InstitutionsTabsList.jsx @@ -3,24 +3,19 @@ // TODO fix animation framer https://github.com/skorphil/nextjs-form/issues/25 import { InstitutionTab } from "../InstitutionTab"; -import { - Tabs, - TabList, - Heading, - Button, - Box, - IconButton, -} from "@chakra-ui/react"; +import { TabList, Heading, Button, Box, IconButton } from "@chakra-ui/react"; import classes from "./InstitutionsTabsList.module.css"; import { CgMathPlus } from "react-icons/cg"; import { useVisualViewportSize } from "../../app/hooks"; import { motion } from "framer-motion"; +import { useFormContext } from "react-hook-form"; -export function InstitutionsTabsList({ - institutions, - simulateKeyboard = false, -}) { +export function InstitutionsTabsList({ simulateKeyboard = false }) { + const { + institutionsFieldArray: { fields: institutions }, + handlers: { handleInstitutionCreate }, + } = useFormContext(); const { height } = useVisualViewportSize(); const isKeyboardOpened = simulateKeyboard || (window.innerHeight - height > 200 ? true : false); @@ -38,39 +33,45 @@ export function InstitutionsTabsList({ key="tablist" className={`${classes.grid} ${isKeyboardOpened ? classes.collapsed : classes.expanded}`} > - {institutions.map((institution, id) => ( + {institutions.map((institution, index) => ( ))} - {isKeyboardOpened - ? newInstitutionButtonCollapsed - : newInstitutionButtonExpanded} + {isKeyboardOpened ? ( + + ) : ( + + )} ); } -const newInstitutionButtonExpanded = ( - -); +function NewInstitutionButtonExpanded({ onCreateInstitution }) { + return ( + + ); +} -const newInstitutionButtonCollapsed = ( - } - /> -); +function NewInstitutionButtonCollapsed({ onCreateInstitution }) { + return ( + } + /> + ); +} diff --git a/components/InstitutionsTabsList/docs.md b/components/InstitutionsTabsList/docs.md new file mode 100644 index 0000000..93a575d --- /dev/null +++ b/components/InstitutionsTabsList/docs.md @@ -0,0 +1,33 @@ +## InstitutionsTabsList +### Props +```diff +// Props +- isCompact (bool) // renamed to isKeyboardOpened +- Institutions (array) // get from context +- onCreate (function) // get from context +- selectedInstitutionId (number) // not needed. Used by InstitutionsList ++ isKeyboardOpened + +// Context ++ { ++ institutionsFieldArray: { fields: institutions }, ++ handlers: { handleInstitutionCreate }, ++ } = useFormContext() +``` + +### Listeners +- restoreButton click + +### States +```mermaid +--- +title: InstitutionsTabsList +--- +stateDiagram-v2 +direction LR + +[*] --> expanded +[*] --> compact +expanded --> compact : prop + isKeyboardOpened changed +compact --> compact : prop + isKeyboardOpened changed +``` \ No newline at end of file diff --git a/components/RecordForm/RecordForm.jsx b/components/RecordForm/RecordForm.jsx index 492cfb5..6873fba 100644 --- a/components/RecordForm/RecordForm.jsx +++ b/components/RecordForm/RecordForm.jsx @@ -4,12 +4,11 @@ Root element of the form "use client"; -import { useForm, FormProvider } from "react-hook-form"; +import { useForm, FormProvider, useFieldArray } from "react-hook-form"; import classes from "./RecordForm.module.css"; -import { Button, IconButton } from "@chakra-ui/react"; +import { Button } from "@chakra-ui/react"; import { useState } from "react"; -import { CgMinimizeAlt } from "react-icons/cg"; import { InstitutionsList } from "../InstitutionsList"; import { FormHeader } from "~/FormHeader"; @@ -105,27 +104,45 @@ const prevRecord = { }; export function RecordForm({ onSubmit }) { - // TODO check naming conventions for submitAction server action + // check naming conventions for submitAction server action const isClient = typeof window !== "undefined"; - const [isIntitutionOpen, setIsInstitutionOpen] = useState(false); + const [isInstitutionOpen, setIsInstitutionOpen] = useState(false); + const [selectedInstitutionIndex, setSelectedInstitutionIndex] = useState(0); - const handleInstitutionOpen = () => { - setIsInstitutionOpen((val) => !val); - }; + const { control, ...form } = useForm({ + defaultValues: prevRecord, + }); + + const institutionsFieldArray = useFieldArray({ + control, + name: `institutions`, + }); const formMethods = { - ...useForm({ - defaultValues: prevRecord, - }), + control, + ...form, + institutionsFieldArray, handlers: { - handleInstitutionOpen: handleInstitutionOpen, + handleInstitutionOpen: () => handleInstitutionOpen(setIsInstitutionOpen), + handleInstitutionCreate: () => + handleInstitutionCreate({ + append: institutionsFieldArray.append, + fields: institutionsFieldArray.fields, + setSelectedIndex: setSelectedInstitutionIndex, + setIsInstitutionOpen: setIsInstitutionOpen, + }), + handleTabsChange: (index) => + handleTabsChange({ + index: index, + setSelectedIndex: setSelectedInstitutionIndex, + }), }, }; return (
- {isIntitutionOpen || ( + {isInstitutionOpen || ( )}
); } + +function handleInstitutionOpen(setState, value) { + value ? setState(value) : setState((val) => !val); +} + +function handleInstitutionCreate({ + append, + setSelectedIndex, + fields, + setIsInstitutionOpen, +}) { + append({ + name: "", + country: "", + assets: [ + { + amount: "", + currency: "", + isEarning: false, + description: "", + }, + ], + }); + const newInstitutionIndex = fields.length; + handleTabsChange({ + index: newInstitutionIndex, + setSelectedIndex: setSelectedIndex, + }); + handleInstitutionOpen(setIsInstitutionOpen, true); +} + +function handleTabsChange({ index, setSelectedIndex }) { + setSelectedIndex(index); +}