Added Commitment Tracker (#652)
This commit is contained in:
@@ -672,6 +672,17 @@ export const CLICKSTREAM_EVENT_NAMES = {
|
||||
description: 'FA_NEARBY_CASE_CLICKED',
|
||||
},
|
||||
|
||||
FA_DAILY_COMMITMENT_CLICKED: {
|
||||
name: 'FA_DAILY_COMMITMENT_CLICKED',
|
||||
description: 'FA_DAILY_COMMITMENT_CLICKED',
|
||||
},
|
||||
FA_DAILY_COMMITMENT_SUBMITTED: {
|
||||
name: 'FA_DAILY_COMMITMENT_SUBMITTED',
|
||||
description: 'FA_DAILY_COMMITMENT_SUBMITTED',
|
||||
},
|
||||
|
||||
|
||||
|
||||
FA_SNAPSHOT_LISTENER: {
|
||||
name: 'FA_SNAPSHOT_LISTENER',
|
||||
description: 'FA_SNAPSHOT_LISTENER',
|
||||
|
||||
@@ -64,6 +64,9 @@ export enum ApiKeys {
|
||||
GET_TELEPHONE_NUMBERS = 'GET_TELEPHONE_NUMBERS',
|
||||
FIRESTORE_INCONSISTENCY_INFO = 'FIRESTORE_INCONSISTENCY_INFO',
|
||||
GET_CASE_DETAILS_FROM_API = 'GET_CASE_DETAILS_FROM_API',
|
||||
DAILY_COMMITMENT = 'DAILY_COMMITMENT',
|
||||
GET_PTP_AMOUNT = 'GET_PTP_AMOUNT',
|
||||
GET_VISIBILITY_STATUS = 'GET_VISIBILITY_STATUS',
|
||||
}
|
||||
|
||||
export const API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
|
||||
@@ -112,8 +115,9 @@ API_URLS[ApiKeys.GET_CASH_COLLECTED] = '/allocation-cycle/cash-collected-split';
|
||||
API_URLS[ApiKeys.GET_TELEPHONE_NUMBERS] = '/v2/collection-cases/telephones-view/{loanAccountNumber}';
|
||||
API_URLS[ApiKeys.FIRESTORE_INCONSISTENCY_INFO] = '/cases/sync-status';
|
||||
API_URLS[ApiKeys.GET_CASE_DETAILS_FROM_API] = '/collection-cases/minimal-collection-case-view/{caseId}';
|
||||
|
||||
|
||||
API_URLS[ApiKeys.DAILY_COMMITMENT] = '/daily-commitment';
|
||||
API_URLS[ApiKeys.GET_PTP_AMOUNT] = '/ptps-due-view/agent-detail';
|
||||
API_URLS[ApiKeys.GET_VISIBILITY_STATUS] = '/daily-commitment/visibility';
|
||||
|
||||
export const API_STATUS_CODE = {
|
||||
OK: 200,
|
||||
|
||||
@@ -68,7 +68,7 @@ export interface IUserSlice extends IUser {
|
||||
agentAttendance: {
|
||||
showAttendanceBanner: boolean;
|
||||
attendanceDate: string;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const initialState: IUserSlice = {
|
||||
|
||||
@@ -87,6 +87,7 @@ export const ToastMessages = {
|
||||
WHATSAPP_NOT_INSTALLED: 'WhatsApp is not installed on your device',
|
||||
FILE_DOWNLOAD_SUCCESS: 'File downloaded successfully',
|
||||
FILE_DOWNLOAD_FAILURE: 'File download failed',
|
||||
COMMITMENT_SUBMITTED_SUCCESSFULLY: 'Commitment submitted successfully',
|
||||
};
|
||||
|
||||
export enum BOTTOM_TAB_ROUTES {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useAppDispatch, useAppSelector } from '@hooks';
|
||||
import CasesList from './CasesList';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import { RootState } from '@store';
|
||||
import { initCrashlytics } from '@utils/firebaseUtils';
|
||||
import Layout from '../layout/Layout';
|
||||
@@ -10,7 +11,6 @@ import Profile from '../Profile';
|
||||
import ProfileIcon from '@rn-ui-lib/icons/ProfileIcon';
|
||||
import VisitPlanIcon from '@rn-ui-lib/icons/VisitPlanIcon';
|
||||
import CasesActionButtons from './CasesActionButtons';
|
||||
import FullScreenLoader from '@rn-ui-lib/components/FullScreenLoader';
|
||||
import { getCurrentScreen } from '@utils/navigationUtlis';
|
||||
import {
|
||||
resetSelectedTodoList,
|
||||
@@ -21,11 +21,17 @@ import {
|
||||
import { addClickstreamEvent } from '@services/clickstreamEventService';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
|
||||
import { BOTTOM_TAB_ROUTES } from './constants';
|
||||
import { getSelfieDocument } from '@actions/profileActions';
|
||||
import FullScreenLoaderWrapper from '@common/FullScreenLoaderWrapper';
|
||||
import DashboardIcon from '../../assets/icons/DashboardIcon';
|
||||
import DashBoardScreens from '../Dashboard/DashBoardScreens';
|
||||
import { isAgentDashboardVisible } from '@screens/Dashboard/utils';
|
||||
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
||||
import { COLORS } from '@rn-ui-lib/colors';
|
||||
import { GenericStyles } from '@rn-ui-lib/styles';
|
||||
import DailyCommitmentIcon from '@rn-ui-lib/icons/DailyCommitmentIcon';
|
||||
import AddCommitment from '../dailyCommitment/DailyCommitmentBottomSheet';
|
||||
import { getVisibilityStatus } from '@screens/dailyCommitment/actions';
|
||||
import { logError } from '@components/utlis/errorUtils';
|
||||
|
||||
const AllCasesMain = () => {
|
||||
const { pendingList, pinnedList, completedList, loading } = useAppSelector(
|
||||
@@ -35,15 +41,57 @@ const AllCasesMain = () => {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const isTeamLead = useAppSelector((state) => state.user.isTeamLead);
|
||||
|
||||
const showAgentDashboard = isAgentDashboardVisible();
|
||||
const [openBottomSheet, setOpenBottomSheet] = useState(false);
|
||||
|
||||
const [isCommitmentFormVisible, setIsCommitmentFormVisible] = useState(false);
|
||||
const [isCommitmentSubmitted, setIsCommitmentSubmitted] = useState(true);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getVisibilityStatus()
|
||||
.then((response) => {
|
||||
setIsCommitmentSubmitted(response?.isCommitmentFilled);
|
||||
setIsCommitmentFormVisible(response?.isCommitmentBannerVisible);
|
||||
})
|
||||
.catch((err) => {
|
||||
logError(err);
|
||||
});
|
||||
}, [isCommitmentSubmitted,isCommitmentFormVisible]);
|
||||
|
||||
const shouldShowBanner = useMemo(() => {
|
||||
return !isTeamLead && !isCommitmentSubmitted && isCommitmentFormVisible;
|
||||
}, [isCommitmentSubmitted, isCommitmentFormVisible, isTeamLead]);
|
||||
|
||||
|
||||
const openCommitmentScreen = () => {
|
||||
setOpenBottomSheet(true);
|
||||
};
|
||||
const CommitmentComponent = () => {
|
||||
return (
|
||||
<>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
style={[GenericStyles.centerAlignedRow, styles.container]}
|
||||
onPress={openCommitmentScreen}
|
||||
>
|
||||
<DailyCommitmentIcon />
|
||||
<Text bold dark style={[GenericStyles.ml8, GenericStyles.mr8, styles.updateText]}>
|
||||
Update your daily commitment
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
);
|
||||
};
|
||||
const HOME_SCREENS: ITabScreen[] = useMemo(() => {
|
||||
const bottomSheetScreens = [
|
||||
{
|
||||
name: BOTTOM_TAB_ROUTES.Cases,
|
||||
component: () => (
|
||||
<CasesList casesList={[...pendingList, ...pinnedList, ...completedList]} allCasesView />
|
||||
<>
|
||||
<CasesList casesList={[...pendingList, ...pinnedList, ...completedList]} allCasesView />
|
||||
{shouldShowBanner ? <CommitmentComponent /> : null}
|
||||
</>
|
||||
),
|
||||
icon: CasesIcon,
|
||||
},
|
||||
@@ -51,7 +99,12 @@ const AllCasesMain = () => {
|
||||
if (!isTeamLead) {
|
||||
bottomSheetScreens.push({
|
||||
name: BOTTOM_TAB_ROUTES.VisitPlan,
|
||||
component: () => <CasesList casesList={pinnedList} isVisitPlan />,
|
||||
component: () => (
|
||||
<>
|
||||
<CasesList casesList={pinnedList} isVisitPlan />
|
||||
{shouldShowBanner ? <CommitmentComponent /> : null}
|
||||
</>
|
||||
),
|
||||
icon: VisitPlanIcon,
|
||||
});
|
||||
}
|
||||
@@ -59,18 +112,34 @@ const AllCasesMain = () => {
|
||||
if (showAgentDashboard) {
|
||||
bottomSheetScreens.push({
|
||||
name: BOTTOM_TAB_ROUTES.Dashboard,
|
||||
component: () => <DashBoardScreens />,
|
||||
component: () => (
|
||||
<>
|
||||
<DashBoardScreens />
|
||||
{shouldShowBanner ? <CommitmentComponent /> : null}
|
||||
</>
|
||||
),
|
||||
icon: DashboardIcon,
|
||||
});
|
||||
}
|
||||
|
||||
bottomSheetScreens.push({
|
||||
name: BOTTOM_TAB_ROUTES.Profile,
|
||||
component: () => <Profile />,
|
||||
component: () => (
|
||||
<>
|
||||
<Profile />
|
||||
{shouldShowBanner ? <CommitmentComponent /> : null}
|
||||
</>
|
||||
),
|
||||
icon: ProfileIcon,
|
||||
});
|
||||
return bottomSheetScreens;
|
||||
}, [pendingList, pinnedList, isTeamLead, showAgentDashboard]);
|
||||
}, [
|
||||
pendingList,
|
||||
pinnedList,
|
||||
isTeamLead,
|
||||
showAgentDashboard,
|
||||
shouldShowBanner,
|
||||
]);
|
||||
|
||||
const onTabPressHandler = (e: any) => {
|
||||
const nextTab = e?.data?.routeName;
|
||||
@@ -99,8 +168,18 @@ const AllCasesMain = () => {
|
||||
onTabPress={(e) => onTabPressHandler(e)}
|
||||
/>
|
||||
<CasesActionButtons />
|
||||
<AddCommitment openBottomSheet={openBottomSheet} setOpenBottomSheet={setOpenBottomSheet} />
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: COLORS.BACKGROUND.TEAL,
|
||||
height: 40,
|
||||
},
|
||||
updateText: {
|
||||
color: COLORS.TEXT.TEAL,
|
||||
},
|
||||
});
|
||||
|
||||
export default AllCasesMain;
|
||||
export default AllCasesMain;
|
||||
@@ -67,6 +67,7 @@ function AuthRouter() {
|
||||
};
|
||||
const CHECK_ATTENDANCE_TIME = 10000;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const appStateChange = AppState.addEventListener('change', async (change) => {
|
||||
if (change !== 'active') return;
|
||||
|
||||
221
src/screens/dailyCommitment/DailyCommitmentBottomSheet.tsx
Normal file
221
src/screens/dailyCommitment/DailyCommitmentBottomSheet.tsx
Normal file
@@ -0,0 +1,221 @@
|
||||
import { Keyboard, SafeAreaView, View, StyleSheet, TouchableOpacity } from 'react-native';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import TextInput, { TextInputMaskType } from '../../../RN-UI-LIB/src/components/TextInput';
|
||||
import Button from '../../../RN-UI-LIB/src/components/Button';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import { Controller, FieldErrors, useForm } from 'react-hook-form';
|
||||
import { isValidAmountEntered } from '../../components/utlis/commonFunctions';
|
||||
import { addCommitmentApi, getTodaysPtpAmount} from './actions';
|
||||
import Heading from '@rn-ui-lib/components/Heading';
|
||||
import DailyCommitmentIcon from '@rn-ui-lib/icons/DailyCommitmentIcon';
|
||||
import BottomSheetWrapper from '@common/BottomSheetWrapper';
|
||||
import CloseIcon from '@rn-ui-lib/icons/CloseIcon';
|
||||
import { COLORS } from '@rn-ui-lib/colors';
|
||||
import { EXAMPLE_VALUES } from './constants';
|
||||
import { useAppDispatch} from '@hooks';
|
||||
import { formatAmount } from '@rn-ui-lib/utils/amount';
|
||||
import { getErrorCashMessage, getErrorVisitMessage } from './ErrorMessages';
|
||||
import { IAddCommitment, IAddCommitmentProps } from '@interfaces/commitmentTracker.types';
|
||||
import HeaderComponent from './headerComponent';
|
||||
import { logError } from '@components/utlis/errorUtils';
|
||||
|
||||
const AddCommitment: React.FC<IAddCommitmentProps> = ({ openBottomSheet, setOpenBottomSheet }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const {
|
||||
control,
|
||||
formState: { errors, dirtyFields },
|
||||
trigger,
|
||||
reset,
|
||||
handleSubmit,
|
||||
} = useForm<IAddCommitment>({
|
||||
mode: 'onChange',
|
||||
});
|
||||
const [submitErrors, setSubmitErrors] = useState<FieldErrors<IAddCommitment>>({});
|
||||
const [todaysPtpAmount, setTodaysPtpAmount] = useState(1000);
|
||||
useEffect(() => {
|
||||
getTodaysPtpAmount()
|
||||
.then((response) => {
|
||||
setTodaysPtpAmount(response?.todaysPtpAmount);
|
||||
})
|
||||
.catch((err) => {logError(err);});
|
||||
}, []);
|
||||
|
||||
const onBack = () => {
|
||||
setOpenBottomSheet((prev) => !prev);
|
||||
setSubmitErrors({});
|
||||
reset();
|
||||
};
|
||||
|
||||
const visitError = Boolean(
|
||||
dirtyFields?.visitsCommitted &&
|
||||
(errors?.visitsCommitted || submitErrors?.visitsCommitted)
|
||||
);
|
||||
const cashError = Boolean(
|
||||
dirtyFields?.cashCommitted &&
|
||||
(errors?.cashCommitted || submitErrors?.cashCommitted)
|
||||
);
|
||||
|
||||
const errorCashMessage = getErrorCashMessage(errors);
|
||||
const errorVisitMessage = getErrorVisitMessage(errors);
|
||||
|
||||
const [isKeyboardVisible, setKeyboardVisible] = useState(false);
|
||||
useEffect(() => {
|
||||
const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
|
||||
setKeyboardVisible(true);
|
||||
});
|
||||
const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
|
||||
setKeyboardVisible(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
keyboardDidShowListener.remove();
|
||||
keyboardDidHideListener.remove();
|
||||
};
|
||||
}, []);
|
||||
const dispatch = useAppDispatch();
|
||||
const addCtaHandler = (data: IAddCommitment) => {
|
||||
setLoading(true);
|
||||
dispatch(
|
||||
addCommitmentApi(data, () => {
|
||||
setLoading(false);
|
||||
})
|
||||
);
|
||||
onBack();
|
||||
};
|
||||
const handleError = (data: FieldErrors<IAddCommitment>) => {
|
||||
setSubmitErrors(data);
|
||||
};
|
||||
|
||||
return (
|
||||
<BottomSheetWrapper
|
||||
heightPercentage={60}
|
||||
visible={openBottomSheet}
|
||||
setVisible={() => setOpenBottomSheet((prev) => !prev)}
|
||||
moveForKeyboard={0.2}
|
||||
HeaderNode={() => <HeaderComponent onBack={onBack} />}
|
||||
>
|
||||
<SafeAreaView style={[GenericStyles.whiteBackground, { height: '100%' }]}>
|
||||
<View style={[GenericStyles.ph16, GenericStyles.pv24]}>
|
||||
<View>
|
||||
<Text style={[GenericStyles.mb8]}>
|
||||
Cash collection commitment
|
||||
<Text style={styles.mandatoryStar}> *</Text>
|
||||
</Text>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
render={({ field: { onChange, onBlur, value } }) => (
|
||||
<TextInput
|
||||
value={value}
|
||||
onChangeText={(number) => {
|
||||
onChange(number);
|
||||
trigger();
|
||||
}}
|
||||
keyboardType="numeric"
|
||||
placeholder={EXAMPLE_VALUES.DUMMY_PTP_AMOUNT}
|
||||
placeholderTextColor='COLORS.TEXT.LIGHT'
|
||||
required={true}
|
||||
maskType={TextInputMaskType.CURRENCY}
|
||||
error={cashError}
|
||||
errorMessage={errorCashMessage}
|
||||
/>
|
||||
)}
|
||||
name="cashCommitted"
|
||||
rules={{
|
||||
required: true,
|
||||
validate: (value) => isValidAmountEntered(Number(value)),
|
||||
min: 0,
|
||||
max: 1e6,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={GenericStyles.mt4}>
|
||||
<Text light>PTP amount for today: {formatAmount(todaysPtpAmount)}</Text>
|
||||
</View>
|
||||
|
||||
<View style={[GenericStyles.mt12]}>
|
||||
<Text style={[GenericStyles.mb8]}>
|
||||
Number of visits<Text style={styles.mandatoryStar}> *</Text>
|
||||
</Text>
|
||||
<Controller
|
||||
control={control}
|
||||
render={({ field: { onChange, onBlur, value } }) => (
|
||||
<TextInput
|
||||
value={value}
|
||||
onChangeText={(number) => {
|
||||
onChange(number);
|
||||
trigger();
|
||||
}}
|
||||
keyboardType="numeric"
|
||||
placeholder={EXAMPLE_VALUES.DUMMY_VISIT_COUNT}
|
||||
placeholderTextColor='COLORS.TEXT.LIGHT'
|
||||
maskType={TextInputMaskType.NUMBER}
|
||||
error={visitError}
|
||||
errorMessage={errorVisitMessage}
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
name="visitsCommitted"
|
||||
rules={{
|
||||
required: true,
|
||||
validate: (value) => isValidAmountEntered(Number(value)),
|
||||
pattern: /^[0-9]*$/,
|
||||
min: 0,
|
||||
max: 99,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={[styles.buttonContainer, isKeyboardVisible && { display: 'none' }]}>
|
||||
<Button
|
||||
variant="primary"
|
||||
title="Commit"
|
||||
style={[GenericStyles.w100]}
|
||||
onPress={handleSubmit(
|
||||
(data) => addCtaHandler(data),
|
||||
(data) => handleError(data)
|
||||
)}
|
||||
showLoader={loading}
|
||||
/>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</BottomSheetWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
heading: {
|
||||
...GenericStyles.relative,
|
||||
},
|
||||
bottomSheet: {
|
||||
marginTop: 10,
|
||||
},
|
||||
headingCrossIcon: {
|
||||
...GenericStyles.absolute,
|
||||
right: 10,
|
||||
},
|
||||
mandatoryStar: {
|
||||
color: COLORS.TEXT.RED,
|
||||
},
|
||||
shadowContainer: {
|
||||
shadowColor: COLORS.BACKGROUND.BLACK,
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 4,
|
||||
},
|
||||
shadowOpacity: 0.08,
|
||||
shadowRadius: 20,
|
||||
borderRadius: 8,
|
||||
},
|
||||
buttonContainer: {
|
||||
bottom: 60,
|
||||
position: 'absolute',
|
||||
marginTop: 24,
|
||||
width: '100%',
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
});
|
||||
|
||||
export default AddCommitment;
|
||||
33
src/screens/dailyCommitment/ErrorMessages.tsx
Normal file
33
src/screens/dailyCommitment/ErrorMessages.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { FieldErrorsImpl } from "react-hook-form";
|
||||
import { ERROR_MESSAGES } from "./constants";
|
||||
|
||||
export const getErrorCashMessage = (errors: Partial<FieldErrorsImpl<{ cashCommitted: string; visitsCommitted: string; }>>) => {
|
||||
let errorCashMessage = '';
|
||||
switch (errors?.cashCommitted?.type) {
|
||||
case 'required':
|
||||
errorCashMessage = ERROR_MESSAGES.PTP_REQUIRED_ERROR;
|
||||
break;
|
||||
case 'min':
|
||||
case 'max':
|
||||
errorCashMessage = ERROR_MESSAGES.PTP_AMOUNT_ERROR;
|
||||
break;
|
||||
}
|
||||
return errorCashMessage;
|
||||
};
|
||||
|
||||
export const getErrorVisitMessage = (errors: Partial<FieldErrorsImpl<{ cashCommitted: string; visitsCommitted: string; }>>) => {
|
||||
let errorVisitMessage = '';
|
||||
switch (errors?.visitsCommitted?.type) {
|
||||
case 'required':
|
||||
errorVisitMessage = ERROR_MESSAGES.VISIT_REQUIRED_ERROR;
|
||||
break;
|
||||
case 'min':
|
||||
case 'max':
|
||||
errorVisitMessage = ERROR_MESSAGES.VISIT_COUNT_ERROR;
|
||||
break;
|
||||
case 'pattern':
|
||||
errorVisitMessage = ERROR_MESSAGES.VISIT_COUNT_ERROR_2;
|
||||
break;
|
||||
}
|
||||
return errorVisitMessage;
|
||||
};
|
||||
67
src/screens/dailyCommitment/actions.ts
Normal file
67
src/screens/dailyCommitment/actions.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { toast } from '../../../RN-UI-LIB/src/components/toast';
|
||||
import { GenericFunctionArgs } from '../../common/GenericTypes';
|
||||
import axiosInstance, {
|
||||
API_STATUS_CODE,
|
||||
ApiKeys,
|
||||
getApiUrl,
|
||||
} from '../../components/utlis/apiHelper';
|
||||
import { COMMITMENT_TYPE } from './constants';
|
||||
import { addClickstreamEvent } from '@services/clickstreamEventService';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
|
||||
import { AppDispatch } from '@store';
|
||||
import { IAddCommitment } from '@interfaces/commitmentTracker.types';
|
||||
import { getSyncTime } from '@hooks/capturingApi';
|
||||
import { logError } from '@components/utlis/errorUtils';
|
||||
|
||||
export const getTodaysPtpAmount = async () => {
|
||||
try {
|
||||
const url = getApiUrl(ApiKeys.GET_PTP_AMOUNT);
|
||||
const response = await axiosInstance.get(url);
|
||||
return response?.data;
|
||||
} catch (err) {
|
||||
logError(err as Error, 'Error fetching today\'s PTP amount:');
|
||||
return COMMITMENT_TYPE.EMPTY_PTP_AMOUNT;
|
||||
}
|
||||
};
|
||||
|
||||
export const getVisibilityStatus = async () => {
|
||||
try {
|
||||
const url = getApiUrl(ApiKeys.GET_VISIBILITY_STATUS);
|
||||
const response = await axiosInstance.get(url);
|
||||
return response?.data;
|
||||
} catch (err) {
|
||||
logError(err as Error, 'Error fetching visibility status:');
|
||||
}
|
||||
};
|
||||
|
||||
export const addCommitmentApi =
|
||||
(data: IAddCommitment, afterApiCallback?: GenericFunctionArgs) => async (dispatch: AppDispatch) => {
|
||||
const { cashCommitted, visitsCommitted } = data;
|
||||
const url = getApiUrl(ApiKeys.DAILY_COMMITMENT);
|
||||
const timestamp = await getSyncTime();
|
||||
const payload = data;
|
||||
axiosInstance
|
||||
.post(url, payload)
|
||||
.then((response: AxiosResponse) => {
|
||||
if (response.status === API_STATUS_CODE.OK) {
|
||||
toast({
|
||||
type: 'info',
|
||||
text1: COMMITMENT_TYPE.COMMITMENT_SUBMITTED_SUCCESSFULLY,
|
||||
});
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_DAILY_COMMITMENT_SUBMITTED);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
toast({
|
||||
type: 'error',
|
||||
text1: COMMITMENT_TYPE.COMMITMENT_SUBMIT_ERROR,
|
||||
});
|
||||
return error?.response?.data || error?.message || error;
|
||||
})
|
||||
.finally(() => {
|
||||
if (typeof afterApiCallback === 'function') {
|
||||
afterApiCallback();
|
||||
}
|
||||
});
|
||||
};
|
||||
16
src/screens/dailyCommitment/constants.ts
Normal file
16
src/screens/dailyCommitment/constants.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export enum EXAMPLE_VALUES {
|
||||
DUMMY_PTP_AMOUNT = 'Eg: ₹10,000',
|
||||
DUMMY_VISIT_COUNT = 'Eg: 12',
|
||||
}
|
||||
export enum ERROR_MESSAGES {
|
||||
VISIT_REQUIRED_ERROR = 'Please enter a value to commit',
|
||||
PTP_REQUIRED_ERROR = 'Please enter an amount to commit',
|
||||
VISIT_COUNT_ERROR = 'Enter a value within 0-99',
|
||||
PTP_AMOUNT_ERROR = 'Enter an amount within ₹10,00,000',
|
||||
VISIT_COUNT_ERROR_2 = 'Please enter a valid number',
|
||||
}
|
||||
export enum COMMITMENT_TYPE {
|
||||
COMMITMENT_SUBMITTED_SUCCESSFULLY = 'Commitment submitted successfully',
|
||||
COMMITMENT_SUBMIT_ERROR = 'Error submitting commitment',
|
||||
EMPTY_PTP_AMOUNT = '---',
|
||||
}
|
||||
42
src/screens/dailyCommitment/headerComponent.tsx
Normal file
42
src/screens/dailyCommitment/headerComponent.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { COLORS } from '@rn-ui-lib/colors';
|
||||
import Heading from '@rn-ui-lib/components/Heading';
|
||||
import CloseIcon from '@rn-ui-lib/icons/CloseIcon';
|
||||
import DailyCommitmentIcon from '@rn-ui-lib/icons/DailyCommitmentIcon';
|
||||
import { GenericStyles } from '@rn-ui-lib/styles';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import React from 'react';
|
||||
import { View, TouchableOpacity } from 'react-native';
|
||||
|
||||
const HeaderComponent = ({ onBack }) => {
|
||||
return (
|
||||
<View style={[GenericStyles.row, GenericStyles.alignCenter, styles.heading]}>
|
||||
<View style={[GenericStyles.mh12]}>
|
||||
<DailyCommitmentIcon />
|
||||
</View>
|
||||
|
||||
<View style={[GenericStyles.mr20]}>
|
||||
<Heading dark type="h3">
|
||||
Update your daily commitment
|
||||
</Heading>
|
||||
</View>
|
||||
|
||||
<View style={styles.headingCrossIcon}>
|
||||
<TouchableOpacity activeOpacity={0.7} onPress={onBack}>
|
||||
<CloseIcon size={20} color={COLORS.TEXT.LIGHT} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
heading: {
|
||||
...GenericStyles.relative,
|
||||
},
|
||||
headingCrossIcon: {
|
||||
...GenericStyles.absolute,
|
||||
right: 10,
|
||||
},
|
||||
});
|
||||
|
||||
export default HeaderComponent;
|
||||
@@ -38,6 +38,8 @@ export interface INotification {
|
||||
date: string;
|
||||
time: string;
|
||||
caseCount: number;
|
||||
cashCommitted: number;
|
||||
visitsCommitted: number;
|
||||
};
|
||||
template: {
|
||||
id: number;
|
||||
|
||||
@@ -27,6 +27,8 @@ const NotificationTemplate: React.FC<INotificationTemplateProps> = ({ data }) =>
|
||||
paymentTimestamp,
|
||||
date,
|
||||
caseCount,
|
||||
cashCommitted,
|
||||
visitsCommitted,
|
||||
} = params || {};
|
||||
|
||||
switch (templateName) {
|
||||
@@ -199,8 +201,23 @@ const NotificationTemplate: React.FC<INotificationTemplateProps> = ({ data }) =>
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
case NotificationTypes.AGENT_COMMITMENTS_VISIT_CASH:
|
||||
return (
|
||||
<Text>
|
||||
<Text light>Your commitment for today has been updated. Cash commitment - </Text>
|
||||
{formatAmount(cashCommitted)}. <Text light> Visit Commitment - </Text> {visitsCommitted}{' '}
|
||||
</Text>
|
||||
);
|
||||
case NotificationTypes.AGENT_DAILY_COMMITMENT:
|
||||
return (
|
||||
<Text>
|
||||
<Text light>Your commitment for today has been submitted. Cash commitment - </Text>
|
||||
{formatAmount(cashCommitted)}. <Text light>Visit Commitment - </Text> {visitsCommitted}{' '}
|
||||
</Text>
|
||||
);
|
||||
|
||||
default:
|
||||
return <Text>New notification</Text>;
|
||||
return <Text>New notification </Text>;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ export enum NotificationTypes {
|
||||
VISIT_PLAN_UPDATE_NOTIFICATION_TEMPLATE = 'VISIT_PLAN_UPDATE_NOTIFICATION_TEMPLATE',
|
||||
AGENT_ID_APPROVED_TEMPLATE = 'AGENT_ID_APPROVED_TEMPLATE',
|
||||
AGENT_ID_REJECTED_TEMPLATE = 'AGENT_ID_REJECTED_TEMPLATE',
|
||||
AGENT_COMMITMENTS_VISIT_CASH = 'AGENT_COMMITMENTS_VISIT_CASH',
|
||||
AGENT_DAILY_COMMITMENT = 'AGENT_DAILY_COMMITMENT',
|
||||
}
|
||||
|
||||
export const NotificationIconsMap = {
|
||||
@@ -54,6 +56,9 @@ export const NotificationIconsMap = {
|
||||
[NotificationTypes.VISIT_PLAN_UPDATE_NOTIFICATION_TEMPLATE]: <NotificationVisitPlanIcon />,
|
||||
[NotificationTypes.AGENT_ID_APPROVED_TEMPLATE]: <IDCardApproveIcon />,
|
||||
[NotificationTypes.AGENT_ID_REJECTED_TEMPLATE]: <IDCardRejectIcon />,
|
||||
[NotificationTypes.AGENT_COMMITMENTS_VISIT_CASH]: <NotificationIcon />,
|
||||
[NotificationTypes.AGENT_DAILY_COMMITMENT]: <NotificationIcon />,
|
||||
|
||||
};
|
||||
|
||||
export enum WidgetStatus {
|
||||
|
||||
16
src/types/commitmentTracker.types.ts
Normal file
16
src/types/commitmentTracker.types.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export interface IAddCommitmentProps {
|
||||
openBottomSheet: boolean;
|
||||
setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
export interface IAddCommitment {
|
||||
cashCommitted: string;
|
||||
visitsCommitted: string;
|
||||
}
|
||||
|
||||
export interface IAlterVIsibility {
|
||||
isCommitmentFilled : boolean;
|
||||
isCommitmentBannerVisible : boolean;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user