useAppBridge Hook 패턴으로 이미지 저장 기능 개선

iOS 웹뷰에서 이미지 다운로드를 위한 네이티브 브릿지 기능을
React Hook 패턴으로 리팩토링하여 일관성과 재사용성 개선

변경사항:
- useAppBridge Hook에 saveImage 메서드 추가
- utils/appBridge.ts에 saveImage 메서드 구현
- 세 개의 샘플 컴포넌트에서 useAppBridge Hook 사용
  * cash-receipt-sample.tsx
  * deposit-receipt-sample.tsx
  * tax-invoice-sample.tsx
- 직접 appBridge import 제거, Hook 패턴으로 통일
- TypeScript 타입 안전성 개선 (null 체크 추가)

기술 개선:
- React Hook 패턴으로 컴포넌트 라이프사이클과 통합
- safeCall을 통한 자동 에러 처리
- iOS 환경에서만 네이티브 브릿지 사용
- Android/웹은 기존 다운로드 방식 유지

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jay Sheen
2025-11-12 16:26:23 +09:00
parent a1d01e68e4
commit 662e76af96
5 changed files with 133 additions and 31 deletions

View File

@@ -9,6 +9,7 @@ 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;
@@ -34,18 +35,56 @@ export const TaxInvoiceSample = ({
transactionDetails
}: TaxInvoiceSampleProps) => {
const { t } = useTranslation();
const { isIOS, saveImage } = useAppBridge();
const downloadImage = () => {
const downloadImage = async () => {
const section = document.getElementById('image-section') as HTMLElement;
toPng(section).then((image) => {
const link = document.createElement('a');
link.download = 'downloadImage.png';
link.href = image;
link.click();
snackBar(t('common.imageRequested'), function(){
onClickToClose();
});
});
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?.success) {
snackBar(t('common.imageSaved'), function(){
onClickToClose();
});
} else {
throw new Error(result?.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);