Waseel: driver capture, chat/calls, dispatch, and session fixes

Driver onboarding now photographs the licence, ID card and vehicle
registration and reads the credential fields off them, plus a camera-only
profile selfie riders check the arriving driver against. Adds in-app chat
and WebRTC calls, push-backed ride offers, ratings, cancellation and
payment sheets, settlement, and the owner dashboard endpoints behind them.

Camera permission on Android:
  - Declare CAMERA and READ_MEDIA_IMAGES in the manifest. expo-image-picker's
    own plugin never declares CAMERA, and Android denies a request for an
    undeclared permission instantly and silently — no dialog is ever shown,
    which is indistinguishable from the app not asking at all.
  - Handle canAskAgain: once Android stops showing the dialog, repeating why
    we need it is a dead end, so offer Open Settings instead (lib/capture-
    permission.ts), matching what the location flow already did.

Session: a 401 on a request that carried a token now ends the session
instead of being reinterpreted per-screen — driver-home had been reading it
as "this user has no driver profile" and showing an onboarding form to an
already-onboarded driver. Requests without a token are exempt so a failed
sign-in doesn't sign you out, and the notification is latched per token so
concurrent polls tear the session down once. (root) gains the auth guard
that turns that into the sign-in screen; app/index.tsx only guarded the way
in, leaving a session that ended mid-screen with nowhere to go.

