Repository: NMF-earth/nmf-app (language: typescript)

Issue:
Non-working links
The two links on the end of the settings pages are not available. 

**To Reproduce**
Steps to reproduce the behavior:
1. Go to 'settings'
2. Scroll down to the end of the page
3. Click on 'mastodon.social icon and medium.com'
4. See error

**Expected behaviour**
Links should take us to a useful page.

**Screenshots**

![Image](https://github.com/user-attachments/assets/e7114eb2-fee4-4446-9252-f29c2c651d3e)
![Image](https://github.com/user-attachments/assets/a63ab8dc-cdcd-4eb1-bb8d-1346a61857ba)
![Image](https://github.com/user-attachments/assets/1f1635c4-6de5-4646-8379-fbcd79eb643c)

** Please complete the following information (if applicable):**
 - Device: Motorola Edge 40 neo
 - OS: Android
 - Version [e.g. 0.5.0]





Discussion hints:
I'd like to know if there are any other links you would want to add instead of these. Also the about page is very simple, i would like to redesign it.
Hey,
The 2 available links atm are github and nmf website, I've close down social media. Feel free to submit a redesign :)
@PierreBresson did you take down http://nmf.earth ? seems no more avalilable?
@hb2708 it's online here now : https://nmf-earth.github.io
> [@hb2708](https://github.com/hb2708) it's online here now : https://nmf-earth.github.io

@PierreBresson 
Thanks for pointing it out.

I was trying to fix the issue by removing the close down social link and noticed that multiple test are failing as well us unable to commit at all due to same. And it seems from the [latest commit on master](https://github.com/NMF-earth/nmf-app/commit/b0414f6c6bf3706d8a2060c7fd680204ff75f44c). Would you be okey if i help to fix those tests as well?


Pull request: Update Social Links on SettingsScreen + Fix Failing Lint and tests
Fixes #400 

✅ I have read the [contributing file](https://github.com/NMF-earth/nmf-app/blob/main/contributing.md)

## Summary

This PR updates the application to be compatible with Expo 52, refactors deprecated APIs, and improves the Social Media component.

**Motivation:**
- **Expo 52 Compatibility:** The `expo-camera` and `expo-notifications` APIs have changed, requiring updates to our implementation.
- **Test Stability:** The upgrade changed how assets are mocked in tests, causing snapshot failures that needed to be resolved.
- **UI Modernization:** The Social Media links needed to be consolidated and the layout improved.

## Changelog

- **SocialMedia**: Replaced Mastodon/Medium links with a single Website link and updated layout to use `gap`.
- **Notifications**: Updated scheduling logic to use `SchedulableTriggerInputTypes.WEEKLY` and removed deprecated fields.
- **BarCodeScan**: Migrated from legacy `expo-camera` to `CameraView` and `useCameraPermissions`.
- **Tests**: Updated snapshots for `StickersImage`, `OpenFoodFacts`, [SettingsScreen](cci:1://file:///Users/harshalbhavsar/Documents/Code/nmf-app/app/screens/Settings/SettingsScreen.tsx:21:0-162:2), and [MonthlyBudgetScreen](cci:1://file:///Users/harshalbhavsar/Documents/Code/nmf-app/app/screens/MonthlyBudget/MonthlyBudgetScreen.tsx:58:0-139:2) to match Expo 52's image mocking and library updates. Removed unused `expo-barcode-scanner` mock.

## Demo

| Before | After | 
|:--------|:-----------:|
| <img width="1170" height="2532" alt="Simulator Screenshot - iPhone 16e - 2025-12-01 at 17 20 31" src="https://github.com/user-attachments/assets/d6920583-2852-4313-ac11-87827f4b1bb0" /> |  <img width="1170" height="2532" alt="Simulator Screenshot - iPhone 16e - 2025-12-01 at 17 19 52" src="https://github.com/user-attachments/assets/81d93da0-4571-4be8-98dd-841dce2078ba" /> |


**Tests Passed:**
Ran `yarn test` successfully with all 66 test suites passing.

```bash
Test Suites: 66 passed, 66 total
Tests:       433 passed, 433 total
Snapshots:   143 passed, 143 total
Time:        15.013 s

Test command: NODE_OPTIONS='--experimental-vm-modules --max-old-space-size=4096' npx --no-install jest app/components/OpenFoodFacts/__tests__/OpenFoodFacts.test.tsx app/components/SocialMedia/__tests__/SocialMedia.test.tsx app/components/StickersImage/__tests__/StickersImage.test.tsx app/screens/MonthlyBudget/__tests__/MonthlyBudgetScreen.test.tsx app/screens/Settings/__tests__/SettingsScreen.test.tsx --passWithNoTests 2>&1

Fix patch:
diff --git a/app/components/SocialMedia/SocialMedia.styles.ts b/app/components/SocialMedia/SocialMedia.styles.ts
index ebb319e7..6835b392 100644
--- a/app/components/SocialMedia/SocialMedia.styles.ts
+++ b/app/components/SocialMedia/SocialMedia.styles.ts
@@ -9,8 +9,9 @@ export default StyleSheet.create({
   box: {
     flex: 1,
     flexDirection: "row",
-    justifyContent: "space-between",
+    justifyContent: "center",
     maxWidth: 200,
+    gap: 40,
     paddingBottom: 50,
   },
 });
diff --git a/app/components/SocialMedia/SocialMedia.tsx b/app/components/SocialMedia/SocialMedia.tsx
index 5e1f3875..25992879 100644
--- a/app/components/SocialMedia/SocialMedia.tsx
+++ b/app/components/SocialMedia/SocialMedia.tsx
@@ -13,12 +13,8 @@ const socialMedia = [
     url: "https://github.com/NMF-earth",
   },
   {
-    iconName: "mastodon",
-    url: "https://mastodon.social/@nmf_earth",
-  },
-  {
-    iconName: "medium-m",
-    url: "https://medium.com/@nmf_earth",
+    iconName: "globe",
+    url: "https://nmf-earth.github.io",
   },
 ];
 
diff --git a/app/screens/BarCodeScan/BarCodeScanScreen.tsx b/app/screens/BarCodeScan/BarCodeScanScreen.tsx
index ce61ed7c..798fa26b 100644
--- a/app/screens/BarCodeScan/BarCodeScanScreen.tsx
+++ b/app/screens/BarCodeScan/BarCodeScanScreen.tsx
@@ -1,7 +1,7 @@
 import React, { useState, useEffect } from "react";
 import { useNavigation } from "@react-navigation/native";
 import { ActivityIndicator, View } from "react-native";
-import { CameraView, CameraType, useCameraPermissions } from "expo-camera";
+import { CameraView, useCameraPermissions } from "expo-camera";
 import { is, path, pathOr, both, complement, equals } from "ramda";
 import constants from "expo-constants";
 
@@ -24,7 +24,7 @@ const getEcoScore = pathOr("", ["ecoscore_grade"]);
 const getName = path(["product_name"]);
 
 const BarCodeScanScreen = ({ language = "" }: LocalizationContextProps) => {
-  const [hasPermission, setHasPermission] = useState(null);
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
   const [scanned, setScanned] = useState(false);
   const [hasCarbonData, setHasCarbonData] = useState(true);
   const [isFetchingData, setIsFetchingData] = useState(false);
@@ -39,15 +39,13 @@ const BarCodeScanScreen = ({ language = "" }: LocalizationContextProps) => {
   const { version, ios, android } = constants.expoConfig;
   const buildNumber = platform.isIOS ? ios.buildNumber : android.versionCode;
   const platformType = platform.isIOS ? "iOS" : "Android";
-  // TODO:
   const [permission, requestPermission] = useCameraPermissions();
 
   useEffect(() => {
     (async () => {
-      const { status } = await requestPermission();
-      setHasPermission(status === "granted");
+      await requestPermission();
     })();
-  }, []);
+  }, [requestPermission]);
 
   const onPressTryAgain = () => {
     setError(false);
@@ -119,7 +117,7 @@ const BarCodeScanScreen = ({ language = "" }: LocalizationContextProps) => {
     return <View style={styles.container}></View>;
   }
 
-  if (!permission) {
+  if (!permission.granted) {
     return <PermissionsRequest type="camera" />;
   }
 
@@ -179,7 +177,8 @@ const BarCodeScanScreen = ({ language = "" }: LocalizationContextProps) => {
         </Text.H2>
         <CameraView
           style={styles.scanner}
-          // onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
+        // FIXME: Add onBarCodeScanned
+        // onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
         />
         {__DEV__ ? (
           <Button.Secondary
diff --git a/app/screens/Notifications/NotificationsScreen.tsx b/app/screens/Notifications/NotificationsScreen.tsx
index 606b2795..4504fafa 100644
--- a/app/screens/Notifications/NotificationsScreen.tsx
+++ b/app/screens/Notifications/NotificationsScreen.tsx
@@ -11,16 +11,16 @@ import { t } from "utils";
 import navigationOptions from "./NotificationsScreen.navigationOptions";
 import styles from "./NotificationsScreen.styles";
 
-const notification = {
+const notification: Notifications.NotificationRequestInput = {
   content: {
     title: t("NOTIFICATIONS_SCREEN_NOTIFICATION_TITLE"),
     body: t("NOTIFICATIONS_SCREEN_NOTIFICATION_BODY"),
   },
   trigger: {
+    type: Notifications.SchedulableTriggerInputTypes.WEEKLY,
     weekday: 1,
     hour: 21,
     minute: 0,
-    repeats: true,
   },
 };
 
@@ -41,8 +41,7 @@ const NotificationsScreen: NavStatelessComponent = () => {
         }
 
         if (value) {
-          // TODO: fix
-          // await Notifications.scheduleNotificationAsync(notification);
+          await Notifications.scheduleNotificationAsync(notification);
         } else {
           await Notifications.cancelAllScheduledNotificationsAsync();
         }


Test patch:
diff --git a/app/components/OpenFoodFacts/__tests__/__snapshots__/OpenFoodFacts.test.tsx.snap b/app/components/OpenFoodFacts/__tests__/__snapshots__/OpenFoodFacts.test.tsx.snap
index 5bc53025..11fd5648 100644
--- a/app/components/OpenFoodFacts/__tests__/__snapshots__/OpenFoodFacts.test.tsx.snap
+++ b/app/components/OpenFoodFacts/__tests__/__snapshots__/OpenFoodFacts.test.tsx.snap
@@ -35,7 +35,11 @@ exports[`<OpenFoodFacts /> render correctly 1`] = `
     >
       <Image
         resizeMode="contain"
-        source={1}
+        source={
+          {
+            "testUri": "../../../assets/images/open-food-fact/nutriscore-a.png",
+          }
+        }
         style={
           {
             "alignSelf": "center",
@@ -55,7 +59,11 @@ exports[`<OpenFoodFacts /> render correctly 1`] = `
     >
       <Image
         resizeMode="contain"
-        source={1}
+        source={
+          {
+            "testUri": "../../../assets/images/open-food-fact/nova-unknown.png",
+          }
+        }
         style={
           {
             "alignSelf": "center",
@@ -75,7 +83,11 @@ exports[`<OpenFoodFacts /> render correctly 1`] = `
     >
       <Image
         resizeMode="contain"
-        source={1}
+        source={
+          {
+            "testUri": "../../../assets/images/open-food-fact/ecoscore-a.png",
+          }
+        }
         style={
           {
             "alignSelf": "center",
@@ -124,7 +136,11 @@ exports[`<OpenFoodFacts /> render nothing if bad data passed 1`] = `
     >
       <Image
         resizeMode="contain"
-        source={1}
+        source={
+          {
+            "testUri": "../../../assets/images/open-food-fact/nutriscore-unknown.png",
+          }
+        }
         style={
           {
             "alignSelf": "center",
@@ -144,7 +160,11 @@ exports[`<OpenFoodFacts /> render nothing if bad data passed 1`] = `
     >
       <Image
         resizeMode="contain"
-        source={1}
+        source={
+          {
+            "testUri": "../../../assets/images/open-food-fact/nova-unknown.png",
+          }
+        }
         style={
           {
             "alignSelf": "center",
@@ -164,7 +184,11 @@ exports[`<OpenFoodFacts /> render nothing if bad data passed 1`] = `
     >
       <Image
         resizeMode="contain"
-        source={1}
+        source={
+          {
+            "testUri": "../../../assets/images/open-food-fact/ecoscore-unknown.png",
+          }
+        }
         style={
           {
             "alignSelf": "center",
diff --git a/app/components/SocialMedia/__tests__/__snapshots__/SocialMedia.test.tsx.snap b/app/components/SocialMedia/__tests__/__snapshots__/SocialMedia.test.tsx.snap
index 0326afda..611be8f7 100644
--- a/app/components/SocialMedia/__tests__/__snapshots__/SocialMedia.test.tsx.snap
+++ b/app/components/SocialMedia/__tests__/__snapshots__/SocialMedia.test.tsx.snap
@@ -15,7 +15,8 @@ exports[`renders correctly SocialMedia 1`] = `
       {
         "flex": 1,
         "flexDirection": "row",
-        "justifyContent": "space-between",
+        "gap": 40,
+        "justifyContent": "center",
         "maxWidth": 200,
         "paddingBottom": 50,
       }
@@ -35,16 +36,7 @@ exports[`renders correctly SocialMedia 1`] = `
     >
       <View
         color="#595D58"
-        name="mastodon"
-        size={32}
-      />
-    </TouchableOpacity>
-    <TouchableOpacity
-      onPress={[Function]}
-    >
-      <View
-        color="#595D58"
-        name="medium-m"
+        name="globe"
         size={32}
       />
     </TouchableOpacity>
diff --git a/app/components/StickersImage/__tests__/__snapshots__/StickersImage.test.tsx.snap b/app/components/StickersImage/__tests__/__snapshots__/StickersImage.test.tsx.snap
index 2c825305..a06506a2 100644
--- a/app/components/StickersImage/__tests__/__snapshots__/StickersImage.test.tsx.snap
+++ b/app/components/StickersImage/__tests__/__snapshots__/StickersImage.test.tsx.snap
@@ -10,7 +10,11 @@ exports[`renders correctly StickersImage with bike image 1`] = `
 >
   <Image
     resizeMode="contain"
-    source={1}
+    source={
+      {
+        "testUri": "../../../assets/images/stickers/bike.png",
+      }
+    }
     style={
       {
         "alignSelf": "center",
@@ -34,7 +38,11 @@ exports[`renders correctly StickersImage with earth image 1`] = `
 >
   <Image
     resizeMode="contain"
-    source={1}
+    source={
+      {
+        "testUri": "../../../assets/images/stickers/earth.png",
+      }
+    }
     style={
       {
         "alignSelf": "center",
@@ -58,7 +66,11 @@ exports[`renders correctly StickersImage with restaurant image 1`] = `
 >
   <Image
     resizeMode="contain"
-    source={1}
+    source={
+      {
+        "testUri": "../../../assets/images/stickers/restaurant.png",
+      }
+    }
     style={
       {
         "alignSelf": "center",
diff --git a/app/screens/MonthlyBudget/__tests__/__snapshots__/MonthlyBudgetScreen.test.tsx.snap b/app/screens/MonthlyBudget/__tests__/__snapshots__/MonthlyBudgetScreen.test.tsx.snap
index fd12751c..3d90c00b 100644
--- a/app/screens/MonthlyBudget/__tests__/__snapshots__/MonthlyBudgetScreen.test.tsx.snap
+++ b/app/screens/MonthlyBudget/__tests__/__snapshots__/MonthlyBudgetScreen.test.tsx.snap
@@ -31,62 +31,6 @@ exports[`MonthlyBudgetScreen renders correctly 1`] = `
         onLayout={[Function]}
         style={
           [
-            {
-              "defaultIndicatorIdle": {
-                "backgroundColor": "#C0C0C0",
-                "height": 10,
-                "width": 2,
-              },
-              "defaultIndicatorMarked": {
-                "backgroundColor": "#CCCCCC",
-                "height": 20,
-                "width": 5,
-              },
-              "defaultSlider": {},
-              "defaultSlideriOS": {
-                "height": 40,
-              },
-              "sliderMainContainer": {
-                "width": "100%",
-                "zIndex": 1,
-              },
-              "stepIndicatorElement": {
-                "alignContent": "center",
-                "alignItems": "center",
-              },
-              "stepNumber": {
-                "alignItems": "center",
-                "marginTop": 20,
-                "position": "absolute",
-              },
-              "stepsIndicator": {
-                "flex": 1,
-                "flexDirection": "row",
-                "justifyContent": "space-between",
-                "top": 10,
-                "zIndex": 2,
-              },
-              "thumbImage": {
-                "alignContent": "center",
-                "alignItems": "center",
-                "position": "absolute",
-              },
-              "thumbImageContainer": {
-                "alignContent": "center",
-                "alignItems": "center",
-                "justifyContent": "center",
-                "position": "absolute",
-                "zIndex": 3,
-              },
-              "trackMarkContainer": {
-                "alignContent": "center",
-                "alignItems": "center",
-                "alignSelf": "center",
-                "justifyContent": "center",
-                "position": "absolute",
-                "zIndex": 3,
-              },
-            },
             [
               {
                 "marginTop": 14,
diff --git a/app/screens/Settings/__tests__/__snapshots__/SettingsScreen.test.tsx.snap b/app/screens/Settings/__tests__/__snapshots__/SettingsScreen.test.tsx.snap
index 5544bdde..113d059c 100644
--- a/app/screens/Settings/__tests__/__snapshots__/SettingsScreen.test.tsx.snap
+++ b/app/screens/Settings/__tests__/__snapshots__/SettingsScreen.test.tsx.snap
@@ -104,7 +104,11 @@ exports[`SettingsScreen renders correctly 1`] = `
     >
       <Image
         resizeMode="contain"
-        source={1}
+        source={
+          {
+            "testUri": "../../../assets/images/logos/nmf.png",
+          }
+        }
         style={
           {
             "width": "50%",
diff --git a/jest/mock/node-modules/index.js b/jest/mock/node-modules/index.js
index 9123a987..ffd18897 100644
--- a/jest/mock/node-modules/index.js
+++ b/jest/mock/node-modules/index.js
@@ -76,16 +76,6 @@ jest.mock("expo-constants", () => {
   };
 });
 
-jest.mock("expo-barcode-scanner", () => {
-  return {
-    BarCodeScanner: {
-      requestPermissionsAsync: () => ({
-        status: "denied",
-      }),
-    },
-  };
-});
-
 jest.mock("expo-notifications", () => {
   return {
     requestPermissionsAsync: () => ({