536 lines
23 KiB
TypeScript
536 lines
23 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { ImageBackground } from 'react-native';
|
|
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, PermissionsAndroid } from 'react-native';
|
|
import { BluetoothManager, BluetoothEscposPrinter, BluetoothTscPrinter } from 'react-native-bluetooth-escpos-printer';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import * as Print from 'expo-print';
|
|
|
|
const requestBlueToothConnect = async () => {
|
|
try {
|
|
const granted = await PermissionsAndroid.request(
|
|
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
|
|
{
|
|
title: 'Cool Photo App Camera Permission',
|
|
message:
|
|
'Cool Photo App needs access to your camera ' +
|
|
'so you can take awesome pictures.',
|
|
buttonNeutral: 'Ask Me Later',
|
|
buttonNegative: 'Cancel',
|
|
buttonPositive: 'OK',
|
|
},
|
|
);
|
|
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
|
console.log('You can use bluetooth connect');
|
|
} else {
|
|
console.log('Camera permission denied');
|
|
}
|
|
} catch (err) {
|
|
console.warn(err);
|
|
}
|
|
};
|
|
const requestBlueToothScan = async () => {
|
|
try {
|
|
const granted = await PermissionsAndroid.request(
|
|
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
|
|
{
|
|
title: 'Cool Photo App Camera Permission',
|
|
message:
|
|
'Cool Photo App needs access to your camera ' +
|
|
'so you can take awesome pictures.',
|
|
buttonNeutral: 'Ask Me Later',
|
|
buttonNegative: 'Cancel',
|
|
buttonPositive: 'OK',
|
|
},
|
|
);
|
|
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
|
console.log('You can use bluetooth scan');
|
|
} else {
|
|
console.log('Camera permission denied');
|
|
}
|
|
} catch (err) {
|
|
console.warn(err);
|
|
}
|
|
};
|
|
const requestAccessFine = async () => {
|
|
try {
|
|
const granted = await PermissionsAndroid.request(
|
|
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
|
|
{
|
|
title: 'Cool Photo App Camera Permission',
|
|
message:
|
|
'Cool Photo App needs access to your camera ' +
|
|
'so you can take awesome pictures.',
|
|
buttonNeutral: 'Ask Me Later',
|
|
buttonNegative: 'Cancel',
|
|
buttonPositive: 'OK',
|
|
},
|
|
);
|
|
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
|
console.log('You can use bluetooth scan');
|
|
} else {
|
|
console.log('Camera permission denied');
|
|
}
|
|
} catch (err) {
|
|
console.warn(err);
|
|
}
|
|
};
|
|
|
|
const formatNumber = function (number: any) {
|
|
return number.toLocaleString('id-ID', {
|
|
minimumFractionDigits: 0,
|
|
maximumFractionDigits: 0
|
|
});
|
|
}
|
|
const ListProduk = function (prop:any) {
|
|
let data = prop.data
|
|
return <>
|
|
{data && Array.isArray(data) && data.map((s:any, k:any) => <>
|
|
<View style={{
|
|
flexDirection:"row",
|
|
marginBottom:10
|
|
}} key={k}>
|
|
<View style={{paddingHorizontal:10}}>
|
|
<Text style={{fontSize:24, fontWeight:'bold'}}>{s?.name}</Text>
|
|
<Text style={{ fontSize: 14, fontWeight: '600', color: "#333" }}>Rp {formatNumber(Number(s.harga))} / {s?.satuan}</Text>
|
|
<View style={{flexDirection:"row"}}>
|
|
<Text style={{fontWeight:"bold"}}>Quantity : </Text>
|
|
<Text style={{color:"red", fontWeight:"bold"}}>{s?.qty} {s?.satuan}</Text>
|
|
</View>
|
|
</View>
|
|
<View style={{
|
|
flex:1
|
|
, flexDirection : "row"
|
|
, alignItems : "flex-end"
|
|
, justifyContent : "flex-end"
|
|
}}>
|
|
<Text style={{ fontWeight: '600', fontSize: 20 }}>Rp {formatNumber(Number(s.qty) * Number(s.harga))}</Text>
|
|
</View>
|
|
</View>
|
|
</>)}
|
|
</>
|
|
}
|
|
|
|
const DetailOrder = ({ act, config, order, orderlist}: any) => {
|
|
|
|
const [showBlue, setShowBlue] = useState(false);
|
|
const [blueList, setBlueList] = useState('');
|
|
|
|
const printStruk = async function(){
|
|
|
|
const html = `
|
|
<html>
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
|
|
<style>
|
|
*{
|
|
font-size:18px;
|
|
margin:0;
|
|
padding:0;
|
|
margin-bottom:1.5px;
|
|
}
|
|
.grid{
|
|
display:grid;
|
|
}
|
|
.border-b-2{
|
|
border-bottom : 1px solid #ddd;
|
|
display : grid;
|
|
grid-template-columns : auto auto auto auto;
|
|
}
|
|
.text-2xl{
|
|
font-size: 24px;
|
|
}
|
|
.text-xl{
|
|
font-size: 20px;
|
|
}
|
|
.mb-3{
|
|
margin-bottom:30px;
|
|
}
|
|
.mb-6{
|
|
margin-bottom:40px;
|
|
}
|
|
.text-right{
|
|
text-align:right;
|
|
}
|
|
.text-center{
|
|
text-align:center;
|
|
}
|
|
.text-left{
|
|
text-align:left;
|
|
}
|
|
.mt-5{
|
|
margin-top: 40px;
|
|
}
|
|
.p-10{
|
|
padding: 40px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="p-10 rounded-md bg-white p-[20px] min-h-[calc(100%)]">
|
|
<div class="grid grid-cols-1 text-gray-600 font-semibold gap-4 mb-5">
|
|
<div>
|
|
<h1 class="text-2xl font-bold">CV. KBS</h1>
|
|
<p class="text-sm mb-3">Jl. Mangga No 10, DENPASAR</p>
|
|
|
|
<div class="grid text-gray-600 font-semibold gap-4" style="grid-template-columns: 130px 5px auto">
|
|
<h1 class="text-sm">ORDER CODE</h1>
|
|
<span class="text-sm">:</span>
|
|
<h1 class="text-sm font-bold">S00030</h1>
|
|
</div>
|
|
<div class="grid text-gray-600 font-semibold gap-4" style="grid-template-columns: 130px 5px auto">
|
|
<h1 class="text-sm">DATE & TIME</h1>
|
|
<span class="text-sm">:</span>
|
|
<h1 class="text-sm">30/07/2024 12:30:00</h1>
|
|
</div>
|
|
<div class="grid text-gray-600 font-semibold gap-4" style="grid-template-columns: 130px 5px auto">
|
|
<h1 class="text-sm">SALES CODE</h1>
|
|
<span class="text-sm">:</span>
|
|
<h1 class="text-sm">SALES-0001</h1>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-1 text-gray-600 font-semibold gap-4">
|
|
<div>
|
|
<h1 class="text-md">CUSTOMER</h1>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<div class="grid grid-cols-1 text-gray-600 font-semibold gap-4 mb-6">
|
|
<div>
|
|
<div class="grid text-gray-600 font-semibold gap-4" style="grid-template-columns: 130px 5px auto">
|
|
<h1 class="text-sm">NAME</h1>
|
|
<span class="text-sm">:</span>
|
|
<h1 class="text-sm">Eddy Brock</h1>
|
|
</div>
|
|
<div class="grid text-gray-600 font-semibold gap-4" style="grid-template-columns: 130px 5px auto">
|
|
<h1 class="text-sm">ADDRESS</h1>
|
|
<span class="text-sm">:</span>
|
|
<h1 class="text-sm">-</h1>
|
|
</div>
|
|
<div class="grid text-gray-600 font-semibold gap-4" style="grid-template-columns: 130px 5px auto">
|
|
<h1 class="text-sm">PHONE NUMBER</h1>
|
|
<span class="text-sm">:</span>
|
|
<h1 class="text-sm">-</h1>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="border-b-2">
|
|
<div class="text-sm text-left">PRODUCT</div>
|
|
<div class="text-sm text-right w-[40px]">QTY</div>
|
|
<div class="text-sm text-right w-[150px]">UNIT PRICE</div>
|
|
<div class="text-sm text-right w-[150px]">AMOUNT</div>
|
|
</div>
|
|
<div class="border-b-2">
|
|
<div class="text-sm text-left">A1-F12</div>
|
|
<div class="text-sm text-right">2</div>
|
|
<div class="text-sm text-right">1.550.500</div>
|
|
<div class="text-sm text-right">3.100.000</div>
|
|
</div>
|
|
<div class="grid mt-5" class="grid" style="grid-template-columns: 160px auto">
|
|
<div></div>
|
|
<div class="grid" style="border-bottom:1px solid #ddd;grid-template-columns: 200px auto">
|
|
<div class="text-sm font-bold">SUBTOTAL BEFORE TAX</div>
|
|
<div class="text-sm text-right">Rp 3.100.000</div>
|
|
</div>
|
|
</div>
|
|
<div class="grid" class="grid" style="grid-template-columns: 160px auto">
|
|
<div></div>
|
|
<div class="grid" style="border-bottom:1px solid #ddd;grid-template-columns: 200px auto">
|
|
<div class="text-sm">TAX</div>
|
|
<div class="text-sm text-right">Rp 341.000</div>
|
|
</div>
|
|
</div>
|
|
<div class="grid" class="grid" style="grid-template-columns: 160px auto">
|
|
<div></div>
|
|
<div class="grid" style="border-bottom:1px solid #ddd;grid-template-columns: 200px auto">
|
|
<div class="text-sm font-bold">TOTAL</div>
|
|
<div class="text-sm text-right">Rp 3.441.000</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
await Print.printAsync({
|
|
html,
|
|
// printerUrl: selectedPrinter?.url, // iOS only
|
|
});
|
|
/*
|
|
await requestBlueToothConnect();
|
|
await requestBlueToothScan();
|
|
await requestAccessFine();
|
|
setShowBlue(true)
|
|
BluetoothManager.isBluetoothEnabled().then((enabled:any) => {
|
|
if(enabled){
|
|
BluetoothManager.scanDevices()
|
|
.then((s:any) => {
|
|
console.log(s);
|
|
setBlueList(JSON.stringify(s))
|
|
}, (er:any) => {
|
|
console.log(er)
|
|
});
|
|
}
|
|
});
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
return (
|
|
<>
|
|
{showBlue?<>
|
|
<View style={{
|
|
position:"absolute"
|
|
, bottom:0
|
|
, width:'100%'
|
|
, zIndex:1
|
|
, height:200
|
|
, backgroundColor:"white"
|
|
}}>
|
|
<View style={{
|
|
flexDirection:"row"
|
|
, height: 50
|
|
, alignItems:"center"
|
|
, justifyContent:"center"
|
|
, backgroundColor: config.color.primary
|
|
}}>
|
|
<Ionicons name={'bluetooth'} style={{color:'white', fontSize:20}} />
|
|
<Text style={{
|
|
textAlign : 'center'
|
|
, fontSize : 16
|
|
, fontWeight : "600"
|
|
, color:"white"
|
|
}}>{(`bluetooth`).toUpperCase()}</Text>
|
|
</View>
|
|
<View>
|
|
<Text>{blueList}</Text>
|
|
</View>
|
|
</View>
|
|
</>:<></>}
|
|
<View style={{backgroundColor:'white', flexDirection: "column", height: "100%" }}>
|
|
<View style={{
|
|
overflow:"hidden",
|
|
height:120,
|
|
flexDirection:"row",
|
|
alignItems:"flex-end"
|
|
}}>
|
|
<ImageBackground
|
|
source={require('../../assets/images/bg/SORT_bg_Order.png')}
|
|
style={{
|
|
flexDirection: "row"
|
|
, alignItems: 'flex-end'
|
|
, top: 0
|
|
, height: 300
|
|
}}
|
|
>
|
|
<View style={[{ paddingVertical: 20, paddingBottom: 30, width: "100%" }]}>
|
|
<Text style={{
|
|
textAlign:"center"
|
|
, fontSize:24
|
|
, fontWeight:'bold'
|
|
, color:"white"
|
|
, marginBottom:5
|
|
}}>{(`detail Order`).toUpperCase()}</Text>
|
|
</View>
|
|
</ImageBackground>
|
|
</View>
|
|
<View style={{ }}>
|
|
<TouchableOpacity onPress={()=>{
|
|
act(false);
|
|
}}>
|
|
<View style={{width:80, marginHorizontal:10, borderRadius:10, padding:8, backgroundColor:config.color.primary}}>
|
|
<Text style={{textAlign:'center', color:"white"}}>{`< Back`}</Text>
|
|
</View>
|
|
</TouchableOpacity>
|
|
</View>
|
|
<View style={{ flex: 1}}>
|
|
<ScrollView>
|
|
<View style={{paddingHorizontal:20,borderBottomWidth:1, borderBottomColor:"#ddd",paddingVertical:10}}>
|
|
<Text style={{fontSize:20, marginBottom:20, fontWeight:'bold'}}>Order : {order?.name}</Text>
|
|
<Text style={{ fontSize: 20, fontWeight:'bold' }}>Customer</Text>
|
|
</View>
|
|
<View style={{ paddingHorizontal: 20, paddingVertical: 5 }}>
|
|
<View style={{flexDirection:"row"}}>
|
|
<Text style={{width:70}}>Name</Text>
|
|
<Text style={{width:10}}>:</Text>
|
|
<Text style={{flex:1}}>{(order?.cus).toUpperCase()}</Text>
|
|
</View>
|
|
<View style={{flexDirection:"row"}}>
|
|
<Text style={{width:70}}>Email</Text>
|
|
<Text style={{width:10}}>:</Text>
|
|
<Text style={{ flex: 1 }}>{(order?.email)}</Text>
|
|
</View>
|
|
<View style={{flexDirection:"row"}}>
|
|
<Text style={{width:70}}>Address</Text>
|
|
<Text style={{width:10}}>:</Text>
|
|
<Text style={{ flex: 1 }}>{(order?.street)}</Text>
|
|
</View>
|
|
</View>
|
|
<Text style={{ paddingHorizontal: 20,marginTop:25, fontSize:18, fontWeight:'bold'}}>{(`products`).toUpperCase()}</Text>
|
|
<View style={{padding:20, minHeight:70, backgroundColor:"#eee"}}>
|
|
<ListProduk data={orderlist && Array.isArray(orderlist) ? orderlist.map(function(o:any){
|
|
return {
|
|
name: o.name
|
|
, harga: o.price_unit
|
|
, qty: o.qty
|
|
, satuan: o.satuan
|
|
}
|
|
}) : [
|
|
{
|
|
name: "A1-f12"
|
|
, harga : 15000
|
|
, qty : 10
|
|
, satuan : "SLOP"
|
|
}
|
|
,{
|
|
name: "A1-K12"
|
|
, harga : 15000
|
|
, qty : 10
|
|
, satuan : "SLOP"
|
|
}
|
|
]} />
|
|
</View>
|
|
<View style={{padding:20}}>
|
|
<Text style={{fontSize:18, fontWeight:'bold'}}>{(`Detail Order`).toUpperCase()}</Text>
|
|
<View style={{
|
|
minHeight:80
|
|
, backgroundColor:"#fff"
|
|
, shadowColor:"#333"
|
|
, shadowOpacity:0.3
|
|
, shadowRadius:10
|
|
, elevation:10
|
|
, borderRadius:10
|
|
, marginTop:10
|
|
, paddingHorizontal:10
|
|
, paddingVertical:15
|
|
, shadowOffset: { width: 0, height: 2 } // {{ edit_1 }}
|
|
}}>
|
|
<View>
|
|
<View style={{
|
|
flexDirection: 'row',
|
|
alignItems:'center'
|
|
}}>
|
|
<Text style={{fontSize:18, flex:1, fontWeight:'600'}}>Sub Total</Text>
|
|
<Text style={{ fontWeight: '500', fontSize: 20, width: 200, textAlign: 'right' }}>Rp {(formatNumber(Number(order?.amount_untaxed)))}</Text>
|
|
</View>
|
|
<View style={{
|
|
flexDirection: 'row',
|
|
alignItems:'center'
|
|
}}>
|
|
<Text style={{fontSize:18, flex:1, fontWeight:'600'}}>Tax (11%)</Text>
|
|
<Text style={{ fontWeight: '500', fontSize: 20, width: 200, textAlign: 'right' }}>Rp {(formatNumber(Number(order?.amount_tax)))}</Text>
|
|
</View>
|
|
<View style={{
|
|
flexDirection: 'row',
|
|
alignItems:'center'
|
|
}}>
|
|
<Text style={{fontSize:18, flex:1, fontWeight:'600', color:"red"}}>Discount</Text>
|
|
<Text style={{ fontWeight:'500', fontSize: 20, width: 200, textAlign: 'right' }}>-</Text>
|
|
</View>
|
|
<View style={{
|
|
flexDirection: 'row',
|
|
alignItems: 'center'
|
|
}}>
|
|
<Text style={{ fontSize: 20, flex: 1, fontWeight: '600' }}>TOTAL</Text>
|
|
<Text style={{ fontWeight: 'bold', fontSize: 22, width: 200, textAlign: 'right' }}>Rp {(formatNumber(Number(order?.amount_total)))}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</ScrollView>
|
|
</View>
|
|
<View style={{ flexDirection: "row", height: 80, backgroundColor: "white" }}>
|
|
<TouchableOpacity onPress={printStruk} style={[styles.button, {
|
|
flex: 1
|
|
, flexDirection: "row"
|
|
, justifyContent: "center"
|
|
, alignItems: "center"
|
|
, backgroundColor: config.color.primary
|
|
}]}>
|
|
<Text style={styles.buttonText}>{(`PRINT`).toUpperCase()}</Text>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity style={[styles.button, {
|
|
flex: 1
|
|
, flexDirection: "row"
|
|
, justifyContent: "center"
|
|
, alignItems: "center"
|
|
, backgroundColor:config.color.primary
|
|
}]}>
|
|
<Text style={styles.buttonText}>{(`VIEW INVOICE`).toUpperCase()}</Text>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity style={[styles.button, {
|
|
flex: 1
|
|
, flexDirection: "row"
|
|
, justifyContent: "center"
|
|
, alignItems: "center"
|
|
, backgroundColor:"red"
|
|
}]}>
|
|
<Text style={styles.buttonText}>{(`Send`).toUpperCase()}</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
</>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
title: {
|
|
fontSize: 32,
|
|
fontWeight: 'bold',
|
|
marginVertical: 10,
|
|
},
|
|
date: {
|
|
fontSize: 16,
|
|
color: '#888',
|
|
marginBottom: 20,
|
|
},
|
|
info: {
|
|
marginBottom: 20,
|
|
},
|
|
infoText: {
|
|
fontSize: 16,
|
|
marginBottom: 5,
|
|
},
|
|
divider: {
|
|
borderBottomColor: '#000',
|
|
borderBottomWidth: 1,
|
|
marginVertical: 10,
|
|
},
|
|
itemRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
marginVertical: 5,
|
|
},
|
|
itemText: {
|
|
fontSize: 18,
|
|
},
|
|
itemTextSatuan: {
|
|
fontSize: 18,
|
|
textAlign: 'center'
|
|
},
|
|
totalRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
marginVertical: 10,
|
|
},
|
|
totalText: {
|
|
fontSize: 24,
|
|
fontWeight: 'bold',
|
|
},
|
|
button: {
|
|
borderRadius: 8,
|
|
padding: 4,
|
|
alignItems: 'center',
|
|
marginHorizontal: 5,
|
|
marginVertical:10,
|
|
height: 50
|
|
},
|
|
buttonText: {
|
|
color: '#fff',
|
|
fontSize: 16,
|
|
fontWeight: 'bold',
|
|
},
|
|
});
|
|
|
|
export default DetailOrder; |