@/store#useAction TypeScript Examples

The following examples show how to use @/store#useAction. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: snackbar.component.tsx    From passwords-fountain with MIT License 6 votes vote down vote up
Snackbar: TypedComponent<Props> = () => {
    const iconSize = 44;
    const [currentMessage] = useSelector(selectSnackbarMessages);
    const hideSnackbar = useAction(overlayActions.hideSnackbar);

    useEffect(() => {
        setTimeout(() => {
            hideSnackbar(currentMessage.id);
        }, snackbarVisibilityTime);
    }, [currentMessage]);

    return (
        <Wrapper type={currentMessage.type}>
            <IconWrapper>
                <Icon
                    name={currentMessage.type}
                    width={iconSize}
                    height={iconSize}
                />
            </IconWrapper>
            <TextWrapper>
                <ErrorType>
                    <Text>{currentMessage.type}</Text>
                </ErrorType>
                <span>{' - '}</span>
                <Text>{currentMessage.messageKey}</Text>
            </TextWrapper>
        </Wrapper>
    );
}
Example #2
Source File: optionsPanel.component.tsx    From passwords-fountain with MIT License 6 votes vote down vote up
OptionsPanel: TypedComponent<Props> = () => {
    const currentVariantName = useSelector(selectCurrentOptionPanelVariantName);
    const setCurrentVariantName = useAction(
        passwordListActions.switchOptionPanelVariant
    );

    const variants: VariantInstances = {
        connectCollapsed: OptionsPanelConnectCollapsed,
        connectExpanded: OptionsPanelConnectExpanded,
        entityFormCollapsed: OptionsPanelEntityFormCollapsed,
        entityFormExpanded: OptionsPanelEntityFormExpanded,
    };

    const CurrentVariant =
        variants[currentVariantName as OptionsPanelVariantName];
    return (
        <Wrapper currentVariantName={currentVariantName}>
            <CurrentVariant switchCurrentVariantName={setCurrentVariantName} />
        </Wrapper>
    );
}
Example #3
Source File: app.tsx    From passwords-fountain with MIT License 5 votes vote down vote up
App: TypedComponent<Props> = () => {
    const isSnackbarVisible = useSelector(selectIsSnackbarVisible);
    const isLoaderVisible = useSelector(selectIsGlobalLoaderVisible);
    const showSnackbar = useAction(overlayActions.showSnackbar);
    const onOffline = (): void => {
        showSnackbar('snackbar.noInternetConnection', 'info');
    };
    const onOnline = (): void => {
        showSnackbar('snackbar.internetIsBack', 'info');
    };

    useEffect(() => {
        window.addEventListener('offline', onOffline);
        window.addEventListener('online', onOnline);

        return (): void => {
            window.removeEventListener('offline', onOffline);
            window.removeEventListener('online', onOnline);
        };
    }, []);

    return (
        <Wrapper>
            <Header>
                <NavBar />
            </Header>
            <PageWrapper>
                <Router>
                    <Home path="/" />
                    <AsyncRoute
                        path="/settings"
                        getComponent={(): Promise<
                            TypedComponent<SettingsProps>
                        > =>
                            import('@/routes/settings/settings').then(
                                module => module.Settings
                            )
                        }
                    />
                    <AsyncRoute
                        path="/app"
                        getComponent={(): Promise<
                            TypedComponent<PasswordListProps>
                        > =>
                            import('@/routes/passwordList/passwordList').then(
                                module => module.PasswordList
                            )
                        }
                    />
                </Router>
            </PageWrapper>
            <Footer />
            {renderIfTrue(() => <Snackbar />)(isSnackbarVisible)}
            {renderIfTrue(() => (
                <LoaderWrapper>
                    <Loader />
                </LoaderWrapper>
            ))(isLoaderVisible)}
        </Wrapper>
    );
}
Example #4
Source File: optionsPanelConnectExpanded.component.tsx    From passwords-fountain with MIT License 5 votes vote down vote up
OptionsPanelConnectExpanded: TypedComponent<VariantProps> = ({
    switchCurrentVariantName,
}: VariantProps) => {
    const encryptedAdminKey = useSelector(selectAdminKey);
    const fetchPasswords = useAction(passwordListActions.fetchPasswords);
    const formRef = useRef(undefined as any);
    const inputRef = useRef(undefined as any);
    const [masterKeyInputState, masterKeyInputProps] = useInputFormControl(
        formRef,
        formValidation,
        'masterKey'
    );

    useEffect(() => {
        inputRef.current.base.focus();
    }, [inputRef]);

    const handleCancelClick = (): void =>
        switchCurrentVariantName(optionsPanelVariantNames.connectCollapsed);

    const handleConfirmClick = async (e: Event): Promise<void> => {
        e.preventDefault();

        if (formRef.current?.isValid) {
            fetchPasswords(masterKeyInputState.value, encryptedAdminKey);
        }
    };

    const renderInput = (id: string): VNode => (
        <TextInput
            ref={inputRef}
            id={id}
            type="password"
            placeholder="e.g. MyStrongPassword1234"
            {...masterKeyInputProps}
        />
    );

    const renderLabel = (): VNode => <Text>optionsPanel.enterMasterKey</Text>;
    const renderError = (): VNode => <Text>{masterKeyInputState.errors}</Text>;
    return (
        <Wrapper>
            <ContentWrapper>
                <Content>
                    <form ref={formRef} onSubmit={handleConfirmClick}>
                        <FormControl
                            id={masterKeyInputProps.name}
                            hasError={masterKeyInputProps.hasError}
                            renderLabel={renderLabel}
                            renderInput={renderInput}
                            renderError={renderError}
                        />
                    </form>
                </Content>
            </ContentWrapper>
            <ButtonWrapper>
                <Button onClick={handleCancelClick}>
                    <Text>optionsPanel.cancel</Text>
                </Button>
                <Button
                    onClick={handleConfirmClick}
                    disabled={!formRef.current?.isValid}
                >
                    <Text>optionsPanel.confirm</Text>
                </Button>
            </ButtonWrapper>
        </Wrapper>
    );
}
Example #5
Source File: passwordList.tsx    From passwords-fountain with MIT License 5 votes vote down vote up
PasswordList: TypedComponent<Props> = () => {
    useFirstTimeRedirection();
    const passwords = useSelector(selectPasswords);
    const isClientSet = useSelector(selectIsClientSet);
    const isGlobalLoaderVisible = useSelector(selectIsGlobalLoaderVisible);
    const shouldRenderPlaceholder =
        !isClientSet ||
        (isClientSet && !isGlobalLoaderVisible && !Boolean(passwords.length));
    const switchOptionsPanelVariant = useAction(
        passwordListActions.switchOptionPanelVariant
    );
    const [
        selectedEntity,
        setSelectedEntity,
    ] = useState<PasswordEntityRaw | null>(null);

    useEffect(() => {
        if (isClientSet) {
            switchOptionsPanelVariant(
                optionsPanelVariantNames.entityFormCollapsed
            );
        }
    }, []);

    const renderPasswords = (): VNode[] => {
        return passwords.map(
            (entity: PasswordEntityRaw): VNode => (
                <PasswordEntityWrapper key={entity.ref.id}>
                    <PasswordEntity
                        data={entity}
                        isSelected={selectedEntity === entity}
                        onClick={setSelectedEntity}
                    />
                </PasswordEntityWrapper>
            )
        );
    };

    const renderPlaceholder = renderIfTrue(
        (): VNode => {
            const iconName = isClientSet ? 'database' : 'padlock';
            const text = isClientSet
                ? 'passwordList.noDataPlaceholder'
                : 'passwordList.connectionPlaceholder';
            return (
                <Placeholder>
                    <IconSizer>
                        <Icon name={iconName} />
                    </IconSizer>
                    <PlaceholderTextWrapper>
                        <Text>{text}</Text>
                    </PlaceholderTextWrapper>
                </Placeholder>
            );
        }
    );

    return (
        <Wrapper>
            <OptionsPanelWrapper>
                <OptionsPanel />
            </OptionsPanelWrapper>
            <ul>{renderPasswords()}</ul>
            {renderPlaceholder(shouldRenderPlaceholder)}
        </Wrapper>
    );
}
Example #6
Source File: optionsPanelEntityFormExpanded.component.tsx    From passwords-fountain with MIT License 4 votes vote down vote up
OptionsPanelEntityFormExpanded: TypedComponent<VariantProps> = ({
    switchCurrentVariantName,
}: VariantProps) => {
    const encryptedAdminKey = useSelector(selectAdminKey);
    const formRef = useRef(undefined as any);
    const firstInputRef = useRef(undefined as any);
    const addNewPassword = useAction(passwordListActions.addNewPassword);
    const editPassword = useAction(passwordListActions.editPassword);
    const fetchPasswords = useAction(passwordListActions.fetchPasswords);

    const editedEntity = useSelector(selectSelectedAndDecryptedEntity);
    const isInEditMode = useSelector(selectIsInEditMode);
    const actionLabel = isInEditMode ? 'optionsPanel.edit' : 'optionsPanel.add';

    useEffect(() => {
        firstInputRef.current.base.focus();
    }, [firstInputRef]);

    const useInputForm = (fieldName: string, defaultValue?: string) =>
        useInputFormControl(formRef, formValidation, fieldName, defaultValue);

    const [labelInputState, labelInputProps] = useInputForm(
        'label',
        editedEntity.label
    );
    const [loginInputState, loginInputProps] = useInputForm(
        'login',
        editedEntity.login
    );
    const [passwordInputState, passwordInputProps] = useInputForm(
        'password',
        editedEntity.password
    );
    const [encryptionKeyInputState, encryptionKeyInputProps] = useInputForm(
        'encryptionKey'
    );

    const handleCancelClick = (): void =>
        switchCurrentVariantName(optionsPanelVariantNames.entityFormCollapsed);

    const handleAction = async (e: Event): Promise<void> => {
        e.preventDefault();

        if (!formRef.current?.isValid) {
            return;
        }

        if (isInEditMode) {
            await editPassword(
                {
                    label: labelInputState.value,
                    login: loginInputState.value,
                    password: passwordInputState.value,
                    refId: editedEntity.refId,
                },
                encryptionKeyInputState.value
            );
        } else {
            await addNewPassword(
                {
                    label: labelInputState.value,
                    login: loginInputState.value,
                    password: passwordInputState.value,
                },
                encryptionKeyInputState.value
            );
        }
        fetchPasswords(encryptionKeyInputState.value, encryptedAdminKey);
    };

    const renderError = (errors: string) => (): VNode => <Text>{errors}</Text>;
    const renderLabel = (label: string, noteText?: string) => (): VNode => (
        <Fragment>
            <Text>{label}</Text>
            {renderIfTrue(() => (
                <NoteLabelWrapper>
                    <Text>settings.noteLabel</Text>{' '}
                    <Text>{noteText as string}</Text>
                </NoteLabelWrapper>
            ))(Boolean(noteText))}
        </Fragment>
    );
    return (
        <Wrapper>
            <ContentWrapper>
                <Content>
                    <form ref={formRef} onSubmit={handleAction}>
                        <FormControlWrapper>
                            <FormControl
                                id={labelInputProps.name}
                                hasError={labelInputProps.hasError}
                                renderLabel={renderLabel(
                                    'optionsPanel.labelInputLabel'
                                )}
                                renderInput={(id: string): VNode => (
                                    <TextInput
                                        ref={firstInputRef}
                                        id={id}
                                        placeholder="e.g. My Bank Account"
                                        {...labelInputProps}
                                    />
                                )}
                                renderError={renderError(
                                    labelInputState.errors
                                )}
                            />
                        </FormControlWrapper>
                        <FormControlWrapper>
                            <FormControl
                                id={loginInputProps.name}
                                hasError={loginInputProps.hasError}
                                renderLabel={renderLabel(
                                    'optionsPanel.loginInputLabel'
                                )}
                                renderInput={(id: string): VNode => (
                                    <TextInput
                                        id={id}
                                        placeholder="e.g. [email protected]"
                                        {...loginInputProps}
                                    />
                                )}
                                renderError={renderError(
                                    loginInputState.errors
                                )}
                            />
                        </FormControlWrapper>
                        <FormControlWrapper>
                            <FormControl
                                id={passwordInputProps.name}
                                hasError={passwordInputProps.hasError}
                                renderLabel={renderLabel(
                                    'optionsPanel.passwordInputLabel'
                                )}
                                renderInput={(id: string): VNode => (
                                    <TextInput
                                        id={id}
                                        type="password"
                                        placeholder="e.g. myPassWord1234"
                                        {...passwordInputProps}
                                    />
                                )}
                                renderError={renderError(
                                    passwordInputState.errors
                                )}
                            />
                        </FormControlWrapper>
                        <FormControlWrapper>
                            <FormControl
                                id={encryptionKeyInputProps.name}
                                hasError={encryptionKeyInputProps.hasError}
                                renderLabel={renderLabel(
                                    'optionsPanel.encryptionKey',
                                    'optionsPanel.noteEncryptionKey'
                                )}
                                renderInput={(id: string): VNode => (
                                    <TextInput
                                        id={id}
                                        type="password"
                                        placeholder="e.g. MyStrongPassword1234"
                                        {...encryptionKeyInputProps}
                                    />
                                )}
                                renderError={renderError(
                                    encryptionKeyInputState.errors
                                )}
                            />
                        </FormControlWrapper>
                        <input type="submit" hidden />
                    </form>
                </Content>
            </ContentWrapper>
            <ButtonWrapper>
                <Button onClick={handleCancelClick}>
                    <Text>optionsPanel.cancel</Text>
                </Button>
                <Button
                    onClick={handleAction}
                    disabled={!formRef.current?.isValid}
                >
                    <Text>{actionLabel}</Text>
                </Button>
            </ButtonWrapper>
        </Wrapper>
    );
}
Example #7
Source File: passwordEntity.component.tsx    From passwords-fountain with MIT License 4 votes vote down vote up
PasswordEntity: TypedComponent<Props> = ({
    data,
    isSelected,
    onClick,
}: Props) => {
    const formRef = useRef(undefined as any);
    const promptInputRef = useRef(undefined as any);
    const [promptType, setPromptType] = useState<PromptType>(
        promptTypes.invisible
    );
    const encryptedAdminKey = useSelector(selectAdminKey);
    const selectedAndDecryptedEntity = useSelector(
        selectSelectedAndDecryptedEntityByRefId(data.ref.id)
    );
    const passwordVisibility =
        Object.keys(selectedAndDecryptedEntity).length !== 0;

    const [
        encryptionKeyInputState,
        encryptionKeyInputProps,
    ] = useInputFormControl(formRef, formValidation, 'encryptionKey');

    const removePassword = useAction(passwordListActions.removePassword);
    const fetchPasswords = useAction(passwordListActions.fetchPasswords);

    const setSelectedAndDecryptedEntity = useAction(
        passwordListActions.setSelectedAndDecryptedEntity
    );
    const resetSelectedAndDecryptedEntity = useAction(
        passwordListActions.resetSelectedAndDecryptedEntity
    );

    useEffect(() => {
        promptInputRef.current?.base?.focus();
    }, [promptInputRef, promptType]);

    const resetPromptState = (): void => {
        setPromptType(promptTypes.invisible);
        encryptionKeyInputState.setValue('');
        encryptionKeyInputState.setErrors('');
    };

    const handleClick = (e: MouseEvent): void => {
        if (e.detail === 0) {
            // Firefox fix - ignore outclicking via ENTER key
            return;
        }

        onClick(isSelected ? null : data);
        resetSelectedAndDecryptedEntity();
        resetPromptState();
    };

    const handleDecryptionPromptConfirm = async (): Promise<void> => {
        const { decrypt } = await import('@/modules/cipher/cipher.service');
        const { login, password } = decrypt(
            data.data.value,
            encryptionKeyInputState.value,
            true
        ) as PasswordEntityVulnerablePayload;

        setSelectedAndDecryptedEntity({
            refId: data.ref.id,
            label: data.data.label,
            login,
            password,
        });
    };

    const handleRemovalPromptConfirm = async (): Promise<void> => {
        const { decrypt } = await import('@/modules/cipher/cipher.service');
        // only to check if master key is known - not needed to removal operation itself
        decrypt(
            data.data.value,
            encryptionKeyInputState.value,
            true
        ) as PasswordEntityVulnerablePayload;

        await removePassword(data.ref.id);
        fetchPasswords(encryptionKeyInputState.value, encryptedAdminKey);
    };

    const handlePromptConfirm = (e: Event): void => {
        e.preventDefault();

        if (!formRef.current?.isValid) {
            return;
        }

        if (promptType === promptTypes.decryption) {
            handleDecryptionPromptConfirm();
        } else {
            handleRemovalPromptConfirm();
        }

        resetPromptState();
    };

    const handleControlClick = (nextPromptType: PromptType) => (
        e: Event
    ): void => {
        e.stopPropagation();
        if (promptType) {
            return;
        }

        setPromptType(nextPromptType);
    };

    const handleFilledEyeClick = (e: Event): void => {
        e.stopPropagation();
        resetSelectedAndDecryptedEntity();
    };

    const renderPrompt = renderIfTrue(() => {
        const confirmBtnLabel =
            promptType === promptTypes.decryption
                ? 'prompt.decrypt'
                : 'prompt.remove';
        return (
            <Prompt
                renderContent={() => (
                    <form ref={formRef} onSubmit={handlePromptConfirm}>
                        <FormControlWrapper>
                            <FormControl
                                id={encryptionKeyInputProps.name}
                                hasError={encryptionKeyInputProps.hasError}
                                renderLabel={() => (
                                    <Text>optionsPanel.enterEncryptionKey</Text>
                                )}
                                renderError={() => (
                                    <Text>
                                        {encryptionKeyInputState.errors}
                                    </Text>
                                )}
                                renderInput={(id: string) => (
                                    <TextInput
                                        ref={promptInputRef}
                                        id={id}
                                        type="password"
                                        placeholder="e.g. MyStrongPassword1234"
                                        {...encryptionKeyInputProps}
                                    />
                                )}
                            />
                        </FormControlWrapper>
                    </form>
                )}
                renderControls={() => (
                    <Fragment>
                        <Button onClick={resetPromptState}>
                            <Text>optionsPanel.cancel</Text>
                        </Button>
                        <Button
                            onClick={handlePromptConfirm}
                            disabled={!formRef.current?.isValid}
                        >
                            <Text>{confirmBtnLabel}</Text>
                        </Button>
                    </Fragment>
                )}
            />
        );
    });

    const renderEyeIcon = () => {
        if (passwordVisibility) {
            return (
                <IconButton
                    iconName="eyeFilled"
                    onClick={handleFilledEyeClick}
                />
            );
        }
        return (
            <IconButton
                iconName="eye"
                onClick={handleControlClick(promptTypes.decryption)}
            />
        );
    };

    const renderControls = renderIfTrue(() => {
        return (
            <Fragment>
                <IconButton
                    iconName="bin"
                    onClick={handleControlClick(promptTypes.removal)}
                />
                {renderEyeIcon()}
            </Fragment>
        );
    });

    return (
        <Wrapper onClick={handleClick} isSelected={isSelected}>
            <GridWrapper>
                <DataWrapper>
                    <Row>
                        <Label>
                            <Text>passwordEntity.label</Text>
                        </Label>{' '}
                        - <Value>{data.data.label}</Value>
                    </Row>
                    <Row>
                        <Label>
                            <Text>passwordEntity.login</Text>
                        </Label>{' '}
                        -{' '}
                        <Value>
                            {selectedAndDecryptedEntity.login ??
                                placeholderEntityValue}
                        </Value>
                    </Row>
                    <Row>
                        <Label>
                            <Text>passwordEntity.password</Text>
                        </Label>{' '}
                        -{' '}
                        <Value>
                            {selectedAndDecryptedEntity.password ??
                                placeholderEntityValue}
                        </Value>
                    </Row>
                </DataWrapper>
                <ControlsWrapper>{renderControls(isSelected)}</ControlsWrapper>
            </GridWrapper>
            {renderPrompt(Boolean(promptType) && isSelected)}
        </Wrapper>
    );
}
Example #8
Source File: settings.tsx    From passwords-fountain with MIT License 4 votes vote down vote up
Settings: TypedComponent<Props> = () => {
    const isFirstTimeOnDevice = useSelector(selectIsFirstTimeOnDevice);
    const fetchPasswords = useAction(passwordListActions.fetchPasswords);
    const formRef = useRef<HTMLFormElement>(undefined as any);
    const [adminKeyInputState, adminKeyInputProps] = useInputFormControl(
        formRef,
        formValidation,
        'adminKey'
    );
    const [masterKeyInputState, masterKeyInputProps] = useInputFormControl(
        formRef,
        formValidation,
        'masterKey'
    );

    const headingText = isFirstTimeOnDevice
        ? 'settings.connectToDB'
        : 'settings.headingText';

    const handleConnectClick = async (e: Event): Promise<void> => {
        e.preventDefault();

        if (!formRef.current?.isValid) {
            return;
        }

        await fetchPasswords(
            masterKeyInputState.value,
            adminKeyInputState.value,
            true
        );
        route('/app');
    };
    const handleBackClick = (): void => {
        history.back();
    };

    const renderNoteLabel = (labelDescription: string, shouldRender: boolean) =>
        renderIfTrue(() => (
            <NoteLabelWrapper>
                <Text>settings.noteLabel</Text>{' '}
                <DescriptiveText>
                    <Text>{labelDescription}</Text>
                </DescriptiveText>
            </NoteLabelWrapper>
        ))(shouldRender);

    const renderLabel = (
        label: string,
        labelDescription: string,
        noteLabelDescription: string,
        shouldRenderNote = false
    ) => (): VNode => {
        return (
            <Fragment>
                <LabelWrapper>
                    <Text>{label}</Text> -{' '}
                    <DescriptiveText>
                        <Text>{labelDescription}</Text>
                    </DescriptiveText>
                </LabelWrapper>
                {renderNoteLabel(noteLabelDescription, shouldRenderNote)}
            </Fragment>
        );
    };
    const renderError = (error: string) => (): VNode => <Text>{error}</Text>;

    return (
        <Wrapper>
            <Header>
                <Heading>
                    <Text>{headingText}</Text>
                </Heading>
            </Header>
            <FormWrapper>
                <form ref={formRef}>
                    <FormControlWrapper>
                        <FormControl
                            id={adminKeyInputProps.name}
                            hasError={Boolean(adminKeyInputProps.hasError)}
                            renderLabel={renderLabel(
                                'settings.adminKeyLabel',
                                'settings.adminKeyLabelDescription',
                                'settings.noteLabelDescriptionAdminKey'
                            )}
                            renderInput={(id: string): VNode => (
                                <TextInput
                                    id={id}
                                    type="password"
                                    placeholder="92xIJf_ge234kalfnqql4o25ou4334201"
                                    {...adminKeyInputProps}
                                />
                            )}
                            renderError={renderError(adminKeyInputState.errors)}
                        />
                    </FormControlWrapper>
                    <FormControlWrapper>
                        <FormControl
                            id={masterKeyInputProps.name}
                            hasError={Boolean(masterKeyInputProps.hasError)}
                            renderLabel={renderLabel(
                                'settings.masterKeyLabel',
                                'settings.masterKeyLabelDescription',
                                'settings.noteLabelDescription',
                                true
                            )}
                            renderInput={(id: string): VNode => (
                                <TextInput
                                    id={id}
                                    type="password"
                                    placeholder="myMasterPassword1234"
                                    {...masterKeyInputProps}
                                />
                            )}
                            renderError={renderError(
                                masterKeyInputState.errors
                            )}
                        />
                    </FormControlWrapper>
                    <ControlsWrapper>
                        <Button onClick={handleBackClick}>
                            <Text>settings.back</Text>
                        </Button>
                        <Button
                            type="submit"
                            onClick={handleConnectClick}
                            disabled={!formRef.current?.isValid}
                        >
                            <Text>settings.connect</Text>
                        </Button>
                    </ControlsWrapper>
                </form>
            </FormWrapper>
        </Wrapper>
    );
}