Index Home Page - Zanegerous/CopperToGold GitHub Wiki

``# Home Page This is where most of our functions are contained as most of the functionality is located here.

Permissions

The start of the file has permission request in order to manage the camera

 if (!permission.granted) {
    return (
      <View className="flex-1">
        <Text className="bg-black text-white rounded-md text-center text-2xl top-5 w-8/12" style={{ fontSize: scale(24) }}>We need your permission to show the camera</Text>
        <Button onPress={requestPermission} title="grant permission" />
      </View>
    );
  }

Saving and Delete Item from Firebase

Saving

  const saveItem = async (item: EbayItem) => {
    const cleanTitle = item.title.replace(/[^a-zA-Z0-9]/g, "_");
    const saveRef = `users/${userUID}/savedItems/${cleanTitle}`
    const itemRef = dbRef(database, saveRef);

    try {
      await set(itemRef, {
        title: item.title,
        price: item.price,
        image: item.image,
        condition: item.condition,
        id: item.id
      });
      console.log('saved Item: ', item.title)
    } catch (error: any) {
      console.error("Save Error: ", error);
    }
  }

Deleting

const deleteSavedItem = async (item: EbayItem) => {
    const cleanTitle = item.title.replace(/[^a-zA-Z0-9]/g, "_");
    const saveRef = dbRef(database, `users/${userUID}/savedItems/${cleanTitle}`);
    
     try {
      await remove(saveRef);
      console.log('Removed Item: ', item.title)
    } catch (error: any) {
      console.error("Delete Error: ", error);
    }
  }

renderResultItem

Formatting for the result box, which formats the search results recieved into something our scrollview can use.

const RenderResultItem = ({ item }: { item: EbayItem }) => {
    const [resultModal, setResultModal] = useState(false);
    const soldPageLink = `https://www.ebay.com/sch/i.html?_nkw=${item.title}&_sacat=0&_from=R40&LH_Sold=1&LH_Complete=1&rt=nc&LH_BIN=1`
    const [saveState, setSaveState] = useState(false);
    const [soldPageModal, setSoldPageModal] = useState(false);
    const textSettings = ' color-white'; // space needed at start

    return (
      <View className="bg-slate-600 flex-1 border-black rounded-md border-spacing-4 border-2 mb-4 mr-5 ml-5 w-2/5">
        <TouchableOpacity
          onPress={() => { setResultModal(true) }}
          className=""
        >

          {/*This is the outside image*/}
          <Image
            source={{ uri: item.image }}
            className="h-48 m-1 rounded-lg"
            resizeMode='contain'
          />
          <Text className="text-center color-blue-900 font-semibold m-2 rounded-lg bg-zinc-400 text-sm">{item.title}</Text>
          <Text className="text-left text-l ml-1 text-white">Listed Price: ${item.price.value}</Text>
          <Text className="text-left ml-1 text-white">Condition: {item.condition}</Text>

        </TouchableOpacity>

        {/* Zoom up modal */}
        <Modal visible={resultModal} onRequestClose={() => { setResultModal(false) }} animationType='fade'>
          <View className="bg-blue-dark-200 flex-1">
            <View className="flex-row justify-between items-center">

              <TouchableOpacity className=" px-1 mt-4 ml-2  "
                onPress={() => {
                  setResultModal(false)
                }}>
                <Icon name={'arrow-circle-o-left'} color={'orange'} size={50} />
              </TouchableOpacity>

              <TouchableOpacity onPress={() => {
                if (saveState == false) {
                  saveItem(item);
                  setSaveState(true);
                } else {
                  deleteSavedItem(item);
                  setSaveState(false);
                }
              }}
                className="mt-4 mr-2 "
              >
                <Icon name={'star'} size={50} color={saveState ? 'yellow' : 'grey'} />
              </TouchableOpacity>
            </View>

            <Text className={"text-center font-bold text-3xl bg-blue-dark-100 w-auto m-1 rounded-xl border-black border-2  mb-2 mt-2" + textSettings}>{item.title}</Text>
            <Image
              source={{ uri: item.image }}
              className="w-11/12 h-1/2 m-1 rounded-lg self-center bg-slate-600"
              resizeMode='contain'
            />
            <Text className={"text-left text-3xl ml-4 mt-6" + textSettings}>Listing Price: ${item.price.value}</Text>
            <Text className={"text-left text-3xl ml-4" + textSettings}>Condition: {item.condition}</Text>


            <View className="flex-row absolute bottom-2 justify-center content-center w-full">
              <TouchableOpacity onPress={() => setSoldPageModal(true)} className="bg-orange-400 rounded-lg border-2 border-black justify-center w-2/5 self-center h-16" >
                <Text className={"text-center text-2xl justify-center" + textSettings}>See Sold Items</Text>
              </TouchableOpacity>
              <TouchableOpacity onPress={() => { setText(item.title); handleSearch(); setResultModal(false) }} className="bg-orange-400 m-2 rounded-lg border-2 border-black w-1/2 justify-center self-center h-16" >
                <Text className={"text-center text-2xl" + textSettings}>Search This Item</Text>
              </TouchableOpacity>
            </View>

            <View className="w-full h-2/3 self-center p-5">
              <Modal visible={soldPageModal} animationType='slide' onRequestClose={() => { setSoldPageModal(false) }}>
                <View className="bg-blue-dark-100">
                  <TouchableOpacity className=" self-left px-1 mt-2 mb-2 ml-2  "
                    onPress={() => {
                      setSoldPageModal(false)
                    }}>
                    <Icon name={'arrow-circle-o-left'} color={'orange'} size={50} />
                  </TouchableOpacity>
                </View>
                <WebView
                  source={{ uri: soldPageLink }}
                  scalesPageToFit={true}
                />
              </Modal>
            </View>
          </View>
        </Modal>
      </View>
    )
  };

