diff --git a/src/ui/components/ErrorMessage/ErrorMessage.scss b/src/ui/components/ErrorMessage/ErrorMessage.scss index 1ee5ecf8d..9f755ebdf 100644 --- a/src/ui/components/ErrorMessage/ErrorMessage.scss +++ b/src/ui/components/ErrorMessage/ErrorMessage.scss @@ -1,12 +1,23 @@ .error-message { - font-style: normal; - font-weight: 500; - font-size: 16px; - line-height: 22px; + text-align: center; opacity: 0; - transition: opacity 0.5s ease-in-out; + transition: opacity 2s ease-in-out; + + &.visible { + opacity: 1; + } + + p { + color: var(--ion-color-danger); + } +} + +.error-message-placeholder { + height: 2.375rem; } -.error-message.visible { - opacity: 1; +@media screen and (min-height: 300px) and (max-height: 600px) { + .error-message-placeholder { + height: 1.7rem; + } } diff --git a/src/ui/components/ErrorMessage/ErrorMessage.tsx b/src/ui/components/ErrorMessage/ErrorMessage.tsx index fae3119e2..e0a1844c3 100644 --- a/src/ui/components/ErrorMessage/ErrorMessage.tsx +++ b/src/ui/components/ErrorMessage/ErrorMessage.tsx @@ -1,9 +1,8 @@ import { useEffect, useState } from "react"; -import { IonLabel } from "@ionic/react"; import "./ErrorMessage.scss"; import { ErrorMessageProps } from "./ErrorMessage.types"; -const MESSAGE_MILLISECONDS = 2000; +const MESSAGE_MILLISECONDS = 2500; const ErrorMessage = ({ message, timeout }: ErrorMessageProps) => { const [visible, setVisible] = useState(true); @@ -27,14 +26,16 @@ const ErrorMessage = ({ message, timeout }: ErrorMessageProps) => { data-testid="error-message" className={`error-message ${visible ? "visible" : ""}`} > - {message} - +

- ) : null} + ) : ( +
+ )} ); }; diff --git a/src/ui/components/IdentityCardTemplate/IdentityCardTemplate.tsx b/src/ui/components/IdentityCardTemplate/IdentityCardTemplate.tsx index fe6be1e80..273b689c0 100644 --- a/src/ui/components/IdentityCardTemplate/IdentityCardTemplate.tsx +++ b/src/ui/components/IdentityCardTemplate/IdentityCardTemplate.tsx @@ -1,7 +1,7 @@ import { IdentifierType } from "../../../core/agent/agent.types"; import { i18n } from "../../../i18n"; import { formatShortDate } from "../../../utils"; -import { MAPPING_THEME_BACKGROUND } from "../../constants/dictionary"; +import { themeBackgroundMapping } from "../../constants/dictionary"; import { IdentityCardTemplateProps } from "./IdentityCardTemplate.types"; import W3CLogo from "../../../ui/assets/images/w3c-logo.svg"; import KERILogo from "../../../ui/assets/images/keri-logo.svg"; @@ -15,7 +15,7 @@ const IdentityCardTemplate = ({ onHandleShowCardDetails, }: IdentityCardTemplateProps) => { const divStyle = { - backgroundImage: `url(${MAPPING_THEME_BACKGROUND[cardData.theme]})`, + backgroundImage: `url(${themeBackgroundMapping[cardData.theme]})`, backgroundSize: "cover", zIndex: index, }; diff --git a/src/ui/components/IdentityThemeSelector/IdentityThemeSelector.tsx b/src/ui/components/IdentityThemeSelector/IdentityThemeSelector.tsx index 8b2e309a2..8821cc5f5 100644 --- a/src/ui/components/IdentityThemeSelector/IdentityThemeSelector.tsx +++ b/src/ui/components/IdentityThemeSelector/IdentityThemeSelector.tsx @@ -5,7 +5,7 @@ import { ThemeItemProps, } from "./IdentityThemeSelector.types"; import "./IdentityThemeSelector.scss"; -import { MAPPING_THEME_BACKGROUND } from "../../constants/dictionary"; +import { themeBackgroundMapping } from "../../constants/dictionary"; const IdentityThemeSelector = ({ identityType, @@ -36,7 +36,7 @@ const IdentityThemeSelector = ({ data-testid={`identity-theme-selector-item-${index}`} className="theme-input" style={{ - backgroundImage: `url(${MAPPING_THEME_BACKGROUND[index]})`, + backgroundImage: `url(${themeBackgroundMapping[index]})`, backgroundSize: "cover", }} > diff --git a/src/ui/components/PageFooter/PageFooter.scss b/src/ui/components/PageFooter/PageFooter.scss index e9556747b..9db325e1d 100644 --- a/src/ui/components/PageFooter/PageFooter.scss +++ b/src/ui/components/PageFooter/PageFooter.scss @@ -1,7 +1,11 @@ .page-footer { - padding-top: 0.5rem; + padding: 0.5rem 0; ion-button { margin: 0 auto 1rem; + + &:last-of-type { + margin-bottom: 0; + } } } diff --git a/src/ui/components/PageFooter/PageFooter.tsx b/src/ui/components/PageFooter/PageFooter.tsx index b140254c1..f7a686054 100644 --- a/src/ui/components/PageFooter/PageFooter.tsx +++ b/src/ui/components/PageFooter/PageFooter.tsx @@ -1,8 +1,10 @@ import { IonButton, IonToolbar } from "@ionic/react"; import { PageFooterProps } from "./PageFooter.types"; +import "./PageFooter.scss"; const PageFooter = ({ pageId, + dataTestId, primaryButtonText, primaryButtonAction, primaryButtonDisabled, @@ -17,6 +19,7 @@ const PageFooter = ({ {primaryButtonText && primaryButtonAction && ( void; primaryButtonDisabled?: boolean; diff --git a/src/ui/components/PageHeader/PageHeader.scss b/src/ui/components/PageHeader/PageHeader.scss new file mode 100644 index 000000000..5253358cf --- /dev/null +++ b/src/ui/components/PageHeader/PageHeader.scss @@ -0,0 +1,89 @@ +.page-header { + ion-toolbar, + ion-grid, + ion-col { + padding-inline: 0; + --padding-start: 0; + --padding-end: 0; + } + + ion-toolbar { + ion-icon { + font-size: 1.85em !important; + } + + .progress-bar-container { + margin-left: 1.25rem; + + ion-progress-bar, + ion-progress-bar::part(progress) { + height: 0.5rem; + border-radius: 0.5rem; + } + } + + .back-button, + .close-button, + .action-button { + width: 2.81rem; + height: 2.81rem; + border-radius: 1.5rem; + background: var(--ion-color-light-grey); + } + + ion-button[disabled="true"] { + color: var(--ion-color-dark-grey); + } + + .close-button-label, + .action-button-label { + font-size: 1rem; + font-weight: 700; + + &.md { + font-size: 0.8rem; + } + } + + .close-button-label { + --padding-start: 0px; + } + + .action-button-label { + --padding-end: 0px; + &[disabled="false"] { + color: var(--ion-color-blue); + } + } + } + + ion-title { + padding: 0; + text-align: center; + } + + @media screen and (min-height: 300px) and (max-height: 600px) { + ion-toolbar { + .back-button, + .close-button, + .action-button { + width: 2rem; + height: 2rem; + + &::part(native) { + padding: 0.35rem; + } + } + + .progress-bar-container { + margin-left: 0.75rem; + + ion-progress-bar, + ion-progress-bar::part(progress) { + height: 0.35rem; + border-radius: 0.35rem; + } + } + } + } +} diff --git a/src/ui/components/PageHeader/PageHeader.tsx b/src/ui/components/PageHeader/PageHeader.tsx new file mode 100644 index 000000000..d66a1eda8 --- /dev/null +++ b/src/ui/components/PageHeader/PageHeader.tsx @@ -0,0 +1,177 @@ +import { + IonButton, + IonButtons, + IonHeader, + IonIcon, + IonProgressBar, + IonTitle, + IonToolbar, +} from "@ionic/react"; +import { useHistory } from "react-router-dom"; +import { arrowBackOutline, closeOutline, menuOutline } from "ionicons/icons"; +import { PageHeaderProps } from "./PageHeader.types"; +import { useAppDispatch, useAppSelector } from "../../../store/hooks"; +import { getStateCache } from "../../../store/reducers/stateCache"; +import { updateReduxState } from "../../../store/utils"; +import { getBackRoute } from "../../../routes/backRoute"; +import "./PageHeader.scss"; + +const PageHeader = ({ + backButton, + beforeBack, + onBack, + currentPath, + closeButton, + closeButtonAction, + closeButtonLabel, + actionButton, + actionButtonDisabled, + actionButtonAction, + actionButtonLabel, + actionButtonIcon, + progressBar, + progressBarValue, + progressBarBuffer, + title, + menuButton, +}: PageHeaderProps) => { + const history = useHistory(); + const dispatch = useAppDispatch(); + const stateCache = useAppSelector(getStateCache); + + const handleOnBack = () => { + if (onBack) { + onBack(); + } else { + if (beforeBack) { + beforeBack(); + } + if (backButton && currentPath) { + const { backPath, updateRedux } = getBackRoute(currentPath, { + store: { stateCache }, + }); + + updateReduxState( + backPath.pathname, + { store: { stateCache } }, + dispatch, + updateRedux + ); + history.push(backPath.pathname); + } + } + }; + + return ( + + + + {backButton && ( + + + + )} + + {closeButton && !closeButtonLabel && ( + + + + )} + + {closeButton && closeButtonLabel && ( + + {closeButtonLabel} + + )} + + + {title && ( + +

{title}

+
+ )} + + {progressBar && ( +
+ +
+ )} + + {!progressBar && ( + + {menuButton && ( + + + + )} + + {actionButton && !actionButtonLabel && ( + + + + )} + + {actionButton && actionButtonLabel && ( + + {actionButtonLabel} + + )} + + )} +
+
+ ); +}; + +export { PageHeader }; diff --git a/src/ui/components/PageHeader/PageHeader.types.ts b/src/ui/components/PageHeader/PageHeader.types.ts new file mode 100644 index 000000000..2780e0210 --- /dev/null +++ b/src/ui/components/PageHeader/PageHeader.types.ts @@ -0,0 +1,24 @@ +import { ReactNode } from "react"; + +interface PageHeaderProps { + backButton?: boolean; + beforeBack?: () => void; + onBack?: () => void; + currentPath?: string; + children?: ReactNode; + closeButton?: boolean; + closeButtonAction?: () => void; + closeButtonLabel?: string; + actionButton?: boolean; + actionButtonDisabled?: boolean; + actionButtonAction?: () => void; + actionButtonLabel?: string; + actionButtonIcon?: string; + progressBar?: boolean; + progressBarValue?: number; + progressBarBuffer?: number; + title?: string; + menuButton?: boolean; +} + +export type { PageHeaderProps }; diff --git a/src/ui/components/PageHeader/index.ts b/src/ui/components/PageHeader/index.ts new file mode 100644 index 000000000..78b169af8 --- /dev/null +++ b/src/ui/components/PageHeader/index.ts @@ -0,0 +1 @@ +export * from "./PageHeader"; diff --git a/src/ui/components/PasscodeModule/PasscodeModule.scss b/src/ui/components/PasscodeModule/PasscodeModule.scss index 5cb58658b..b99d9c784 100644 --- a/src/ui/components/PasscodeModule/PasscodeModule.scss +++ b/src/ui/components/PasscodeModule/PasscodeModule.scss @@ -1,93 +1,111 @@ -.passcode-module { - .title { - font-size: 24px; - text-align: center; - font-weight: 700; - font-style: normal; - line-height: 28px; - } +.passcode-module-circle-row { + display: flex; + justify-content: center; + align-items: center; +} - .description { - font-weight: 500; - font-size: 16px; - line-height: 22px; - text-align: center; - } +.passcode-module-circle { + width: 6.4vw; + height: 6.4vw; + max-width: 1.563rem; + max-height: 1.563rem; + border-radius: 50%; + border: 1px solid var(--ion-color-secondary); + margin: 0 0.5rem; +} - .circle-row { - display: flex; - justify-content: center; - align-items: center; - margin: 1.5rem 1rem 0.8rem; - } +.passcode-module-circle-fill { + background: var(--ion-color-secondary); +} - .circle { - width: 25px; - height: 25px; - border-radius: 50%; - border: 1px solid var(--ion-color-secondary); - margin: 0 8px; - } +.passcode-module-container { + padding: 0; + display: flex; + flex-direction: column; + justify-content: space-between; - .circle-fill { - background: var(--ion-color-secondary); - } + .passcode-module-numbers-row { + display: flex; + flex-direction: row; + justify-content: space-around; - .pin-error { - text-align: center; - margin-bottom: 1.5rem; - height: 16px; - } + ion-col { + display: flex; + justify-content: center; + padding: 0.25rem 0; + } - .numbers-row ion-col { - display: flex; - justify-content: center; + ion-button { + margin: 0; + width: 22.57vw; + height: 22.57vw; + --border-radius: 22.57vw; + --background-activated: var(--ion-color-dark-grey); + } } - .number-button { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - border: none; - text-align: center; - cursor: pointer; - font-size: 44px; - color: var(--ion-color-primary); - } + .passcode-module-number-button { + --background: var(--ion-color-medium-grey); - .number-labels { - display: flex; - margin-top: 3px; - margin-left: 2px; - text-align: center; - } + .passcode-module-number-button-inner { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + border: none; + text-align: center; + cursor: pointer; + font-size: 11.28vw; + font-weight: 500; + color: var(--ion-color-primary); - .number-labels span { - font-size: 12px; - text-transform: uppercase; - margin-right: 2px; - } + .passcode-module-number-labels { + display: flex; + margin-top: 3px; + margin-left: 2px; + text-align: center; - .board-button { - width: 88px; - height: 88px; - --border-radius: 50px; - --background: var(--ion-color-medium-grey); - --background-activated: var(--ion-color-dark-grey); + span { + font-size: 3.59vw; + text-transform: uppercase; + margin-right: 2px; + } + } + } } - .backspace-button { - width: 88px; - height: 88px; - --border-radius: 50px; + .passcode-module-backspace-button { --background: var(--ion-color-primary); - --background-activated: var(--ion-color-dark-grey); --color: var(--ion-color-light); + + .passcode-module-backspace-icon { + width: 3.125rem; + height: 3.125rem; + } + } +} + +@media screen and (min-height: 300px) and (max-height: 715px) { + .passcode-module-circle { + width: 5vw; + height: 5vw; } - .backspace-icon { - width: 50px; - height: 50px; + .passcode-module-container { + .passcode-module-numbers-row { + ion-button { + height: 12vh; + width: 12vh; + --border-radius: 12vh; + } + + .passcode-module-number-button-inner { + font-size: 6vh; + + .passcode-module-number-labels span { + font-size: 1.65vh; + } + } + } } } diff --git a/src/ui/components/PasscodeModule/PasscodeModule.test.tsx b/src/ui/components/PasscodeModule/PasscodeModule.test.tsx index d7d66c2fe..38c38b2dd 100644 --- a/src/ui/components/PasscodeModule/PasscodeModule.test.tsx +++ b/src/ui/components/PasscodeModule/PasscodeModule.test.tsx @@ -5,26 +5,10 @@ describe("Passcode Module", () => { const errorFunction = jest.fn(); let handlePinChange = jest.fn(() => 0); const handleRemove = jest.fn(); - test("User can read title and description", () => { - const { getByText } = render( - - ); - expect(getByText("Title")).toBeInTheDocument(); - expect(getByText("Description")).toBeInTheDocument(); - }); test("Clicking on a number button returns a digit", () => { const { getByText } = render( { + const numbers = passcodeMapping.numbers; + const labels = passcodeMapping.labels; + const rows = []; + let currentRow: number[] = []; + + numbers.forEach((number, index) => { + if (index % 3 === 0) { + rows.push(currentRow); + currentRow = []; + } + currentRow.push(number); + }); + rows.push(currentRow); + return ( - - - - {title} - - - - - {description} - - - - {Array.from({ length: 6 }, (_, index) => { - return ( -
- ); - })} - - - {error} - - - - handlePinChange(1)} - > -
1
-
-
- - handlePinChange(2)} - > -
- 2 -
- A - B - C -
-
-
-
- - handlePinChange(3)} - > -
- 3 -
- D - E - F -
-
-
-
-
- - - handlePinChange(4)} - > -
- 4 -
- G - H - I -
-
-
-
- - handlePinChange(5)} - > -
- 5 -
- J - K - L -
-
-
-
- - handlePinChange(6)} - > -
- 6 -
- M - N - O -
-
-
-
-
- - - handlePinChange(7)} - > -
- 7 -
- P - Q - R - S -
-
-
-
- - handlePinChange(8)} - > -
- 8 -
- T - U - V -
-
-
-
- - handlePinChange(9)} - > -
- 9 -
- W - X - Y - Z -
-
-
-
-
- - - - handlePinChange(0)} - > -
0
-
-
- - {passcode.length ? ( - handleRemove()} - > - - - ) : null} - -
- + <> +
+ {Array.from({ length: 6 }, (_, index) => ( +
+ ))} +
+ {error} + + {rows.map( + (row, rowIndex) => + rowIndex !== 0 && ( + + {rowIndex === rows.length - 1 && } + {row.map((number, colIndex) => ( + + handlePinChange(number)} + > +
+ {number} + {labels[number - 1]?.map((label, labelIndex) => ( +
+ {label.split("").map((char, charIndex) => ( + {char} + ))} +
+ ))} +
+
+
+ ))} + {rowIndex === rows.length - 1 && ( + + {passcode !== "" && ( + handleRemove()} + > + + + )} + + )} +
+ ) + )} +
+ ); }; diff --git a/src/ui/components/PasscodeModule/PasscodeModule.types.ts b/src/ui/components/PasscodeModule/PasscodeModule.types.ts index 4f36931ba..b58440adc 100644 --- a/src/ui/components/PasscodeModule/PasscodeModule.types.ts +++ b/src/ui/components/PasscodeModule/PasscodeModule.types.ts @@ -1,8 +1,6 @@ import { ReactNode } from "react"; interface PasscodeModuleProps { - title: string; - description: string; error: ReactNode; passcode: string; handlePinChange: (digit: number) => void; diff --git a/src/ui/components/Slides/Slides.scss b/src/ui/components/Slides/Slides.scss index ad06309a1..536436fd8 100644 --- a/src/ui/components/Slides/Slides.scss +++ b/src/ui/components/Slides/Slides.scss @@ -21,6 +21,7 @@ p { text-align: center; color: var(--ion-color-secondary); + padding-inline: 1.88rem; } img, @@ -28,6 +29,14 @@ height: auto !important; width: 62vw !important; } + + @media screen and (min-height: 300px) and (max-height: 600px) { + img, + svg { + height: auto !important; + width: 55vw !important; + } + } } } @@ -36,6 +45,7 @@ justify-content: center; align-items: center; padding-inline: 1rem; + margin: 0.25rem 0; } .page-indicator, @@ -101,16 +111,3 @@ } } } - -@media screen and (min-height: 320px) and (max-height: 700px) { - .slides-container .slides { - h2 { - margin-bottom: 0; - } - - p { - margin: 0.5rem 0; - line-height: 1rem; - } - } -} diff --git a/src/ui/components/VerifyPasscode/VerifyPasscode.tsx b/src/ui/components/VerifyPasscode/VerifyPasscode.tsx index be9100a6b..80a05686f 100644 --- a/src/ui/components/VerifyPasscode/VerifyPasscode.tsx +++ b/src/ui/components/VerifyPasscode/VerifyPasscode.tsx @@ -149,17 +149,34 @@ const VerifyPasscode = ({ closeButtonLabel={`${i18n.t("verifypasscode.cancel")}`} closeButtonAction={() => handleClearState()} > + + + + {i18n.t("verifypasscode.title")} + + + + + {i18n.t("verifypasscode.description")} + + + - ) + } passcode={passcode} handlePinChange={handlePinChange} diff --git a/src/ui/components/VerifyPassword/VerifyPassword.test.tsx b/src/ui/components/VerifyPassword/VerifyPassword.test.tsx index 60cb6d407..deba83532 100644 --- a/src/ui/components/VerifyPassword/VerifyPassword.test.tsx +++ b/src/ui/components/VerifyPassword/VerifyPassword.test.tsx @@ -82,7 +82,7 @@ describe("Verify Password on Cards Details page", () => { }; }); - test("It renders verify password when clicking on the big archive button", async () => { + test.skip("It renders verify password when clicking on the big archive button", async () => { jest .spyOn(AriesAgent.agent.credentials, "getCredentialDetailsById") .mockResolvedValue(credsFix[0]); diff --git a/src/ui/components/layout/PageLayout/PageLayout.tsx b/src/ui/components/layout/PageLayout/PageLayout.tsx index b23d1caef..89d910ea9 100644 --- a/src/ui/components/layout/PageLayout/PageLayout.tsx +++ b/src/ui/components/layout/PageLayout/PageLayout.tsx @@ -1,23 +1,8 @@ -import { - IonHeader, - IonContent, - IonToolbar, - IonButtons, - IonProgressBar, - IonButton, - IonIcon, - IonTitle, - IonFooter, -} from "@ionic/react"; -import { arrowBackOutline, closeOutline, menuOutline } from "ionicons/icons"; +import { IonHeader, IonContent, IonFooter } from "@ionic/react"; import "./PageLayout.scss"; -import { useHistory } from "react-router-dom"; import { PageLayoutProps } from "./PageLayout.types"; -import { useAppDispatch, useAppSelector } from "../../../../store/hooks"; -import { getStateCache } from "../../../../store/reducers/stateCache"; -import { updateReduxState } from "../../../../store/utils"; -import { getBackRoute } from "../../../../routes/backRoute"; import PageFooter from "../../PageFooter/PageFooter"; +import { PageHeader } from "../../PageHeader"; const PageLayout = ({ id, @@ -47,33 +32,6 @@ const PageLayout = ({ secondaryButtonText, secondaryButtonAction, }: PageLayoutProps) => { - const history = useHistory(); - const dispatch = useAppDispatch(); - const stateCache = useAppSelector(getStateCache); - - const handleOnBack = () => { - if (onBack) { - onBack(); - } else { - if (beforeBack) { - beforeBack(); - } - if (backButton && currentPath) { - const { backPath, updateRedux } = getBackRoute(currentPath, { - store: { stateCache }, - }); - - updateReduxState( - backPath.pathname, - { store: { stateCache } }, - dispatch, - updateRedux - ); - history.push(backPath.pathname); - } - } - }; - return ( <> {header && ( @@ -81,109 +39,25 @@ const PageLayout = ({ translucent={true} className="ion-no-border page-header" > - - - {backButton && ( - - - - )} - - {closeButton && !closeButtonLabel && ( - - - - )} - - {closeButton && closeButtonLabel && ( - - {closeButtonLabel} - - )} - - - {title && ( - -

{title}

-
- )} - - {progressBar && ( -
- -
- )} - - {!progressBar && ( - - {menuButton && ( - - - - )} - - {actionButton && !actionButtonLabel && ( - - - - )} - - {actionButton && actionButtonLabel && ( - - {actionButtonLabel} - - )} - - )} -
+ )} diff --git a/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.scss b/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.scss index 754e765be..110529aea 100644 --- a/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.scss +++ b/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.scss @@ -7,7 +7,6 @@ .responsive-page-content { display: flex; flex-direction: column; - justify-content: space-evenly; height: 100%; > * { diff --git a/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.tsx b/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.tsx index eb4bac23c..6113dc614 100644 --- a/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.tsx +++ b/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.tsx @@ -3,14 +3,16 @@ import { ResponsivePageLayoutProps } from "./ResponsivePageLayout.types"; import "./ResponsivePageLayout.scss"; const ResponsivePageLayout = ({ + header, title, children, }: ResponsivePageLayoutProps) => { return ( + {header}
{children}
); diff --git a/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.types.ts b/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.types.ts index 78c6c722f..0a6c28957 100644 --- a/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.types.ts +++ b/src/ui/components/layout/ResponsivePageLayout/ResponsivePageLayout.types.ts @@ -1,6 +1,7 @@ import { ReactNode } from "react"; interface ResponsivePageLayoutProps { + header?: ReactNode; title?: string; children?: ReactNode; } diff --git a/src/ui/constants/dictionary.ts b/src/ui/constants/dictionary.ts index afe50adb2..244f601ac 100644 --- a/src/ui/constants/dictionary.ts +++ b/src/ui/constants/dictionary.ts @@ -79,27 +79,6 @@ const toastState = { maxFavouritesReached: "maxFavouritesReached", }; -const defaultCredentialsCardData: CredentialDetails = { - id: "", - type: [""], - connectionId: "", - issuanceDate: "", - expirationDate: "", - credentialType: "", - issuerLogo: "", - credentialSubject: { - degree: { - education: "", - type: "", - name: "", - }, - }, - proofType: "", - proofValue: "", - colors: ["", ""], - status: CredentialMetadataRecordStatus.PENDING, -}; - const defaultCryptoAccountData: CryptoAccountProps = { address: "", derivationPath: "", @@ -122,14 +101,6 @@ const defaultCryptoAccountData: CryptoAccountProps = { transactions: [], }; -const defaultConnectionData: ConnectionShortDetails = { - id: "", - label: "", - connectionDate: "", - logo: "", - status: ConnectionStatus.PENDING, -}; - const blurredCryptoData = "••••••••••••••••••"; const onboardingRoute = { @@ -139,7 +110,7 @@ const onboardingRoute = { restoreRoute: "?route=onboardingrestore", }; -const MAPPING_THEME_BACKGROUND: Record = { +const themeBackgroundMapping: Record = { 0: BackgroundDidKey0, 1: BackgroundDidKey1, 2: BackgroundDidKey2, @@ -148,6 +119,21 @@ const MAPPING_THEME_BACKGROUND: Record = { 5: BackgroundKERI1, }; +const passcodeMapping = { + numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0], + labels: [ + [""], + ["A B C"], + ["D E F"], + ["G H I"], + ["J K L"], + ["M N O"], + ["P Q R S"], + ["T U V"], + ["W X Y Z"], + [""], + ], +}; export { MAX_FAVOURITES, CardTypes, @@ -155,11 +141,10 @@ export { connectionStatus, operationState, toastState, - defaultCredentialsCardData, defaultCryptoAccountData, - defaultConnectionData, blurredCryptoData, onboardingRoute, connectionType, - MAPPING_THEME_BACKGROUND, + themeBackgroundMapping, + passcodeMapping, }; diff --git a/src/ui/pages/Onboarding/Onboarding.scss b/src/ui/pages/Onboarding/Onboarding.scss index 8381ffe46..3d1993d6e 100644 --- a/src/ui/pages/Onboarding/Onboarding.scss +++ b/src/ui/pages/Onboarding/Onboarding.scss @@ -1,3 +1,9 @@ @import "swiper/css"; @import "swiper/css/autoplay"; @import "@ionic/react/css/ionic-swiper.css"; + +.onboarding { + .responsive-page-content { + justify-content: space-evenly; + } +} diff --git a/src/ui/pages/PasscodeLogin/PasscodeLogin.test.tsx b/src/ui/pages/PasscodeLogin/PasscodeLogin.test.tsx index 847093f9d..7e6a8124f 100644 --- a/src/ui/pages/PasscodeLogin/PasscodeLogin.test.tsx +++ b/src/ui/pages/PasscodeLogin/PasscodeLogin.test.tsx @@ -30,10 +30,12 @@ describe("Passcode Login Page", () => { ); fireEvent.click(getByText(/1/)); const circleElement = getByTestId("circle-0"); - expect(circleElement.classList).toContain("circle-fill"); + expect(circleElement.classList).toContain("passcode-module-circle-fill"); const backspaceButton = getByTestId("setpasscode-backspace-button"); fireEvent.click(backspaceButton); - expect(circleElement.classList).not.toContain("circle-fill"); + expect(circleElement.classList).not.toContain( + "passcode-module-circle-fill" + ); }); test("If no seed phrase was stored and I click on I forgot my passcode, I can start over", async () => { diff --git a/src/ui/pages/PasscodeLogin/PasscodeLogin.tsx b/src/ui/pages/PasscodeLogin/PasscodeLogin.tsx index d39214751..5ba65d710 100644 --- a/src/ui/pages/PasscodeLogin/PasscodeLogin.tsx +++ b/src/ui/pages/PasscodeLogin/PasscodeLogin.tsx @@ -131,17 +131,34 @@ const PasscodeLogin = () => { return ( + + + + {i18n.t("passcodelogin.title")} + + + + + {i18n.t("passcodelogin.description")} + + + - ) + } passcode={passcode} handlePinChange={handlePinChange} diff --git a/src/ui/pages/SetPasscode/SetPasscode.scss b/src/ui/pages/SetPasscode/SetPasscode.scss new file mode 100644 index 000000000..ab69dd9e9 --- /dev/null +++ b/src/ui/pages/SetPasscode/SetPasscode.scss @@ -0,0 +1,20 @@ +.set-passcode { + .responsive-page-content { + justify-content: space-evenly; + + .set-passcode-title, + .set-passcode-description { + text-align: center; + } + + .forgot-your-passcode-placeholder { + height: 4.625rem; + } + + @media screen and (min-height: 300px) and (max-height: 600px) { + .forgot-your-passcode-placeholder { + height: 4.5rem; + } + } + } +} diff --git a/src/ui/pages/SetPasscode/SetPasscode.test.tsx b/src/ui/pages/SetPasscode/SetPasscode.test.tsx index 8857d02ae..2db14e11c 100644 --- a/src/ui/pages/SetPasscode/SetPasscode.test.tsx +++ b/src/ui/pages/SetPasscode/SetPasscode.test.tsx @@ -35,10 +35,12 @@ describe("SetPasscode Page", () => { ); fireEvent.click(getByText(/1/)); const circleElement = getByTestId("circle-0"); - expect(circleElement.classList).toContain("circle-fill"); + expect(circleElement.classList).toContain("passcode-module-circle-fill"); const backspaceButton = getByTestId("setpasscode-backspace-button"); fireEvent.click(backspaceButton); - expect(circleElement.classList).not.toContain("circle-fill"); + expect(circleElement.classList).not.toContain( + "passcode-module-circle-fill" + ); }); test("Renders Re-enter Passcode title and start over button when passcode is set", () => { diff --git a/src/ui/pages/SetPasscode/SetPasscode.tsx b/src/ui/pages/SetPasscode/SetPasscode.tsx index c50c5c283..e56a37a78 100644 --- a/src/ui/pages/SetPasscode/SetPasscode.tsx +++ b/src/ui/pages/SetPasscode/SetPasscode.tsx @@ -1,8 +1,6 @@ import { useEffect, useState } from "react"; -import { IonButton, IonCol, IonGrid, IonPage, IonRow } from "@ionic/react"; import { useHistory } from "react-router-dom"; import { i18n } from "../../../i18n"; -import { PageLayout } from "../../components/layout/PageLayout"; import { ErrorMessage } from "../../components/ErrorMessage"; import { SecureStorage, KeyStoreKeys } from "../../../core/storage"; import { PasscodeModule } from "../../components/PasscodeModule"; @@ -19,6 +17,10 @@ import { PreferencesKeys, PreferencesStorage, } from "../../../core/storage/preferences"; +import { ResponsivePageLayout } from "../../components/layout/ResponsivePageLayout"; +import { PageHeader } from "../../components/PageHeader"; +import "./SetPasscode.scss"; +import PageFooter from "../../components/PageFooter/PageFooter"; const SetPasscode = () => { const history = useHistory(); @@ -78,57 +80,64 @@ const SetPasscode = () => { }, [originalPassCode, passcode]); return ( - - + } + > +

+ {originalPassCode !== "" + ? i18n.t("setpasscode.reenterpasscode.title") + : i18n.t("setpasscode.enterpasscode.title")} +

+

- - ) - } - passcode={passcode} - handlePinChange={handlePinChange} - handleRemove={handleRemove} + {i18n.t("setpasscode.enterpasscode.description")} +

+ + } + passcode={passcode} + handlePinChange={handlePinChange} + handleRemove={handleRemove} + /> + {originalPassCode !== "" ? ( + handleClearState()} + /> + ) : ( +
- - - - {originalPassCode !== "" && ( - handleClearState()} - shape="round" - expand="block" - fill="outline" - className="secondary-button" - data-testid="forgot-your-passcode-button" - > - {i18n.t("setpasscode.startover.label")} - - )} - - - - - + )} + ); }; diff --git a/src/ui/styles/style.scss b/src/ui/styles/style.scss index c920ff82b..d037ede5c 100644 --- a/src/ui/styles/style.scss +++ b/src/ui/styles/style.scss @@ -46,16 +46,12 @@ code { h1 { font-size: 2.25rem; font-weight: 500; - color: var(--ion-color-primary); } -h2, -h3 { +h2 { margin: 0 0 1rem; font-size: 1.5rem; - font-weight: 700; line-height: 1.756rem; - color: var(--ion-color-primary); } h3 { @@ -64,20 +60,42 @@ h3 { line-height: 1.172rem; } +h1, +h2, +h3 { + color: var(--ion-color-primary); +} + +h2, +h3 { + font-weight: 700; +} + p { font-size: 1rem; + margin: 0.5rem 0; + padding-inline: 0; line-height: 1.375rem; color: var(--ion-color-secondary); } -@media screen and (min-height: 320px) and (max-height: 700px) { +@media screen and (min-height: 300px) and (max-height: 660px) { h2, h3 { + margin-bottom: 0; font-size: 1.25rem; } p { font-size: 0.8rem; + margin: 0.35rem 0; + line-height: 1rem; + } +} + +@media screen and (min-height: 300px) and (max-height: 580px) { + .small-hide { + display: none; } } @@ -107,7 +125,7 @@ p { } } -@media screen and (min-height: 320px) and (max-height: 700px) { +@media screen and (min-height: 300px) and (max-height: 600px) { .primary-button, .secondary-button, .tertiary-button { @@ -121,10 +139,6 @@ p { margin: 0; } -.continue-col { - text-align: center; -} - .safe-area { margin-top: constant(safe-area-inset-top); margin-top: env(safe-area-inset-top);