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,9 @@
#pragma once
typedef enum LayoutAnimationType {
ENTERING = 1,
EXITING = 2,
LAYOUT = 3,
SHARED_ELEMENT_TRANSITION = 4,
SHARED_ELEMENT_TRANSITION_PROGRESS = 5,
} LayoutAnimationType;

View File

@@ -0,0 +1,205 @@
#include "LayoutAnimationsManager.h"
#include "CollectionUtils.h"
#include "Shareables.h"
#ifndef NDEBUG
#include <utility>
#endif
namespace reanimated {
void LayoutAnimationsManager::configureAnimationBatch(
const std::vector<LayoutAnimationConfig> &layoutAnimationsBatch) {
auto lock = std::unique_lock<std::recursive_mutex>(animationsMutex_);
std::vector<LayoutAnimationConfig> sharedTransitionConfigs;
for (auto layoutAnimationConfig : layoutAnimationsBatch) {
const auto &[tag, type, config, sharedTransitionTag] =
layoutAnimationConfig;
if (type == SHARED_ELEMENT_TRANSITION ||
type == SHARED_ELEMENT_TRANSITION_PROGRESS) {
clearSharedTransitionConfig(tag);
sharedTransitionConfigs.push_back(std::move(layoutAnimationConfig));
} else {
if (config == nullptr) {
getConfigsForType(type).erase(tag);
} else {
getConfigsForType(type)[tag] = config;
}
}
}
for (const auto &[tag, type, config, sharedTransitionTag] :
sharedTransitionConfigs) {
if (config == nullptr) {
continue;
}
sharedTransitionGroups_[sharedTransitionTag].push_back(tag);
viewTagToSharedTag_[tag] = sharedTransitionTag;
getConfigsForType(SHARED_ELEMENT_TRANSITION)[tag] = config;
if (type == SHARED_ELEMENT_TRANSITION) {
ignoreProgressAnimationForTag_.insert(tag);
}
}
}
void LayoutAnimationsManager::setShouldAnimateExiting(
const int tag,
const bool value) {
auto lock = std::unique_lock<std::recursive_mutex>(animationsMutex_);
shouldAnimateExitingForTag_[tag] = value;
}
bool LayoutAnimationsManager::shouldAnimateExiting(
const int tag,
const bool shouldAnimate) {
auto lock = std::unique_lock<std::recursive_mutex>(animationsMutex_);
return collection::contains(shouldAnimateExitingForTag_, tag)
? shouldAnimateExitingForTag_[tag]
: shouldAnimate;
}
bool LayoutAnimationsManager::hasLayoutAnimation(
const int tag,
const LayoutAnimationType type) {
auto lock = std::unique_lock<std::recursive_mutex>(animationsMutex_);
if (type == SHARED_ELEMENT_TRANSITION_PROGRESS) {
auto end = ignoreProgressAnimationForTag_.end();
return ignoreProgressAnimationForTag_.find(tag) == end;
}
return collection::contains(getConfigsForType(type), tag);
}
void LayoutAnimationsManager::clearSharedTransitionConfig(const int tag) {
auto lock = std::unique_lock<std::recursive_mutex>(animationsMutex_);
#ifndef NDEBUG
const auto &pair = viewsScreenSharedTagMap_[tag];
screenSharedTagSet_.erase(pair);
viewsScreenSharedTagMap_.erase(tag);
#endif // NDEBUG
sharedTransitionAnimations_.erase(tag);
auto const &groupName = viewTagToSharedTag_[tag];
if (groupName.empty()) {
viewTagToSharedTag_.erase(tag);
return;
}
auto &group = sharedTransitionGroups_[groupName];
auto position = std::find(group.begin(), group.end(), tag);
if (position != group.end()) {
group.erase(position);
}
if (group.size() == 0) {
sharedTransitionGroups_.erase(groupName);
}
viewTagToSharedTag_.erase(tag);
ignoreProgressAnimationForTag_.erase(tag);
}
void LayoutAnimationsManager::clearLayoutAnimationConfig(const int tag) {
auto lock = std::unique_lock<std::recursive_mutex>(animationsMutex_);
enteringAnimations_.erase(tag);
exitingAnimations_.erase(tag);
layoutAnimations_.erase(tag);
shouldAnimateExitingForTag_.erase(tag);
clearSharedTransitionConfig(tag);
}
void LayoutAnimationsManager::startLayoutAnimation(
jsi::Runtime &rt,
const int tag,
const LayoutAnimationType type,
const jsi::Object &values) {
std::shared_ptr<Shareable> config, viewShareable;
{
auto lock = std::unique_lock<std::recursive_mutex>(animationsMutex_);
config = getConfigsForType(type)[tag];
}
// TODO: cache the following!!
jsi::Value layoutAnimationRepositoryAsValue =
rt.global()
.getPropertyAsObject(rt, "global")
.getProperty(rt, "LayoutAnimationsManager");
jsi::Function startAnimationForTag =
layoutAnimationRepositoryAsValue.getObject(rt).getPropertyAsFunction(
rt, "start");
startAnimationForTag.call(
rt,
jsi::Value(tag),
jsi::Value(static_cast<int>(type)),
values,
config->getJSValue(rt));
}
void LayoutAnimationsManager::cancelLayoutAnimation(
jsi::Runtime &rt,
const int tag) const {
jsi::Value layoutAnimationRepositoryAsValue =
rt.global()
.getPropertyAsObject(rt, "global")
.getProperty(rt, "LayoutAnimationsManager");
jsi::Function cancelLayoutAnimation =
layoutAnimationRepositoryAsValue.getObject(rt).getPropertyAsFunction(
rt, "stop");
cancelLayoutAnimation.call(rt, jsi::Value(tag));
}
/*
The top screen on the stack triggers the animation, so we need to find
the sibling view registered in the past. This method finds view
registered in the same transition group (with the same transition tag)
which has been added to that group directly before the one that we
provide as an argument.
*/
int LayoutAnimationsManager::findPrecedingViewTagForTransition(const int tag) {
auto const &groupName = viewTagToSharedTag_[tag];
auto const &group = sharedTransitionGroups_[groupName];
auto position = std::find(group.begin(), group.end(), tag);
if (position != group.end() && position != group.begin()) {
return *std::prev(position);
}
return -1;
}
#ifndef NDEBUG
std::string LayoutAnimationsManager::getScreenSharedTagPairString(
const int screenTag,
const std::string &sharedTag) const {
return std::to_string(screenTag) + ":" + sharedTag;
}
void LayoutAnimationsManager::checkDuplicateSharedTag(
const int viewTag,
const int screenTag) {
if (!viewTagToSharedTag_.count(viewTag)) {
return;
}
const auto &sharedTag = viewTagToSharedTag_[viewTag];
const auto &pair = getScreenSharedTagPairString(screenTag, sharedTag);
bool hasDuplicate = screenSharedTagSet_.count(pair);
if (hasDuplicate) {
jsLogger_->warnOnJS(
"[Reanimated] Duplicate shared tag \"" + sharedTag +
"\" on the same screen");
}
viewsScreenSharedTagMap_[viewTag] = pair;
screenSharedTagSet_.insert(pair);
}
#endif // NDEBUG
std::unordered_map<int, std::shared_ptr<Shareable>> &
LayoutAnimationsManager::getConfigsForType(const LayoutAnimationType type) {
switch (type) {
case ENTERING:
return enteringAnimations_;
case EXITING:
return exitingAnimations_;
case LAYOUT:
return layoutAnimations_;
case SHARED_ELEMENT_TRANSITION:
case SHARED_ELEMENT_TRANSITION_PROGRESS:
return sharedTransitionAnimations_;
default:
assert(false);
}
}
} // namespace reanimated

