diff --git a/app/@newrecord/(.)new-record/page.jsx b/app/@newrecord/(.)new-record/page.jsx deleted file mode 100644 index be9ac85..0000000 --- a/app/@newrecord/(.)new-record/page.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import { RecordForm } from "~/RecordForm"; -import { Center } from "@chakra-ui/react"; -export default function Page() { - return ( -
- -
- ); -} diff --git a/app/@newrecord/default.js b/app/@newrecord/default.js deleted file mode 100644 index 6ddf1b7..0000000 --- a/app/@newrecord/default.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function Default() { - return null; -} diff --git a/app/api/page.jsx b/app/api/page.jsx deleted file mode 100644 index 12b005d..0000000 --- a/app/api/page.jsx +++ /dev/null @@ -1,8 +0,0 @@ -import { dbConnect } from "../../serverActions/appendRecord"; - -export default async function handler(req, res) { - //the rest of your code here -} - -await dbConnect(); -// dbConnect().catch((err) => console.error("MongoDB connection error:", err)); diff --git a/app/new-record/page.jsx b/app/new-record/page.jsx deleted file mode 100644 index afeed47..0000000 --- a/app/new-record/page.jsx +++ /dev/null @@ -1,5 +0,0 @@ -import { RecordForm } from "~/RecordForm"; - -export default function NewRecord() { - return ; -} diff --git a/components/InstitutionContainer/InstitutionContainer.jsx b/components/InstitutionContainer/InstitutionContainer.jsx index 36676f2..21e3ce1 100644 --- a/components/InstitutionContainer/InstitutionContainer.jsx +++ b/components/InstitutionContainer/InstitutionContainer.jsx @@ -21,6 +21,7 @@ export function InstitutionContainer({ institutionName, isInstitutionOpen }) { handlers: formHandlers = { handleInstitutionOpen }, } = useFormContext(); + console.log("container getValues", getValues("institutions")); // Fast solution to allow edit name of newly created institution // Will be replaced whith https://github.com/users/skorphil/projects/4/views/1?pane=issue&itemId=53834705 const institutionIndex = parseInt(institutionName.split(".")[1]); diff --git a/components/InstitutionsList/InstitutionsList.jsx b/components/InstitutionsList/InstitutionsList.jsx index 920474e..daa0492 100644 --- a/components/InstitutionsList/InstitutionsList.jsx +++ b/components/InstitutionsList/InstitutionsList.jsx @@ -1,22 +1,14 @@ "use client"; import { InstitutionsTabsList } from "../InstitutionsTabsList"; -import { InstitutionContainer } from "../InstitutionContainer"; -import { - Tabs, - Text, - TabPanels, - TabPanel, - Center, - Heading, - VStack, - Image, -} from "@chakra-ui/react"; +import { Tabs } from "@chakra-ui/react"; import { useVisualViewportSize } from "../../app/hooks"; import classes from "./InstitutionsList.module.css"; import { useFormContext } from "react-hook-form"; +import { InstitutionPanel } from "./components"; function InstitutionsList({ + institutionPanelOverlay, simulateKeyboard = false, isInstitutionOpen, selectedInstitution, @@ -38,7 +30,8 @@ function InstitutionsList({ variant="grid" padding={isInstitutionOpen || 2} > - - {selectedInstitution === null ? ( - - ) : ( - false - )} - {institutions.map((institution, index) => ( - - - - ))} - - ); -} - -function ContentPanelOverlay({ image, headingText, text }) { - return ( -
- - Illustration - - - - {headingText} - - {text} - - -
- ); -} diff --git a/components/InstitutionsList/components/InstitutionPanel.jsx b/components/InstitutionsList/components/InstitutionPanel.jsx new file mode 100644 index 0000000..286314f --- /dev/null +++ b/components/InstitutionsList/components/InstitutionPanel.jsx @@ -0,0 +1,52 @@ +"use client"; +import { InstitutionContainer } from "../../InstitutionContainer"; +import { TabPanels, TabPanel } from "@chakra-ui/react"; +import { useFormContext } from "react-hook-form"; +import { getInstitutionPanelOverlayState } from "../utils/getInstitutionPanelOverlayState"; +import { InstitutionPanelOverlayAllDeleted } from "./InstitutionPanelOverlayAllDeleted"; +import { InstitutionPanelOverlayInstitutionsLoaded } from "./InstitutionPanelOverlayInstitutionsLoaded"; + +// TODO add all instituion deleted state +export function InstitutionPanel({ + institutions, + selectedInstitution, + isInstitutionOpen, +}) { + const { + formState: { defaultValues }, + getValues, + } = useFormContext(); + + const overlayState = getInstitutionPanelOverlayState( + defaultValues, + getValues + ); + + return ( + + {selectedInstitution !== null ? ( + institutions.map((institution, index) => ( + + + + )) + ) : overlayState == "success" && selectedInstitution == null ? ( + + ) : overlayState == "allDeleted" && selectedInstitution == null ? ( + + ) : ( + false + )} + + ); +} diff --git a/components/InstitutionsList/components/InstitutionPanelOverlay.jsx b/components/InstitutionsList/components/InstitutionPanelOverlay.jsx new file mode 100644 index 0000000..565384e --- /dev/null +++ b/components/InstitutionsList/components/InstitutionPanelOverlay.jsx @@ -0,0 +1,18 @@ +import { Text, Center, Heading, VStack, Image } from "@chakra-ui/react"; + +export function InstitutionPanelOverlay({ image, headingText, text }) { + return ( +
+ + Illustration + + + + {headingText} + + {text} + + +
+ ); +} diff --git a/components/InstitutionsList/components/InstitutionPanelOverlayAllDeleted.jsx b/components/InstitutionsList/components/InstitutionPanelOverlayAllDeleted.jsx new file mode 100644 index 0000000..72a1090 --- /dev/null +++ b/components/InstitutionsList/components/InstitutionPanelOverlayAllDeleted.jsx @@ -0,0 +1,11 @@ +import { InstitutionPanelOverlay } from "./InstitutionPanelOverlay"; + +export function InstitutionPanelOverlayAllDeleted() { + return ( + + ); +} diff --git a/components/InstitutionsList/components/InstitutionPanelOverlayInstitutionsLoaded.jsx b/components/InstitutionsList/components/InstitutionPanelOverlayInstitutionsLoaded.jsx new file mode 100644 index 0000000..7a2644d --- /dev/null +++ b/components/InstitutionsList/components/InstitutionPanelOverlayInstitutionsLoaded.jsx @@ -0,0 +1,11 @@ +import { InstitutionPanelOverlay } from "./InstitutionPanelOverlay"; + +export function InstitutionPanelOverlayInstitutionsLoaded() { + return ( + + ); +} diff --git a/components/InstitutionsList/components/index.js b/components/InstitutionsList/components/index.js new file mode 100644 index 0000000..8380afe --- /dev/null +++ b/components/InstitutionsList/components/index.js @@ -0,0 +1 @@ +export { InstitutionPanel } from "./InstitutionPanel"; diff --git a/components/InstitutionsList/index.js b/components/InstitutionsList/index.js index 347694d..d80b8f6 100644 --- a/components/InstitutionsList/index.js +++ b/components/InstitutionsList/index.js @@ -1,2 +1,3 @@ export { InstitutionsList } from "./InstitutionsList"; export { institutionsListStyle } from "./InstitutionList.chakra"; +export { InstitutionPanelOverlay } from "./components/InstitutionPanelOverlay"; diff --git a/components/InstitutionsList/utils/getInstitutionPanelOverlayState.ts b/components/InstitutionsList/utils/getInstitutionPanelOverlayState.ts new file mode 100644 index 0000000..76fc565 --- /dev/null +++ b/components/InstitutionsList/utils/getInstitutionPanelOverlayState.ts @@ -0,0 +1,40 @@ +import { DefaultValues, FieldValues, UseFormGetValues } from "react-hook-form"; + +/** + * Function for deriving the InstitutionPanelOverlay state + * from useFormContext + */ +export function getInstitutionPanelOverlayState(defaultValues:DefaultValues, getValues:UseFormGetValues) { + const formValues = getValues("institutions"); + const isAllDeleted = isAllInstitutionsDeleted(formValues); + const isFetchedPrevious = isFetchedPreviousRecords(defaultValues, isAllDeleted); +// console.log("isFetchedPrevious TS", isFetchedPrevious); +// console.log("isAllDeleted TS", isAllDeleted); + +if (isFetchedPrevious && !isAllDeleted) { + return 'success' + } else if (isAllDeleted) { + return 'allDeleted' + } else return false; +} + +function isAllInstitutionsDeleted(formValues) { + const institutionsIndexes = formValues.map((institution, index) => ({ + index, + isDeleted: institution.isDeleted, + })); + const availableIndexes = institutionsIndexes + .filter((institution) => institution.isDeleted != true) + .map((institution) => institution.index); + + if (institutionsIndexes.length > 0 && availableIndexes.length == 0) { + return true; + } else return false; + } + + function isFetchedPreviousRecords(defaultValues, isAllDeleted) { + if (defaultValues.institutions && !isAllDeleted) { + return true; + } else return false; + } + \ No newline at end of file diff --git a/components/InstitutionsList/utils/index.js b/components/InstitutionsList/utils/index.js new file mode 100644 index 0000000..443324a --- /dev/null +++ b/components/InstitutionsList/utils/index.js @@ -0,0 +1 @@ +export { getInstitutionPanelOverlayState } from "./getInstitutionPanelOverlayState"; diff --git a/components/RecordForm/RecordForm.jsx b/components/RecordForm/RecordForm.jsx index 523593c..430cfbc 100644 --- a/components/RecordForm/RecordForm.jsx +++ b/components/RecordForm/RecordForm.jsx @@ -13,7 +13,7 @@ import { useState } from "react"; import { Button, Progress, useToast } from "@chakra-ui/react"; import { InstitutionsList } from "components/InstitutionsList"; import { FormHeader } from "components/FormHeader"; -import { FormStateOverlay, FormWarning } from "./components"; +import { FormOverlay, FormAlert } from "./components"; import { appendRecord } from "serverActions/appendRecord"; import { getDefaultValues } from "./utils"; @@ -25,7 +25,7 @@ export function RecordForm() { const [selectedInstitutionIndex, setSelectedInstitutionIndex] = useState(null); const [formOverlay, setFormOverlay] = useState(false); - const [warningState, setWarningState] = useState(null); + const [formAlert, setFormAlert] = useState(null); const toast = useToast({ position: "top" }); const router = useRouter(); const arrayName = "institutions"; @@ -33,7 +33,7 @@ export function RecordForm() { defaultValues: async () => getDefaultValues({ setFormOverlay, - setWarningState, + setFormAlert, handleInstitutionCreate: formMethods.handlers.handleInstitutionCreate, }), }); @@ -106,11 +106,11 @@ export function RecordForm() { } /> - {warningState?.isVisible && ( - - setWarningState((current) => ({ + setFormAlert((current) => ({ ...current, isVisible: false, })) @@ -123,12 +123,12 @@ export function RecordForm() { {form.formState.isLoading ? ( ) : formOverlay ? ( - {formOverlay.children} - + ) : (
+ + + + + {heading} + + + + + {message} + {onHide && ( + + )} + + + + + ); +} diff --git a/components/RecordForm/components/FormStateOverlay.jsx b/components/RecordForm/components/FormOverlay.jsx similarity index 77% rename from components/RecordForm/components/FormStateOverlay.jsx rename to components/RecordForm/components/FormOverlay.jsx index aec63d8..d5023db 100644 --- a/components/RecordForm/components/FormStateOverlay.jsx +++ b/components/RecordForm/components/FormOverlay.jsx @@ -12,10 +12,15 @@ import { AccordionPanel, } from "@chakra-ui/react"; -export function FormStateOverlay({ image, errorMessage, children }) { - /** - * Overlay to display errors or states in RecordForm - */ +/** + * Overlays form body. Used for empty states and blocking errors. + * Can contain hidden system error text. + * + * @param {string} [image] - The path to state illustartion + * @param {string} [errorMessage] - System error message + * @param children – overlay content + */ +export function FormOverlay({ image, errorMessage, children }) { return (
diff --git a/components/RecordForm/components/FormWarning.jsx b/components/RecordForm/components/FormWarning.jsx deleted file mode 100644 index 6e4b925..0000000 --- a/components/RecordForm/components/FormWarning.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { - Button, - Accordion, - AccordionButton, - AccordionItem, - AccordionIcon, - Box, - AccordionPanel, - Text, -} from "@chakra-ui/react"; - -export function FormWarning({ heading, message, onHide }) { - return ( - - - -

- - - {heading} - - - -

- - {message} - - -
-
-
- ); -} diff --git a/components/RecordForm/components/index.js b/components/RecordForm/components/index.js index a50c9fd..244e663 100644 --- a/components/RecordForm/components/index.js +++ b/components/RecordForm/components/index.js @@ -1,2 +1,2 @@ -export { FormStateOverlay } from "./FormStateOverlay"; -export { FormWarning } from "./FormWarning"; +export { FormOverlay } from "./FormOverlay"; +export { FormAlert } from "./FormAlert"; diff --git a/components/RecordForm/docs/components.md b/components/RecordForm/docs/components.md new file mode 100644 index 0000000..f2c618f --- /dev/null +++ b/components/RecordForm/docs/components.md @@ -0,0 +1,17 @@ +```mermaid +flowchart TB + RecordForm --> + FormOverlay & FormAlert +``` + +## FormOverlay +Overlays form body. Used for empty states and blocking errors. Can contain hidden system error text. + +![FormOverlay design](img/FormOverlay.png) + + +## FormAlert +Alert, appended to the top of RecordForm. Used for non-blocking warnings or information. Can be expanded and explicitly closed until reload of the form. + +![FormAlert design](img/FormAlert.png) + diff --git a/components/RecordForm/docs/img/FormAlert.png b/components/RecordForm/docs/img/FormAlert.png new file mode 100644 index 0000000..d51f4d4 Binary files /dev/null and b/components/RecordForm/docs/img/FormAlert.png differ diff --git a/components/RecordForm/docs/img/FormOverlay.png b/components/RecordForm/docs/img/FormOverlay.png new file mode 100644 index 0000000..d84c9e3 Binary files /dev/null and b/components/RecordForm/docs/img/FormOverlay.png differ diff --git a/components/RecordForm/docs.md b/components/RecordForm/docs/overview.md similarity index 100% rename from components/RecordForm/docs.md rename to components/RecordForm/docs/overview.md diff --git a/components/RecordForm/handlers/handleEmptyState.jsx b/components/RecordForm/handlers/handleEmptyState.jsx index c87d90d..a68da79 100644 --- a/components/RecordForm/handlers/handleEmptyState.jsx +++ b/components/RecordForm/handlers/handleEmptyState.jsx @@ -1,6 +1,3 @@ -/* -Root element of the form -*/ "use client"; import { Button, Heading, Text } from "@chakra-ui/react"; diff --git a/components/RecordForm/handlers/handleFetchError.tsx b/components/RecordForm/handlers/handleFetchError.tsx index 6d8a55c..1848a3b 100644 --- a/components/RecordForm/handlers/handleFetchError.tsx +++ b/components/RecordForm/handlers/handleFetchError.tsx @@ -1,6 +1,3 @@ -/* -Root element of the form -*/ "use client"; import { Heading, Text } from "@chakra-ui/react"; diff --git a/components/RecordForm/handlers/handleRecordExist.jsx b/components/RecordForm/handlers/handleRecordExist.jsx index 5324eb8..e90292c 100644 --- a/components/RecordForm/handlers/handleRecordExist.jsx +++ b/components/RecordForm/handlers/handleRecordExist.jsx @@ -1,9 +1,6 @@ -/* -Root element of the form -*/ "use client"; -export function handleRecordExist({ existingRecordDate, setWarningState }) { - setWarningState({ +export function handleRecordExist({ existingRecordDate, setFormAlert }) { + setFormAlert({ heading: `Record from ${new Date(existingRecordDate).toLocaleDateString( "en-US", { diff --git a/components/RecordForm/handlers/handleSavingError.jsx b/components/RecordForm/handlers/handleSavingError.jsx index 22cb9e0..1ba6e1a 100644 --- a/components/RecordForm/handlers/handleSavingError.jsx +++ b/components/RecordForm/handlers/handleSavingError.jsx @@ -1,6 +1,3 @@ -/* -Root element of the form -*/ "use client"; export function handleSavingError({ toast, error }) { toast({ diff --git a/components/RecordForm/handlers/handleSavingSuccess.jsx b/components/RecordForm/handlers/handleSavingSuccess.jsx index bd7846e..8e96e37 100644 --- a/components/RecordForm/handlers/handleSavingSuccess.jsx +++ b/components/RecordForm/handlers/handleSavingSuccess.jsx @@ -1,6 +1,3 @@ -/* -Root element of the form -*/ "use client"; export function handleSavingSuccess({ toast }) { toast({ diff --git a/components/RecordForm/utils/getDefaultValues.js b/components/RecordForm/utils/getDefaultValues.js index f18d08a..6d9e731 100644 --- a/components/RecordForm/utils/getDefaultValues.js +++ b/components/RecordForm/utils/getDefaultValues.js @@ -6,24 +6,23 @@ import { } from "../handlers"; import { isInCurrentMonth } from "./isDateInCurrentMonth"; +/** + * Get initial values for the RecordForm and handling error states and alerts, + * based on received values + * + * @param setFormOverlay - state setter from RecordForm + * @param setFormAlert - state setter from RecordForm + * @param handleInstitutionCreate - handler from formMethods whith arguments + * from RecordForm + * + * @returns object to use as react-form-hook defaultValues for {@link RecordForm} + * or void if errors / empty states + */ export async function getDefaultValues({ setFormOverlay, handleInstitutionCreate, - setWarningState, + setFormAlert, }) { - /** - * Get initial values for the RecordForm and handling errors and warnings, - * based on received values - * - * @param setFormOverlay - state setter from RecordForm - * @param setWarningState - state setter from RecordForm - * @param handleInstitutionCreate - handler from formMethods whith arguments - * from RecordForm - * - * @returns object to use as react-form-hook defaultValues for {@link RecordForm} - * or void if errors / empty states - */ - let latestRecord = null; try { latestRecord = await getLatestRecord(); @@ -40,7 +39,7 @@ export async function getDefaultValues({ } else if (isInCurrentMonth(latestRecord.date)) { handleRecordExist({ existingRecordDate: latestRecord.date, - setWarningState, + setFormAlert, }); }