textSearch()

Takes the image from the camera and determines what text is located in it, returning the text and placing it in the search bar for the user to edit before searching

const takePictureText = async (camera: { takePictureAsync: () => any } | null) => {
    try {
        if (camera != null) {
            
            const apiKey = ''; // hidden for security reasons will be moved to back end
            const photo = await camera.takePictureAsync();
            const urifetch = await fetch(photo.uri);
            const blob = await urifetch.blob();
            const storage = getStorage();
            const dateUploadTime = Date.now()
            // upload the image ref
            const folderLocation = `user/${getUserID()}/temp/${dateUploadTime}.jpg`
            const imageRef = storageRef(storage, folderLocation);
            await uploadBytes(imageRef, blob);
            const firebaseUrl = await getDownloadURL(imageRef);

            const endpointUrl = `https://api.apilayer.com/image_to_text/url?url=${encodeURIComponent(firebaseUrl)}`;

            const response = await axios.get(endpointUrl, {
                headers: {
                    apiKey: apiKey,
                },
            });

            const text = response.data.all_text;

            // remove it once done.
            await deleteObject(imageRef);
            return text;
        }
    } catch (error) {
        console.error('Error: ', error);
        return 'Error'
    }
};

There is also search settings which can be changed so that it is able to define what type of stuff you

 <View className={settingWrapper}>
            <Text style={{ fontSize: scale(16) }} className={buttonText}>
              Item Condition: {
                itemCondition === 'all' ? 'All' :
                  itemCondition === '1000' ? 'New' :
                    itemCondition === '3000' ? 'Used' :
                      itemCondition === '7000' ? 'Parts' : 'All'
              }
            </Text>
            <Picker
              selectedValue={itemCondition}
              onValueChange={(value) => setItemCondition(value)}
              style={{
                height: 40,
                width: '20%',
                backgroundColor: '#fff',
                borderRadius: 5,
                textAlign: 'center',
              }}
            >
              {itemConditionOptions.map((option) => (
                <Picker.Item key={option.value} label={option.label} value={option.value} />
              ))}
            </Picker>
          </View>

renderHistory

This is the formatting for the history bar, located on the home page. currently not functional on the result page due to personal preference.

dualSearchMerge

This function converts and compares the results from the text search aswell as the image result, returning what exists in both lists.

convertImageToBase64

this function converts a given image uri into base64 format to be utilized.

searchBarcodeResult

When the camera scans a barcode, then this function will set the text to the scanned barcode and search it.

takePicture

This function gets the current cameraview and captures the image, then it searches the image through ebay.

searchImageResults

This function takes in a base64 image string, then sending it to be searched on ebay, also managing the loading icon.

searchTextResults

This function calls the text variable, then sending it to be searched on ebay, also managing the loading icon.

searchSold

sets the sold view to showcase sold items

handleSearchOpen

Animation to open the search bar and modify modal variables

handleSeardchClose

Animation to close the search bar and modify modal variables

handleHistory

Logic to update the search history, setting it up to 10 values.

handleSearch

If text exists this handles the text search

getAvgPrice

Takes in a list of Ebay items and calculates the average based on the length and price.

const getAvgPrice = (list: EbayItem[] | null): number => {
    if (list == null || list.length == 0) {
      return 0;
    } else {
      const total = list.reduce((sum, item) => sum + parseFloat(item.price.value), 0);
      const avg = total / list.length
      return parseFloat(avg.toFixed(2));
    }
  };

Translation

Added all the i18n text translation for english to spanish to all text in the index.

 <View className="bg-slate-600 flex-1 border-black rounded-md border-spacing-4 border-2 mb-4 mr-5 ml-5 w-2/5">
        <TouchableOpacity
          onPress={() => { setResultModal(true) }}
          className=""
        >

          {/*This is the outside image*/}
          <Image
            source={{ uri: item.image }}
            className="h-48 m-1 rounded-lg"
            resizeMode='contain'
          />
          <Text className="text-center color-blue-900 font-semibold m-2 rounded-lg bg-zinc-400 text-sm">{item.title}</Text>
          <Text className="text-left text-l ml-1 text-white">{t("PriceListed")}: ${item.price.value}</Text>
          <Text className="text-left ml-1 text-white">{t("ItemConditioning")}: {item.condition}</Text>
        </TouchableOpacity>

return

This is the formatting for all of the code, managing and calling functions in order to manage the home/index page

⚠️ **GitHub.com Fallback** ⚠️