Skip to content

Commit

Permalink
feat(ui): standardise share QR modal (#436)
Browse files Browse the repository at this point in the history
* feat(ui): standardise add connection modal

* feat(ui): standardise add connection modal and share QR modal

* feat(ui): move inline callback to new function

---------

Co-authored-by: Vu Van Duc <vuvanduc@Vus-MacBook-Pro.local>
  • Loading branch information
Sotatek-DukeVu and Vu Van Duc committed Apr 25, 2024
1 parent 540823f commit e63bcac
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 352 deletions.
3 changes: 2 additions & 1 deletion src/locales/en/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,8 @@
"title": "Add a ",
"scan": "Scan QR Code",
"connect": "Scan to connect",
"provide": "Provide QR Code"
"provide": "Provide QR Code",
"close": "Done"
},
"verifypassword": {
"title": "Enter password",
Expand Down
2 changes: 1 addition & 1 deletion src/ui/components/AppWrapper/AppWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ const AppWrapper = (props: { children: ReactNode }) => {
passcodeIsSet,
seedPhraseIsSet,
passwordIsSet,
passwordIsSkipped: !passcodeIsSet,
passwordIsSkipped: !passwordIsSet,
})
);

Expand Down
106 changes: 32 additions & 74 deletions src/ui/components/ConnectModal/ConnectModal.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
import {
IonModal,
IonGrid,
IonRow,
IonCol,
IonButton,
IonIcon,
} from "@ionic/react";
import { scanCircleOutline, qrCodeOutline } from "ionicons/icons";
import { i18n } from "../../../i18n";
import { PageLayout } from "../layout/PageLayout";
import { ConnectModalProps } from "./ConnectModal.types";
import "./ConnectModal.scss";
import { useAppDispatch } from "../../../store/hooks";
import { setCurrentOperation } from "../../../store/reducers/stateCache";
import { OperationType } from "../../globals/types";
import { OptionItem, OptionModal } from "../OptionsModal";

const ConnectModal = ({
type,
Expand All @@ -23,71 +14,38 @@ const ConnectModal = ({
}: ConnectModalProps) => {
const dispatch = useAppDispatch();

const options: OptionItem[] = [
{
icon: scanCircleOutline,
label: i18n.t("connectmodal.scan"),
onClick: () => {
dispatch(setCurrentOperation(OperationType.SCAN_CONNECTION));
},
testId: "add-connection-modal-scan-qr-code",
},
{
icon: qrCodeOutline,
label: i18n.t("connectmodal.provide"),
onClick: handleProvideQr,
testId: "add-connection-modal-provide-qr-code",
},
];

const handleClose = () => setConnectModalIsOpen(false);

return (
<IonModal
isOpen={connectModalIsOpen}
initialBreakpoint={0.3}
breakpoints={[0, 0.3]}
className="page-layout short-modal"
data-testid="add-connection-modal"
onDidDismiss={() => setConnectModalIsOpen(false)}
>
<div className="add-connection-modal modal">
<PageLayout
header={true}
closeButton={false}
title={`${i18n.t("connectmodal.title") + type.toLowerCase()}`}
>
<IonGrid>
<IonRow>
<IonCol
size="12"
className="add-connection-modal-body"
>
<span
className="add-connection-modal-option"
data-testid="add-connection-modal-scan-qr-code"
onClick={() => {
dispatch(
setCurrentOperation(OperationType.SCAN_CONNECTION)
);
}}
>
<span>
<IonButton shape="round">
<IonIcon
slot="icon-only"
icon={scanCircleOutline}
/>
</IonButton>
</span>
<span className="add-connection-modal-label">
{i18n.t("connectmodal.scan")}
</span>
</span>
<span
className="add-connection-modal-option"
data-testid="add-connection-modal-provide-qr-code"
onClick={handleProvideQr}
>
<span>
<IonButton shape="round">
<IonIcon
slot="icon-only"
icon={qrCodeOutline}
/>
</IonButton>
</span>
<span className="add-connection-modal-label">
{i18n.t("connectmodal.provide")}
</span>
</span>
</IonCol>
</IonRow>
</IonGrid>
</PageLayout>
</div>
</IonModal>
<OptionModal
modalIsOpen={connectModalIsOpen}
componentId="add-connection-modal"
onDismiss={handleClose}
header={{
closeButton: true,
closeButtonAction: handleClose,
closeButtonLabel: `${i18n.t("connectmodal.close")}`,
title: `${i18n.t("connectmodal.title")} ${type.toLowerCase()}`,
}}
items={options}
/>
);
};

Expand Down
2 changes: 2 additions & 0 deletions src/ui/components/OptionsModal/OptionsModal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
--background: transparent;
}
}
}

