533 lines
23 KiB
TypeScript
533 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;
|
||
|
}
|
||
|
</style>
|
||
|
</head>
|
||
|
<body>
|
||
|
<div class="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">${(`sales order`).toUpperCase()}</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">Tanggal & Jam</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">Kode Sales</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">Nama</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">Alamat</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">No. Telp</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">Produk</div>
|
||
|
<div class="text-sm text-right w-[40px]">Qty</div>
|
||
|
<div class="text-sm text-right w-[150px]">Harga satuan</div>
|
||
|
<div class="text-sm text-right w-[150px]">Nominal</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">Jumlah Sebelum Pajak</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">Pajak</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}}>Nama</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}}>Alamat</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'}}>{(`produk`).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'}}>Pajak (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"}}>Diskon</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}>{(`lihat invoice`).toUpperCase()}</Text>
|
||
|
</TouchableOpacity>
|
||
|
<TouchableOpacity style={[styles.button, {
|
||
|
flex: 1
|
||
|
, flexDirection: "row"
|
||
|
, justifyContent: "center"
|
||
|
, alignItems: "center"
|
||
|
, backgroundColor:"red"
|
||
|
}]}>
|
||
|
<Text style={styles.buttonText}>{(`kirim ke`).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;
|