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,121 @@
// Copyright 2022-present 650 Industries. All rights reserved.
import PhotosUI
/**
Protocol that describes scenarios we care about while the user is picking media.
*/
protocol OnMediaPickingResultHandler {
@available(iOS 14, *)
func didPickMultipleMedia(selection: [PHPickerResult])
func didPickMedia(mediaInfo: MediaInfo)
func didCancelPicking()
}
/**
This class is responsible for responding to any events that are happening in `UIImagePickerController`.
It then forwards them back in unified way via `OnMediaPickingResultHandler`.
The functionality of this delegate is separated from the main module class for two reasons:
1) main module cannot inherit from `NSObject` (and that's required by three protocols we must conform to),
because it already inherits from `Module` class and Swift language does not allow multiple inheritance,
2) it separates some logic from the main module class and hopefully makes it cleaner.
*/
internal class ImagePickerHandler: NSObject,
PHPickerViewControllerDelegate,
UINavigationControllerDelegate,
UIImagePickerControllerDelegate,
UIAdaptivePresentationControllerDelegate {
private let onMediaPickingResultHandler: OnMediaPickingResultHandler
private let hideStatusBarWhenPresented: Bool
private var statusBarVisibilityController = StatusBarVisibilityController()
init(onMediaPickingResultHandler: OnMediaPickingResultHandler, hideStatusBarWhenPresented: Bool) {
self.onMediaPickingResultHandler = onMediaPickingResultHandler
self.hideStatusBarWhenPresented = hideStatusBarWhenPresented
}
private func handlePickedMedia(mediaInfo: MediaInfo) {
statusBarVisibilityController.maybeRestoreStatusBarVisibility()
onMediaPickingResultHandler.didPickMedia(mediaInfo: mediaInfo)
}
@available(iOS 14, *)
private func handlePickedMedia(selection: [PHPickerResult]) {
statusBarVisibilityController.maybeRestoreStatusBarVisibility()
onMediaPickingResultHandler.didPickMultipleMedia(selection: selection)
}
private func handlePickingCancellation() {
statusBarVisibilityController.maybeRestoreStatusBarVisibility()
onMediaPickingResultHandler.didCancelPicking()
}
// MARK: - UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: MediaInfo) {
DispatchQueue.main.async {
picker.dismiss(animated: true) { [weak self] in
self?.handlePickedMedia(mediaInfo: info)
}
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
DispatchQueue.main.async {
picker.dismiss(animated: true) { [weak self] in
self?.handlePickingCancellation()
}
}
}
// MARK: - PHPickerViewControllerDelegate
@available(iOS 14, *)
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
DispatchQueue.main.async {
picker.dismiss(animated: true) { [weak self] in
// The PHPickerViewController returns empty collection when canceled
if results.isEmpty {
self?.handlePickingCancellation()
} else {
self?.handlePickedMedia(selection: results)
}
}
}
}
// MARK: - UIAdaptivePresentationControllerDelegate
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
handlePickingCancellation()
}
// MARK: - UINavigationControllerDelegate
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
statusBarVisibilityController.maybePreserveVisibilityAndHideStatusBar(hideStatusBarWhenPresented)
}
}
/**
Protocol that is a common type for supported picker controllers.
*/
internal protocol PickerUIController: UIViewController {
func setResultHandler(_ handler: ImagePickerHandler)
}
extension UIImagePickerController: PickerUIController {
func setResultHandler(_ handler: ImagePickerHandler) {
self.delegate = handler
self.presentationController?.delegate = handler
}
}
@available(iOS 14, *)
extension PHPickerViewController: PickerUIController {
func setResultHandler(_ handler: ImagePickerHandler) {
self.delegate = handler
self.presentationController?.delegate = handler
}
}