Skip to content

Commit

Permalink
feat: useForm and enable academic year selection
Browse files Browse the repository at this point in the history
  • Loading branch information
Gum-Joe committed Aug 14, 2024
1 parent dc432ab commit 0ad967e
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 39 deletions.
15 changes: 12 additions & 3 deletions collection/app/(app)/PageActions.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { AcademicYear } from "@docsoc/eactivities";
import { Paper, MultiSelect, Group, Button } from "@mantine/core";
import { UseFormReturnType } from "@mantine/form";
import React from "react";

export const PageActions = () => {
export const PageActions = ({
formHook,
academicYears,
}: {
formHook: UseFormReturnType<{ academicYears: AcademicYear[]; shortcode: string }>;
academicYears: string[];
}) => {
return (
<Paper p="lg" withBorder>
<Group justify="space-between">
<MultiSelect
label="Show purchases from academic years"
description=" "
defaultValue={["23-24"]}
data={["23-24", "24-25"]}
key={formHook.key("academicYears")}
data={academicYears}
{...formHook.getInputProps("academicYears")}
/>
<Button>Import data from eActivities</Button>{" "}
</Group>
Expand Down
86 changes: 51 additions & 35 deletions collection/app/(app)/UserSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,31 @@
import { UserInfo } from "@/components/UserInfo";
import { BuyerItemsTable } from "@/components/tables/BuyerItemsTable";
import { OrderResponse } from "@/lib/crud/purchase";
import { AcademicYear } from "@docsoc/eactivities";
import { Group, TextInput, Button, Alert, Container, Center, Stack } from "@mantine/core";
import { useForm } from "@mantine/form";
import { useRouter, useSearchParams } from "next/navigation";
import React, { useCallback, useEffect, useMemo, useState, useTransition } from "react";
import { FaSearch, FaTimesCircle } from "react-icons/fa";

import { PageActions } from "./PageActions";

export const UserSearch = () => {
interface UserSearchProps {
currentAcademicYear: AcademicYear;
validAcaemicYears: string[];
}

export const UserSearch: React.FC<UserSearchProps> = ({
currentAcademicYear,
validAcaemicYears,
}) => {
const [error, setError] = useState<string | null>(null);
const [purchases, setPurchases] = useState<OrderResponse[]>([]);
const [isPending, startTransition] = useTransition();

// Need to allow clearing on route change to home
const [shortcodeFormState, setSetshortcodeFormState] = useState("");

const searchParams = useSearchParams();
const router = useRouter();
const shortcode = useMemo(() => searchParams.get("shortcode") || "", [searchParams]);
const shortcodeURLParam = useMemo(() => searchParams.get("shortcode") || "", [searchParams]);

const fetchPurchases = useCallback(async (shortcode: string) => {
const res = await fetch(`/api/purchases/${shortcode}`, {
Expand All @@ -40,42 +47,45 @@ export const UserSearch = () => {
}
}, []);

// Form
// 2 fields: shortcode & academic year purcahses.
// Default value of shortcode is from the URL if possible
const form = useForm({
initialValues: { shortcode: shortcodeURLParam, academicYears: [currentAcademicYear] },

validate: {
shortcode: (value) => {
if (typeof value !== "string") return "Please enter a shortcode";
return;
},
},
});
useEffect(() => {
if (shortcode) {
setSetshortcodeFormState(shortcode);
fetchPurchases(shortcode);
if (shortcodeURLParam) {
fetchPurchases(shortcodeURLParam);
} else {
setPurchases([]);
setSetshortcodeFormState("");
form.setFieldValue("shortcode", "");
}
}, [shortcode, fetchPurchases]);
// can't add form as would cause infinite loop
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [shortcodeURLParam, fetchPurchases]);

const submitAction = useCallback(
async (formState: FormData) => {
setError(null);
const shortcode = formState.get("shortcode")?.toString().trim();
({ shortcode }: { shortcode: string }) => {
startTransition(() => {
setError(null);

if (typeof shortcode !== "string") {
setError("Please enter a shortcode");
return;
}

router.push("/?shortcode=" + shortcode);
router.push("/?shortcode=" + shortcode);
});
},
[router],
);

const submitActionWithTransition = useCallback(
(formState: FormData) => {
startTransition(async () => await submitAction(formState));
},
[submitAction],
);

return (
<Container w="70%">
<Stack gap="lg">
<PageActions />
<PageActions academicYears={validAcaemicYears} formHook={form} />
<Center>
<Stack w="90%" justify="centre" align="centre">
<form
Expand All @@ -85,7 +95,8 @@ export const UserSearch = () => {
justifyContent: "center",
alignItems: "center",
}}
action={submitActionWithTransition}
onSubmit={form.onSubmit(submitAction)}
action={() => {}}
>
<Group w="100%">
<TextInput
Expand All @@ -96,14 +107,19 @@ export const UserSearch = () => {
required
name="shortcode"
id="shortcode"
onChange={(e) =>
setSetshortcodeFormState(e.currentTarget.value)
}
value={shortcodeFormState}
{...form.getInputProps("shortcode")}
/>
<Button loading={isPending} type="submit">
Submit
</Button>
<Button
color="pink"
onClick={() => {
router.push("/");
}}
>
Clear
</Button>
</Group>
</form>
{error && (
Expand All @@ -114,14 +130,14 @@ export const UserSearch = () => {
</Stack>
</Center>
<Center>
<UserInfo shortcode={shortcode} />
<UserInfo shortcode={shortcodeURLParam} />
</Center>

{!error ? (
<BuyerItemsTable
shortcode={shortcode}
shortcode={shortcodeURLParam}
purchases={purchases}
refresh={() => fetchPurchases(shortcode)}
refresh={() => fetchPurchases(shortcodeURLParam)}
/>
) : (
<></>
Expand Down
11 changes: 10 additions & 1 deletion collection/app/(app)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import { auth } from "@/auth";
import { getAcademicYear } from "@/lib/config";
import { Stack, Title } from "@mantine/core";
import { redirect } from "next/navigation";
import React from "react";

import { UserSearch } from "./UserSearch";
import { getAcademicYearsInDB } from "@/lib/crud/academic-year";

export default async function Index() {
const session = await auth();

if (!session) redirect("/auth/login");

// Get academic years
const currentAcademicYear = await getAcademicYear();
const academicYears = await getAcademicYearsInDB();

return (
<Stack gap="lg">
<Title order={1}>DoCSoc Collection System</Title>
<UserSearch />
<UserSearch
currentAcademicYear={currentAcademicYear}
validAcaemicYears={academicYears}
/>
</Stack>
);
}
7 changes: 7 additions & 0 deletions collection/lib/crud/academic-year.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use server";

import prisma from "../db";

export async function getAcademicYearsInDB() {
return (await prisma.academicYear.findMany()).map((year) => year.year);
}

0 comments on commit 0ad967e

Please sign in to comment.