@fadyshawky/react-native-magic 2.0.4 → 2.0.6

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.
Files changed (80) hide show
  1. package/package.json +1 -1
  2. package/template/App.tsx +28 -19
  3. package/template/ios/reactnativemagic/AppDelegate.mm +5 -0
  4. package/template/src/common/components/Background.tsx +6 -4
  5. package/template/src/common/components/Container.tsx +6 -9
  6. package/template/src/common/components/OTPInput.tsx +3 -2
  7. package/template/src/common/components/PrimaryButton.tsx +23 -23
  8. package/template/src/common/components/PrimaryTextInput.tsx +189 -199
  9. package/template/src/common/components/RadioIcon.tsx +4 -4
  10. package/template/src/common/components/SafeText.tsx +41 -0
  11. package/template/src/common/components/SearchBar.tsx +19 -17
  12. package/template/src/common/components/TryAgain.tsx +3 -3
  13. package/template/src/common/localization/LocalizationProvider.tsx +14 -17
  14. package/template/src/common/localization/RTLInitializer.tsx +90 -0
  15. package/template/src/common/localization/localization.ts +8 -0
  16. package/template/src/common/localization/translations/commonLocalization.ts +33 -6
  17. package/template/src/common/localization/translations/emptyLocalization.ts +6 -2
  18. package/template/src/common/localization/translations/errorsLocalization.ts +33 -13
  19. package/template/src/common/localization/translations/homeLocalization.ts +6 -2
  20. package/template/src/common/localization/translations/loginLocalization.ts +32 -9
  21. package/template/src/common/localization/translations/mainNavigationLocalization.ts +30 -0
  22. package/template/src/common/localization/translations/navigationLocalization.ts +48 -0
  23. package/template/src/common/localization/translations/onboardingLocalization.ts +40 -9
  24. package/template/src/common/localization/translations/otpLocalization.ts +28 -0
  25. package/template/src/common/localization/translations/pagesLocalization.ts +13 -1
  26. package/template/src/common/localization/translations/passwordLocalization.ts +54 -0
  27. package/template/src/common/localization/translations/profileLocalization.ts +4 -4
  28. package/template/src/common/utils/FeesCaalculation.tsx +37 -0
  29. package/template/src/common/utils/index.tsx +11 -0
  30. package/template/src/common/utils/printData.tsx +161 -0
  31. package/template/src/common/validations/errorValidations.ts +3 -2
  32. package/template/src/core/api/serverHeaders.ts +62 -1
  33. package/template/src/core/store/Categories/categoryActions.ts +33 -0
  34. package/template/src/core/store/Categories/categorySlice.ts +75 -0
  35. package/template/src/core/store/Categories/categoryState.ts +41 -0
  36. package/template/src/core/store/Providers/providersActions.ts +102 -0
  37. package/template/src/core/store/Providers/providersSlice.ts +136 -0
  38. package/template/src/core/store/Providers/providersState.ts +37 -0
  39. package/template/src/core/store/Services/servicesActions.ts +191 -0
  40. package/template/src/core/store/Services/servicesSlice.ts +205 -0
  41. package/template/src/core/store/Services/servicesState.ts +466 -0
  42. package/template/src/core/store/app/appSlice.ts +13 -5
  43. package/template/src/core/store/app/appState.ts +10 -2
  44. package/template/src/core/store/rootReducer.ts +6 -1
  45. package/template/src/core/store/store.tsx +55 -2
  46. package/template/src/core/store/user/userActions.ts +164 -26
  47. package/template/src/core/store/user/userSlice.ts +193 -21
  48. package/template/src/core/store/user/userState.ts +148 -25
  49. package/template/src/core/theme/colors.ts +12 -0
  50. package/template/src/core/theme/themes.ts +1 -1
  51. package/template/src/core/utils/stringUtils.ts +114 -0
  52. package/template/src/navigation/AuthStack.tsx +8 -0
  53. package/template/src/navigation/HeaderComponents.tsx +52 -1
  54. package/template/src/navigation/MainNavigation.tsx +3 -1
  55. package/template/src/navigation/MainStack.tsx +39 -56
  56. package/template/src/navigation/TabBar.tsx +111 -59
  57. package/template/src/navigation/types.ts +24 -0
  58. package/template/src/screens/Login/Login.tsx +83 -85
  59. package/template/src/screens/OTP/OTPScreen.tsx +169 -0
  60. package/template/src/screens/home/Components/PayByCode.tsx +129 -0
  61. package/template/src/screens/home/HomeScreen.tsx +1 -103
  62. package/template/src/screens/home/hooks/useHomeData.ts +32 -38
  63. package/template/src/screens/index.tsx +24 -0
  64. package/template/src/common/components/Stepper.tsx +0 -153
  65. package/template/src/common/components/Svg.tsx +0 -25
  66. package/template/src/common/hooks/useDebounce.ts +0 -17
  67. package/template/src/common/hooks/usePrevious.ts +0 -11
  68. package/template/src/common/urls/emailUrl.ts +0 -20
  69. package/template/src/common/urls/mapUrl.ts +0 -22
  70. package/template/src/common/utils/listHandlers.ts +0 -30
  71. package/template/src/common/utils/serializeQueryParams.ts +0 -10
  72. package/template/src/common/validations/hooks/useDatesError.ts +0 -40
  73. package/template/src/common/validations/profileValidations.ts +0 -30
  74. package/template/src/navigation/TopTabBar.tsx +0 -77
  75. package/template/src/screens/Settings/Settings.tsx +0 -5
  76. package/template/src/screens/home/components/CarouselSection.tsx +0 -79
  77. package/template/src/screens/home/components/FeaturedCarousel.tsx +0 -128
  78. package/template/src/screens/main/Main.tsx +0 -5
  79. package/template/src/screens/registration/RegistrationScreen.tsx +0 -198
  80. package/template/src/screens/resetPassword/ForgotPasswordScreen.tsx +0 -129
