Files
Eric FELIXINE e30ae8ed09 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
2026-06-01 18:00:35 -04:00

155 lines
4.2 KiB
Objective-C

// Copyright 2018-present 650 Industries. All rights reserved.
#import <EXNotifications/EXPushTokenModule.h>
#import <EXNotifications/EXPushTokenManager.h>
#import <ExpoModulesCore/EXEventEmitterService.h>
static NSString * const onDevicePushTokenEventName = @"onDevicePushToken";
@interface EXPushTokenModule ()
@property (nonatomic, weak) id<EXPushTokenManager> pushTokenManager;
@property (nonatomic, assign) BOOL isListening;
@property (nonatomic, assign) BOOL isBeingObserved;
@property (nonatomic, assign) BOOL isSettlingPromise;
@property (nonatomic, weak) id<EXEventEmitterService> eventEmitter;
@property (nonatomic, strong) EXPromiseResolveBlock getDevicePushTokenResolver;
@property (nonatomic, strong) EXPromiseRejectBlock getDevicePushTokenRejecter;
@end
@implementation EXPushTokenModule
EX_EXPORT_MODULE(ExpoPushTokenManager);
# pragma mark - Exported methods
EX_EXPORT_METHOD_AS(getDevicePushTokenAsync,
getDevicePushTokenResolving:(EXPromiseResolveBlock)resolve rejecting:(EXPromiseRejectBlock)reject)
{
if (_getDevicePushTokenRejecter) {
reject(@"E_AWAIT_PROMISE", @"Another async call to this method is in progress. Await the first Promise.", nil);
return;
}
_getDevicePushTokenResolver = resolve;
_getDevicePushTokenRejecter = reject;
[self setIsSettlingPromise:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
}
EX_EXPORT_METHOD_AS(unregisterForNotificationsAsync,
unregisterForNotificationsAsync:(EXPromiseResolveBlock)resolve reject:(EXPromiseRejectBlock)reject)
{
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
resolve(nil);
}
# pragma mark - EXModuleRegistryConsumer
- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
{
_eventEmitter = [moduleRegistry getModuleImplementingProtocol:@protocol(EXEventEmitterService)];
_pushTokenManager = [moduleRegistry getSingletonModuleForName:@"PushTokenManager"];
}
# pragma mark - EXEventEmitter
- (NSArray<NSString *> *)supportedEvents
{
return @[onDevicePushTokenEventName];
}
- (void)startObserving
{
[self setIsBeingObserved:YES];
}
- (void)stopObserving
{
[self setIsBeingObserved:NO];
}
- (BOOL)shouldListen
{
return _isBeingObserved || _isSettlingPromise;
}
- (void)updateListeningState
{
if ([self shouldListen] && !_isListening) {
[_pushTokenManager addListener:self];
_isListening = YES;
} else if (![self shouldListen] && _isListening) {
[_pushTokenManager removeListener:self];
_isListening = NO;
}
}
# pragma mark - EXPushTokenListener
- (void)onDidRegisterWithDeviceToken:(NSData *)devicePushToken
{
NSMutableString *stringToken = [NSMutableString string];
const char *bytes = [devicePushToken bytes];
for (int i = 0; i < [devicePushToken length]; i++) {
[stringToken appendFormat:@"%02.2hhx", bytes[i]];
}
if (_getDevicePushTokenResolver) {
_getDevicePushTokenResolver(stringToken);
[self onGetDevicePushTokenPromiseSettled];
}
if (_isBeingObserved) {
[_eventEmitter sendEventWithName:onDevicePushTokenEventName
body:@{ @"devicePushToken": stringToken }];
}
}
- (void)onDidFailToRegisterWithError:(NSError *)error
{
if (_getDevicePushTokenRejecter) {
NSString *message = @"Notification registration failed: ";
// A common error, localizedDescription may not be helpful.
if (error.code == 3000 && [NSCocoaErrorDomain isEqualToString:error.domain]) {
message = [message stringByAppendingString:@"\"Push Notifications\" capability hasn't been added to the app in current environment: "];
}
message = [message stringByAppendingFormat:@"%@", error.localizedDescription];
_getDevicePushTokenRejecter(@"E_REGISTRATION_FAILED", message, error);
[self onGetDevicePushTokenPromiseSettled];
}
}
- (void)onGetDevicePushTokenPromiseSettled
{
_getDevicePushTokenResolver = nil;
_getDevicePushTokenRejecter = nil;
[self setIsSettlingPromise:NO];
}
# pragma mark - Internal state
- (void)setIsBeingObserved:(BOOL)isBeingObserved
{
_isBeingObserved = isBeingObserved;
[self updateListeningState];
}
- (void)setIsSettlingPromise:(BOOL)isSettlingPromise
{
_isSettlingPromise = isSettlingPromise;
[self updateListeningState];
}
@end