Also ignore .uploads/ — it holds driver licence, ID and vehicle scans plus
profile photos, which are personal data and must not be committed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Krikorios
2026-08-26 02:17:55 +03:00
co-authored by Claude Opus 5
parent 1d84003e0a
commit 8807ff41c5
111 changed files with 14568 additions and 1411 deletions
+209
View File
@@ -27,17 +27,22 @@
"eslint-plugin-prettier": "^5.2.1",
"expo": "~51.0.28",
"expo-auth-session": "~5.5.2",
"expo-build-properties": "^0.12.5",
"expo-clipboard": "~6.0.3",
"expo-constants": "~16.0.2",
"expo-crypto": "~13.0.2",
"expo-font": "~12.0.9",
"expo-image-picker": "~15.1.0",
"expo-keep-awake": "~13.0.2",
"expo-linking": "^6.3.1",
"expo-location": "^17.0.1",
"expo-notifications": "^0.28.19",
"expo-router": "~3.5.23",
"expo-secure-store": "^13.0.2",
"expo-splash-screen": "~0.27.5",
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.7",
"expo-task-manager": "~11.8.2",
"expo-web-browser": "~13.0.3",
"nativewind": "^2.0.11",
"nodemailer": "^9.0.5",
@@ -47,6 +52,7 @@
"react-dom": "18.2.0",
"react-native": "^0.74.5",
"react-native-gesture-handler": "~2.16.1",
"react-native-incall-manager": "^4.2.2",
"react-native-maps": "^1.14.0",
"react-native-maps-directions": "^1.9.0",
"react-native-modal": "^13.0.1",
@@ -55,6 +61,7 @@
"react-native-screens": "3.31.1",
"react-native-swiper": "^1.6.0",
"react-native-web": "~0.19.10",
"react-native-webrtc": "^124.0.8",
"zustand": "^4.5.5"
},
"devDependencies": {
@@ -3156,6 +3163,11 @@
"version": "2.0.3",
"license": "BSD-3-Clause"
},
"node_modules/@ide/backoff": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@ide/backoff/-/backoff-1.0.0.tgz",
"integrity": "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g=="
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"license": "ISC",
@@ -6692,6 +6704,18 @@
"version": "2.0.6",
"license": "MIT"
},
"node_modules/assert": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz",
"integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==",
"dependencies": {
"call-bind": "^1.0.2",
"is-nan": "^1.3.2",
"object-is": "^1.1.5",
"object.assign": "^4.1.4",
"util": "^0.12.5"
}
},
"node_modules/ast-types": {
"version": "0.15.2",
"license": "MIT",
@@ -7089,6 +7113,11 @@
"@babel/core": "^7.0.0"
}
},
"node_modules/badgin": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz",
"integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"license": "MIT"
@@ -9337,6 +9366,29 @@
"invariant": "^2.2.4"
}
},
"node_modules/expo-build-properties": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-0.12.5.tgz",
"integrity": "sha512-donC1le0PYfLKCPKRMGQoixuWuwDWCngzXSoQXUPsgHTDHQUKr8aw+lcWkTwZcItgNovcnk784I0dyfYDcxybA==",
"dependencies": {
"ajv": "^8.11.0",
"semver": "^7.6.0"
},
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-build-properties/node_modules/semver": {
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/expo-clipboard": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-6.0.3.tgz",
@@ -9384,6 +9436,25 @@
"expo": "*"
}
},
"node_modules/expo-image-loader": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-4.7.0.tgz",
"integrity": "sha512-cx+MxxsAMGl9AiWnQUzrkJMJH4eNOGlu7XkLGnAXSJrRoIiciGaKqzeaD326IyCTV+Z1fXvIliSgNW+DscvD8g==",
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-image-picker": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-15.1.0.tgz",
"integrity": "sha512-6cE10S7d0qG7+pcHtsYukRKuFL44ssOM0/v+5JIBzRwxpIgGA6qokr8PxasFEpxOA9NpN0gwry33jmq1qLXJTg==",
"dependencies": {
"expo-image-loader": "~4.7.0"
},
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-keep-awake": {
"version": "13.0.2",
"license": "MIT",
@@ -9493,6 +9564,57 @@
"invariant": "^2.2.4"
}
},
"node_modules/expo-notifications": {
"version": "0.28.19",
"resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.28.19.tgz",
"integrity": "sha512-rKKTnVQQ9XNQyTNwKmI9OlchhVu0XOZfRpImMqPFCJg6IwECM1izdas2SLCbE/GApg2Tw3U5R2fd26OnCtUU/w==",
"dependencies": {
"@expo/image-utils": "^0.5.0",
"@ide/backoff": "^1.0.0",
"abort-controller": "^3.0.0",
"assert": "^2.0.0",
"badgin": "^1.1.5",
"expo-application": "~5.9.0",
"expo-constants": "~16.0.0",
"fs-extra": "^9.1.0"
},
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-notifications/node_modules/fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/expo-notifications/node_modules/jsonfile": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
"integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
"dependencies": {
"universalify": "^2.0.0"
},
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/expo-notifications/node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/expo-router": {
"version": "3.5.24",
"resolved": "https://registry.npmjs.org/expo-router/-/expo-router-3.5.24.tgz",
@@ -9562,6 +9684,17 @@
"expo": "*"
}
},
"node_modules/expo-task-manager": {
"version": "11.8.2",
"resolved": "https://registry.npmjs.org/expo-task-manager/-/expo-task-manager-11.8.2.tgz",
"integrity": "sha512-Uhy3ol5gYeZOyeRFddYjLI1B2DGRH1gjp/YC8Hpn5p5MVENviySoKNF+wd98rRvOAokzrzElyDBHSTfX+C3tpg==",
"dependencies": {
"unimodules-app-loader": "~4.6.0"
},
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-web-browser": {
"version": "13.0.3",
"license": "MIT",
@@ -10933,6 +11066,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-nan": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
"integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
"dependencies": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-negative-zero": {
"version": "2.0.3",
"license": "MIT",
@@ -14292,6 +14440,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-is": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"license": "MIT",
@@ -15576,6 +15739,14 @@
"react": "^16.6.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-native-incall-manager": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/react-native-incall-manager/-/react-native-incall-manager-4.2.2.tgz",
"integrity": "sha512-r8zVNIDEFBcceHkmJKKahTiIdK5fu5ohKSAzt3MV+sltlE9bkYLVD0piJ55NfBusDDywPqRJwvdCHZPWdI8iUg==",
"peerDependencies": {
"react-native": ">=0.40.0"
}
},
"node_modules/react-native-maps": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/react-native-maps/-/react-native-maps-1.14.0.tgz",
@@ -15691,6 +15862,39 @@
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
},
"node_modules/react-native-webrtc": {
"version": "124.0.8",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-124.0.8.tgz",
"integrity": "sha512-uuQxvmk+mvnk5U0tr+1N42sKZqgm41fJrBA+fmCvML9J9P4roSh2So82t5RHAlu/vE9vxu5AKgivAiH61clCBg==",
"dependencies": {
"base64-js": "1.5.1",
"debug": "4.3.4"
},
"peerDependencies": {
"react-native": ">=0.60.0"
}
},
"node_modules/react-native-webrtc/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/react-native-webrtc/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/react-native/node_modules/@jest/types": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz",
@@ -17798,6 +18002,11 @@
"node": ">=4"
}
},
"node_modules/unimodules-app-loader": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/unimodules-app-loader/-/unimodules-app-loader-4.6.0.tgz",
"integrity": "sha512-FRNIlx7sLBDVPG117JnEBhnzZkTIgZTEwYW2rzrY9HdvLBTpRN+k0dxY50U/CAhFHW3zMD0OP5JAlnSQRhx5HA=="
},
"node_modules/unique-filename": {
"version": "3.0.0",
"license": "ISC",