|
- "use client";
- import React, { useCallback, useEffect, useMemo, useState } from "react";
- import { useRouter, useSearchParams } from "next/navigation";
- import {
- Add,
- Clear,
- PersonAdd,
- PersonRemove,
- Remove,
- Search,
- } from "@mui/icons-material";
- import { useTranslation } from "react-i18next";
- import {
- FieldErrors,
- FormProvider,
- SubmitErrorHandler,
- SubmitHandler,
- useForm,
- useFormContext,
- } from "react-hook-form";
- import {
- Box,
- Card,
- CardContent,
- Grid,
- IconButton,
- InputAdornment,
- Stack,
- Tab,
- Tabs,
- TabsProps,
- TextField,
- Typography,
- } from "@mui/material";
- import { differenceBy } from "lodash";
- import { UserInputs } from "@/app/api/user/actions";
- import { auth } from "@/app/api/group/actions";
- import SearchResults, { Column } from "../SearchResults";
-
- export interface Props {
- auths: auth[];
- }
-
- const AuthAllocation: React.FC<Props> = ({ auths }) => {
- const { t } = useTranslation();
- const searchParams = useSearchParams();
- const id = parseInt(searchParams.get("id") || "0");
- const {
- setValue,
- getValues,
- formState: { defaultValues },
- reset,
- resetField,
- } = useFormContext<UserInputs>();
- const initialAuths = auths.map((u) => ({ ...u })).sort((a, b) => a.id - b.id);
- const [filteredAuths, setFilteredAuths] = useState(initialAuths);
- const [selectedAuths, setSelectedAuths] = useState<typeof filteredAuths>(
- () => {
- return filteredAuths.filter(
- (s) => getValues("addAuthIds")?.includes(s.id)
- );
- }
- );
- const [removeAuthIds, setRemoveAuthIds] = useState<number[]>([]);
-
- // Adding / Removing Auth
- const addAuth = useCallback((auth: auth) => {
- setSelectedAuths((a) => [...a, auth]);
- }, []);
- const removeAuth = useCallback((auth: auth) => {
- setSelectedAuths((a) => a.filter((a) => a.id !== auth.id));
- setRemoveAuthIds((prevIds) => [...prevIds, auth.id]);
- }, []);
-
- const clearAuth = useCallback(() => {
- if (defaultValues !== undefined) {
- resetField("addAuthIds");
- setSelectedAuths(
- initialAuths.filter(
- (auth) => defaultValues.addAuthIds?.includes(auth.id)
- )
- );
- }
- }, [defaultValues]);
-
- // Sync with form
- useEffect(() => {
- setValue(
- "addAuthIds",
- selectedAuths.map((a) => a.id)
- );
- setValue("removeAuthIds", removeAuthIds);
- }, [selectedAuths, removeAuthIds, setValue]);
-
- const AuthPoolColumns = useMemo<Column<auth>[]>(
- () => [
- {
- label: t("Add"),
- name: "id",
- onClick: addAuth,
- buttonIcon: <Add />,
- },
- { label: t("authority"), name: "authority" },
- { label: t("description"), name: "name" },
- ],
- [addAuth, t]
- );
-
- const allocatedAuthColumns = useMemo<Column<auth>[]>(
- () => [
- {
- label: t("Remove"),
- name: "id",
- onClick: removeAuth,
- buttonIcon: <Remove color="warning" />,
- },
- { label: t("authority"), name: "authority" },
- { label: t("description"), name: "name" },
- ],
- [removeAuth, selectedAuths, t]
- );
-
- const [query, setQuery] = React.useState("");
- const onQueryInputChange = React.useCallback<
- React.ChangeEventHandler<HTMLInputElement>
- >((e) => {
- setQuery(e.target.value);
- }, []);
- const clearQueryInput = React.useCallback(() => {
- setQuery("");
- }, []);
-
- React.useEffect(() => {
- setFilteredAuths(
- initialAuths.filter((a) =>
- (
- a.authority.toLowerCase().includes(query.toLowerCase()) ||
- a.name?.toLowerCase().includes(query.toLowerCase())
- )
- )
- );
- }, [auths, query]);
-
- const resetAuth = React.useCallback(() => {
- clearQueryInput();
- clearAuth();
- }, [clearQueryInput, clearAuth]);
-
- const formProps = useForm({});
-
- // Tab related
- const [tabIndex, setTabIndex] = React.useState(0);
- const handleTabChange = React.useCallback<NonNullable<TabsProps["onChange"]>>(
- (_e, newValue) => {
- setTabIndex(newValue);
- },
- []
- );
-
- return (
- <>
- <FormProvider {...formProps}>
- <Card sx={{ display: "block" }}>
- <CardContent
- sx={{ display: "flex", flexDirection: "column", gap: 1 }}
- >
- <Stack gap={2}>
- <Typography variant="overline" display="block">
- {t("Authority")}
- </Typography>
- <Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
- <Grid item xs={6} display="flex" alignItems="center">
- <Search sx={{ marginInlineEnd: 1 }} />
- <TextField
- variant="standard"
- fullWidth
- onChange={onQueryInputChange}
- value={query}
- placeholder={t(
- "Search by Authority or description or position."
- )}
- InputProps={{
- endAdornment: query && (
- <InputAdornment position="end">
- <IconButton onClick={clearQueryInput}>
- <Clear />
- </IconButton>
- </InputAdornment>
- ),
- }}
- />
- </Grid>
- </Grid>
- <Tabs value={tabIndex} onChange={handleTabChange}>
- <Tab label={t("Authority Pool")} />
- <Tab
- label={`${t("Allocated Authority")} (${
- selectedAuths.length
- })`}
- />
- </Tabs>
- <Box sx={{ marginInline: -3 }}>
- {tabIndex === 0 && (
- <SearchResults
- noWrapper
- items={differenceBy(filteredAuths, selectedAuths, "id")}
- columns={AuthPoolColumns}
- />
- )}
- {tabIndex === 1 && (
- <SearchResults
- noWrapper
- items={selectedAuths}
- columns={allocatedAuthColumns}
- />
- )}
- </Box>
- </Stack>
- </CardContent>
- </Card>
- </FormProvider>
- </>
- );
- };
- export default AuthAllocation;
|