diff --git a/apps/admin-ui/public/images/deactivated-account.png b/apps/admin-ui/public/images/deactivated-account.png new file mode 100644 index 0000000000..ffb0aca1f4 Binary files /dev/null and b/apps/admin-ui/public/images/deactivated-account.png differ diff --git a/apps/admin-ui/src/App.tsx b/apps/admin-ui/src/App.tsx index c5df9663bc..4e6f7ce1c9 100644 --- a/apps/admin-ui/src/App.tsx +++ b/apps/admin-ui/src/App.tsx @@ -14,6 +14,7 @@ import NotificationsRouter from "./spa/notifications/router"; import Error404 from "./common/Error404"; import { UserPermissionChoice } from "@gql/gql-types"; import { UnitsRouter } from "./spa/unit/router"; +import DeactivatedAccount from "common/src/components/DeactivatedAccount"; const Units = dynamic(() => import("./spa/unit")); @@ -151,6 +152,15 @@ function ClientApp({ UserPermissionChoice.CanManageNotifications )} /> + + } + /> diff --git a/apps/admin-ui/src/i18n/index.ts b/apps/admin-ui/src/i18n/index.ts index 9f5cda01d1..895e558ce2 100644 --- a/apps/admin-ui/src/i18n/index.ts +++ b/apps/admin-ui/src/i18n/index.ts @@ -74,4 +74,14 @@ i18n.addResourceBundle("fi", "forms", { invalidEmail: "Sähköpostin tulee olla oikeassa muodossa (sisältäen @-merkin)", }); +i18n.addResourceBundle("fi", "errors", { + deactivatedAccount: { + heading: "Käyttäjätunnuksesi ei ole voimassa.", + subHeadingA: "Ota yhteyttä asiakaspalveluun sähköpostitse", + subHeadingB: "tai Ota yhteyttä-lomakkeella.", + email: "varaamo@hel.fi", + button: "Ota yhteyttä", + }, +}); + export default i18n; diff --git a/apps/ui/pages/deactivated-account.tsx b/apps/ui/pages/deactivated-account.tsx new file mode 100644 index 0000000000..26ea670c1b --- /dev/null +++ b/apps/ui/pages/deactivated-account.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import { getCommonServerSideProps } from "@/modules/serverUtils"; +import { GetServerSidePropsContext } from "next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import DeactivatedAccount from "common/src/components/DeactivatedAccount"; + +export async function getServerSideProps({ + locale, +}: GetServerSidePropsContext) { + return { + props: { + ...getCommonServerSideProps(), + ...(await serverSideTranslations(locale ?? "fi")), + }, + }; +} + +const DeactivatedAccountPage = ({ feedbackUrl }: { feedbackUrl: string }) => { + return ( + + ); +}; + +export default DeactivatedAccountPage; diff --git a/apps/ui/public/images/deactivated-account.png b/apps/ui/public/images/deactivated-account.png new file mode 100644 index 0000000000..ffb0aca1f4 Binary files /dev/null and b/apps/ui/public/images/deactivated-account.png differ diff --git a/apps/ui/public/locales/en/errors.json b/apps/ui/public/locales/en/errors.json index 1d9e6d8ae9..373403fff9 100644 --- a/apps/ui/public/locales/en/errors.json +++ b/apps/ui/public/locales/en/errors.json @@ -5,6 +5,13 @@ "500": { "body": "Something unexpected happened" }, + "deactivatedAccount": { + "heading": "Your User ID is not valid.", + "subHeadingA": "Please contact support via email at", + "subHeadingB": "or via the Contact us form.", + "email": "varaamo@hel.fi", + "button": "Contact us" + }, "applicationMutation": { "Validation error": "Error in the API call", "Form validation error": "Form validation error", diff --git a/apps/ui/public/locales/fi/errors.json b/apps/ui/public/locales/fi/errors.json index c46122d463..4ae8b56e5a 100644 --- a/apps/ui/public/locales/fi/errors.json +++ b/apps/ui/public/locales/fi/errors.json @@ -5,6 +5,13 @@ "500": { "body": "Jotain meni pieleen" }, + "deactivatedAccount": { + "heading": "Käyttäjätunnuksesi ei ole voimassa.", + "subHeadingA": "Ota yhteyttä asiakaspalveluun sähköpostitse", + "subHeadingB": "tai Ota yhteyttä-lomakkeella.", + "email": "varaamo@hel.fi", + "button": "Ota yhteyttä" + }, "applicationMutation": { "Validation error": "Virheellinen rajapintakutsu", "Form validation error": "Virheellinen lomake", diff --git a/apps/ui/public/locales/sv/errors.json b/apps/ui/public/locales/sv/errors.json index a427c711fa..3cfb510be7 100644 --- a/apps/ui/public/locales/sv/errors.json +++ b/apps/ui/public/locales/sv/errors.json @@ -5,6 +5,13 @@ "500": { "body": "Något oväntat hände" }, + "deactivatedAccount": { + "heading": "Ditt användar-ID är inte giltigt.", + "subHeadingA": "Var god och kontakta vår kundtjänst via email på", + "subHeadingB": "eller via Ta kontakt-formuläret.", + "email": "varaamo@hel.fi", + "button": "Ta kontakt" + }, "applicationMutation": { "Validation error": "Ett fel uppstod i API-anropet", "Form validation error": "Formuläret innehåller fel", diff --git a/packages/common/src/components/DeactivatedAccount.tsx b/packages/common/src/components/DeactivatedAccount.tsx new file mode 100644 index 0000000000..c492e7c3a9 --- /dev/null +++ b/packages/common/src/components/DeactivatedAccount.tsx @@ -0,0 +1,111 @@ +import React from "react"; +import { useTranslation } from "next-i18next"; +import styled from "styled-components"; +import IconButton from "./IconButton"; +import { IconArrowRight } from "hds-react"; +import { fontBold, H1 } from "../common/typography"; +import { breakpoints } from "../common/style"; +import Image from "next/image"; + +const ErrorContainer = styled.div` + display: flex; + flex-direction: column; + max-width: var(--container-width-xl); + margin: 0 auto; + gap: var(--spacing-xl); + padding-block: var(--spacing-xl); + padding-inline: var(--spacing-s); + + --spacing-hz: var(--spacing-s); + @media (min-width: ${breakpoints.m}) { + flex-direction: row; + padding-inline: var(--spacing-m); + + --spacing-hz: var(--spacing-m); + } +`; + +const Img = styled(Image)` + object-fit: contain; + width: auto; + height: auto; + margin: 0 auto; + @media (min-width: ${breakpoints.l}) { + flex-grow: 1; + display: flex; + max-width: 350px; + width: 419px; + } +`; + +const TextContent = styled.div` + display: flex; + flex-direction: column; + gap: var(--spacing-xl); + justify-content: center; + @media (min-width: ${breakpoints.l}) { + order: -1; + } +`; + +const Body = styled.p` + margin: 0; +`; + +const Email = styled.a` + margin: var(--spacing-xs) 0 0; + ${fontBold} +`; + +// NOTE: This is a copy of the Footer component from the common package +const constructFeedbackUrl = ( + feedbackUrl: string, + i18n: { language: string } +) => { + try { + const url = new URL(feedbackUrl); + url.searchParams.set("lang", i18n.language); + return url.toString(); + } catch (e) { + return null; + } +}; + +const DeactivatedAccount = ({ + feedbackUrl, + imgSrc, +}: { + feedbackUrl: string; + imgSrc: string; +}) => { + const { t, i18n } = useTranslation(); + return ( + + + +

{t("errors:deactivatedAccount.heading")}

+ + {`${t("errors:deactivatedAccount.subHeadingA")} `} + + {t("errors:deactivatedAccount.email")} + + {` ${t("errors:deactivatedAccount.subHeadingB")}`} + +
+
+ ); +}; + +export default DeactivatedAccount;