.option-list {
.option-item {
--padding-start: 0.5rem;
--background: transparent;
Expand Down
56 changes: 31 additions & 25 deletions src/ui/components/OptionsModal/OptionsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
import { IonIcon, IonItem, IonLabel, IonList } from "@ionic/react";
import { ResponsiveModal } from "../layout/ResponsiveModal";
import { PageHeader } from "../PageHeader";
import { OptionModalProps } from "./OptionsModal.types";
import { OptionListProps, OptionModalProps } from "./OptionsModal.types";
import { combineClassNames } from "../../utils/style";
import "./OptionsModal.scss";

const OptionList = ({ className, data }: OptionListProps) => {
const classNames = combineClassNames("option-list", className);
const getOptionItemClass = (className?: string) =>
combineClassNames("option-item", className);

return (
<IonList
className={classNames}
lines="none"
>
{data.map((item) => (
<IonItem
data-testid={item.testId}
key={item.label}
onClick={item.onClick}
className={getOptionItemClass(item.className)}
>
<IonIcon
icon={item.icon}
slot="start"
></IonIcon>
<IonLabel>{item.label}</IonLabel>
</IonItem>
))}
</IonList>
);
};

const OptionModal = ({
header,
items,
children,
customClasses,
...props
}: OptionModalProps) => {
const getOptionItemClass = (className?: string) =>
combineClassNames("option-item", className);
const modalClass = combineClassNames("options-modal", customClasses);

return (
Expand All @@ -22,30 +48,10 @@ const OptionModal = ({
{...props}
>
<PageHeader {...header} />
{items && items.length > 0 && (
<IonList
className="option-list"
lines="none"
>
{items.map((item) => (
<IonItem
data-testid={item.testId}
key={item.label}
onClick={item.onClick}
className={getOptionItemClass(item.className)}
>
<IonIcon
icon={item.icon}
slot="start"
></IonIcon>
<IonLabel>{item.label}</IonLabel>
</IonItem>
))}
</IonList>
)}
{items && items.length > 0 && <OptionList data={items} />}
{children}
</ResponsiveModal>
);
};

export { OptionModal };
export { OptionModal, OptionList };
5 changes: 5 additions & 0 deletions src/ui/components/OptionsModal/OptionsModal.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export interface OptionItem {
testId?: string;
}

export interface OptionListProps {
data: OptionItem[];
className?: string;
}

export interface OptionModalProps extends ResponsiveModalProps {
header: PageHeaderProps;
items?: OptionItem[];
Expand Down
47 changes: 18 additions & 29 deletions src/ui/components/ShareQR/MoreOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IonButton, IonCol, IonGrid, IonIcon, IonRow } from "@ionic/react";
import { Share } from "@capacitor/share";
import { openOutline } from "ionicons/icons";
import { i18n } from "../../../i18n";
import { OptionList } from "../OptionsModal";

const MoreOptions = ({
text,
Expand All @@ -10,35 +10,24 @@ const MoreOptions = ({
text: string;
onClick?: () => void;
}) => {
const handleClick = async () => {
if (onClick) onClick();
await Share.share({
text: text,
});
};

return (
<IonGrid>
<IonRow>
<IonCol size="12">
<span
className="share-qr-modal-option"
data-testid="share-qr-modal-share-button"
onClick={async () => {
if (onClick) onClick();
await Share.share({
text: text,
});
}}
>
<span>
<IonButton shape="round">
<IonIcon
slot="icon-only"
icon={openOutline}
/>
</IonButton>
</span>
<span className="share-qr-modal-info-block-data">
{i18n.t("shareqr.more")}
</span>
</span>
</IonCol>
</IonRow>
</IonGrid>
<OptionList
data={[
{
testId: "share-qr-modal-share-button",
onClick: handleClick,
icon: openOutline,
label: `${i18n.t("shareqr.more")}`,
},
]}
/>
);
};

Expand Down

0 comments on commit e63bcac

Please sign in to comment.