Files
nice-app-web/src/entities/common/ui/tax-invoice-sample.tsx
2025-11-15 16:38:27 +09:00

669 lines
34 KiB
TypeScript

import moment from 'moment';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { motion } from 'framer-motion';
import { snackBar } from '@/shared/lib';
import { toPng } from 'html-to-image';
import { useTranslation } from 'react-i18next';
import { useEffect, useState } from 'react';
import { NumericFormat } from 'react-number-format';
import { FilterMotionDuration, FilterMotionVariants } from '../model/constant';
import { RecipientInfo, SupplierInfo, TransactionDetails } from '@/entities/vat-return/model/types';
import '@/shared/ui/assets/css/style-tax-invoice.css';
import { useAppBridge } from '@/hooks/useAppBridge';
export interface TaxInvoiceSampleProps {
taxInvoiceSampleOn: boolean;
setTaxInvoiceSampleOn: (taxInvoiceSampleOn: boolean) => void;
supplierInfo?: SupplierInfo;
recipientInfo?: RecipientInfo;
issueDate?: string;
supplyAmount?: number;
taxAmount?: number
totalAmount?: number;
transactionDetails?: TransactionDetails;
};
export const TaxInvoiceSample = ({
taxInvoiceSampleOn,
setTaxInvoiceSampleOn,
supplierInfo,
recipientInfo,
issueDate,
supplyAmount,
taxAmount,
totalAmount,
transactionDetails
}: TaxInvoiceSampleProps) => {
const { t } = useTranslation();
const { isIOS, saveImage } = useAppBridge();
const [newSupplyAmount, setNewSupplyAmount] = useState<Array<string>>([]);
const [newTaxAmount, setNewTaxAmount] = useState<Array<string>>([]);
const downloadImage = async () => {
const section = document.getElementById('image-section') as HTMLElement;
try {
const imageDataUrl = await toPng(section);
const fileName = 'tax-invoice-' + moment().format('YYMMDDHHmmss');
// iOS 네이티브 환경인 경우 네이티브 브릿지 사용
if (isIOS) {
try {
// data:image/png;base64, 부분 제거하고 순수 base64 데이터만 추출
const base64Data = imageDataUrl.split(',')[1];
if (!base64Data) {
throw new Error('Failed to extract base64 data');
}
const result = await saveImage({
imageData: base64Data,
fileName: fileName + '.png',
mimeType: 'image/png'
});
if (result?.filePath) {
snackBar(t('common.imageSaved'), function(){
onClickToClose();
});
} else {
throw new Error('Failed to save image');
}
} catch (error) {
console.error('Native image save failed:', error);
snackBar(t('common.imageSaveFailed'));
}
} else {
// Android 또는 웹 환경인 경우 기존 방식 사용 (다운로드 링크)
const link = document.createElement('a');
link.download = fileName + '.png';
link.href = imageDataUrl + '#' + fileName + '.png';
link.click();
snackBar(t('common.imageRequested'), function(){
onClickToClose();
});
}
} catch (error) {
console.error('Image generation failed:', error);
snackBar(t('common.imageGenerationFailed'));
}
};
const onClickToClose = () => {
setTaxInvoiceSampleOn(false);
};
const showNewSupplyAmount = () => {
let rs = [];
let emptyCnt = 11 - newSupplyAmount.length;
for(let i=0;i<emptyCnt;i++){
rs.push(
<td className="inner-table10-td2">&nbsp</td>
);
}
for(let i=0;i<newSupplyAmount.length;i++){
let str = newSupplyAmount[i];
rs.push(
<td className="inner-table10-td2">{ str }</td>
);
}
return rs;
};
const showNewTaxAmount = () => {
let rs = [];
let emptyCnt = 10 - newTaxAmount.length;
for(let i=0;i<emptyCnt;i++){
rs.push(
<td className="inner-table10-td2">&nbsp</td>
);
}
for(let i=0;i<newTaxAmount.length;i++){
let str = newTaxAmount[i];
rs.push(
<td className="inner-table10-td2">{ str }</td>
);
}
return rs;
};
const refactSupplyAmount = () => {
let supplyAmountArr: Array<string> = [];
if(supplyAmount){
let newSupplyAmt = ''+supplyAmount;
supplyAmountArr = newSupplyAmt.split('');
}
setNewSupplyAmount(supplyAmountArr);
};
const refactTaxAmount = () => {
let taxAmountArr: Array<string> = [];
if(taxAmount){
let newTaxAmt = ''+taxAmount;
taxAmountArr = newTaxAmt.split('');
}
setNewTaxAmount(taxAmountArr);
};
useEffect(() => {
if(!!taxInvoiceSampleOn){
setTimeout(() => {
downloadImage();
}, 500);
}
}, [taxInvoiceSampleOn]);
useEffect(() => {
refactSupplyAmount();
refactTaxAmount();
}, []);
return (
<>
<div className="tax-invoice">
<div id="image-section">
<center className="wrap-center">
<table
className="outer-table"
role="presentation"
>
<tr>
<td
className="outer-table-td"
align="center"
>
<table
className="inner-table"
role="presentation"
>
<tr>
<td className="inner-table-td1">
<img
className="nicepay-logo"
src={ IMAGE_ROOT + '/mail_nicepay_logo.svg' }
alt="NICEPAY"
style={{ paddingLeft: '20px' }}
/>
</td>
</tr>
<tr>
<td style={{ padding: 0 }}>
<table
className="inner-table3"
role="presentation"
>
<tr>
<td className="inner-table3-td1">
<table
className="inner-table4"
role="presentation"
>
<tr>
<td className="inner-table4-td1"></td>
</tr>
</table>
</td>
</tr>
<tr>
<td className="inner-table4-td2">
<table
className="inner-table5"
role="presentation"
>
<tr>
<td className="inner-table5-td1"></td>
<td className="inner-table5-td2">
<table
className="inner-table6"
role="presentation"
>
<tr>
<td className="inner-table6-td1"></td>
<td className="inner-table6-td2">&nbsp;</td>
</tr>
<tr>
<td className="inner-table6-td3"></td>
<td className="inner-table6-td4">&nbsp;</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td className="inner-table4-td2">
<table
className="inner-table7"
role="presentation"
>
<tr>
<td className="inner-table7-td1">
<table
className="inner-table6"
role="presentation"
>
<tr>
<td className="inner-table6-td5">
<br /><br />
</td>
<td className="inner-table6-td6">
<table
className="inner-table6"
role="presentation"
>
<tr>
<td className="inner-table6-td7"></td>
<td
className="inner-table6-td8"
colSpan={ 3 }
>{ supplierInfo?.businessRegistrationNumber }</td>
</tr>
<tr>
<td className="inner-table6-td7">()</td>
<td className="inner-table6-td9">{ supplierInfo?.companyName }</td>
<td className="inner-table6-td10"></td>
<td className="inner-table6-td8">{ supplierInfo?.ceoName }</td>
</tr>
<tr>
<td className="inner-table6-td7"> </td>
<td
className="inner-table6-td8"
colSpan={ 3 }
>{ supplierInfo?.address }</td>
</tr>
<tr>
<td className="inner-table6-td7-1"></td>
<td className="inner-table6-td9-1">{ supplierInfo?.businessType }</td>
<td className="inner-table6-td10-1"></td>
<td className="inner-table6-td8-1">{ supplierInfo?.businessItem }</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td className="inner-table7-td2">
<table
className="inner-table6"
role="presentation"
>
<tr>
<td className="inner-table6-td11">
<br /><br /><br /><br />
</td>
<td className="inner-table6-td12">
<table
className="inner-table6"
>
<tr>
<td className="inner-table6-td7"></td>
<td
className="inner-table6-td8"
colSpan={ 3 }
>{ recipientInfo?.businessRegistrationNumber }</td>
</tr>
<tr>
<td className="inner-table6-td7">()</td>
<td className="inner-table6-td9">{ recipientInfo?.companyName }</td>
<td className="inner-table6-td10"></td>
<td className="inner-table6-td8">{ recipientInfo?.ceoName }</td>
</tr>
<tr>
<td className="inner-table6-td7"> </td>
<td
className="inner-table6-td8"
colSpan={ 3 }
>{ recipientInfo?.address }</td>
</tr>
<tr>
<td className="inner-table6-td7-1"></td>
<td className="inner-table6-td9-1">{ recipientInfo?.businessType }</td>
<td className="inner-table6-td10-1"></td>
<td className="inner-table6-td8-1">{ recipientInfo?.businessItem }</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td className="inner-table4-td2">
<table
className="inner-table8"
role="presentation"
>
<tr>
<td className="inner-table8-td1">
<table
className="inner-table9"
role="presentation"
>
<tr>
<td className="inner-table9-td1"></td>
</tr>
<tr>
<td style={{ padding: 0 }}>
<table
className="inner-table9"
role="presentation"
>
<tr>
<td className="inner-table9-td2"></td>
<td className="inner-table9-td2"></td>
<td className="inner-table9-td2"></td>
</tr>
<tr>
<td className="inner-table9-td2-1">{ (!!issueDate)? moment(issueDate).format('YYYY'): '' }</td>
<td className="inner-table9-td2-1">{ (!!issueDate)? moment(issueDate).format('MM'): '' }</td>
<td className="inner-table9-td2-1">{ (!!issueDate)? moment(issueDate).format('DD'): '' }</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td className="inner-table9-td3">
<table
className="inner-table10"
role="presentation"
>
<tr>
<td className="inner-table9-td1"></td>
</tr>
<tr>
<td style={{ padding: 0 }}>
<table
className="inner-table10"
role="presentation"
>
<tr>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
</tr>
<tr>
{ showNewSupplyAmount() }
</tr>
</table>
</td>
</tr>
</table>
</td>
<td className="inner-table9-td3">
<table
className="inner-table10"
role="presentation"
>
<tr>
<td className="inner-table9-td1"></td>
</tr>
<tr>
<td style={{ padding:0 }}>
<table
className="inner-table10"
role="presentation"
>
<tr>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
<td className="inner-table10-td1"></td>
</tr>
<tr>
{ showNewTaxAmount() }
</tr>
</table>
</td>
</tr>
</table>
</td>
<td className="inner-table9-td4">
<table
role="presentation"
className="inner-table11"
>
<tr>
<td className="inner-table11-td1"></td>
</tr>
<tr>
<td className="inner-table11-td2">&nbsp;</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td className="inner-table4-td2">
<table
role="presentation"
className="inner-table12"
>
<tr>
<td className="inner-table12-td1">
<table className="inner-table13">
<tr>
<td className="inner-table13-td1"></td>
</tr>
<tr>
<td className="inner-table13-td1">/</td>
</tr>
<tr>
<td className="inner-table13-td2">{ (!!transactionDetails?.transactionPeriod)? moment(transactionDetails.transactionPeriod).format('MM/DD'): '' }</td>
</tr>
<tr>
<td className="inner-table13-td2">&nbsp</td>
</tr>
<tr>
<td className="inner-table13-td3">&nbsp</td>
</tr>
</table>
</td>
<td className="inner-table12-td2">
<table
role="presentation"
className="inner-table6"
>
<tr>
<td
colSpan={ 7 }
className="inner-table11-td1"
> </td>
</tr>
<tr>
<td className="inner-table9-td1"></td>
<td className="inner-table9-td1"></td>
<td className="inner-table9-td1"></td>
<td className="inner-table9-td1"></td>
<td className="inner-table9-td1"></td>
<td className="inner-table9-td1"></td>
<td className="inner-table11-td1"></td>
</tr>
<tr>
<td className="inner-table6-td9">{ transactionDetails?.itemName }</td>
<td className="inner-table6-td9">{ transactionDetails?.specification }</td>
<td className="inner-table6-td13">
<NumericFormat
value={ transactionDetails?.quantity }
thousandSeparator
displayType="text"
></NumericFormat>
</td>
<td className="inner-table6-td14">
<NumericFormat
value={ transactionDetails?.unitPrice }
thousandSeparator
displayType="text"
></NumericFormat>
</td>
<td className="inner-table6-td14">
<NumericFormat
value={ transactionDetails?.supplyAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</td>
<td className="inner-table6-td14">
<NumericFormat
value={ transactionDetails?.taxAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</td>
<td className="inner-table6-td15">{ transactionDetails?.remarks }</td>
</tr>
<tr>
<td className="inner-table6-td9">&nbsp;</td>
<td className="inner-table6-td9">&nbsp;</td>
<td className="inner-table6-td13">&nbsp;</td>
<td className="inner-table6-td14">&nbsp;</td>
<td className="inner-table6-td14">&nbsp;</td>
<td className="inner-table6-td14">&nbsp;</td>
<td className="inner-table6-td15">&nbsp;</td>
</tr>
<tr>
<td className="inner-table6-td9-1">&nbsp;</td>
<td className="inner-table6-td9-1">&nbsp;</td>
<td className="inner-table6-td13-1">&nbsp;</td>
<td className="inner-table6-td14-1">&nbsp;</td>
<td className="inner-table6-td14-1">&nbsp;</td>
<td className="inner-table6-td14-1">&nbsp;</td>
<td className="inner-table6-td15-1">&nbsp;</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td className="table_wrap">
<table
className="inner-table6"
role="presentation"
>
<tr>
<td className="inner-table4-td2">
<table
className="inner-table15"
role="presentation"
>
<tr>
<td className="inner-table15-td1">
<table
className="inner-table6"
role="presentation"
>
<tr>
<td className="inner-table15-td2"></td>
<td className="inner-table15-td2"></td>
<td className="inner-table15-td2"></td>
<td className="inner-table15-td2"></td>
<td className="inner-table15-td4"></td>
</tr>
<tr>
<td className="inner-table15-td3">
<NumericFormat
value={ totalAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</td>
<td className="inner-table15-td3">
<NumericFormat
value={ 0 }
thousandSeparator
displayType="text"
></NumericFormat>
</td>
<td className="inner-table15-td3">
<NumericFormat
value={ 0 }
thousandSeparator
displayType="text"
></NumericFormat>
</td>
<td className="inner-table15-td3">
<NumericFormat
value={ 0 }
thousandSeparator
displayType="text"
></NumericFormat>
</td>
<td className="inner-table15-td5"><NumericFormat
value={ 0 }
thousandSeparator
displayType="text"
></NumericFormat></td>
</tr>
</table>
</td>
<td className="inner-table15-td6">
<span className="inner-table15-td7"> </span>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td className="inner-table4-td4">
<table
className="inner-table14"
role="presentation"
>
<tr>
<td
className="inner-table4-td2"
style={{ verticalAlign: 'middle'}}
>
<img
className="nicepay-gray-logo"
src={ IMAGE_ROOT + '/mail_nicepay_logo_gray.svg' }
alt="NICEPAY"
/>
</td>
<td className="tax-invoice-footer">
등록번호 : 815-81-00527 | 등록번호 : 02-006-00041
<br />
주소 : 서울특별시 28 25 (3) N타워 9 ()
<br />
우편번호 : 03456 | www.nicepay.co.kr
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</center>
</div>
</div>
</>
);
};