RepairShopr / react-native-signature-capture

A simple modular component for react native (iOS) to capture a signature as an image
MIT License
962 stars 514 forks source link

BUG: Save/Clear issues on having Multiple Signature Captures in the same component #300

Open ksodhithentia opened 8 months ago

ksodhithentia commented 8 months ago

I have a component with 2 signatures, am passing 2 unique ref but still the top one is not responsive. When i hit clear/save it always triggers clear/save on the bottom pad.

This issue is in ios only. Android works fine.

import React, {useEffect, useState} from 'react'; import {View, Text} from '@gluestack-ui/themed'; import SignaturePad from '../SignaturePad';

interface SignaturesProps { inspectionId: string; contentData: { reg_contact?: string; reg_inspectorid?: {text: string}; }; }

const Signatures: React.FC = ({ inspectionId: initialInspectionId, contentData, }) => { const {t} = useCustomTranslation(); const [inspectionId, setInspectionId] = useState(initialInspectionId); useEffect(() => { setInspectionId(initialInspectionId); }, [initialInspectionId]);

return ( <View pt={'$5'}>

{t('INSPECTION_REPORT_SIGNATURES_SUB_HEADING')}
  <View pt={'$5'}>
    <Text size="sm">
      {t('INSPECTION_REPORT_BUSINESS_REPRESENTATIVE_LABEL_NAME')}
    </Text>
    <Text size="lg">{contentData?.reg_contact}</Text>
    <View pt={'$5'}>
      <SignatureComponent></SignatureComponent>
      {/* <SignaturePad
        fileName={'representative_esign.png'}
        entity="reg_inspection"
        entityId={inspectionId}
        inspectionReportId={inspectionId}
      /> */}
    </View>
  </View>

  <View pt={'$5'}>
    <Text size="sm">
      {t('INSPECTION_REPORT_INSPECTION_MEETING_DETAILS_LABEL_INSPECTOR')}
    </Text>
    <Text size="lg">{contentData?.reg_inspectorid?.text}</Text>
    <View pt={'$5'}>
      {/* <SignaturePad
        fileName={'inspector_esign.png'}
        entity="reg_inspection"
        entityId={inspectionId}
        inspectionReportId={inspectionId}
      /> */}
    </View>
  </View>
</View>

); };

export default Signatures;

import SignatureCapture from 'react-native-signature-capture'; import RNFS from 'react-native-fs'; import React, { FC, useState, useRef, useEffect, useMemo, useCallback, } from 'react'; import {StyleSheet, Platform} from 'react-native'; import {View, Image, Button, ButtonText} from '@gluestack-ui/themed'; import {useAppDispatch, useAppSelector} from '../store/hooks'; import {setError} from '../store/slices/globalStateUtilSlice'; import {UploadFileType} from './fileUpload/FileUpload'; import {setSignatures} from '../store/slices/signaturePadSlice'; import {clearError} from '../store/slices/globalStateUtilSlice';

interface SignaturePadProps { fileName: string; entity: string; entityId: string; inspectionReportId: string; }

const SignaturePad: FC = ({ fileName, entity, entityId, inspectionReportId, }) => { const sign = useRef(null); const entityIdRef = useRef(entityId); const inspectionReportIdRef = useRef(inspectionReportId);

useEffect(() => { entityIdRef.current = entityId; inspectionReportIdRef.current = inspectionReportId; }, [entityId, inspectionReportId]);

const [signatureFileLocation, setSignatureFileLocation] = useState(''); const [ifFileAlreadyExists, setIfFileAlreadyExists] = useState(false);

const [isDirty, setIsDirty] = useState(false); const dispatch = useAppDispatch(); const {signatures} = useAppSelector(State => State.signaturesUpload);

const signatureImages = useMemo( () => signatures[inspectionReportId]?.[entity]?.[entityId] || [], [signatures, inspectionReportId, entity, entityId], );

useEffect(() => { if ( fileName && entity && entityIdRef.current && inspectionReportIdRef.current ) { let signatureByName: UploadFileType | undefined; if (signatureImages.length > 0) { signatureByName = signatureImages.find(si => { return inspectionReportIdRef.current + '_' + fileName === si.name; }); signatureByName && setIfFileAlreadyExists(true); signatureByName && setSignatureFileLocation('file://' + signatureByName?.uri); } } }, [fileName, entity, entityId, inspectionReportId]);

const buildFileName = useCallback( async (savedImagePath: string): Promise => { let newFilePath = ''; try { const directory = savedImagePath.substring( 0, savedImagePath.lastIndexOf('/'), ); newFilePath = ${directory}/${inspectionReportIdRef.current}_${fileName};

    const fileExists = await RNFS.exists(newFilePath);

    if (fileExists) {
      await RNFS.unlink(newFilePath);
    }

    await RNFS.moveFile(savedImagePath, newFilePath);
    alert('Signature Saved!');
    return newFilePath;
  } catch (error) {
    dispatch(setError(error));
    throw error;
  }
},
[dispatch, fileName, entity, entityId, inspectionReportId],

);

const addSignatureToStore: any = useCallback( async (uri: string, name: string, type: string) => { try { const filePath = await buildFileName(uri); const data = { name: inspectionReportIdRef.current + '_' + fileName, uri: filePath, type: type, }; dispatch( setSignatures({ file: data, inspectionReportId: inspectionReportIdRef.current, entity: entity, entityId: entityIdRef.current, }), ); dispatch(clearError()); } catch (error) { console.error('Error adding signature to store:', error); } }, [buildFileName, dispatch, entity, entityId, inspectionReportId, fileName], );

const saveSign = async () => { isDirty ? sign.current?.saveImage() : alert('Empty Signature!'); };

const resetSign = () => { setIsDirty(false); !ifFileAlreadyExists ? sign.current.resetImage() : setIfFileAlreadyExists(false); };

const onSaveEvent = (result: any) => { addSignatureToStore(result.pathName, fileName, 'png'); };

const onDragEvent = () => { setIsDirty(true); };

return (

{ifFileAlreadyExists ? ( signatureFileLocation ? ( {'inspector ) : null ) : ( )}
</View>

); };

const styles = StyleSheet.create({ signature: { width: '100%', height: 192, }, disabledButton: { display: 'none', }, });

export default SignaturePad;