{company.name}
diff --git a/src/pages/Users/components/UserDetail/ContactInfo.tsx b/src/pages/Users/components/UserDetail/ContactInfo.tsx
index bfeb053..7af3124 100644
--- a/src/pages/Users/components/UserDetail/ContactInfo.tsx
+++ b/src/pages/Users/components/UserDetail/ContactInfo.tsx
@@ -1,4 +1,5 @@
import classNames from 'classnames';
+import { useTranslation } from 'react-i18next';
import './ContactInfo.scss';
import { BaseComponentProps } from 'common/components/types';
@@ -44,6 +45,8 @@ const ContactInfo = ({
testid = 'contact-info',
user,
}: ContactInfoProps): JSX.Element | false => {
+ const { t } = useTranslation();
+
if (isLoading) {
// loading state
return (
@@ -73,7 +76,7 @@ const ContactInfo = ({
{showHeader && (
- Contact Info
+ {t('contact', { ns: 'user' })}
)}
diff --git a/src/pages/Users/components/UserDetail/UserDetail.tsx b/src/pages/Users/components/UserDetail/UserDetail.tsx
index c5db0b8..9e338bd 100644
--- a/src/pages/Users/components/UserDetail/UserDetail.tsx
+++ b/src/pages/Users/components/UserDetail/UserDetail.tsx
@@ -1,5 +1,6 @@
import { IonCol, IonGrid, IonRow } from '@ionic/react';
import classNames from 'classnames';
+import { useTranslation } from 'react-i18next';
import './UserDetail.scss';
import { BaseComponentProps } from 'common/components/types';
@@ -36,6 +37,7 @@ const UserDetail = ({
testid = 'user-detail',
userId,
}: UserDetailProps): JSX.Element => {
+ const { t } = useTranslation();
const { data: user, isError, isLoading } = useGetUser({ userId });
const baseProps = {
@@ -48,7 +50,7 @@ const UserDetail = ({
return (
-
+
);
diff --git a/src/pages/Users/components/UserDetail/UserDetailPage.tsx b/src/pages/Users/components/UserDetail/UserDetailPage.tsx
index bf26086..6dd4c55 100644
--- a/src/pages/Users/components/UserDetail/UserDetailPage.tsx
+++ b/src/pages/Users/components/UserDetail/UserDetailPage.tsx
@@ -1,6 +1,7 @@
import { IonButton, IonButtons, IonContent, IonPage, IonText, useIonRouter } from '@ionic/react';
import { useState } from 'react';
import { useParams } from 'react-router';
+import { useTranslation } from 'react-i18next';
import { PropsWithTestId } from 'common/components/types';
import { useGetUser } from 'pages/Users/api/useGetUser';
@@ -37,6 +38,7 @@ interface UserDetailPageRouteParams {
export const UserDetailPage = ({
testid = 'page-user-detail',
}: UserDetailPageProps): JSX.Element => {
+ const { t } = useTranslation();
const router = useIonRouter();
const { createToast } = useToasts();
const [showConfirmDelete, setShowConfirmDelete] = useState
(false);
@@ -54,7 +56,7 @@ export const UserDetailPage = ({
user && (
<>
setShowConfirmDelete(true)}
@@ -86,7 +88,7 @@ export const UserDetailPage = ({
{user.name}
setShowConfirmDelete(true)}
data-testid={`${testid}-page-header-button-delete`}
@@ -127,9 +129,9 @@ export const UserDetailPage = ({
onSuccess={() => {
setShowConfirmDelete(false);
createToast({
- buttons: [DismissButton],
+ buttons: [DismissButton()],
duration: 5000,
- message: `${user?.name} deleted`,
+ message: `${user?.name} ${t('deleted')}`,
});
router.goBack();
}}
diff --git a/src/pages/Users/components/UserEdit/UserEdit.tsx b/src/pages/Users/components/UserEdit/UserEdit.tsx
index 6360a78..e9be022 100644
--- a/src/pages/Users/components/UserEdit/UserEdit.tsx
+++ b/src/pages/Users/components/UserEdit/UserEdit.tsx
@@ -1,6 +1,7 @@
import { useState } from 'react';
import { IonCol, IonGrid, IonRow, useIonRouter } from '@ionic/react';
import classNames from 'classnames';
+import { useTranslation } from 'react-i18next';
import { BaseComponentProps } from 'common/components/types';
import { User } from 'common/models/user';
@@ -25,6 +26,7 @@ interface UserEditProps extends BaseComponentProps {
* @returns {JSX.Element} JSX
*/
const UserEdit = ({ className, user, testid = 'user-edit' }: UserEditProps): JSX.Element => {
+ const { t } = useTranslation();
const router = useIonRouter();
const [error, setError] = useState('');
const { mutate: updateUser } = useUpdateUser();
@@ -38,7 +40,7 @@ const UserEdit = ({ className, user, testid = 'user-edit' }: UserEditProps): JSX
{error && (
@@ -56,9 +58,9 @@ const UserEdit = ({ className, user, testid = 'user-edit' }: UserEditProps): JSX
setProgress(false);
setSubmitting(false);
createToast({
- buttons: [DismissButton],
+ buttons: [DismissButton()],
duration: 5000,
- message: `${user.name} updated`,
+ message: `${user.name} ${t('updated')}`,
});
if (router.canGoBack()) {
router.goBack();
diff --git a/src/pages/Users/components/UserForm/UserForm.tsx b/src/pages/Users/components/UserForm/UserForm.tsx
index c3102b4..648fbb8 100644
--- a/src/pages/Users/components/UserForm/UserForm.tsx
+++ b/src/pages/Users/components/UserForm/UserForm.tsx
@@ -3,6 +3,7 @@ import { IonButton } from '@ionic/react';
import { Form, Formik, FormikHelpers } from 'formik';
import { object, string } from 'yup';
import classNames from 'classnames';
+import { useTranslation } from 'react-i18next';
import './UserForm.scss';
import { BaseComponentProps } from 'common/components/types';
@@ -25,20 +26,6 @@ interface UserFormProps extends BaseComponentProps {
user?: User;
}
-/**
- * User form validation schema.
- */
-const validationSchema = object({
- name: string().required('Required. '),
- username: string()
- .required('Required. ')
- .min(8, 'Must be at least 8 characters. ')
- .max(30, 'Must be at most 30 characters. '),
- email: string().required('Required. ').email('Must be an email address. '),
- phone: string().required('Required. '),
- website: string().url('Must be a URL. '),
-});
-
/**
* The `UserForm` component renders a Formik form for creating or editing
* a `User`.
@@ -52,11 +39,26 @@ const UserForm = ({
testid = 'form-user',
}: UserFormProps): JSX.Element => {
const focusInput = useRef(null);
+ const { t } = useTranslation();
useEffect(() => {
focusInput.current?.setFocus();
}, []);
+ /**
+ * User form validation schema.
+ */
+ const validationSchema = object({
+ name: string().required(t('validation.required')),
+ username: string()
+ .required(t('validation.required'))
+ .min(8, ({ min }) => t('validation.min', { min }))
+ .max(30, ({ max }) => t('validation.max', { max })),
+ email: string().required(t('validation.required')).email(t('validation.email')),
+ phone: string().required(t('validation.required')),
+ website: string().url(t('validation.url')),
+ });
+
return (
@@ -75,7 +77,7 @@ const UserForm = ({
)}
diff --git a/src/pages/Users/components/UserList/UserGrid.tsx b/src/pages/Users/components/UserList/UserGrid.tsx
index 2f7bee8..bdc58f6 100644
--- a/src/pages/Users/components/UserList/UserGrid.tsx
+++ b/src/pages/Users/components/UserList/UserGrid.tsx
@@ -1,6 +1,7 @@
import { IonCol, IonGrid, IonRow } from '@ionic/react';
import classNames from 'classnames';
import isEmpty from 'lodash/isEmpty';
+import { useTranslation } from 'react-i18next';
import './UserGrid.scss';
import { BaseComponentProps } from 'common/components/types';
@@ -29,6 +30,7 @@ interface UserGridProps extends BaseComponentProps {
* @see {@link IonGrid}
*/
const UserGrid = ({ className, filterBy, testid = 'grid-user' }: UserGridProps): JSX.Element => {
+ const { t } = useTranslation();
const { data: users, isError, isLoading } = useGetUsers();
const baseProps = {
@@ -43,7 +45,7 @@ const UserGrid = ({ className, filterBy, testid = 'grid-user' }: UserGridProps):
);
@@ -54,7 +56,7 @@ const UserGrid = ({ className, filterBy, testid = 'grid-user' }: UserGridProps):
return (
-
+
);
@@ -67,7 +69,7 @@ const UserGrid = ({ className, filterBy, testid = 'grid-user' }: UserGridProps):
return (
-
+
);
diff --git a/src/pages/Users/components/UserList/UserList.tsx b/src/pages/Users/components/UserList/UserList.tsx
index a016dab..d43135f 100644
--- a/src/pages/Users/components/UserList/UserList.tsx
+++ b/src/pages/Users/components/UserList/UserList.tsx
@@ -1,6 +1,7 @@
import { IonList, IonListHeader } from '@ionic/react';
import classNames from 'classnames';
import isEmpty from 'lodash/isEmpty';
+import { useTranslation } from 'react-i18next';
import './UserList.scss';
import { BaseComponentProps } from 'common/components/types';
@@ -22,7 +23,6 @@ import EmptyCard from 'common/components/Card/EmptyCard';
interface UserListProps extends BaseComponentProps {
filterBy?: string;
header?: string;
- showHeader?: boolean;
}
/**
@@ -34,10 +34,10 @@ interface UserListProps extends BaseComponentProps {
const UserList = ({
className,
filterBy,
- header = 'Users',
- showHeader = false,
+ header,
testid = 'list-user',
}: UserListProps): JSX.Element => {
+ const { t } = useTranslation();
const { data: users, isError, isLoading } = useGetUsers();
const baseProps = {
@@ -52,7 +52,7 @@ const UserList = ({
);
@@ -63,7 +63,7 @@ const UserList = ({
return (
-
+
);
@@ -76,7 +76,7 @@ const UserList = ({
return (
-
+
);
@@ -85,7 +85,7 @@ const UserList = ({
// Success state
return (
- {showHeader && {header}}
+ {header && {header}}
{filteredUsers &&
filteredUsers.map((user, index) => (
diff --git a/src/pages/Users/components/UserList/UserListItem.tsx b/src/pages/Users/components/UserList/UserListItem.tsx
index 1026d7e..c803854 100644
--- a/src/pages/Users/components/UserList/UserListItem.tsx
+++ b/src/pages/Users/components/UserList/UserListItem.tsx
@@ -102,7 +102,7 @@ const UserListItem = ({ className, lines, testid, user }: UserListItemProps): JS
onSuccess={() => {
setShowConfirmDelete(false);
createToast({
- buttons: [DismissButton],
+ buttons: [DismissButton()],
duration: 5000,
message: `${user?.name} deleted`,
});
diff --git a/src/pages/Users/components/UserList/UserListPage.tsx b/src/pages/Users/components/UserList/UserListPage.tsx
index f3cab18..13eb2f3 100644
--- a/src/pages/Users/components/UserList/UserListPage.tsx
+++ b/src/pages/Users/components/UserList/UserListPage.tsx
@@ -12,6 +12,7 @@ import {
import { useState } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import classNames from 'classnames';
+import { useTranslation } from 'react-i18next';
import './UserListPage.scss';
import { PropsWithTestId } from 'common/components/types';
@@ -35,6 +36,7 @@ import UserAddModal from '../UserAdd/UserAddModal';
export const UserListPage = ({ testid = 'page-user-list' }: PropsWithTestId): JSX.Element => {
const [isOpenModal, setIsOpenModal] = useState(false);
const [search, setSearch] = useState('');
+ const { t } = useTranslation();
const queryClient = useQueryClient();
const { handleIonScroll, scrollDirection } = useScrollContext();
@@ -59,7 +61,7 @@ export const UserListPage = ({ testid = 'page-user-list' }: PropsWithTestId): JS
,
@@ -77,11 +79,11 @@ export const UserListPage = ({ testid = 'page-user-list' }: PropsWithTestId): JS
- Users
+ {t('navigation.users')}
setIsOpenModal(true)}
data-testid={`${testid}-page-header-button-create`}
>
diff --git a/src/pages/Users/components/UserSummaryCard/UserSummaryCard.tsx b/src/pages/Users/components/UserSummaryCard/UserSummaryCard.tsx
index afc66ea..c090773 100644
--- a/src/pages/Users/components/UserSummaryCard/UserSummaryCard.tsx
+++ b/src/pages/Users/components/UserSummaryCard/UserSummaryCard.tsx
@@ -7,6 +7,7 @@ import {
IonCardTitle,
} from '@ionic/react';
import classNames from 'classnames';
+import { useTranslation } from 'react-i18next';
import './UserSummaryCard.scss';
import { useGetUsers } from 'pages/Users/api/useGetUsers';
@@ -30,6 +31,7 @@ const UserSummaryCard = ({
testid = 'card-user-summary',
}: UserSummaryCardProps): JSX.Element => {
const { data: users } = useGetUsers();
+ const { t } = useTranslation();
return (
- Users
+ {t('navigation.users')}
{users && (
{users.length}
)}
- Tap to view all users.
+ {t('tap-to-view', { ns: 'user' })}
-
- Browse and search all the users. View user profiles and read their posts.
-
+ {t('browse-and-search', { ns: 'user' })}
);
};
diff --git a/src/test/test-utils.tsx b/src/test/test-utils.tsx
index 071fae5..9194ea9 100644
--- a/src/test/test-utils.tsx
+++ b/src/test/test-utils.tsx
@@ -7,6 +7,7 @@ import {
RenderOptions,
} from '@testing-library/react';
+import 'common/utils/i18n';
import WithAllProviders from './wrappers/WithAllProviders';
const customRender = (ui: React.ReactElement, options?: RenderOptions, { route = '/' } = {}) => {
diff --git a/src/theme/typography.scss b/src/theme/typography.scss
index 28f5c2f..c35c0f7 100644
--- a/src/theme/typography.scss
+++ b/src/theme/typography.scss
@@ -77,4 +77,18 @@
.break-keep {
word-break: keep-all;
}
+
+ // text transform
+ .capitalize {
+ text-transform: capitalize;
+ }
+ .lowercase {
+ text-transform: lowercase;
+ }
+ .uppercase {
+ text-transform: uppercase;
+ }
+ .normal-case {
+ text-transform: none;
+ }
}