@smileid/usesmileid 12.0.0 → 12.0.2
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/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/camera/camera_defaults.d.ts +2 -0
- package/dist/camera/camera_defaults.d.ts.map +1 -1
- package/dist/camera/camera_defaults.js +2 -0
- package/dist/camera/camera_defaults.js.map +1 -1
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts +11 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts.map +1 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js +17 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js.map +1 -0
- package/dist/core/exception/capture_validation_exceptions.d.ts +1 -0
- package/dist/core/exception/capture_validation_exceptions.d.ts.map +1 -1
- package/dist/core/exception/capture_validation_exceptions.js +1 -0
- package/dist/core/exception/capture_validation_exceptions.js.map +1 -1
- package/dist/core/exception/flow_exceptions.d.ts +4 -2
- package/dist/core/exception/flow_exceptions.d.ts.map +1 -1
- package/dist/core/exception/flow_exceptions.js +3 -2
- package/dist/core/exception/flow_exceptions.js.map +1 -1
- package/dist/core/exception/index.d.ts +1 -0
- package/dist/core/exception/index.d.ts.map +1 -1
- package/dist/core/exception/index.js +1 -0
- package/dist/core/exception/index.js.map +1 -1
- package/dist/core/exception/missing_job_type_exception.d.ts +1 -3
- package/dist/core/exception/missing_job_type_exception.d.ts.map +1 -1
- package/dist/core/exception/missing_job_type_exception.js +2 -4
- package/dist/core/exception/missing_job_type_exception.js.map +1 -1
- package/dist/core/exception/use_smile_id_error_code.d.ts +1 -0
- package/dist/core/exception/use_smile_id_error_code.d.ts.map +1 -1
- package/dist/core/exception/use_smile_id_error_code.js +1 -0
- package/dist/core/exception/use_smile_id_error_code.js.map +1 -1
- package/dist/core/models/config.d.ts +19 -0
- package/dist/core/models/config.d.ts.map +1 -1
- package/dist/core/models/document_type.d.ts +1 -1
- package/dist/core/models/document_type.d.ts.map +1 -1
- package/dist/core/models/document_type.js +2 -2
- package/dist/core/models/document_type.js.map +1 -1
- package/dist/core/models/global_privacy_control.d.ts +36 -0
- package/dist/core/models/global_privacy_control.d.ts.map +1 -0
- package/dist/core/models/global_privacy_control.js +39 -0
- package/dist/core/models/global_privacy_control.js.map +1 -0
- package/dist/core/models/network_config.d.ts +2 -2
- package/dist/core/models/network_config.js +2 -2
- package/dist/data/api/interceptors/smile_auth_interceptor.d.ts.map +1 -1
- package/dist/data/api/interceptors/smile_auth_interceptor.js +3 -17
- package/dist/data/api/interceptors/smile_auth_interceptor.js.map +1 -1
- package/dist/data/api/smile_id_api.d.ts +5 -1
- package/dist/data/api/smile_id_api.d.ts.map +1 -1
- package/dist/data/api/smile_id_api.js +30 -27
- package/dist/data/api/smile_id_api.js.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.d.ts +4 -4
- package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.js +6 -6
- package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
- package/dist/data/model/job_request.d.ts +28 -12
- package/dist/data/model/job_request.d.ts.map +1 -1
- package/dist/data/model/token_payload.d.ts +78 -0
- package/dist/data/model/token_payload.d.ts.map +1 -0
- package/dist/data/model/token_payload.js +132 -0
- package/dist/data/model/token_payload.js.map +1 -0
- package/dist/data/model/user_details_payload.d.ts +39 -0
- package/dist/data/model/user_details_payload.d.ts.map +1 -0
- package/dist/data/model/user_details_payload.js +53 -0
- package/dist/data/model/user_details_payload.js.map +1 -0
- package/dist/data/smile_id_urls.d.ts +1 -1
- package/dist/data/smile_id_urls.js +1 -1
- package/dist/data/smile_id_urls.js.map +1 -1
- package/dist/data/util/retry_util.d.ts +1 -1
- package/dist/data/util/retry_util.d.ts.map +1 -1
- package/dist/data/util/retry_util.js +5 -0
- package/dist/data/util/retry_util.js.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.d.ts +15 -3
- package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.js +20 -8
- package/dist/data/util/use_smile_id_token_decoder.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/l10n/strings_en.d.ts +4 -1
- package/dist/l10n/strings_en.d.ts.map +1 -1
- package/dist/l10n/strings_en.js +4 -1
- package/dist/l10n/strings_en.js.map +1 -1
- package/dist/l10n/use_smile_id_localizations.d.ts +10 -0
- package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
- package/dist/l10n/use_smile_id_localizations.js +59 -3
- package/dist/l10n/use_smile_id_localizations.js.map +1 -1
- package/dist/metadata/builder_configuration.d.ts +5 -0
- package/dist/metadata/builder_configuration.d.ts.map +1 -1
- package/dist/metadata/builder_configuration.js +1 -0
- package/dist/metadata/builder_configuration.js.map +1 -1
- package/dist/metadata/metadata_configuration_mappers.d.ts +2 -3
- package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -1
- package/dist/metadata/metadata_configuration_mappers.js +13 -6
- package/dist/metadata/metadata_configuration_mappers.js.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.js +14 -5
- package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
- package/dist/presentation/components/use_smile_id_button.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_button.js +8 -2
- package/dist/presentation/components/use_smile_id_button.js.map +1 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts +5 -2
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js +8 -3
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.js +8 -3
- package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts +16 -0
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.js +18 -0
- package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +6 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.js +7 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +23 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts +22 -3
- package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.js +84 -46
- package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_capture_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js +13 -3
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js +3 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js +0 -8
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js +25 -5
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js.map +1 -1
- package/dist/presentation/flow/use_smile_id_flow.d.ts.map +1 -1
- package/dist/presentation/flow/use_smile_id_flow.js +45 -12
- package/dist/presentation/flow/use_smile_id_flow.js.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.d.ts +16 -2
- package/dist/presentation/flow/validation/flow_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.js +61 -47
- package/dist/presentation/flow/validation/flow_validator.js.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.d.ts +7 -0
- package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.js +52 -27
- package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
- package/dist/presentation/flow/validation/user_details_validator.d.ts +9 -0
- package/dist/presentation/flow/validation/user_details_validator.d.ts.map +1 -0
- package/dist/presentation/flow/validation/user_details_validator.js +40 -0
- package/dist/presentation/flow/validation/user_details_validator.js.map +1 -0
- package/dist/presentation/screen/helpers/capture_screen_helpers.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/capture_screen_helpers.js +1 -0
- package/dist/presentation/screen/helpers/capture_screen_helpers.js.map +1 -1
- package/dist/presentation/screen/helpers/capture_ui_state.d.ts +6 -6
- package/dist/presentation/screen/helpers/capture_ui_state.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/capture_ui_state.js +19 -19
- package/dist/presentation/screen/helpers/capture_ui_state.js.map +1 -1
- package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts +2 -2
- package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/ess_turn_haptics.js +6 -6
- package/dist/presentation/screen/helpers/ess_turn_haptics.js.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts +5 -5
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +11 -11
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js.map +1 -1
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts +13 -3
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.js +48 -6
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +4 -2
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.js +90 -23
- package/dist/presentation/screen/use_smile_id_capture_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_consent_screen.d.ts +7 -0
- package/dist/presentation/screen/use_smile_id_consent_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_consent_screen.js +6 -5
- package/dist/presentation/screen/use_smile_id_consent_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js +5 -13
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +1 -21
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.js +3 -14
- package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
- package/dist/presentation/utils/locale_utils.d.ts +10 -4
- package/dist/presentation/utils/locale_utils.d.ts.map +1 -1
- package/dist/presentation/utils/locale_utils.js +13 -5
- package/dist/presentation/utils/locale_utils.js.map +1 -1
- package/dist/testing/fake_face_analyzer.d.ts +43 -0
- package/dist/testing/fake_face_analyzer.d.ts.map +1 -0
- package/dist/testing/fake_face_analyzer.js +52 -0
- package/dist/testing/fake_face_analyzer.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +7 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/scenario_expectations.d.ts +28 -0
- package/dist/testing/scenario_expectations.d.ts.map +1 -0
- package/dist/testing/scenario_expectations.js +65 -0
- package/dist/testing/scenario_expectations.js.map +1 -0
- package/dist/testing/scenario_loader.d.ts +11 -0
- package/dist/testing/scenario_loader.d.ts.map +1 -0
- package/dist/testing/scenario_loader.js +64 -0
- package/dist/testing/scenario_loader.js.map +1 -0
- package/dist/testing/scripted_scan_results.d.ts +17 -0
- package/dist/testing/scripted_scan_results.d.ts.map +1 -0
- package/dist/testing/scripted_scan_results.js +52 -0
- package/dist/testing/scripted_scan_results.js.map +1 -0
- package/package.json +11 -4
- package/src/__tests__/dsl.test.ts +51 -1
- package/src/__tests__/react_native_mock.tsx +22 -0
- package/src/__tests__/setup_react_native.ts +17 -2
- package/src/__tests__/snapshots/__snapshots__/screens_structural.test.tsx.snap +5267 -0
- package/src/__tests__/snapshots/screens_structural.test.tsx +230 -0
- package/src/camera/__tests__/camera_permissions.test.ts +72 -0
- package/src/camera/__tests__/camera_system_focus.test.ts +173 -0
- package/src/camera/__tests__/use_smile_id_camera_preview.test.tsx +461 -0
- package/src/camera/__tests__/use_smile_id_camera_system.test.ts +103 -0
- package/src/camera/__tests__/use_smile_id_frame_stream_hook.test.tsx +229 -0
- package/src/camera/camera_defaults.ts +3 -0
- package/src/core/exception/__tests__/builder_validation_exceptions.test.ts +81 -0
- package/src/core/exception/agent_mode_with_enhanced_liveness_exception.ts +20 -0
- package/src/core/exception/capture_validation_exceptions.ts +1 -0
- package/src/core/exception/flow_exceptions.test.ts +10 -0
- package/src/core/exception/flow_exceptions.ts +3 -2
- package/src/core/exception/index.ts +1 -0
- package/src/core/exception/missing_job_type_exception.ts +2 -4
- package/src/core/exception/use_smile_id_error_code.ts +1 -0
- package/src/core/models/__tests__/document_type.test.ts +2 -2
- package/src/core/models/__tests__/flow_models.test.ts +26 -0
- package/src/core/models/config.ts +22 -0
- package/src/core/models/document_type.ts +2 -2
- package/src/core/models/global_privacy_control.ts +45 -0
- package/src/core/models/network_config.ts +2 -2
- package/src/data/api/__tests__/smile_id_api.test.ts +275 -1
- package/src/data/api/interceptors/__tests__/credential_header_redaction.test.ts +144 -0
- package/src/data/api/interceptors/__tests__/gzip_interceptor.test.ts +83 -0
- package/src/data/api/interceptors/smile_auth_interceptor.ts +3 -18
- package/src/data/api/smile_id_api.ts +36 -49
- package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +6 -2
- package/src/data/dsl/__tests__/use_smile_id_network_builder.test.ts +157 -0
- package/src/data/dsl/builder/__tests__/config_builders.test.ts +62 -0
- package/src/data/dsl/builder/retry_config_builder.ts +6 -6
- package/src/data/factory/__tests__/retry_gzip_mac_composition.test.ts +163 -0
- package/src/data/factory/__tests__/signed_job_submission_headers.test.ts +1 -1
- package/src/data/model/__tests__/token_payload.test.ts +224 -0
- package/src/data/model/__tests__/user_details_payload.test.ts +100 -0
- package/src/data/model/job_request.ts +27 -12
- package/src/data/model/token_payload.ts +182 -0
- package/src/data/model/user_details_payload.ts +84 -0
- package/src/data/repository/__tests__/network_retries.test.ts +1 -1
- package/src/data/repository/__tests__/repository_dispatch.test.ts +366 -0
- package/src/data/repository/__tests__/use_smile_id_repository.test.ts +1 -1
- package/src/data/security/__tests__/request_canonicalizer.test.ts +132 -0
- package/src/data/security/__tests__/signing_crypto.test.ts +203 -0
- package/src/data/smile_id_urls.ts +1 -1
- package/src/data/util/__tests__/retry_util.test.ts +25 -0
- package/src/data/util/__tests__/use_smile_id_token_decoder.test.ts +179 -0
- package/src/data/util/retry_util.ts +9 -1
- package/src/data/util/use_smile_id_token_decoder.ts +29 -8
- package/src/index.ts +6 -4
- package/src/l10n/__tests__/use_smile_id_localizations.test.ts +122 -5
- package/src/l10n/__tests__/use_smile_id_localizations_provider.test.tsx +112 -0
- package/src/l10n/__tests__/use_smile_id_localizations_surface.test.ts +231 -0
- package/src/l10n/strings_en.ts +5 -1
- package/src/l10n/use_smile_id_localizations.ts +80 -3
- package/src/metadata/__tests__/device_orientation_sampling.test.ts +165 -0
- package/src/metadata/__tests__/geolocation.test.ts +150 -0
- package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +39 -0
- package/src/metadata/__tests__/metadata_configuration_objects.test.ts +2 -1
- package/src/metadata/__tests__/metadata_device_context.test.ts +3 -3
- package/src/metadata/__tests__/metadata_device_os_android.test.ts +18 -0
- package/src/metadata/__tests__/metadata_golden_fixture.json +1 -1
- package/src/metadata/__tests__/metadata_payload_golden.test.ts +4 -4
- package/src/metadata/__tests__/optional_native_modules.test.ts +234 -0
- package/src/metadata/__tests__/use_smile_id_metadata.test.ts +1 -1
- package/src/metadata/__tests__/use_smile_id_metadata_factory.test.ts +615 -0
- package/src/metadata/builder_configuration.ts +6 -0
- package/src/metadata/metadata_configuration_mappers.ts +21 -7
- package/src/metadata/use_smile_id_metadata_factory.ts +17 -6
- package/src/presentation/assets/si_document_green_book_hero_animation.json +1 -4668
- package/src/presentation/assets/si_document_hero_animation.json +1 -4799
- package/src/presentation/assets/si_document_hero_back_animation.json +1 -2039
- package/src/presentation/assets/si_document_passport_hero_animation.json +1 -14491
- package/src/presentation/assets/si_ess_all_directions_hero_animation.json +1 -0
- package/src/presentation/assets/si_ess_animation_all_directions.json +1 -6589
- package/src/presentation/assets/si_selfie_hero_animation.json +1 -1439
- package/src/presentation/assets/si_smile_to_capture_animation.json +1 -1439
- package/src/presentation/components/__tests__/use_smile_id_content_card.test.tsx +112 -0
- package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +9 -4
- package/src/presentation/components/__tests__/use_smile_id_face_oval_image.test.tsx +190 -0
- package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +44 -0
- package/src/presentation/components/__tests__/use_smile_id_learn_more_content.test.tsx +159 -0
- package/src/presentation/components/__tests__/use_smile_id_processing_center_indicator.test.tsx +88 -0
- package/src/presentation/components/use_smile_id_button.tsx +7 -2
- package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +9 -3
- package/src/presentation/components/use_smile_id_instructions_hero.tsx +10 -0
- package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +3 -3
- package/src/presentation/flow/__tests__/flow_navigation_manager.test.ts +372 -1
- package/src/presentation/flow/__tests__/use_smile_id_flow.test.tsx +651 -0
- package/src/presentation/flow/dsl/__tests__/use_smile_id_builder_component.test.tsx +120 -0
- package/src/presentation/flow/dsl/builder/__tests__/config_builder.test.ts +25 -0
- package/src/presentation/flow/dsl/builder/config_builder.ts +21 -0
- package/src/presentation/flow/dsl/builder/screens_builder.ts +7 -12
- package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +27 -1
- package/src/presentation/flow/flow_navigation_manager.ts +108 -93
- package/src/presentation/flow/graph/__tests__/screen_renderer.test.tsx +102 -0
- package/src/presentation/flow/model/instructions_defaults.ts +1 -1
- package/src/presentation/flow/screen/__tests__/orchestrated_capture_screen.test.tsx +836 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_consent_screen.test.tsx +165 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_instructions_screen.test.tsx +163 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_preview_screen.test.tsx +224 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_processing_screen.test.tsx +338 -0
- package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +18 -3
- package/src/presentation/flow/screen/orchestrated_consent_screen.tsx +5 -0
- package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +0 -12
- package/src/presentation/flow/screen/orchestrated_processing_screen.tsx +42 -5
- package/src/presentation/flow/use_smile_id_flow.tsx +63 -12
- package/src/presentation/flow/validation/__tests__/flow_validator.test.ts +219 -1
- package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +200 -0
- package/src/presentation/flow/validation/flow_validator.ts +85 -57
- package/src/presentation/flow/validation/job_type_validator.ts +73 -39
- package/src/presentation/flow/validation/user_details_validator.ts +53 -0
- package/src/presentation/screen/__tests__/capture_ui_state.test.ts +66 -47
- package/src/presentation/screen/__tests__/ess_turn_haptics.test.ts +15 -11
- package/src/presentation/screen/__tests__/feedback_copy_table.test.ts +145 -0
- package/src/presentation/screen/__tests__/scan_state_to_overlay_state.test.ts +47 -27
- package/src/presentation/screen/__tests__/use_smile_id_capture_screen.test.tsx +524 -14
- package/src/presentation/screen/__tests__/use_smile_id_document_back_instructions.test.tsx +4 -2
- package/src/presentation/screen/__tests__/use_smile_id_permission_screen.test.tsx +68 -0
- package/src/presentation/screen/__tests__/use_smile_id_preview_screen.test.tsx +10 -40
- package/src/presentation/screen/helpers/__tests__/use_capture_orientation_lock.test.tsx +212 -0
- package/src/presentation/screen/helpers/capture_screen_helpers.ts +1 -0
- package/src/presentation/screen/helpers/capture_ui_state.ts +27 -27
- package/src/presentation/screen/helpers/ess_turn_haptics.ts +9 -9
- package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +13 -13
- package/src/presentation/screen/helpers/use_capture_orientation_lock.ts +69 -7
- package/src/presentation/screen/use_smile_id_capture_screen.tsx +107 -28
- package/src/presentation/screen/use_smile_id_consent_screen.tsx +16 -5
- package/src/presentation/screen/use_smile_id_document_back_instructions.tsx +14 -23
- package/src/presentation/screen/use_smile_id_document_preview_screen.tsx +1 -1
- package/src/presentation/screen/use_smile_id_preview_screen.tsx +13 -45
- package/src/presentation/screen/use_smile_id_processing_screen.tsx +1 -1
- package/src/presentation/theme/__tests__/use_use_smile_id_fonts.test.tsx +166 -0
- package/src/presentation/utils/__tests__/locale_utils.test.ts +46 -5
- package/src/presentation/utils/locale_utils.ts +13 -4
- package/src/testing/__tests__/fake_face_analyzer.test.ts +42 -0
- package/src/testing/__tests__/scenario_expectations.test.ts +110 -0
- package/src/testing/__tests__/scenario_loader.test.ts +64 -0
- package/src/testing/fake_face_analyzer.ts +82 -0
- package/src/testing/index.ts +15 -0
- package/src/testing/scenario_expectations.ts +87 -0
- package/src/testing/scenario_loader.ts +83 -0
- package/src/testing/scripted_scan_results.ts +66 -0
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts +0 -15
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js +0 -19
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js.map +0 -1
- package/src/presentation/components/use_smile_id_face_silhouette_overlay.tsx +0 -27
|
@@ -3,6 +3,14 @@ import * as ScreenOrientation from "expo-screen-orientation";
|
|
|
3
3
|
import { UseSmileIDCrashReporting } from "@smileid/usesmileid_bridge";
|
|
4
4
|
import type { DocumentOrientation } from "../../../core/models/document_type";
|
|
5
5
|
|
|
6
|
+
export type CaptureOrientationOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* Lock applied when the capture screen unmounts. Defaults to portrait-up;
|
|
9
|
+
* threaded from the builder's `exitOrientations`.
|
|
10
|
+
*/
|
|
11
|
+
readonly exitLock?: ScreenOrientation.OrientationLock;
|
|
12
|
+
};
|
|
13
|
+
|
|
6
14
|
/**
|
|
7
15
|
* Lock device orientation for a capture screen, scoped to its lifetime
|
|
8
16
|
* (`"Landscape"` → landscape, `"Portrait"` → portrait-up).
|
|
@@ -10,26 +18,76 @@ import type { DocumentOrientation } from "../../../core/models/document_type";
|
|
|
10
18
|
* Each screen asserts its OWN orientation on mount, so document → selfie
|
|
11
19
|
* reverts deterministically rather than depending on the previous
|
|
12
20
|
* screen's teardown winning a race against the next camera initialising.
|
|
13
|
-
* Unmount restores portrait-up as a safety net.
|
|
14
21
|
*
|
|
15
22
|
* Locks are global: the host app must permit the locked orientations at
|
|
16
23
|
* the OS level (iOS `UISupportedInterfaceOrientations`, Android activity
|
|
17
|
-
* `screenOrientation`) for the lock to take effect
|
|
24
|
+
* `screenOrientation`) for the lock to take effect — a host that does not
|
|
25
|
+
* is warned about and reported rather than silently staying upright.
|
|
18
26
|
*/
|
|
19
27
|
export function useCaptureOrientationLock(
|
|
20
28
|
orientation: DocumentOrientation,
|
|
29
|
+
{
|
|
30
|
+
exitLock = ScreenOrientation.OrientationLock.PORTRAIT_UP,
|
|
31
|
+
}: CaptureOrientationOptions = {},
|
|
21
32
|
): void {
|
|
22
33
|
useEffect(() => {
|
|
23
34
|
const target =
|
|
24
35
|
orientation === "Landscape"
|
|
25
36
|
? ScreenOrientation.OrientationLock.LANDSCAPE
|
|
26
37
|
: ScreenOrientation.OrientationLock.PORTRAIT_UP;
|
|
38
|
+
void reportIfLockUnsupported(target);
|
|
27
39
|
void lockOrientation(target);
|
|
28
40
|
|
|
29
41
|
return () => {
|
|
30
|
-
void lockOrientation(
|
|
42
|
+
void lockOrientation(exitLock);
|
|
31
43
|
};
|
|
32
|
-
}, [orientation]);
|
|
44
|
+
}, [orientation, exitLock]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Surface a host build that cannot honour `target`. `lockAsync` resolves
|
|
49
|
+
* successfully in that case, so without this preflight the capture screen
|
|
50
|
+
* just stays in the wrong orientation with no signal. (Expo's `app.json`
|
|
51
|
+
* `orientation` value is not such a case: the module's app-delegate hook
|
|
52
|
+
* outranks the baked `Info.plist` on iOS — device-verified.)
|
|
53
|
+
*/
|
|
54
|
+
async function reportIfLockUnsupported(
|
|
55
|
+
target: ScreenOrientation.OrientationLock,
|
|
56
|
+
): Promise<void> {
|
|
57
|
+
let supported: boolean;
|
|
58
|
+
try {
|
|
59
|
+
supported = await ScreenOrientation.supportsOrientationLockAsync(target);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
reportOrientationFailure(error);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (supported) return;
|
|
65
|
+
|
|
66
|
+
// `typeof` guard: `__DEV__` is bundler-injected and absent outside Metro-like
|
|
67
|
+
// environments, where a bare reference throws rather than reading falsy.
|
|
68
|
+
const isDevBuild = typeof __DEV__ !== "undefined" && __DEV__;
|
|
69
|
+
if (isDevBuild && !warnedUnsupportedTargets.has(target)) {
|
|
70
|
+
warnedUnsupportedTargets.add(target);
|
|
71
|
+
console.warn(
|
|
72
|
+
"[UseSmileID] The capture screen needs to lock the device orientation, " +
|
|
73
|
+
"but this build does not permit it. Allow the required orientations " +
|
|
74
|
+
"in your app's iOS Info.plist / Android manifest.",
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
reportOrientationFailure(
|
|
78
|
+
new Error(`orientation lock unsupported by host build: ${target}`),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Dedupes the dev warning per target: a flow remounts the capture screen for the back
|
|
84
|
+
* side and interstitial, and the misconfiguration can't change mid-session.
|
|
85
|
+
*/
|
|
86
|
+
const warnedUnsupportedTargets = new Set<ScreenOrientation.OrientationLock>();
|
|
87
|
+
|
|
88
|
+
/** Test seam: clears the once-per-target dev-warning dedupe. */
|
|
89
|
+
export function resetUnsupportedLockWarningsForTesting(): void {
|
|
90
|
+
warnedUnsupportedTargets.clear();
|
|
33
91
|
}
|
|
34
92
|
|
|
35
93
|
/** Lock to `target`, routing a native failure through crash reporting. */
|
|
@@ -39,8 +97,12 @@ async function lockOrientation(
|
|
|
39
97
|
try {
|
|
40
98
|
await ScreenOrientation.lockAsync(target);
|
|
41
99
|
} catch (error) {
|
|
42
|
-
|
|
43
|
-
error instanceof Error ? error : new Error(String(error)),
|
|
44
|
-
);
|
|
100
|
+
reportOrientationFailure(error);
|
|
45
101
|
}
|
|
46
102
|
}
|
|
103
|
+
|
|
104
|
+
function reportOrientationFailure(error: unknown): void {
|
|
105
|
+
UseSmileIDCrashReporting.captureException(
|
|
106
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
@@ -28,11 +28,14 @@ import type {
|
|
|
28
28
|
DocumentAnalyzer,
|
|
29
29
|
FaceAnalyzer,
|
|
30
30
|
} from "@smileid/usesmileid_platform_interface";
|
|
31
|
-
import type {
|
|
31
|
+
import type {
|
|
32
|
+
CaptureReadyEvent,
|
|
33
|
+
UseSmileIDScanState,
|
|
34
|
+
} from "@smileid/usesmileid_bridge";
|
|
32
35
|
import {
|
|
33
36
|
CaptureReadyEventKind,
|
|
34
37
|
DocumentSide,
|
|
35
|
-
|
|
38
|
+
UseSmileIDScanStateType,
|
|
36
39
|
} from "@smileid/usesmileid_bridge";
|
|
37
40
|
import { CaptureType } from "../../core/models/ml_config";
|
|
38
41
|
import type { DocumentCaptureMode } from "../../core/models/document_capture_mode";
|
|
@@ -108,7 +111,7 @@ export type UseSmileIDCaptureScreenProps = {
|
|
|
108
111
|
readonly onDocumentOrigin?: (origin: DocumentImageOrigin) => void;
|
|
109
112
|
|
|
110
113
|
/** Fires when the state machine reaches `"timeout"`; the screen stops streaming. */
|
|
111
|
-
readonly onCaptureTimeout?: (state:
|
|
114
|
+
readonly onCaptureTimeout?: (state: UseSmileIDScanState) => void;
|
|
112
115
|
|
|
113
116
|
readonly onBack?: () => void;
|
|
114
117
|
readonly showAttribution?: boolean;
|
|
@@ -116,6 +119,9 @@ export type UseSmileIDCaptureScreenProps = {
|
|
|
116
119
|
/** Keeps the oval rim neutral through CAPTURING/PROCESSING — ESS has no green oval treatment. */
|
|
117
120
|
readonly enableEnhancedLiveness?: boolean;
|
|
118
121
|
|
|
122
|
+
/** Runs a selfie capture on the rear camera. Ignored for document capture. */
|
|
123
|
+
readonly allowAgentMode?: boolean;
|
|
124
|
+
|
|
119
125
|
/**
|
|
120
126
|
* Document aspect ratio (width / height) for the document capture
|
|
121
127
|
* guide cutout. Ignored for selfie capture. Omitted ⇒ the overlay's
|
|
@@ -162,9 +168,12 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
162
168
|
const theme = props.theme ?? defaultLightTheme;
|
|
163
169
|
const showAttribution = props.showAttribution ?? true;
|
|
164
170
|
const enableEnhancedLiveness = props.enableEnhancedLiveness ?? false;
|
|
171
|
+
const allowAgentMode = props.allowAgentMode ?? false;
|
|
165
172
|
// Literal union — useCameraDevice takes the lowercase string directly.
|
|
166
173
|
const cameraFacing: "front" | "back" =
|
|
167
|
-
props.captureType === CaptureType.selfie
|
|
174
|
+
props.captureType === CaptureType.selfie && !allowAgentMode
|
|
175
|
+
? "front"
|
|
176
|
+
: "back";
|
|
168
177
|
|
|
169
178
|
const { hasPermission, requestPermission } = useCameraPermission();
|
|
170
179
|
const device = useCameraDevice(cameraFacing);
|
|
@@ -202,8 +211,8 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
202
211
|
}, [hasPermission, requestPermission]);
|
|
203
212
|
|
|
204
213
|
// Per-frame scan state drives the overlay + feedback bubble.
|
|
205
|
-
const [scanState, setScanState] = useState<
|
|
206
|
-
type:
|
|
214
|
+
const [scanState, setScanState] = useState<UseSmileIDScanState>({
|
|
215
|
+
type: UseSmileIDScanStateType.Initial,
|
|
207
216
|
});
|
|
208
217
|
const [streaming, setStreaming] = useState<boolean>(false);
|
|
209
218
|
// Bumped on every Start tap to reset the feedback debouncer.
|
|
@@ -213,6 +222,13 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
213
222
|
const [hasAnalyzedFrame, setHasAnalyzedFrame] = useState<boolean>(false);
|
|
214
223
|
// Fallback shutter, revealed after activateManualAfterMs. Resets per mount.
|
|
215
224
|
const [manualShutterRevealed, setManualShutterRevealed] = useState(false);
|
|
225
|
+
// Set when a document scan times out, so the recovery controls stay on screen
|
|
226
|
+
// after the scan (and `streaming`) stops. `timedOutRef` keeps the terminal
|
|
227
|
+
// branch idempotent without latching the one-shot delivery gate.
|
|
228
|
+
const [captureTimedOut, setCaptureTimedOut] = useState(false);
|
|
229
|
+
const timedOutRef = useRef(false);
|
|
230
|
+
// Set when streaming produced no analyzed frame at all, which the analyzer's own timeout cannot report.
|
|
231
|
+
const [captureStalled, setCaptureStalled] = useState(false);
|
|
216
232
|
// True while a manual/gallery delivery is in flight — disables the controls.
|
|
217
233
|
const [deliveringDocument, setDeliveringDocument] = useState(false);
|
|
218
234
|
// Transient gallery-import error; overrides the live chip, self-clears so the user can re-pick.
|
|
@@ -232,7 +248,7 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
232
248
|
const completedRef = useRef<boolean>(false);
|
|
233
249
|
// Raw (not committed) frame state for the session-boundary check, so
|
|
234
250
|
// transitions the 1% bucketing skips committing are still seen.
|
|
235
|
-
const previousScanStateRef = useRef<
|
|
251
|
+
const previousScanStateRef = useRef<UseSmileIDScanState | null>(null);
|
|
236
252
|
|
|
237
253
|
// Capture telemetry: wall-clock start (first analyzed frame) and a
|
|
238
254
|
// rising-edge `unsatisfied` retry counter, surfaced via onCaptureComplete.
|
|
@@ -268,8 +284,28 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
268
284
|
setSessionEpoch((epoch) => epoch + 1);
|
|
269
285
|
// A new session must not compare against the old session's last state.
|
|
270
286
|
previousScanStateRef.current = null;
|
|
271
|
-
|
|
272
|
-
|
|
287
|
+
// Clear the terminal latches so a retry after a timeout or a stall is a fresh session.
|
|
288
|
+
const wasTerminal = timedOutRef.current;
|
|
289
|
+
timedOutRef.current = false;
|
|
290
|
+
setCaptureTimedOut(false);
|
|
291
|
+
setCaptureStalled(false);
|
|
292
|
+
setScanState({ type: UseSmileIDScanStateType.Initial });
|
|
293
|
+
setHasAnalyzedFrame(false);
|
|
294
|
+
// Frames banked before the abandoned session must not pad this one.
|
|
295
|
+
capturedEventsRef.current = [];
|
|
296
|
+
if (wasTerminal) {
|
|
297
|
+
// A timed-out native session is terminal — stream only after it resets,
|
|
298
|
+
// or the first retry frame re-reports Timeout and re-latches the error.
|
|
299
|
+
void props.analyzer
|
|
300
|
+
.reset()
|
|
301
|
+
.catch((error) => UseSmileIDCrashReporting.captureException(error))
|
|
302
|
+
.finally(() => {
|
|
303
|
+
if (!completedRef.current) setStreaming(true);
|
|
304
|
+
});
|
|
305
|
+
} else {
|
|
306
|
+
setStreaming(true);
|
|
307
|
+
}
|
|
308
|
+
}, [streaming, onStartCapture, props.analyzer]);
|
|
273
309
|
|
|
274
310
|
const analyzer = props.analyzer;
|
|
275
311
|
const onCaptureComplete = props.onCaptureComplete;
|
|
@@ -475,13 +511,14 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
475
511
|
if (captureStartedAtRef.current === null) {
|
|
476
512
|
captureStartedAtRef.current = Date.now();
|
|
477
513
|
}
|
|
478
|
-
const isUnsatisfied =
|
|
514
|
+
const isUnsatisfied =
|
|
515
|
+
result.state.type === UseSmileIDScanStateType.Unsatisfied;
|
|
479
516
|
if (isUnsatisfied && !wasUnsatisfiedRef.current) {
|
|
480
517
|
captureRetriesRef.current += 1;
|
|
481
518
|
}
|
|
482
519
|
wasUnsatisfiedRef.current = isUnsatisfied;
|
|
483
520
|
|
|
484
|
-
if (result.state.type ===
|
|
521
|
+
if (result.state.type === UseSmileIDScanStateType.Unsatisfied) {
|
|
485
522
|
capturedEventsRef.current = [];
|
|
486
523
|
} else if (result.capturedEvents.length > 0) {
|
|
487
524
|
capturedEventsRef.current = [
|
|
@@ -507,8 +544,9 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
507
544
|
|
|
508
545
|
// Terminal states: finished → flush + complete; timeout → failure
|
|
509
546
|
// without flushing (no captured artifacts to wait on).
|
|
510
|
-
if (result.state.type ===
|
|
511
|
-
|
|
547
|
+
if (result.state.type === UseSmileIDScanStateType.Finished) {
|
|
548
|
+
// `timedOutRef` too: stopping the stream is async, so a frame queued before the timeout can still land here.
|
|
549
|
+
if (completedRef.current || timedOutRef.current) return;
|
|
512
550
|
completedRef.current = true;
|
|
513
551
|
setStreaming(false);
|
|
514
552
|
// flush() waits for every emitted JPG to land on disk before we
|
|
@@ -524,10 +562,12 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
524
562
|
onDocumentOrigin?.(DocumentImageOrigin.CameraAutoCapture);
|
|
525
563
|
onCaptureComplete?.(capturedEventsRef.current, captureTelemetry());
|
|
526
564
|
});
|
|
527
|
-
} else if (result.state.type ===
|
|
528
|
-
if (completedRef.current) return;
|
|
529
|
-
completedRef.current = true;
|
|
565
|
+
} else if (result.state.type === UseSmileIDScanStateType.Timeout) {
|
|
566
|
+
if (completedRef.current || timedOutRef.current) return;
|
|
530
567
|
setStreaming(false);
|
|
568
|
+
// The terminal state rides on `timedOutRef`, not the one-shot delivery gate, so the shutter and Start button stay usable.
|
|
569
|
+
timedOutRef.current = true;
|
|
570
|
+
setCaptureTimedOut(true);
|
|
531
571
|
onCaptureTimeout?.(result.state);
|
|
532
572
|
}
|
|
533
573
|
},
|
|
@@ -549,7 +589,10 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
549
589
|
sessionEpoch,
|
|
550
590
|
);
|
|
551
591
|
const isInstructionState =
|
|
552
|
-
scanState.type ===
|
|
592
|
+
scanState.type === UseSmileIDScanStateType.Initial && !streaming;
|
|
593
|
+
// A selfie timeout leaves `scanState` on Timeout, so the instruction predicate alone would hide the only way to retry.
|
|
594
|
+
const showStartButton =
|
|
595
|
+
(isInstructionState || captureTimedOut) && !isDocumentCapture;
|
|
553
596
|
const canStart = !streaming && !completedRef.current;
|
|
554
597
|
|
|
555
598
|
const previewReady = hasPermission && device != null;
|
|
@@ -564,6 +607,28 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
564
607
|
[analyzer.frameProcessorPluginName],
|
|
565
608
|
);
|
|
566
609
|
|
|
610
|
+
// Every terminal signal arrives inside a frame result, so a camera that delivers no frame at all would sit on the initial state forever.
|
|
611
|
+
// Latest-ref, not a dep: an inline `onCaptureTimeout` prop is a fresh identity every render, which would restart the wall clock.
|
|
612
|
+
const onCaptureTimeoutRef = useRef(onCaptureTimeout);
|
|
613
|
+
onCaptureTimeoutRef.current = onCaptureTimeout;
|
|
614
|
+
useEffect(() => {
|
|
615
|
+
if (!streaming || hasAnalyzedFrame) return;
|
|
616
|
+
const timer = setTimeout(() => {
|
|
617
|
+
if (completedRef.current || timedOutRef.current) return;
|
|
618
|
+
timedOutRef.current = true;
|
|
619
|
+
setCaptureStalled(true);
|
|
620
|
+
setCaptureTimedOut(true);
|
|
621
|
+
setStreaming(false);
|
|
622
|
+
onCaptureTimeoutRef.current?.({ type: UseSmileIDScanStateType.Timeout });
|
|
623
|
+
}, CameraDefaults.firstFrameTimeoutMs);
|
|
624
|
+
return () => clearTimeout(timer);
|
|
625
|
+
}, [streaming, hasAnalyzedFrame]);
|
|
626
|
+
|
|
627
|
+
// A frame disproves the stall; document capture has no Start button to clear it by hand.
|
|
628
|
+
useEffect(() => {
|
|
629
|
+
if (hasAnalyzedFrame) setCaptureStalled(false);
|
|
630
|
+
}, [hasAnalyzedFrame]);
|
|
631
|
+
|
|
567
632
|
// A missing plugin means no frame ever produces a result — report once
|
|
568
633
|
// on capture start rather than sitting silently on the initial state.
|
|
569
634
|
const pluginErrorReportedRef = useRef(false);
|
|
@@ -687,13 +752,18 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
687
752
|
// Document controls — live capture only (after Start). Manual shutter
|
|
688
753
|
// follows the capture mode + fallback timer; gallery follows
|
|
689
754
|
// allowGalleryUpload. Renderer also hides both during CAPTURING/PROCESSING.
|
|
755
|
+
// A timeout offers the shutter in every capture mode — it is the recovery
|
|
756
|
+
// affordance, so it outranks `captureMode` and survives `streaming` going
|
|
757
|
+
// false with the scan.
|
|
690
758
|
const manualShutterAvailable =
|
|
691
759
|
isDocumentCapture &&
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
760
|
+
(captureTimedOut ||
|
|
761
|
+
(streaming &&
|
|
762
|
+
(captureMode?.kind === "manualCapture" ||
|
|
763
|
+
(captureMode?.kind === "autoCaptureWithManualFallback" &&
|
|
764
|
+
manualShutterRevealed))));
|
|
765
|
+
const galleryAvailable =
|
|
766
|
+
isDocumentCapture && (streaming || captureTimedOut) && allowGalleryUpload;
|
|
697
767
|
|
|
698
768
|
// Deps are scalar fields (mapCaptureUiState returns a fresh object per
|
|
699
769
|
// render). captureProgress intentionally stays a separate per-frame prop.
|
|
@@ -704,10 +774,12 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
704
774
|
enableEnhancedLiveness,
|
|
705
775
|
animationDirection: uiState.animationDirection,
|
|
706
776
|
poseMatched: uiState.poseMatched,
|
|
707
|
-
// A transient gallery-import error
|
|
708
|
-
feedbackKey:
|
|
777
|
+
// A stalled camera, then a transient gallery-import error, preempt the live feedback chip.
|
|
778
|
+
feedbackKey: captureStalled
|
|
779
|
+
? "si_capture_camera_unavailable"
|
|
780
|
+
: (galleryErrorKey ?? settledFeedbackKey),
|
|
709
781
|
// Documents auto-start (no Start button); selfie keeps its.
|
|
710
|
-
showCaptureButton:
|
|
782
|
+
showCaptureButton: showStartButton,
|
|
711
783
|
showManualShutter: manualShutterAvailable,
|
|
712
784
|
showGalleryUpload: galleryAvailable,
|
|
713
785
|
isBackSide: documentSide === DocumentSide.Back,
|
|
@@ -726,7 +798,8 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
726
798
|
uiState.poseMatched,
|
|
727
799
|
settledFeedbackKey,
|
|
728
800
|
galleryErrorKey,
|
|
729
|
-
|
|
801
|
+
captureStalled,
|
|
802
|
+
showStartButton,
|
|
730
803
|
isDocumentCapture,
|
|
731
804
|
manualShutterAvailable,
|
|
732
805
|
galleryAvailable,
|
|
@@ -806,8 +879,14 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
|
|
|
806
879
|
<UseSmileIDThemeProvider value={theme}>
|
|
807
880
|
{/* Translucent status bar → full-bleed window so the oval's reference
|
|
808
881
|
frame is the full screen (no-op on iOS). On-device-pending: residual
|
|
809
|
-
inset also depends on the host SafeAreaProvider config.
|
|
810
|
-
|
|
882
|
+
inset also depends on the host SafeAreaProvider config.
|
|
883
|
+
`dark-content` because the capture overlay draws a near-opaque white
|
|
884
|
+
scrim behind the status bar, whatever the host app's own bar style. */}
|
|
885
|
+
<StatusBar
|
|
886
|
+
translucent
|
|
887
|
+
backgroundColor="transparent"
|
|
888
|
+
barStyle="dark-content"
|
|
889
|
+
/>
|
|
811
890
|
<UseSmileIDCaptureContent
|
|
812
891
|
state={contentState}
|
|
813
892
|
captureProgress={uiState.captureProgress}
|
|
@@ -26,6 +26,7 @@ import { UseSmileIDLearnMoreContent } from "../components/use_smile_id_learn_mor
|
|
|
26
26
|
import { UseSmileIDPartnerIcon } from "../components/use_smile_id_partner_icon";
|
|
27
27
|
import { UseSmileIDRoundedCheckbox } from "../components/use_smile_id_rounded_checkbox";
|
|
28
28
|
import { useUseSmileIDLocalizations } from "../../l10n/use_smile_id_localizations_provider";
|
|
29
|
+
import { GlobalPrivacyControl } from "../../core/models/global_privacy_control";
|
|
29
30
|
import { getDefaultConsentState, getDeviceLocale } from "../utils/locale_utils";
|
|
30
31
|
import {
|
|
31
32
|
buildConsentRows,
|
|
@@ -59,6 +60,12 @@ export type UseSmileIDConsentScreenProps = {
|
|
|
59
60
|
readonly showAttribution?: boolean;
|
|
60
61
|
readonly onAllow?: (info: ConsentInformation) => void;
|
|
61
62
|
readonly onDeny?: () => void;
|
|
63
|
+
/**
|
|
64
|
+
* Partner-declared consent posture; seeds the checkbox's initial state
|
|
65
|
+
* via `getDefaultConsentState`. Defaults to the universal opt-out
|
|
66
|
+
* baseline (`GlobalPrivacyControl.OptOut`).
|
|
67
|
+
*/
|
|
68
|
+
readonly globalPrivacyControl?: GlobalPrivacyControl;
|
|
62
69
|
readonly theme?: UseSmileIDTheme;
|
|
63
70
|
/**
|
|
64
71
|
* Render the bottom-pinned Allow button via a partner-supplied
|
|
@@ -107,11 +114,15 @@ export function UseSmileIDConsentScreen(props: UseSmileIDConsentScreenProps) {
|
|
|
107
114
|
const loc = useUseSmileIDLocalizations();
|
|
108
115
|
const showAttribution = props.showAttribution ?? true;
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
//
|
|
114
|
-
|
|
117
|
+
const globalPrivacyControl =
|
|
118
|
+
props.globalPrivacyControl ?? GlobalPrivacyControl.OptOut;
|
|
119
|
+
|
|
120
|
+
// Posture-aware default: the opt-out baseline starts ticked everywhere;
|
|
121
|
+
// the legacy opt-in posture consults the resolved BCP-47 locale and
|
|
122
|
+
// starts unticked for EU member states (GDPR opt-in).
|
|
123
|
+
const [consented, setConsented] = useState(() =>
|
|
124
|
+
getDefaultConsentState(globalPrivacyControl),
|
|
125
|
+
);
|
|
115
126
|
const [learnMoreOpen, setLearnMoreOpen] = useState(false);
|
|
116
127
|
|
|
117
128
|
const subtitleParts = composeConsentSubtitleParts(props.partnerName, loc);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StyleSheet, Text, View } from "react-native";
|
|
2
2
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
3
3
|
import type { UseSmileIDTheme } from "../theme/theme";
|
|
4
4
|
import { useUseSmileIDTheme } from "../theme/theme_context";
|
|
5
|
+
import { UseSmileIDAttribution } from "../components/use_smile_id_attribution";
|
|
5
6
|
import { UseSmileIDBackButton } from "../components/use_smile_id_back_button";
|
|
6
7
|
import { UseSmileIDButton } from "../components/use_smile_id_button";
|
|
7
8
|
import { UseSmileIDInstructionsHero } from "../components/use_smile_id_instructions_hero";
|
|
@@ -48,7 +49,7 @@ export function UseSmileIDDocumentBackInstructions(
|
|
|
48
49
|
styles.root,
|
|
49
50
|
{
|
|
50
51
|
backgroundColor: theme.colors.background,
|
|
51
|
-
paddingHorizontal: theme.spacing.
|
|
52
|
+
paddingHorizontal: theme.spacing.medium,
|
|
52
53
|
paddingVertical: theme.spacing.medium,
|
|
53
54
|
},
|
|
54
55
|
]}
|
|
@@ -70,12 +71,15 @@ export function UseSmileIDDocumentBackInstructions(
|
|
|
70
71
|
...theme.typography.pageHeading,
|
|
71
72
|
fontWeight: "800",
|
|
72
73
|
color: theme.colors.titleText,
|
|
74
|
+
textAlign: "center",
|
|
73
75
|
}}
|
|
74
76
|
testID="si_document_back_instructions_title"
|
|
75
77
|
>
|
|
76
78
|
{localizations.siDocumentFlipTitle(props.documentTypeDisplayName)}
|
|
77
79
|
</Text>
|
|
78
80
|
|
|
81
|
+
<View style={{ height: theme.spacing.medium }} />
|
|
82
|
+
|
|
79
83
|
<View style={styles.hero} testID="si_document_back_instructions_hero">
|
|
80
84
|
<UseSmileIDInstructionsHero
|
|
81
85
|
source={heroSource}
|
|
@@ -98,24 +102,17 @@ export function UseSmileIDDocumentBackInstructions(
|
|
|
98
102
|
{allowSkip ? (
|
|
99
103
|
<>
|
|
100
104
|
<View style={{ height: theme.spacing.small }} />
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
<UseSmileIDButton
|
|
106
|
+
label={localizations.siDocumentSkipBack}
|
|
107
|
+
onClick={onSkip}
|
|
108
|
+
variant="secondary"
|
|
109
|
+
theme={theme}
|
|
104
110
|
testID="si_document_skip_back_button"
|
|
105
|
-
|
|
106
|
-
>
|
|
107
|
-
<Text
|
|
108
|
-
style={{
|
|
109
|
-
...theme.typography.button,
|
|
110
|
-
color: theme.colors.primary,
|
|
111
|
-
textAlign: "center",
|
|
112
|
-
}}
|
|
113
|
-
>
|
|
114
|
-
{localizations.siDocumentSkipBack}
|
|
115
|
-
</Text>
|
|
116
|
-
</Pressable>
|
|
111
|
+
/>
|
|
117
112
|
</>
|
|
118
113
|
) : null}
|
|
114
|
+
<View style={{ height: theme.spacing.small }} />
|
|
115
|
+
<UseSmileIDAttribution theme={theme} />
|
|
119
116
|
</View>
|
|
120
117
|
</SafeAreaView>
|
|
121
118
|
);
|
|
@@ -125,10 +122,4 @@ const styles = StyleSheet.create({
|
|
|
125
122
|
root: { flex: 1 },
|
|
126
123
|
hero: { flex: 1 },
|
|
127
124
|
bottom: { alignItems: "center" },
|
|
128
|
-
skip: {
|
|
129
|
-
height: 48,
|
|
130
|
-
alignItems: "center",
|
|
131
|
-
justifyContent: "center",
|
|
132
|
-
alignSelf: "stretch",
|
|
133
|
-
},
|
|
134
125
|
});
|
|
@@ -47,7 +47,7 @@ export function UseSmileIDDocumentPreviewScreen(
|
|
|
47
47
|
edges={["left", "right", "bottom"]}
|
|
48
48
|
style={[
|
|
49
49
|
styles.root,
|
|
50
|
-
{ backgroundColor: theme.colors.
|
|
50
|
+
{ backgroundColor: theme.colors.background },
|
|
51
51
|
]}
|
|
52
52
|
testID="si_document_preview_screen"
|
|
53
53
|
>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState
|
|
1
|
+
import { useState } from "react";
|
|
2
2
|
import { StyleSheet, Text, View, type LayoutChangeEvent } from "react-native";
|
|
3
3
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
4
4
|
import type { UseSmileIDTheme } from "../theme/theme";
|
|
@@ -16,28 +16,13 @@ export type UseSmileIDPreviewScreenProps = {
|
|
|
16
16
|
readonly showAttribution?: boolean;
|
|
17
17
|
readonly onAccept?: () => void;
|
|
18
18
|
readonly onReject?: () => void;
|
|
19
|
-
/**
|
|
20
|
-
* Render the Accept button via a partner-supplied slot.
|
|
21
|
-
*
|
|
22
|
-
* **Slot contract:** providing *any* slot (continue or cancel)
|
|
23
|
-
* replaces the *entire* default confirmation row. If you supply
|
|
24
|
-
* `continueButton` and want a Retake control too, supply
|
|
25
|
-
* `cancelButton` as well — the default Retake tile does not
|
|
26
|
-
* fall through.
|
|
27
|
-
*/
|
|
28
|
-
readonly continueButton?: (props: { onClick: () => void }) => ReactNode;
|
|
29
|
-
/**
|
|
30
|
-
* Render the Reject (retake) button via a partner-supplied slot.
|
|
31
|
-
* See the slot contract note on `continueButton`.
|
|
32
|
-
*/
|
|
33
|
-
readonly cancelButton?: (props: { onClick: () => void }) => ReactNode;
|
|
34
19
|
readonly theme?: UseSmileIDTheme;
|
|
35
20
|
};
|
|
36
21
|
|
|
37
22
|
/**
|
|
38
23
|
* Preview screen — confirms the captured selfie before submission.
|
|
39
24
|
*
|
|
40
|
-
* - Uniform page (`
|
|
25
|
+
* - Uniform page (`background`, theme-following) with the
|
|
41
26
|
* captured image clipped to the face oval. The oval scales to the
|
|
42
27
|
* leftover height above the card so the two never overlap; no scrim
|
|
43
28
|
* is painted.
|
|
@@ -74,16 +59,12 @@ export function UseSmileIDPreviewScreen(props: UseSmileIDPreviewScreenProps) {
|
|
|
74
59
|
if (state.canRetake) props.onReject?.();
|
|
75
60
|
};
|
|
76
61
|
|
|
77
|
-
const customContinue = props.continueButton;
|
|
78
|
-
const customCancel = props.cancelButton;
|
|
79
|
-
const hasSlots = Boolean(customContinue || customCancel);
|
|
80
|
-
|
|
81
62
|
return (
|
|
82
63
|
<SafeAreaView
|
|
83
64
|
edges={["left", "right", "bottom"]}
|
|
84
65
|
style={[
|
|
85
66
|
styles.root,
|
|
86
|
-
{ backgroundColor: theme.colors.
|
|
67
|
+
{ backgroundColor: theme.colors.background },
|
|
87
68
|
]}
|
|
88
69
|
testID="si_preview_screen"
|
|
89
70
|
onLayout={onScreenLayout}
|
|
@@ -122,23 +103,16 @@ export function UseSmileIDPreviewScreen(props: UseSmileIDPreviewScreenProps) {
|
|
|
122
103
|
{loc.siPreviewSubtitle}
|
|
123
104
|
</Text>
|
|
124
105
|
<View style={{ marginTop: theme.spacing.medium }}>
|
|
125
|
-
{
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
onReject={handleReject}
|
|
136
|
-
acceptLabel={loc.siPreviewConfirm}
|
|
137
|
-
rejectLabel={loc.siPreviewRetake}
|
|
138
|
-
theme={theme}
|
|
139
|
-
testID="si_preview_confirmation_buttons"
|
|
140
|
-
/>
|
|
141
|
-
)}
|
|
106
|
+
{/* The confirm/retake buttons are the fixed icon pair and are not
|
|
107
|
+
customisable. */}
|
|
108
|
+
<UseSmileIDConfirmationButtons
|
|
109
|
+
onAccept={handleAccept}
|
|
110
|
+
onReject={handleReject}
|
|
111
|
+
acceptLabel={loc.siPreviewConfirm}
|
|
112
|
+
rejectLabel={loc.siPreviewRetake}
|
|
113
|
+
theme={theme}
|
|
114
|
+
testID="si_preview_confirmation_buttons"
|
|
115
|
+
/>
|
|
142
116
|
</View>
|
|
143
117
|
</UseSmileIDCardSurface>
|
|
144
118
|
|
|
@@ -150,10 +124,4 @@ export function UseSmileIDPreviewScreen(props: UseSmileIDPreviewScreenProps) {
|
|
|
150
124
|
const styles = StyleSheet.create({
|
|
151
125
|
root: { flex: 1, overflow: "hidden" },
|
|
152
126
|
card: { alignItems: "center" },
|
|
153
|
-
buttonRow: {
|
|
154
|
-
flexDirection: "row",
|
|
155
|
-
alignSelf: "stretch",
|
|
156
|
-
justifyContent: "space-between",
|
|
157
|
-
alignItems: "center",
|
|
158
|
-
},
|
|
159
127
|
});
|
|
@@ -110,7 +110,7 @@ export function UseSmileIDProcessingScreen(
|
|
|
110
110
|
<SafeAreaView
|
|
111
111
|
style={[
|
|
112
112
|
styles.root,
|
|
113
|
-
{ backgroundColor: theme.colors.
|
|
113
|
+
{ backgroundColor: theme.colors.background },
|
|
114
114
|
]}
|
|
115
115
|
testID="si_processing_screen"
|
|
116
116
|
onLayout={onScreenLayout}
|