@fadyshawky/react-native-magic 2.1.3 → 2.1.5
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/package.json +1 -1
- package/template/README.md +78 -45
- package/template/src/common/components/PrimaryTextInput.tsx +11 -2
- package/template/src/core/store/user/userActions.ts +0 -173
- package/template/src/core/store/user/userSlice.ts +9 -248
- package/template/src/core/store/user/userState.ts +2 -128
- package/template/src/screens/Login/Login.tsx +0 -1
- package/template/src/screens/home/hooks/useHomeData.ts +1 -37
- package/template/src/screens/home/types.ts +0 -7
- package/template/src/screens/home/Components/PayByCode.tsx +0 -129
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fadyshawky/react-native-magic",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "Plug-and-play React Native template: TypeScript, Redux, React Navigation, scalable architecture. Init and start developing without hassle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native-magic",
|
package/template/README.md
CHANGED
|
@@ -1,79 +1,112 @@
|
|
|
1
|
-
|
|
1
|
+
# ReactNativeMagic
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Plug and play** – create your app and start developing without hassle.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A production-ready React Native template with TypeScript, Redux, React Navigation, and a scalable architecture (Uprise-style). Use it to bootstrap new apps with one command.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Requirements
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- **Node.js >= 20** ([Download](https://nodejs.org/en/download/))
|
|
10
|
+
- JDK >= 11 ([Download](https://www.oracle.com/java/technologies/downloads/))
|
|
11
|
+
- Ruby >= 2.7.5 (for iOS)
|
|
12
|
+
- Xcode (for iOS) / Android Studio (for Android)
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
## Quick start
|
|
12
15
|
|
|
13
16
|
```bash
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# OR using Yarn
|
|
18
|
-
yarn start
|
|
17
|
+
npx @react-native-community/cli init YourAppName --template @fadyshawky/react-native-magic
|
|
18
|
+
cd YourAppName
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Optional: set your bundle ID at creation:
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
```bash
|
|
24
|
+
npx @react-native-community/cli init YourAppName --template @fadyshawky/react-native-magic --package-name com.yourcompany.yourapp
|
|
25
|
+
```
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
For iOS, install pods:
|
|
26
28
|
|
|
27
29
|
```bash
|
|
28
|
-
|
|
29
|
-
npm run android
|
|
30
|
-
|
|
31
|
-
# OR using Yarn
|
|
32
|
-
yarn android
|
|
30
|
+
cd ios && pod install && cd ..
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
Then run:
|
|
36
34
|
|
|
37
35
|
```bash
|
|
38
|
-
|
|
39
|
-
npm run ios
|
|
36
|
+
npm start
|
|
37
|
+
npm run ios # or an Android variant below
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## First steps after creating your app
|
|
41
|
+
|
|
42
|
+
1. **App name & bundle ID** – Set at init (or you’ll be prompted for package name if you didn’t pass `--package-name`). See [CUSTOMIZATION.md](template/docs/CUSTOMIZATION.md#app-name-and-bundle-id).
|
|
43
|
+
2. **API** – Copy `.env.example` to `.env` and set `API_BASE_URL` (and other vars) for your backend.
|
|
44
|
+
3. **Theme** – Edit `src/core/theme/colors.ts` (and `fonts.ts`, `commonSizes.ts` if needed) for your brand.
|
|
45
|
+
4. **Config** – Optional: adjust `src/core/config/index.ts` for feature toggles or app-level constants.
|
|
46
|
+
|
|
47
|
+
## Documentation
|
|
48
|
+
|
|
49
|
+
In your generated project you’ll have:
|
|
50
|
+
|
|
51
|
+
- **[docs/ARCHITECTURE.md](template/docs/ARCHITECTURE.md)** – Layers, folder map, data flow, SOLID.
|
|
52
|
+
- **[docs/CUSTOMIZATION.md](template/docs/CUSTOMIZATION.md)** – App name, bundle ID, API, theme, adding a screen/slice/language.
|
|
53
|
+
- **[docs/BEST_PRACTICES.md](template/docs/BEST_PRACTICES.md)** – Code style, structure, testing, security, upgrades.
|
|
54
|
+
|
|
55
|
+
## Project structure (in your app)
|
|
40
56
|
|
|
41
|
-
# OR using Yarn
|
|
42
|
-
yarn ios
|
|
43
57
|
```
|
|
58
|
+
src/
|
|
59
|
+
├── common/ # Shared components, localization, helpers, validations, utils
|
|
60
|
+
├── core/ # Store (Redux), API, theme, config
|
|
61
|
+
├── navigation/ # Auth stack, main stack, tabs
|
|
62
|
+
├── screens/ # Feature screens
|
|
63
|
+
└── sheetManager/ # Action sheets
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Scripts
|
|
44
67
|
|
|
45
|
-
|
|
68
|
+
| Command | Description |
|
|
69
|
+
|---------|-------------|
|
|
70
|
+
| `npm start` | Start Metro bundler |
|
|
71
|
+
| `npm run ios` | Run on iOS |
|
|
72
|
+
| `npm run android:prod:debug` | Run Android (production, debug) |
|
|
73
|
+
| `npm run android:prod:release` | Run Android (production, release) |
|
|
74
|
+
| `npm run android:staging:debug` | Run Android (staging, debug) |
|
|
75
|
+
| `npm run android:staging:release` | Run Android (staging, release) |
|
|
76
|
+
| `npm run android:development:debug` | Run Android (development, debug) |
|
|
77
|
+
| `npm run android:development:release` | Run Android (development, release) |
|
|
78
|
+
| `npm test` | Run tests |
|
|
79
|
+
| `npm run lint` | Lint code |
|
|
46
80
|
|
|
47
|
-
|
|
81
|
+
## Versioning
|
|
48
82
|
|
|
49
|
-
|
|
83
|
+
- **React Native**: ^0.84.x (current stable at release).
|
|
84
|
+
- **React**: ^19.2.x.
|
|
85
|
+
- **Node**: >= 20 (LTS).
|
|
50
86
|
|
|
51
|
-
|
|
87
|
+
Dependencies use **caret (^)** so your app can get patch/minor updates independently.
|
|
52
88
|
|
|
53
|
-
|
|
54
|
-
2. For **Android**: Press the <kbd>R</kbd> key twice or select **"Reload"** from the **Developer Menu** (<kbd>Ctrl</kbd> + <kbd>M</kbd> (on Window and Linux) or <kbd>Cmd ⌘</kbd> + <kbd>M</kbd> (on macOS)) to see your changes!
|
|
89
|
+
## Common issues
|
|
55
90
|
|
|
56
|
-
|
|
91
|
+
**iOS – Pod install fails**
|
|
57
92
|
|
|
58
|
-
|
|
93
|
+
```bash
|
|
94
|
+
cd ios && pod deintegrate && pod install && cd ..
|
|
95
|
+
```
|
|
59
96
|
|
|
60
|
-
|
|
97
|
+
**Android – Gradle / SDK**
|
|
61
98
|
|
|
62
|
-
|
|
99
|
+
- Run `./gradlew clean` in `android/`.
|
|
100
|
+
- Ensure `android/local.properties` has `sdk.dir` set to your Android SDK path.
|
|
63
101
|
|
|
64
|
-
|
|
65
|
-
- If you're curious to learn more about React Native, check out the [Introduction to React Native](https://reactnative.dev/docs/getting-started).
|
|
102
|
+
**Upgrading React Native**
|
|
66
103
|
|
|
67
|
-
|
|
104
|
+
Use [React Native Upgrade Helper](https://react-native-community.github.io/upgrade-helper/) (select current → target version) and apply the suggested changes.
|
|
68
105
|
|
|
69
|
-
|
|
106
|
+
## License
|
|
70
107
|
|
|
71
|
-
|
|
108
|
+
MIT – see [LICENSE.md](LICENSE.md).
|
|
72
109
|
|
|
73
|
-
|
|
110
|
+
## Author
|
|
74
111
|
|
|
75
|
-
|
|
76
|
-
- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment.
|
|
77
|
-
- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**.
|
|
78
|
-
- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts.
|
|
79
|
-
- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native.
|
|
112
|
+
Fady Shawky – [GitHub](https://github.com/fadyshawky)
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
ViewStyle,
|
|
23
23
|
} from 'react-native';
|
|
24
24
|
import {useTheme} from '../../core/theme/ThemeProvider';
|
|
25
|
-
import {PrimaryColors, AlertColors} from '../../core/theme/colors';
|
|
25
|
+
import {PrimaryColors, AlertColors, NaturalColors} from '../../core/theme/colors';
|
|
26
26
|
import {isIos} from '../../core/theme/commonConsts';
|
|
27
27
|
import {CommonSizes} from '../../core/theme/commonSizes';
|
|
28
28
|
import {CommonStyles} from '../../core/theme/commonStyles';
|
|
@@ -93,6 +93,15 @@ export const PrimaryTextInput: FC<IProps> = memo(
|
|
|
93
93
|
const {theme} = useTheme();
|
|
94
94
|
const [regexError, setRegexError] = useState<string | null>(null);
|
|
95
95
|
|
|
96
|
+
// Ensure gradient colors are always a valid array (BVLinearGradient crashes on null/undefined)
|
|
97
|
+
const gradientColors = useMemo(
|
|
98
|
+
() => [
|
|
99
|
+
theme.colors.mutedLavender ?? NaturalColors.naturalColor_100,
|
|
100
|
+
theme.colors.indigoBlue ?? PrimaryColors.PlatinateBlue_400,
|
|
101
|
+
],
|
|
102
|
+
[theme.colors.mutedLavender, theme.colors.indigoBlue],
|
|
103
|
+
);
|
|
104
|
+
|
|
96
105
|
const onLocalFocus = useCallback(
|
|
97
106
|
(e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
98
107
|
setFocused(true);
|
|
@@ -158,7 +167,7 @@ export const PrimaryTextInput: FC<IProps> = memo(
|
|
|
158
167
|
}}>
|
|
159
168
|
<GradientBorderView
|
|
160
169
|
gradientProps={{
|
|
161
|
-
colors:
|
|
170
|
+
colors: gradientColors,
|
|
162
171
|
}}
|
|
163
172
|
style={{
|
|
164
173
|
borderWidth: CommonSizes.borderWidth.small,
|
|
@@ -37,176 +37,3 @@ export const userLogin = createAsyncThunk(
|
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
);
|
|
40
|
-
|
|
41
|
-
export const verifyOTP = createAsyncThunk(
|
|
42
|
-
'user/verifyOTP',
|
|
43
|
-
async (
|
|
44
|
-
{
|
|
45
|
-
verification_code,
|
|
46
|
-
mobile_number,
|
|
47
|
-
device_token,
|
|
48
|
-
scheme_id,
|
|
49
|
-
}: {
|
|
50
|
-
verification_code: string;
|
|
51
|
-
mobile_number: string;
|
|
52
|
-
device_token?: string;
|
|
53
|
-
scheme_id: number;
|
|
54
|
-
},
|
|
55
|
-
{rejectWithValue, getState, dispatch}: any,
|
|
56
|
-
) => {
|
|
57
|
-
try {
|
|
58
|
-
const data: {
|
|
59
|
-
mobile_number: string;
|
|
60
|
-
verification_code: string;
|
|
61
|
-
device_token?: string;
|
|
62
|
-
scheme_id: number;
|
|
63
|
-
} = {
|
|
64
|
-
mobile_number,
|
|
65
|
-
verification_code,
|
|
66
|
-
device_token: undefined,
|
|
67
|
-
scheme_id: 1,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const token = (getState() as RootState).user.tempToken;
|
|
71
|
-
|
|
72
|
-
const response = await post({
|
|
73
|
-
url: 'wallet_users/verifylogin',
|
|
74
|
-
data,
|
|
75
|
-
config: {
|
|
76
|
-
headers: {
|
|
77
|
-
Authorization: `${token}`,
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
return handleFetchJsonResponse(response);
|
|
83
|
-
} catch (e: any) {
|
|
84
|
-
const serverError = extractServerError(e);
|
|
85
|
-
|
|
86
|
-
return rejectWithValue({
|
|
87
|
-
...serverError,
|
|
88
|
-
message: ensureString(serverError.message),
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
export const getBalance = createAsyncThunk(
|
|
95
|
-
'user/getBalance',
|
|
96
|
-
async (_, {rejectWithValue, getState, dispatch}: any) => {
|
|
97
|
-
try {
|
|
98
|
-
const token = (getState() as RootState).user.accessToken;
|
|
99
|
-
|
|
100
|
-
const response = await post({
|
|
101
|
-
url: 'wallet_users/getbalance',
|
|
102
|
-
data: {},
|
|
103
|
-
config: {
|
|
104
|
-
headers: {
|
|
105
|
-
Authorization: `${token}`,
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
return handleFetchJsonResponse(response);
|
|
111
|
-
} catch (e: any) {
|
|
112
|
-
const serverError = extractServerError(e);
|
|
113
|
-
|
|
114
|
-
return rejectWithValue({
|
|
115
|
-
...serverError,
|
|
116
|
-
message: ensureString(serverError.message),
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
export const resetPassword = createAsyncThunk(
|
|
123
|
-
'user/resetPassword',
|
|
124
|
-
async (
|
|
125
|
-
{
|
|
126
|
-
mpin,
|
|
127
|
-
new_mpin,
|
|
128
|
-
confirm_mpin,
|
|
129
|
-
}: {mpin: string; new_mpin: string; confirm_mpin: string},
|
|
130
|
-
{rejectWithValue, getState},
|
|
131
|
-
) => {
|
|
132
|
-
try {
|
|
133
|
-
const token = (getState() as RootState).user.accessToken;
|
|
134
|
-
|
|
135
|
-
const response = await post({
|
|
136
|
-
url: 'wallet_users/force-update-mpin',
|
|
137
|
-
data: {mpin, new_mpin, confirm_mpin},
|
|
138
|
-
config: {
|
|
139
|
-
headers: {
|
|
140
|
-
Authorization: `${token}`,
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
return handleFetchJsonResponse(response);
|
|
146
|
-
} catch (e: any) {
|
|
147
|
-
const serverError = extractServerError(e);
|
|
148
|
-
|
|
149
|
-
return rejectWithValue({
|
|
150
|
-
...serverError,
|
|
151
|
-
message: ensureString(serverError.message),
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
export const fetchHistory = createAsyncThunk(
|
|
158
|
-
'user/fetchHistory',
|
|
159
|
-
async (
|
|
160
|
-
{data}: {data: {page: number; limit: number}},
|
|
161
|
-
{rejectWithValue, getState},
|
|
162
|
-
) => {
|
|
163
|
-
try {
|
|
164
|
-
const token = (getState() as RootState).user.accessToken;
|
|
165
|
-
const response = await post({
|
|
166
|
-
url: 'wallet_users/history',
|
|
167
|
-
data: {page: data.page, limit: data.limit},
|
|
168
|
-
config: {
|
|
169
|
-
headers: {
|
|
170
|
-
Authorization: `${token}`,
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
return handleFetchJsonResponse(response);
|
|
176
|
-
} catch (e: any) {
|
|
177
|
-
const serverError = extractServerError(e);
|
|
178
|
-
|
|
179
|
-
return rejectWithValue({
|
|
180
|
-
...serverError,
|
|
181
|
-
message: ensureString(serverError.message),
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
export const fetchHistoryDetails = createAsyncThunk(
|
|
188
|
-
'user/fetchHistoryDetails',
|
|
189
|
-
async ({trxRef}: {trxRef: string}, {rejectWithValue, getState}) => {
|
|
190
|
-
try {
|
|
191
|
-
const token = (getState() as RootState).user.accessToken;
|
|
192
|
-
|
|
193
|
-
const response = await post({
|
|
194
|
-
url: 'wallet_users/history/details',
|
|
195
|
-
data: {trxRef},
|
|
196
|
-
config: {
|
|
197
|
-
headers: {
|
|
198
|
-
Authorization: `${token}`,
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
return handleFetchJsonResponse(response);
|
|
204
|
-
} catch (e: any) {
|
|
205
|
-
const serverError = extractServerError(e);
|
|
206
|
-
return rejectWithValue({
|
|
207
|
-
...serverError,
|
|
208
|
-
message: ensureString(serverError.message),
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
);
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
import {createSlice} from '@reduxjs/toolkit';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
import { cloneDeep, uniqBy } from 'lodash';
|
|
3
|
+
import { LoadState } from '../../../../types';
|
|
4
|
+
import { newState } from '../../../common/utils/newState';
|
|
5
|
+
import { handleErrorResponse } from '../../api/responseHandlers';
|
|
5
6
|
import {
|
|
6
|
-
|
|
7
|
-
userLogin,
|
|
8
|
-
getBalance,
|
|
9
|
-
verifyOTP,
|
|
10
|
-
fetchHistoryDetails,
|
|
11
|
-
fetchHistory,
|
|
7
|
+
userLogin
|
|
12
8
|
} from './userActions';
|
|
13
|
-
import {UserInitialState,
|
|
14
|
-
import {cloneDeep, uniqBy} from 'lodash';
|
|
9
|
+
import { UserInitialState, UserState } from './userState';
|
|
15
10
|
|
|
16
|
-
function loginHandler(state: UserState, payload: {payload:
|
|
11
|
+
function loginHandler(state: UserState, payload: {payload: any}) {
|
|
17
12
|
return newState(state, {
|
|
18
|
-
tempToken: payload.payload.token,
|
|
19
13
|
loginLoading: LoadState['allIsLoaded'],
|
|
20
14
|
});
|
|
21
15
|
}
|
|
@@ -36,257 +30,24 @@ function loginErrorHandler(
|
|
|
36
30
|
});
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
function verifyOTPHandler(state: UserState, payload: {payload: UserPayload}) {
|
|
40
|
-
return newState(state, {
|
|
41
|
-
user: {
|
|
42
|
-
type: payload.payload.type,
|
|
43
|
-
mobile_number: payload.payload.mobile_number,
|
|
44
|
-
full_name: payload.payload.fullname,
|
|
45
|
-
merchantStore: payload.payload.merchantStore,
|
|
46
|
-
status: payload.payload.status,
|
|
47
|
-
},
|
|
48
|
-
accessToken: payload.payload.token,
|
|
49
|
-
loginLoading: LoadState['allIsLoaded'],
|
|
50
|
-
current_balance: payload?.payload?.current_balance?.find(
|
|
51
|
-
i => i.name === 'Deposit',
|
|
52
|
-
)?.value,
|
|
53
|
-
daily_commission: payload?.payload?.current_balance?.find(
|
|
54
|
-
i => i.name === 'Daily Commission',
|
|
55
|
-
)?.value,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
function verifyOTPLoadingHandler(state: UserState) {
|
|
59
|
-
return newState(state, {
|
|
60
|
-
loginLoading: LoadState['pullToRefresh'],
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function verifyOTPErrorHandler(
|
|
65
|
-
state: UserState,
|
|
66
|
-
payload: {payload: {message: string}},
|
|
67
|
-
) {
|
|
68
|
-
handleErrorResponse(
|
|
69
|
-
(payload.payload.message as string) || 'Verify OTP failed',
|
|
70
|
-
);
|
|
71
|
-
return newState(state, {
|
|
72
|
-
loginLoading: LoadState['error'],
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
33
|
function logoutHandler(state: UserState) {
|
|
77
34
|
return newState(state, UserInitialState);
|
|
78
35
|
}
|
|
79
36
|
|
|
80
|
-
function resetPasswordHandler(
|
|
81
|
-
state: UserState,
|
|
82
|
-
payload: {payload: UserPayload},
|
|
83
|
-
) {
|
|
84
|
-
return newState(state, {
|
|
85
|
-
user: {
|
|
86
|
-
...state.user,
|
|
87
|
-
status: payload.payload.status,
|
|
88
|
-
},
|
|
89
|
-
loginLoading: LoadState['allIsLoaded'],
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function resetPasswordLoadingHandler(state: UserState) {
|
|
94
|
-
return newState(state, {
|
|
95
|
-
loginLoading: LoadState['pullToRefresh'],
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function getBalanceHandler(state: UserState, payload: {payload: UserPayload}) {
|
|
100
|
-
return newState(state, {
|
|
101
|
-
current_balance: payload?.payload?.balance?.find(i => i.name === 'Deposit')
|
|
102
|
-
?.value,
|
|
103
|
-
daily_commission: payload?.payload?.balance?.find(
|
|
104
|
-
i => i.name === 'Daily Commission',
|
|
105
|
-
)?.value,
|
|
106
|
-
loginLoading: LoadState['allIsLoaded'],
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function getBalanceLoadingHandler(state: UserState) {
|
|
111
|
-
return newState(state, {
|
|
112
|
-
loginLoading: LoadState['pullToRefresh'],
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function getBalanceErrorHandler(
|
|
117
|
-
state: UserState,
|
|
118
|
-
payload: {payload: {message: string}},
|
|
119
|
-
) {
|
|
120
|
-
handleErrorResponse((payload.payload.message as string) || 'Register failed');
|
|
121
|
-
return newState(state, {
|
|
122
|
-
loginLoading: LoadState['error'],
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function updateHandler(state: UserState, payload: any) {
|
|
127
|
-
return newState(state, {
|
|
128
|
-
user: {
|
|
129
|
-
...state.user,
|
|
130
|
-
...payload.payload,
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function resetPasswordErrorHandler(
|
|
136
|
-
state: UserState,
|
|
137
|
-
payload: {payload: {message: string}},
|
|
138
|
-
) {
|
|
139
|
-
handleErrorResponse(
|
|
140
|
-
(payload.payload.message as string) || 'Password reset failed',
|
|
141
|
-
);
|
|
142
|
-
return newState(state, {
|
|
143
|
-
loginLoading: LoadState['error'],
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function setFavoriteCategoriesHandler(
|
|
148
|
-
state: UserState,
|
|
149
|
-
payload: {payload: number},
|
|
150
|
-
) {
|
|
151
|
-
if (!state.favoriteCategories) {
|
|
152
|
-
state.favoriteCategories = [];
|
|
153
|
-
}
|
|
154
|
-
state.favoriteCategories.push(payload.payload);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function setFavoriteProvidersHandler(
|
|
158
|
-
state: UserState,
|
|
159
|
-
payload: {payload: number},
|
|
160
|
-
) {
|
|
161
|
-
if (!state.favoriteProviders) {
|
|
162
|
-
state.favoriteProviders = [];
|
|
163
|
-
}
|
|
164
|
-
state.favoriteProviders.push(payload.payload);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function removeFavoriteCategoriesHandler(
|
|
168
|
-
state: UserState,
|
|
169
|
-
payload: {payload: number},
|
|
170
|
-
) {
|
|
171
|
-
if (state.favoriteCategories) {
|
|
172
|
-
state.favoriteCategories = state.favoriteCategories.filter(
|
|
173
|
-
id => id !== payload.payload,
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function removeFavoriteProvidersHandler(
|
|
179
|
-
state: UserState,
|
|
180
|
-
payload: {payload: number},
|
|
181
|
-
) {
|
|
182
|
-
if (state.favoriteProviders) {
|
|
183
|
-
state.favoriteProviders = state.favoriteProviders.filter(
|
|
184
|
-
id => id !== payload.payload,
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function fetchHistoryHandler(
|
|
190
|
-
state: UserState,
|
|
191
|
-
payload: {payload: UserPayload},
|
|
192
|
-
) {
|
|
193
|
-
let tmp = cloneDeep(state.history);
|
|
194
|
-
tmp = [...tmp, ...payload.payload.requests];
|
|
195
|
-
tmp = uniqBy(tmp, 'transaction_reference_num');
|
|
196
|
-
return newState(state, {
|
|
197
|
-
history: tmp,
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function fetchHistoryLoadingHandler(state: UserState) {
|
|
202
|
-
return newState(state, {
|
|
203
|
-
loginLoading: LoadState['pullToRefresh'],
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function fetchHistoryErrorHandler(
|
|
208
|
-
state: UserState,
|
|
209
|
-
payload: {payload: {message: string}},
|
|
210
|
-
) {
|
|
211
|
-
handleErrorResponse(
|
|
212
|
-
(payload.payload.message as string) || 'Fetch history failed',
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function fetchHistoryDetailsHandler(
|
|
217
|
-
state: UserState,
|
|
218
|
-
payload: {payload: UserPayload},
|
|
219
|
-
) {
|
|
220
|
-
return newState(state, {
|
|
221
|
-
historyDetails: payload.payload.data,
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function fetchHistoryDetailsLoadingHandler(state: UserState) {
|
|
226
|
-
return newState(state, {
|
|
227
|
-
loginLoading: LoadState['pullToRefresh'],
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function fetchHistoryDetailsErrorHandler(
|
|
232
|
-
state: UserState,
|
|
233
|
-
payload: {payload: {message: string}},
|
|
234
|
-
) {
|
|
235
|
-
handleErrorResponse(
|
|
236
|
-
(payload.payload.message as string) || 'Fetch history details failed',
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function clearHistoryHandler(state: UserState) {
|
|
241
|
-
return newState(state, {
|
|
242
|
-
history: UserInitialState.history,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
37
|
export const {reducer: UserReducer, actions} = createSlice({
|
|
247
38
|
name: 'user',
|
|
248
39
|
initialState: UserInitialState,
|
|
249
40
|
reducers: {
|
|
250
|
-
setLogin: loginHandler,
|
|
251
|
-
setLoginLoading: loginLoadingHandler,
|
|
252
|
-
setLoginError: loginLoadingHandler,
|
|
253
41
|
setLogout: logoutHandler,
|
|
254
|
-
setUpdate: updateHandler,
|
|
255
|
-
setFavoriteCategories: setFavoriteCategoriesHandler,
|
|
256
|
-
setFavoriteProviders: setFavoriteProvidersHandler,
|
|
257
|
-
removeFavoriteCategories: removeFavoriteCategoriesHandler,
|
|
258
|
-
removeFavoriteProviders: removeFavoriteProvidersHandler,
|
|
259
|
-
clearHistory: clearHistoryHandler,
|
|
260
42
|
},
|
|
261
43
|
extraReducers: builder => {
|
|
262
44
|
builder
|
|
263
45
|
.addCase(userLogin.fulfilled, loginHandler)
|
|
264
46
|
.addCase(userLogin.rejected, loginErrorHandler)
|
|
265
|
-
.addCase(userLogin.pending, loginLoadingHandler)
|
|
266
|
-
.addCase(resetPassword.fulfilled, resetPasswordHandler)
|
|
267
|
-
.addCase(resetPassword.rejected, resetPasswordErrorHandler)
|
|
268
|
-
.addCase(resetPassword.pending, resetPasswordLoadingHandler)
|
|
269
|
-
.addCase(getBalance.fulfilled, getBalanceHandler)
|
|
270
|
-
.addCase(getBalance.rejected, getBalanceErrorHandler)
|
|
271
|
-
.addCase(getBalance.pending, getBalanceLoadingHandler)
|
|
272
|
-
.addCase(verifyOTP.fulfilled, verifyOTPHandler)
|
|
273
|
-
.addCase(verifyOTP.rejected, verifyOTPErrorHandler)
|
|
274
|
-
.addCase(verifyOTP.pending, verifyOTPLoadingHandler)
|
|
275
|
-
.addCase(fetchHistory.fulfilled, fetchHistoryHandler)
|
|
276
|
-
.addCase(fetchHistory.rejected, fetchHistoryErrorHandler)
|
|
277
|
-
.addCase(fetchHistory.pending, fetchHistoryLoadingHandler)
|
|
278
|
-
.addCase(fetchHistoryDetails.fulfilled, fetchHistoryDetailsHandler)
|
|
279
|
-
.addCase(fetchHistoryDetails.rejected, fetchHistoryDetailsErrorHandler)
|
|
280
|
-
.addCase(fetchHistoryDetails.pending, fetchHistoryDetailsLoadingHandler);
|
|
47
|
+
.addCase(userLogin.pending, loginLoadingHandler);
|
|
281
48
|
},
|
|
282
49
|
});
|
|
283
50
|
|
|
284
51
|
export const {
|
|
285
52
|
setLogout,
|
|
286
|
-
setUpdate,
|
|
287
|
-
setFavoriteCategories,
|
|
288
|
-
setFavoriteProviders,
|
|
289
|
-
removeFavoriteCategories,
|
|
290
|
-
removeFavoriteProviders,
|
|
291
|
-
clearHistory,
|
|
292
53
|
} = actions;
|
|
@@ -2,105 +2,16 @@ import {LoadState} from '../../../../types';
|
|
|
2
2
|
|
|
3
3
|
export interface UserState {
|
|
4
4
|
user: User;
|
|
5
|
-
current_balance: number;
|
|
6
|
-
daily_commission: number;
|
|
7
5
|
accessToken: string;
|
|
8
6
|
loginLoading: string;
|
|
9
|
-
tempToken: string;
|
|
10
|
-
favoriteCategories: number[];
|
|
11
|
-
favoriteProviders: number[];
|
|
12
|
-
history: HistoryEntity[];
|
|
13
|
-
historyDetails: HistoryDetailsEntity[];
|
|
14
7
|
}
|
|
15
8
|
export interface User {
|
|
16
9
|
type: string;
|
|
17
10
|
mobile_number: string;
|
|
18
11
|
full_name: string;
|
|
19
|
-
merchantStore: MerchantStore;
|
|
20
12
|
status: string;
|
|
21
13
|
}
|
|
22
|
-
|
|
23
|
-
id: number;
|
|
24
|
-
wallet_user_id: number;
|
|
25
|
-
name: string;
|
|
26
|
-
address: string;
|
|
27
|
-
city: string;
|
|
28
|
-
region: string;
|
|
29
|
-
store_imgs?: null;
|
|
30
|
-
tax_card?: null;
|
|
31
|
-
commercial_registration?: null;
|
|
32
|
-
createdAt: string;
|
|
33
|
-
updatedAt: string;
|
|
34
|
-
id_front: string;
|
|
35
|
-
id_back: string;
|
|
36
|
-
selfie?: null;
|
|
37
|
-
}
|
|
38
|
-
export interface HistoryEntity {
|
|
39
|
-
id: number;
|
|
40
|
-
transaction_reference_num: string;
|
|
41
|
-
bee_transaction_id?: null;
|
|
42
|
-
fawry_transaction_id?: string | null;
|
|
43
|
-
transaction_serial_num?: string | null;
|
|
44
|
-
amount: string | number;
|
|
45
|
-
sender_fees: string;
|
|
46
|
-
reciever_fees: string;
|
|
47
|
-
sender_identifier: string;
|
|
48
|
-
reciever_identifier: string;
|
|
49
|
-
status: string;
|
|
50
|
-
sender_status: string;
|
|
51
|
-
receiver_status: string;
|
|
52
|
-
reason?: null;
|
|
53
|
-
transactionReason: string;
|
|
54
|
-
display_reason?: null;
|
|
55
|
-
sender_interchange_amount: string;
|
|
56
|
-
receiver_interchange_amount: string;
|
|
57
|
-
sender_commission: string;
|
|
58
|
-
receiver_commission: string;
|
|
59
|
-
bulk_id?: null;
|
|
60
|
-
sender_name: string;
|
|
61
|
-
receiver_name: string;
|
|
62
|
-
notification_id?: null;
|
|
63
|
-
transaction_data?: null;
|
|
64
|
-
convenience: string;
|
|
65
|
-
tips: string;
|
|
66
|
-
reference1?: null;
|
|
67
|
-
reference2?: null;
|
|
68
|
-
meta?: null;
|
|
69
|
-
createdAt: string;
|
|
70
|
-
updatedAt: string;
|
|
71
|
-
transaction_type: number;
|
|
72
|
-
sender_id: number;
|
|
73
|
-
reciever_id: number;
|
|
74
|
-
sender_scheme_id: number;
|
|
75
|
-
receiver_scheme_id: number;
|
|
76
|
-
'Transaction_type.id': number;
|
|
77
|
-
'Transaction_type.name': string;
|
|
78
|
-
'Transaction_type.name_ar'?: null;
|
|
79
|
-
'Transaction_type.request_type': string;
|
|
80
|
-
'Transaction_type.request_type_ar'?: null;
|
|
81
|
-
'Transaction_type.timeout': string;
|
|
82
|
-
'Transaction_type.on_off_us': string;
|
|
83
|
-
'Transaction_type.sender_type': string;
|
|
84
|
-
'Transaction_type.profile_type'?: null;
|
|
85
|
-
'Transaction_type.receiver_type': string;
|
|
86
|
-
'Transaction_type.tahweel_operation': string;
|
|
87
|
-
'Transaction_type.send_fees'?: string | null;
|
|
88
|
-
'Transaction_type.receive_fees': string;
|
|
89
|
-
'Transaction_type.send_limit': string;
|
|
90
|
-
'Transaction_type.receive_limit': string;
|
|
91
|
-
'Transaction_type.send_commision'?: string | null;
|
|
92
|
-
'Transaction_type.receive_commision'?: null;
|
|
93
|
-
'Transaction_type.createdAt': string;
|
|
94
|
-
'Transaction_type.updatedAt': string;
|
|
95
|
-
providerName?: string | null;
|
|
96
|
-
serviceName?: string | null;
|
|
97
|
-
totalAmount?: number | null;
|
|
98
|
-
}
|
|
99
|
-
export interface HistoryDetailsEntity {
|
|
100
|
-
value: string;
|
|
101
|
-
type: string;
|
|
102
|
-
label?: string;
|
|
103
|
-
}
|
|
14
|
+
|
|
104
15
|
|
|
105
16
|
export enum UserStatus {
|
|
106
17
|
ACTIVE = 'Active',
|
|
@@ -109,25 +20,7 @@ export enum UserStatus {
|
|
|
109
20
|
PENDING = 'Pending',
|
|
110
21
|
}
|
|
111
22
|
|
|
112
|
-
|
|
113
|
-
type: string;
|
|
114
|
-
mobile_number: string;
|
|
115
|
-
full_name: string;
|
|
116
|
-
merchantStore: MerchantStore;
|
|
117
|
-
requests: HistoryEntity[];
|
|
118
|
-
data: HistoryDetailsEntity[];
|
|
119
|
-
balance: {
|
|
120
|
-
name: string;
|
|
121
|
-
value: number;
|
|
122
|
-
}[];
|
|
123
|
-
current_balance: {
|
|
124
|
-
name: string;
|
|
125
|
-
value: number;
|
|
126
|
-
}[];
|
|
127
|
-
status: UserStatus;
|
|
128
|
-
fullname: string;
|
|
129
|
-
token: string;
|
|
130
|
-
}
|
|
23
|
+
|
|
131
24
|
|
|
132
25
|
export const UserInitialState: UserState = {
|
|
133
26
|
user: {
|
|
@@ -135,28 +28,9 @@ export const UserInitialState: UserState = {
|
|
|
135
28
|
mobile_number: '',
|
|
136
29
|
full_name: '',
|
|
137
30
|
status: UserStatus.PENDING,
|
|
138
|
-
merchantStore: {
|
|
139
|
-
id: 0,
|
|
140
|
-
wallet_user_id: 0,
|
|
141
|
-
name: '',
|
|
142
|
-
address: '',
|
|
143
|
-
city: '',
|
|
144
|
-
region: '',
|
|
145
|
-
createdAt: '',
|
|
146
|
-
updatedAt: '',
|
|
147
|
-
id_front: '',
|
|
148
|
-
id_back: '',
|
|
149
|
-
},
|
|
150
31
|
},
|
|
151
|
-
current_balance: 0,
|
|
152
|
-
daily_commission: 0,
|
|
153
32
|
accessToken: '',
|
|
154
33
|
loginLoading: LoadState['needLoad'],
|
|
155
|
-
tempToken: '',
|
|
156
|
-
favoriteCategories: [],
|
|
157
|
-
favoriteProviders: [],
|
|
158
|
-
history: [],
|
|
159
|
-
historyDetails: [],
|
|
160
34
|
};
|
|
161
35
|
|
|
162
36
|
export interface UserEntity {
|
|
@@ -21,7 +21,6 @@ import {userLogin} from '../../core/store/user/userActions';
|
|
|
21
21
|
import {CommonSizes} from '../../core/theme/commonSizes';
|
|
22
22
|
import {Fonts} from '../../core/theme/fonts';
|
|
23
23
|
import {useTheme} from '../../core/theme/ThemeProvider';
|
|
24
|
-
import {Header} from '../../navigation/HeaderComponents';
|
|
25
24
|
import type {RootStackParamList} from '../../navigation/types';
|
|
26
25
|
|
|
27
26
|
export function Login(): JSX.Element {
|
|
@@ -1,54 +1,18 @@
|
|
|
1
1
|
import {useState} from 'react';
|
|
2
|
-
import {getCategories} from '../../../core/store/Categories/categoryActions';
|
|
3
|
-
import {clearSelectedCategory} from '../../../core/store/Categories/categorySlice';
|
|
4
|
-
import {getHomeProviders} from '../../../core/store/Providers/providersActions';
|
|
5
2
|
import {useAppDispatch, useAppSelector} from '../../../core/store/reduxHelpers';
|
|
6
3
|
import {RootState} from '../../../core/store/rootReducer';
|
|
7
|
-
import {getBalance} from '../../../core/store/user/userActions';
|
|
8
|
-
import {clearSelectedProvider} from '../../../core/store/Providers/providersSlice';
|
|
9
4
|
export function useHomeData() {
|
|
10
5
|
const [isLoading, setIsLoading] = useState(false);
|
|
11
6
|
const dispatch = useAppDispatch();
|
|
12
7
|
const {categories, loadState} = useAppSelector(
|
|
13
8
|
(state: RootState) => state.categories,
|
|
14
9
|
);
|
|
15
|
-
const [isPayByCodeModalVisible, setIsPayByCodeModalVisible] = useState(false);
|
|
16
|
-
const {homeProviders} = useAppSelector((state: RootState) => state.providers);
|
|
17
10
|
const {user} = useAppSelector((state: RootState) => state.user);
|
|
18
11
|
|
|
19
|
-
|
|
20
|
-
setIsLoading(true);
|
|
21
|
-
try {
|
|
22
|
-
const balance = await dispatch(getBalance());
|
|
23
|
-
if (balance.type.includes('fulfilled')) {
|
|
24
|
-
const categoryResponse = await dispatch(
|
|
25
|
-
getCategories({data: {limit: 30}}),
|
|
26
|
-
);
|
|
27
|
-
if (categoryResponse.type.includes('fulfilled')) {
|
|
28
|
-
const category_id = categoryResponse?.payload?.categories?.[0]?.id;
|
|
29
|
-
await dispatch(getHomeProviders({data: {category_id: category_id}}));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error('Error fetching home data:', error);
|
|
34
|
-
} finally {
|
|
35
|
-
setIsLoading(false);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const refreshData = () => {
|
|
40
|
-
fetchData();
|
|
41
|
-
};
|
|
12
|
+
|
|
42
13
|
|
|
43
14
|
return {
|
|
44
15
|
isLoading,
|
|
45
|
-
refreshData,
|
|
46
|
-
fetchData,
|
|
47
|
-
categories,
|
|
48
16
|
user,
|
|
49
|
-
homeProviders,
|
|
50
|
-
loadState,
|
|
51
|
-
isPayByCodeModalVisible,
|
|
52
|
-
setIsPayByCodeModalVisible,
|
|
53
17
|
};
|
|
54
18
|
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import React, {useState} from 'react';
|
|
2
|
-
import {Modal, StyleSheet, View} from 'react-native';
|
|
3
|
-
import {RTLAwareView} from '../../../common/components/RTLAwareView';
|
|
4
|
-
import {CommonSizes} from '../../../core/theme/commonSizes';
|
|
5
|
-
import {PrimaryTextInput} from '../../../common/components/PrimaryTextInput';
|
|
6
|
-
import {useTheme} from '../../../core/theme/ThemeProvider';
|
|
7
|
-
import {PrimaryButton} from '../../../common/components/PrimaryButton';
|
|
8
|
-
import {ButtonType} from '../../../../types';
|
|
9
|
-
import {useAppDispatch} from '../../../core/store/reduxHelpers';
|
|
10
|
-
import {getServiceById} from '../../../core/store/Services/servicesActions';
|
|
11
|
-
import {getProviderById} from '../../../core/store/Providers/providersActions';
|
|
12
|
-
import {useNavigation} from '@react-navigation/native';
|
|
13
|
-
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
|
14
|
-
import {RootStackParamList} from '../../../navigation/types';
|
|
15
|
-
import {useTranslation} from '../../../common/localization/LocalizationProvider';
|
|
16
|
-
|
|
17
|
-
export function PayByCode({
|
|
18
|
-
isVisible,
|
|
19
|
-
onClose,
|
|
20
|
-
}: {
|
|
21
|
-
isVisible: boolean;
|
|
22
|
-
onClose: () => void;
|
|
23
|
-
}): JSX.Element {
|
|
24
|
-
const {theme} = useTheme();
|
|
25
|
-
const t = useTranslation();
|
|
26
|
-
const [code, setCode] = useState('');
|
|
27
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
28
|
-
const dispatch = useAppDispatch();
|
|
29
|
-
const navigation =
|
|
30
|
-
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
|
|
31
|
-
|
|
32
|
-
const getService = async () => {
|
|
33
|
-
if (!code) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
setIsLoading(true);
|
|
38
|
-
const response = await dispatch(
|
|
39
|
-
getServiceById({data: {BillTypeCode: code}}),
|
|
40
|
-
);
|
|
41
|
-
if (response.type.includes('fulfilled')) {
|
|
42
|
-
const providerResponse = await dispatch(
|
|
43
|
-
getProviderById({
|
|
44
|
-
data: {BillerId: response.payload.service.BillerId},
|
|
45
|
-
}),
|
|
46
|
-
);
|
|
47
|
-
if (providerResponse.type.includes('fulfilled')) {
|
|
48
|
-
setCode('');
|
|
49
|
-
onClose();
|
|
50
|
-
setTimeout(() => {
|
|
51
|
-
navigation.navigate('SingleService', {
|
|
52
|
-
serviceID: undefined,
|
|
53
|
-
});
|
|
54
|
-
}, 200);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.error(error);
|
|
59
|
-
} finally {
|
|
60
|
-
setIsLoading(false);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<Modal
|
|
66
|
-
onRequestClose={onClose}
|
|
67
|
-
visible={isVisible}
|
|
68
|
-
transparent
|
|
69
|
-
style={styles.modal}>
|
|
70
|
-
<RTLAwareView
|
|
71
|
-
style={{
|
|
72
|
-
...styles.container,
|
|
73
|
-
backgroundColor: theme.colors.surface,
|
|
74
|
-
borderWidth: 1,
|
|
75
|
-
borderColor: theme.colors.indigoBlue,
|
|
76
|
-
}}>
|
|
77
|
-
<PrimaryTextInput
|
|
78
|
-
value={code}
|
|
79
|
-
onChangeText={setCode}
|
|
80
|
-
placeholder={t('enterCode', 'home')}
|
|
81
|
-
/>
|
|
82
|
-
<RTLAwareView
|
|
83
|
-
style={{
|
|
84
|
-
flexDirection: 'row',
|
|
85
|
-
alignItems: 'center',
|
|
86
|
-
justifyContent: 'space-between',
|
|
87
|
-
}}>
|
|
88
|
-
<PrimaryButton
|
|
89
|
-
disabled={isLoading}
|
|
90
|
-
isLoading={isLoading}
|
|
91
|
-
onPress={() => {
|
|
92
|
-
onClose();
|
|
93
|
-
setCode('');
|
|
94
|
-
}}
|
|
95
|
-
style={{width: '48%'}}
|
|
96
|
-
label={t('cancel', 'home')}
|
|
97
|
-
type={ButtonType.solid}
|
|
98
|
-
/>
|
|
99
|
-
<PrimaryButton
|
|
100
|
-
disabled={isLoading}
|
|
101
|
-
isLoading={isLoading}
|
|
102
|
-
onPress={getService}
|
|
103
|
-
style={{width: '48%'}}
|
|
104
|
-
label={t('search', 'home')}
|
|
105
|
-
type={ButtonType.solid}
|
|
106
|
-
/>
|
|
107
|
-
</RTLAwareView>
|
|
108
|
-
</RTLAwareView>
|
|
109
|
-
</Modal>
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const styles = StyleSheet.create({
|
|
114
|
-
modal: {
|
|
115
|
-
flex: 1,
|
|
116
|
-
backgroundColor: 'red',
|
|
117
|
-
alignItems: 'center',
|
|
118
|
-
justifyContent: 'center',
|
|
119
|
-
},
|
|
120
|
-
container: {
|
|
121
|
-
width: '95%',
|
|
122
|
-
// minHeight: '40%',
|
|
123
|
-
alignSelf: 'center',
|
|
124
|
-
borderRadius: CommonSizes.borderRadius.large,
|
|
125
|
-
padding: CommonSizes.spacing.large,
|
|
126
|
-
gap: CommonSizes.spacing.large,
|
|
127
|
-
marginTop: '45%',
|
|
128
|
-
},
|
|
129
|
-
});
|