csa-react-60/src/screens/bill/Bill.js
2025-07-25 11:03:42 +07:00

565 lines
20 KiB
JavaScript

import React, { Component } from 'react'
import Icon from '../../components/Icon'
import {
Accordion,
Badge,
Body,
Button,
Content,
Header,
Left,
List,
ListItem,
Right,
Title,
View
} from 'native-base'
import { Dimensions, FlatList, ScrollView, StyleSheet, TouchableOpacity, SafeAreaView, Alert } from 'react-native'
import LinearGradient from 'react-native-linear-gradient'
import Text from '../../components/Text';
import { payment } from '../../api/UserApi'
import { connect } from "react-redux";
import {bindActionCreators} from "redux";
import {appSetDevice, appSetPushToken, appSetToken, appSetUser} from "../../redux/app/action";
import moment from "moment";
import IndicatorLoading from '../../components/IndicatorLoading';
import { t } from 'src/utils/i18n'
const { height, width } = Dimensions.get('window')
function ItemOrder({title,cost,description,type}){
let iconShow = ''
let iconColor = ''
switch(type){
case 0:
iconShow = 'ic_event_note'
iconColor = '#00000080'
break;
case 1:
iconShow = 'ic_bed'
iconColor = '#FF6122'
break;
case 2:
iconShow = 'ic_water'
iconColor = '#5AC8FA'
break;
case 3:
iconShow = 'ic_thunder'
iconColor = '#FFCC00'
break;
case 4:
iconShow = 'ic_event_note'
iconColor = '#00000080'
break;
case 5:
iconShow = 'ic_water'
iconColor = '#5AC8FA'
break;
case 6:
iconShow = 'ic_thunder'
iconColor = '#FFCC00'
break;
case 7:
iconShow = 'ic_event_note'
iconColor = '#00000080'
break;
}
return <View style={{flexDirection:'row',height:64,width:'100%',borderBottomWidth:1,alignItems:'center',borderColor:'#EAEAF4',paddingHorizontal:16}}>
<View style={{ ...styles.circleShapeView, backgroundColor: iconColor,marginRight:16 }}>
<Icon active name={iconShow} size={20} color="white" />
</View>
<View style={{flex:1}}>
<View style={{ flexDirection: 'row' }}>
<Text style={{ flex: 1 }}>{title}</Text>
<Text style={{ ...styles.colorTextPayment, textAlign: 'center' }}>{cost} {t('baht')}</Text>
</View>
<Text style={{ color: '#00000080', fontSize: 12, marginLeft: 5}}>{description != '' ? description : '-'}</Text>
</View>
</View>
}
class BillScreen extends Component {
constructor(props) {
super(props)
this.state = {
isLoading:false,
payment: [],
sum_payment: [],
activePage: 0,
isCanPay: true,
all_payment : [],
room_number_array : [],
};
this._onCarouselScroll = this._onCarouselScroll.bind(this)
this.checkDueDate = this.checkDueDate.bind(this)
this.checkstatusBill = this.checkstatusBill.bind(this)
}
componentDidMount() {
this.setState({isLoading: true})
if(this.props.user){
payment(this.props.user.id)
.then(res => {
if(res.ok){
let sum_payment = [];
let array_payment = [];
let sum_cost_room = res.data.sum_cost_room;
if(Object.keys(sum_cost_room).length > 0) {
Object.keys(sum_cost_room).map((sum_cost) => {
sum_payment.push({
total_cost : sum_cost_room[sum_cost].total_cost,
room: sum_cost_room[sum_cost].room,
project: sum_cost_room[sum_cost].project,
due_at: sum_cost_room[sum_cost].due_at,
}
)
})
}
let payment = res.data.payment_room_period
if(Object.keys(payment).length > 0){
Object.keys(payment).map((pay) => {
if(Object.keys(payment[pay]).length > 0){
Object.keys(payment[pay]).map((detail) => {
this.state.room_number_array.push(pay)
array_payment.push({
room_id: pay,
period: detail,
// total_cost: payment[pay][detail].total_cost,
// details: payment[pay][detail].details,
// status: payment[pay][detail].status,
// created_at: payment[pay][detail].created_at,
// payment_id: payment[pay][detail].id,
// enable_qr: payment[pay][detail].enable_qr
...payment[pay][detail]
})
})
}
})
}
let all_payment_data = array_payment;
let array_room_no = this.state.room_number_array;
this.setState({
room_number_array: array_room_no.filter((item, i, ar) => ar.indexOf(item) === i)
});
let first_room = this.state.room_number_array[0];
array_payment = array_payment.filter((obj)=>{
return Object.keys(obj).reduce((acc, curr)=>{
return obj.room_id === first_room
}, false);
});
let date_now = moment()
let findTimeout = array_payment.find((item) => {return moment(item.due_at) == date_now})
//check bill timeout
if(findTimeout !== undefined){
this.setState({
isCanPay: false
})
}
if(sum_payment.length > 0){
this.setState({
room_number_array: sum_payment.map(function(item){
return item.room
})
});
}
this.setState({
isLoading:false,
payment: array_payment,
sum_payment: sum_payment,
all_payment: all_payment_data
})
}
})
}
}
getMonth(period_month){
let new_month = 'มกราคม'
switch (period_month) {
case '01':
new_month = 'มกราคม';
break;
case '02':
new_month = 'กุมภาพันธ์';
break;
case '03':
new_month = 'มีนาคม';
break;
case '04':
new_month = 'เมษายน';
break;
case '05':
new_month = 'พฤษภาคม';
break;
case '06':
new_month = 'มิถุนายน';
break;
case '07':
new_month = 'กรกฎาคม';
break;
case '08':
new_month = 'สิงหาคม';
break;
case '09':
new_month = 'กันยายน';
break;
case '10':
new_month = 'ตุลาคม';
break;
case '11':
new_month = 'พฤศจิกายน';
break;
case '12':
new_month = 'ธันวาคม';
break;
default:
new_month = 'มกราคม';
break;
}
return new_month;
}
getTitle (period) {
let period_month = moment(period, "MM/Y").format('MM');
let period_year = parseInt(moment(period, "MM/Y").format('Y')) + 543;
let new_month = 'มกราคม';
let new_period = new_month + ' ' + period_year;
new_month = this.getMonth(period_month)
new_period = new_month + ' ' + period_year;
return new_period;
}
checkDueDate(date){
// console.log('date -------- ',moment(date))
// console.log('now -------- ',moment())
let due_date = moment(date)
let now = moment()
if(due_date < now){
return false
}
return true
}
checkstatusBill(data,boolDate){
if(data.status == 'paid'){
return <TouchableOpacity style={{backgroundColor:data.status === 'pending' ? '#145EB3' : 'white',
height: 32,width: 103,justifyContent:'center',alignItems:'center',borderRadius:5,
borderColor: data.status !== 'pending' ? 'grey' : '',
borderWidth: data.status !== 'pending' ? 1 : 0}}
disabled={data.status === 'pending' ? false : true}
onPress={() => {
this.state.isCanPay ?
data.status === 'pending' && this.props.navigation.navigate('Payment',{payment_id:data.id})
: Alert.alert(null, 'รายการค้างชำระของคุณ เกินกำหนดชำระ กรุณาติดต่อสำนักงานบริการลูกค้า',[{text: t('ok')}])
}}>
<Text style={{ color: data.status === 'pending' ? 'white' : 'rgba(0, 0, 0, 0.25)'}}>{data.status === 'pending' ? 'จ่ายเงิน' : 'จ่ายแล้ว'}</Text>
</TouchableOpacity>
}else{
if(!boolDate){
return <View>
<Text style={{ color: 'red',borderWidth:1,borderColor:'#00000040',borderRadius:5,paddingHorizontal:6}}>{'เกินกำหนดชำระ'}</Text>
</View>
}else{
return <TouchableOpacity style={{backgroundColor:data.status === 'pending' ? '#145EB3' : 'white',
height: 32,width: 103,justifyContent:'center',alignItems:'center',borderRadius:5,
borderColor: data.status !== 'pending' ? 'grey' : '',
borderWidth: data.status !== 'pending' ? 1 : 0}}
disabled={data.status === 'pending' ? false : true}
onPress={() => {
this.state.isCanPay ?
data.status === 'pending' && this.props.navigation.navigate('Payment',{payment_id:data.id})
: Alert.alert(null, 'รายการค้างชำระของคุณ เกินกำหนดชำระ กรุณาติดต่อสำนักงานบริการลูกค้า',[{text: t('ok')}])
}}>
<Text style={{ color: data.status === 'pending' ? 'white' : 'rgba(0, 0, 0, 0.25)'}}>{data.status === 'pending' ? 'จ่ายเงิน' : 'จ่ายแล้ว'}</Text>
</TouchableOpacity>
}
}
}
_renderHeader(data, expanded) {
// if(data.room_id == this.state.sum_payment[this.state.activePage].room.id){
let checkBool = this.checkDueDate(data.due_at == null || data.due_at == undefined ? moment() : data.due_at)
return (
<View style={{flex:1,flexDirection:'row',backgroundColor:'#B8DAAA',height: 64,borderBottomWidth:1,borderBottomColor:'white',alignItems:'center',justifyContent:'space-between',paddingHorizontal:16}}>
<View style={{justifyContent:'center',flex:1}}>
<Text>{t('month')} {this.getTitle(data.period)}</Text>
<View style={{flexDirection:'row',alignItems:'center',justifyContent:'space-between'}}>
{expanded || data.status != 'pending' ? <Text /> : <Text note style={styles.colorTextPayment}>{t('outstanding_balance')} {data.total_cost}</Text>}
{expanded || <Text style={{fontSize:10,marginRight:16}}>{t('view_more')}</Text>}
</View>
</View>
{
this.checkstatusBill(data,checkBool)
}
{/* {
checkBool ?
data.enable_qr &&
<TouchableOpacity style={{backgroundColor:data.status === 'pending' ? '#145EB3' : 'white',
height: 32,width: 103,justifyContent:'center',alignItems:'center',borderRadius:5,
borderColor: data.status !== 'pending' ? 'grey' : '',
borderWidth: data.status !== 'pending' ? 1 : 0}}
disabled={data.status === 'pending' ? false : true}
onPress={() => {
this.state.isCanPay ?
data.status === 'pending' && this.props.navigation.navigate('Payment',{payment_id:data.id})
: Alert.alert(null, 'รายการค้างชำระของคุณ เกินกำหนดชำระ กรุณาติดต่อสำนักงานบริการลูกค้า',[{text: t('ok')}])
}}>
<Text style={{ color: data.status === 'pending' ? 'white' : 'rgba(0, 0, 0, 0.25)'}}>{data.status === 'pending' ? 'จ่ายเงิน' : 'จ่ายแล้ว'}</Text>
</TouchableOpacity>
:
<View>
<Text style={{ color: 'red',borderWidth:1,borderColor:'#00000040',borderRadius:5,paddingHorizontal:6}}>{'เกินกำหนดชำระ'}</Text>
</View>
} */}
</View>
)
// }
}
_renderContent(data) {
let water_cost = 0;
let electrict_cost = 0;
let room_cost = 0;
let service_cost = 0;
let date_payment = '';
let extra_info = '';
let d = moment(data.created_at).format('D')
let m = moment(data.created_at).format('MM')
let y = parseInt(moment(data.created_at).format('Y')) + 543
date_payment = d + ' ' + this.getMonth(m) + ' ' + y
let descriptionRoom = '-'
let descriptionWater = '-'
let descriptionElec = '-'
let descriptionService = '-'
// console.log('check data ----------> ',data)
if(data.details){
data.details.map((det) => {
if(det.sequence === 1){
room_cost = det.cost
room_extra_info = det.extra_info != null ? det.extra_info : ''
descriptionRoom = det.descript == '' ? '-' : det.descript
}
if(det.sequence === 2){
water_cost = det.cost
water_extra_info = det.extra_info != null ? det.extra_info : ''
descriptionWater = det.descript == '' ? '-' : det.descript
}
if(det.sequence === 3){
electrict_cost = det.cost
electrict_extra_info = det.extra_info != null ? det.extra_info : ''
descriptionElec = det.descript == '' ? '-' : det.descript
}
if(det.sequence === 4){
service_cost = det.cost
service_extra_info = det.extra_info != null ? det.extra_info : ''
descriptionService = det.descript == '' ? '-' : det.descript
}
})
}
return (
<View>
{
data.details.map((info,index) => {
return <ItemOrder title={info.name} cost={info.cost} description={info.descript} key={'order_info_'+index} type={info.type}/>
})
}
<View style={{ height:50,width:'100%', backgroundColor:'#8BC34A',alignItems: 'flex-end',justifyContent:'center' }}>
<Text style={{ color: 'white',marginRight:15,fontSize:18 }}>รวม {data.total_cost} {t('baht')}</Text>
</View>
</View>
)
}
getDueDate (date) {
if(date){
let d = moment(date).format('D')
let m = moment(date).format('MM')
let y = parseInt(moment(date).format('Y')) + 543
let new_month = 'ม.ค.';
let new_date = d + ' ' + new_month + ' ' + y;
switch (m) {
case '01':
new_month = 'ม.ค.';
break;
case '02':
new_month = 'ก.พ.';
break;
case '03':
new_month = 'มี.ค.';
break;
case '04':
new_month = 'เม.ย.';
break;
case '05':
new_month = 'พ.ค.';
break;
case '06':
new_month = 'มิ.ย.';
break;
case '07':
new_month = 'ก.ค.';
break;
case '08':
new_month = 'ส.ค.';
break;
case '09':
new_month = 'ก.ย.';
break;
case '10':
new_month = 'ต.ค.';
break;
case '11':
new_month = 'พ.ย.';
break;
case '12':
new_month = 'ธ.ค.';
break;
default:
new_month = 'ม.ค.';
break;
}
new_date = d + ' ' + new_month + ' ' + y;
return new_date;
}else{
return '';
}
}
renderNativeItemImages = (item) => {
// console.log('check data item ',item)
return <View style={{width: width, alignItems: 'center', paddingTop: 10, paddingBottom: 40,height: 177,}}>
<View style={{width: '60%', height: '100%', backgroundColor: '#06ADB8', borderRadius: 5 }}>
<LinearGradient colors={['#4BAF3B', '#0e5e29']} style={{ flex:1, borderRadius: 5, height: 120,paddingBottom:10, justifyContent:'space-between'}}>
<View style={{ padding: 16,paddingBottom: 5,paddingTop:10 , borderRadius: 5}}>
<Text style={{ color: 'white', fontSize: 18 }}>{t('room')} {item.room}</Text>
<Text style={{ color: 'rgba(255, 255, 255, 0.65)', fontSize: 14 }}>{item.project && item.project.name}</Text>
<Text style={{ color: 'white' }}>{t('outstanding_balance')} <Text style={{ color: 'white' ,fontSize:18 }}>{item.total_cost} {t('baht')}</Text></Text>
</View>
{
item.due_at !== null
? (
<View style={{height:24,backgroundColor: '#FF2D55',justifyContent:'center',alignItems:'center'}}>
<Text style={{ fontSize: 12, color: 'white'}}>{t('please_pay_before')} {this.getDueDate(item.due_at)}</Text>
</View>
)
: null
}
</LinearGradient>
</View>
</View>
}
_onCarouselScroll(e) {
const scrollX = e.nativeEvent.contentOffset.x
this.setState({
activePage: Math.ceil(scrollX / width)
})
// console.log(e);
}
groupArrayOfObjects(list, key) {
return list.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
}
roomFilter(index){
let payment_exits = this.state.all_payment;
let another_room = this.state.room_number_array[index];
let payment_array = payment_exits.filter((obj)=>{
return Object.keys(obj).reduce((acc, curr)=>{
return obj.room_id === another_room
}, false);
});
this.state.payment = payment_array;
}
_keyExtractor = (item, index) => 'bill_'+index
render() {
return (
<SafeAreaView style={{flex: 1}}>
<ScrollView contentContainerStyle={styles.contentContainer}>
<View style={{ alignItems: 'center'}}>
{
this.state.sum_payment.length == 0 &&
<View style={{margin:16,width: '90%', height: 55,backgroundColor:'#00000080',justifyContent:'center',alignItems:'center',borderRadius:5}}>
<Text style={{fontSize:14,color:'white',textAlign:'center'}}>{this.props.user.room} {t('no_outstanding_balance')}</Text>
</View>
}
<FlatList
data={this.state.sum_payment}
renderItem={({ item }) => this.renderNativeItemImages(item)}
horizontal={true}
onScroll={this._onCarouselScroll}
onScrollEndDrag={this.roomFilter(this.state.activePage)}
pagingEnabled={true}
extraData={this.state}
keyExtractor={this._keyExtractor}
/>
<View style={{ position: 'absolute', bottom: 10, width: '100%', justifyContent: 'center', flexDirection: 'row' }}>
{this.state.sum_payment.map((item, i) => <View key={'sum_payment_'+i} style={[{ width: 10, height: 10, borderRadius: 5, backgroundColor: this.state.activePage == i ? '#269A21' : 'rgba(124, 187, 51, 0.3)', marginHorizontal: 4 }]}></View>)}
</View>
</View>
<View style={{flex:1}}>
<Accordion
dataArray={ this.state.payment }
expanded={this.state.payment.length - 1}
renderHeader={(data, expanded) => { return this._renderHeader(data, expanded) }}
renderContent={(data) => { return this._renderContent(data) }} />
</View>
</ScrollView>
<IndicatorLoading loadingVisible={this.state.isLoading}/>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
circleShapeView: {
width: 32,
height: 32,
borderRadius: 100,
justifyContent: 'center',
alignItems: 'center'
},
contentContainer: {
backgroundColor: '#EEFFD7',
paddingVertical: 0,
flexGrow: 1,
},
colorTextPayment: {
color: '#3AA40C'
}
})
const mapDisPatchToProps = state => ({
user: state.app.user
})
export default connect(mapDisPatchToProps)(BillScreen)