Skip to content

Commit

Permalink
feat(ui): implement disconnect actived connection alert when create n…
Browse files Browse the repository at this point in the history
…ew connection and alert user when connect wallet with empty identifier
  • Loading branch information
Vu Van Duc authored and Vu Van Duc committed May 9, 2024
1 parent 3b0a775 commit 7a673d6
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 54 deletions.
21 changes: 19 additions & 2 deletions src/locales/en/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,8 @@
},
"alert": {
"title": "Would you like to grant permission for using your camera?"
}
},
"pastemeerkatid": "Paste Meerkat ID"
},
"chat": {
"tab": {
Expand Down Expand Up @@ -869,7 +870,18 @@
"header": "New connection",
"cancel": "Cancel",
"scanqr": "Scan QR code",
"pastePID": "Paste Peer ID"
"pastePID": "Paste Peer ID",
"disconnectbeforecreatealert": {
"message": "You are currently connected. To connect with a new wallet, you will be disconnected from your current selection. Would you like to disconnect and continue?",
"confirm": "Continue",
"cancel": "Cancel"
}
},
"inputpidmodal": {
"header": "Paste Meerkat ID",
"cancel": "Cancel",
"confirm": "Confirm",
"scanQR": "Scan QR code"
},
"connectionhistory": {
"title": "Connection History",
Expand All @@ -881,6 +893,11 @@
"confirm": "Yes, I’m sure",
"cancel": "Cancel"
},
"missingidentifieralert": {
"message": "To connect with Cardano, you need to create a KERI AID identifier. Would you like to create one now?",
"confirm": "Create identifier",
"cancel": "Cancel"
},
"confirmconnect": {
"done": "Done",
"connectbtn": "Connect",
Expand Down
1 change: 1 addition & 0 deletions src/ui/globals/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum OperationType {
SCAN_CONNECTION = "scanConnection",
ADD_CREDENTIAL = "addCredential",
RECEIVE_CONNECTION = "receiveConnection",
CREATE_IDENTIFIER_CONNECT_WALLET = "createIdentifierConnectWallet",
}

enum ToastMsgType {
Expand Down
16 changes: 10 additions & 6 deletions src/ui/pages/Identifiers/Identifiers.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ describe("Identifiers Tab", () => {

test("Renders favourites in Identifiers", () => {
const { getByText } = render(
<Provider store={mockedStore}>
<Identifiers />
</Provider>
<MemoryRouter initialEntries={[TabsRoutePath.IDENTIFIERS]}>
<Provider store={mockedStore}>
<Identifiers />
</Provider>
</MemoryRouter>
);

expect(
Expand All @@ -83,9 +85,11 @@ describe("Identifiers Tab", () => {

test("Renders Identifiers Tab and all elements in it", () => {
const { getByText, getByTestId } = render(
<Provider store={mockedStore}>
<Identifiers />
</Provider>
<MemoryRouter initialEntries={[TabsRoutePath.IDENTIFIERS]}>
<Provider store={mockedStore}>
<Identifiers />
</Provider>
</MemoryRouter>
);

expect(getByTestId("identifiers-tab")).toBeInTheDocument();
Expand Down
53 changes: 39 additions & 14 deletions src/ui/pages/Identifiers/Identifiers.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import { IonButton, IonIcon, useIonViewWillEnter } from "@ionic/react";
import { peopleOutline, addOutline } from "ionicons/icons";
import { addOutline, peopleOutline } from "ionicons/icons";
import { useEffect, useRef, useState } from "react";
import { TabLayout } from "../../components/layout/TabLayout";
import { useHistory } from "react-router-dom";
import { Agent } from "../../../core/agent/agent";
import { IdentifierShortDetails } from "../../../core/agent/services/identifier.types";
import { i18n } from "../../../i18n";
import { CardsPlaceholder } from "../../components/CardsPlaceholder";
import { CardsStack } from "../../components/CardsStack";
import { TabsRoutePath } from "../../../routes/paths";
import { useAppDispatch, useAppSelector } from "../../../store/hooks";
import {
getFavouritesIdentifiersCache,
getIdentifiersCache,
setIdentifiersCache,
} from "../../../store/reducers/identifiersCache";
import { setCurrentRoute } from "../../../store/reducers/stateCache";
import { TabsRoutePath } from "../../../routes/paths";
import {
getCurrentOperation,
setCurrentOperation,
setCurrentRoute,
} from "../../../store/reducers/stateCache";
import { CardsPlaceholder } from "../../components/CardsPlaceholder";
import { CardsStack } from "../../components/CardsStack";
import { CreateIdentifier } from "../../components/CreateIdentifier";
import { CardType } from "../../globals/types";
import { TabLayout } from "../../components/layout/TabLayout";
import { CardType, OperationType } from "../../globals/types";
import { Connections } from "../Connections";
import { IdentifierShortDetails } from "../../../core/agent/services/identifier.types";
import "./Identifiers.scss";
import { IdentifiersList } from "./components/IdentifiersList";
import { Agent } from "../../../core/agent/agent";
import { StartAnimationSource } from "./Identifiers.type";
import { IdentifiersList } from "./components/IdentifiersList";

const CLEAR_STATE_DELAY = 1000;

Expand Down Expand Up @@ -65,9 +70,11 @@ const AdditionalButtons = ({

const Identifiers = () => {
const pageId = "identifiers-tab";
const history = useHistory();
const dispatch = useAppDispatch();
const identifiersData = useAppSelector(getIdentifiersCache);
const favouritesIdentifiers = useAppSelector(getFavouritesIdentifiersCache);
const currentOperation = useAppSelector(getCurrentOperation);
const [favIdentifiers, setFavIdentifiers] = useState<
IdentifierShortDetails[]
>([]);
Expand All @@ -90,6 +97,15 @@ const Identifiers = () => {
dispatch(setCurrentRoute({ path: TabsRoutePath.IDENTIFIERS }));
});

useEffect(() => {
if (
currentOperation === OperationType.CREATE_IDENTIFIER_CONNECT_WALLET &&
history.location.pathname === TabsRoutePath.IDENTIFIERS
) {
setCreateIdentifierModalIsOpen(true);
}
}, [currentOperation, history.location.pathname]);

useEffect(() => {
setShowPlaceholder(identifiersData.length === 0);
setFavIdentifiers(
Expand Down Expand Up @@ -168,6 +184,17 @@ const Identifiers = () => {
: ""
}`;

const handleCloseCreateIdentifier = (isOpen: boolean) => {
if (
!isOpen &&
currentOperation === OperationType.CREATE_IDENTIFIER_CONNECT_WALLET
) {
dispatch(setCurrentOperation(OperationType.IDLE));
}

setCreateIdentifierModalIsOpen(isOpen);
};

return (
<>
<Connections
Expand Down Expand Up @@ -243,12 +270,10 @@ const Identifiers = () => {
</TabLayout>
<CreateIdentifier
modalIsOpen={createIdentifierModalIsOpen}
setModalIsOpen={(isOpen: boolean) =>
setCreateIdentifierModalIsOpen(isOpen)
}
setModalIsOpen={handleCloseCreateIdentifier}
/>
</>
);
};

export { Identifiers, AdditionalButtons };
export { AdditionalButtons, Identifiers };
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import configureStore from "redux-mock-store";
import EN_TRANSLATIONS from "../../../../../locales/en/en.json";
import { TabsRoutePath } from "../../../../../routes/paths";
import { setToastMsg } from "../../../../../store/reducers/stateCache";
import { identifierFix } from "../../../../__fixtures__/identifierFix";
import { walletConnectionsFix } from "../../../../__fixtures__/walletConnectionsFix";
import { ToastMsgType } from "../../../../globals/types";
import { ConfirmConnectModal } from "./ConfirmConnectModal";
Expand Down Expand Up @@ -32,6 +33,9 @@ const initialState = {
passwordIsSet: true,
},
},
identifiersCache: {
identifiers: [...identifierFix],
},
};

const storeMocked = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { IonButton, IonIcon } from "@ionic/react";
import { personCircleOutline, trashOutline, copyOutline } from "ionicons/icons";
import { copyOutline, personCircleOutline, trashOutline } from "ionicons/icons";
import { i18n } from "../../../../../i18n";
import { OptionModal } from "../../../../components/OptionsModal";
import { ConfirmConnectModalProps } from "./ConfirmConnectModal.types";
import "./ConfirmConnectModal.scss";
import { writeToClipboard } from "../../../../utils/clipboard";
import { useAppDispatch } from "../../../../../store/hooks";
import { setToastMsg } from "../../../../../store/reducers/stateCache";
import { OptionModal } from "../../../../components/OptionsModal";
import { ToastMsgType } from "../../../../globals/types";
import { useAppDispatch } from "../../../../../store/hooks";
import { writeToClipboard } from "../../../../utils/clipboard";
import { combineClassNames } from "../../../../utils/style";
import "./ConfirmConnectModal.scss";
import { ConfirmConnectModalProps } from "./ConfirmConnectModal.types";

const ConfirmConnectModal = ({
openModal,
Expand Down Expand Up @@ -57,8 +57,8 @@ const ConfirmConnectModal = ({
};

const confirm = () => {
onConfirm();
closeModal();
onConfirm();
};

const confirmClass = combineClassNames("confirm-connect-submit", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { walletConnectionsFix } from "../../../../__fixtures__/walletConnections
import { ConnectWallet } from "./ConnectWallet";
import { setToastMsg } from "../../../../../store/reducers/stateCache";
import { ToastMsgType } from "../../../../globals/types";
import { identifierFix } from "../../../../__fixtures__/identifierFix";

jest.mock("@ionic/react", () => ({
...jest.requireActual("@ionic/react"),
Expand Down Expand Up @@ -44,6 +45,9 @@ const initialState = {
walletConnections: [...walletConnectionsFix],
connectedWallet: walletConnectionsFix[1],
},
identifiersCache: {
identifiers: [...identifierFix],
},
};

const storeMocked = {
Expand All @@ -66,6 +70,9 @@ describe("Confirm connect modal", () => {
walletConnectionsCache: {
walletConnections: [],
},
identifiersCache: {
identifiers: [...identifierFix],
},
};

const storeMocked = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { Provider } from "react-redux";
import configureStore from "redux-mock-store";
import EN_TRANSLATIONS from "../../../../../locales/en/en.json";
import { TabsRoutePath } from "../../../../../routes/paths";
import { setCurrentOperation } from "../../../../../store/reducers/stateCache";
import { OperationType } from "../../../../globals/types";
import { walletConnectionsFix } from "../../../../__fixtures__/walletConnectionsFix";
import { ConnectWalletActions } from "./ConnectWalletActions";

jest.mock("@ionic/react", () => ({
Expand All @@ -31,6 +30,10 @@ const initialState = {
passwordIsSet: true,
},
},
walletConnectionsCache: {
walletConnections: [],
connectedWallet: null,
},
};

const storeMocked = {
Expand All @@ -42,10 +45,12 @@ describe("Connect wallet actions modal", () => {
test("Render connect wallet actions", async () => {
const closeFn = jest.fn();
const openInputPidFn = jest.fn();
const onQRScanFn = jest.fn();

const { getByTestId, getByText } = render(
<Provider store={storeMocked}>
<ConnectWalletActions
onQRScan={onQRScanFn}
openModal={true}
closeModal={closeFn}
onInputPid={openInputPidFn}
Expand All @@ -65,15 +70,103 @@ describe("Connect wallet actions modal", () => {
});

await waitFor(() => {
expect(dispatchMock).toBeCalledWith(
setCurrentOperation(OperationType.SCAN_CONNECTION)
expect(onQRScanFn).toBeCalled();
});

act(() => {
fireEvent.click(getByTestId("connect-wallet-modal-input-pid"));
});

await waitFor(() => {
expect(openInputPidFn).toBeCalled();
});
});

test("Disconnect alert before create new connection", async () => {
const initialState = {
stateCache: {
routes: [TabsRoutePath.IDENTIFIERS],
authentication: {
loggedIn: true,
time: Date.now(),
passcodeIsSet: true,
passwordIsSet: true,
},
},
walletConnectionsCache: {
walletConnections: walletConnectionsFix,
connectedWallet: walletConnectionsFix[0],
},
};

const storeMocked = {
...mockStore(initialState),
dispatch: dispatchMock,
};

const closeFn = jest.fn();
const openInputPidFn = jest.fn();
const onQRScanFn = jest.fn();

const { getByTestId, getByText } = render(
<Provider store={storeMocked}>
<ConnectWalletActions
onQRScan={onQRScanFn}
openModal={true}
closeModal={closeFn}
onInputPid={openInputPidFn}
/>
</Provider>
);

act(() => {
fireEvent.click(getByTestId("connect-wallet-modal-scan-qr-code"));
});

await waitFor(() => {
expect(
getByText(
EN_TRANSLATIONS.connectwallet.connectwalletmodal
.disconnectbeforecreatealert.message
)
).toBeVisible();
});

act(() => {
fireEvent.click(
getByText(
EN_TRANSLATIONS.connectwallet.connectwalletmodal
.disconnectbeforecreatealert.confirm
)
);
});

await waitFor(() => {
expect(onQRScanFn).toBeCalled();
});

act(() => {
fireEvent.click(getByTestId("connect-wallet-modal-input-pid"));
});

await waitFor(() => {
expect(
getByText(
EN_TRANSLATIONS.connectwallet.connectwalletmodal
.disconnectbeforecreatealert.message
)
).toBeVisible();
});

act(() => {
fireEvent.click(
getByText(
EN_TRANSLATIONS.connectwallet.connectwalletmodal
.disconnectbeforecreatealert.confirm
)
);
});

await waitFor(() => {
expect(openInputPidFn).toBeCalled();
});
Expand Down

0 comments on commit 7a673d6

Please sign in to comment.