diff --git a/src/assets/icons/BookIcon.tsx b/src/assets/icons/BookIcon.tsx
new file mode 100644
index 00000000..a87b7655
--- /dev/null
+++ b/src/assets/icons/BookIcon.tsx
@@ -0,0 +1,13 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+const BookIcon = () => (
+
+);
+
+export default BookIcon;
diff --git a/src/assets/icons/RightChevronIcon.tsx b/src/assets/icons/RightChevronIcon.tsx
index 69e11441..002a2652 100644
--- a/src/assets/icons/RightChevronIcon.tsx
+++ b/src/assets/icons/RightChevronIcon.tsx
@@ -1,7 +1,9 @@
+import { COLORS } from '@rn-ui-lib/colors';
+import { IconProps } from '@rn-ui-lib/icons/types';
import React from 'react';
import { G, Mask, Path, Rect, Svg } from 'react-native-svg';
-const RightChevronIcon = () => {
+const RightChevronIcon: React.FC = ({ fillColor = COLORS.TEXT.BLUE }) => {
return (
diff --git a/src/assets/icons/TextMaterialIcon.tsx b/src/assets/icons/TextMaterialIcon.tsx
new file mode 100644
index 00000000..36b8e98a
--- /dev/null
+++ b/src/assets/icons/TextMaterialIcon.tsx
@@ -0,0 +1,13 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+const TextMaterialIcon = () => (
+
+);
+
+export default TextMaterialIcon;
diff --git a/src/assets/icons/VideoIcon.tsx b/src/assets/icons/VideoIcon.tsx
new file mode 100644
index 00000000..a96db6a9
--- /dev/null
+++ b/src/assets/icons/VideoIcon.tsx
@@ -0,0 +1,20 @@
+import * as React from 'react';
+import Svg, { G, Path, Defs, ClipPath, Rect } from 'react-native-svg';
+
+const VideoIcon = () => (
+
+);
+
+export default VideoIcon;
diff --git a/src/common/Constants.ts b/src/common/Constants.ts
index 51d9e77a..afd8ed3b 100644
--- a/src/common/Constants.ts
+++ b/src/common/Constants.ts
@@ -464,9 +464,9 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_VIEW_PAST_FEEDBACK_PREV_PAGE_FAILED',
description: 'FA_VIEW_PAST_FEEDBACK_PREV_PAGE_FAILED',
},
- FA_VIEW_PHOTO_CLICKED: {
- name: 'FA_VIEW_PHOTO_CLICKED',
- description: 'FA_VIEW_PHOTO_CLICKED'
+ FA_VIEW_PHOTO_CLICKED: {
+ name: 'FA_VIEW_PHOTO_CLICKED',
+ description: 'FA_VIEW_PHOTO_CLICKED',
},
FA_CUSTOMER_DOCUMENT_CLICKED: {
name: 'FA_CUSTOMER_DOCUMENT_CLICKED',
@@ -513,7 +513,6 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_VIEW_ALL_ESCALATIONS_SCREEN_LANDED',
description: 'FA_VIEW_ALL_ESCALATIONS_SCREEN_LANDED',
},
-
// Notifications
FA_NOTIFICATION_ICON_CLICK: {
@@ -810,7 +809,7 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_FETCHED_CUSTOMER_DOCUMENTS',
description: 'FA_FETCHED_CUSTOMER_DOCUMENTS',
},
- FA_FETCH_CUSTOMER_DOCUMENTS_FAILED: {
+ FA_FETCH_CUSTOMER_DOCUMENTS_FAILED: {
name: 'FA_FETCHED_CUSTOMER_DOCUMENTS_FAILED',
description: 'FA_FETCHED_CUSTOMER_DOCUMENTS_FAILED',
},
@@ -837,7 +836,7 @@ export const CLICKSTREAM_EVENT_NAMES = {
FA_CHANNEL_CLICKED_SHARE_JOURNEY: {
name: 'FA_CHANNEL_CLICKED_SHARE_JOURNEY',
description: 'FA_CHANNEL_CLICKED_SHARE_JOURNEY',
- },
+ },
FA_PHONE_NUMBER_CLICKED_SHARE_JOURNEY: {
name: 'FA_PHONE_NUMBER_CLICKED_SHARE_JOURNEY',
description: 'FA_PHONE_NUMBER_CLICKED_SHARE_JOURNEY',
@@ -1133,7 +1132,7 @@ export const CLICKSTREAM_EVENT_NAMES = {
},
LITMUS_EXPERIMENT: {
name: 'LITMUS_EXPERIMENT',
- description: 'LITMUS_EXPERIMENT'
+ description: 'LITMUS_EXPERIMENT',
},
//FEE WAIVE CLICKSTREAM EVENTS
@@ -1294,107 +1293,129 @@ export const CLICKSTREAM_EVENT_NAMES = {
description: 'Call banner clicked',
},
FA_READ_PERMISSION_ERROR: {
- name: 'ERROR_IN_FETCHING_READ_PERMISSION',
- description: 'Error in fetching read permission'
+ name: 'ERROR_IN_FETCHING_READ_PERMISSION',
+ description: 'Error in fetching read permission',
},
FA_READ_PERMISSION_NOT_PROVIDED: {
- name: 'FA_READ_PERMISSION_NOT_PROVIDED',
- description: 'Read permission not provided'
+ name: 'FA_READ_PERMISSION_NOT_PROVIDED',
+ description: 'Read permission not provided',
},
FA_CALLING_FEEDBACK_NUDGE_LOADED: {
name: 'FA_CALLING_FEEDBACK_NUDGE_LOADED',
- description: 'Calling feedback nudge loaded'
+ description: 'Calling feedback nudge loaded',
},
FA_CALLING_FEEDBACK_NUDGE_FEEDBACK_BUTTON_CLICKED: {
name: 'FA_CALLING_FEEDBACK_NUDGE_FEEDBACK_BUTTON_CLICKED',
- description: 'Fill feedback button clicked'
+ description: 'Fill feedback button clicked',
},
FA_CALLING_FEEDBACK_NUDGE_CLOSED: {
name: 'FA_CALLING_FEEDBACK_NUDGE_CLOSED',
- description: 'Feedback nudge closed'
+ description: 'Feedback nudge closed',
},
FA_INSTALLING_CODEPUSH: {
- name : 'FA_INSTALLING_CODEPUSH',
- description: 'Codepush installation started'
+ name: 'FA_INSTALLING_CODEPUSH',
+ description: 'Codepush installation started',
},
FA_CODEPUSH_DEFAULT_STATUS: {
- name : 'FA_CODEPUSH_DEFAULT_STATUS',
- description: 'Codepush default fallback case'
+ name: 'FA_CODEPUSH_DEFAULT_STATUS',
+ description: 'Codepush default fallback case',
},
FA_CODEPUSH_UNKNOWN_ERROR: {
- name : 'FA_CODEPUSH_UNKNOWN_ERROR',
- description: 'Codepush unknown error'
+ name: 'FA_CODEPUSH_UNKNOWN_ERROR',
+ description: 'Codepush unknown error',
},
FA_FEEDBACK_IMAGE_NOT_FOUND: {
name: 'FA_FEEDBACK_IMAGE_NOT_FOUND',
- description: 'Feedback image not found'
+ description: 'Feedback image not found',
},
FA_UNSYNC_FEEDBACK_CAPTURED: {
name: 'FA_UNSYNC_FEEDBACK_CAPTURED',
- description: 'Unsync feedback captured'
+ description: 'Unsync feedback captured',
},
FA_API_FAILED: {
name: 'FA_API_FAILED',
- description: 'API failed'
+ description: 'API failed',
},
// Apk Update
FA_APK_UPDATE_DOWNLOAD_STARTED: {
name: 'FA_APK_UPDATE_DOWNLOAD_STARTED',
- description: 'APK update download started'
+ description: 'APK update download started',
},
FA_APK_UPDATE_DOWNLOAD_SUCCESS: {
name: 'FA_APK_UPDATE_DOWNLOAD_SUCCESS',
- description: 'APK update download completed'
+ description: 'APK update download completed',
},
FA_APK_UPDATE_DOWNLOAD_FAILED: {
name: 'FA_APK_UPDATE_DOWNLOAD_FAILED',
- description: 'APK update download failed'
+ description: 'APK update download failed',
},
FA_APK_UPDATE_BUTTON_CLICKED: {
name: 'FA_APK_UPDATE_BUTTON_CLICKED',
- description: 'APK update button clicked'
+ description: 'APK update button clicked',
},
FA_APK_UPDATE_INSTALL_STARTED: {
name: 'FA_APK_UPDATE_INSTALL_STARTED',
- description: 'APK update installation started'
+ description: 'APK update installation started',
},
FA_APK_UPDATE_INSTALL_FAILED: {
name: 'FA_APK_UPDATE_INSTALL_FAILED',
- description: 'APK update installation failed'
+ description: 'APK update installation failed',
},
FA_APK_UPDATE_FALLBACK_TRIGGERED: {
name: 'FA_APK_UPDATE_FALLBACK_TRIGGERED',
- description: 'APK update fallback triggered'
+ description: 'APK update fallback triggered',
},
FA_APK_UPDATE_CORRUPTED_FILE_DOWNLOADED: {
name: 'FA_APK_UPDATE_CORRUPTED_FILE_DOWNLOADED',
- description: 'APK update corrupted file downloaded'
+ description: 'APK update corrupted file downloaded',
},
FA_APK_UPDATE_INSTALL_SUCCESS: {
name: 'FA_APK_UPDATE_INSTALL_SUCCESS',
- description: 'APK update installation success'
+ description: 'APK update installation success',
},
FA_POST_OPERATIVE_HOURS_SCREEN_LOADED: {
name: 'FA_POST_OPERATIVE_HOURS_SCREEN_LOADED',
- description: 'Post operative hours screen loaded'
+ description: 'Post operative hours screen loaded',
},
FA_PERSIST_ORIGINAL_IMAGE_FAILURE: {
name: 'FA_PERSIST_ORIGINAL_IMAGE_FAILURE',
- description: 'Failed to persist original image'
+ description: 'Failed to persist original image',
},
// Filter coachmarks
FA_FILTER_COACHMARKS_LOADED: {
name: 'FA_FILTER_COACHMARKS_LOADED',
- description: 'Filter coachmarks loaded'
+ description: 'Filter coachmarks loaded',
},
FA_FILTER_COACHMARKS_FAILED: {
name: 'FA_FILTER_COACHMARKS_FAILED',
- description: 'Filter coachmarks failed'
- }
+ description: 'Filter coachmarks failed',
+ },
+
+ // Training module
+ FA_PROFILE_PAGE_TRAINING_MATERIAL_CLICKED: {
+ name: 'FA_PROFILE_PAGE_TRAINING_MATERIAL_CLICKED',
+ description: 'Training material clicked',
+ },
+ FA_TRAINING_MATERIAL_LIST_SCREEN_LOADED: {
+ name: 'FA_TRAINING_MATERIAL_LIST_SCREEN_LOADED',
+ description: 'Training material screen loaded',
+ },
+ FA_TRAINING_MATERIAL_ITEM_CLICKED: {
+ name: 'FA_TRAINING_MATERIAL_ITEM_CLICKED',
+ description: 'Training material item clicked',
+ },
+ FA_TRAINING_MATERIAL_ITEM_LOADED: {
+ name: 'FA_TRAINING_MATERIAL_ITEM_LOADED',
+ description: 'Training material item loaded',
+ },
+ FA_TRAINING_MATERIAL_PDF_PAGE_CHANGED: {
+ name: 'FA_TRAINING_MATERIAL_PDF_PAGE_CHANGED',
+ description: 'Training material PDF page changed',
+ },
} as const;
export enum MimeType {
@@ -1541,4 +1562,4 @@ export const API_ERROR_MESSAGE = 'Oops! something went wrong';
export enum BuildFlavours {
FIELD_AGENTS = 'fieldAgents',
CALLING_AGENTS = 'callingAgents',
-}
\ No newline at end of file
+}
diff --git a/src/components/pdfRenderer/PdfRenderer.tsx b/src/components/pdfRenderer/PdfRenderer.tsx
new file mode 100644
index 00000000..e00a743b
--- /dev/null
+++ b/src/components/pdfRenderer/PdfRenderer.tsx
@@ -0,0 +1,70 @@
+import { COLORS } from '@rn-ui-lib/colors';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import React, { useEffect, useState } from 'react';
+import { ActivityIndicator, SafeAreaView, StyleSheet } from 'react-native';
+import PdfRendererView from 'react-native-pdf-renderer';
+import { IPdfRenderer } from './interfaces';
+import RNFetchBlob from 'react-native-blob-util';
+import SuspenseLoader from '@rn-ui-lib/components/suspense_loader/SuspenseLoader';
+import Text from '@rn-ui-lib/components/Text';
+
+const ERROR_STATE = 'ERROR';
+
+const PdfRenderer: React.FC = ({ docId, url, onPageChange }) => {
+ const [pdfFilePath, setPdfFilePath] = useState('');
+ const isLoading = !pdfFilePath;
+ const error = pdfFilePath === ERROR_STATE;
+
+ const saveFileToCache = async () => {
+ const cacheDirectory = RNFetchBlob.fs.dirs.CacheDir;
+ const cacheFilePath = `${cacheDirectory}/${docId}.pdf`;
+ const doesFileExist = await RNFetchBlob.fs.exists(cacheFilePath);
+ if (doesFileExist) {
+ setPdfFilePath(cacheFilePath);
+ return;
+ }
+ const highQualityResponse = await RNFetchBlob.fetch('GET', url);
+ if (highQualityResponse.respInfo.status !== 200) {
+ setPdfFilePath(ERROR_STATE);
+ } else if (highQualityResponse.respInfo.status === 200) {
+ const highQualityImageBase64 = await highQualityResponse.base64();
+ await RNFetchBlob.fs.writeFile(cacheFilePath, highQualityImageBase64, 'base64');
+ setPdfFilePath(cacheFilePath);
+ }
+ };
+
+ useEffect(() => {
+ saveFileToCache();
+ }, [url]);
+
+ const handlePageChange = (pageNumber: number) => {
+ onPageChange?.(pageNumber);
+ };
+
+ return (
+
+ }>
+ {error ? (
+ Failed to load PDF
+ ) : (
+
+ )}
+
+
+ );
+};
+
+export const styles = StyleSheet.create({
+ pdf: {
+ flex: 1,
+ backgroundColor: COLORS.BACKGROUND.GREY_LIGHT_2,
+ },
+});
+
+export default PdfRenderer;
diff --git a/src/components/pdfRenderer/interfaces.ts b/src/components/pdfRenderer/interfaces.ts
new file mode 100644
index 00000000..5075386e
--- /dev/null
+++ b/src/components/pdfRenderer/interfaces.ts
@@ -0,0 +1,5 @@
+export interface IPdfRenderer {
+ docId: string;
+ url: string;
+ onPageChange?: (pageNumber: number) => void;
+}
\ No newline at end of file
diff --git a/src/components/utlis/apiHelper.ts b/src/components/utlis/apiHelper.ts
index 3c1ef760..03e35bbe 100644
--- a/src/components/utlis/apiHelper.ts
+++ b/src/components/utlis/apiHelper.ts
@@ -215,7 +215,7 @@ API_URLS[ApiKeys.GET_GROUPED_ADDRESSES_AND_GEOLOCATIONS] =
API_URLS[ApiKeys.GET_EMI_SCHEDULE] = '/collection-cases/emiSchedule';
API_URLS[ApiKeys.GET_REPAYMENTS] = '/collection-cases/repayments';
API_URLS[ApiKeys.GET_FEEDBACK_HISTORY] = '/feedback/filters';
-API_URLS[ApiKeys.GET_PRIORTIY_FEEDBACK] = 'feedback/case-status';
+API_URLS[ApiKeys.GET_PRIORTIY_FEEDBACK] = '/feedback/case-status';
export const API_STATUS_CODE = {
OK: 200,
diff --git a/src/components/webViewVideoPlayer/WebViewVideoPlayer.tsx b/src/components/webViewVideoPlayer/WebViewVideoPlayer.tsx
new file mode 100644
index 00000000..cb73d6a1
--- /dev/null
+++ b/src/components/webViewVideoPlayer/WebViewVideoPlayer.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import WebView from 'react-native-webview';
+import { IWebViewVideoPlayer } from './interfaces';
+import { videoPlayerHTML } from './constants';
+
+const WebViewVideoPlayer: React.FC = ({ url }) => {
+ return (
+
+ );
+};
+
+export default WebViewVideoPlayer;
diff --git a/src/components/webViewVideoPlayer/constants.ts b/src/components/webViewVideoPlayer/constants.ts
new file mode 100644
index 00000000..b9cfe5f1
--- /dev/null
+++ b/src/components/webViewVideoPlayer/constants.ts
@@ -0,0 +1,11 @@
+export const videoPlayerHTML = (url: string) => `
+
+
+
+
+
+
+`;
diff --git a/src/components/webViewVideoPlayer/interfaces.ts b/src/components/webViewVideoPlayer/interfaces.ts
new file mode 100644
index 00000000..ee1c2d86
--- /dev/null
+++ b/src/components/webViewVideoPlayer/interfaces.ts
@@ -0,0 +1,3 @@
+export interface IWebViewVideoPlayer {
+ url: string;
+}
\ No newline at end of file
diff --git a/src/reducer/trainingMaterialSlice.ts b/src/reducer/trainingMaterialSlice.ts
new file mode 100644
index 00000000..119fd42a
--- /dev/null
+++ b/src/reducer/trainingMaterialSlice.ts
@@ -0,0 +1,58 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+import {
+ ITrainingMaterial,
+ TrainingMaterialContentType,
+} from '@screens/trainingMaterial/interfaces';
+
+interface ITrainingMaterialSlice {
+ loading: boolean;
+ data: ITrainingMaterial[];
+}
+
+const MOCK_DATA = [
+ {
+ documentReferenceId: 'doc1',
+ topic: 'If Customer is demanding settlement',
+ contentType: TrainingMaterialContentType.PDF,
+ createdAt: '2021-06-02T00:00:00.000Z',
+ isNewMaterial: true,
+ metadata: {
+ duration: '',
+ pageCount: '10 Pages',
+ },
+ },
+ {
+ documentReferenceId: 'doc2',
+ topic: 'How to fill daily commitment',
+ contentType: TrainingMaterialContentType.VIDEO,
+ createdAt: '2021-06-02T00:00:00.000Z',
+ isNewMaterial: false,
+ metadata: {
+ duration: '10 min',
+ pageCount: '',
+ },
+ },
+];
+
+const initialState: ITrainingMaterialSlice = {
+ loading: false,
+ data: MOCK_DATA,
+};
+
+const TrainingMaterialSlice = createSlice({
+ name: 'trainingMaterial',
+ initialState,
+ reducers: {
+ setTrainingMaterialLoading: (state, action: PayloadAction) => {
+ state.loading = action.payload;
+ },
+ setTrainingMaterialData: (state, action: PayloadAction) => {
+ state.data = action.payload;
+ },
+ },
+});
+
+export const { setTrainingMaterialLoading, setTrainingMaterialData } =
+ TrainingMaterialSlice.actions;
+
+export default TrainingMaterialSlice.reducer;
diff --git a/src/screens/Profile/Navigation/constants.ts b/src/screens/Profile/Navigation/constants.ts
index 039769ea..cc4076bb 100644
--- a/src/screens/Profile/Navigation/constants.ts
+++ b/src/screens/Profile/Navigation/constants.ts
@@ -10,6 +10,7 @@ import store from '@store';
import { Alert } from 'react-native';
import { ProfileScreenStackEnum } from '../ProfileStack';
import CountComponent from '../CountComponent';
+import BookIcon from '@assets/icons/BookIcon';
export const getNavigationLinks = () => {
const { isTeamLead, selectedAgent, featureFlags } = store?.getState().user;
@@ -37,6 +38,15 @@ export const getNavigationLinks = () => {
isNew: true,
NewComponent: CountComponent,
},
+ {
+ name: 'Training material',
+ icon: BookIcon,
+ isVisible: true,
+ onPress: () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PROFILE_PAGE_TRAINING_MATERIAL_CLICKED);
+ navigateToScreen(ProfileScreenStackEnum.TRAINING_MATERIAL);
+ },
+ },
{
name: 'Logout',
icon: LogoutIcon,
diff --git a/src/screens/Profile/ProfileStack.tsx b/src/screens/Profile/ProfileStack.tsx
index 0e42b135..c58a70ce 100644
--- a/src/screens/Profile/ProfileStack.tsx
+++ b/src/screens/Profile/ProfileStack.tsx
@@ -9,6 +9,8 @@ import Profile from '.';
import AgentIdCard from './AgentIdCard';
import MyDocuments from './MyDocuments';
import PDFFullScreen from '@screens/caseDetails/PDFFullScreen';
+import TrainingMaterial from '@screens/trainingMaterial/TrainingMaterial';
+import TrainingMaterialDetail from '@screens/trainingMaterial/TrainingMaterialDetail';
const Stack = createNativeStackNavigator();
@@ -20,6 +22,8 @@ export enum ProfileScreenStackEnum {
AGENT_ID_CARD = 'agentIdCard',
MY_DOCUMENTS = 'myDocuments',
PDF_FULL = 'pdfFull',
+ TRAINING_MATERIAL = 'trainingMaterial',
+ TRAINING_MATERIAL_DETAIL = 'trainingMaterialDetail',
}
const ProfileStack = () => {
@@ -47,6 +51,12 @@ const ProfileStack = () => {
component={PDFFullScreen}
options={{ ...DEFAULT_SCREEN_OPTIONS, orientation: 'all' }}
/>
+
+
);
};
diff --git a/src/screens/trainingMaterial/TrainingMaterial.tsx b/src/screens/trainingMaterial/TrainingMaterial.tsx
new file mode 100644
index 00000000..7a509432
--- /dev/null
+++ b/src/screens/trainingMaterial/TrainingMaterial.tsx
@@ -0,0 +1,56 @@
+import { goBack } from '@components/utlis/navigationUtlis';
+import { useAppDispatch, useAppSelector } from '@hooks';
+import { COLORS } from '@rn-ui-lib/colors';
+import NavigationHeader from '@rn-ui-lib/components/NavigationHeader';
+import SuspenseLoader from '@rn-ui-lib/components/suspense_loader/SuspenseLoader';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import Layout from '@screens/layout/Layout';
+import React, { useEffect } from 'react';
+import { ActivityIndicator, ScrollView, View } from 'react-native';
+import TrainingMaterialListItem from './TrainingMaterialListItem';
+import { setShouldHideTabBar } from '@reducers/commonSlice';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+
+const TrainingMaterial = () => {
+ const loading = useAppSelector((state) => state.trainingMaterial.loading);
+ const trainingMaterial = useAppSelector((state) => state.trainingMaterial.data);
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ dispatch(setShouldHideTabBar(true));
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_TRAINING_MATERIAL_LIST_SCREEN_LOADED);
+ return () => {
+ dispatch(setShouldHideTabBar(false));
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+ }
+ >
+
+
+
+ {trainingMaterial.map((item) => (
+
+ ))}
+
+
+
+
+
+ );
+};
+
+export default TrainingMaterial;
diff --git a/src/screens/trainingMaterial/TrainingMaterialDetail.tsx b/src/screens/trainingMaterial/TrainingMaterialDetail.tsx
new file mode 100644
index 00000000..8f408fb8
--- /dev/null
+++ b/src/screens/trainingMaterial/TrainingMaterialDetail.tsx
@@ -0,0 +1,56 @@
+import NavigationHeader from '@rn-ui-lib/components/NavigationHeader';
+import Layout from '@screens/layout/Layout';
+import React, { useEffect } from 'react';
+import { ITrainingMaterialDetail, TrainingMaterialContentType } from './interfaces';
+import { goBack } from '@components/utlis/navigationUtlis';
+import { View } from 'react-native';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import WebViewVideoPlayer from '@components/webViewVideoPlayer/WebViewVideoPlayer';
+import PdfRenderer from '@components/pdfRenderer/PdfRenderer';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+
+const TrainingMaterialDetail: React.FC = (props) => {
+ const {
+ route: {
+ params: { trainingMaterialData },
+ },
+ } = props;
+ const { topic, contentType, documentReferenceId } = trainingMaterialData;
+ const isVideo = contentType === TrainingMaterialContentType.VIDEO;
+
+ useEffect(() => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_TRAINING_MATERIAL_ITEM_LOADED, {
+ contentType,
+ documentReferenceId,
+ });
+ }, []);
+
+ const handlePageChange = (pageNumber: number) => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_TRAINING_MATERIAL_PDF_PAGE_CHANGED, {
+ pageNumber,
+ documentReferenceId,
+ });
+ };
+
+ return (
+
+
+
+ {isVideo ? (
+
+ ) : (
+
+ )}
+
+
+ );
+};
+
+export default TrainingMaterialDetail;
diff --git a/src/screens/trainingMaterial/TrainingMaterialListItem.tsx b/src/screens/trainingMaterial/TrainingMaterialListItem.tsx
new file mode 100644
index 00000000..321b365f
--- /dev/null
+++ b/src/screens/trainingMaterial/TrainingMaterialListItem.tsx
@@ -0,0 +1,94 @@
+import React from 'react';
+import { ITrainingMaterialListItem } from './interfaces';
+import { Pressable, StyleSheet, View } from 'react-native';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import { TrainingMaterialContentMap } from './constants';
+import RightChevronIcon from '@assets/icons/RightChevronIcon';
+import Text from '@rn-ui-lib/components/Text';
+import { COLORS } from '@rn-ui-lib/colors';
+import { BUSINESS_DATE_FORMAT, dateFormat } from '@rn-ui-lib/utils/dates';
+import Tag, { TagVariant } from '@rn-ui-lib/components/Tag';
+import { navigateToScreen } from '@components/utlis/navigationUtlis';
+import { ProfileScreenStackEnum } from '@screens/Profile/ProfileStack';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+
+const TrainingMaterialListItem: React.FC = ({
+ trainingMaterialData,
+}) => {
+ const { contentType, topic, metadata, createdAt, isNewMaterial, documentReferenceId } =
+ trainingMaterialData || {};
+ const { icon, interaction, metadataKey } = TrainingMaterialContentMap[contentType] || {};
+ const metadataValue = metadata?.[metadataKey];
+
+ const handleMaterialPress = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_TRAINING_MATERIAL_ITEM_CLICKED, {
+ documentReferenceId,
+ });
+ navigateToScreen(ProfileScreenStackEnum.TRAINING_MATERIAL_DETAIL, {
+ trainingMaterialData,
+ });
+ };
+
+ return (
+
+ {isNewMaterial ? : null}
+
+
+ {icon}
+
+
+ {topic}
+
+
+
+ {interaction}
+
+
+ {' '}
+ ●{' '}
+
+
+ {metadataValue}
+
+ ●
+
+ {dateFormat(new Date(createdAt), BUSINESS_DATE_FORMAT)}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ newTag: {
+ position: 'absolute',
+ top: 0,
+ right: 0,
+ borderTopWidth: 0,
+ borderRightWidth: 0,
+ borderTopLeftRadius: 0,
+ borderBottomRightRadius: 0,
+ },
+ bullet: {
+ color: COLORS.TEXT.GREY_1,
+ },
+});
+
+export default TrainingMaterialListItem;
diff --git a/src/screens/trainingMaterial/constants.tsx b/src/screens/trainingMaterial/constants.tsx
new file mode 100644
index 00000000..c63c6467
--- /dev/null
+++ b/src/screens/trainingMaterial/constants.tsx
@@ -0,0 +1,20 @@
+import TextMaterialIcon from '@assets/icons/TextMaterialIcon';
+import { TrainingMaterialContentType } from './interfaces';
+import VideoIcon from '@assets/icons/VideoIcon';
+import PDFFullScreen from '@screens/caseDetails/PDFFullScreen';
+import WebViewVideoPlayer from '@components/webViewVideoPlayer/WebViewVideoPlayer';
+
+export const TrainingMaterialContentMap = {
+ [TrainingMaterialContentType.PDF]: {
+ interaction: 'Reading',
+ icon: ,
+ metadataKey: 'pageCount',
+ component: PDFFullScreen,
+ },
+ [TrainingMaterialContentType.VIDEO]: {
+ interaction: 'Video',
+ icon: ,
+ metadataKey: 'duration',
+ component: WebViewVideoPlayer,
+ },
+};
diff --git a/src/screens/trainingMaterial/interfaces.ts b/src/screens/trainingMaterial/interfaces.ts
new file mode 100644
index 00000000..56799fbf
--- /dev/null
+++ b/src/screens/trainingMaterial/interfaces.ts
@@ -0,0 +1,25 @@
+export enum TrainingMaterialContentType {
+ PDF = 'PDF',
+ VIDEO = 'VIDEO',
+}
+
+export interface ITrainingMaterial {
+ documentReferenceId: string;
+ topic: string;
+ contentType: TrainingMaterialContentType;
+ createdAt: string;
+ isNewMaterial: boolean;
+ metadata: Record;
+}
+
+export interface ITrainingMaterialListItem {
+ trainingMaterialData: ITrainingMaterial;
+}
+
+export interface ITrainingMaterialDetail {
+ route: {
+ params: {
+ trainingMaterialData: ITrainingMaterial;
+ };
+ };
+}
diff --git a/src/store/store.ts b/src/store/store.ts
index 7c5abb5d..6f82d789 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -36,6 +36,7 @@ import documentsSlice from '@reducers/documentsSlice';
import topFeedbacksSlice from '@reducers/topFeedbacksSlice';
import escalationSlice from '@reducers/escalationSlice';
import postOperationalHourRestrictionsSlice from '@reducers/postOperationalHourRestrictionsSlice';
+import trainingMaterialSlice from '@reducers/trainingMaterialSlice';
const rootReducer = combineReducers({
case: caseReducer,
@@ -71,7 +72,8 @@ const rootReducer = combineReducers({
documentsSlice: documentsSlice,
topFeedbacks: topFeedbacksSlice,
escalationSlice: escalationSlice,
- postOperationalHourRestrictionsSlice: postOperationalHourRestrictionsSlice
+ postOperationalHourRestrictionsSlice: postOperationalHourRestrictionsSlice,
+ trainingMaterial: trainingMaterialSlice,
});
const persistConfig = {
@@ -95,7 +97,7 @@ const persistConfig = {
'feedbackFilters',
'litmusExperiment',
'activeCall',
- 'appUpdate'
+ 'appUpdate',
],
blackList: [
'case',