Files
cpost-mobile/src/screens/home/branches/ui/ListBranches.tsx
Samandar Turgunboyev ef73715048 update
2025-08-27 15:37:37 +05:00

240 lines
6.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useQuery } from '@tanstack/react-query';
import { Branch, branchApi } from 'api/branch';
import BottomModal from 'components/BottomModal';
import LayoutTwo from 'components/LayoutTwo';
import LoadingScreen from 'components/LoadingScreen';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import WebView from 'react-native-webview';
import Minus from 'svg/Minus';
import Plus from 'svg/Plus';
const ListBranches = () => {
const route = useRoute<RouteProp<any>>();
const webviewRef = useRef<WebView>(null);
const [webViewReady, setWebViewReady] = useState(false);
const [selectedBranch, setSelectedBranch] = useState<Branch | null>(null);
const [isModalVisible, setModalVisible] = useState(false);
const navigation = useNavigation<NativeStackNavigationProp<any>>();
const { t } = useTranslation();
const { data } = useQuery({
queryKey: ['branchList'],
queryFn: branchApi.branchList,
});
useEffect(() => {
if (webViewReady && route.params?.branchId) {
const branch = data && data.find(b => b.id === route?.params?.branchId);
if (branch) {
setSelectedBranch(branch);
setModalVisible(true);
const jsCode = `
map.setCenter([${branch.latitude}, ${branch.longitude}], 14);
placemark${branch.id}?.balloon.open();
true;
`;
webviewRef.current?.injectJavaScript(jsCode);
}
}
}, [webViewReady, route.params]);
const generatePlacemarks = () => {
if (!data || !data.length) return '';
return data
.map(
branch => `
var placemark${branch.id} = new ymaps.Placemark([${branch.latitude}, ${branch.longitude}], {
balloonContent: '${branch.name}'
}, {
iconLayout: 'default#image',
iconImageSize: [30, 30],
iconImageOffset: [-15, -30]
});
placemark${branch.id}.events.add('click', function () {
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'branch_click',
id: ${branch.id}
}));
});
map.geoObjects.add(placemark${branch.id});
`,
)
.join('\n');
};
const html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>
<style>
html, body, #map {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
let map;
ymaps.ready(function () {
map = new ymaps.Map("map", {
center: [40.5, 67.9],
zoom: 6,
controls: []
});
${generatePlacemarks()}
window.ReactNativeWebView.postMessage("map_ready");
});
function zoomIn() {
if (map) map.setZoom(map.getZoom() + 1);
}
function zoomOut() {
if (map) map.setZoom(map.getZoom() - 1);
}
</script>
</body>
</html>
`;
const handleZoom = (type: 'in' | 'out') => {
const command = type === 'in' ? 'zoomIn(); true;' : 'zoomOut(); true;';
webviewRef.current?.injectJavaScript(command);
};
if (!data) return <LoadingScreen />;
return (
<LayoutTwo title={t('Filiallar royxati')}>
{!webViewReady && (
<View style={{ width: '100%', height: '100%', margin: 'auto' }}>
<LoadingScreen />
</View>
)}
<View style={styles.container}>
<WebView
ref={webviewRef}
originWhitelist={['*']}
source={{ html }}
javaScriptEnabled
domStorageEnabled
onMessage={event => {
try {
const message = event.nativeEvent.data;
if (message === 'map_ready') {
setWebViewReady(true);
return;
}
const parsed = JSON.parse(message);
if (parsed.type === 'branch_click') {
const branchItem =
data && data.find((b: Branch) => b.id === parsed.id);
if (branchItem) {
setSelectedBranch(branchItem);
setModalVisible(true);
}
}
} catch (e) {
console.warn('WebView message parse error:', e);
}
}}
style={{ flex: 1 }}
/>
{webViewReady && (
<View style={{ position: 'absolute', bottom: 0 }}>
<View style={styles.zoomControls}>
<TouchableOpacity
style={styles.zoomButton}
onPress={() => handleZoom('in')}
>
<Text>
<Plus color="#DEDEDE" />
</Text>
</TouchableOpacity>
<View style={styles.divider} />
<TouchableOpacity
style={styles.zoomButton}
onPress={() => handleZoom('out')}
>
<Text>
<Minus color="#DEDEDE" />
</Text>
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.button}
onPress={() => navigation.navigate('Branches')}
>
<Text style={styles.buttonText}>{t('Manzilni tekshirish')}</Text>
</TouchableOpacity>
</View>
)}
<BottomModal
visible={isModalVisible}
onClose={() => setModalVisible(false)}
branch={selectedBranch}
/>
</View>
</LayoutTwo>
);
};
export default ListBranches;
const styles = StyleSheet.create({
container: { flex: 1 },
zoomControls: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#373737',
borderRadius: 20,
width: '10%',
padding: 4,
marginLeft: '85%',
bottom: 20,
},
zoomButton: {
borderRadius: 8,
width: 40,
height: 40,
marginVertical: 4,
justifyContent: 'center',
alignItems: 'center',
},
divider: { height: 1, width: '100%', backgroundColor: '#DEDEDE' },
button: {
bottom: 10,
width: '95%',
margin: 'auto',
alignSelf: 'center',
backgroundColor: '#009CFF',
paddingVertical: 14,
paddingHorizontal: 28,
borderRadius: 10,
elevation: 4,
},
buttonText: {
color: '#fff',
fontWeight: '600',
fontSize: 16,
textAlign: 'center',
},
});