teableio/teable

View on GitHub
packages/sdk/src/context/table/LinkViewProvider.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import { useQuery } from '@tanstack/react-query';
import { getShareView } from '@teable/openapi';
import { map } from 'lodash';
import React, { useMemo } from 'react';
import { ReactQueryKeys } from '../../config/react-query-keys';
import { useFields } from '../../hooks';
import { addQueryParamsToWebSocketUrl } from '../../utils/urlParams';
import { AnchorContext } from '../anchor/AnchorContext';
import { ConnectionProvider } from '../app';
import { getWsPath } from '../app/useConnection';
import { FieldProvider } from '../field';
import { SearchProvider } from '../query';
import { RecordProvider } from '../record';
import { TablePermissionContext, TablePermissionContextDefaultValue } from '../table-permission';
import { ShareViewContext } from './ShareViewContext';

export interface ILinkViewProvider {
  linkFieldId: string;
  linkBaseId?: string;
  fallback?: React.ReactNode;
  children: React.ReactNode;
}

const ReadonlyFieldsPermissionProvider = ({ children }: { children: React.ReactNode }) => {
  const fields = useFields({ withHidden: true, withDenied: true });
  const fieldIds = map(fields, 'id');

  const value = useMemo(() => {
    return {
      ...TablePermissionContextDefaultValue,
      field: {
        create: false,
        fields: fieldIds.reduce(
          (acc, fieldId) => {
            acc[fieldId] = {
              'field|read': true,
            };
            return acc;
          },
          {} as Record<string, Record<string, boolean>>
        ),
      },
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [JSON.stringify(fieldIds)]);

  return (
    <TablePermissionContext.Provider value={value}>{children}</TablePermissionContext.Provider>
  );
};

export const LinkViewProvider: React.FC<ILinkViewProvider> = ({
  linkFieldId,
  linkBaseId,
  children,
  fallback,
}) => {
  const { data: shareData, isLoading } = useQuery({
    queryKey: ReactQueryKeys.shareView(linkFieldId),
    enabled: Boolean(linkFieldId),
    queryFn: () => getShareView(linkFieldId).then(({ data }) => data),
  });

  const wsPath = useMemo(() => {
    if (typeof window === 'object') {
      return addQueryParamsToWebSocketUrl(getWsPath(), { shareId: linkFieldId });
    }
    return undefined;
  }, [linkFieldId]);

  if (isLoading || !linkFieldId || !shareData) {
    return fallback;
  }

  const { tableId, viewId, fields } = shareData;
  return (
    <ConnectionProvider wsPath={wsPath}>
      <ShareViewContext.Provider value={shareData}>
        <AnchorContext.Provider value={{ baseId: linkBaseId, tableId, viewId }}>
          <SearchProvider>
            <FieldProvider fallback={fallback} serverSideData={fields}>
              <ReadonlyFieldsPermissionProvider>
                <RecordProvider>{children}</RecordProvider>
              </ReadonlyFieldsPermissionProvider>
            </FieldProvider>
          </SearchProvider>
        </AnchorContext.Provider>
      </ShareViewContext.Provider>
    </ConnectionProvider>
  );
};