parent
cb4d2d965d
commit
2f280e5986
15 changed files with 784 additions and 72 deletions
@ -0,0 +1,17 @@ |
||||
import proxy from "../proxy"; |
||||
|
||||
const transport = { |
||||
list: |
||||
(data = {}) => |
||||
async (dispatch) => { |
||||
await proxy.get("transport/list", data, { dispatch }); |
||||
}, |
||||
set: |
||||
(data = {}, data2 = {}, data3 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.post("transport/setTransport", data, { dispatch }); |
||||
await proxy.get("userFactor/info", data2, { dispatch }); |
||||
}, |
||||
}; |
||||
|
||||
export default transport; |
@ -0,0 +1,25 @@ |
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
list: [], |
||||
}; |
||||
export default function transport(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "transport/list": |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
list: data, |
||||
error: null, |
||||
}; |
||||
case "transport/info": |
||||
return { ...state, loading: false, error: null}; |
||||
case "transport/loading": |
||||
return { ...state, loading: true }; |
||||
case "transport/error": |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -1,12 +1,308 @@ |
||||
import { View, Text } from 'react-native' |
||||
import React from 'react' |
||||
import { |
||||
View, |
||||
Text, |
||||
SafeAreaView, |
||||
ScrollView, |
||||
StyleSheet, |
||||
StatusBar, |
||||
Platform, |
||||
Dimensions, |
||||
Appearance, |
||||
} from "react-native"; |
||||
import React, { useEffect, useState } from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { publicApi, userAddress } from "../../redux/actions"; |
||||
import { useNavigation } from "@react-navigation/native"; |
||||
import { asyncAwesomeAlert } from "../../utils/AsyncWrappers"; |
||||
|
||||
const Address = () => { |
||||
//components
|
||||
import Navbar from "../../components/Navbar"; |
||||
import CustomPressable from "../../components/Pressable"; |
||||
import CustomTextInput from "../../components/CustomTextInput"; |
||||
import Select from "../../components/Select"; |
||||
|
||||
//style
|
||||
import tw from "tailwind-rn"; |
||||
import Colors from "../../constants/Colors"; |
||||
import fontSize from "../../constants/fontSize"; |
||||
|
||||
const Address = ({ |
||||
city, |
||||
province, |
||||
getCity, |
||||
getProvince, |
||||
provinces, |
||||
cities, |
||||
createAddress, |
||||
loading, |
||||
setPhase, |
||||
cityLoading, |
||||
}) => { |
||||
const colorScheme = Appearance.getColorScheme(); |
||||
const navigation = useNavigation(); |
||||
|
||||
const [addressFields, setAddressFields] = useState({}); |
||||
const [mapAddress, setMapAddress] = useState(null); |
||||
|
||||
useEffect(() => { |
||||
getProvince(); |
||||
}, []); |
||||
|
||||
useEffect(() => { |
||||
// if(provinces?.length > 0){
|
||||
console.log(province); |
||||
// }
|
||||
}, [province]); |
||||
|
||||
useEffect(() => { |
||||
if (addressFields?.provinceId) { |
||||
getCity({ |
||||
provinceId: provinces.filter( |
||||
(province) => province.name === addressFields?.provinceId |
||||
)[0].id, |
||||
}); |
||||
} |
||||
}, [addressFields]); |
||||
|
||||
const onChange = (name, value) => { |
||||
setAddressFields({ ...addressFields, [name]: value }); |
||||
}; |
||||
|
||||
const submit = () => { |
||||
const { |
||||
firstName, |
||||
lastName, |
||||
cellphone, |
||||
phone, |
||||
address, |
||||
provinceId, |
||||
cityId, |
||||
postalCode, |
||||
} = addressFields; |
||||
|
||||
if (!firstName) { |
||||
return asyncAwesomeAlert("خطا", "نام خود را وارد کنید.", { |
||||
showCancelButton: false, |
||||
}); |
||||
} |
||||
if (!lastName) { |
||||
return asyncAwesomeAlert("خطا", "نام خانوادگی خود را وارد کنید", { |
||||
showCancelButton: false, |
||||
}); |
||||
} |
||||
if (!cellphone) { |
||||
return asyncAwesomeAlert("خطا", "شماره موبایل خود را وارد کنید.", { |
||||
showCancelButton: false, |
||||
}); |
||||
} |
||||
if (!phone) { |
||||
return asyncAwesomeAlert("خطا", "شماره تلفن خود را وارد کنید.", { |
||||
showCancelButton: false, |
||||
}); |
||||
} |
||||
if (!provinceId) { |
||||
return asyncAwesomeAlert("خطا", "نام استان خود را وارد کنید.", { |
||||
showCancelButton: false, |
||||
}); |
||||
} |
||||
if (!cityId) { |
||||
return asyncAwesomeAlert("خطا", "نام شهرستان خود را وارد کنید.", { |
||||
showCancelButton: false, |
||||
}); |
||||
} |
||||
if (!postalCode) { |
||||
return asyncAwesomeAlert("خطا", "کد پستی خود را وارد کنید.", { |
||||
showCancelButton: false, |
||||
}); |
||||
} |
||||
if (!mapAddress) { |
||||
return asyncAwesomeAlert("خطا", "آدرس خود را از روی نقشه انتخاب کن", { |
||||
showCancelButton: false, |
||||
}); |
||||
} |
||||
|
||||
createAddress({ |
||||
firstName, |
||||
lastName, |
||||
cellphone, |
||||
phone, |
||||
address: mapAddress, |
||||
provinceId: provinces.filter( |
||||
(province) => province.name === provinceId |
||||
)[0].id, |
||||
cityId: cities.filter((city) => city.name === cityId)[0]?.id, |
||||
postalCode, |
||||
location: null, |
||||
}); |
||||
|
||||
navigation.goBack(); |
||||
}; |
||||
|
||||
const Header = ({ title, text }) => { |
||||
return ( |
||||
<View> |
||||
<Text>Address</Text> |
||||
<View style={tw("flex flex-col mt-2")}> |
||||
<Text |
||||
style={{ |
||||
fontFamily: "bold", |
||||
fontSize: fontSize.lg, |
||||
color: Colors.theme1[colorScheme].gray20, |
||||
}} |
||||
> |
||||
{title} |
||||
</Text> |
||||
<Text |
||||
style={{ |
||||
fontFamily: "regular", |
||||
fontSize: fontSize.sm, |
||||
color: Colors.theme1[colorScheme].gray20 + "aa", |
||||
}} |
||||
> |
||||
{text} |
||||
</Text> |
||||
</View> |
||||
); |
||||
}; |
||||
|
||||
return ( |
||||
<SafeAreaView |
||||
style={{ |
||||
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0, |
||||
position: "relative", |
||||
}} |
||||
> |
||||
<Navbar |
||||
headerOptions={{ |
||||
logo: false, |
||||
menu: true, |
||||
hamburgerMenu: false, |
||||
title: "", |
||||
bookmark: true, |
||||
qr: false, |
||||
back: true, |
||||
}} |
||||
/> |
||||
<ScrollView |
||||
contentContainerStyle={styles.contentContainerStyle} |
||||
style={styles.container} |
||||
> |
||||
<View style={tw("w-full flex flex-col pb-4")}> |
||||
<Header |
||||
title="اطلاعات هویتی" |
||||
text="( لطفا نام و نام خانوادگی خود را به طور کامل وارد نمایید )" |
||||
/> |
||||
<CustomTextInput |
||||
label="نام" |
||||
placeholder="" |
||||
textAlign="right" |
||||
name="firstName" |
||||
maxlength="40" |
||||
value={addressFields?.firstName} |
||||
onChange={(name, value) => onChange(name, value)} |
||||
autoFocus={false} |
||||
regex={(val) => val} |
||||
/> |
||||
<CustomTextInput |
||||
label="نام خانوادگی" |
||||
placeholder="" |
||||
textAlign="right" |
||||
name="lastName" |
||||
maxlength="60" |
||||
value={addressFields?.lastName} |
||||
onChange={(name, value) => onChange(name, value)} |
||||
autoFocus={false} |
||||
regex={(val) => val} |
||||
/> |
||||
<Header |
||||
title="شماره تماس" |
||||
text="( شماره موبایل و شماره تلفن ثابت خود را
|
||||
به همراه پیش شماره وارد کنید )" |
||||
/> |
||||
<CustomTextInput |
||||
label="شماره موبایل" |
||||
placeholder="" |
||||
textAlign="left" |
||||
name="cellphone" |
||||
maxlength="11" |
||||
value={addressFields?.cellphone} |
||||
onChange={(name, value) => onChange(name, value)} |
||||
autoFocus={false} |
||||
regex={(val) => val} |
||||
/> |
||||
<CustomTextInput |
||||
label="شماره تلفن" |
||||
placeholder="" |
||||
textAlign="left" |
||||
name="phone" |
||||
maxlength="11" |
||||
value={addressFields?.phone} |
||||
onChange={(name, value) => onChange(name, value)} |
||||
autoFocus={false} |
||||
regex={(val) => val} |
||||
/> |
||||
<Header |
||||
title="آدرس" |
||||
text="( لطفا نام استان و شهرستان و آدرس |
||||
خود را با دقت تکمیل نمایید )" |
||||
/> |
||||
<View style={tw("w-full mt-4")}> |
||||
<Select |
||||
defaultValue={province[0]} |
||||
onChange={(name, value) => onChange(name, value)} |
||||
options={province} |
||||
width={"100%"} |
||||
name="provinceId" |
||||
/> |
||||
</View> |
||||
<View style={tw("w-full mt-4")}> |
||||
<Select |
||||
defaultValue={city[0]} |
||||
onChange={(name, value) => onChange(name, value)} |
||||
options={city} |
||||
width={"100%"} |
||||
name="cityId" |
||||
/> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default Address; |
||||
<CustomPressable |
||||
title={"ثبت آدرس"} |
||||
backgroundColor={Colors.theme1[colorScheme].greenCF} |
||||
color={"white"} |
||||
border={{ color: "#196EC0", width: 0 }} |
||||
width={"100%"} |
||||
onPress={() => navigation.push("Address")} |
||||
/> |
||||
</View> |
||||
</ScrollView> |
||||
</SafeAreaView> |
||||
); |
||||
}; |
||||
|
||||
const styles = StyleSheet.create({ |
||||
contentContainerStyle: { |
||||
paddingBottom: 100, |
||||
}, |
||||
container: { |
||||
width: Dimensions.get("window").width, |
||||
backgroundColor: "white", |
||||
flexDirection: "column", |
||||
paddingVertical: 5, |
||||
paddingHorizontal: 16, |
||||
}, |
||||
}); |
||||
|
||||
const mapStateToProps = (state) => ({ |
||||
provinces: state.publicApi.provinces, |
||||
province: state.publicApi.province, |
||||
cities: state.publicApi.cities, |
||||
city: state.publicApi.city, |
||||
loading: state.userAddress.loading, |
||||
cityLoading: state.publicApi.loading, |
||||
}); |
||||
|
||||
const mapDispatchToProps = { |
||||
getProvince: publicApi.getProvince, |
||||
getCity: publicApi.getCity, |
||||
createAddress: userAddress.add, |
||||
}; |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Address); |
||||
|
@ -1,12 +1,144 @@ |
||||
import { View, Text } from 'react-native' |
||||
import React from 'react' |
||||
import { |
||||
View, |
||||
Text, |
||||
Pressable, |
||||
TouchableOpacity, |
||||
Appearance, |
||||
ActivityIndicator, |
||||
} from "react-native"; |
||||
import React from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { useNavigation } from "@react-navigation/native"; |
||||
import { userFactor } from "../../../redux/actions"; |
||||
|
||||
//style
|
||||
import tw from "tailwind-rn"; |
||||
import Colors from "../../../constants/Colors"; |
||||
import fontSize from "../../../constants/fontSize"; |
||||
|
||||
const Address = ({ addresses, update, userId, userAddressId, loading }) => { |
||||
const colorScheme = Appearance.getColorScheme(); |
||||
const navigation = useNavigation(); |
||||
|
||||
const Location = ({ address, active }) => { |
||||
return ( |
||||
<Pressable |
||||
style={[ |
||||
{ |
||||
backgroundColor: |
||||
userAddressId === address?.id |
||||
? Colors.theme1[colorScheme].greenCF + "15" |
||||
: Colors.theme1[colorScheme].grayE3 + "44", |
||||
borderWidth: 2, |
||||
borderColor: |
||||
userAddressId === address?.id |
||||
? Colors.theme1[colorScheme].greenCF |
||||
: Colors.theme1[colorScheme].grayE3, |
||||
}, |
||||
tw( |
||||
`flex flex-row-reverse items-center w-full px-3 py-2 rounded-md mt-2` |
||||
), |
||||
]} |
||||
onPress={() => |
||||
userAddressId === address?.id |
||||
? {} |
||||
: update({ userAddressId: address.id, userId }) |
||||
} |
||||
> |
||||
{loading && userAddressId !== address?.id ? ( |
||||
<ActivityIndicator |
||||
size="small" |
||||
color={Colors.theme1[colorScheme].greenC8} |
||||
/> |
||||
) : ( |
||||
<View |
||||
style={[ |
||||
tw("w-5 h-5 rounded-full"), |
||||
{ |
||||
backgroundColor: active |
||||
? Colors.theme1[colorScheme].greenCF |
||||
: "white", |
||||
borderWidth: userAddressId === address?.id ? 4 : 1, |
||||
borderColor: |
||||
userAddressId === address?.id |
||||
? Colors.theme1[colorScheme].black |
||||
: Colors.theme1[colorScheme].gray20 + "33", |
||||
}, |
||||
]} |
||||
></View> |
||||
)} |
||||
<View style={tw("flex flex-1 flex-col mr-2")}> |
||||
<Text |
||||
style={[ |
||||
{ |
||||
fontFamily: "bold", |
||||
fontSize: fontSize.tiny, |
||||
lineHeight: 22, |
||||
}, |
||||
]} |
||||
> |
||||
{address.address} |
||||
</Text> |
||||
</View> |
||||
</Pressable> |
||||
); |
||||
}; |
||||
|
||||
const Address = () => { |
||||
return ( |
||||
<View> |
||||
<Text>Address</Text> |
||||
<View style={tw("w-full mt-2")}> |
||||
<View style={tw("p-0 m-0 flex flex-col")}> |
||||
{addresses.map((address, index) => ( |
||||
<Location |
||||
address={address} |
||||
key={index} |
||||
active={userAddressId === address?.id} |
||||
/> |
||||
))} |
||||
</View> |
||||
<TouchableOpacity |
||||
style={[ |
||||
{ |
||||
backgroundColor: Colors.theme1[colorScheme].grayE3 + "44", |
||||
borderColor: Colors.theme1[colorScheme].gray2077 + '55', |
||||
borderWidth: 1, |
||||
}, |
||||
tw( |
||||
`flex flex-row-reverse justify-center py-3 rounded-md items-center w-full mt-4` |
||||
), |
||||
]} |
||||
onPress={() => navigation.push("CreateAddress")} |
||||
> |
||||
<Text |
||||
style={{ |
||||
fontFamily: "regular", |
||||
fontSize: fontSize.tiny, |
||||
color: Colors.theme1[colorScheme].gray2077, |
||||
}} |
||||
> |
||||
یک آدرس جدید اضافه کنید |
||||
</Text> |
||||
<Text |
||||
style={{ |
||||
marginRight: 2, |
||||
fontSize: fontSize.xl, |
||||
color: Colors.theme1[colorScheme].gray20, |
||||
}} |
||||
> |
||||
+ |
||||
</Text> |
||||
</TouchableOpacity> |
||||
</View> |
||||
) |
||||
} |
||||
); |
||||
}; |
||||
|
||||
const mapStateToProps = (state) => ({ |
||||
userId: state.user.status?.id, |
||||
userAddressId: state.userFactor.info?.userAddressId, |
||||
loading: state.userFactor.loading, |
||||
}); |
||||
|
||||
const mapDispatchToProps = { |
||||
update: userFactor.update, |
||||
}; |
||||
|
||||
export default Address |
||||
export default connect(mapStateToProps, mapDispatchToProps)(Address); |
||||
|
@ -1,12 +1,80 @@ |
||||
import { View, Text } from 'react-native' |
||||
import React from 'react' |
||||
import { View, Text, Pressable, Appearance } from "react-native"; |
||||
import React, { useCallback, useState } from "react"; |
||||
import { connect } from "react-redux"; |
||||
|
||||
const TransportDate = () => { |
||||
//style
|
||||
import tw from "tailwind-rn"; |
||||
import Colors from "../../../constants/Colors"; |
||||
import fontSize from "../../../constants/fontSize"; |
||||
|
||||
const TransportDate = ({ transportDate }) => { |
||||
const colorScheme = Appearance.getColorScheme(); |
||||
const [activeDate, setActiveDate] = useState(transportDate?.times[0]); |
||||
|
||||
const Time = useCallback(({ time, active }) => { |
||||
return ( |
||||
<Pressable |
||||
style={[ |
||||
tw(`flex flex-col items-center w-full px-2 py-1.5 rounded-md mt-3`), |
||||
{ |
||||
backgroundColor: active |
||||
? Colors.theme1[colorScheme].greenCF + "15" |
||||
: Colors.theme1[colorScheme].grayE3 + "44", |
||||
borderWidth: 2, |
||||
borderColor: active |
||||
? Colors.theme1[colorScheme].greenCF |
||||
: Colors.theme1[colorScheme].grayE3, |
||||
}, |
||||
]} |
||||
onPress={() => setActiveDate(time)} |
||||
> |
||||
<Text |
||||
style={{ |
||||
fontFamily: "bold", |
||||
fontSize: fontSize.lg, |
||||
color: active |
||||
? Colors.theme1[colorScheme].gray20 |
||||
: Colors.theme1[colorScheme].gray20, |
||||
}} |
||||
> |
||||
{time.time} |
||||
</Text> |
||||
<Text |
||||
style={{ |
||||
fontFamily: "bold", |
||||
fontSize: fontSize.sm, |
||||
color: active |
||||
? Colors.theme1[colorScheme].green20 |
||||
: Colors.theme1[colorScheme].gray20, |
||||
}} |
||||
> |
||||
تکمیل ظرفیت |
||||
</Text> |
||||
</Pressable> |
||||
); |
||||
}, []); |
||||
return ( |
||||
<View> |
||||
<Text>TransportDate</Text> |
||||
<View style={tw("mt-0 w-full")}> |
||||
<Text |
||||
style={{ |
||||
fontSize: fontSize.lg, |
||||
fontFamily: "bold", |
||||
color: Colors.theme1[colorScheme].green79, |
||||
}} |
||||
> |
||||
زمان ارسال را انتخاب کنید |
||||
</Text> |
||||
<View style={tw("p-0 m-0 flex flex-col w-full")}> |
||||
{transportDate?.times?.map((time, index) => ( |
||||
<Time time={time} key={index} active={time === activeDate} /> |
||||
))} |
||||
</View> |
||||
) |
||||
} |
||||
</View> |
||||
); |
||||
}; |
||||
|
||||
const mapStateToProps = (state) => ({}); |
||||
|
||||
const mapDispatchToProps = {}; |
||||
|
||||
export default TransportDate |
||||
export default connect(mapStateToProps, mapDispatchToProps)(TransportDate); |
||||
|
@ -1,12 +1,134 @@ |
||||
import { View, Text } from 'react-native' |
||||
import React from 'react' |
||||
import { |
||||
View, |
||||
Text, |
||||
Pressable, |
||||
TouchableOpacity, |
||||
Appearance, |
||||
ActivityIndicator, |
||||
} from "react-native"; |
||||
import React, { useEffect, useCallback } from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { useNavigation } from "@react-navigation/native"; |
||||
import { transport } from "../../../redux/actions"; |
||||
import separate from "../../../utils/separate"; |
||||
|
||||
const TransportMethod = () => { |
||||
//style
|
||||
import tw from "tailwind-rn"; |
||||
import Colors from "../../../constants/Colors"; |
||||
import fontSize from "../../../constants/fontSize"; |
||||
|
||||
const TransportMethod = ({ |
||||
list, |
||||
getList, |
||||
setTransport, |
||||
factorInfo, |
||||
userId, |
||||
loading, |
||||
}) => { |
||||
const colorScheme = Appearance.getColorScheme(); |
||||
|
||||
useEffect(() => { |
||||
getList(); |
||||
}, []); |
||||
|
||||
const Method = useCallback( |
||||
({ method, active }) => { |
||||
return ( |
||||
<View> |
||||
<Text>TransportMethod</Text> |
||||
</View> |
||||
<Pressable |
||||
style={[ |
||||
tw(`flex flex-col items-center w-full px-2 py-1.5 rounded-md mt-3`), |
||||
{ |
||||
backgroundColor: active |
||||
? Colors.theme1[colorScheme].greenCF + "15" |
||||
: Colors.theme1[colorScheme].grayE3 + "44", |
||||
borderWidth: 2, |
||||
borderColor: active |
||||
? Colors.theme1[colorScheme].greenCF |
||||
: Colors.theme1[colorScheme].grayE3, |
||||
}, |
||||
]} |
||||
onPress={() => |
||||
!active |
||||
? setTransport( |
||||
{ factorId: factorInfo?.id, transportId: method?.id }, |
||||
{ userId }, |
||||
{} |
||||
) |
||||
} |
||||
: {} |
||||
} |
||||
> |
||||
{loading && !active ? ( |
||||
<ActivityIndicator |
||||
size="small" |
||||
color={ |
||||
factorInfo?.transportId === method?.id |
||||
? Colors.theme1[colorScheme].greenC8 |
||||
: Colors.theme1[colorScheme].gray20 |
||||
} |
||||
/> |
||||
) : ( |
||||
<Text |
||||
style={{ |
||||
fontFamily: "bold", |
||||
fontSize: fontSize.lg, |
||||
color: active |
||||
? Colors.theme1[colorScheme].gray20 |
||||
: Colors.theme1[colorScheme].gray20, |
||||
}} |
||||
> |
||||
{method.name} |
||||
</Text> |
||||
)} |
||||
<Text |
||||
style={{ |
||||
fontFamily: "bold", |
||||
fontSize: fontSize.sm, |
||||
color: active |
||||
? Colors.theme1[colorScheme].green20 |
||||
: Colors.theme1[colorScheme].gray20, |
||||
}} |
||||
> |
||||
هزینه ارسال {separate(method.price)} |
||||
</Text> |
||||
</Pressable> |
||||
); |
||||
}, |
||||
[factorInfo, loading] |
||||
); |
||||
return ( |
||||
<View style={tw("mt-0 w-full")}> |
||||
<Text |
||||
style={{ |
||||
fontSize: fontSize.lg, |
||||
fontFamily: "bold", |
||||
color: Colors.theme1[colorScheme].green79, |
||||
}} |
||||
> |
||||
لطفا یک روش ارسال انتخاب کنید |
||||
</Text> |
||||
<View style={tw("p-0 m-0 flex flex-col w-full")}> |
||||
{list?.map((method, index) => ( |
||||
<Method |
||||
method={method} |
||||
key={index} |
||||
active={factorInfo?.transportId === method?.id} |
||||
/> |
||||
))} |
||||
</View> |
||||
</View> |
||||
); |
||||
}; |
||||
|
||||
const mapStateToProps = (state) => ({ |
||||
list: state.transport.list, |
||||
factorInfo: state.userFactor.info, |
||||
userId: state.user.status?.id, |
||||
loading: state.userFactor.loading, |
||||
}); |
||||
|
||||
const mapDispatchToProps = { |
||||
getList: transport.list, |
||||
setTransport: transport.set, |
||||
}; |
||||
|
||||
export default TransportMethod |
||||
export default connect(mapStateToProps, mapDispatchToProps)(TransportMethod); |
||||
|
Loading…
Reference in new issue