RocketChat/Rocket.Chat

View on GitHub
apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsersWithData.tsx

Summary

Maintainability
A
1 hr
Test Coverage
import type { IRoom } from '@rocket.chat/core-typings';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useEndpoint, useTranslation, useToastMessageDispatch } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useState, useEffect } from 'react';

import { useFormatDateAndTime } from '../../../../../hooks/useFormatDateAndTime';
import { useRoomToolbox } from '../../../contexts/RoomToolboxContext';
import InviteUsers from './InviteUsers';

type InviteUsersWithDataProps = {
    rid: IRoom['_id'];
    onClickBack: () => void;
};

const InviteUsersWithData = ({ rid, onClickBack }: InviteUsersWithDataProps): ReactElement => {
    const t = useTranslation();
    const dispatchToastMessage = useToastMessageDispatch();
    const [
        {
            isEditing,
            url,
            caption,
            error,
            daysAndMaxUses: { days, maxUses },
        },
        setInviteState,
    ] = useState({
        isEditing: false,
        daysAndMaxUses: { days: '1', maxUses: '0' },
        url: '',
        caption: '',
        error: undefined as Error | undefined,
    });

    const { closeTab } = useRoomToolbox();
    const format = useFormatDateAndTime();
    const findOrCreateInvite = useEndpoint('POST', '/v1/findOrCreateInvite');

    const handleEdit = useMutableCallback(() => setInviteState((prevState) => ({ ...prevState, isEditing: true })));
    const handleBackToLink = useMutableCallback(() => setInviteState((prevState) => ({ ...prevState, isEditing: false })));

    const linkExpirationText = useMutableCallback((data) => {
        if (!data) {
            return '';
        }

        if (data.expires) {
            const expiration = new Date(data.expires);
            if (data.maxUses) {
                const usesLeft = data.maxUses - data.uses;
                return t('Your_invite_link_will_expire_on__date__or_after__usesLeft__uses', {
                    date: format(expiration),
                    usesLeft,
                });
            }

            return t('Your_invite_link_will_expire_on__date__', { date: format(expiration) });
        }

        if (data.maxUses) {
            const usesLeft = data.maxUses - data.uses;
            return t('Your_invite_link_will_expire_after__usesLeft__uses', { usesLeft });
        }

        return t('Your_invite_link_will_never_expire');
    });

    useEffect(() => {
        (async (): Promise<void> => {
            try {
                const data = await findOrCreateInvite({ rid, days: Number(days), maxUses: Number(maxUses) });
                setInviteState((prevState) => ({ ...prevState, url: data?.url, caption: linkExpirationText(data) }));
                dispatchToastMessage({ type: 'success', message: t('Invite_link_generated') });
            } catch (error) {
                setInviteState((prevState) => ({ ...prevState, error: error as Error }));
            }
        })();
    }, [dispatchToastMessage, t, findOrCreateInvite, linkExpirationText, rid, days, maxUses]);

    const handleGenerateLink = useMutableCallback((daysAndMaxUses) => {
        setInviteState((prevState) => ({ ...prevState, daysAndMaxUses, isEditing: false }));
    });

    return (
        <InviteUsers
            isEditing={isEditing}
            error={error}
            linkText={url}
            captionText={caption}
            daysAndMaxUses={{ days, maxUses }}
            onClose={closeTab}
            onClickBackMembers={onClickBack}
            onClickBackLink={handleBackToLink}
            onClickEdit={handleEdit}
            onClickNewLink={handleGenerateLink}
        />
    );
};

export default InviteUsersWithData;