dashpresshq/dashpress

View on GitHub
src/frontend/views/data/Details/DetailsView.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
A
100%
import { Fragment } from "react";

import { ViewStateMachine } from "@/components/app/view-state-machine";
import { Skeleton } from "@/components/ui/skeleton";
import {
  useAppConfiguration,
  useEntityConfiguration,
} from "@/frontend/hooks/configuration/configuration.store";
import { useEntityDataDetails } from "@/frontend/hooks/data/data.store";
import {
  useEntityCrudFields,
  useEntityFieldLabels,
  useEntityFieldSelections,
  useProcessedEntityFieldTypes,
} from "@/frontend/hooks/entity/entity.config";
import { useEntityToOneReferenceFields } from "@/frontend/hooks/entity/entity.store";
import { useEvaluateScriptContext } from "@/frontend/hooks/scripts";
import { DataStates } from "@/frontend/lib/data/types";

import { evalutePresentationScript } from "../evaluatePresentationScript";
import { useEntityViewStateMachine } from "../hooks/useEntityViewStateMachine";
import { PortalColumnRender } from "../Table/portal";
import { viewSpecialDataTypes } from "../viewSpecialDataTypes";
import { PreDataDetails } from "./portal";

export function EntityDetailsView({
  entityId,
  entity,
  displayFrom,
}: {
  entityId: string;
  entity: string;
  displayFrom: "details" | "canvas";
}) {
  const dataDetails = useEntityDataDetails({ entity, entityId });
  const entityFieldTypes = useProcessedEntityFieldTypes(entity);
  const entityCrudFields = useEntityCrudFields(entity, "details");
  const defaultDateFormat = useAppConfiguration("default_date_format");
  const getEntityFieldLabels = useEntityFieldLabels(entity);
  const evaluateScriptContext = useEvaluateScriptContext();
  const entityToOneReferenceFields = useEntityToOneReferenceFields(entity);
  const entityFieldSelections = useEntityFieldSelections(entity);
  const entityPresentationScript = useEntityConfiguration(
    "entity_presentation_script",
    entity
  );

  const error =
    dataDetails.error ||
    entityCrudFields.error ||
    entityFieldTypes.error ||
    defaultDateFormat.error ||
    entityPresentationScript.error ||
    entityToOneReferenceFields.error;

  const isLoading =
    dataDetails.isLoading ||
    defaultDateFormat.isLoading ||
    entityToOneReferenceFields.isLoading ||
    entityPresentationScript.isLoading ||
    entityCrudFields.isLoading;

  const viewState = useEntityViewStateMachine({
    isLoading,
    error,
    crudAction: "details",
    entity,
  });

  return (
    <ViewStateMachine
      loading={viewState.type === DataStates.Loading || !entityId}
      error={
        viewState.type === DataStates.Error ? viewState.message : undefined
      }
      loader={
        <>
          {Array.from({ length: 7 }, (_, k) => k).map((key) => (
            <Fragment key={key}>
              <Skeleton className="mb-2 h-4 w-24" />
              <Skeleton className="mb-4 h-5 max-w-xs" />
            </Fragment>
          ))}
        </>
      }
    >
      <PreDataDetails entity={entity} entityId={entityId} />
      <div aria-label="Details Section">
        {entityCrudFields.data.map(({ name }) => {
          const rawValue = dataDetails?.data?.[name];

          const value = evalutePresentationScript(
            entityPresentationScript.data.script,
            {
              field: name,
              from: "details",
              row: dataDetails?.data,
              value: rawValue,
              ...evaluateScriptContext,
            }
          );

          const specialDataTypeRender = viewSpecialDataTypes({
            fieldName: name,
            value,
            entityToOneReferenceFields: entityToOneReferenceFields.data,
            entityFieldSelections,
            entityFieldTypes,
            options: {
              displayFrom,
              defaultDateFormat: defaultDateFormat.data,
            },
          });

          const contentToRender = specialDataTypeRender || (
            <span className="break-words">
              {typeof value === "object" ? JSON.stringify(value) : value}
            </span>
          );

          return (
            <div
              className="[&_.show-on-hover]:opacity-0 [&_.show-on-hover]:hover:opacity-100"
              key={name}
            >
              <p className="text-xs font-semibold">
                {getEntityFieldLabels(name)}
              </p>
              <p className="mb-2 text-sm">
                <PortalColumnRender
                  {...{
                    column: name,
                    value: rawValue,
                    entity,
                    entityId,
                  }}
                >
                  {contentToRender}
                </PortalColumnRender>
              </p>
            </div>
          );
        })}
      </div>
    </ViewStateMachine>
  );
}