All files / libs/lti/views/participant-enrollment/src/lib/enrollment-content/widgets/document EnrollmentEmbeddedDocumentWidgetPresentation.tsx

0% Statements 0/117
0% Branches 0/1
0% Functions 0/1
0% Lines 0/117

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118                                                                                                                                                                                                                                           
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { IconCheckbox } from '@tabler/icons-react';
import { memo, useEffect, useMemo, type ReactNode } from 'react';
import { FormattedMessage } from 'react-intl';
import { match, P } from 'ts-pattern';

import { Button, Group, Skeleton, Stack, Tooltip, Typography } from '@allshares/studio-design-system';
import { DocumentSignatureRequiredBadge, DocumentSignedBadge } from '@amalia/lti/components';

type EnrollmentEmbeddedDocumentWidgetPresentationProps = {
  readonly documentBlob?: Blob;
  readonly documentName?: string;
  readonly isLoading: boolean;
  readonly isSignatureRequired: boolean;
  readonly isSignPending?: boolean;
  readonly isSigningDisabled?: boolean;
  readonly onSign?: () => void;
  readonly signedAt?: Date | null;
  readonly tooltipContent?: ReactNode;
};

const EmbeddedPdfIframe = styled.iframe`
  border: none;
  width: 100%;
  min-height: 720px;
`;

export const EnrollmentEmbeddedDocumentWidgetPresentation = memo(function EnrollmentEmbeddedDocumentWidgetPresentation({
  documentBlob,
  documentName,
  isLoading,
  isSignatureRequired,
  isSignPending = false,
  isSigningDisabled = false,
  onSign,
  signedAt,
  tooltipContent,
}: EnrollmentEmbeddedDocumentWidgetPresentationProps) {
  const documentUrl = useMemo(
    () => (documentBlob ? URL.createObjectURL(new Blob([documentBlob], { type: 'application/pdf' })) : null),
    [documentBlob],
  );

  useEffect(
    () => () => {
      if (documentUrl) {
        URL.revokeObjectURL(documentUrl);
      }
    },
    [documentUrl],
  );

  return (
    <Stack
      gap={40}
      css={css`
        width: 100%;
      `}
    >
      <Skeleton visible={isLoading}>
        <Group
          align="flex-start"
          gap={16}
          justify="space-between"
        >
          <Group
            align="center"
            gap={12}
          >
            <Typography variant="bodyLargeMedium">{documentName}</Typography>

            {match({ isSignatureRequired, signedAt })
              .with({ signedAt: P.nonNullable }, (props) => <DocumentSignedBadge signedAt={props.signedAt} />)
              .with({ isSignatureRequired: true }, () => <DocumentSignatureRequiredBadge />)
              .otherwise(() => null)}
          </Group>

          {!!isSignatureRequired && !signedAt && (
            <Tooltip content={tooltipContent}>
              <Button
                disabled={isSigningDisabled}
                icon={<IconCheckbox />}
                isLoading={isSignPending}
                size="large"
                variant="primary"
                onClick={onSign}
              >
                <FormattedMessage defaultMessage="Mark as signed" />
              </Button>
            </Tooltip>
          )}
        </Group>
      </Skeleton>

      <div
        css={css`
          width: 100%;
          margin: 0 auto;
        `}
      >
        {documentUrl ? (
          <EmbeddedPdfIframe
            src={documentUrl}
            title={documentName}
          />
        ) : (
          <Skeleton
            css={css`
              min-height: 720px;
            `}
          />
        )}
      </div>
    </Stack>
  );
});