View File

@@ -0,0 +1,80 @@
#pragma once
#include "JSLogger.h"
#include "LayoutAnimationType.h"
#include "Shareables.h"
#include <jsi/jsi.h>
#include <stdio.h>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace reanimated {
using namespace facebook;
struct LayoutAnimationConfig {
int tag;
LayoutAnimationType type;
std::shared_ptr<Shareable> config;
std::string sharedTransitionTag;
};
class LayoutAnimationsManager {
public:
explicit LayoutAnimationsManager(const std::shared_ptr<JSLogger> &jsLogger)
: jsLogger_(jsLogger) {}
void configureAnimationBatch(
const std::vector<LayoutAnimationConfig> &layoutAnimationsBatch);
void setShouldAnimateExiting(const int tag, const bool value);
bool shouldAnimateExiting(const int tag, const bool shouldAnimate);
bool hasLayoutAnimation(const int tag, const LayoutAnimationType type);
void startLayoutAnimation(
jsi::Runtime &rt,
const int tag,
const LayoutAnimationType type,
const jsi::Object &values);
void clearLayoutAnimationConfig(const int tag);
void clearSharedTransitionConfig(const int tag);
void cancelLayoutAnimation(jsi::Runtime &rt, const int tag) const;
int findPrecedingViewTagForTransition(const int tag);
#ifndef NDEBUG
std::string getScreenSharedTagPairString(
const int screenTag,
const std::string &sharedTag) const;
void checkDuplicateSharedTag(const int viewTag, const int screenTag);
#endif
private:
std::unordered_map<int, std::shared_ptr<Shareable>> &getConfigsForType(
const LayoutAnimationType type);
std::shared_ptr<JSLogger> jsLogger_;
#ifndef NDEBUG
// This set's function is to detect duplicate sharedTags on a single screen
// it contains strings in form: "reactScreenTag:sharedTag"
std::unordered_set<std::string> screenSharedTagSet_;
// And this map is to remove collected pairs on SET removal
std::unordered_map<int, std::string> viewsScreenSharedTagMap_;
#endif
std::unordered_map<int, std::shared_ptr<Shareable>> enteringAnimations_;
std::unordered_map<int, std::shared_ptr<Shareable>> exitingAnimations_;
std::unordered_map<int, std::shared_ptr<Shareable>> layoutAnimations_;
std::unordered_map<int, std::shared_ptr<Shareable>>
sharedTransitionAnimations_;
std::unordered_set<int> ignoreProgressAnimationForTag_;
std::unordered_map<std::string, std::vector<int>> sharedTransitionGroups_;
std::unordered_map<int, std::string> viewTagToSharedTag_;
std::unordered_map<int, bool> shouldAnimateExitingForTag_;
mutable std::recursive_mutex
animationsMutex_; // Protects `enteringAnimations_`, `exitingAnimations_`,
// `layoutAnimations_`, `viewSharedValues_` and `shouldAnimateExitingForTag_`.
};
} // namespace reanimated