Skip to content

Commit

Permalink
implemented warning when record existing
Browse files Browse the repository at this point in the history
resolves #70

-refactored getLatestRecord
  • Loading branch information
skorphil committed Mar 14, 2024
1 parent 72b3b04 commit 5d6f6df
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 81 deletions.
37 changes: 37 additions & 0 deletions components/RecordForm/FormWarning.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
Button,
Accordion,
AccordionButton,
AccordionItem,
AccordionIcon,
Box,
AccordionPanel,
Text,
} from "@chakra-ui/react";

import Link from "next/link";

export function FormWarning({ heading, message, onHide }) {
return (
<Box bg="yellow.900" m={2} borderRadius="md">
<Accordion w="100%" allowToggle>
<AccordionItem borderStyle="none">
<h2>
<AccordionButton>
<Box as="span" flex="1" textAlign="left">
{heading}
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel maxH="180px" overflow="auto" pb={4}>
<Text>{message}</Text>
<Button mt={2} variant="link" onClick={onHide}>
Hide warning
</Button>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Box>
);
}
109 changes: 71 additions & 38 deletions components/RecordForm/RecordForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,40 @@ import { FormHeader } from "~/FormHeader";
import { handleInstitution } from "handlers";
import { useRouter } from "next/navigation";
import { appendRecord } from "serverActions/appendRecord";
import { getLatestRecord } from "serverActions/getLatestRecord";
// import { getLatestRecord } from "serverActions/getLatestRecord";
import { FetchingErrorState } from "./FetchingErrorState";
import { getDefaultValues } from "./utils/getDefaultValues";
import { isInCurrentMonth } from "./utils/isDateInCurrentMonth";
import { FormWarning } from "./FormWarning";

export function RecordForm() {
const [isInstitutionOpen, setIsInstitutionOpen] = useState(false);
const [selectedInstitutionIndex, setSelectedInstitutionIndex] = useState(0);
const [errorState, setErrorState] = useState(false);
const [warningState, setWarningState] = useState(null);
const toast = useToast({ position: "top" });
const router = useRouter();
const arrayName = "institutions";

const { control, ...form } = useForm({
defaultValues: async () => {
try {
const initialValues = await getLatestRecord();
const initialValues = await getDefaultValues();
if (initialValues === null) {
console.log("no def values");
} else if (isInCurrentMonth(initialValues.date)) {
setWarningState({
heading: `Record from ${new Date(
initialValues.date
).toLocaleDateString("en-US", {
day: "numeric",
month: "long",
})} will be replaced`,
message: `There is a saved record for this month already.
Saving current record will override that.`,
isVisible: true,
});
}
return initialValues;
} catch (error) {
setErrorState(error.stack);
Expand Down Expand Up @@ -75,44 +94,58 @@ export function RecordForm() {
return (
<FormProvider {...formMethods}>
{isInstitutionOpen || (
<FormHeader
text="New Record"
rightButtons={
<>
<Button
onClick={() => {
router.push("/");
}}
variant="outline"
>
Cancel
</Button>
<Button
onClick={formMethods.handleSubmit(async (data) => {
try {
await appendRecord(data);
<>
<FormHeader
text="New Record"
rightButtons={
<>
<Button
onClick={() => {
router.push("/");
toast({
title: "Record saved",
status: "success",
duration: 3000,
});
} catch (error) {
toast({
title: "Error saving record",
description: error.message,
status: "error",
isClosable: true,
});
}
})}
>
Save
</Button>
</>
}
/>
}}
variant="outline"
>
Cancel
</Button>
<Button
onClick={formMethods.handleSubmit(async (data) => {
try {
await appendRecord(data);
router.push("/");
toast({
title: "Record saved",
status: "success",
duration: 3000,
});
} catch (error) {
toast({
title: "Error saving record",
description: error.message,
status: "error",
isClosable: true,
});
}
})}
>
Save
</Button>
</>
}
/>
{warningState?.isVisible && (
<FormWarning
{...warningState}
onHide={() =>
setWarningState((current) => ({
...current,
isVisible: false,
}))
}
/>
)}
</>
)}

{form.formState.isLoading ? (
<Progress size="xs" isIndeterminate />
) : errorState ? (
Expand Down
12 changes: 0 additions & 12 deletions components/RecordForm/SlowLoadingToast.jsx

This file was deleted.

23 changes: 23 additions & 0 deletions components/RecordForm/utils/getDefaultValues.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getLatestRecord } from "serverActions/getLatestRecord";

export async function getDefaultValues() {
/**
* Getting initial values for the RecordForm
*
* @returns object to use as react-form-hook defaultValues for RecordForm
* or null if no records in db
*/

const latestRecord = await getLatestRecord();
if (latestRecord === null) return null;

const initialValues = {
date: latestRecord.date,
institutions: latestRecord.institutions.map((institution) => ({
...institution,
isDeleted: false,
})),
};

return initialValues;
}
15 changes: 15 additions & 0 deletions components/RecordForm/utils/isDateInCurrentMonth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export function isInCurrentMonth(unixDateInMs) {
/**
* Check if provided unix date is in current month
*
* @returns boolean
*/

const date = new Date(unixDateInMs);
const now = new Date();

return (
date.getFullYear() === now.getFullYear() &&
date.getMonth() === now.getMonth()
);
}
54 changes: 25 additions & 29 deletions serverActions/getLatestRecord.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,36 @@
/*
Server Action used to get latest record from mongodb.
Latest record then transfomed into format, which is used by react-hook-form in RecordForm
as defaultValues.
*/

// TODO pass errors to RecordForm

"use server";

import connect from "utils/mongooseConnect";
import Record from "models/record";

export async function getLatestRecord() {
try {
await connect();
const latestRecord = await Record.find()
.sort({ createdAt: -1 })
.limit(1)
.exec();
const institutionsList = latestRecord[0]?.institutions.toObject({
transform: function (doc, ret) {
delete ret._id;
return ret;
},
});
/**
* Getting latest record from mongodb
*
* @throws Error retreiving record, when mongoose can't perform Record.find
*
* @returns list of institutions with assets
* to be used by react-hook-form in RecordForm as defaultValues
*/

const initialValues = {
institutions: institutionsList?.map((institution) => ({
...institution,
isDeleted: false,
})),
};
await connect();

return initialValues;
let recordsList = null;
try {
recordsList = await Record.find().sort({ createdAt: -1 }).limit(1).exec();
} catch (error) {
throw error;
throw new Error("Error retreiving record:", error.message);
}

if (recordsList.length === 0) return null;

const latestRecord = recordsList[0].toObject({
transform: function (doc, ret) {
delete ret._id;
delete ret.__v;
return ret;
},
});

return latestRecord;
}
4 changes: 2 additions & 2 deletions utils/mongooseConnect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import mongoose from "mongoose";
async function connect() {
try {
await mongoose.connect(process.env.MONGO_URI);
console.log("Database connected!");
console.info("Database connected");
} catch (error) {
throw ("MongooseConnect error:", error);
throw ("mongooseConnect error:", error.message);
}
}

Expand Down

0 comments on commit 5d6f6df

Please sign in to comment.