diff --git a/android/app/build.gradle b/android/app/build.gradle index 4188f78..437c87f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -117,3 +117,5 @@ dependencies { implementation jscFlavor } } + +apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle") \ No newline at end of file diff --git a/app/api/dashboardApi.ts b/app/api/dashboardApi.ts index 6689dd0..89b9001 100644 --- a/app/api/dashboardApi.ts +++ b/app/api/dashboardApi.ts @@ -1,6 +1,7 @@ import { DeliveryPartnerLocationRequest, DeliveryPartnerLocationResponse, + EarningsSummaryResponse, ToggleStatusPayload, ToggleStatusResponse, } from '@interfaces'; @@ -25,3 +26,10 @@ export const deliveryPartnerLocation = async ( ); return response; }; + +export const dashBoardApi = async (): Promise => { + const response = await apiClient.get( + '/delivery-partners/earnings/dashboard', + ); + return response; +} \ No newline at end of file diff --git a/app/features/screens/dashboardScreen/dashboardScreen.tsx b/app/features/screens/dashboardScreen/dashboardScreen.tsx index 1563fdd..69d596d 100644 --- a/app/features/screens/dashboardScreen/dashboardScreen.tsx +++ b/app/features/screens/dashboardScreen/dashboardScreen.tsx @@ -13,13 +13,13 @@ import { PrimaryButton } from '@components'; import { BellIcon, PersonIcon, WalletIcon, ClipboardIcon } from '@icons'; import { useAppDispatch, useAppSelector } from '@store'; import { setOnlineStatus } from '@store/commonReducers/auth'; -import { useNavigation } from '@react-navigation/native'; +import { useFocusEffect, useNavigation } from '@react-navigation/native'; import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { AppStackParamList } from '@navigation/navigationTypes'; import { RouteNames, JobStatus } from '@utils/constants'; import { formatCurrency } from '@utils/formatters'; import { getStyles } from './dashboardScreen.styles'; -import { toggleStatus, updateDeliveryPartnerLocation } from './thunk'; +import { getDashBoardDetails, toggleStatus, updateDeliveryPartnerLocation } from './thunk'; import { getCurrentLocationWithAddress, showPermissionDeniedAlert, @@ -47,11 +47,13 @@ export const DashboardScreen: React.FC = () => { const { todayEarnings, completedCount, onlineMinutes, weeklyData } = useAppSelector(state => state.earnings); // const { jobStatus, activeJob } = useAppSelector(state => state.job); + const { earningsSummaryResponse } = useAppSelector(state => state.dashboard); const locationIntervalRef = useRef | null>( null, ); + const sendLocationUpdate = useCallback(async () => { try { const result = await getCurrentLocationWithAddress(); @@ -74,6 +76,9 @@ export const DashboardScreen: React.FC = () => { useEffect(() => { dispatch(getAccountInfoThunk()); }, [dispatch]); + useFocusEffect(useCallback(() => { + dispatch(getDashBoardDetails()); + }, [dispatch])); useEffect(() => { if (isOnline) { @@ -156,9 +161,8 @@ export const DashboardScreen: React.FC = () => { const formatOnlineTime = (mins: number) => { const hours = Math.floor(mins / 60); const remainingMins = mins % 60; - return `${hours}h ${ - remainingMins < 10 ? `0${remainingMins}` : remainingMins - }m`; + return `${hours}h ${remainingMins < 10 ? `0${remainingMins}` : remainingMins + }m`; }; // Helper to render chart bar heights dynamically based on amounts @@ -224,7 +228,7 @@ export const DashboardScreen: React.FC = () => { - {formatCurrency(isOnline ? todayEarnings : 0)} + {formatCurrency(Number(earningsSummaryResponse?.todayEarnings?.total))} Earnings @@ -233,7 +237,7 @@ export const DashboardScreen: React.FC = () => { - {isOnline ? completedCount : 0} + {earningsSummaryResponse?.todayEarnings?.completedCount} Completed @@ -242,7 +246,7 @@ export const DashboardScreen: React.FC = () => { - {formatOnlineTime(isOnline ? onlineMinutes : 0)} + {formatOnlineTime(Number(earningsSummaryResponse?.todayEarnings?.onlineMinutes))} Online Time @@ -277,11 +281,10 @@ export const DashboardScreen: React.FC = () => { Weekly Overview - {weeklyData.map((data, index) => { + {earningsSummaryResponse?.weeklyEarnings?.map((data, index) => { // Bar height percent - const heightPercent = `${ - (data.amount / maxWeeklyAmount) * 85 - }%`; + const heightPercent = `${(data.amount / maxWeeklyAmount) * 85 + }%`; return ( ₹{data.amount} diff --git a/app/features/screens/dashboardScreen/reducer.ts b/app/features/screens/dashboardScreen/reducer.ts index 895cc11..ffd4b39 100644 --- a/app/features/screens/dashboardScreen/reducer.ts +++ b/app/features/screens/dashboardScreen/reducer.ts @@ -1,9 +1,10 @@ import { DeliveryPartnerLocationResponse, + EarningsSummaryResponse, ToggleStatusResponse, } from '@interfaces'; import { createReducer } from '@reduxjs/toolkit'; -import { toggleStatus, updateDeliveryPartnerLocation } from './thunk'; +import { getDashBoardDetails, toggleStatus, updateDeliveryPartnerLocation } from './thunk'; export interface ToggleState { loading: boolean; @@ -11,6 +12,9 @@ export interface ToggleState { availabiltyStatus: ToggleStatusResponse | null; deliveryPartnerLocation: DeliveryPartnerLocationResponse | null; deliveryLocError: string | null; + earningsSummaryResponse: EarningsSummaryResponse | null; + earningsSummaryLoading: boolean; + earningsSummaryError: string | null; } export const initialState: ToggleState = { @@ -19,6 +23,9 @@ export const initialState: ToggleState = { availabiltyStatus: null, deliveryPartnerLocation: null, deliveryLocError: null, + earningsSummaryResponse: null, + earningsSummaryLoading: false, + earningsSummaryError: null, }; export const dashBoardReducer = createReducer(initialState, builder => { @@ -40,5 +47,17 @@ export const dashBoardReducer = createReducer(initialState, builder => { }) .addCase(updateDeliveryPartnerLocation.rejected, (state, action) => { state.deliveryLocError = action.payload as string; + }) + .addCase(getDashBoardDetails.pending, state => { + state.earningsSummaryLoading = true; + state.earningsSummaryError = null; + }) + .addCase(getDashBoardDetails.fulfilled, (state, action) => { + state.earningsSummaryLoading = false; + state.earningsSummaryResponse = action.payload; + }) + .addCase(getDashBoardDetails.rejected, (state, action) => { + state.earningsSummaryLoading = false; + state.earningsSummaryError = action.payload as string; }); }); diff --git a/app/features/screens/dashboardScreen/thunk.ts b/app/features/screens/dashboardScreen/thunk.ts index 85693e0..b63c86a 100644 --- a/app/features/screens/dashboardScreen/thunk.ts +++ b/app/features/screens/dashboardScreen/thunk.ts @@ -1,7 +1,8 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import { deliveryPartnerLocation, toggleStatus as toggleStatusApi } from '@api'; +import { dashBoardApi, deliveryPartnerLocation, toggleStatus as toggleStatusApi } from '@api'; import { DeliveryPartnerLocationRequest, + EarningsSummaryResponse, ToggleStatusPayload, } from '@interfaces'; @@ -29,3 +30,16 @@ export const updateDeliveryPartnerLocation = createAsyncThunk( } }, ); + +export const getDashBoardDetails = createAsyncThunk( + 'dashboard/getDashBoardDetails', + async (_, { rejectWithValue }) => { + try { + const response = await dashBoardApi(); + return response; + } catch (error: unknown) { + console.log(error); + return rejectWithValue(error); + } + } +) diff --git a/app/interfaces/dashboard.ts b/app/interfaces/dashboard.ts index 0de3bc3..a2f7584 100644 --- a/app/interfaces/dashboard.ts +++ b/app/interfaces/dashboard.ts @@ -21,3 +21,19 @@ export interface DeliveryPartnerLocationResponse { latitude: number; longitude: number; } + +export interface EarningsSummaryResponse { + todayEarnings: TodayEarnings; + weeklyEarnings: WeeklyEarning[]; +} + +export interface TodayEarnings { + total: number; + completedCount: number; + onlineMinutes: number; +} + +export interface WeeklyEarning { + day: string; + amount: number; +} \ No newline at end of file diff --git a/app/navigation/bottomTabNavigator.tsx b/app/navigation/bottomTabNavigator.tsx index b71814e..cb02634 100644 --- a/app/navigation/bottomTabNavigator.tsx +++ b/app/navigation/bottomTabNavigator.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import { BottomTabParamList } from '@navigation/navigationTypes'; import { EarningsScreen, @@ -18,33 +19,75 @@ const BottomTabNavigator: React.FC = () => { return ( ({ headerShown: false, tabBarActiveTintColor: colors.primary, tabBarInactiveTintColor: colors.textSecondary, - tabBarStyle: { backgroundColor: colors.background }, - }} + tabBarStyle: { + backgroundColor: colors.background, + }, + tabBarIcon: ({ color, size, focused }) => { + let iconName: string; + + switch (route.name) { + case RouteNames.Dashboard: + iconName = focused ? 'home' : 'home-outline'; + break; + + case RouteNames.Earnings: + iconName = focused ? 'cash' : 'cash-multiple'; + break; + + case RouteNames.Jobs: + iconName = focused ? 'briefcase' : 'briefcase-outline'; + break; + + case RouteNames.Inbox: + iconName = focused ? 'message' : 'message-outline'; + break; + + case RouteNames.Profile: + iconName = focused ? 'account' : 'account-outline'; + break; + + default: + iconName = 'circle'; + } + + return ( + + ); + }, + })} > + + + + { ); }; -export default BottomTabNavigator; +export default BottomTabNavigator; \ No newline at end of file diff --git a/package.json b/package.json index e68fde1..5255675 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "react-native-screens": "^4.25.2", "react-native-svg": "^15.15.5", "react-native-uuid": "^2.0.4", + "react-native-vector-icons": "^10.3.0", "react-native-worklets": "^0.10.0", "react-redux": "^9.3.0", "reactotron-react-native": "^5.2.0", diff --git a/yarn.lock b/yarn.lock index 76b692c..5227062 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2706,6 +2706,15 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + cliui@^8.0.1: version "8.0.1" resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" @@ -5787,7 +5796,7 @@ prompts@^2.0.1, prompts@^2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@*, prop-types@^15.8.1: +prop-types@*, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -5961,6 +5970,14 @@ react-native-uuid@^2.0.4: resolved "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.4.tgz" integrity sha512-LSJNeh559qC17fgVPBsWuTSW/OygFp2dwTcf94IQBLYft5FzIQS9pCsuT36OPvyvDOMb6yiGr6TafaJDnz9PPQ== +react-native-vector-icons@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-10.3.0.tgz#de440f2627a2ed1079ce3b99d5b9d4f86894df28" + integrity sha512-IFQ0RE57819hOUdFvgK4FowM5aMXg7C7XKsuGLevqXkkIJatc3QopN0wYrb2IrzUgmdpfP+QVIbI3S6h7M0btw== + dependencies: + prop-types "^15.7.2" + yargs "^16.1.1" + react-native-worklets@^0.10.0: version "0.10.2" resolved "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.10.2.tgz" @@ -7131,6 +7148,11 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" @@ -7153,6 +7175,19 @@ yargs@^15.1.0: y18n "^4.0.0" yargs-parser "^18.1.2" +yargs@^16.1.1: + version "16.2.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.2.tgz#c56731dca0d2788ae0866dd3c83907d6bab85f7d" + integrity sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@^17.3.1, yargs@^17.6.2: version "17.7.3" resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz"