react-native-salespanda 0.7.6 → 0.7.7

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 (130) hide show
  1. package/lib/module/NativeSalespanda.js.map +1 -0
  2. package/lib/module/SalespandaApp.js.map +1 -0
  3. package/lib/module/assets/images/index.js.map +1 -0
  4. package/lib/module/components/BottomSheet.js.map +1 -0
  5. package/lib/module/components/ContactViaModal.js.map +1 -0
  6. package/lib/module/components/Loader.js.map +1 -0
  7. package/lib/module/components/ScreenHeader.js.map +1 -0
  8. package/lib/module/components/SearchBar.js.map +1 -0
  9. package/lib/module/components/TabsHeader.js.map +1 -0
  10. package/lib/module/components/index.js.map +1 -0
  11. package/lib/module/config/FlavorConfig.js.map +1 -0
  12. package/lib/module/config/SalespandaConfig.js.map +1 -0
  13. package/lib/module/constants/Colors.js.map +1 -0
  14. package/lib/module/constants/GetPlatorm.js.map +1 -0
  15. package/lib/module/index.js.map +1 -0
  16. package/lib/module/navigation/AppNavigator.js.map +1 -0
  17. package/lib/module/navigation/BottomTabNavigator.js.map +1 -0
  18. package/lib/module/navigation/DrawerNavigator.js.map +1 -0
  19. package/lib/module/navigation/StackNavigator.js.map +1 -0
  20. package/lib/module/screens/CRM/AddContactModal.js.map +1 -0
  21. package/lib/module/screens/CRM/CategoryTabs.js.map +1 -0
  22. package/lib/module/screens/CRM/ContactItem.js.map +1 -0
  23. package/lib/module/screens/CRM/FilterDropdown.js.map +1 -0
  24. package/lib/module/screens/CRM/FunnelChart.js.map +1 -0
  25. package/lib/module/screens/CRM/InfoCard.js.map +1 -0
  26. package/lib/module/screens/CRM/LeadCard.js.map +1 -0
  27. package/lib/module/screens/CRM/LogCallScreen.js.map +1 -0
  28. package/lib/module/screens/CRM/TopTabs.js.map +1 -0
  29. package/lib/module/screens/CRM/index.js.map +1 -0
  30. package/lib/module/screens/ReportsScreen.js.map +1 -0
  31. package/lib/module/screens/Tabs/ActivityAnalytics.js.map +1 -0
  32. package/lib/module/screens/Tabs/CRMScreen.js.map +1 -0
  33. package/lib/module/screens/Tabs/DigitalDiary.js.map +1 -0
  34. package/lib/module/screens/Tabs/HomeScreen.js.map +1 -0
  35. package/lib/module/screens/Tabs/NotificationsScreen.js.map +1 -0
  36. package/lib/module/screens/contentliberary/contentliberary.js.map +1 -0
  37. package/lib/module/services/api.js.map +1 -0
  38. package/lib/module/services/authService.js.map +1 -0
  39. package/lib/module/store/index.js.map +1 -0
  40. package/lib/typescript/src/NativeSalespanda.d.ts.map +1 -0
  41. package/lib/typescript/src/SalespandaApp.d.ts.map +1 -0
  42. package/lib/typescript/src/assets/images/index.d.ts.map +1 -0
  43. package/lib/typescript/src/components/BottomSheet.d.ts.map +1 -0
  44. package/lib/typescript/src/components/ContactViaModal.d.ts.map +1 -0
  45. package/lib/typescript/src/components/Loader.d.ts.map +1 -0
  46. package/lib/typescript/src/components/ScreenHeader.d.ts.map +1 -0
  47. package/lib/typescript/src/components/SearchBar.d.ts.map +1 -0
  48. package/lib/typescript/src/components/TabsHeader.d.ts.map +1 -0
  49. package/lib/typescript/src/components/index.d.ts.map +1 -0
  50. package/lib/typescript/src/config/FlavorConfig.d.ts.map +1 -0
  51. package/lib/typescript/src/config/SalespandaConfig.d.ts.map +1 -0
  52. package/lib/typescript/src/constants/Colors.d.ts.map +1 -0
  53. package/lib/typescript/src/constants/GetPlatorm.d.ts.map +1 -0
  54. package/lib/typescript/src/index.d.ts.map +1 -0
  55. package/lib/typescript/src/navigation/AppNavigator.d.ts.map +1 -0
  56. package/lib/typescript/src/navigation/BottomTabNavigator.d.ts.map +1 -0
  57. package/lib/typescript/src/navigation/DrawerNavigator.d.ts.map +1 -0
  58. package/lib/typescript/src/navigation/StackNavigator.d.ts.map +1 -0
  59. package/lib/typescript/src/screens/CRM/AddContactModal.d.ts.map +1 -0
  60. package/lib/typescript/src/screens/CRM/CategoryTabs.d.ts.map +1 -0
  61. package/lib/typescript/src/screens/CRM/ContactItem.d.ts.map +1 -0
  62. package/lib/typescript/src/screens/CRM/FilterDropdown.d.ts.map +1 -0
  63. package/lib/typescript/src/screens/CRM/FunnelChart.d.ts.map +1 -0
  64. package/lib/typescript/src/screens/CRM/InfoCard.d.ts.map +1 -0
  65. package/lib/typescript/src/screens/CRM/LeadCard.d.ts.map +1 -0
  66. package/lib/typescript/src/screens/CRM/LogCallScreen.d.ts.map +1 -0
  67. package/lib/typescript/src/screens/CRM/TopTabs.d.ts.map +1 -0
  68. package/lib/typescript/src/screens/CRM/index.d.ts.map +1 -0
  69. package/lib/typescript/src/screens/ReportsScreen.d.ts.map +1 -0
  70. package/lib/typescript/src/screens/Tabs/ActivityAnalytics.d.ts.map +1 -0
  71. package/lib/typescript/src/screens/Tabs/CRMScreen.d.ts.map +1 -0
  72. package/lib/typescript/src/screens/Tabs/DigitalDiary.d.ts.map +1 -0
  73. package/lib/typescript/src/screens/Tabs/HomeScreen.d.ts.map +1 -0
  74. package/lib/typescript/src/screens/Tabs/NotificationsScreen.d.ts.map +1 -0
  75. package/lib/typescript/src/screens/contentliberary/contentliberary.d.ts.map +1 -0
  76. package/lib/typescript/src/services/api.d.ts.map +1 -0
  77. package/lib/typescript/src/services/authService.d.ts.map +1 -0
  78. package/lib/typescript/src/store/index.d.ts.map +1 -0
  79. package/package.json +4 -3
  80. package/react-native.config.js +3 -4
  81. package/src/NativeSalespanda.ts +7 -0
  82. package/src/SalespandaApp.tsx +141 -0
  83. package/src/assets/images/bottomtabs/analytics.png +0 -0
  84. package/src/assets/images/bottomtabs/analyticsactive.png +0 -0
  85. package/src/assets/images/bottomtabs/crm.png +0 -0
  86. package/src/assets/images/bottomtabs/crmactive.png +0 -0
  87. package/src/assets/images/bottomtabs/diary.png +0 -0
  88. package/src/assets/images/bottomtabs/diaryactive.png +0 -0
  89. package/src/assets/images/bottomtabs/home.png +0 -0
  90. package/src/assets/images/bottomtabs/homeactive.png +0 -0
  91. package/src/assets/images/bottomtabs/notification.png +0 -0
  92. package/src/assets/images/bottomtabs/notificationactive.png +0 -0
  93. package/src/assets/images/index.js +11 -0
  94. package/src/assets/images/index.ts +40 -0
  95. package/src/components/BottomSheet.tsx +146 -0
  96. package/src/components/ContactViaModal.tsx +80 -0
  97. package/src/components/Loader.tsx +48 -0
  98. package/src/components/ScreenHeader.tsx +57 -0
  99. package/src/components/SearchBar.tsx +59 -0
  100. package/src/components/TabsHeader.tsx +72 -0
  101. package/src/components/index.ts +5 -0
  102. package/src/config/FlavorConfig.ts +55 -0
  103. package/src/config/SalespandaConfig.ts +142 -0
  104. package/src/constants/Colors.ts +17 -0
  105. package/src/constants/GetPlatorm.ts +29 -0
  106. package/src/index.tsx +31 -0
  107. package/src/navigation/AppNavigator.tsx +24 -0
  108. package/src/navigation/BottomTabNavigator.tsx +181 -0
  109. package/src/navigation/DrawerNavigator.tsx +306 -0
  110. package/src/navigation/StackNavigator.tsx +32 -0
  111. package/src/screens/CRM/AddContactModal.tsx +57 -0
  112. package/src/screens/CRM/CategoryTabs.tsx +109 -0
  113. package/src/screens/CRM/ContactItem.tsx +168 -0
  114. package/src/screens/CRM/FilterDropdown.tsx +34 -0
  115. package/src/screens/CRM/FunnelChart.tsx +103 -0
  116. package/src/screens/CRM/InfoCard.tsx +51 -0
  117. package/src/screens/CRM/LeadCard.tsx +69 -0
  118. package/src/screens/CRM/LogCallScreen.tsx +318 -0
  119. package/src/screens/CRM/TopTabs.tsx +95 -0
  120. package/src/screens/CRM/index.ts +10 -0
  121. package/src/screens/ReportsScreen.tsx +37 -0
  122. package/src/screens/Tabs/ActivityAnalytics.tsx +25 -0
  123. package/src/screens/Tabs/CRMScreen.tsx +381 -0
  124. package/src/screens/Tabs/DigitalDiary.tsx +35 -0
  125. package/src/screens/Tabs/HomeScreen.tsx +379 -0
  126. package/src/screens/Tabs/NotificationsScreen.tsx +25 -0
  127. package/src/screens/contentliberary/contentliberary.tsx +268 -0
  128. package/src/services/api.ts +173 -0
  129. package/src/services/authService.ts +75 -0
  130. package/src/store/index.ts +16 -0