@@ -1,6 +1,6 @@
1
1
  export const profileLocalization = {
2
2
  en: {
3
- studentProfile: 'Student Profile',
3
+ studentProfile: 'User Profile',
4
4
  allDetails: 'All Details',
5
5
  settings: 'Settings',
6
6
  darkMode: 'Dark Mode',
@@ -11,10 +11,10 @@ export const profileLocalization = {
11
11
  logout: 'Logout',
12
12
  changeLanguage: 'Change Language',
13
13
  changeLanguageConfirmation:
14
- 'Are you sure you want to change the language? The app will restart to apply changes.',
14
+ 'Are you sure you want to change the language? The app will restart.',
15
15
  },
16
16
  ar: {
17
- studentProfile: 'الملف الشخصي للطالب',
17
+ studentProfile: 'الملف الشخصي',
18
18
  allDetails: 'جميع التفاصيل',
19
19
  settings: 'الإعدادات',
20
20
  darkMode: 'الوضع الداكن',
@@ -25,6 +25,6 @@ export const profileLocalization = {
25
25
  logout: 'تسجيل الخروج',
26
26
  changeLanguage: 'تغيير اللغة',
27
27
  changeLanguageConfirmation:
28
- 'هل أنت متأكد أنك تريد تغيير اللغة؟ سيتم إعادة تشغيل التطبيق لتطبيق التغييرات.',
28
+ 'هل تريد تغيير اللغة؟ سيتم إعادة تشغيل التطبيق.',
29
29
  },
30
30
  };
@@ -0,0 +1,37 @@
1
+ import {
2
+ Service,
3
+ TierEntity,
4
+ Percent1,
5
+ } from '../../core/store/Services/servicesState';
6
+
7
+ export function initFees(service: Service, amount: string) {
8
+ let fee = 0;
9
+ if (service?.Fees) {
10
+ for (const f of service.Fees) {
11
+ if (f.AcctType && f.AcctType !== 'SDA') continue;
12
+ fee = fee + calculateFees(Number(amount), f.Tier as TierEntity[]);
13
+ }
14
+ }
15
+ return fee;
16
+ }
17
+
18
+ export function calculateFees(amount: number, tiers: TierEntity[]) {
19
+ if (!tiers || !amount || amount < 0) return 0;
20
+
21
+ const tier = tiers.find(t => amount >= t.LowerAmt && amount <= t.UpperAmt);
22
+
23
+ if (!tier) return 0;
24
+
25
+ const fixed = tier.FixedAmt?.Amt || 0;
26
+ const percent = tier.Percent?.Value ? tier.Percent.Value / 100 : 0;
27
+ const minPercentFee = (tier.Percent as Percent1)?.MinAmt || 0;
28
+ const maxPercentFee = tier.Percent?.MaxAmt || 0;
29
+ const calculatedPercentFee = Number((percent * amount).toFixed(2));
30
+
31
+ const percentFee = Math.min(
32
+ Math.max(calculatedPercentFee, minPercentFee),
33
+ maxPercentFee,
34
+ );
35
+
36
+ return fixed + percentFee;
37
+ }
@@ -0,0 +1,11 @@
1
+ // Fee calculation utilities
2
+ export {initFees, calculateFees} from './FeesCaalculation';
3
+
4
+ // State management utility
5
+ export {newState} from './newState';
6
+
7
+ // Size calculation utility
8
+ export {createPerfectSize} from './createPerfectSize';
9
+
10
+ // Print data utility
11
+ export {makePrintData} from './printData';
@@ -0,0 +1,161 @@
1
+ import moment from 'moment';
2
+ import {Service} from '../../core/store/Services/servicesState';
3
+ import {ServiceProvider} from '../../core/store/Providers/providersState';
4
+
5
+ const localization = {
6
+ serialNumber: 'الرقم التسلسلي',
7
+ serviceName: 'اسم الخدمة',
8
+ providerName: 'اسم المقدم',
9
+ customerNumber: 'رقم العميل',
10
+ value: 'القيمة',
11
+ serviceCost: 'تكلفة الخدمة',
12
+ operationNumber: 'رقم العملية',
13
+ referenceNumber: 'الرقم المرجعي',
14
+ time: 'الوقت',
15
+ total: 'الإجمالي',
16
+ expiryDate: 'تاريخ الانتهاء',
17
+ dueDate: 'الموعد المستحق',
18
+ issueDate: 'تاريخ الإصدار',
19
+ quantity: 'الكمية',
20
+ vatValue: 'القسيمة',
21
+ };
22
+
23
+ export const makePrintData = ({
24
+ service,
25
+ BillingAcct,
26
+ provider,
27
+ billInfo,
28
+ amuont,
29
+ fees,
30
+ quantity,
31
+ vatValue,
32
+ }: {
33
+ service: Service;
34
+ BillingAcct: string;
35
+ provider: ServiceProvider;
36
+ billInfo: any;
37
+ amuont: string;
38
+ fees: number;
39
+ quantity: string;
40
+ vatValue: string;
41
+ }) => {
42
+ let newData = [];
43
+ newData.push({
44
+ value: 'logo',
45
+ type: 'image',
46
+ });
47
+
48
+ newData.push({
49
+ value: service?.Name,
50
+ type: 'header2',
51
+ });
52
+ if (billInfo?.BillLabel) {
53
+ newData.push({
54
+ value: billInfo?.BillLabel,
55
+ type: 'header2',
56
+ });
57
+ }
58
+ newData.push({
59
+ value: provider?.BillerName,
60
+ type: 'header2',
61
+ });
62
+
63
+ if (BillingAcct) {
64
+ newData.push({
65
+ value: BillingAcct,
66
+ type: 'body',
67
+ label: localization['customerNumber'],
68
+ });
69
+ }
70
+ // response?.PmtInfo?.ExtraBillingAcctKeys?.ExtraBillingAcctKey?.forEach(
71
+ // (item: any) => {
72
+ // newData.push({
73
+ // value: item.Value,
74
+ // type: 'extra_description'
75
+ // });
76
+ // }
77
+ // );
78
+
79
+ if (!!vatValue) {
80
+ newData.push({
81
+ value: `${vatValue}`,
82
+ label: localization['vatValue'],
83
+ type: 'body',
84
+ });
85
+ }
86
+ if (quantity) {
87
+ newData.push({
88
+ value: `${quantity}`,
89
+ label: localization['quantity'],
90
+ type: 'body',
91
+ });
92
+ }
93
+ newData.push({
94
+ value: `${amuont} EGP`,
95
+ label: localization['value'],
96
+ type: 'body',
97
+ });
98
+
99
+ if (fees?.toString() !== '0') {
100
+ newData.push({
101
+ value: `${fees?.toString()} EGP`,
102
+ label: localization['serviceCost'],
103
+ type: 'body',
104
+ });
105
+ }
106
+ newData.push({
107
+ value: moment().format('YYYY-MM-DD HH:mm'),
108
+ label: localization['time'],
109
+ type: 'body',
110
+ });
111
+
112
+ newData.push({
113
+ value: quantity
114
+ ? `${(Number(quantity) * (Number(amuont) + Number(fees)))?.toFixed(
115
+ 2,
116
+ )} EGP`
117
+ : `${(Number(amuont) + Number(fees))?.toString()} EGP`,
118
+ label: localization['total'],
119
+ type: 'body_title',
120
+ });
121
+
122
+ if (billInfo?.DueDt) {
123
+ newData.push({
124
+ value: billInfo?.DueDt,
125
+ type: 'body',
126
+ label: localization['dueDate'],
127
+ });
128
+ }
129
+
130
+ if (billInfo?.IssueDt) {
131
+ newData.push({
132
+ value: billInfo?.IssueDt,
133
+ type: 'body',
134
+ label: localization['issueDate'],
135
+ });
136
+ }
137
+
138
+ if (billInfo?.ExtraBillInfo) {
139
+ newData.push({
140
+ value: billInfo?.ExtraBillInfo,
141
+ type: 'description',
142
+ label: '',
143
+ });
144
+ }
145
+
146
+ if (!!service?.meta?.note) {
147
+ newData.push({
148
+ value: service?.meta?.note,
149
+ type: 'description',
150
+ });
151
+ }
152
+
153
+ if (!!service?.meta?.explain) {
154
+ newData.push({
155
+ value: service?.meta?.explain,
156
+ type: 'description',
157
+ });
158
+ }
159
+
160
+ return newData;
161
+ };
@@ -1,8 +1,9 @@
1
+ import {localization} from '../localization/localization';
1
2
  import {unwrapResult} from '@reduxjs/toolkit';
2
3
  import {Alert} from 'react-native';
4
+ import {IErrorResult, ErrorRepresentationType} from '../../../types';
3
5
  import Snackbar from 'react-native-snackbar';
4
- import {ErrorRepresentationType, IErrorResult} from '../../../types';
5
- import {localization} from '../localization/localization';
6
+ import {NewColors} from '../../core/theme/colors';
6
7
  export function handlePromiseResult(
7
8
  promiseAction: Promise<any>,
8
9
  successMessage?: string,
@@ -1,6 +1,10 @@
1
1
  import axios, {AxiosDefaults} from 'axios';
2
+ import DeviceInfo from 'react-native-device-info';
3
+ import {fetch} from 'react-native-ssl-pinning';
2
4
 
3
5
  export const defaultHeaders: HeadersInit_ = {
6
+ 'app-version': DeviceInfo.getVersion(),
7
+ 'serial-number': DeviceInfo.getSerialNumberSync(),
4
8
  Connection: 'keep-alive',
5
9
  'Content-Type': 'application/json',
6
10
  };
@@ -10,7 +14,7 @@ declare type MethodData = {
10
14
  config?: any;
11
15
  };
12
16
 
13
- const baseURL = '';
17
+ const baseURL = 'https://sofapi.neo-dg.app/api/v1/mobile/';
14
18
 
15
19
  const instance = axios.create({
16
20
  baseURL: baseURL,
@@ -19,6 +23,63 @@ const instance = axios.create({
19
23
  },
20
24
  });
21
25
 
26
+ export async function configureSecureRequest() {
27
+ // Only apply SSL pinning in production
28
+ if (baseURL.includes('neopayplus')) {
29
+ try {
30
+ instance.defaults.adapter = (config: any) => {
31
+ const url = `${config.baseURL}${config.url}`;
32
+ const fetchOptions: any = {
33
+ method: config.method?.toUpperCase() || 'GET',
34
+ timeoutInterval: 0,
35
+ headers: {
36
+ ...config.headers,
37
+ Accept: 'application/json',
38
+ 'Content-Type': 'application/json',
39
+ },
40
+ // Don't double stringify the data
41
+ body: config.data ? config.data : undefined,
42
+ sslPinning: {
43
+ certs: ['STAR.neopayplus.com'],
44
+ allowInvalidCertificates: false,
45
+ validatesDomainName: true,
46
+ },
47
+ };
48
+
49
+ if (fetchOptions.method === 'GET' || fetchOptions.method === 'HEAD') {
50
+ delete fetchOptions.body;
51
+ }
52
+
53
+ return fetch(url, fetchOptions)
54
+ .then(async response => {
55
+ const data = await response.json();
56
+ return {
57
+ data,
58
+ status: response.status,
59
+ statusText: response.statusText,
60
+ headers: response.headers,
61
+ config,
62
+ request: {},
63
+ };
64
+ })
65
+ .catch(error => {
66
+ console.error('error: ', error);
67
+ if (error === 'timeout') {
68
+ throw new Error(error);
69
+ } else if (JSON.parse(error?.bodyString)?.error) {
70
+ throw new Error(JSON.parse(error?.bodyString)?.error);
71
+ } else if (JSON.parse(error?.bodyString)?.message) {
72
+ throw new Error(JSON.parse(error?.bodyString)?.message);
73
+ }
74
+ });
75
+ };
76
+ } catch (error) {
77
+ console.info('error: ', error);
78
+ throw error;
79
+ }
80
+ }
81
+ }
82
+
22
83
  // Export HTTP methods using the configured instance
23
84
  export const post = ({url, data, config}: MethodData) =>
24
85
  instance.post(url, data, config);
@@ -0,0 +1,33 @@
1
+ import {createAsyncThunk} from '@reduxjs/toolkit';
2
+ import {handleFetchJsonResponse} from '../../api/responseHandlers';
3
+ import {post} from '../../api/serverHeaders';
4
+ import {RootState} from '../rootReducer';
5
+ import {extractServerError} from '../../api/errorHandler';
6
+
7
+ export const getCategories = createAsyncThunk(
8
+ 'categories/list',
9
+ async (
10
+ {data: {limit}}: {data: {limit?: number}},
11
+ {rejectWithValue, getState, dispatch}: any,
12
+ ) => {
13
+ try {
14
+ const token = (getState() as RootState).user.accessToken;
15
+
16
+ const response = await post({
17
+ url: 'serviceMangement/Category/get_categories',
18
+ data: {limit},
19
+ config: {
20
+ headers: {
21
+ Authorization: `${token}`,
22
+ },
23
+ },
24
+ });
25
+
26
+ return handleFetchJsonResponse(response);
27
+ } catch (e: any) {
28
+ // Extract the server error from the Axios error
29
+ const serverError = extractServerError(e);
30
+ return rejectWithValue(serverError);
31
+ }
32
+ },
33
+ );
@@ -0,0 +1,75 @@
1
+ import {createSlice} from '@reduxjs/toolkit';
2
+ import {newState} from '../../../common/utils/newState';
3
+ import {handleErrorResponse} from '../../api/responseHandlers';
4
+ import {getCategories} from './categoryActions';
5
+ import {
6
+ CategoriesInitialState,
7
+ CategoriesState,
8
+ Category,
9
+ CategoryPayload,
10
+ } from './categoryState';
11
+ import {LoadState} from '../../../../types';
12
+
13
+ function getCategoriesHandler(
14
+ state: CategoriesState,
15
+ payload: {payload: CategoryPayload},
16
+ ) {
17
+ return newState(state, {
18
+ categories: payload.payload.categories,
19
+ settings: payload.payload.settings,
20
+ loadState: LoadState.allIsLoaded,
21
+ });
22
+ }
23
+ function getCategoriesLoadingHandler(state: CategoriesState) {
24
+ return newState(state, {
25
+ loadState: LoadState.loadingMore,
26
+ });
27
+ }
28
+
29
+ function getCategoriesErrorHandler(
30
+ state: CategoriesState,
31
+ payload: {payload: {message: string}},
32
+ ) {
33
+ handleErrorResponse(payload.payload.message || 'Categories fetch failed');
34
+ return newState(state, {
35
+ loadState: LoadState.error,
36
+ });
37
+ }
38
+
39
+ function categoriesLogoutHandler(state: CategoriesState) {
40
+ return newState(state, CategoriesInitialState);
41
+ }
42
+
43
+ function selectedCategoryHandler(
44
+ state: CategoriesState,
45
+ payload: {payload: Category},
46
+ ) {
47
+ return newState(state, {
48
+ selectedCategory: payload.payload,
49
+ });
50
+ }
51
+
52
+ function clearSelectedCategoryHandler(state: CategoriesState) {
53
+ return newState(state, {
54
+ selectedCategory: CategoriesInitialState.selectedCategory,
55
+ });
56
+ }
57
+
58
+ export const {reducer: CategoriesReducer, actions} = createSlice({
59
+ name: 'categories',
60
+ initialState: CategoriesInitialState,
61
+ reducers: {
62
+ setCategoriesLogout: categoriesLogoutHandler,
63
+ setSelectedCategory: selectedCategoryHandler,
64
+ clearSelectedCategory: clearSelectedCategoryHandler,
65
+ },
66
+ extraReducers: builder => {
67
+ builder
68
+ .addCase(getCategories.fulfilled, getCategoriesHandler)
69
+ .addCase(getCategories.rejected, getCategoriesErrorHandler)
70
+ .addCase(getCategories.pending, getCategoriesLoadingHandler);
71
+ },
72
+ });
73
+
74
+ export const {setCategoriesLogout, setSelectedCategory, clearSelectedCategory} =
75
+ actions;
@@ -0,0 +1,41 @@
1
+ import {LoadState} from '../../../../types';
2
+
3
+ export type PosSettings = {
4
+ id: number;
5
+ name: string;
6
+ function_name: string;
7
+ is_active: boolean;
8
+ createdAt: string;
9
+ updatedAt: string;
10
+ };
11
+
12
+ export interface CategoriesState {
13
+ categories: Category[];
14
+ loadState: LoadState;
15
+ settings: PosSettings[];
16
+ selectedCategory: Category | null;
17
+ }
18
+
19
+ export interface Category {
20
+ createdAt?: string | null;
21
+ externalId?: null;
22
+ id: number;
23
+ img_url: string;
24
+ name: string;
25
+ name_en?: string | null;
26
+ parent_id: number;
27
+ priority: number;
28
+ updatedAt: string;
29
+ }
30
+
31
+ export interface CategoryPayload {
32
+ categories: Category[];
33
+ settings: PosSettings[];
34
+ }
35
+
36
+ export const CategoriesInitialState: CategoriesState = {
37
+ categories: [],
38
+ loadState: LoadState.idle,
39
+ settings: [],
40
+ selectedCategory: null,
41
+ };
@@ -0,0 +1,102 @@
1
+ import {createAsyncThunk} from '@reduxjs/toolkit';
2
+ import {handleFetchJsonResponse} from '../../api/responseHandlers';
3
+ import {get, post} from '../../api/serverHeaders';
4
+ import {RootState} from '../rootReducer';
5
+ import {extractServerError} from '../../api/errorHandler';
6
+ import {ensureString} from '../../utils/stringUtils';
7
+
8
+ export const getProviders = createAsyncThunk(
9
+ 'providers/getProviders',
10
+ async (
11
+ {
12
+ data: {limit, category_id},
13
+ }: {data: {limit?: number; category_id?: number}},
14
+ {rejectWithValue, getState, dispatch}: any,
15
+ ) => {
16
+ try {
17
+ const token = (getState() as RootState).user.accessToken;
18
+
19
+ const response = await post({
20
+ url: 'serviceProvider_category',
21
+ data: {limit, category_id},
22
+ config: {
23
+ headers: {
24
+ Authorization: `${token}`,
25
+ },
26
+ },
27
+ });
28
+
29
+ return handleFetchJsonResponse(response);
30
+ } catch (e: any) {
31
+ const serverError = extractServerError(e);
32
+
33
+ return rejectWithValue({
34
+ ...serverError,
35
+ message: ensureString(serverError.message),
36
+ });
37
+ }
38
+ },
39
+ );
40
+
41
+ export const getProviderById = createAsyncThunk(
42
+ 'providers/getProviderById',
43
+ async (
44
+ {data: {BillerId}}: {data: {BillerId?: number}},
45
+ {rejectWithValue, getState, dispatch}: any,
46
+ ) => {
47
+ try {
48
+ const token = (getState() as RootState).user.accessToken;
49
+
50
+ const response = await get({
51
+ url: `serviceMangement/get-single-provider/${BillerId}`,
52
+ config: {
53
+ headers: {
54
+ Authorization: `${token}`,
55
+ },
56
+ },
57
+ });
58
+
59
+ return handleFetchJsonResponse(response);
60
+ } catch (e: any) {
61
+ const serverError = extractServerError(e);
62
+
63
+ return rejectWithValue({
64
+ ...serverError,
65
+ message: ensureString(serverError.message),
66
+ });
67
+ }
68
+ },
69
+ );
70
+
71
+ export const getHomeProviders = createAsyncThunk(
72
+ 'providers/getHomeProviders',
73
+ async (
74
+ {
75
+ data: {limit, category_id},
76
+ }: {data: {limit?: number; category_id?: number}},
77
+ {rejectWithValue, getState, dispatch}: any,
78
+ ) => {
79
+ try {
80
+ const token = (getState() as RootState).user.accessToken;
81
+
82
+ const response = await post({
83
+ url: 'serviceProvider_category',
84
+ data: {limit, category_id},
85
+ config: {
86
+ headers: {
87
+ Authorization: `${token}`,
88
+ },
89
+ },
90
+ });
91
+
92
+ return handleFetchJsonResponse(response);
93
+ } catch (e: any) {
94
+ const serverError = extractServerError(e);
95
+
96
+ return rejectWithValue({
97
+ ...serverError,
98
+ message: ensureString(serverError.message),
99
+ });
100
+ }
101
+ },
102
+ );