Skip to content

Instantly share code, notes, and snippets.

@AlexandroMtzG
Created February 6, 2023 04:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexandroMtzG/cd15eecf5081f3d4ff38b70342710605 to your computer and use it in GitHub Desktop.
Save AlexandroMtzG/cd15eecf5081f3d4ff38b70342710605 to your computer and use it in GitHub Desktop.
// Route View (Client component): Table with rows and quick row overview
// Date: 2023-02-04
// Version: SaasRock v0.8.2
import { useLoaderData, useActionData, useSearchParams, Link, useNavigate } from "@remix-run/react";
import { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import ButtonPrimary from "~/components/ui/buttons/ButtonPrimary";
import ExternalLinkEmptyIcon from "~/components/ui/icons/ExternalLinkEmptyIcon";
import IndexPageLayout from "~/components/ui/layouts/IndexPageLayout";
import SlideOverWideEmpty from "~/components/ui/slideOvers/SlideOverWideEmpty";
import DocumentForm from "../../components/DocumentForm";
import { DocumentDto } from "../../dtos/DocumentDto";
import { DocumentRoutesIndexApi } from "../api/DocumentRoutes.Index.Api";
import AccountDocuments from "~/modules/documents/components/AccountDocuments";
import { useAppData } from "~/utils/data/useAppData";
import InputSearch from "~/components/ui/input/InputSearch";
import InputSelect from "~/components/ui/input/InputSelect";
import { DocumentTypeDto } from "~/modules/codeGeneratorTests/document-types/dtos/DocumentTypeDto";
import DocumentTypeHelper from "~/modules/documents/helpers/DocumentTypeHelper";
export default function DocumentRoutesIndexView() {
const { t } = useTranslation();
const appData = useAppData();
const data = useLoaderData<DocumentRoutesIndexApi.LoaderData>();
const actionData = useActionData<{ error?: string; success?: string }>();
const [searchParams, setSearchParams] = useSearchParams();
const navigate = useNavigate();
const [searchInput, setSearchInput] = useState<string>("");
const [overviewItem, setOverviewItem] = useState<DocumentDto>();
useEffect(() => {
setOverviewItem(data.overviewItem ?? undefined);
}, [data.overviewItem]);
function filteredTypes() {
return appData.documentTypes.filter(
(t) => t.name.toLowerCase().includes(searchInput.toLowerCase()) || t.description.toLowerCase().includes(searchInput.toLowerCase())
);
}
function onClick(type: DocumentTypeDto, year: number, period: number) {
const existingDocument = data.items.find((d) => d.typeId === type.row.id && d.year === year && d.period === period);
if (existingDocument) {
searchParams.set("overview", existingDocument.row.id);
setSearchParams(searchParams);
} else {
navigate(`new?typeId=${type.row.id}&year=${year}&period=${period}`);
}
}
function getYear() {
if (searchParams.get("year")) {
const year = Number(searchParams.get("year")?.toString());
const possibleYears = DocumentTypeHelper.getPossibleYears();
if (possibleYears.find((f) => f.value === year)) {
return year;
}
}
return new Date().getFullYear();
}
return (
<IndexPageLayout
title={t("Documents")}
buttons={
<>
<ButtonPrimary to="new">{t("shared.new")}</ButtonPrimary>
</>
}
>
<div className="flex space-x-2">
<div className="w-full">
<InputSearch value={searchInput} setValue={setSearchInput} />
</div>
<div className="w-32">
<InputSelect
value={getYear()}
options={DocumentTypeHelper.getPossibleYears()}
setValue={(e) => {
if (Number(e) === new Date().getFullYear()) {
searchParams.delete("year");
} else {
searchParams.set("year", Number(e).toString());
}
setSearchParams(searchParams);
}}
/>
</div>
</div>
<AccountDocuments year={getYear()} types={filteredTypes()} documents={data.items} onClick={onClick} />
<SlideOverWideEmpty
withTitle={false}
withClose={false}
title={t("Document")}
open={!!searchParams.get("overview")?.toString()}
onClose={() => {
searchParams.delete("overview");
setSearchParams(searchParams);
setTimeout(() => {
setOverviewItem(undefined);
}, 100);
}}
className="sm:max-w-md"
buttons={
<>
<Link
to={overviewItem?.row.id ?? ""}
className="rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2"
>
<span className="sr-only">Close panel</span>
<ExternalLinkEmptyIcon className="h-6 w-6" aria-hidden="true" />
</Link>
</>
}
>
{!overviewItem ? <div>{t("shared.loading")}...</div> : <DocumentForm item={overviewItem} actionData={actionData} />}
</SlideOverWideEmpty>
</IndexPageLayout>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment