dashpresshq/dashpress

View on GitHub
src/frontend/views/entity/Fields/FieldsSelection.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
F
0%
import { msg } from "@lingui/macro";
import { isNotEmpty } from "class-validator";
import arrayMutators from "final-form-arrays";
import { Fragment, useState } from "react";
import { Field, Form } from "react-final-form";
import { FieldArray } from "react-final-form-arrays";

import { DELETE_BUTTON_PROPS } from "@/components/app/button/constants";
import { FormButton } from "@/components/app/button/form";
import { SoftButton } from "@/components/app/button/soft";
import { SpectrumColorInputField } from "@/components/app/form/input/spectrum";
import { FormSwitch } from "@/components/app/form/input/switch";
import { FormInput } from "@/components/app/form/input/text";
import { Card, CardContent } from "@/components/ui/card";
import { SPECTRUM_COLORS } from "@/components/ui/spectrum";
import { useAppConfigurationDomainMessages } from "@/frontend/hooks/configuration/configuration.constant";
import { composeValidators, required } from "@/frontend/lib/validations";
import { isUseColorsFlagOn } from "@/shared/logic/entities/selection.utils";
import type {
  EntityTypesForSelection,
  IColorableSelection,
} from "@/shared/types/ui";

// Reference is a special case basically only use color

const ManagableEntities = ["selection"];

interface IProps {
  field: string;
  selections: IColorableSelection[];
  entityType: EntityTypesForSelection;
  onSubmit: (values: IColorableSelection[]) => void;
}

const replaceForIntialValues = (selections: IColorableSelection[]) => {
  return selections.map((selection) => ({
    ...selection,
    label: { ...selection.label, message: selection.label.values?.[0] },
  }));
};

const replaceForSubmission = (selections: IColorableSelection[]) => {
  return selections.map((selection) => ({
    ...selection,
    label: {
      ...selection.label,
      message: "{0}",
      values: { 0: selection.label.message },
    },
  }));
};

export function FieldSelectionCanvas({
  field,
  onSubmit,
  entityType,
  selections,
}: IProps) {
  const [useColors, setUseColors] = useState(isUseColorsFlagOn(selections));
  const domainMessages = useAppConfigurationDomainMessages("entity_selections");
  if (!field) {
    return null;
  }

  return (
    <Form
      onSubmit={(values: { selections: IColorableSelection[] }) => {
        onSubmit(replaceForSubmission(values.selections));
      }}
      mutators={{
        ...arrayMutators,
      }}
      initialValues={{ selections: replaceForIntialValues(selections) }}
      render={({ handleSubmit, values, pristine, form }) => (
        <form onSubmit={handleSubmit} className="mb-3">
          {entityType !== "boolean" && (
            <FormSwitch
              label={msg`Use Colors`}
              name="use-colors"
              value={useColors}
              onChange={(newUseColorValue) => {
                setUseColors(newUseColorValue);
                form.change(
                  "selections",
                  (
                    values as { selections: IColorableSelection[] }
                  ).selections.map((selection, index) => ({
                    ...selection,
                    color: newUseColorValue
                      ? SPECTRUM_COLORS[index % SPECTRUM_COLORS.length]
                      : undefined,
                  }))
                );
              }}
            />
          )}
          <FieldArray name="selections">
            {({ fields }) => (
              <>
                {fields.map((name, index) => (
                  <Fragment key={name}>
                    <Card className="mt-3">
                      <CardContent>
                        <Field
                          name={`${name}.value`}
                          validate={composeValidators((value) =>
                            isNotEmpty(value) ? undefined : "Required"
                          )}
                          validateFields={[]}
                        >
                          {({ meta, input }) => (
                            <FormInput
                              disabled={!ManagableEntities.includes(entityType)}
                              label={msg`Value`}
                              required={ManagableEntities.includes(entityType)}
                              input={input}
                              meta={meta}
                            />
                          )}
                        </Field>
                        <Field
                          name={`${name}.label.message`}
                          validate={required}
                          validateFields={[]}
                        >
                          {({ meta, input }) => (
                            <FormInput
                              label={msg`Label`}
                              required
                              input={input}
                              meta={meta}
                            />
                          )}
                        </Field>
                        <div className="flex justify-between">
                          {useColors ? (
                            <Field
                              name={`${name}.color`}
                              validate={required}
                              validateFields={[]}
                            >
                              {({ input, meta }) => (
                                <SpectrumColorInputField
                                  formInput={{ input, meta }}
                                />
                              )}
                            </Field>
                          ) : (
                            <div />
                          )}
                          {ManagableEntities.includes(entityType) && (
                            <SoftButton
                              size="icon"
                              {...DELETE_BUTTON_PROPS({
                                action: () => {
                                  fields.remove(index);
                                },
                                isMakingRequest: false,
                                label: msg`Delete Selection`,
                                shouldConfirmAlert: undefined,
                              })}
                            />
                          )}
                        </div>
                      </CardContent>
                    </Card>
                  </Fragment>
                ))}

                <div className="mt-3 flex justify-between">
                  {ManagableEntities.includes(entityType) && (
                    <SoftButton
                      systemIcon="Plus"
                      label={msg`Add New Option`}
                      size={null}
                      action={() => {
                        fields.push({
                          label: msg``,
                          value: "",
                          color: useColors
                            ? SPECTRUM_COLORS[
                                fields.length % SPECTRUM_COLORS.length
                              ]
                            : undefined,
                        } as IColorableSelection);
                      }}
                    />
                  )}

                  <FormButton
                    systemIcon="Save"
                    isMakingRequest={false}
                    text={domainMessages.FORM_LANG.UPSERT}
                    disabled={pristine}
                  />
                </div>
              </>
            )}
          </FieldArray>
        </form>
      )}
    />
  );
}