screen bug fix

This commit is contained in:
Samandar Turgunboyev
2025-12-10 11:02:58 +05:00
parent 87bd8cdea6
commit c426b729b9
24 changed files with 663 additions and 403 deletions

41
App.tsx
View File

@@ -7,14 +7,7 @@ import { navigationRef } from 'components/NavigationRef';
import i18n from 'i18n/i18n'; import i18n from 'i18n/i18n';
import React, { useEffect, useMemo, useRef, useState } from 'react'; import React, { useEffect, useMemo, useRef, useState } from 'react';
import { I18nextProvider } from 'react-i18next'; import { I18nextProvider } from 'react-i18next';
import { import { Animated, Dimensions, LogBox, StatusBar, View } from 'react-native';
Animated,
Dimensions,
LogBox,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import Toast from 'react-native-toast-message'; import Toast from 'react-native-toast-message';
import SplashScreen from './src/components/SplashScreen'; import SplashScreen from './src/components/SplashScreen';
@@ -68,6 +61,7 @@ export default function App() {
const [isSplashVisible, setIsSplashVisible] = useState(true); const [isSplashVisible, setIsSplashVisible] = useState(true);
const isMounted = useRef(false); const isMounted = useRef(false);
const currentAnimation = useRef<Animated.CompositeAnimation | null>(null); const currentAnimation = useRef<Animated.CompositeAnimation | null>(null);
const token = getToken();
useEffect(() => { useEffect(() => {
loadInitialAuthData(); loadInitialAuthData();
@@ -165,8 +159,19 @@ export default function App() {
[], [],
); );
if (initialRoute === null) { if (!initialRoute || isSplashVisible || !currentAnimation) {
return <View style={{ flex: 1, backgroundColor: '#000' }} />; return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ffff',
}}
>
<SplashScreen onFinish={handleSplashFinish} />
</View>
);
} }
return ( return (
@@ -178,10 +183,9 @@ export default function App() {
<Stack.Navigator <Stack.Navigator
screenOptions={{ screenOptions={{
headerShown: false, headerShown: false,
animation: 'none', animation: 'slide_from_right',
gestureEnabled: false, gestureEnabled: false,
}} }}
// initialRouteName set once (we ensure it's available before first render)
initialRouteName={initialRoute} initialRouteName={initialRoute}
> >
<Stack.Screen name="Onboarding"> <Stack.Screen name="Onboarding">
@@ -225,19 +229,6 @@ export default function App() {
</Stack.Navigator> </Stack.Navigator>
</NavigationContainer> </NavigationContainer>
{/* Splash transition */}
{isSplashVisible && (
<Animated.View
style={{
...StyleSheet.absoluteFillObject,
transform: [{ translateX: slideAnim }],
zIndex: 10,
}}
>
<SplashScreen onFinish={handleSplashFinish} />
</Animated.View>
)}
<Toast config={toastConfig} /> <Toast config={toastConfig} />
</View> </View>
</I18nextProvider> </I18nextProvider>

File diff suppressed because one or more lines are too long

View File

@@ -15,7 +15,7 @@ class MainActivity : ReactActivity() {
override fun getMainComponentName(): String = "first" override fun getMainComponentName(): String = "first"
override fun onCreate(savedInstanceState: android.os.Bundle?) { override fun onCreate(savedInstanceState: android.os.Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(null)
} }
/** /**

View File

@@ -9,6 +9,7 @@ import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.react.defaults.DefaultReactNativeHost
import com.swmansion.rnscreens.RNScreensPackage
class MainApplication : Application(), ReactApplication { class MainApplication : Application(), ReactApplication {

View File

@@ -4,9 +4,15 @@
// import notifee, { AndroidImportance } from '@notifee/react-native'; // import notifee, { AndroidImportance } from '@notifee/react-native';
// import messaging from '@react-native-firebase/messaging'; // import messaging from '@react-native-firebase/messaging';
import { AppRegistry } from 'react-native'; import { AppRegistry } from 'react-native';
import { enableScreens } from 'react-native-screens';
import App from './App'; import App from './App';
import { name as appName } from './app.json'; import { name as appName } from './app.json';
enableScreens({
freezeOnBlur: true, // background screen componenti freeze bo'ladi
});
// messaging().setBackgroundMessageHandler(async remoteMessage => { // messaging().setBackgroundMessageHandler(async remoteMessage => {
// console.log('Background message:', remoteMessage); // console.log('Background message:', remoteMessage);

8
package-lock.json generated
View File

@@ -27,7 +27,7 @@
"react-native-app-link": "^1.0.1", "react-native-app-link": "^1.0.1",
"react-native-asset": "^2.1.1", "react-native-asset": "^2.1.1",
"react-native-biometrics": "^3.0.1", "react-native-biometrics": "^3.0.1",
"react-native-config": "^1.5.6", "react-native-config": "^1.5.0",
"react-native-confirmation-code-field": "^8.0.1", "react-native-confirmation-code-field": "^8.0.1",
"react-native-device-info": "^14.0.4", "react-native-device-info": "^14.0.4",
"react-native-dotenv": "^3.4.11", "react-native-dotenv": "^3.4.11",
@@ -13011,9 +13011,9 @@
} }
}, },
"node_modules/react-native-config": { "node_modules/react-native-config": {
"version": "1.5.6", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/react-native-config/-/react-native-config-1.5.6.tgz", "resolved": "https://registry.npmjs.org/react-native-config/-/react-native-config-1.5.0.tgz",
"integrity": "sha512-UB3LEco0FGGbbGvS+DfH2VmGKiP/y5C2MkmfBmfsIaxHSbM1KOTMKYG7YRf6xFhZbJ/01BedHG7SIny5i7N9BQ==", "integrity": "sha512-slecooA/0tCwhb+RuWEbwLqtKirGh9vWPRpgDfH7uPAraCciqHNH2XjS9ylW+Spn4FUrHg5KWTqUGs9BdBADHg==",
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"react-native-windows": ">=0.61" "react-native-windows": ">=0.61"

View File

@@ -32,7 +32,7 @@
"react-native-app-link": "^1.0.1", "react-native-app-link": "^1.0.1",
"react-native-asset": "^2.1.1", "react-native-asset": "^2.1.1",
"react-native-biometrics": "^3.0.1", "react-native-biometrics": "^3.0.1",
"react-native-config": "^1.5.6", "react-native-config": "^1.5.0",
"react-native-confirmation-code-field": "^8.0.1", "react-native-confirmation-code-field": "^8.0.1",
"react-native-device-info": "^14.0.4", "react-native-device-info": "^14.0.4",
"react-native-dotenv": "^3.4.11", "react-native-dotenv": "^3.4.11",

View File

@@ -1,23 +1,29 @@
// helpers/event.ts // helpers/event.ts
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { createMMKV } from 'react-native-mmkv'; import { createMMKV } from 'react-native-mmkv';
export const authEvents = new EventEmitter(); export const authEvents = new EventEmitter();
export const enum AUTH {
USER = 'user',
AUTH = 'auth',
}
// MMKV instance // MMKV instance
export const storage = createMMKV(); export const storage = createMMKV();
// Memory cachez // Memory cache
let tokenCache: string | null = null; let tokenCache: string | null = null;
let languageCache: string | null = null; let languageCache: string | null = null;
// Load on app start // Load on app start (synchronous)
export function loadInitialAuthData() { export function loadInitialAuthData() {
tokenCache = storage.getString('token') || null; tokenCache = storage.getString('token') || null;
languageCache = storage.getString('language') || null; languageCache = storage.getString('language') || null;
} }
export function getToken() { export function getToken() {
return tokenCache; return storage.getString('token');
} }
export function setToken(token: string | null) { export function setToken(token: string | null) {
@@ -29,6 +35,18 @@ export function setToken(token: string | null) {
} }
} }
export function saveAuth() {
storage.set('user', AUTH.USER);
}
export function removeAuth() {
storage.set('user', AUTH.AUTH);
}
export function getAuth() {
storage.getString('user');
}
export function getLanguage() { export function getLanguage() {
return languageCache; return languageCache;
} }

View File

@@ -0,0 +1,8 @@
export const formatPrice = (amount: number | string) => {
const numericAmount = Number(amount) || 0;
const formatted = numericAmount
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
return formatted;
};

View File

@@ -246,7 +246,10 @@
"Email": "Электронная почта", "Email": "Электронная почта",
"Telegram": "Телеграм", "Telegram": "Телеграм",
"Roziman": "Согласен", "Roziman": "Согласен",
"To'lov kutilmoqda": "Ожидание оплаты",
"Reys": "Рейс",
"To'lov holati": "Статус оплаты", "To'lov holati": "Статус оплаты",
"Bekor qilingan": "Отменено", "Bekor qilingan": "Отменено",
"Mahsulot nomi": "Название товара",
"Ma'lumotlarni to'liq kiriting": "Введите полные данные" "Ma'lumotlarni to'liq kiriting": "Введите полные данные"
} }

View File

@@ -26,6 +26,8 @@
"Familiya": "Familiya", "Familiya": "Familiya",
"Familiyangiz": "Familiyangiz", "Familiyangiz": "Familiyangiz",
"Bizni qaerdan topdingiz?": "Bizni qaerdan topdingiz?", "Bizni qaerdan topdingiz?": "Bizni qaerdan topdingiz?",
"Reys": "Reys",
"narxi": "narxi",
"Bizni kim tavsiya qildi...": "Bizni kim tavsiya qildi...", "Bizni kim tavsiya qildi...": "Bizni kim tavsiya qildi...",
"Foydalanish shartlari": "Foydalanish shartlari", "Foydalanish shartlari": "Foydalanish shartlari",
"bilan tanishib chiqdim!": "bilan tanishib chiqdim!", "bilan tanishib chiqdim!": "bilan tanishib chiqdim!",
@@ -156,6 +158,7 @@
"Mahsulotlar ogirligi": "Mahsulotlar ogirligi", "Mahsulotlar ogirligi": "Mahsulotlar ogirligi",
"Faol": "Faol", "Faol": "Faol",
"Kutilmoqda": "Kutilmoqda", "Kutilmoqda": "Kutilmoqda",
"To'lov kutilmoqda": "To'lov kutilmoqda",
"Faol emas": "Faol emas", "Faol emas": "Faol emas",
"Xatolik yuz berdi!": "Xatolik yuz berdi!", "Xatolik yuz berdi!": "Xatolik yuz berdi!",
"Akkaunt faol emas!": "Akkaunt faol emas!", "Akkaunt faol emas!": "Akkaunt faol emas!",
@@ -177,6 +180,7 @@
"som": "so'm", "som": "so'm",
"Umumiy narx": "Umumiy narx", "Umumiy narx": "Umumiy narx",
"Yopish": "Yopish", "Yopish": "Yopish",
"Mahsulot nomi": "Mahsulot nomi",
"Passportlarim": "Passportlarim", "Passportlarim": "Passportlarim",
"Hali pasport qo'shilmagan": "Hali pasport qo'shilmagan", "Hali pasport qo'shilmagan": "Hali pasport qo'shilmagan",
"Yangi pasport qo'shish uchun tugmani bosing": "Yangi passport qo'shish uchun tugmani bosing", "Yangi pasport qo'shish uchun tugmani bosing": "Yangi passport qo'shish uchun tugmani bosing",

View File

@@ -5,7 +5,7 @@ import { authApi } from 'api/auth';
import { otpPayload, resendPayload } from 'api/auth/type'; import { otpPayload, resendPayload } from 'api/auth/type';
import AppText from 'components/AppText'; import AppText from 'components/AppText';
import ErrorNotification from 'components/ErrorNotification'; import ErrorNotification from 'components/ErrorNotification';
import { setToken } from 'helpers/event'; import { saveAuth, setToken } from 'helpers/event';
import formatPhone from 'helpers/formatPhone'; import formatPhone from 'helpers/formatPhone';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@@ -78,7 +78,11 @@ const Confirm = () => {
mutationFn: (payload: otpPayload) => authApi.verifyOtp(payload), mutationFn: (payload: otpPayload) => authApi.verifyOtp(payload),
onSuccess: async res => { onSuccess: async res => {
setToken(res.data.accessToken); setToken(res.data.accessToken);
navigation.navigate('Home'); saveAuth();
navigation.reset({
index: 0,
routes: [{ name: 'Home' }], // login sahifasiga qaytarish
});
setVisible(false); setVisible(false);
}, },
onError: (err: any) => { onError: (err: any) => {

View File

@@ -84,7 +84,10 @@ const Confirm = ({
mutationFn: (payload: otpPayload) => authApi.verifyOtp(payload), mutationFn: (payload: otpPayload) => authApi.verifyOtp(payload),
onSuccess: async res => { onSuccess: async res => {
setToken(res.data.accessToken); setToken(res.data.accessToken);
navigation.navigate('Confirm'); navigation.reset({
index: 0,
routes: [{ name: 'Home' }], // login sahifasiga qaytarish
});
setErrorConfirm(null); setErrorConfirm(null);
}, },
onError: (err: any) => { onError: (err: any) => {

View File

@@ -13,6 +13,7 @@ import AppText from 'components/AppText';
import DatePickerInput from 'components/DatePicker'; import DatePickerInput from 'components/DatePicker';
import ErrorNotification from 'components/ErrorNotification'; import ErrorNotification from 'components/ErrorNotification';
import SingleFileDrop from 'components/FileDrop'; import SingleFileDrop from 'components/FileDrop';
import { saveAuth } from 'helpers/event';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@@ -79,11 +80,10 @@ const SecondStep = () => {
mutationFn: (payload: sendPassportPayload) => mutationFn: (payload: sendPassportPayload) =>
passportApi.sendPassport(payload), passportApi.sendPassport(payload),
onSuccess: res => { onSuccess: res => {
navigation.navigate('Home'); navigation.replace('Home');
saveAuth();
}, },
onError: (err: any) => { onError: (err: any) => {
console.dir(err);
setError(err?.response?.data || 'Xatolik yuz berdi'); setError(err?.response?.data || 'Xatolik yuz berdi');
setVisible(true); setVisible(true);
}, },

View File

@@ -1,7 +1,7 @@
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import AppText from 'components/AppText'; import AppText from 'components/AppText';
import { setToken } from 'helpers/event'; import { removeAuth, setToken } from 'helpers/event';
import * as React from 'react'; import * as React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
@@ -36,7 +36,8 @@ const ProfilePages = (props: componentNameProps) => {
style: 'destructive', style: 'destructive',
onPress: async () => { onPress: async () => {
try { try {
setToken(null); setToken('');
removeAuth();
navigation.reset({ navigation.reset({
index: 0, index: 0,
routes: [{ name: 'Login' }], // login sahifasiga qaytarish routes: [{ name: 'Login' }], // login sahifasiga qaytarish

View File

@@ -1,15 +1,15 @@
import { PacketsData } from 'api/packets'; import { PacketsData } from 'api/packets';
import AppText from 'components/AppText'; import AppText from 'components/AppText';
import { formatPrice } from 'helpers/formatPrice';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FlatList, StyleSheet, TouchableOpacity, View } from 'react-native'; import { FlatList, StyleSheet, TouchableOpacity, View } from 'react-native';
import Auto from 'svg/Auto';
import Avia from 'svg/Avia'; import Avia from 'svg/Avia';
import BagIcon from 'svg/BagIcon'; import BagIcon from 'svg/BagIcon';
import BoxIcon from 'svg/Box'; import BoxIcon from 'svg/Box';
import Store from 'svg/Store'; import Store from 'svg/Store';
import SuccessIcon from 'svg/SuccessIcon';
import TrunkIcon from 'svg/TrunkIcon'; import TrunkIcon from 'svg/TrunkIcon';
import Wallet from 'svg/Wallet';
import { DataInfo } from '../lib/data'; import { DataInfo } from '../lib/data';
const statusColorMap: Record<string, string> = { const statusColorMap: Record<string, string> = {
@@ -30,13 +30,14 @@ const statuses = [
'DELIVERED', 'DELIVERED',
'PAID', 'PAID',
] as const; ] as const;
type FilterType = (typeof statuses)[number]; type FilterType = (typeof statuses)[number];
const tabList: { label: string; value: FilterType }[] = [ const tabList: { label: string; value: FilterType }[] = [
{ label: "Yig'ilmoqda", value: 'COLLECTING' }, { label: "Yig'ilmoqda", value: 'COLLECTING' },
{ label: "Yo'lda", value: 'ON_THE_WAY' }, { label: "Yo'lda", value: 'ON_THE_WAY' },
{ label: 'Bojxonada', value: 'IN_CUSTOMS' }, { label: 'Bojxonada', value: 'IN_CUSTOMS' },
{ label: 'Toshkent omboriga yetib keldi', value: 'IN_WAREHOUSE' }, { label: 'Omborga yetib keldi', value: 'IN_WAREHOUSE' },
{ label: 'Topshirish punktida', value: 'DELIVERED' }, { label: 'Topshirish punktida', value: 'DELIVERED' },
{ label: 'Qabul qilingan', value: 'PAID' }, { label: 'Qabul qilingan', value: 'PAID' },
]; ];
@@ -51,20 +52,18 @@ const Order = ({ data, openModal, selectedData }: Props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const styles = useMemo(() => makeStyles(), []); const styles = useMemo(() => makeStyles(), []);
const createIcons = useCallback( /** 🔥 SUCCESS ICON faqat paymentStatus ga qarab ozgaradi */
(cargo: string) => [ const createIcons = useCallback((cargo: string, paymentStatus?: string) => {
const isPaid = paymentStatus === 'PAYED';
return [
{ {
status: 'COLLECTING', status: 'COLLECTING',
icon: <BoxIcon width={24} height={24} color="" />, icon: <BoxIcon width={24} height={24} color="" />,
}, },
{ {
status: 'ON_THE_WAY', status: 'ON_THE_WAY',
icon: icon: <Avia width={24} height={24} color="" />,
cargo === 'avia' ? (
<Avia width={24} height={24} color="" />
) : (
<Auto width={24} height={24} color="" view="-4" />
),
}, },
{ {
status: 'IN_CUSTOMS', status: 'IN_CUSTOMS',
@@ -79,29 +78,33 @@ const Order = ({ data, openModal, selectedData }: Props) => {
icon: <TrunkIcon width={24} height={24} color="" />, icon: <TrunkIcon width={24} height={24} color="" />,
}, },
{ {
status: 'PAID', status: 'PENDING',
icon: <SuccessIcon width={24} height={24} color="" />, icon: (
<Wallet
width={24}
height={24}
color={isPaid ? '#28A7E8' : '#C0C0C0'}
/>
),
}, },
], ];
[], }, []);
);
const handleItemPress = useCallback( const handleItemPress = useCallback(
(item: DataInfo) => { (item: DataInfo) => openModal(item),
openModal(item);
},
[openModal], [openModal],
); );
const renderOrderItem = useCallback( const renderOrderItem = useCallback(
({ item, index }: { item: DataInfo; index: number }) => { ({ item }: { item: DataInfo }) => {
const currentStatusIndex = statuses.indexOf( const currentStatusIndex = statuses.indexOf(
item.deliveryStatus as FilterType, item.deliveryStatus as FilterType,
); );
const icons = createIcons(item.deliveryStatus);
const icons = createIcons(item.deliveryStatus, item.paymentStatus);
return ( return (
<TouchableOpacity key={index} onPress={() => handleItemPress(item)}> <TouchableOpacity onPress={() => handleItemPress(item)}>
<View style={styles.card}> <View style={styles.card}>
<FlatList <FlatList
data={icons} data={icons}
@@ -109,14 +112,42 @@ const Order = ({ data, openModal, selectedData }: Props) => {
numColumns={6} numColumns={6}
contentContainerStyle={styles.statusCard} contentContainerStyle={styles.statusCard}
renderItem={({ item: iconItem, index: i }) => { renderItem={({ item: iconItem, index: i }) => {
const iconColor = i <= currentStatusIndex ? '#28A7E8' : '#000'; let iconColor = '#000';
const viewColor = let bgColor = '#0000001A';
i <= currentStatusIndex ? '#28A7E81A' : '#0000001A';
if (
iconItem.status === 'DELIVERED' &&
item.deliveryStatus === 'DELIVERED'
) {
iconColor = '#28A7E8';
bgColor = '#28A7E81A';
} else if (iconItem.status === 'PENDING') {
if (item.paymentStatus === 'PAYED') {
iconColor = '#28A7E8'; // blue
bgColor = '#28A7E81A';
} else if (item.paymentStatus === 'PENDING') {
iconColor = '#FFA500'; // orange
bgColor = '#FFA5001A';
} else {
iconColor = '#C0C0C0'; // gray
bgColor = '#C0C0C01A';
}
} else if (i <= currentStatusIndex) {
iconColor = '#28A7E8'; // blue
bgColor = '#28A7E81A';
}
return ( return (
<View style={styles.iconWrapper}> <View style={styles.iconWrapper}>
<View <View
style={[styles.circle, { backgroundColor: viewColor }]} style={[
styles.circle,
{
backgroundColor: bgColor,
justifyContent: 'center',
alignItems: 'center',
},
]}
> >
{React.cloneElement(iconItem.icon, { color: iconColor })} {React.cloneElement(iconItem.icon, { color: iconColor })}
</View> </View>
@@ -133,29 +164,62 @@ const Order = ({ data, openModal, selectedData }: Props) => {
}} }}
/> />
{/* Status Label */}
<View <View
style={[ style={[
styles.statusLabelWrapper,
{ {
backgroundColor: `${statusColorMap[item.deliveryStatus]}1A`, flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
}, },
]} ]}
> >
<AppText <AppText
style={[ style={[
styles.statusText, styles.statusText,
{ color: statusColorMap[item.deliveryStatus] }, styles.statusLabelWrapper,
{
color: statusColorMap[item.deliveryStatus],
backgroundColor: `${statusColorMap[item.deliveryStatus]}1A`,
},
]} ]}
> >
{t( {t(
tabList.find(tab => tab.value === item.deliveryStatus) tabList.find(el => el.value === item.deliveryStatus)?.label ||
?.label || '', '',
)} )}
</AppText> </AppText>
<AppText
style={[
styles.statusText,
styles.statusLabelWrapper,
{
color:
item.paymentStatus === 'NEW'
? '#D32F2F'
: item.paymentStatus === 'PENDING'
? '#FFA500'
: item.paymentStatus === 'PAYED'
? '#32CD32'
: '#D32F2F',
backgroundColor:
item.paymentStatus === 'NEW'
? '#D32F2F1A'
: item.paymentStatus === 'PENDING'
? '#FFA5001A'
: item.paymentStatus === 'PAYED'
? '#32CD321A'
: '#D32F2F',
},
]}
>
{item.paymentStatus === 'NEW'
? t("To'lanmagan")
: item.paymentStatus === 'PENDING'
? t("To'lov kutilmoqda")
: item.paymentStatus === 'PAYED' && t("To'langan")}
</AppText>
</View> </View>
{/* Info */}
<View style={styles.infoCard}> <View style={styles.infoCard}>
<AppText style={styles.infoTitle}>{t('Reys raqami')}</AppText> <AppText style={styles.infoTitle}>{t('Reys raqami')}</AppText>
<AppText <AppText
@@ -164,16 +228,70 @@ const Order = ({ data, openModal, selectedData }: Props) => {
{item.packetName} {item.packetName}
</AppText> </AppText>
</View> </View>
{item.items.map(e => (
<View
key={e.trekId}
style={{
...styles.infoCard,
flexDirection: 'column',
gap: 4,
marginTop: 4,
}}
>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
gap: 4,
}}
>
<AppText style={styles.infoTitle}>
{t('Mahsulot nomi')}
</AppText>
<AppText style={styles.infoText}>{e.name}</AppText>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
gap: 4,
}}
>
<AppText style={styles.infoTitle}>{t('Trek ID')}</AppText>
<AppText style={styles.infoText}>{e.trekId}</AppText>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
gap: 4,
}}
>
<AppText style={styles.infoTitle}>{t('Ogirligi')}</AppText>
<AppText style={styles.infoText}>{e.weight} kg</AppText>
</View>
</View>
))}
<View style={styles.infoCard}> <View style={styles.infoCard}>
<AppText style={styles.infoTitle}> <AppText style={styles.infoTitle}>
{t('Mahsulotlar ogirligi')} {t('Mahsulotlar ogirligi')}
</AppText> </AppText>
<AppText style={styles.infoText}>{item.weight}</AppText> <AppText style={styles.infoText}>{item.weight} kg</AppText>
</View>
<View style={styles.infoCard}>
<AppText style={styles.infoTitle}>{t('Umumiy narxi')}</AppText>
<AppText style={styles.infoText}>{item.totalPrice}</AppText>
</View> </View>
{(item.deliveryStatus === 'DELIVERED' ||
item.paymentStatus === 'PAID') && (
<View style={styles.infoCard}>
<AppText style={styles.infoTitle}>{t('Umumiy narxi')}</AppText>
<AppText style={styles.infoText}>
{formatPrice(item.totalPrice)} {t('som')}
</AppText>
</View>
)}
</View> </View>
</TouchableOpacity> </TouchableOpacity>
); );
@@ -207,49 +325,37 @@ const Order = ({ data, openModal, selectedData }: Props) => {
const makeStyles = () => const makeStyles = () =>
StyleSheet.create({ StyleSheet.create({
container: { container: { width: '95%', margin: 'auto', borderRadius: 10 },
width: '95%',
margin: 'auto',
borderRadius: 10,
},
count: { count: {
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between', justifyContent: 'space-between',
alignItems: 'center',
marginTop: 10, marginTop: 10,
}, },
title: { title: { fontSize: 16, fontWeight: '500', color: '#333' },
fontSize: 16,
fontWeight: '500',
color: '#333',
},
card: { card: {
backgroundColor: '#fff', backgroundColor: '#fff',
margin: 1,
marginTop: 8, marginTop: 8,
padding: 15, padding: 15,
borderRadius: 10, borderRadius: 10,
// iOS
shadowColor: '#000', shadowColor: '#000',
shadowOffset: { width: 0, height: 2 }, shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2, shadowOpacity: 0.2,
shadowRadius: 2, shadowRadius: 2,
// Android
elevation: 2, elevation: 2,
}, },
statusCard: { statusCard: { marginBottom: 10 },
marginBottom: 10,
},
circle: { circle: {
padding: 8, padding: 8,
borderRadius: 50, borderRadius: 50,
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
}, },
divider: { divider: { width: 20, borderBottomWidth: 2, borderStyle: 'dashed' },
width: 20, iconWrapper: {
borderBottomWidth: 2, flexDirection: 'row',
borderStyle: 'dashed', alignItems: 'center',
flex: 1,
marginBottom: 10,
}, },
statusLabelWrapper: { statusLabelWrapper: {
borderRadius: 8, borderRadius: 8,
@@ -258,31 +364,14 @@ const makeStyles = () =>
paddingHorizontal: 10, paddingHorizontal: 10,
marginBottom: 12, marginBottom: 12,
}, },
statusText: { statusText: { fontFamily: 'GolosText-Bold', fontSize: 16 },
fontFamily: 'GolosText-Bold',
fontSize: 16,
},
infoCard: { infoCard: {
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between', justifyContent: 'space-between',
marginBottom: 6, marginBottom: 6,
}, },
iconWrapper: { infoTitle: { fontSize: 16, color: '#979797', fontWeight: '500' },
flexDirection: 'row', infoText: { fontSize: 14, color: '#28A7E8', fontWeight: '500' },
alignItems: 'center',
flex: 1,
marginBottom: 10,
},
infoTitle: {
fontSize: 16,
color: '#979797',
fontWeight: '500',
},
infoText: {
fontSize: 14,
color: '#28A7E8',
fontWeight: '500',
},
}); });
export default Order; export default Order;

View File

@@ -1,4 +1,5 @@
import AppText from 'components/AppText'; import AppText from 'components/AppText';
import { formatPrice } from 'helpers/formatPrice';
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
@@ -22,14 +23,6 @@ const OrderDetailModal = ({ visible, setVisible, selectedOrder }: Props) => {
const translateY = useRef(new Animated.Value(50)).current; const translateY = useRef(new Animated.Value(50)).current;
const { t } = useTranslation(); const { t } = useTranslation();
const parsePrice = (priceStr: string) => {
return Number(priceStr.replace(/[^\d]/g, ''));
};
const parseWeight = (weightStr: string) => {
return Number(weightStr.replace(/[^\d.]/g, ''));
};
const closeModal = () => { const closeModal = () => {
Animated.timing(opacity, { Animated.timing(opacity, {
toValue: 0, toValue: 0,
@@ -82,10 +75,6 @@ const OrderDetailModal = ({ visible, setVisible, selectedOrder }: Props) => {
style={{ maxHeight: 250 }} style={{ maxHeight: 250 }}
> >
{selectedOrder.items.map((product, index) => { {selectedOrder.items.map((product, index) => {
const totalPrice = product.totalPrice;
const weight = product.weight;
const pricePerKg = Math.ceil(weight ? totalPrice / weight : 0);
return ( return (
<View key={product.trekId + index} style={styles.productItem}> <View key={product.trekId + index} style={styles.productItem}>
<View style={styles.row}> <View style={styles.row}>
@@ -100,13 +89,12 @@ const OrderDetailModal = ({ visible, setVisible, selectedOrder }: Props) => {
{t('Ogirligi')}: {product.weight} {t('Ogirligi')}: {product.weight}
</AppText> </AppText>
<AppText style={styles.detail}> <AppText style={styles.detail}>
{t('Narxi')}: 1kg * {pricePerKg.toLocaleString('uz-UZ')}{' '} {t('Narxi')}: {product.price}$
{t("so'm")}
</AppText> </AppText>
</View> </View>
<View style={styles.rowRight}> <View style={styles.rowRight}>
<AppText style={styles.total}> <AppText style={styles.total}>
{t('Umumiy narxi')}: {product.totalPrice} {t('som')} {t('Umumiy narxi')}: {product.totalPrice}$
</AppText> </AppText>
</View> </View>
</View> </View>
@@ -117,7 +105,7 @@ const OrderDetailModal = ({ visible, setVisible, selectedOrder }: Props) => {
<View style={styles.totalRow}> <View style={styles.totalRow}>
<AppText style={styles.totalLabel}>{t('Umumiy narx')}:</AppText> <AppText style={styles.totalLabel}>{t('Umumiy narx')}:</AppText>
<AppText style={styles.totalValue}> <AppText style={styles.totalValue}>
{selectedOrder.totalPrice} {formatPrice(selectedOrder.totalPrice)} {t('som')}
</AppText> </AppText>
</View> </View>

View File

@@ -18,8 +18,6 @@ import { DataInfo } from '../lib/data';
import Filter from './Filter'; import Filter from './Filter';
import Order from './Order'; import Order from './Order';
import OrderDetailModal from './OrderDetailModal'; import OrderDetailModal from './OrderDetailModal';
import PaymentFilter from './PaymentFilter';
import Tabs from './Tabs';
const Status = () => { const Status = () => {
const { width: screenWidth } = useWindowDimensions(); const { width: screenWidth } = useWindowDimensions();
@@ -47,14 +45,13 @@ const Status = () => {
isLoading, isLoading,
isFetching, isFetching,
} = useQuery({ } = useQuery({
queryKey: ['status', filter, transportTypes, page, paymentStatus], queryKey: ['status', transportTypes, page, paymentStatus],
queryFn: () => queryFn: () =>
packetsApi.getPacketsStatus(filter, { packetsApi.getPackets({
page, page,
size: 10, size: 10,
cargoType: transportTypes, cargoType: transportTypes,
sort: 'id', sort: 'id',
paymentStatus: paymentStatus,
direction: 'DESC', direction: 'DESC',
}), }),
}); });
@@ -146,7 +143,7 @@ const Status = () => {
if (statusData?.data.length === 0 || statusData === undefined) { if (statusData?.data.length === 0 || statusData === undefined) {
return ( return (
<Layout> <Layout>
<Tabs filter={filter} setFilter={setFilter} /> {/* <Tabs filter={filter} setFilter={setFilter} /> */}
<View style={styles.controls}> <View style={styles.controls}>
<View <View
style={{ style={{
@@ -163,10 +160,10 @@ const Status = () => {
data={statusData} data={statusData}
setSelectedData={setSelectedData} setSelectedData={setSelectedData}
/> />
<PaymentFilter {/* <PaymentFilter
paymentStatus={paymentStatus} paymentStatus={paymentStatus}
setPaymentStatus={setPaymentStatus} setPaymentStatus={setPaymentStatus}
/> /> */}
</View> </View>
</View> </View>
<NoResult message={t("Hech qanday ma'lumot topilmadi")} /> <NoResult message={t("Hech qanday ma'lumot topilmadi")} />
@@ -181,7 +178,7 @@ const Status = () => {
refreshControl={refreshControl} refreshControl={refreshControl}
removeClippedSubviews={true} removeClippedSubviews={true}
> >
<Tabs filter={filter} setFilter={setFilter} /> {/* <Tabs filter={filter} setFilter={setFilter} /> */}
<View style={styles.controls}> <View style={styles.controls}>
{/* <View style={styles.searchContainer}> {/* <View style={styles.searchContainer}>
<TextInput <TextInput
@@ -206,10 +203,10 @@ const Status = () => {
data={statusData!} data={statusData!}
setSelectedData={setSelectedData} setSelectedData={setSelectedData}
/> />
<PaymentFilter {/* <PaymentFilter
paymentStatus={paymentStatus} paymentStatus={paymentStatus}
setPaymentStatus={setPaymentStatus} setPaymentStatus={setPaymentStatus}
/> /> */}
</View> </View>
</View> </View>
<Order <Order

View File

@@ -4,7 +4,7 @@ import { PacketsData } from 'api/packets';
import AppText from 'components/AppText'; import AppText from 'components/AppText';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { TouchableOpacity, View } from 'react-native'; import { StyleSheet, TouchableOpacity, View } from 'react-native';
import { PaymentStyle } from './style'; import { PaymentStyle } from './style';
type WalletStackParamList = { type WalletStackParamList = {
@@ -22,6 +22,7 @@ interface Props {
const Payment = ({ packets }: Props) => { const Payment = ({ packets }: Props) => {
const navigation = useNavigation<LoginScreenNavigationProp>(); const navigation = useNavigation<LoginScreenNavigationProp>();
const { t } = useTranslation(); const { t } = useTranslation();
const styles = useMemo(() => makeStyles(), []);
const handlePaymentPress = useCallback( const handlePaymentPress = useCallback(
(item: any) => { (item: any) => {
@@ -52,10 +53,17 @@ const Payment = ({ packets }: Props) => {
const renderPaymentCard = useCallback( const renderPaymentCard = useCallback(
(item: any) => { (item: any) => {
const isPaid = const isPaid =
item.paymentStatus === 'PAYED' || item.paymentStatus === 'PENDING'; item.paymentStatus === 'PAYED' || item.paymentStatus === 'PAID';
const cardStyle = [ const cardStyle = [
PaymentStyle.card, PaymentStyle.card,
{ borderColor: isPaid ? '#4CAF50' : '#D32F2F', borderWidth: 1.5 }, {
borderColor: isPaid
? '#4CAF50'
: item.paymentStatus === 'PENDING'
? '#FFA500'
: '#D32F2F',
borderWidth: 1.5,
},
]; ];
return ( return (
@@ -70,6 +78,20 @@ const Payment = ({ packets }: Props) => {
<AppText style={PaymentStyle.title}>{item.packetName}</AppText> <AppText style={PaymentStyle.title}>{item.packetName}</AppText>
{isPaid ? ( {isPaid ? (
<AppText style={PaymentStyle.badge}>{t("To'langan")}</AppText> <AppText style={PaymentStyle.badge}>{t("To'langan")}</AppText>
) : item.paymentStatus === 'PENDING' ? (
<AppText
style={{
backgroundColor: '#FFA500',
color: '#fff',
fontSize: 12,
paddingHorizontal: 8,
paddingVertical: 2,
borderRadius: 5,
overflow: 'hidden',
}}
>
{t('Kutilmoqda')}
</AppText>
) : ( ) : (
<AppText style={badgeStyle}>{t("To'lanmagan")}</AppText> <AppText style={badgeStyle}>{t("To'lanmagan")}</AppText>
)} )}
@@ -87,7 +109,53 @@ const Payment = ({ packets }: Props) => {
{item.packetName} {item.packetName}
</AppText> </AppText>
</View> </View>
<View style={PaymentStyle.row}> {item.items.map((e: any) => (
<View
key={e.trekId}
style={{
...styles.infoCard,
flexDirection: 'column',
gap: 4,
}}
>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
gap: 4,
}}
>
<AppText style={styles.infoTitle}>
{t('Mahsulot nomi')}
</AppText>
<AppText style={styles.infoText}>{e.name}</AppText>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
gap: 4,
}}
>
<AppText style={styles.infoTitle}>{t('Trek ID')}</AppText>
<AppText style={styles.infoText}>{e.trekId}</AppText>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
gap: 4,
}}
>
<AppText style={styles.infoTitle}>{t('Ogirligi')}</AppText>
<AppText style={styles.infoText}>{e.weight} kg</AppText>
</View>
</View>
))}
{/* <View style={PaymentStyle.row}>
<AppText style={PaymentStyle.infoTitle}> <AppText style={PaymentStyle.infoTitle}>
{t("Mahsulotlar og'irligi")} {t("Mahsulotlar og'irligi")}
</AppText> </AppText>
@@ -104,7 +172,7 @@ const Payment = ({ packets }: Props) => {
{t('Umumiy narxi')} {t('Umumiy narxi')}
</AppText> </AppText>
<AppText style={PaymentStyle.text}>{item.totalPrice}</AppText> <AppText style={PaymentStyle.text}>{item.totalPrice}</AppText>
</View> </View> */}
</View> </View>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
@@ -120,4 +188,59 @@ const Payment = ({ packets }: Props) => {
); );
}; };
const makeStyles = () =>
StyleSheet.create({
container: { width: '95%', margin: 'auto', borderRadius: 10 },
count: {
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: 10,
},
title: { fontSize: 16, fontWeight: '500', color: '#333' },
card: {
backgroundColor: '#fff',
marginTop: 8,
padding: 15,
borderRadius: 10,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 2,
elevation: 2,
},
statusCard: { marginBottom: 10 },
circle: {
padding: 8,
borderRadius: 50,
alignItems: 'center',
justifyContent: 'center',
},
divider: { width: 20, borderBottomWidth: 2, borderStyle: 'dashed' },
iconWrapper: {
flexDirection: 'row',
alignItems: 'center',
flex: 1,
marginBottom: 10,
},
statusLabelWrapper: {
borderRadius: 8,
alignSelf: 'flex-start',
paddingVertical: 6,
paddingHorizontal: 10,
marginBottom: 12,
},
statusText: { fontFamily: 'GolosText-Bold', fontSize: 16 },
infoCard: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 6,
},
infoTitle: { fontSize: 16, color: '#979797', fontWeight: '500' },
infoText: { fontSize: 14, color: '#28A7E8', fontWeight: '500' },
});
export default Payment; export default Payment;

View File

@@ -58,8 +58,6 @@ const ModalPay = ({
queryFn: authApi.getMe, queryFn: authApi.getMe,
}); });
console.log(getMe, 'getMe');
const { mutate, isPending } = useMutation({ const { mutate, isPending } = useMutation({
mutationFn: ({ id, payType }: { id: number; payType: string }) => mutationFn: ({ id, payType }: { id: number; payType: string }) =>
packetsApi.payPackets(id, { payType }), packetsApi.payPackets(id, { payType }),

View File

@@ -1,9 +1,10 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import exchanges_api from 'api/exchanges'; import exchanges_api from 'api/exchanges';
import AppText from 'components/AppText'; import AppText from 'components/AppText';
import { formatPrice } from 'helpers/formatPrice';
import * as React from 'react'; import * as React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Dimensions, ScrollView, View } from 'react-native'; import { Dimensions, ScrollView, StyleSheet, View } from 'react-native';
import Svg, { Circle, Path } from 'react-native-svg'; import Svg, { Circle, Path } from 'react-native-svg';
import Plane from 'svg/Plane'; import Plane from 'svg/Plane';
import { PaymentStyle } from '../../payment/ui/style'; import { PaymentStyle } from '../../payment/ui/style';
@@ -17,6 +18,7 @@ const PaymentProduct = ({ packet }: PaymentProductProps) => {
const screenWidth = Dimensions.get('window').width; const screenWidth = Dimensions.get('window').width;
const isSmallScreen = screenWidth < 380; const isSmallScreen = screenWidth < 380;
const svgWidth = screenWidth * 0.8; const svgWidth = screenWidth * 0.8;
const svgWidthProduct = screenWidth * 1;
const { data } = useQuery({ const { data } = useQuery({
queryKey: ['exchanges'], queryKey: ['exchanges'],
@@ -80,21 +82,23 @@ const PaymentProduct = ({ packet }: PaymentProductProps) => {
: { flexBasis: '48%', alignItems: 'flex-end' }, : { flexBasis: '48%', alignItems: 'flex-end' },
]} ]}
> >
<AppText style={PaymentStyle.titleMethod}>Cargo</AppText> <AppText style={PaymentStyle.titleMethod}>{t('Reys')}</AppText>
<AppText style={PaymentStyle.textMethod}>12.267 UZS/ kg</AppText> <AppText style={[PaymentStyle.textMethod, { textAlign: 'left' }]}>
{packet.packetName}
</AppText>
</View> </View>
{/* <View {/* <View
style={[ style={[
PaymentStyle.info, PaymentStyle.info,
isSmallScreen isSmallScreen
? { flexBasis: '48%', alignItems: 'flex-start' } ? { flexBasis: '48%', alignItems: 'flex-end' }
: { flexBasis: '48%', alignItems: 'flex-start' }, : { flexBasis: '48%', alignItems: 'flex-end' },
]} ]}
> >
<AppText style={PaymentStyle.titleMethod}>{t('Yetkazish vaqti')}</AppText> <AppText style={PaymentStyle.titleMethod}>Cargo</AppText>
<AppText style={PaymentStyle.textMethod}>08.25.2025</AppText> <AppText style={PaymentStyle.textMethod}>12.267 UZS/ kg</AppText>
</View> */} </View>
<View <View
style={[ style={[
@@ -104,11 +108,11 @@ const PaymentProduct = ({ packet }: PaymentProductProps) => {
: { flexBasis: '48%', alignItems: 'flex-start' }, : { flexBasis: '48%', alignItems: 'flex-start' },
]} ]}
> >
<AppText style={PaymentStyle.titleMethod}>Reys</AppText> <AppText style={PaymentStyle.titleMethod}>
<AppText style={[PaymentStyle.textMethod, { textAlign: 'left' }]}> {t('Yetkazish vaqti')}
{packet.packetName}
</AppText> </AppText>
</View> <AppText style={PaymentStyle.textMethod}>08.25.2025</AppText>
</View> */}
</View> </View>
<View <View
style={{ style={{
@@ -149,36 +153,40 @@ const PaymentProduct = ({ packet }: PaymentProductProps) => {
/> />
</View> </View>
{packet.items.map((item: any, index: number) => { {packet.items.map((item: any, index: number) => {
const price = Number(item.price);
const weight = Number(item.weight);
const total = price * weight;
// formatlash: 0 decimal, som bilan
const formattedPrice = price.toFixed(0);
const formattedTotal = total.toFixed(0);
return ( return (
<View key={index} style={{ marginBottom: 15 }}> <View key={index} style={{ marginBottom: 15 }}>
<View style={PaymentStyle.receiptCard}> <View style={PaymentStyle.receiptCard}>
<View style={PaymentStyle.rowBetween}> <View style={PaymentStyle.rowBetween}>
<AppText style={PaymentStyle.itemName}>{item.name}</AppText> <View style={{ width: '100%' }}>
<AppText style={PaymentStyle.track}> <AppText style={PaymentStyle.itemName}>{item.name}</AppText>
{t('Trek ID')}: {item.trackId} <AppText style={PaymentStyle.track}>
</AppText> {t('Trek ID')}: {item.trekId}
</AppText>
</View>
</View> </View>
<View style={PaymentStyle.rowBetween}> <View style={PaymentStyle.rowBetween}>
<AppText style={PaymentStyle.weight}> <AppText style={PaymentStyle.weight}>
{t('Ogirligi')}: {weight} kg {t('Ogirligi')}: {item.weight} kg
</AppText> </AppText>
<AppText style={PaymentStyle.price}> <AppText style={PaymentStyle.price}>
1kg * {formattedPrice} {t('som')} {t('Narxi')}: {item.price}$
</AppText> </AppText>
</View> </View>
<View style={PaymentStyle.rowRight}> <View style={PaymentStyle.rowRight}>
<AppText style={PaymentStyle.total}> <AppText style={PaymentStyle.total}>
{t('Umumiy narxi')}: {formattedTotal} {t('som')} {t('Umumiy narxi')}: {item.totalPrice} $
</AppText> </AppText>
</View> </View>
</View> </View>
<Svg height="1" width={svgWidthProduct}>
<Path
d={`M 0 0 Q ${svgWidthProduct} 0 ${svgWidthProduct} 0`}
stroke="#8C8A93"
strokeWidth="2"
fill="none"
strokeDasharray="9"
/>
</Svg>
</View> </View>
); );
})} })}
@@ -205,7 +213,7 @@ const PaymentProduct = ({ packet }: PaymentProductProps) => {
]} ]}
> >
<AppText style={PaymentStyle.titleMethod}> <AppText style={PaymentStyle.titleMethod}>
{packet.totalPrice} {formatPrice(packet.totalPrice)} {t('som')}
</AppText> </AppText>
</View> </View>
</View> </View>
@@ -214,4 +222,15 @@ const PaymentProduct = ({ packet }: PaymentProductProps) => {
); );
}; };
const styles = StyleSheet.create({
cornerStyle: {
position: 'absolute' as const,
width: 40,
height: 40,
borderTopWidth: 6,
borderLeftWidth: 6,
borderColor: '#007AFF',
},
});
export default PaymentProduct; export default PaymentProduct;

View File

@@ -1,8 +1,10 @@
import { RouteProp, useRoute } from '@react-navigation/native'; import { RouteProp, useRoute } from '@react-navigation/native';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { authApi } from 'api/auth';
import exchanges_api from 'api/exchanges'; import exchanges_api from 'api/exchanges';
import AppText from 'components/AppText'; import AppText from 'components/AppText';
import LayoutTwo from 'components/LayoutTwo'; import LayoutTwo from 'components/LayoutTwo';
import { formatPrice } from 'helpers/formatPrice';
import * as React from 'react'; import * as React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
@@ -42,6 +44,10 @@ const PaymentQrCode = () => {
const [cardModal, setCardModal] = React.useState(false); const [cardModal, setCardModal] = React.useState(false);
const [payModal, setPayModal] = React.useState(false); const [payModal, setPayModal] = React.useState(false);
const [success, setSuccess] = React.useState(false); const [success, setSuccess] = React.useState(false);
const { data: getMe } = useQuery({
queryKey: ['getMe'],
queryFn: authApi.getMe,
});
const screenWidth = Dimensions.get('window').width; const screenWidth = Dimensions.get('window').width;
const isSmallScreen = screenWidth < 380; const isSmallScreen = screenWidth < 380;
@@ -102,7 +108,7 @@ const PaymentQrCode = () => {
)} )}
</View> </View>
<View {/* <View
style={[ style={[
PaymentStyle.info, PaymentStyle.info,
isSmallScreen isSmallScreen
@@ -112,7 +118,7 @@ const PaymentQrCode = () => {
> >
<AppText style={PaymentStyle.titleMethod}>Cargo</AppText> <AppText style={PaymentStyle.titleMethod}>Cargo</AppText>
<AppText style={PaymentStyle.textMethod}>12.267 UZS/ kg</AppText> <AppText style={PaymentStyle.textMethod}>12.267 UZS/ kg</AppText>
</View> </View> */}
{/* <View {/* <View
style={[ style={[
@@ -132,11 +138,11 @@ const PaymentQrCode = () => {
style={[ style={[
PaymentStyle.info, PaymentStyle.info,
isSmallScreen isSmallScreen
? { flexBasis: '48%', alignItems: 'flex-start' } ? { flexBasis: '48%', alignItems: 'flex-end' }
: { flexBasis: '48%', alignItems: 'flex-start' }, : { flexBasis: '48%', alignItems: 'flex-end' },
]} ]}
> >
<AppText style={PaymentStyle.titleMethod}>Reys</AppText> <AppText style={PaymentStyle.titleMethod}>{t('Reys')}</AppText>
<AppText style={[PaymentStyle.textMethod, { textAlign: 'left' }]}> <AppText style={[PaymentStyle.textMethod, { textAlign: 'left' }]}>
{packets.packetName} {packets.packetName}
</AppText> </AppText>
@@ -180,42 +186,46 @@ const PaymentQrCode = () => {
}} }}
/> />
</View> </View>
{packets.items.map((item: any, index: number) => ( {packets.items.map((item: any, index: number) => {
<View key={index} style={{ marginBottom: 15 }}> return (
<View style={PaymentStyle.receiptCard}> <View key={index} style={{ marginBottom: 15 }}>
<View style={PaymentStyle.rowBetween}> <View style={PaymentStyle.receiptCard}>
<View style={{ width: '100%' }}> <View style={PaymentStyle.rowBetween}>
<AppText style={PaymentStyle.itemName}>{item.name}</AppText> <View style={{ width: '100%' }}>
<AppText style={PaymentStyle.track}> <AppText style={PaymentStyle.itemName}>
{t('Trek ID')}: {item.trekId} {item.name}
</AppText>
<AppText style={PaymentStyle.track}>
{t('Trek ID')}: {item.trekId}
</AppText>
</View>
</View>
<View style={PaymentStyle.rowBetween}>
<AppText style={PaymentStyle.weight}>
{t('Ogirligi')}: {item.weight} kg
</AppText>
<AppText style={PaymentStyle.price}>
{t('Narxi')}: {item.price}$
</AppText>
</View>
<View style={PaymentStyle.rowRight}>
<AppText style={PaymentStyle.total}>
{t('Umumiy narxi')}: {item.totalPrice} $
</AppText> </AppText>
</View> </View>
</View> </View>
<View style={PaymentStyle.rowBetween}> <Svg height="1" width={svgWidthProduct}>
<AppText style={PaymentStyle.weight}> <Path
{t('Ogirligi')}: {item.weight} d={`M 0 0 Q ${svgWidthProduct} 0 ${svgWidthProduct} 0`}
</AppText> stroke="#8C8A93"
<AppText style={PaymentStyle.price}> strokeWidth="2"
1kg * {item.price} fill="none"
</AppText> strokeDasharray="9"
</View> />
<View style={PaymentStyle.rowRight}> </Svg>
<AppText style={PaymentStyle.total}>
{t('Umumiy narxi')}: {item.totalPrice} {t('som')}
</AppText>
</View>
</View> </View>
<Svg height="1" width={svgWidthProduct}> );
<Path })}
d={`M 0 0 Q ${svgWidthProduct} 0 ${svgWidthProduct} 0`}
stroke="#8C8A93"
strokeWidth="2"
fill="none"
strokeDasharray="9"
/>
</Svg>
</View>
))}
<View style={PaymentStyle.infoCard}> <View style={PaymentStyle.infoCard}>
<View <View
style={[ style={[
@@ -239,7 +249,7 @@ const PaymentQrCode = () => {
]} ]}
> >
<AppText style={PaymentStyle.titleMethod}> <AppText style={PaymentStyle.titleMethod}>
{packets.totalPrice} {formatPrice(packets.totalPrice)} {t('som')}
</AppText> </AppText>
</View> </View>
<View <View
@@ -339,13 +349,17 @@ const PaymentQrCode = () => {
setPayModal={setPayModal} setPayModal={setPayModal}
/> />
)} )}
{packets.paymentStatus !== 'PAYED' && ( {getMe && !getMe.aviaCargoId.includes('CP') && (
<TouchableOpacity <>
style={[PaymentStyle.button, { bottom: bottom + 80 }]} {packets.paymentStatus !== 'PAYED' && (
onPress={toggleModal} <TouchableOpacity
> style={[PaymentStyle.button, { bottom: bottom + 80 }]}
<AppText style={PaymentStyle.btnText}>{t("To'lash")}</AppText> onPress={toggleModal}
</TouchableOpacity> >
<AppText style={PaymentStyle.btnText}>{t("To'lash")}</AppText>
</TouchableOpacity>
)}
</>
)} )}
</LayoutTwo> </LayoutTwo>
); );

View File

@@ -1,24 +1,19 @@
import * as React from "react" import * as React from 'react';
import Svg, { Path } from "react-native-svg" import Svg, { Path } from 'react-native-svg';
interface Props { interface Props {
color: string, color: string;
width?: number, width?: number;
height?: number, height?: number;
view?: string view?: string;
} }
const Auto = ({ color, height = 24, width = 24, view = "0" }: Props) => ( const Auto = ({ color, height = 24, width = 24, view = '0' }: Props) => (
<Svg <Svg width={width} height={height} fill="none" viewBox={`0 ${view} 24 24`}>
width={width} <Path
height={height} fill={color}
fill="none" d="M7.965 13a3.5 3.5 0 0 1-6.93 0H0V1a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2h3l3 4.056V13h-2.035a3.501 3.501 0 0 1-6.93 0h-5.07ZM14 2H2v8.05a3.5 3.5 0 0 1 5.663.95h5.674c.168-.353.393-.674.663-.95V2Zm2 6h4v-.285L17.992 5H16v3Zm.5 6a1.5 1.5 0 1 0 0-3.001 1.5 1.5 0 0 0 0 3.001ZM6 12.5a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0Z"
viewBox={`0 ${view} 24 24`} />
> </Svg>
<Path );
fill={color} export default Auto;
d="M7.965 13a3.5 3.5 0 0 1-6.93 0H0V1a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2h3l3 4.056V13h-2.035a3.501 3.501 0 0 1-6.93 0h-5.07ZM14 2H2v8.05a3.5 3.5 0 0 1 5.663.95h5.674c.168-.353.393-.674.663-.95V2Zm2 6h4v-.285L17.992 5H16v3Zm.5 6a1.5 1.5 0 1 0 0-3.001 1.5 1.5 0 0 0 0 3.001ZM6 12.5a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0Z"
/>
</Svg>
)
export default Auto