feat(app):copy to clipboard and ui and logic modifications

This commit is contained in:
Atanu Das 2026-08-03 17:42:19 +05:30
parent 1aed769b62
commit 48c2ac64c5
10 changed files with 115 additions and 85 deletions

View File

@ -3,6 +3,7 @@ import { View, Text, TouchableOpacity } from 'react-native';
import { HeaderProps } from './header.props';
import { getStyles } from './header.styles';
import { useAppTheme } from '@theme';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
export const Header: React.FC<HeaderProps> = ({ title, onBack, rightComponent }) => {
const { colors } = useAppTheme();
@ -13,7 +14,7 @@ export const Header: React.FC<HeaderProps> = ({ title, onBack, rightComponent })
<View style={styles.backButton}>
{onBack && (
<TouchableOpacity onPress={onBack} activeOpacity={0.7}>
<Text style={styles.backText}>{'<'}</Text>
<MaterialIcons name="arrow-back" size={24} color="black" />
</TouchableOpacity>
)}
</View>

View File

@ -3,6 +3,7 @@ import { View, TextInput, Text } from 'react-native';
import { SearchBarProps } from './searchBar.props';
import { getStyles } from './searchBar.styles';
import { useAppTheme } from '@theme';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
export const SearchBar: React.FC<SearchBarProps> = ({
value,
@ -16,7 +17,11 @@ export const SearchBar: React.FC<SearchBarProps> = ({
return (
<View style={styles.container}>
<Text style={styles.icon}>🔍</Text>
<MaterialCommunityIcons
name="magnify"
size={24}
color={colors.primary}
/>
<TextInput
style={styles.input}
value={value}

View File

@ -14,6 +14,7 @@ import { AppStackParamList } from '../../../navigation/appStack';
import { MainTabParamList } from '../../../navigation/mainTabNavigator';
import { logoutUser, useAppDispatch, useAppSelector } from '@store';
import { getWalletBalanceThunk } from './thunk';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
type AccountNavProp = CompositeNavigationProp<
BottomTabNavigationProp<MainTabParamList, 'AccountScreen'>,
@ -37,21 +38,15 @@ const MENU_SECTIONS: MenuSectionData[] = [
{
title: 'Account',
items: [
// {
// icon: '📍',
// label: 'My Addresses',
// subLabel: 'Manage delivery addresses',
// tint: '#FDECEA',
// },
{
icon: '💳',
icon: 'wallet-outline',
label: 'Wallet',
subLabel: 'Cards, UPI & wallets',
tint: '#FFF4E5',
onPress: navigation => navigation.navigate('WalletScreen'),
},
{
icon: '🔔',
icon: 'bell-outline',
label: 'Notifications',
subLabel: 'Alerts, offers & updates',
tint: '#FFF9DB',
@ -62,20 +57,20 @@ const MENU_SECTIONS: MenuSectionData[] = [
title: 'Support & Legal',
items: [
{
icon: '',
icon: 'help-circle-outline',
label: 'Help & Support',
subLabel: 'FAQs and contact us',
tint: '#EAF4FF',
onPress: navigation => navigation.navigate('HelpSupportScreen'),
},
{
icon: '📋',
icon: 'file-document-outline',
label: 'Terms & Conditions',
subLabel: 'Our terms of service',
tint: '#F1F0FF',
},
{
icon: '🔒',
icon: 'shield-lock-outline',
label: 'Privacy Policy',
subLabel: 'How we handle your data',
tint: '#E9F7EF',
@ -130,7 +125,11 @@ export const AccountScreen: React.FC = () => {
<Text style={styles.profileName}>{user?.name || 'User'}</Text>
<View style={styles.profilePhoneRow}>
<Text style={styles.profilePhoneIcon}>📞</Text>
<MaterialCommunityIcons
name="phone-outline"
size={20}
color={colors.primary}
/>
<Text style={styles.profilePhone}>
{user?.phone || '+91 98765 43210'}
</Text>
@ -182,7 +181,11 @@ export const AccountScreen: React.FC = () => {
{ backgroundColor: item.tint },
]}
>
<Text style={styles.menuIcon}>{item.icon}</Text>
<MaterialCommunityIcons
name={item.icon}
size={24}
color={colors.primary}
/>
</View>
<View style={styles.menuTextWrap}>
<Text style={styles.menuLabel}>{item.label}</Text>

View File

@ -43,4 +43,9 @@ export const getStyles = (colors: any) => StyleSheet.create({
fontSize: typography.fontSize.md,
color: colors.textSecondary,
},
loaderContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});

View File

@ -1,8 +1,9 @@
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
import React, { useCallback, useEffect, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity, ActivityIndicator } from 'react-native';
import {
useNavigation,
CompositeNavigationProp,
useFocusEffect,
} from '@react-navigation/native';
import { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
import { StackNavigationProp } from '@react-navigation/stack';
@ -54,14 +55,14 @@ export const MyOrdersScreen: React.FC = () => {
const navigation = useNavigation<MyOrdersNavProp>();
const [activeTab, setActiveTab] = useState('All');
const dispatch = useAppDispatch();
const { orderHistory } = useAppSelector(
const { orderHistory, isLoading } = useAppSelector(
(state: RootState) => state.paymentMethods,
);
// console.log(orderHistory);
useEffect(() => {
useFocusEffect(useCallback(() => {
dispatch(getOrderHistoryThunk());
}, []);
}, []));
const ONGOING_STATUSES = [
'PENDING',
@ -103,54 +104,59 @@ export const MyOrdersScreen: React.FC = () => {
</TouchableOpacity>
))}
</View>
<FlatList
data={filteredOrders}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<OrderHistoryCard
providerName={item?.merchant?.name || ''}
providerImage={item?.merchant?.imageUrl || ''}
orderDate={formatDate(item?.createdAt)}
status={item.status}
total={Number(item?.totalAmount) || 0}
items={item.orderItems}
onTrack={() => {
if (item?.status === 'OUT_FOR_DELIVERY') {
// navigation.navigate('ProviderDetailsScreen', {
// providerName: item?.merchant?.name || '',
// });
// } else {
navigation.navigate('LiveTrackingScreen', {
orderId: item?.id || '',
{isLoading ? (
<View style={styles.loaderContainer}>
<ActivityIndicator size="large" color={colors.primary} />
</View>
) : (
<FlatList
data={filteredOrders}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<OrderHistoryCard
providerName={item?.merchant?.name || ''}
providerImage={item?.merchant?.imageUrl || ''}
orderDate={formatDate(item?.createdAt)}
status={item.status}
total={Number(item?.totalAmount) || 0}
items={item.orderItems}
onTrack={() => {
if (item?.status === 'OUT_FOR_DELIVERY') {
// navigation.navigate('ProviderDetailsScreen', {
// providerName: item?.merchant?.name || '',
// });
// } else {
navigation.navigate('LiveTrackingScreen', {
orderId: item?.id || '',
});
}
}}
onDetails={() => {
// if (
// item?.status === 'PENDING' ||
// item?.status === 'CONFIRMED' ||
// item?.status === 'PREPARING' ||
// item?.status === 'READY_FOR_PICKUP' ||
// item?.status === 'OUT_FOR_DELIVERY'
// ) {
navigation.navigate('OrderDetailsScreen', {
orderId: item.id,
});
}
}}
onDetails={() => {
// if (
// item?.status === 'PENDING' ||
// item?.status === 'CONFIRMED' ||
// item?.status === 'PREPARING' ||
// item?.status === 'READY_FOR_PICKUP' ||
// item?.status === 'OUT_FOR_DELIVERY'
// ) {
navigation.navigate('OrderDetailsScreen', {
orderId: item.id,
});
// } else {
// navigation.navigate('OrderDeliveredScreen', {
// orderId: item.id,
// });
// }
}}
/>
)}
contentContainerStyle={styles.list}
ListEmptyComponent={
<View style={styles.empty}>
<Text style={styles.emptyText}>No orders found</Text>
</View>
}
/>
// } else {
// navigation.navigate('OrderDeliveredScreen', {
// orderId: item.id,
// });
// }
}}
/>
)}
contentContainerStyle={styles.list}
ListEmptyComponent={
<View style={styles.empty}>
<Text style={styles.emptyText}>No orders found</Text>
</View>
}
/>)}
</View>
);
};

View File

@ -14,6 +14,7 @@ import { Header } from '@components';
import { useAppTheme } from '@theme';
import { useAppDispatch, useAppSelector, getAllOffersThunk } from '@store';
import { Promotion, PromotionType } from '@interfaces';
import Clipboard from '@react-native-clipboard/clipboard';
const getPromoVisuals = (type: PromotionType) => {
switch (type) {
@ -69,16 +70,18 @@ export const OffersScreen: React.FC = () => {
}, [dispatch]),
);
// const handleCopy = (item: Promotion) => {
// setCopiedId(item.id);
// const textToCopy = item.badgeText || item.title;
// if (Platform.OS === 'android') {
// ToastAndroid.show(`Copied "${textToCopy}"`, ToastAndroid.SHORT);
// }
// setTimeout(() => {
// setCopiedId(prev => (prev === item.id ? null : prev));
// }, 2000);
// };
const handleCopy = (item: Promotion) => {
Clipboard.setString(item.badgeText);
setCopiedId(item.id);
// const textToCopy = item.badgeText || item.title;
// if (Platform.OS === 'android') {
// ToastAndroid.show(`Copied "${textToCopy}"`, ToastAndroid.SHORT);
// }
setTimeout(() => {
setCopiedId(prev => (prev === item.id ? null : prev));
}, 2000);
};
const renderOfferCard = ({ item }: { item: Promotion }) => {
const visuals = getPromoVisuals(item.promotionType);
@ -119,8 +122,8 @@ export const OffersScreen: React.FC = () => {
<TouchableOpacity
style={[styles.copyButton, isCopied && styles.copyButtonSuccess]}
// onPress={() => handleCopy(item)}
onPress={() => { }}
onPress={() => handleCopy(item)}
// onPress={() => { }}
activeOpacity={0.8}
>
<Text style={styles.copyButtonText}>

View File

@ -22,6 +22,7 @@ import { useAppDispatch, useAppSelector } from '@store';
import { getProductDetailsThunk } from './thunk';
import { getDiscountPercentage, formatPrice } from '@components';
import { getFullUrl } from '@utils';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
type ProviderDetailsNavProp = StackNavigationProp<
AppStackParamList,
@ -101,8 +102,7 @@ export const ProviderDetailsScreen: React.FC = () => {
const handleIncrement = () => {
if (!product) return;
const newQty = localQty + 1;
setLocalQty(newQty);
dispatch(updateCartItemThunk({ productId: product.id, quantity: newQty }));
dispatch(updateCartItemThunk({ productId: product.id, quantity: newQty })).unwrap().then(() => setLocalQty(newQty));
};
const handleDecrement = () => {
@ -375,7 +375,7 @@ export const ProviderDetailsScreen: React.FC = () => {
activeOpacity={0.8}
onPress={() => navigation.goBack()}
>
<Text style={styles.iconButtonText}></Text>
<MaterialIcons name="arrow-back" size={24} color="black" />
</TouchableOpacity>
<View style={styles.iconButtonGroup}>
<TouchableOpacity
@ -480,7 +480,7 @@ export const ProviderDetailsScreen: React.FC = () => {
<Text style={styles.qtyValue}>{localQty}</Text>
<TouchableOpacity
style={styles.qtyBtn}
onPress={() => setLocalQty(q => q + 1)}
onPress={handleAddToCart}
activeOpacity={0.7}
>
<Text style={styles.qtyBtnText}>+</Text>

View File

@ -23,6 +23,7 @@ import { MainTabParamList } from '../../../navigation/mainTabNavigator';
import { useAppDispatch, useAppSelector } from '@store';
import { getProductsByCategoryThunk } from './thunk';
import { Products } from '@interfaces';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
// ─── Types ───────────────────────────────────────────────────────────────────
@ -114,7 +115,7 @@ export const SearchScreen: React.FC = () => {
searchQuery.trim().length === 0
? true
: p.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
(p.brand ?? '').toLowerCase().includes(searchQuery.toLowerCase()),
(p.brand ?? '').toLowerCase().includes(searchQuery.toLowerCase()),
);
// Category chips: prepend "All"
@ -207,7 +208,7 @@ export const SearchScreen: React.FC = () => {
activeOpacity={0.7}
onPress={() => navigation.goBack()}
>
<Text style={styles.backBtnText}></Text>
<MaterialIcons name="arrow-back" size={24} color="black" />
</TouchableOpacity>
<Text style={styles.headerTitle} numberOfLines={1}>
{headerCategoryName}

View File

@ -11,6 +11,7 @@
},
"dependencies": {
"@react-native-async-storage/async-storage": "^3.1.1",
"@react-native-clipboard/clipboard": "^1.16.3",
"@react-native-community/checkbox": "^0.5.20",
"@react-native/new-app-screen": "0.86.0",
"@react-navigation/bottom-tabs": "^7.18.3",

View File

@ -1386,6 +1386,11 @@
dependencies:
idb "8.0.3"
"@react-native-clipboard/clipboard@^1.16.3":
version "1.16.3"
resolved "https://registry.yarnpkg.com/@react-native-clipboard/clipboard/-/clipboard-1.16.3.tgz#7807a90fd9984bf4d3a96faf2eee20457984a9bd"
integrity sha512-cMIcvoZKIrShzJHEaHbTAp458R9WOv0fB6UyC7Ek4Qk561Ow/DrzmmJmH/rAZg21Z6ixJ4YSdFDC14crqIBmCQ==
"@react-native-community/checkbox@^0.5.20":
version "0.5.20"
resolved "https://registry.yarnpkg.com/@react-native-community/checkbox/-/checkbox-0.5.20.tgz#7b8004a80a90988d5dff208693524f069270b849"