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,120 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "Timeline.h"
#include <react/renderer/uimanager/UIManager.h>
namespace facebook::react {
Timeline::Timeline(const ShadowTree& shadowTree) : shadowTree_(&shadowTree) {
record(shadowTree.getCurrentRevision().rootShadowNode);
};
#pragma mark - Public
SurfaceId Timeline::getSurfaceId() const noexcept {
return shadowTree_->getSurfaceId();
}
void Timeline::pause() const noexcept {
std::scoped_lock lock(mutex_);
assert(!paused_ && "");
paused_ = true;
}
void Timeline::resume() const noexcept {
std::scoped_lock lock(mutex_);
if (!snapshots_.empty()) {
rewind(snapshots_.at(snapshots_.size() - 1));
}
assert(paused_ && "");
paused_ = false;
}
bool Timeline::isPaused() const noexcept {
std::scoped_lock lock(mutex_);
return paused_;
}
TimelineFrame::List Timeline::getFrames() const noexcept {
std::scoped_lock lock(mutex_);
auto frames = TimelineFrame::List{};
frames.reserve(snapshots_.size());
for (const auto& snapshot : snapshots_) {
frames.push_back(snapshot.getFrame());
}
return frames;
}
TimelineFrame Timeline::getCurrentFrame() const noexcept {
assert(snapshots_.size() > currentSnapshotIndex_);
return snapshots_.at(currentSnapshotIndex_).getFrame();
}
void Timeline::rewind(const TimelineFrame& frame) const noexcept {
std::scoped_lock lock(mutex_);
rewind(snapshots_.at(frame.getIndex()));
}
RootShadowNode::Unshared Timeline::shadowTreeWillCommit(
const ShadowTree& /*shadowTree*/,
const RootShadowNode::Shared& /*oldRootShadowNode*/,
const RootShadowNode::Unshared& newRootShadowNode) const noexcept {
std::scoped_lock lock(mutex_);
if (rewinding_) {
return newRootShadowNode;
}
record(newRootShadowNode);
if (paused_) {
return nullptr;
}
return newRootShadowNode;
}
#pragma mark - Private & Internal
void Timeline::record(
const RootShadowNode::Shared& rootShadowNode) const noexcept {
auto index = (int)snapshots_.size();
snapshots_.push_back(TimelineSnapshot{rootShadowNode, index});
if (!paused_) {
currentSnapshotIndex_ = index;
}
}
void Timeline::rewind(const TimelineSnapshot& snapshot) const noexcept {
std::scoped_lock lock(mutex_);
currentSnapshotIndex_ = snapshot.getFrame().getIndex();
assert(!rewinding_ && "");
rewinding_ = true;
auto rootShadowNode = snapshot.getRootShadowNode();
shadowTree_->commit(
[&](const RootShadowNode& /*oldRootShadowNode*/)
-> RootShadowNode::Unshared {
return std::static_pointer_cast<RootShadowNode>(
rootShadowNode->ShadowNode::clone({}));
},
{});
assert(rewinding_ && "");
rewinding_ = false;
}
} // namespace facebook::react

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <memory>
#include <mutex>
#include <vector>
#include <react/renderer/core/ReactPrimitives.h>
#include <react/renderer/timeline/TimelineSnapshot.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
namespace facebook::react {
class UIManager;
class Timeline final {
friend class TimelineHandler;
friend class TimelineController;
public:
Timeline(const ShadowTree& shadowTree);
private:
#pragma mark - Private methods to be used by `TimelineHandler`.
void pause() const noexcept;
void resume() const noexcept;
bool isPaused() const noexcept;
TimelineFrame::List getFrames() const noexcept;
TimelineFrame getCurrentFrame() const noexcept;
void rewind(const TimelineFrame& frame) const noexcept;
SurfaceId getSurfaceId() const noexcept;
#pragma mark - Private methods to be used by `TimelineController`.
RootShadowNode::Unshared shadowTreeWillCommit(
const ShadowTree& shadowTree,
const RootShadowNode::Shared& oldRootShadowNode,
const RootShadowNode::Unshared& newRootShadowNode) const noexcept;
#pragma mark - Private & Internal
void record(const RootShadowNode::Shared& rootShadowNode) const noexcept;
void rewind(const TimelineSnapshot& snapshot) const noexcept;
mutable std::recursive_mutex mutex_;
mutable const ShadowTree* shadowTree_{nullptr};
mutable int currentSnapshotIndex_{0};
mutable TimelineSnapshot::List snapshots_{};
mutable bool paused_{false};
mutable bool rewinding_{false};
};
} // namespace facebook::react

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TimelineController.h"
#include <react/renderer/mounting/ShadowTree.h>
#include <react/renderer/uimanager/UIManager.h>
namespace facebook::react {
TimelineHandler TimelineController::enable(SurfaceId surfaceId) const {
assert(uiManager_);
const ShadowTree* shadowTreePtr = nullptr;
uiManager_->getShadowTreeRegistry().visit(
surfaceId,
[&](const ShadowTree& shadowTree) { shadowTreePtr = &shadowTree; });
assert(shadowTreePtr);
{
std::unique_lock<std::shared_mutex> lock(timelinesMutex_);
auto timeline = std::make_unique<Timeline>(*shadowTreePtr);
auto handler = TimelineHandler{*timeline};
timelines_.emplace(surfaceId, std::move(timeline));
return handler;
}
}
void TimelineController::disable(TimelineHandler&& handler) const {
std::unique_lock<std::shared_mutex> lock(timelinesMutex_);
auto iterator = timelines_.find(handler.getSurfaceId());
assert(iterator != timelines_.end());
timelines_.erase(iterator);
handler.release();
}
void TimelineController::commitHookWasRegistered(
const UIManager& uiManager) noexcept {
uiManager_ = &uiManager;
}
void TimelineController::commitHookWasUnregistered(
const UIManager& /*uiManager*/) noexcept {
uiManager_ = nullptr;
}
RootShadowNode::Unshared TimelineController::shadowTreeWillCommit(
const ShadowTree& shadowTree,
const RootShadowNode::Shared& oldRootShadowNode,
const RootShadowNode::Unshared& newRootShadowNode) noexcept {
std::shared_lock<std::shared_mutex> lock(timelinesMutex_);
assert(uiManager_ && "`uiManager_` must not be `nullptr`.");
lastUpdatedSurface_ = shadowTree.getSurfaceId();
auto iterator = timelines_.find(shadowTree.getSurfaceId());
if (iterator == timelines_.end()) {
return newRootShadowNode;
}
auto& timeline = *iterator->second;
return timeline.shadowTreeWillCommit(
shadowTree, oldRootShadowNode, newRootShadowNode);
}
} // namespace facebook::react

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <memory>
#include <shared_mutex>
#include <unordered_map>
#include <react/renderer/core/ReactPrimitives.h>
#include <react/renderer/timeline/Timeline.h>
#include <react/renderer/timeline/TimelineHandler.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
namespace facebook::react {
/*
* Provides tools for introspecting the series of commits and associated
* side-effects, allowing to "rewind" UI to any particular commit from the past.
*/
class TimelineController final : public UIManagerCommitHook {
public:
using Shared = std::shared_ptr<const TimelineController>;
/*
* Creates a `TimelineHandler` associated with given `SurfaceId` and starts
* the introspection process.
*/
TimelineHandler enable(SurfaceId surfaceId) const;
/*
* Consumes and destroys a `TimelineHandler` instance triggering the
* destruction of all associated resources and stopping the introspection
* process.
*/
void disable(TimelineHandler&& handler) const;
/*
* TO BE DELETED.
*/
SurfaceId lastUpdatedSurface() const {
return lastUpdatedSurface_;
}
#pragma mark - UIManagerCommitHook
RootShadowNode::Unshared shadowTreeWillCommit(
const ShadowTree& shadowTree,
const RootShadowNode::Shared& oldRootShadowNode,
const RootShadowNode::Unshared& newRootShadowNode) noexcept override;
void commitHookWasRegistered(const UIManager& uiManager) noexcept override;
void commitHookWasUnregistered(const UIManager& uiManager) noexcept override;
private:
/*
* Protects all the data members.
*/
mutable std::shared_mutex timelinesMutex_;
/*
* Owning collection of all running `Timeline` instances.
*/
mutable std::unordered_map<SurfaceId, std::unique_ptr<Timeline>> timelines_;
mutable const UIManager* uiManager_;
mutable SurfaceId lastUpdatedSurface_;
};
} // namespace facebook::react

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TimelineFrame.h"
namespace facebook::react {
TimelineFrame::TimelineFrame(int index, TelemetryTimePoint timePoint) noexcept
: index_(index), timePoint_(timePoint) {}
int TimelineFrame::getIndex() const noexcept {
return index_;
}
TelemetryTimePoint TimelineFrame::getTimePoint() const noexcept {
return timePoint_;
}
} // namespace facebook::react

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/core/LayoutPrimitives.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
#include <react/utils/Telemetry.h>
namespace facebook::react {
/*
* Represents a reference to a commit from the past.
* The reference can be safely used to address a particular commit from non-core
* code.
*/
class TimelineFrame final {
friend class TimelineSnapshot;
/*
* Constructor is private and must be called by `TimelineSnapshot` only.
*/
TimelineFrame(int index, TelemetryTimePoint timePoint) noexcept;
public:
using List = std::vector<TimelineFrame>;
TimelineFrame() = delete;
TimelineFrame(const TimelineFrame& timelineFrame) noexcept = default;
TimelineFrame& operator=(const TimelineFrame& other) noexcept = default;
int getIndex() const noexcept;
TelemetryTimePoint getTimePoint() const noexcept;
private:
int index_;
TelemetryTimePoint timePoint_;
};
} // namespace facebook::react

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TimelineHandler.h"
#include <algorithm>
#include <react/renderer/timeline/Timeline.h>
namespace facebook::react {
TimelineHandler::TimelineHandler(const Timeline& timeline) noexcept
: timeline_(&timeline) {}
TimelineHandler::TimelineHandler(TimelineHandler&& other) noexcept {
this->operator=(std::move(other));
}
TimelineHandler::~TimelineHandler() noexcept {
if (timeline_ != nullptr) {
// Improper deallocation indicates a severe error in application logic:
abort();
}
}
TimelineHandler& TimelineHandler::operator=(TimelineHandler&& other) noexcept {
assert(other.timeline_ && "Moving from an empty `TimelineHandler`.");
timeline_ = other.timeline_;
other.timeline_ = nullptr;
return *this;
}
#pragma mark - Public
void TimelineHandler::pause() const noexcept {
ensureNotEmpty();
timeline_->pause();
}
void TimelineHandler::resume() const noexcept {
ensureNotEmpty();
timeline_->resume();
}
bool TimelineHandler::isPaused() const noexcept {
ensureNotEmpty();
return timeline_->isPaused();
}
TimelineFrame TimelineHandler::getCurrentFrame() const noexcept {
ensureNotEmpty();
return timeline_->getCurrentFrame();
}
TimelineFrame::List TimelineHandler::getFrames() const noexcept {
ensureNotEmpty();
return timeline_->getFrames();
}
void TimelineHandler::rewind(const TimelineFrame& frame) const noexcept {
ensureNotEmpty();
return timeline_->rewind(frame);
}
void TimelineHandler::seek(int delta) const noexcept {
ensureNotEmpty();
auto frames = timeline_->getFrames();
auto currentFrame = timeline_->getCurrentFrame();
auto seekFrameIndex = currentFrame.getIndex() + delta;
seekFrameIndex =
std::min((int)frames.size() - 1, std::max(0, seekFrameIndex));
timeline_->rewind(frames.at(seekFrameIndex));
}
#pragma mark - Private
SurfaceId TimelineHandler::getSurfaceId() const noexcept {
return timeline_->getSurfaceId();
}
void TimelineHandler::release() noexcept {
timeline_ = nullptr;
}
void TimelineHandler::ensureNotEmpty() const noexcept {
if (timeline_ == nullptr) {
abort();
}
}
} // namespace facebook::react

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/core/LayoutPrimitives.h>
#include <react/renderer/timeline/TimelineFrame.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
namespace facebook::react {
class Timeline;
class TimelineHandler final {
public:
~TimelineHandler() noexcept;
/*
* Movable, not copyable.
*/
TimelineHandler(TimelineHandler&& other) noexcept;
TimelineHandler(const TimelineHandler& timelineHandler) = delete;
TimelineHandler& operator=(TimelineHandler&& other) noexcept;
TimelineHandler& operator=(const TimelineHandler& other) = delete;
/*
* Stops (or resumes) mounting of new commits.
* A surface has to be paused to allow rewinding the UI to some past commit.
*/
void pause() const noexcept;
void resume() const noexcept;
bool isPaused() const noexcept;
/*
* Provides access to recorded frames.
*/
TimelineFrame::List getFrames() const noexcept;
TimelineFrame getCurrentFrame() const noexcept;
/*
* Rewinds the UI to a given frame.
*/
void rewind(const TimelineFrame& frame) const noexcept;
/*
* Rewinds the UI for a given number of frames back or forward.
*/
void seek(int delta) const noexcept;
private:
friend class TimelineController;
/*
* Can only be constructed by `TimelineController`.
*/
TimelineHandler(const Timeline& timeline) noexcept;
/*
* Must be called before deallocation to make it not crash.
* Must be only called by `TimelineController`.
*/
void release() noexcept;
/*
* Returns a `SurfaceId` of the assigned Surface.
*/
SurfaceId getSurfaceId() const noexcept;
void ensureNotEmpty() const noexcept;
const Timeline* timeline_{};
};
} // namespace facebook::react

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TimelineSnapshot.h"
#include <react/utils/Telemetry.h>
#include <utility>
namespace facebook::react {
TimelineSnapshot::TimelineSnapshot(
RootShadowNode::Shared rootShadowNode,
int index) noexcept
: rootShadowNode_(std::move(rootShadowNode)),
frame_(TimelineFrame{index, telemetryTimePointNow()}) {}
RootShadowNode::Shared TimelineSnapshot::getRootShadowNode() const noexcept {
return rootShadowNode_;
}
TimelineFrame TimelineSnapshot::getFrame() const noexcept {
return frame_;
}
} // namespace facebook::react

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/root/RootShadowNode.h>
#include <react/renderer/timeline/TimelineFrame.h>
namespace facebook::react {
/*
* Represents a reference to a commit from the past used by `Timeline`.
*/
class TimelineSnapshot final {
public:
using List = std::vector<TimelineSnapshot>;
TimelineSnapshot(RootShadowNode::Shared rootShadowNode, int index) noexcept;
TimelineFrame getFrame() const noexcept;
RootShadowNode::Shared getRootShadowNode() const noexcept;
private:
RootShadowNode::Shared rootShadowNode_;
TimelineFrame frame_;
};
} // namespace facebook::react