@vijayp-07/react-native-boiler-plate 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +355 -64
- package/package.json +1 -1
- package/template/README.md +108 -5
- package/template/src/api/apiMethods.ts +65 -0
- package/template/src/api/axiosInstance.ts +10 -20
- package/template/src/api/endPoints.ts +18 -0
- package/template/src/api/index.ts +3 -0
- package/template/src/appRedux/modules/ProfileSlice.ts +3 -3
- package/template/src/assets/images/IC_HidePassword.svg +4 -0
- package/template/src/assets/images/IC_ShowPassword.svg +4 -0
- package/template/src/assets/images/index.ts +4 -0
- package/template/src/components/Container.tsx +62 -0
- package/template/src/components/PrimaryFlashMessage.tsx +0 -2
- package/template/src/components/PrimaryLoader.tsx +1 -1
- package/template/src/components/PrimaryTextInput.tsx +84 -0
- package/template/src/components/index.ts +4 -0
- package/template/src/i18n/en.json +12 -8
- package/template/src/i18n/es.json +13 -9
- package/template/src/i18n/hi.json +34 -0
- package/template/src/i18n/i18n.ts +5 -1
- package/template/src/screens/Home/index.tsx +3 -10
- package/template/src/screens/Login/index.tsx +69 -17
- package/template/src/screens/ModalScreen/index.tsx +1 -1
- package/template/src/screens/Profile/index.tsx +11 -3
- package/template/src/services/authService.ts +23 -0
- package/template/src/services/index.ts +1 -0
- package/template/src/types/index.ts +72 -6
- package/template/yarn.lock +7488 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {AxiosRequestConfig} from 'axios';
|
|
2
|
+
import axiosInstance from './axiosInstance';
|
|
3
|
+
import {prettyPrint} from '@common';
|
|
4
|
+
import {ApiResponseType} from '@types';
|
|
5
|
+
|
|
6
|
+
type Method = 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
7
|
+
|
|
8
|
+
const request = async <T>(
|
|
9
|
+
method: Method,
|
|
10
|
+
url: string,
|
|
11
|
+
body?: any,
|
|
12
|
+
config?: AxiosRequestConfig,
|
|
13
|
+
): Promise<ApiResponseType<T>> => {
|
|
14
|
+
try {
|
|
15
|
+
const response = await axiosInstance[method]<T>(
|
|
16
|
+
url,
|
|
17
|
+
body ?? config,
|
|
18
|
+
body ? config : undefined,
|
|
19
|
+
);
|
|
20
|
+
prettyPrint({
|
|
21
|
+
[`API_${method.toUpperCase()}_SUCCESS`]: {url, status: response.status},
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
success: true,
|
|
25
|
+
data: response.data,
|
|
26
|
+
message: 'Success',
|
|
27
|
+
status: response.status,
|
|
28
|
+
};
|
|
29
|
+
} catch (error: any) {
|
|
30
|
+
prettyPrint({[`API_${method.toUpperCase()}_ERROR`]: {url, error}});
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
data: null,
|
|
34
|
+
message:
|
|
35
|
+
error?.response?.data?.message ??
|
|
36
|
+
error?.message ??
|
|
37
|
+
'Something went wrong',
|
|
38
|
+
status: error?.response?.status ?? 0,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const apiGet = <T = any>(url: string, config?: AxiosRequestConfig) =>
|
|
44
|
+
request<T>('get', url, undefined, config);
|
|
45
|
+
|
|
46
|
+
export const apiPost = <T = any>(
|
|
47
|
+
url: string,
|
|
48
|
+
body?: any,
|
|
49
|
+
config?: AxiosRequestConfig,
|
|
50
|
+
) => request<T>('post', url, body, config);
|
|
51
|
+
|
|
52
|
+
export const apiPut = <T = any>(
|
|
53
|
+
url: string,
|
|
54
|
+
body?: any,
|
|
55
|
+
config?: AxiosRequestConfig,
|
|
56
|
+
) => request<T>('put', url, body, config);
|
|
57
|
+
|
|
58
|
+
export const apiPatch = <T = any>(
|
|
59
|
+
url: string,
|
|
60
|
+
body?: any,
|
|
61
|
+
config?: AxiosRequestConfig,
|
|
62
|
+
) => request<T>('patch', url, body, config);
|
|
63
|
+
|
|
64
|
+
export const apiDelete = <T = any>(url: string, config?: AxiosRequestConfig) =>
|
|
65
|
+
request<T>('delete', url, undefined, config);
|
|
@@ -21,23 +21,14 @@ axiosInstance.interceptors.request.use(
|
|
|
21
21
|
if (accessToken) {
|
|
22
22
|
config.headers.Authorization = `Bearer ${accessToken}`;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (platform) {
|
|
27
|
-
config.headers['app-platform'] = platform;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const appVersion = DeviceInfo.getVersion();
|
|
31
|
-
if (appVersion) {
|
|
32
|
-
config.headers['app-version'] = appVersion;
|
|
33
|
-
}
|
|
24
|
+
config.headers['app-platform'] = Platform.OS;
|
|
25
|
+
config.headers['app-version'] = DeviceInfo.getVersion();
|
|
34
26
|
} catch (error) {
|
|
35
|
-
console.warn('Failed to attach
|
|
27
|
+
console.warn('Failed to attach request headers:', error);
|
|
36
28
|
}
|
|
37
29
|
return config;
|
|
38
30
|
},
|
|
39
31
|
error => {
|
|
40
|
-
// Handle request errors (e.g., network issues).
|
|
41
32
|
prettyPrint({AXIOS_INSTANCE_INTERCEPTORS_REQUEST_USE_ERROR: error});
|
|
42
33
|
return Promise.reject(error);
|
|
43
34
|
},
|
|
@@ -51,23 +42,22 @@ axiosInstance.interceptors.response.use(
|
|
|
51
42
|
return response;
|
|
52
43
|
},
|
|
53
44
|
function (error) {
|
|
45
|
+
prettyPrint({RESPONSE_ERROR: error});
|
|
54
46
|
if (axios.isAxiosError(error)) {
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
const status = error.response?.status;
|
|
48
|
+
if (status === 401) {
|
|
49
|
+
showDangerMessage('Something went wrong! please login again');
|
|
57
50
|
clearAsyncData();
|
|
58
51
|
dispatch(resetUserData());
|
|
59
|
-
|
|
60
|
-
} else if (error.response?.status === 500) {
|
|
52
|
+
} else if (status === 500) {
|
|
61
53
|
showDangerMessage(
|
|
62
|
-
|
|
54
|
+
`500 Internal Server Error on ${error.response?.config.url}`,
|
|
63
55
|
);
|
|
64
|
-
dispatch(toggleLoader(false));
|
|
65
56
|
} else if (!error.response) {
|
|
66
57
|
showDangerMessage('Network error. Please check your connection.');
|
|
67
|
-
dispatch(toggleLoader(false));
|
|
68
58
|
}
|
|
59
|
+
dispatch(toggleLoader(false));
|
|
69
60
|
}
|
|
70
|
-
prettyPrint({AXIOS_INSTANCE_INTERCEPTORS_REQUEST_RESPONSE_ERROR: error});
|
|
71
61
|
return Promise.reject(error);
|
|
72
62
|
},
|
|
73
63
|
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────
|
|
2
|
+
// API ENDPOINTS
|
|
3
|
+
// Add all your endpoint paths here grouped by feature.
|
|
4
|
+
// Usage: import { endPoints } from '@api';
|
|
5
|
+
// ─────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export const endPoints = {
|
|
8
|
+
// ── Auth ──────────────────────────────────────────
|
|
9
|
+
auth: {
|
|
10
|
+
login: '/auth/login',
|
|
11
|
+
register: '/auth/register',
|
|
12
|
+
forgotPassword: '/auth/forgot-password',
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
// Add more feature groups below as your app grows
|
|
16
|
+
// home: { ... },
|
|
17
|
+
// user: { ... },
|
|
18
|
+
} as const;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {UserTypes} from '@types';
|
|
1
|
+
import {Languages, UserTypes} from '@types';
|
|
2
2
|
import {PayloadAction, createSlice} from '@reduxjs/toolkit';
|
|
3
3
|
import {ASYNC_KEY, removeAsyncData, setAsyncData} from '@common';
|
|
4
4
|
import {onChangeLanguage} from '@i18n';
|
|
5
5
|
|
|
6
6
|
interface ProfileState {
|
|
7
7
|
userData: UserTypes;
|
|
8
|
-
language:
|
|
8
|
+
language: Languages;
|
|
9
9
|
isLogIn: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -44,7 +44,7 @@ export const profileSlice = createSlice({
|
|
|
44
44
|
state.userData = initialState.userData;
|
|
45
45
|
removeAsyncData(ASYNC_KEY.USER);
|
|
46
46
|
},
|
|
47
|
-
setLanguage: (state, action: PayloadAction<
|
|
47
|
+
setLanguage: (state, action: PayloadAction<Languages>) => {
|
|
48
48
|
state.language = action.payload;
|
|
49
49
|
onChangeLanguage(action.payload);
|
|
50
50
|
},
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M16 8V7C16 4.79086 14.2091 3 12 3C9.79086 3 8 4.79086 8 7V8" stroke="#222222" stroke-width="2" stroke-linecap="round"/>
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.87868 7.87868C3 8.75736 3 10.1716 3 13V14C3 17.7712 3 19.6569 4.17157 20.8284C5.34315 22 7.22876 22 11 22H13C16.7712 22 18.6569 22 19.8284 20.8284C21 19.6569 21 17.7712 21 14V13C21 10.1716 21 8.75736 20.1213 7.87868C19.2426 7 17.8284 7 15 7H9C6.17157 7 4.75736 7 3.87868 7.87868ZM12 15C12.5523 15 13 14.5523 13 14C13 13.4477 12.5523 13 12 13C11.4477 13 11 13.4477 11 14C11 14.5523 11.4477 15 12 15ZM15 14C15 15.3062 14.1652 16.4175 13 16.8293V19H11V16.8293C9.83481 16.4175 9 15.3062 9 14C9 12.3431 10.3431 11 12 11C13.6569 11 15 12.3431 15 14Z" fill="#222222"/>
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.87868 7.87868C3 8.75736 3 10.1716 3 13V14C3 17.7712 3 19.6569 4.17157 20.8284C5.34315 22 7.22876 22 11 22H13C16.7712 22 18.6569 22 19.8284 20.8284C21 19.6569 21 17.7712 21 14V13C21 10.1716 21 8.75736 20.1213 7.87868C19.2426 7 17.8284 7 15 7H9C6.17157 7 4.75736 7 3.87868 7.87868ZM12 15C12.5523 15 13 14.5523 13 14C13 13.4477 12.5523 13 12 13C11.4477 13 11 13.4477 11 14C11 14.5523 11.4477 15 12 15ZM15 14C15 15.3062 14.1652 16.4175 13 16.8293V19H11V16.8293C9.83481 16.4175 9 15.3062 9 14C9 12.3431 10.3431 11 12 11C13.6569 11 15 12.3431 15 14Z" fill="#222222"/>
|
|
3
|
+
<path d="M16.5 7.99981C16.8043 6.17359 16.0108 4.33842 14.4717 3.30935L14.0979 3.05946C12.0734 1.70579 9.3937 1.87263 7.55269 3.46699L6.66992 4.23149" stroke="#222222" stroke-width="2" stroke-linecap="round"/>
|
|
4
|
+
</svg>
|
|
@@ -2,10 +2,14 @@ import IC_Home_Active from './IC_Home_Active.svg';
|
|
|
2
2
|
import IC_Home_UnActive from './IC_Home_UnActive.svg';
|
|
3
3
|
import IC_Setting_Active from './IC_Setting_Active.svg';
|
|
4
4
|
import IC_Setting_UnActive from './IC_Setting_UnActive.svg';
|
|
5
|
+
import IC_HidePassword from './IC_HidePassword.svg';
|
|
6
|
+
import IC_ShowPassword from './IC_ShowPassword.svg';
|
|
5
7
|
|
|
6
8
|
export {
|
|
7
9
|
IC_Home_Active,
|
|
8
10
|
IC_Home_UnActive,
|
|
9
11
|
IC_Setting_Active,
|
|
10
12
|
IC_Setting_UnActive,
|
|
13
|
+
IC_HidePassword,
|
|
14
|
+
IC_ShowPassword,
|
|
11
15
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {View, StyleSheet, StyleProp, ViewStyle} from 'react-native';
|
|
3
|
+
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
|
4
|
+
|
|
5
|
+
interface ContainerProps {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
backgroundColor?: string;
|
|
8
|
+
hideBottomSafeArea?: boolean;
|
|
9
|
+
hideTopSafeArea?: boolean;
|
|
10
|
+
padding?: number;
|
|
11
|
+
paddingTop?: number;
|
|
12
|
+
paddingBottom?: number;
|
|
13
|
+
paddingLeft?: number;
|
|
14
|
+
paddingRight?: number;
|
|
15
|
+
style?: StyleProp<ViewStyle>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const Container: React.FC<ContainerProps> = ({
|
|
19
|
+
children,
|
|
20
|
+
backgroundColor,
|
|
21
|
+
hideBottomSafeArea,
|
|
22
|
+
hideTopSafeArea,
|
|
23
|
+
padding,
|
|
24
|
+
paddingTop,
|
|
25
|
+
paddingBottom,
|
|
26
|
+
paddingLeft,
|
|
27
|
+
paddingRight,
|
|
28
|
+
style,
|
|
29
|
+
}) => {
|
|
30
|
+
const {top, bottom} = useSafeAreaInsets();
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<View
|
|
34
|
+
style={[
|
|
35
|
+
styles.container,
|
|
36
|
+
style,
|
|
37
|
+
{backgroundColor: backgroundColor ?? 'transparent'},
|
|
38
|
+
padding !== undefined && {padding},
|
|
39
|
+
paddingLeft !== undefined && {paddingLeft},
|
|
40
|
+
paddingRight !== undefined && {paddingRight},
|
|
41
|
+
{
|
|
42
|
+
paddingTop:
|
|
43
|
+
(paddingTop ?? padding ?? 0) + (!hideTopSafeArea ? top : 0),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
paddingBottom:
|
|
47
|
+
(paddingBottom ?? padding ?? 0) +
|
|
48
|
+
(!hideBottomSafeArea ? bottom : 0),
|
|
49
|
+
},
|
|
50
|
+
]}>
|
|
51
|
+
{children}
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const styles = StyleSheet.create({
|
|
57
|
+
container: {
|
|
58
|
+
flex: 1,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export default Container;
|
|
@@ -3,7 +3,6 @@ import {View, StyleSheet, Animated} from 'react-native';
|
|
|
3
3
|
import FlashMessage, {FlashMessageProps} from 'react-native-flash-message';
|
|
4
4
|
import {colors, perfectSize} from '@theme';
|
|
5
5
|
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
|
6
|
-
import {prettyPrint} from '@common';
|
|
7
6
|
import PrimaryText from './PrimaryText';
|
|
8
7
|
import {fonts} from '@fonts';
|
|
9
8
|
|
|
@@ -17,7 +16,6 @@ const TYPE_CONFIG: Record<string, {bg: string; accent: string; icon: string}> =
|
|
|
17
16
|
};
|
|
18
17
|
|
|
19
18
|
const FlashMessageComponent: FC<{message: any}> = ({message}) => {
|
|
20
|
-
prettyPrint({message});
|
|
21
19
|
const type = message?.type ?? 'default';
|
|
22
20
|
const {bg, accent, icon} = TYPE_CONFIG[type] ?? TYPE_CONFIG.default;
|
|
23
21
|
const {top, bottom} = useSafeAreaInsets();
|
|
@@ -7,7 +7,7 @@ interface PrimaryLoaderProps {
|
|
|
7
7
|
isLocalLoading?: boolean;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const PrimaryLoader: FC<PrimaryLoaderProps> = ({isLocalLoading
|
|
10
|
+
const PrimaryLoader: FC<PrimaryLoaderProps> = ({isLocalLoading}) => {
|
|
11
11
|
const {isLoading} = useAppSelector(state => state.loader);
|
|
12
12
|
const isVisible = isLocalLoading ?? isLoading;
|
|
13
13
|
return isVisible ? (
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {fonts} from '@fonts';
|
|
2
|
+
import {IC_HidePassword, IC_ShowPassword} from '@images';
|
|
3
|
+
import {colors, perfectSize} from '@theme';
|
|
4
|
+
import {forwardRef, useState} from 'react';
|
|
5
|
+
import {
|
|
6
|
+
StyleProp,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
TextInput,
|
|
9
|
+
TextInputProps,
|
|
10
|
+
TouchableOpacity,
|
|
11
|
+
View,
|
|
12
|
+
ViewStyle,
|
|
13
|
+
} from 'react-native';
|
|
14
|
+
|
|
15
|
+
interface PrimaryTextInputProps extends TextInputProps {
|
|
16
|
+
containerStyle?: StyleProp<ViewStyle> | undefined;
|
|
17
|
+
isPassword?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const PrimaryTextInput = forwardRef(
|
|
21
|
+
(props: PrimaryTextInputProps, ref: any) => {
|
|
22
|
+
const {style, containerStyle, isPassword, ...restProps} = props;
|
|
23
|
+
|
|
24
|
+
const [hidePassword, setHidPassword] = useState<boolean>(true);
|
|
25
|
+
return (
|
|
26
|
+
<View style={[styles.container, containerStyle]}>
|
|
27
|
+
<TextInput
|
|
28
|
+
ref={ref}
|
|
29
|
+
style={[styles.textInput, style]}
|
|
30
|
+
autoCapitalize={'none'}
|
|
31
|
+
autoCorrect={false}
|
|
32
|
+
placeholderTextColor={colors.black60}
|
|
33
|
+
secureTextEntry={isPassword && hidePassword}
|
|
34
|
+
{...restProps}
|
|
35
|
+
/>
|
|
36
|
+
{isPassword && (
|
|
37
|
+
<TouchableOpacity
|
|
38
|
+
activeOpacity={0.6}
|
|
39
|
+
onPress={() => setHidPassword(!hidePassword)}>
|
|
40
|
+
{hidePassword ? (
|
|
41
|
+
<IC_HidePassword
|
|
42
|
+
width={perfectSize(24)}
|
|
43
|
+
height={perfectSize(24)}
|
|
44
|
+
/>
|
|
45
|
+
) : (
|
|
46
|
+
<IC_ShowPassword
|
|
47
|
+
width={perfectSize(24)}
|
|
48
|
+
height={perfectSize(24)}
|
|
49
|
+
/>
|
|
50
|
+
)}
|
|
51
|
+
</TouchableOpacity>
|
|
52
|
+
)}
|
|
53
|
+
</View>
|
|
54
|
+
);
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const styles = StyleSheet.create({
|
|
59
|
+
container: {
|
|
60
|
+
flexDirection: 'row',
|
|
61
|
+
alignItems: 'center',
|
|
62
|
+
height: perfectSize(45),
|
|
63
|
+
borderRadius: perfectSize(6),
|
|
64
|
+
backgroundColor: colors.white,
|
|
65
|
+
paddingHorizontal: perfectSize(16),
|
|
66
|
+
paddingVertical: 0,
|
|
67
|
+
borderWidth: perfectSize(1),
|
|
68
|
+
borderColor: colors.black,
|
|
69
|
+
includeFontPadding: false,
|
|
70
|
+
columnGap: perfectSize(10),
|
|
71
|
+
},
|
|
72
|
+
textInput: {
|
|
73
|
+
flex: 1,
|
|
74
|
+
backgroundColor: colors.white,
|
|
75
|
+
includeFontPadding: false,
|
|
76
|
+
fontFamily: fonts.primary,
|
|
77
|
+
fontSize: perfectSize(14),
|
|
78
|
+
color: colors.black,
|
|
79
|
+
paddingVertical: 0,
|
|
80
|
+
paddingHorizontal: 0,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export default PrimaryTextInput;
|
|
@@ -4,12 +4,16 @@ import PrimaryButton from './PrimaryButton';
|
|
|
4
4
|
import PrimaryText from './PrimaryText';
|
|
5
5
|
import NoInternetModalPopUp from './NoInternetModalPopUp';
|
|
6
6
|
import PrimaryScrollView from './PrimaryScrollView';
|
|
7
|
+
import Container from './Container';
|
|
8
|
+
import PrimaryTextInput from './PrimaryTextInput';
|
|
7
9
|
|
|
8
10
|
export {
|
|
9
11
|
PrimaryLoader,
|
|
10
12
|
PrimaryFlashMessage,
|
|
11
13
|
PrimaryButton,
|
|
12
14
|
PrimaryText,
|
|
15
|
+
PrimaryTextInput,
|
|
13
16
|
PrimaryScrollView,
|
|
14
17
|
NoInternetModalPopUp,
|
|
18
|
+
Container,
|
|
15
19
|
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"loginScreen": {
|
|
3
|
-
"
|
|
4
|
-
"login": "Login"
|
|
5
|
-
"showErrorMessage": "Show Error Message"
|
|
3
|
+
"logIn": "LogIn",
|
|
4
|
+
"login": "Login"
|
|
6
5
|
},
|
|
7
6
|
"modalScreen": {
|
|
8
7
|
"modalScreen": "Modal Screen",
|
|
@@ -10,8 +9,7 @@
|
|
|
10
9
|
},
|
|
11
10
|
"homeScreen": {
|
|
12
11
|
"homeScreen": "Home Screen",
|
|
13
|
-
"openModalScreen": "Open Modal Screen"
|
|
14
|
-
"showSuccessMessage": "Show Success Message"
|
|
12
|
+
"openModalScreen": "Open Modal Screen"
|
|
15
13
|
},
|
|
16
14
|
"profileScreen": {
|
|
17
15
|
"profileScreen": "Profile Screen",
|
|
@@ -20,11 +18,17 @@
|
|
|
20
18
|
"cancel": "Cancel"
|
|
21
19
|
},
|
|
22
20
|
"validations": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
21
|
+
"email": "Please enter email",
|
|
22
|
+
"validEmail": "Please enter valid email",
|
|
23
|
+
"password": "Please enter password"
|
|
24
|
+
},
|
|
25
|
+
"messages": {
|
|
26
|
+
"loginSuccessful": "Login successful!",
|
|
27
|
+
"logoutSuccessful": "Logout successful!"
|
|
25
28
|
},
|
|
26
29
|
"languages": {
|
|
27
30
|
"en": "English",
|
|
28
|
-
"es": "Spanish"
|
|
31
|
+
"es": "Spanish",
|
|
32
|
+
"hi": "Hindi"
|
|
29
33
|
}
|
|
30
34
|
}
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"loginScreen": {
|
|
3
|
-
"
|
|
4
|
-
"login": "
|
|
5
|
-
"showErrorMessage": "Mostrar mensaje de error"
|
|
3
|
+
"logIn": "Iniciar sesión",
|
|
4
|
+
"login": "Acceso"
|
|
6
5
|
},
|
|
7
6
|
"modalScreen": {
|
|
8
7
|
"modalScreen": "Pantalla Modal",
|
|
9
8
|
"modalDescription": "Esta es una pantalla modal. Toque afuera para cerrarla."
|
|
10
9
|
},
|
|
11
10
|
"homeScreen": {
|
|
12
|
-
"homeScreen": "Pantalla
|
|
13
|
-
"openModalScreen": "Abrir
|
|
14
|
-
"showSuccessMessage": "Mostrar mensaje de éxito"
|
|
11
|
+
"homeScreen": "Pantalla Principal",
|
|
12
|
+
"openModalScreen": "Abrir Pantalla Modal"
|
|
15
13
|
},
|
|
16
14
|
"profileScreen": {
|
|
17
15
|
"profileScreen": "Pantalla de Perfil",
|
|
@@ -20,11 +18,17 @@
|
|
|
20
18
|
"cancel": "Cancelar"
|
|
21
19
|
},
|
|
22
20
|
"validations": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
21
|
+
"email": "Por favor ingrese el correo electrónico",
|
|
22
|
+
"validEmail": "Por favor ingrese un correo electrónico válido",
|
|
23
|
+
"password": "Por favor ingrese la contraseña"
|
|
24
|
+
},
|
|
25
|
+
"messages": {
|
|
26
|
+
"loginSuccessful": "¡Inicio de sesión exitoso!",
|
|
27
|
+
"logoutSuccessful": "¡Cierre de sesión exitoso!"
|
|
25
28
|
},
|
|
26
29
|
"languages": {
|
|
27
30
|
"en": "Inglés",
|
|
28
|
-
"es": "Español"
|
|
31
|
+
"es": "Español",
|
|
32
|
+
"hi": "Hindi"
|
|
29
33
|
}
|
|
30
34
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"loginScreen": {
|
|
3
|
+
"logIn": "लॉग इन",
|
|
4
|
+
"login": "लॉगिन"
|
|
5
|
+
},
|
|
6
|
+
"modalScreen": {
|
|
7
|
+
"modalScreen": "मोडल स्क्रीन",
|
|
8
|
+
"modalDescription": "यह एक मोडल स्क्रीन है। बंद करने के लिए बाहर टैप करें।"
|
|
9
|
+
},
|
|
10
|
+
"homeScreen": {
|
|
11
|
+
"homeScreen": "होम स्क्रीन",
|
|
12
|
+
"openModalScreen": "मोडल स्क्रीन खोलें"
|
|
13
|
+
},
|
|
14
|
+
"profileScreen": {
|
|
15
|
+
"profileScreen": "प्रोफाइल स्क्रीन",
|
|
16
|
+
"logout": "लॉगआउट",
|
|
17
|
+
"changeLanguage": "भाषा बदलें",
|
|
18
|
+
"cancel": "रद्द करें"
|
|
19
|
+
},
|
|
20
|
+
"validations": {
|
|
21
|
+
"email": "कृपया ईमेल दर्ज करें",
|
|
22
|
+
"validEmail": "कृपया मान्य ईमेल दर्ज करें",
|
|
23
|
+
"password": "कृपया पासवर्ड दर्ज करें"
|
|
24
|
+
},
|
|
25
|
+
"messages": {
|
|
26
|
+
"loginSuccessful": "लॉगिन सफल हुआ!",
|
|
27
|
+
"logoutSuccessful": "लॉगआउट सफल हुआ!"
|
|
28
|
+
},
|
|
29
|
+
"languages": {
|
|
30
|
+
"en": "अंग्रेज़ी",
|
|
31
|
+
"es": "स्पेनिश",
|
|
32
|
+
"hi": "हिंदी"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -2,17 +2,21 @@ import i18n from 'i18next';
|
|
|
2
2
|
import {initReactI18next} from 'react-i18next';
|
|
3
3
|
import en from './en.json';
|
|
4
4
|
import es from './es.json';
|
|
5
|
+
import hi from './hi.json';
|
|
5
6
|
import moment from 'moment';
|
|
6
7
|
|
|
7
8
|
require('moment/locale/es');
|
|
9
|
+
require('moment/locale/hi');
|
|
8
10
|
|
|
9
11
|
import {ASYNC_KEY, setAsyncData} from '@common';
|
|
12
|
+
import {Languages} from '@types';
|
|
10
13
|
|
|
11
14
|
i18n.use(initReactI18next).init({
|
|
12
15
|
compatibilityJSON: 'v4',
|
|
13
16
|
resources: {
|
|
14
17
|
en: {translation: en},
|
|
15
18
|
es: {translation: es},
|
|
19
|
+
hi: {translation: hi},
|
|
16
20
|
},
|
|
17
21
|
lng: 'en',
|
|
18
22
|
fallbackLng: 'en',
|
|
@@ -29,7 +33,7 @@ i18n.on('languageChanged', lng => {
|
|
|
29
33
|
// Set initial moment locale
|
|
30
34
|
moment.locale(i18n.language);
|
|
31
35
|
|
|
32
|
-
export const onChangeLanguage = async (lang:
|
|
36
|
+
export const onChangeLanguage = async (lang: Languages) => {
|
|
33
37
|
await i18n.changeLanguage(lang);
|
|
34
38
|
await setAsyncData(ASYNC_KEY.LANGUAGE, lang);
|
|
35
39
|
};
|
|
@@ -4,7 +4,6 @@ import {TabNavigationWithAppStackScreenProps} from '@types';
|
|
|
4
4
|
import {colors, perfectSize} from '@theme';
|
|
5
5
|
import {fonts} from '@fonts';
|
|
6
6
|
import {PrimaryButton, PrimaryText} from '@components';
|
|
7
|
-
import {showSuccessMessage} from '@common';
|
|
8
7
|
import {useTranslation} from 'react-i18next';
|
|
9
8
|
import moment from 'moment';
|
|
10
9
|
|
|
@@ -14,22 +13,16 @@ const Home: FC<TabNavigationWithAppStackScreenProps<'Home'>> = ({
|
|
|
14
13
|
const {t: translate} = useTranslation();
|
|
15
14
|
return (
|
|
16
15
|
<View style={styles.mainView}>
|
|
17
|
-
<PrimaryText style={styles.
|
|
16
|
+
<PrimaryText style={styles.lblHomeScreen}>
|
|
18
17
|
{translate('homeScreen.homeScreen')}
|
|
19
18
|
</PrimaryText>
|
|
20
|
-
<PrimaryText style={styles.
|
|
19
|
+
<PrimaryText style={styles.lblHomeScreen}>
|
|
21
20
|
{moment().format('LLLL')}
|
|
22
21
|
</PrimaryText>
|
|
23
22
|
<PrimaryButton
|
|
24
23
|
label={translate('homeScreen.openModalScreen')}
|
|
25
24
|
onPress={() => navigation.navigate('ModalScreen')}
|
|
26
25
|
/>
|
|
27
|
-
<PrimaryButton
|
|
28
|
-
label={translate('homeScreen.showSuccessMessage')}
|
|
29
|
-
onPress={() => {
|
|
30
|
-
showSuccessMessage(translate('validations.testSuccess'));
|
|
31
|
-
}}
|
|
32
|
-
/>
|
|
33
26
|
</View>
|
|
34
27
|
);
|
|
35
28
|
};
|
|
@@ -44,7 +37,7 @@ const styles = StyleSheet.create({
|
|
|
44
37
|
alignItems: 'center',
|
|
45
38
|
rowGap: perfectSize(20),
|
|
46
39
|
},
|
|
47
|
-
|
|
40
|
+
lblHomeScreen: {
|
|
48
41
|
fontFamily: fonts.bold,
|
|
49
42
|
fontSize: perfectSize(20),
|
|
50
43
|
},
|