feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -0,0 +1,127 @@
package expo.modules.application
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Build
import android.os.RemoteException
import android.provider.Settings
import com.android.installreferrer.api.InstallReferrerClient
import com.android.installreferrer.api.InstallReferrerStateListener
import expo.modules.kotlin.Promise
import expo.modules.kotlin.exception.CodedException
import expo.modules.kotlin.exception.Exceptions
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class ApplicationPackageNameNotFoundException(cause: PackageManager.NameNotFoundException) :
CodedException(message = "Unable to get install time of this application. Could not get package info or package name.", cause = cause)
class ApplicationModule : Module() {
private val context: Context
get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
override fun definition() = ModuleDefinition {
Name("ExpoApplication")
Constants {
return@Constants mapOf(
"applicationName" to applicationName,
"applicationId" to packageName,
"nativeApplicationVersion" to versionName,
"nativeBuildVersion" to versionCode.toString()
)
}
Property("androidId") {
Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
}
AsyncFunction<Double>("getInstallationTimeAsync") {
val packageManager = context.packageManager
val packageName = context.packageName
packageManager
.getPackageInfoCompat(packageName, 0)
.firstInstallTime
.toDouble()
}
AsyncFunction<Double>("getLastUpdateTimeAsync") {
val packageManager = context.packageManager
val packageName = context.packageName
packageManager
.getPackageInfoCompat(packageName, 0)
.lastUpdateTime
.toDouble()
}
AsyncFunction("getInstallReferrerAsync") { promise: Promise ->
val installReferrer = StringBuilder()
val referrerClient = InstallReferrerClient.newBuilder(context).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
when (responseCode) {
InstallReferrerClient.InstallReferrerResponse.OK -> {
// Connection established and response received
try {
val response = referrerClient.installReferrer
installReferrer.append(response.installReferrer)
} catch (e: RemoteException) {
promise.reject("ERR_APPLICATION_INSTALL_REFERRER_REMOTE_EXCEPTION", "RemoteException getting install referrer information. This may happen if the process hosting the remote object is no longer available.", e)
return
}
promise.resolve(installReferrer.toString())
}
InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> // API not available in the current Play Store app
promise.reject("ERR_APPLICATION_INSTALL_REFERRER_UNAVAILABLE", "The current Play Store app doesn't provide the installation referrer API, or the Play Store may not be installed.", null)
InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE -> // Connection could not be established
promise.reject("ERR_APPLICATION_INSTALL_REFERRER", "General error retrieving the install referrer: response code $responseCode", null)
else -> promise.reject("ERR_APPLICATION_INSTALL_REFERRER", "General error retrieving the install referrer: response code $responseCode", null)
}
referrerClient.endConnection()
}
override fun onInstallReferrerServiceDisconnected() {
promise.reject("ERR_APPLICATION_INSTALL_REFERRER_SERVICE_DISCONNECTED", "Connection to install referrer service was lost.", null)
}
})
}
}
private val applicationName
get() = context.applicationInfo.loadLabel(context.packageManager).toString()
private val packageName
get() = context.packageName
private val packageManager
get() = context.packageManager
private val versionName
get() = packageManager.getPackageInfoCompat(packageName, 0).versionName
private val versionCode
get() = getLongVersionCode(packageManager.getPackageInfoCompat(packageName, 0)).toInt()
}
private fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int = 0): PackageInfo =
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags.toLong()))
} else {
@Suppress("DEPRECATION")
getPackageInfo(packageName, flags)
}
} catch (e: PackageManager.NameNotFoundException) {
throw ApplicationPackageNameNotFoundException(e)
}
private fun getLongVersionCode(info: PackageInfo): Long {
return if (Build.VERSION.SDK_INT >= 28) {
info.longVersionCode
} else {
@Suppress("DEPRECATION")
info.versionCode.toLong()
}
}