@@ -0,0 +1,379 @@
1
+ import React from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ ScrollView,
8
+ Image,
9
+ FlatList,
10
+ Dimensions,
11
+ } from 'react-native';
12
+ import {
13
+ scale,
14
+ verticalScale,
15
+ moderateScale,
16
+ moderateVerticalScale,
17
+ } from 'react-native-size-matters';
18
+ import { SafeAreaView } from 'react-native-safe-area-context';
19
+ import Loader from '../../components/Loader';
20
+ import TabsHeader from '../../components/TabsHeader';
21
+ import { Colors } from '../../constants/Colors';
22
+ import {
23
+ useAuthenticateMutation,
24
+ useLazyGetHomeQuery,
25
+ useSpssoLoginMutation,
26
+ loadPersistedTokens,
27
+ persistTokens,
28
+ setRuntimeTokens,
29
+ clearPersistedTokens,
30
+ } from '../../services/api';
31
+ import type { HomeResponse } from '../../services/api';
32
+
33
+ interface MenuItemProps {
34
+ title: string;
35
+ imageUrl?: string | null;
36
+ onPress?: () => void;
37
+ }
38
+
39
+ const MenuItem: React.FC<MenuItemProps> = ({ imageUrl, onPress }) => {
40
+ return (
41
+ <TouchableOpacity
42
+ style={styles.menuItem}
43
+ onPress={onPress}
44
+ activeOpacity={0.8}
45
+ >
46
+ {imageUrl ? (
47
+ <Image source={{ uri: imageUrl }} style={styles.menuItemImage} />
48
+ ) : (
49
+ <Loader message="" />
50
+ )}
51
+ </TouchableOpacity>
52
+ );
53
+ };
54
+
55
+ const HomeScreen: React.FC = () => {
56
+ const [loading, setLoading] = React.useState<boolean>(false);
57
+ const [error, setError] = React.useState<string | null>(null);
58
+ const [homeData, setHomeData] = React.useState<
59
+ HomeResponse['response'] | null
60
+ >(null);
61
+
62
+ type BannerItem = {
63
+ image: string;
64
+ title?: string;
65
+ link?: string | null;
66
+ };
67
+
68
+ const [authenticate] = useAuthenticateMutation();
69
+ const [spssoLogin] = useSpssoLoginMutation();
70
+ const [triggerHome, { isFetching: isHomeFetching }] = useLazyGetHomeQuery();
71
+
72
+ const bannerItems: BannerItem[] = React.useMemo(
73
+ () =>
74
+ homeData?.home_banner && homeData.home_banner.length > 0
75
+ ? homeData.home_banner.map((item) => ({
76
+ image: item.image,
77
+ title: item.title ?? undefined,
78
+ link: item.link ?? null,
79
+ }))
80
+ : [],
81
+ [homeData?.home_banner]
82
+ );
83
+
84
+ const menuItems = React.useMemo(() => homeData?.menu ?? [], [homeData?.menu]);
85
+
86
+ const screenWidth = Dimensions.get('window').width;
87
+ const [activeIndex, setActiveIndex] = React.useState(0);
88
+ const flatListRef = React.useRef<any>(null);
89
+
90
+ const handleMomentumScrollEnd = (e: any) => {
91
+ const offsetX = e.nativeEvent.contentOffset.x;
92
+ const index = Math.round(offsetX / screenWidth);
93
+ setActiveIndex(index);
94
+ };
95
+
96
+ const loadHomeData = React.useCallback(
97
+ async (isRetry?: boolean) => {
98
+ try {
99
+ setLoading(true);
100
+ setError(null);
101
+
102
+ const storedTokens = await loadPersistedTokens();
103
+ let accessToken = storedTokens.accessToken;
104
+ let token = storedTokens.token;
105
+
106
+ if (!accessToken) {
107
+ const authResp = await authenticate({}).unwrap();
108
+ accessToken = authResp.access_token;
109
+ setRuntimeTokens({ accessToken });
110
+ await persistTokens({ accessToken });
111
+ }
112
+
113
+ if (!token && accessToken) {
114
+ const ssoResp = await spssoLogin({
115
+ access_token: accessToken,
116
+ }).unwrap();
117
+ token = ssoResp.token;
118
+ setRuntimeTokens({ token });
119
+ await persistTokens({ token });
120
+ }
121
+
122
+ if (!token) {
123
+ throw new Error('Missing auth token, please try again.');
124
+ }
125
+
126
+ const tokenHeader: string | undefined = token ?? undefined;
127
+ const homeResp = await triggerHome({
128
+ tokenOverride: tokenHeader,
129
+ }).unwrap();
130
+
131
+ const isSuccess =
132
+ homeResp.statusCode === '200' &&
133
+ homeResp.status?.toLowerCase() === 'success';
134
+ if (!isSuccess) {
135
+ const code = homeResp.statusCode;
136
+
137
+ if (
138
+ !isRetry &&
139
+ code &&
140
+ (code === '1008' || code === '401' || code === '403')
141
+ ) {
142
+ await clearPersistedTokens();
143
+ setRuntimeTokens({ token: null, accessToken: null });
144
+ await loadHomeData(true);
145
+ return;
146
+ }
147
+
148
+ throw new Error(homeResp?.message || 'Failed to load home data');
149
+ }
150
+
151
+ setHomeData(homeResp.response);
152
+ setLoading(false);
153
+ } catch (e: any) {
154
+ const statusCode = e?.status || e?.data?.statusCode;
155
+ if (statusCode === 401 || statusCode === 403) {
156
+ setError(null);
157
+ return;
158
+ }
159
+ setError(
160
+ e?.data?.message ||
161
+ e?.message ||
162
+ 'Failed to load home data. Please try again.'
163
+ );
164
+ setLoading(false);
165
+ }
166
+ },
167
+ [authenticate, spssoLogin, triggerHome]
168
+ );
169
+
170
+ React.useEffect(() => {
171
+ loadHomeData();
172
+ }, [loadHomeData]);
173
+
174
+ React.useEffect(() => {
175
+ const id = setInterval(() => {
176
+ setActiveIndex((prev) => {
177
+ const next =
178
+ bannerItems.length > 0 ? (prev + 1) % bannerItems.length : 0;
179
+ if (flatListRef.current) {
180
+ try {
181
+ flatListRef.current.scrollToIndex({ index: next, animated: true });
182
+ } catch {
183
+ // ignore scroll failures
184
+ }
185
+ }
186
+ return next;
187
+ });
188
+ }, 2500);
189
+ return () => {
190
+ clearInterval(id);
191
+ };
192
+ }, [bannerItems.length]);
193
+
194
+ return (
195
+ <SafeAreaView style={styles.safeArea} edges={['top', 'bottom']}>
196
+ <View style={styles.container}>
197
+ <TabsHeader title="Home" />
198
+
199
+ <View style={styles.contentWrapper}>
200
+ {loading || isHomeFetching || !homeData ? (
201
+ <Loader overlay message="Loading home data..." />
202
+ ) : null}
203
+
204
+ <View style={styles.carouselContainer}>
205
+ <FlatList
206
+ ref={flatListRef}
207
+ data={bannerItems}
208
+ keyExtractor={(item, idx) => `${item.title || 'banner'}-${idx}`}
209
+ renderItem={({ item }) => (
210
+ <TouchableOpacity activeOpacity={0.9} onPress={() => {}}>
211
+ <Image
212
+ source={{ uri: item.image }}
213
+ style={[styles.carouselImage, { width: screenWidth }]}
214
+ />
215
+ </TouchableOpacity>
216
+ )}
217
+ horizontal
218
+ pagingEnabled
219
+ showsHorizontalScrollIndicator={false}
220
+ onMomentumScrollEnd={handleMomentumScrollEnd}
221
+ getItemLayout={(_, index) => ({
222
+ length: screenWidth,
223
+ offset: screenWidth * index,
224
+ index,
225
+ })}
226
+ />
227
+ <View style={styles.carouselIndicatorsOverlay}>
228
+ {bannerItems.map((_, idx) => (
229
+ <View
230
+ key={idx}
231
+ style={[
232
+ styles.indicator,
233
+ idx === activeIndex ? styles.activeIndicator : null,
234
+ ]}
235
+ />
236
+ ))}
237
+ </View>
238
+ </View>
239
+
240
+ <ScrollView
241
+ style={styles.scrollView}
242
+ contentContainerStyle={styles.scrollContent}
243
+ >
244
+ {error ? (
245
+ <>
246
+ <Text style={styles.errorText}>{error}</Text>
247
+ <TouchableOpacity onPress={() => loadHomeData()}>
248
+ <Text style={styles.retryText}>Tap to retry</Text>
249
+ </TouchableOpacity>
250
+ </>
251
+ ) : null}
252
+
253
+ {menuItems.length > 0 ? (
254
+ <View style={styles.menuGrid}>
255
+ {menuItems.map((item) => (
256
+ <MenuItem
257
+ key={item.title}
258
+ title={item.title}
259
+ imageUrl={item.image}
260
+ />
261
+ ))}
262
+ </View>
263
+ ) : null}
264
+ </ScrollView>
265
+ </View>
266
+ </View>
267
+ </SafeAreaView>
268
+ );
269
+ };
270
+
271
+ export default HomeScreen;
272
+
273
+ const styles = StyleSheet.create({
274
+ safeArea: {
275
+ flex: 1,
276
+ backgroundColor: Colors.white,
277
+ },
278
+ container: {
279
+ flex: 1,
280
+ backgroundColor: Colors.white,
281
+ },
282
+ scrollView: {
283
+ flex: 1,
284
+ backgroundColor: Colors.white,
285
+ },
286
+ scrollContent: {
287
+ paddingBottom: verticalScale(24),
288
+ },
289
+ carouselContainer: {
290
+ width: '100%',
291
+ backgroundColor: Colors.white,
292
+ position: 'relative',
293
+ },
294
+ carouselImage: {
295
+ height: verticalScale(155),
296
+ resizeMode: 'contain',
297
+ backgroundColor: Colors.white,
298
+ },
299
+ carouselIndicatorsOverlay: {
300
+ position: 'absolute',
301
+ left: 0,
302
+ right: 0,
303
+ bottom: verticalScale(20),
304
+ flexDirection: 'row',
305
+ justifyContent: 'center',
306
+ alignItems: 'center',
307
+ },
308
+ indicator: {
309
+ width: scale(8),
310
+ height: scale(8),
311
+ borderRadius: moderateScale(4),
312
+ backgroundColor: Colors.divider,
313
+ marginHorizontal: scale(4),
314
+ },
315
+ activeIndicator: {
316
+ backgroundColor: Colors.white,
317
+ width: scale(24),
318
+ },
319
+ menuGrid: {
320
+ flexDirection: 'row',
321
+ flexWrap: 'wrap',
322
+ paddingTop: scale(8),
323
+ paddingBottom: verticalScale(16),
324
+ justifyContent: 'flex-start',
325
+ alignSelf: 'center',
326
+ width: '100%',
327
+ },
328
+ menuItem: {
329
+ width: '29.5%',
330
+ aspectRatio: 1,
331
+ borderRadius: moderateScale(16),
332
+ marginBottom: moderateVerticalScale(8),
333
+ marginHorizontal: scale(6),
334
+ overflow: 'hidden',
335
+ },
336
+ iconContainer: {
337
+ width: scale(50),
338
+ height: scale(50),
339
+ justifyContent: 'center',
340
+ alignItems: 'center',
341
+ marginBottom: verticalScale(8),
342
+ },
343
+ iconText: {
344
+ fontSize: moderateScale(24),
345
+ },
346
+ menuItemImage: {
347
+ width: '100%',
348
+ height: '100%',
349
+ resizeMode: 'cover',
350
+ },
351
+ menuItemText: {
352
+ fontSize: moderateScale(11),
353
+ textAlign: 'center',
354
+ color: Colors.black,
355
+ fontWeight: '500',
356
+ },
357
+ statusText: {
358
+ fontSize: moderateScale(12),
359
+ color: Colors.black,
360
+ paddingHorizontal: scale(12),
361
+ paddingTop: verticalScale(8),
362
+ },
363
+ errorText: {
364
+ fontSize: moderateScale(12),
365
+ color: 'red',
366
+ paddingHorizontal: scale(12),
367
+ paddingTop: verticalScale(4),
368
+ },
369
+ retryText: {
370
+ fontSize: moderateScale(12),
371
+ color: Colors.primary,
372
+ paddingHorizontal: scale(12),
373
+ paddingTop: verticalScale(6),
374
+ },
375
+ contentWrapper: {
376
+ flex: 1,
377
+ position: 'relative',
378
+ },
379
+ });
@@ -0,0 +1,25 @@
1
+ import { StyleSheet, ScrollView } from 'react-native';
2
+ import { SafeAreaView } from 'react-native-safe-area-context';
3
+ import { Colors } from '../../constants/Colors';
4
+ import TabsHeader from '../../components/TabsHeader';
5
+
6
+ const NotificationsScreen: React.FC = () => {
7
+ return (
8
+ <SafeAreaView style={styles.container} edges={['top', 'bottom']}>
9
+ <TabsHeader title="Notifications" />
10
+ <ScrollView style={styles.scrollView} />
11
+ </SafeAreaView>
12
+ );
13
+ };
14
+
15
+ export default NotificationsScreen;
16
+
17
+ const styles = StyleSheet.create({
18
+ container: {
19
+ flex: 1,
20
+ backgroundColor: Colors.background,
21
+ },
22
+ scrollView: {
23
+ flex: 1,
24
+ },
25
+ });
@@ -0,0 +1,268 @@
1
+ import { useState } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ TextInput,
8
+ FlatList,
9
+ Image,
10
+ Dimensions,
11
+ ScrollView,
12
+ } from 'react-native';
13
+ import FeatherIcon from 'react-native-vector-icons/Feather';
14
+ import { SafeAreaView } from 'react-native-safe-area-context';
15
+
16
+ const { width } = Dimensions.get('window');
17
+ const categories = [
18
+ 'All',
19
+ 'Co-Branded',
20
+ 'Videos',
21
+ 'Reel',
22
+ 'Social',
23
+ 'Brochure',
24
+ 'Leaflet',
25
+ ];
26
+ const greetingsData = [
27
+ {
28
+ id: '1',
29
+ title: 'Happy Diwali!',
30
+ tags: ['Video', 'Co-branded'],
31
+ image:
32
+ 'https://img.freepik.com/premium-vector/poster-festival-lights-diwali_1287372-756.jpg?w=1060',
33
+ },
34
+ {
35
+ id: '2',
36
+ title: 'Happy Diwali!',
37
+ tags: ['Video', 'Co-branded'],
38
+ image:
39
+ 'https://img.freepik.com/premium-vector/poster-festival-lights-diwali_1287372-756.jpg?w=1060',
40
+ },
41
+ ];
42
+ export default function DashboardScreen() {
43
+ const [selectedCat, setSelectedCat] = useState('All');
44
+ return (
45
+ <ScrollView style={styles.container} showsVerticalScrollIndicator={false}>
46
+ <SafeAreaView>
47
+ {/* Header */}
48
+ <View style={styles.headerRow}>
49
+ <TouchableOpacity>
50
+ <FeatherIcon name="arrow-left" size={24} color="#000" />
51
+ </TouchableOpacity>
52
+ <Text style={styles.headerTitle}>Content Library</Text>
53
+ <TouchableOpacity>
54
+ <FeatherIcon name="heart" size={24} color="#000" />
55
+ </TouchableOpacity>
56
+ </View>
57
+ {/* Search Bar */}
58
+ <View style={styles.searchBox}>
59
+ <FeatherIcon name="search" size={18} color="#999" />
60
+ <TextInput
61
+ placeholder="Search by content name, tags"
62
+ placeholderTextColor="#999"
63
+ style={styles.input}
64
+ />
65
+ </View>
66
+ {/* Category Tabs */}
67
+ <View style={styles.categoryContainer}>
68
+ <ScrollView horizontal showsHorizontalScrollIndicator={false}>
69
+ {categories.map((cat, index) => {
70
+ const isActive = selectedCat === cat;
71
+ return (
72
+ <TouchableOpacity
73
+ key={index}
74
+ onPress={() => setSelectedCat(cat)}
75
+ style={styles.tabItem}
76
+ >
77
+ <Text
78
+ style={[styles.tabText, isActive && styles.activeTabText]}
79
+ >
80
+ {cat}
81
+ </Text>
82
+ {/* Yellow bottom line */}
83
+ {isActive ? (
84
+ <View style={styles.activeLine} />
85
+ ) : (
86
+ <View style={{ height: 3 }} />
87
+ )}
88
+ </TouchableOpacity>
89
+ );
90
+ })}
91
+ </ScrollView>
92
+ </View>
93
+ {/* Greetings Section */}
94
+ <View style={styles.sectionHeader}>
95
+ <Text style={styles.sectionTitle}>Greetings (9)</Text>
96
+ <TouchableOpacity>
97
+ <Text style={styles.seeAll}>See all</Text>
98
+ </TouchableOpacity>
99
+ </View>
100
+ <FlatList
101
+ data={greetingsData}
102
+ keyExtractor={(item) => item.id}
103
+ horizontal
104
+ showsHorizontalScrollIndicator={false}
105
+ renderItem={({ item }) => <Card item={item} />}
106
+ />
107
+ </SafeAreaView>
108
+ </ScrollView>
109
+ );
110
+ }
111
+ function Card({ item }: any) {
112
+ return (
113
+ <View style={styles.card}>
114
+ <Image source={{ uri: item.image }} style={styles.cardImage} />
115
+ {/* Heart button */}
116
+ <TouchableOpacity style={styles.cardHeart}>
117
+ <FeatherIcon name="heart" size={18} color="#fff" />
118
+ </TouchableOpacity>
119
+ {/* Tags */}
120
+ <View style={styles.tagRow}>
121
+ {item.tags.map((t: string, i: number) => (
122
+ <View key={i} style={styles.tag}>
123
+ <Text style={styles.tagText}>{t}</Text>
124
+ </View>
125
+ ))}
126
+ </View>
127
+ {/* Title + Share */}
128
+ <View style={styles.cardFooter}>
129
+ <Text numberOfLines={1} style={styles.cardTitle}>
130
+ {item.title}
131
+ </Text>
132
+ <TouchableOpacity
133
+ style={{ flexDirection: 'row', alignItems: 'center' }}
134
+ >
135
+ <Text style={styles.shareText}>Share</Text>
136
+ <FeatherIcon name="chevron-right" size={16} color="#ff9900" />
137
+ </TouchableOpacity>
138
+ </View>
139
+ </View>
140
+ );
141
+ }
142
+ const styles = StyleSheet.create({
143
+ container: {
144
+ padding: 16,
145
+ backgroundColor: '#fff',
146
+ },
147
+ headerRow: {
148
+ flexDirection: 'row',
149
+ alignItems: 'center',
150
+ justifyContent: 'space-between',
151
+ marginBottom: 12,
152
+ },
153
+ headerTitle: {
154
+ fontSize: 20,
155
+ fontWeight: '600',
156
+ marginLeft: -120, // shifts title closer to back icon like screenshot
157
+ },
158
+ searchBox: {
159
+ flexDirection: 'row',
160
+ alignItems: 'center',
161
+ backgroundColor: '#fff',
162
+ borderRadius: 12,
163
+ paddingHorizontal: 12,
164
+ paddingVertical: 10,
165
+ borderWidth: 1,
166
+ borderColor: '#ddd',
167
+ marginTop: 10,
168
+ },
169
+ input: {
170
+ marginLeft: 8,
171
+ flex: 1,
172
+ fontSize: 14,
173
+ },
174
+ categoryContainer: {
175
+ marginTop: 18,
176
+ paddingBottom: 6,
177
+ borderBottomWidth: 1,
178
+ borderColor: '#e4e4e4',
179
+ },
180
+ tabItem: {
181
+ marginRight: 24,
182
+ alignItems: 'center',
183
+ },
184
+ tabText: {
185
+ fontSize: 15,
186
+ color: '#666',
187
+ marginBottom: 6,
188
+ },
189
+ activeTabText: {
190
+ color: '#000',
191
+ fontWeight: '600',
192
+ },
193
+ activeLine: {
194
+ height: 3,
195
+ width: 25,
196
+ backgroundColor: '#fbbf24', // exact yellow underline
197
+ borderRadius: 2,
198
+ },
199
+ sectionHeader: {
200
+ marginTop: 20,
201
+ marginBottom: 10,
202
+ flexDirection: 'row',
203
+ justifyContent: 'space-between',
204
+ alignItems: 'center',
205
+ },
206
+ sectionTitle: {
207
+ fontSize: 18,
208
+ fontWeight: '600',
209
+ },
210
+ seeAll: {
211
+ color: '#ff9900',
212
+ fontWeight: '600',
213
+ },
214
+ card: {
215
+ width: width * 0.7,
216
+ marginRight: 16,
217
+ borderRadius: 14,
218
+ backgroundColor: '#fff',
219
+ overflow: 'hidden',
220
+ elevation: 2,
221
+ },
222
+ cardImage: {
223
+ width: '100%',
224
+ height: 160,
225
+ },
226
+ cardHeart: {
227
+ position: 'absolute',
228
+ top: 10,
229
+ right: 10,
230
+ backgroundColor: 'rgba(0,0,0,0.4)',
231
+ padding: 6,
232
+ borderRadius: 20,
233
+ },
234
+ tagRow: {
235
+ flexDirection: 'row',
236
+ marginTop: 6,
237
+ marginLeft: 8,
238
+ },
239
+ tag: {
240
+ backgroundColor: '#fff',
241
+ paddingHorizontal: 6,
242
+ paddingVertical: 2,
243
+ borderRadius: 6,
244
+ marginRight: 6,
245
+ borderWidth: 1,
246
+ borderColor: '#ddd',
247
+ },
248
+ tagText: {
249
+ fontSize: 10,
250
+ color: '#444',
251
+ },
252
+ cardFooter: {
253
+ padding: 10,
254
+ flexDirection: 'row',
255
+ justifyContent: 'space-between',
256
+ alignItems: 'center',
257
+ },
258
+ cardTitle: {
259
+ width: '60%',
260
+ fontSize: 14,
261
+ fontWeight: '600',
262
+ },
263
+ shareText: {
264
+ color: '#ff9900',
265
+ fontWeight: '600',
266
+ marginRight: 4,
267
+ },
268
+ });