huridocs/uwazi

View on GitHub
app/react/V2/Routes/Settings/MenuConfig/components/MenuForm.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
/* eslint-disable react/jsx-props-no-spreading */
import React, { useEffect, useState } from 'react';

import { Translate, t } from 'app/I18N';
import { InputField, Select, OptionSchema } from 'app/V2/Components/Forms';
import { useForm } from 'react-hook-form';
import { ClientSettingsLinkSchema } from 'app/apiResponseTypes';
import { Button, Card } from 'app/V2/Components/UI';
import { CheckCircleIcon } from '@heroicons/react/24/outline';
import uniqueID from 'shared/uniqueID';

type SettingsLinkForm = ClientSettingsLinkSchema & { groupId?: string; type: 'link' | 'group' };

interface MenuFormProps {
  closePanel: () => void;
  link?: ClientSettingsLinkSchema & { groupId?: string };
  links?: ClientSettingsLinkSchema[];
  submit: (formValues: ClientSettingsLinkSchema[]) => void;
}

const MenuForm = ({ closePanel, submit, link, links = [] }: MenuFormProps) => {
  const [groups, setGroups] = useState<OptionSchema[]>([]);
  useEffect(() => {
    if (links) {
      const _groups = links
        .filter(_link => _link.type === 'group' && _link.title)
        .map(_link => ({
          label: t('Menu', _link.title, _link.title, false),
          value: _link._id?.toString(),
          key: _link._id?.toString(),
        })) as OptionSchema[];
      const emptyGroup = { label: t('System', 'No Group', 'No Group', false), value: '', key: '-' };
      setGroups([emptyGroup, ..._groups]);
    }
  }, [links]);

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<SettingsLinkForm>({
    values: {
      title: link?.title || '',
      type: link?.type || 'link',
      url: link?.url || '',
      sublinks: link?.sublinks,
      _id: link?._id?.toString(),
      groupId: link?.groupId?.toString(),
    },
    mode: 'onSubmit',
  });

  const updateInGroups = (groupId: string | undefined, linkData: SettingsLinkForm) => {
    let currentLinks = [...links] || [];
    if (!groupId) {
      let linkIndex = currentLinks.findIndex(_link => _link._id === linkData._id);
      linkIndex = linkIndex === -1 ? currentLinks.length : linkIndex;
      currentLinks[linkIndex] = linkData;
    }

    if (groupId) {
      currentLinks = currentLinks.filter(_link => _link._id !== linkData._id);

      currentLinks = currentLinks.map(_link => {
        if (!_link.sublinks) {
          return _link;
        }

        if (_link._id !== groupId) {
          const toBeReturned = {
            ..._link,
            sublinks: _link.sublinks.filter(sublink => sublink._id !== linkData._id),
          };
          return toBeReturned;
        }
        let sublinkIndex = _link.sublinks.findIndex(sublink => sublink._id === linkData._id);
        sublinkIndex = sublinkIndex === -1 ? _link.sublinks.length : sublinkIndex;
        const sublinks = [..._link.sublinks];
        sublinks[sublinkIndex] = linkData;
        return { ..._link, sublinks };
      });
    }

    return currentLinks;
  };

  const onSubmit = (formValues: SettingsLinkForm) => {
    const { groupId, ...linkData } = formValues;

    if (!linkData._id) {
      linkData._id = `tmp_${uniqueID()}`;
    }

    if (linkData.type === 'link') {
      delete linkData.sublinks;
    }

    const updatedLinks = updateInGroups(groupId, linkData);

    submit(updatedLinks);
  };

  const hostname = window?.location?.origin || '';

  return (
    <div className="relative h-full">
      <div className="p-4 mb-4 border rounded-md shadow-sm border-gray-50 bg-primary-100 text-primary-700">
        <div className="flex items-center w-full gap-1 text-base font-semibold">
          <div className="w-5 h-5 text-sm">
            <CheckCircleIcon />
          </div>
          <Translate>Using URLs</Translate>
        </div>
        <div className="force-ltr">
          <Translate>
            If it is an external URL, use a fully formed URL. Ie. http://www.uwazi.io.
          </Translate>
          <br />
          <Translate translationKey="Navigation menu tool tip part 1">
            If it is an internal URL within this website, be sure to delete the first part
          </Translate>{' '}
          ({hostname}),{' '}
          <Translate translationKey="Navigation menu tool tip part 2">
            leaving only a relative URL starting with a slash character. Ie. /some_url.
          </Translate>
        </div>
      </div>
      <form onSubmit={handleSubmit(onSubmit)} id="menu-form">
        <Card
          title={
            link?.type === 'group' ? <Translate>Group</Translate> : <Translate>Link</Translate>
          }
        >
          <div className="flex flex-col gap-4">
            <InputField
              id="link-title"
              data-testid="menu-form-link-title"
              label={<Translate>Title</Translate>}
              {...register('title', { required: true })}
              hasErrors={!!errors.title}
            />
            {link?.type === 'link' && (
              <>
                <InputField
                  id="link-url"
                  data-testid="menu-form-link-url"
                  label={<Translate>URL</Translate>}
                  {...register('url', { required: true })}
                  hasErrors={!!errors.url}
                />
                <Select
                  id="link-group"
                  data-testid="menu-form-link-group"
                  label={<Translate>Group</Translate>}
                  {...register('groupId')}
                  options={groups}
                />
              </>
            )}
          </div>
        </Card>
      </form>
      <div className="absolute bottom-0 flex w-full gap-2 px-4 py-3">
        <Button
          styling="light"
          onClick={closePanel}
          className="grow"
          data-testid="menu-form-cancel"
        >
          <Translate>Cancel</Translate>
        </Button>
        <Button className="grow" type="submit" form="menu-form" data-testid="menu-form-submit">
          {link?.title ? <Translate>Update</Translate> : <Translate>Add</Translate>}
        </Button>
      </div>
    </div>
  );
};

export { MenuForm };