- 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
129 lines
2.8 KiB
JavaScript
129 lines
2.8 KiB
JavaScript
"use strict";
|
|
const urlencoded = require("./urlencoded");
|
|
|
|
function stableSortBy(arr, compare) {
|
|
return arr
|
|
.map((item, index) => ({ item, index }))
|
|
.sort((a, b) => compare(a.item, b.item) || a.index - b.index)
|
|
.map(({ item }) => item);
|
|
}
|
|
|
|
exports.implementation = class URLSearchParamsImpl {
|
|
constructor(globalObject, constructorArgs, { doNotStripQMark = false }) {
|
|
let init = constructorArgs[0];
|
|
this._list = [];
|
|
this._url = null;
|
|
|
|
if (!doNotStripQMark && typeof init === "string" && init[0] === "?") {
|
|
init = init.slice(1);
|
|
}
|
|
|
|
if (Array.isArray(init)) {
|
|
for (const pair of init) {
|
|
if (pair.length !== 2) {
|
|
throw new TypeError("Failed to construct 'URLSearchParams': parameter 1 sequence's element does not " +
|
|
"contain exactly two elements.");
|
|
}
|
|
this._list.push([pair[0], pair[1]]);
|
|
}
|
|
} else if (typeof init === "object" && Object.getPrototypeOf(init) === null) {
|
|
for (const name of Object.keys(init)) {
|
|
const value = init[name];
|
|
this._list.push([name, value]);
|
|
}
|
|
} else {
|
|
this._list = urlencoded.parseUrlencoded(init);
|
|
}
|
|
}
|
|
|
|
_updateSteps() {
|
|
if (this._url !== null) {
|
|
let query = urlencoded.serializeUrlencoded(this._list);
|
|
if (query === "") {
|
|
query = null;
|
|
}
|
|
this._url._url.query = query;
|
|
}
|
|
}
|
|
|
|
append(name, value) {
|
|
this._list.push([name, value]);
|
|
this._updateSteps();
|
|
}
|
|
|
|
delete(name) {
|
|
let i = 0;
|
|
while (i < this._list.length) {
|
|
if (this._list[i][0] === name) {
|
|
this._list.splice(i, 1);
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
this._updateSteps();
|
|
}
|
|
|
|
get(name) {
|
|
for (const tuple of this._list) {
|
|
if (tuple[0] === name) {
|
|
return tuple[1];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
getAll(name) {
|
|
const output = [];
|
|
for (const tuple of this._list) {
|
|
if (tuple[0] === name) {
|
|
output.push(tuple[1]);
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
has(name) {
|
|
for (const tuple of this._list) {
|
|
if (tuple[0] === name) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
set(name, value) {
|
|
let found = false;
|
|
let i = 0;
|
|
while (i < this._list.length) {
|
|
if (this._list[i][0] === name) {
|
|
if (found) {
|
|
this._list.splice(i, 1);
|
|
} else {
|
|
found = true;
|
|
this._list[i][1] = value;
|
|
i++;
|
|
}
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
if (!found) {
|
|
this._list.push([name, value]);
|
|
}
|
|
this._updateSteps();
|
|
}
|
|
|
|
sort() {
|
|
this._list = stableSortBy(this._list, (a, b) => a[0] > b[0]);
|
|
this._updateSteps();
|
|
}
|
|
|
|
[Symbol.iterator]() {
|
|
return this._list[Symbol.iterator]();
|
|
}
|
|
|
|
toString() {
|
|
return urlencoded.serializeUrlencoded(this._list);
|
|
}
|
|
};
|