Skip to content

Commit

Permalink
FormNavigationBlocker -> FormChangesTracker
Browse files Browse the repository at this point in the history
useFormNavigationBlocking -> useDiscardFormChangesConfirmation
Update exports from default to module
  • Loading branch information
edmundito committed Apr 11, 2022
1 parent c8e866f commit fba94d8
Show file tree
Hide file tree
Showing 15 changed files with 71 additions and 81 deletions.
6 changes: 3 additions & 3 deletions airbyte-webapp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { FeatureService } from "hooks/services/Feature";
import { ServicesProvider } from "core/servicesProvider";
import { ApiServices } from "core/ApiServices";
import { StoreProvider } from "views/common/StoreProvider";
import ConfirmationModalServiceProvider from "hooks/services/ConfirmationModal";
import { ConfirmationModalService } from "hooks/services/ConfirmationModal";

import en from "./locales/en.json";
import GlobalStyle from "./global-styles";
Expand Down Expand Up @@ -54,9 +54,9 @@ const Services: React.FC = ({ children }) => (
<WorkspaceServiceProvider>
<FeatureService>
<NotificationService>
<ConfirmationModalServiceProvider>
<ConfirmationModalService>
<ApiServices>{children}</ApiServices>
</ConfirmationModalServiceProvider>
</ConfirmationModalService>
</NotificationService>
</FeatureService>
</WorkspaceServiceProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ interface Props {
onSubmit: () => void;
}

const ConfirmationModal: React.FC<Props> = ({ onClose, title, text, onSubmit, submitButtonText }) => (
export const ConfirmationModal: React.FC<Props> = ({ onClose, title, text, onSubmit, submitButtonText }) => (
<Modal onClose={onClose} title={title}>
<Content>
{text}
Expand All @@ -46,5 +46,3 @@ const ConfirmationModal: React.FC<Props> = ({ onClose, title, text, onSubmit, su
</Content>
</Modal>
);

export default ConfirmationModal;
5 changes: 1 addition & 4 deletions airbyte-webapp/src/components/ConfirmationModal/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
import ConfirmationModal from "./ConfirmationModal";

export default ConfirmationModal;
export { ConfirmationModal };
export { ConfirmationModal } from "./ConfirmationModal";
25 changes: 25 additions & 0 deletions airbyte-webapp/src/components/FormChangesTracker/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useLayoutEffect, useMemo } from "react";
import { uniqueId } from "lodash";
import { useLocation } from "react-router-dom";

import { useChangedFormsById } from "hooks/useDiscardFormChangesConfirmation";

interface Props {
changed: boolean;
}

const FormChangesTracker: React.FC<Props> = ({ changed }) => {
const location = useLocation();
const [changedFormsById, setChangedFormsById] = useChangedFormsById();
const id = useMemo(() => `${location.pathname}__${uniqueId("form_")}`, [location.pathname]);

useLayoutEffect(() => {
if (!!changedFormsById?.[id] !== changed) {
setChangedFormsById({ ...changedFormsById, [id]: changed });
}
}, [id, changed, setChangedFormsById, changedFormsById]);

return null;
};

export default FormChangesTracker;
25 changes: 0 additions & 25 deletions airbyte-webapp/src/components/FormNavigationBlocker/index.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import React, { useContext, useEffect, useMemo } from "react";

import ConfirmationModalComponent from "components/ConfirmationModal";
import { ConfirmationModal } from "components/ConfirmationModal";

import useTypesafeReducer from "hooks/useTypesafeReducer";

import { ConfirmationModal, ConfirmationModalServiceApi, ConfirmationModalState } from "./types";
import { ConfirmationModalOptions, ConfirmationModalServiceApi, ConfirmationModalState } from "./types";
import { actions, initialState, confirmationModalServiceReducer } from "./reducer";

const confirmationModalServiceContext = React.createContext<ConfirmationModalServiceApi | undefined>(undefined);
const ConfirmationModalServiceContext = React.createContext<ConfirmationModalServiceApi | undefined>(undefined);

export const useConfirmationModalService: (
confirmationModal?: ConfirmationModal,
confirmationModal?: ConfirmationModalOptions,
dependencies?: []
) => {
openConfirmationModal: (confirmationModal: ConfirmationModal) => void;
openConfirmationModal: (confirmationModal: ConfirmationModalOptions) => void;
closeConfirmationModal: () => void;
} = (confirmationModal, dependencies) => {
const confirmationModalService = useContext(confirmationModalServiceContext);
const confirmationModalService = useContext(ConfirmationModalServiceContext);
if (!confirmationModalService) {
throw new Error("useConfirmationModalService must be used within a ConfirmationModalService.");
}
Expand All @@ -39,7 +39,7 @@ export const useConfirmationModalService: (
};
};

const ConfirmationModalService = ({ children }: { children: React.ReactNode }) => {
export const ConfirmationModalService = React.memo(({ children }: { children: React.ReactNode }) => {
const [state, { openConfirmationModal, closeConfirmationModal }] = useTypesafeReducer<
ConfirmationModalState,
typeof actions
Expand All @@ -55,11 +55,11 @@ const ConfirmationModalService = ({ children }: { children: React.ReactNode }) =

return (
<>
<confirmationModalServiceContext.Provider value={confirmationModalService}>
<ConfirmationModalServiceContext.Provider value={confirmationModalService}>
{children}
</confirmationModalServiceContext.Provider>
</ConfirmationModalServiceContext.Provider>
{state.isOpen && state.confirmationModal ? (
<ConfirmationModalComponent
<ConfirmationModal
onClose={closeConfirmationModal}
title={state.confirmationModal.title}
text={state.confirmationModal.text}
Expand All @@ -69,6 +69,4 @@ const ConfirmationModalService = ({ children }: { children: React.ReactNode }) =
) : null}
</>
);
};

export default React.memo(ConfirmationModalService);
});
5 changes: 1 addition & 4 deletions airbyte-webapp/src/hooks/services/ConfirmationModal/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
import ConfirmationModalService from "./ConfirmationModalService";

export default ConfirmationModalService;
export { ConfirmationModalService };
export * from "./ConfirmationModalService";
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ActionType, createAction, createReducer } from "typesafe-actions";

import { ConfirmationModal, ConfirmationModalState } from "./types";
import { ConfirmationModalOptions, ConfirmationModalState } from "./types";

export const actions = {
openConfirmationModal: createAction("OPEN_CONFIRMATION_MODAL")<ConfirmationModal>(),
openConfirmationModal: createAction("OPEN_CONFIRMATION_MODAL")<ConfirmationModalOptions>(),
closeConfirmationModal: createAction("CLOSE_CONFIRMATION_MODAL")(),
};

Expand Down
6 changes: 3 additions & 3 deletions airbyte-webapp/src/hooks/services/ConfirmationModal/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React from "react";

export interface ConfirmationModal {
export interface ConfirmationModalOptions {
submitButtonText: React.ReactNode;
title: React.ReactNode;
text: React.ReactNode;
onSubmit: () => Promise<void>;
}

export interface ConfirmationModalServiceApi {
openConfirmationModal: (confirmationModal: ConfirmationModal) => void;
openConfirmationModal: (confirmationModal: ConfirmationModalOptions) => void;
closeConfirmationModal: () => void;
}

export interface ConfirmationModalState {
isOpen: boolean;
confirmationModal: ConfirmationModal | null;
confirmationModal: ConfirmationModalOptions | null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,39 @@ import { useCallback, useMemo } from "react";
import { createGlobalState } from "react-use";

import { useBlocker } from "./router/useBlocker";
import { useConfirmationModalService } from "./services/ConfirmationModal/ConfirmationModalService";
import { ConfirmationModal } from "./services/ConfirmationModal/types";
import { useConfirmationModalService } from "./services/ConfirmationModal";
import { ConfirmationModalOptions } from "./services/ConfirmationModal/types";

export const useBlockingFormsById = createGlobalState<Record<string, boolean>>({});
export const useChangedFormsById = createGlobalState<Record<string, boolean>>({});

const useFormNavigationBlocking = () => {
const [blockingFormsById, setBlockingFormsById] = useBlockingFormsById();
const useDiscardFormChangesConfirmation = () => {
const [changedFormsById, setChangedFormsById] = useChangedFormsById();
const { openConfirmationModal, closeConfirmationModal } = useConfirmationModalService();

const blocker = useCallback(
(tx: Transition) => {
const modalData: ConfirmationModal = {
const modalData: ConfirmationModalOptions = {
title: "Discard changes",
text: "There are unsaved changes. Are you sure you want to discard your changes?",
submitButtonText: "Discard changes",
onSubmit: async () => {
setBlockingFormsById({});
setChangedFormsById({});
closeConfirmationModal();
tx.retry();
},
};

openConfirmationModal(modalData);
},
[closeConfirmationModal, openConfirmationModal, setBlockingFormsById]
[closeConfirmationModal, openConfirmationModal, setChangedFormsById]
);

const isFormBlocking = useMemo(
() => Object.values(blockingFormsById ?? {}).reduce((acc, value) => acc || value, false),
[blockingFormsById]
const formsChanged = useMemo(
() => Object.values(changedFormsById ?? {}).reduce((acc, value) => acc || value, false),
[changedFormsById]
);

useBlocker(blocker, isFormBlocking);
useBlocker(blocker, formsChanged);
};

export default useFormNavigationBlocking;
export default useDiscardFormChangesConfirmation;
6 changes: 3 additions & 3 deletions airbyte-webapp/src/packages/cloud/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { AnalyticsProvider } from "views/common/AnalyticsProvider";
import { FeatureService } from "hooks/services/Feature";
import { AuthenticationProvider } from "packages/cloud/services/auth/AuthService";
import { StoreProvider } from "views/common/StoreProvider";
import ConfirmationModalServiceProvider from "hooks/services/ConfirmationModal";
import { ConfirmationModalService } from "hooks/services/ConfirmationModal";

import { AppServicesProvider } from "./services/AppServicesProvider";
import { IntercomProvider } from "./services/thirdParty/intercom/IntercomProvider";
Expand Down Expand Up @@ -47,15 +47,15 @@ const Services: React.FC = ({ children }) => (
<AnalyticsProvider>
<ApiErrorBoundary>
<NotificationServiceProvider>
<ConfirmationModalServiceProvider>
<ConfirmationModalService>
<FeatureService>
<AppServicesProvider>
<AuthenticationProvider>
<IntercomProvider>{children}</IntercomProvider>
</AuthenticationProvider>
</AppServicesProvider>
</FeatureService>
</ConfirmationModalServiceProvider>
</ConfirmationModalService>
</NotificationServiceProvider>
</ApiErrorBoundary>
</AnalyticsProvider>
Expand Down
4 changes: 2 additions & 2 deletions airbyte-webapp/src/pages/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Navigate, Route, Routes, useLocation } from "react-router-dom";
import { useIntl } from "react-intl";
import { useEffectOnce } from "react-use";

import useFormNavigationBlocking from "hooks/useFormNavigationBlocking";
import useDiscardFormChangesConfirmation from "hooks/useDiscardFormChangesConfirmation";
import { useConfig } from "config";
import MainView from "views/layout/MainView";
import { CompleteOauthRequest } from "views/CompleteOauthRequest";
Expand Down Expand Up @@ -54,7 +54,7 @@ const useAddAnalyticsContextForWorkspace = (workspace: Workspace): void => {
};

const MainViewRoutes: React.FC<{ workspace: Workspace }> = ({ workspace }) => {
useFormNavigationBlocking();
useDiscardFormChangesConfirmation();

return (
<MainView>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Field, FieldProps, Form, Formik } from "formik";
import { ControlLabels, DropDown, DropDownRow, H5, Input, Label } from "components";
import ResetDataModal from "components/ResetDataModal";
import { ModalTypes } from "components/ResetDataModal/types";
import FormNavigationBlocker from "components/FormNavigationBlocker";
import FormChangesTracker from "components/FormChangesTracker";

import { equal } from "utils/objects";
import { useCurrentWorkspace } from "services/workspaces/WorkspacesService";
Expand Down Expand Up @@ -154,7 +154,7 @@ const ConnectionForm: React.FC<ConnectionFormProps> = ({
>
{({ isSubmitting, setFieldValue, isValid, dirty, resetForm, values }) => (
<FormContainer className={className}>
<FormNavigationBlocker block={dirty} />
<FormChangesTracker changed={dirty} />
<Section title={<FormattedMessage id="connection.transfer" />}>
<Field name="schedule">
{({ field, meta }: FieldProps<ScheduleProperties>) => (
Expand Down
4 changes: 2 additions & 2 deletions airbyte-webapp/src/views/Connection/FormCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useMutation } from "react-query";
import { useIntl } from "react-intl";
import styled from "styled-components";

import FormNavigationBlocker from "components/FormNavigationBlocker";
import FormChangesTracker from "components/FormChangesTracker";

import EditControls from "views/Connection/ConnectionForm/components/EditControls";
import { CollapsibleCardProps, CollapsibleCard } from "views/Connection/CollapsibleCard";
Expand Down Expand Up @@ -34,7 +34,7 @@ export const FormCard: React.FC<
{({ resetForm, isSubmitting, dirty, isValid }) => (
<CollapsibleCard {...props}>
<FormContainer>
<FormNavigationBlocker block={dirty} />
<FormChangesTracker changed={dirty} />
{children}
<div>
<EditControls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as yup from "yup";
import { getIn, useFormik, useFormikContext } from "formik";

import { Button, ControlLabels, DropDown, Input } from "components";
import FormNavigationBlocker from "components/FormNavigationBlocker";
import FormChangesTracker from "components/FormChangesTracker";

import { equal } from "utils/objects";
import { Transformation } from "core/domain/connection/operation";
Expand Down Expand Up @@ -100,7 +100,7 @@ const TransformationForm: React.FC<TransformationProps> = ({

return (
<>
<FormNavigationBlocker block={isNewTransformation || dirty} />
<FormChangesTracker changed={isNewTransformation || dirty} />
<Content>
<Column>
<Label
Expand Down

0 comments on commit fba94d8

Please sign in to comment.