react-native-rectangle-doc-scanner 3.115.0 → 3.118.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FullDocScanner.js +53 -56
- package/package.json +1 -1
- package/src/FullDocScanner.tsx +73 -85
package/dist/FullDocScanner.js
CHANGED
|
@@ -125,19 +125,13 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
125
125
|
const [rotationDegrees, setRotationDegrees] = (0, react_1.useState)(0);
|
|
126
126
|
const [capturedPhotos, setCapturedPhotos] = (0, react_1.useState)([]);
|
|
127
127
|
const [currentPhotoIndex, setCurrentPhotoIndex] = (0, react_1.useState)(0);
|
|
128
|
-
const [previewPhotoIndex, setPreviewPhotoIndex] = (0, react_1.useState)(0);
|
|
129
128
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
130
129
|
const docScannerRef = (0, react_1.useRef)(null);
|
|
131
130
|
const captureModeRef = (0, react_1.useRef)(null);
|
|
132
131
|
const captureInProgressRef = (0, react_1.useRef)(false);
|
|
133
132
|
const rectangleCaptureTimeoutRef = (0, react_1.useRef)(null);
|
|
134
133
|
const rectangleHintTimeoutRef = (0, react_1.useRef)(null);
|
|
135
|
-
const currentPhotoIndexRef = (0, react_1.useRef)(currentPhotoIndex);
|
|
136
134
|
const isBusinessMode = type === 'business';
|
|
137
|
-
const maxPhotos = isBusinessMode ? 2 : 1;
|
|
138
|
-
(0, react_1.useEffect)(() => {
|
|
139
|
-
currentPhotoIndexRef.current = currentPhotoIndex;
|
|
140
|
-
}, [currentPhotoIndex]);
|
|
141
135
|
const mergedStrings = (0, react_1.useMemo)(() => ({
|
|
142
136
|
captureHint: strings?.captureHint,
|
|
143
137
|
manualHint: strings?.manualHint,
|
|
@@ -190,7 +184,6 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
190
184
|
hasBase64: !!croppedImage.data,
|
|
191
185
|
});
|
|
192
186
|
setProcessing(false);
|
|
193
|
-
setPreviewPhotoIndex(currentPhotoIndexRef.current);
|
|
194
187
|
// Show confirmation screen
|
|
195
188
|
setCroppedImageData({
|
|
196
189
|
path: croppedImage.path,
|
|
@@ -237,8 +230,6 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
237
230
|
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
238
231
|
return;
|
|
239
232
|
}
|
|
240
|
-
const previewIndex = currentPhotoIndexRef.current;
|
|
241
|
-
setPreviewPhotoIndex(previewIndex);
|
|
242
233
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
243
234
|
if (captureMode === 'no-grid') {
|
|
244
235
|
console.log('[FullDocScanner] No grid at capture button press: opening cropper for manual selection');
|
|
@@ -400,21 +391,25 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
400
391
|
rotationDegrees: rotationNormalized,
|
|
401
392
|
};
|
|
402
393
|
const updatedPhotos = [...capturedPhotos, currentPhoto];
|
|
403
|
-
console.log('[FullDocScanner] Photos captured:', updatedPhotos.length
|
|
404
|
-
//
|
|
405
|
-
|
|
406
|
-
// 두 번째 사진 촬영 여부를 물어봄 (UI에서 버튼으로 표시)
|
|
407
|
-
setCapturedPhotos(updatedPhotos);
|
|
408
|
-
setCurrentPhotoIndex(1);
|
|
409
|
-
// 확인 화면을 유지하고 "뒷면 촬영" 버튼을 표시
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
// 모든 사진 촬영 완료 - 결과 반환
|
|
413
|
-
console.log('[FullDocScanner] All photos captured, returning results');
|
|
394
|
+
console.log('[FullDocScanner] Photos captured:', updatedPhotos.length);
|
|
395
|
+
// 결과 반환
|
|
396
|
+
console.log('[FullDocScanner] Returning results');
|
|
414
397
|
onResult(updatedPhotos);
|
|
415
|
-
}, [croppedImageData, rotationDegrees, capturedPhotos,
|
|
398
|
+
}, [croppedImageData, rotationDegrees, capturedPhotos, onResult]);
|
|
416
399
|
const handleCaptureSecondPhoto = (0, react_1.useCallback)(() => {
|
|
417
400
|
console.log('[FullDocScanner] Capturing second photo');
|
|
401
|
+
if (!croppedImageData) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
// 현재 사진(앞면)을 먼저 저장
|
|
405
|
+
const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
|
|
406
|
+
const currentPhoto = {
|
|
407
|
+
path: croppedImageData.path,
|
|
408
|
+
base64: croppedImageData.base64,
|
|
409
|
+
rotationDegrees: rotationNormalized,
|
|
410
|
+
};
|
|
411
|
+
setCapturedPhotos([currentPhoto]);
|
|
412
|
+
setCurrentPhotoIndex(1);
|
|
418
413
|
// 확인 화면을 닫고 카메라로 돌아감
|
|
419
414
|
setCroppedImageData(null);
|
|
420
415
|
setRotationDegrees(0);
|
|
@@ -434,27 +429,19 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
434
429
|
if (docScannerRef.current?.reset) {
|
|
435
430
|
docScannerRef.current.reset();
|
|
436
431
|
}
|
|
437
|
-
}, []);
|
|
438
|
-
const handleSkipSecondPhoto = (0, react_1.useCallback)(() => {
|
|
439
|
-
console.log('[FullDocScanner] Skipping second photo');
|
|
440
|
-
// 첫 번째 사진만 반환
|
|
441
|
-
onResult(capturedPhotos);
|
|
442
|
-
}, [capturedPhotos, onResult]);
|
|
432
|
+
}, [croppedImageData, rotationDegrees]);
|
|
443
433
|
const handleRetake = (0, react_1.useCallback)(() => {
|
|
444
434
|
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
setCurrentPhotoIndex(1);
|
|
456
|
-
setPreviewPhotoIndex(1);
|
|
457
|
-
}
|
|
435
|
+
// Business 모드에서 두 번째 사진을 다시 찍는 경우, 첫 번째 사진 유지
|
|
436
|
+
if (isBusinessMode && capturedPhotos.length === 1) {
|
|
437
|
+
console.log('[FullDocScanner] Retake detected on back photo - keeping front photo');
|
|
438
|
+
setCurrentPhotoIndex(1);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
// 첫 번째 사진 또는 일반 모드: 모든 상태 초기화
|
|
442
|
+
console.log('[FullDocScanner] Retake detected - resetting all photos');
|
|
443
|
+
setCapturedPhotos([]);
|
|
444
|
+
setCurrentPhotoIndex(0);
|
|
458
445
|
}
|
|
459
446
|
setCroppedImageData(null);
|
|
460
447
|
setRotationDegrees(0);
|
|
@@ -475,7 +462,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
475
462
|
if (docScannerRef.current?.reset) {
|
|
476
463
|
docScannerRef.current.reset();
|
|
477
464
|
}
|
|
478
|
-
}, [capturedPhotos,
|
|
465
|
+
}, [capturedPhotos.length, isBusinessMode]);
|
|
479
466
|
const handleRectangleDetect = (0, react_1.useCallback)((event) => {
|
|
480
467
|
const stableCounter = event.stableCounter ?? 0;
|
|
481
468
|
const rectangleCoordinates = event.rectangleOnScreen ?? event.rectangleCoordinates;
|
|
@@ -529,7 +516,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
529
516
|
// check_DP: Show confirmation screen
|
|
530
517
|
react_1.default.createElement(react_native_1.View, { style: styles.confirmationContainer },
|
|
531
518
|
isBusinessMode && (react_1.default.createElement(react_native_1.View, { style: styles.photoHeader },
|
|
532
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.photoHeaderText },
|
|
519
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.photoHeaderText }, currentPhotoIndex === 0 ? mergedStrings.first : mergedStrings.second))),
|
|
533
520
|
isImageRotationSupported() ? (react_1.default.createElement(react_native_1.View, { style: styles.rotateButtonsCenter },
|
|
534
521
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.rotateButtonTop, onPress: () => handleRotateImage(-90), accessibilityLabel: "\uC67C\uCABD\uC73C\uB85C 90\uB3C4 \uD68C\uC804", accessibilityRole: "button" },
|
|
535
522
|
react_1.default.createElement(react_native_1.Text, { style: styles.rotateIconText }, "\u21BA"),
|
|
@@ -537,27 +524,17 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
537
524
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.rotateButtonTop, onPress: () => handleRotateImage(90), accessibilityLabel: "\uC624\uB978\uCABD\uC73C\uB85C 90\uB3C4 \uD68C\uC804", accessibilityRole: "button" },
|
|
538
525
|
react_1.default.createElement(react_native_1.Text, { style: styles.rotateIconText }, "\u21BB"),
|
|
539
526
|
react_1.default.createElement(react_native_1.Text, { style: styles.rotateButtonLabel }, "\uC6B0\uB85C 90\u00B0")))) : null,
|
|
527
|
+
isBusinessMode && capturedPhotos.length === 0 && (react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.captureBackButton, onPress: handleCaptureSecondPhoto, accessibilityLabel: mergedStrings.secondBtn, accessibilityRole: "button" },
|
|
528
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.captureBackButtonText }, mergedStrings.secondBtn))),
|
|
540
529
|
react_1.default.createElement(react_native_1.Image, { source: { uri: croppedImageData.path }, style: [
|
|
541
530
|
styles.previewImage,
|
|
542
531
|
{ transform: [{ rotate: `${rotationDegrees}deg` }] }
|
|
543
532
|
], resizeMode: "contain" }),
|
|
544
|
-
isBusinessMode &&
|
|
545
|
-
capturedPhotos.length === 1 &&
|
|
546
|
-
currentPhotoIndex === 1 &&
|
|
547
|
-
previewPhotoIndex === 0 &&
|
|
548
|
-
mergedStrings.secondPrompt ? (react_1.default.createElement(react_native_1.Text, { style: styles.confirmationPromptText }, mergedStrings.secondPrompt)) : null,
|
|
549
533
|
react_1.default.createElement(react_native_1.View, { style: styles.confirmationButtons },
|
|
550
534
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.retakeButton], onPress: handleRetake, accessibilityLabel: mergedStrings.retake, accessibilityRole: "button" },
|
|
551
535
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
currentPhotoIndex === 1 &&
|
|
555
|
-
previewPhotoIndex === 0 ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
556
|
-
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleCaptureSecondPhoto, accessibilityLabel: mergedStrings.secondBtn, accessibilityRole: "button" },
|
|
557
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.secondBtn)),
|
|
558
|
-
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.skipButton], onPress: handleSkipSecondPhoto, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
|
|
559
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm)))) : (react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
|
|
560
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm)))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
536
|
+
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
|
|
537
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
561
538
|
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture: false, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, onRectangleDetect: handleRectangleDetect, showManualCaptureButton: false, enableTorch: flashEnabled },
|
|
562
539
|
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
563
540
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [
|
|
@@ -820,4 +797,24 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
820
797
|
paddingVertical: 6,
|
|
821
798
|
borderRadius: 16,
|
|
822
799
|
},
|
|
800
|
+
captureBackButton: {
|
|
801
|
+
position: 'absolute',
|
|
802
|
+
bottom: 140,
|
|
803
|
+
left: 0,
|
|
804
|
+
right: 0,
|
|
805
|
+
alignItems: 'center',
|
|
806
|
+
zIndex: 15,
|
|
807
|
+
},
|
|
808
|
+
captureBackButtonText: {
|
|
809
|
+
color: '#fff',
|
|
810
|
+
fontSize: 16,
|
|
811
|
+
fontWeight: '600',
|
|
812
|
+
// backgroundColor: 'rgba(255,100,50,0.9)',
|
|
813
|
+
paddingHorizontal: 32,
|
|
814
|
+
paddingVertical: 14,
|
|
815
|
+
borderRadius: 24,
|
|
816
|
+
borderWidth: 2,
|
|
817
|
+
borderColor: '#fff',
|
|
818
|
+
overflow: 'hidden',
|
|
819
|
+
},
|
|
823
820
|
});
|
package/package.json
CHANGED
package/src/FullDocScanner.tsx
CHANGED
|
@@ -183,21 +183,14 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
183
183
|
const [rotationDegrees, setRotationDegrees] = useState(0);
|
|
184
184
|
const [capturedPhotos, setCapturedPhotos] = useState<FullDocScannerResult[]>([]);
|
|
185
185
|
const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0);
|
|
186
|
-
const [previewPhotoIndex, setPreviewPhotoIndex] = useState(0);
|
|
187
186
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
188
187
|
const docScannerRef = useRef<DocScannerHandle | null>(null);
|
|
189
188
|
const captureModeRef = useRef<'grid' | 'no-grid' | null>(null);
|
|
190
189
|
const captureInProgressRef = useRef(false);
|
|
191
190
|
const rectangleCaptureTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
192
191
|
const rectangleHintTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
193
|
-
const currentPhotoIndexRef = useRef(currentPhotoIndex);
|
|
194
192
|
|
|
195
193
|
const isBusinessMode = type === 'business';
|
|
196
|
-
const maxPhotos = isBusinessMode ? 2 : 1;
|
|
197
|
-
|
|
198
|
-
useEffect(() => {
|
|
199
|
-
currentPhotoIndexRef.current = currentPhotoIndex;
|
|
200
|
-
}, [currentPhotoIndex]);
|
|
201
194
|
|
|
202
195
|
const mergedStrings = useMemo(
|
|
203
196
|
() => ({
|
|
@@ -269,8 +262,6 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
269
262
|
|
|
270
263
|
setProcessing(false);
|
|
271
264
|
|
|
272
|
-
setPreviewPhotoIndex(currentPhotoIndexRef.current);
|
|
273
|
-
|
|
274
265
|
// Show confirmation screen
|
|
275
266
|
setCroppedImageData({
|
|
276
267
|
path: croppedImage.path,
|
|
@@ -333,9 +324,6 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
333
324
|
return;
|
|
334
325
|
}
|
|
335
326
|
|
|
336
|
-
const previewIndex = currentPhotoIndexRef.current;
|
|
337
|
-
setPreviewPhotoIndex(previewIndex);
|
|
338
|
-
|
|
339
327
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
340
328
|
|
|
341
329
|
if (captureMode === 'no-grid') {
|
|
@@ -540,24 +528,31 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
540
528
|
};
|
|
541
529
|
|
|
542
530
|
const updatedPhotos = [...capturedPhotos, currentPhoto];
|
|
543
|
-
console.log('[FullDocScanner] Photos captured:', updatedPhotos.length
|
|
544
|
-
|
|
545
|
-
// Business 모드이고 아직 첫 번째 사진만 찍은 경우
|
|
546
|
-
if (isBusinessMode && updatedPhotos.length === 1) {
|
|
547
|
-
// 두 번째 사진 촬영 여부를 물어봄 (UI에서 버튼으로 표시)
|
|
548
|
-
setCapturedPhotos(updatedPhotos);
|
|
549
|
-
setCurrentPhotoIndex(1);
|
|
550
|
-
// 확인 화면을 유지하고 "뒷면 촬영" 버튼을 표시
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
531
|
+
console.log('[FullDocScanner] Photos captured:', updatedPhotos.length);
|
|
553
532
|
|
|
554
|
-
//
|
|
555
|
-
console.log('[FullDocScanner]
|
|
533
|
+
// 결과 반환
|
|
534
|
+
console.log('[FullDocScanner] Returning results');
|
|
556
535
|
onResult(updatedPhotos);
|
|
557
|
-
}, [croppedImageData, rotationDegrees, capturedPhotos,
|
|
536
|
+
}, [croppedImageData, rotationDegrees, capturedPhotos, onResult]);
|
|
558
537
|
|
|
559
538
|
const handleCaptureSecondPhoto = useCallback(() => {
|
|
560
539
|
console.log('[FullDocScanner] Capturing second photo');
|
|
540
|
+
|
|
541
|
+
if (!croppedImageData) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// 현재 사진(앞면)을 먼저 저장
|
|
546
|
+
const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
|
|
547
|
+
const currentPhoto: FullDocScannerResult = {
|
|
548
|
+
path: croppedImageData.path,
|
|
549
|
+
base64: croppedImageData.base64,
|
|
550
|
+
rotationDegrees: rotationNormalized,
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
setCapturedPhotos([currentPhoto]);
|
|
554
|
+
setCurrentPhotoIndex(1);
|
|
555
|
+
|
|
561
556
|
// 확인 화면을 닫고 카메라로 돌아감
|
|
562
557
|
setCroppedImageData(null);
|
|
563
558
|
setRotationDegrees(0);
|
|
@@ -577,29 +572,21 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
577
572
|
if (docScannerRef.current?.reset) {
|
|
578
573
|
docScannerRef.current.reset();
|
|
579
574
|
}
|
|
580
|
-
}, []);
|
|
575
|
+
}, [croppedImageData, rotationDegrees]);
|
|
581
576
|
|
|
582
|
-
const handleSkipSecondPhoto = useCallback(() => {
|
|
583
|
-
console.log('[FullDocScanner] Skipping second photo');
|
|
584
|
-
// 첫 번째 사진만 반환
|
|
585
|
-
onResult(capturedPhotos);
|
|
586
|
-
}, [capturedPhotos, onResult]);
|
|
587
577
|
|
|
588
578
|
const handleRetake = useCallback(() => {
|
|
589
579
|
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|
|
590
580
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
setCurrentPhotoIndex(1);
|
|
601
|
-
setPreviewPhotoIndex(1);
|
|
602
|
-
}
|
|
581
|
+
// Business 모드에서 두 번째 사진을 다시 찍는 경우, 첫 번째 사진 유지
|
|
582
|
+
if (isBusinessMode && capturedPhotos.length === 1) {
|
|
583
|
+
console.log('[FullDocScanner] Retake detected on back photo - keeping front photo');
|
|
584
|
+
setCurrentPhotoIndex(1);
|
|
585
|
+
} else {
|
|
586
|
+
// 첫 번째 사진 또는 일반 모드: 모든 상태 초기화
|
|
587
|
+
console.log('[FullDocScanner] Retake detected - resetting all photos');
|
|
588
|
+
setCapturedPhotos([]);
|
|
589
|
+
setCurrentPhotoIndex(0);
|
|
603
590
|
}
|
|
604
591
|
|
|
605
592
|
setCroppedImageData(null);
|
|
@@ -621,7 +608,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
621
608
|
if (docScannerRef.current?.reset) {
|
|
622
609
|
docScannerRef.current.reset();
|
|
623
610
|
}
|
|
624
|
-
}, [capturedPhotos,
|
|
611
|
+
}, [capturedPhotos.length, isBusinessMode]);
|
|
625
612
|
|
|
626
613
|
const handleRectangleDetect = useCallback((event: RectangleDetectEvent) => {
|
|
627
614
|
const stableCounter = event.stableCounter ?? 0;
|
|
@@ -689,7 +676,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
689
676
|
{isBusinessMode && (
|
|
690
677
|
<View style={styles.photoHeader}>
|
|
691
678
|
<Text style={styles.photoHeaderText}>
|
|
692
|
-
{
|
|
679
|
+
{currentPhotoIndex === 0 ? mergedStrings.first : mergedStrings.second}
|
|
693
680
|
</Text>
|
|
694
681
|
</View>
|
|
695
682
|
)}
|
|
@@ -717,6 +704,19 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
717
704
|
</TouchableOpacity>
|
|
718
705
|
</View>
|
|
719
706
|
) : null}
|
|
707
|
+
|
|
708
|
+
{/* 뒷면 촬영 버튼 - 상단에 표시 (Business 모드이고 첫 번째 사진일 때만) */}
|
|
709
|
+
{isBusinessMode && capturedPhotos.length === 0 && (
|
|
710
|
+
<TouchableOpacity
|
|
711
|
+
style={styles.captureBackButton}
|
|
712
|
+
onPress={handleCaptureSecondPhoto}
|
|
713
|
+
accessibilityLabel={mergedStrings.secondBtn}
|
|
714
|
+
accessibilityRole="button"
|
|
715
|
+
>
|
|
716
|
+
<Text style={styles.captureBackButtonText}>{mergedStrings.secondBtn}</Text>
|
|
717
|
+
</TouchableOpacity>
|
|
718
|
+
)}
|
|
719
|
+
|
|
720
720
|
<Image
|
|
721
721
|
source={{ uri: croppedImageData.path }}
|
|
722
722
|
style={[
|
|
@@ -725,13 +725,6 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
725
725
|
]}
|
|
726
726
|
resizeMode="contain"
|
|
727
727
|
/>
|
|
728
|
-
{isBusinessMode &&
|
|
729
|
-
capturedPhotos.length === 1 &&
|
|
730
|
-
currentPhotoIndex === 1 &&
|
|
731
|
-
previewPhotoIndex === 0 &&
|
|
732
|
-
mergedStrings.secondPrompt ? (
|
|
733
|
-
<Text style={styles.confirmationPromptText}>{mergedStrings.secondPrompt}</Text>
|
|
734
|
-
) : null}
|
|
735
728
|
<View style={styles.confirmationButtons}>
|
|
736
729
|
<TouchableOpacity
|
|
737
730
|
style={[styles.confirmButton, styles.retakeButton]}
|
|
@@ -742,39 +735,14 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
742
735
|
<Text style={styles.confirmButtonText}>{mergedStrings.retake}</Text>
|
|
743
736
|
</TouchableOpacity>
|
|
744
737
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
onPress={handleCaptureSecondPhoto}
|
|
754
|
-
accessibilityLabel={mergedStrings.secondBtn}
|
|
755
|
-
accessibilityRole="button"
|
|
756
|
-
>
|
|
757
|
-
<Text style={styles.confirmButtonText}>{mergedStrings.secondBtn}</Text>
|
|
758
|
-
</TouchableOpacity>
|
|
759
|
-
<TouchableOpacity
|
|
760
|
-
style={[styles.confirmButton, styles.skipButton]}
|
|
761
|
-
onPress={handleSkipSecondPhoto}
|
|
762
|
-
accessibilityLabel={mergedStrings.confirm}
|
|
763
|
-
accessibilityRole="button"
|
|
764
|
-
>
|
|
765
|
-
<Text style={styles.confirmButtonText}>{mergedStrings.confirm}</Text>
|
|
766
|
-
</TouchableOpacity>
|
|
767
|
-
</>
|
|
768
|
-
) : (
|
|
769
|
-
<TouchableOpacity
|
|
770
|
-
style={[styles.confirmButton, styles.confirmButtonPrimary]}
|
|
771
|
-
onPress={handleConfirm}
|
|
772
|
-
accessibilityLabel={mergedStrings.confirm}
|
|
773
|
-
accessibilityRole="button"
|
|
774
|
-
>
|
|
775
|
-
<Text style={styles.confirmButtonText}>{mergedStrings.confirm}</Text>
|
|
776
|
-
</TouchableOpacity>
|
|
777
|
-
)}
|
|
738
|
+
<TouchableOpacity
|
|
739
|
+
style={[styles.confirmButton, styles.confirmButtonPrimary]}
|
|
740
|
+
onPress={handleConfirm}
|
|
741
|
+
accessibilityLabel={mergedStrings.confirm}
|
|
742
|
+
accessibilityRole="button"
|
|
743
|
+
>
|
|
744
|
+
<Text style={styles.confirmButtonText}>{mergedStrings.confirm}</Text>
|
|
745
|
+
</TouchableOpacity>
|
|
778
746
|
</View>
|
|
779
747
|
</View>
|
|
780
748
|
) : (
|
|
@@ -1117,4 +1085,24 @@ const styles = StyleSheet.create({
|
|
|
1117
1085
|
paddingVertical: 6,
|
|
1118
1086
|
borderRadius: 16,
|
|
1119
1087
|
},
|
|
1088
|
+
captureBackButton: {
|
|
1089
|
+
position: 'absolute',
|
|
1090
|
+
bottom: 140,
|
|
1091
|
+
left: 0,
|
|
1092
|
+
right: 0,
|
|
1093
|
+
alignItems: 'center',
|
|
1094
|
+
zIndex: 15,
|
|
1095
|
+
},
|
|
1096
|
+
captureBackButtonText: {
|
|
1097
|
+
color: '#fff',
|
|
1098
|
+
fontSize: 16,
|
|
1099
|
+
fontWeight: '600',
|
|
1100
|
+
// backgroundColor: 'rgba(255,100,50,0.9)',
|
|
1101
|
+
paddingHorizontal: 32,
|
|
1102
|
+
paddingVertical: 14,
|
|
1103
|
+
borderRadius: 24,
|
|
1104
|
+
borderWidth: 2,
|
|
1105
|
+
borderColor: '#fff',
|
|
1106
|
+
overflow: 'hidden',
|
|
1107
|
+
},
|
|
1120
1108
|
});
|