Skip to content

Commit 374e99b

Browse files
authored
Merge pull request #6 from bert27/refactor/drinks-ui
fix(client): unify simulation mode logic and ensure mock cards visibility
2 parents cfca889 + 18b2fb7 commit 374e99b

File tree

9 files changed

+182
-50
lines changed

9 files changed

+182
-50
lines changed

client/src/components/simulation-alert/simulation-alert.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import { Alert, SxProps, Theme } from '@mui/material';
3+
import { SIMULATION_MESSAGE } from '@/utils/simulation';
34

45
interface SimulationAlertProps {
56
isMock: boolean;
@@ -23,7 +24,7 @@ export const SimulationAlert: React.FC<SimulationAlertProps> = ({ isMock, sx })
2324
...sx
2425
}}
2526
>
26-
Modo Simulación Activado: Navegando en Vercel (HTTPS). Conexión real deshabilitada por seguridad.
27+
{SIMULATION_MESSAGE}
2728
</Alert>
2829
);
2930
};

client/src/pages/car/hooks/use-robot-control.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IDashboardState } from '@/pages/car/models/model';
33
import { robotService } from '@/services/robot.service';
44
import { directionWebRobot } from "@/config/api.config";
55
import { useRemoteControl } from '@/context/remote-control-context';
6+
import { isSimulationMode } from '@/utils/simulation';
67

78
export const useRobotControl = () => {
89
// Convert http/https to ws/wss
@@ -47,7 +48,7 @@ export const useRobotControl = () => {
4748
const [color, setColor] = useState("#00d2ff");
4849
const [lastCmd, setLastCmd] = useState<string>("");
4950
const [connectionError, setConnectionError] = useState<string | null>(null);
50-
const [isMock, setIsMock] = useState(import.meta.env.VITE_MOCK_SERVER === 'true');
51+
const [isMock, setIsMock] = useState(isSimulationMode());
5152

5253
// Generic Socket Connector
5354
const setupSocket = useCallback((
@@ -58,8 +59,8 @@ export const useRobotControl = () => {
5859
setSocketCallback?: (socket: WebSocket | null) => void
5960
) => {
6061
// Mixed Content / HTTPS Detection
61-
if ((window.location.protocol === 'https:' && url.startsWith('ws:')) || import.meta.env.VITE_MOCK_SERVER === 'true') {
62-
console.warn(`[MockMode] Activation Request. Secure: ${window.location.protocol === 'https:'}, Env: ${import.meta.env.VITE_MOCK_SERVER}`);
62+
if ((window.location.protocol === 'https:' && url.startsWith('ws:')) || isSimulationMode()) {
63+
console.warn(`[MockMode] Activation Request. Secure: ${window.location.protocol === 'https:'}, Simulation: ${isSimulationMode()}`);
6364
setIsMock(true);
6465
return { cleanup: () => { } };
6566
}

client/src/pages/drinks/hooks/use-cocktails.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useState, useEffect } from "react";
22
import { Cocktail } from "@/pages/drinks/models/drinks-model";
33
import { drinksService } from "@/services/drinks.service";
44
import { availableCocktails } from "@/pages/drinks/data/cocktails.data";
5+
import { isSimulationMode } from "@/utils/simulation";
56

67
export const useCocktails = () => {
78
const [cocktails, setCocktails] = useState<Cocktail[]>([]);
@@ -24,12 +25,12 @@ export const useCocktails = () => {
2425
}))
2526
}));
2627
setCocktails(mapped);
27-
} else if (import.meta.env.VITE_MOCK_SERVER === 'true' || window.location.protocol === 'https:') {
28+
} else if (isSimulationMode()) {
2829
setCocktails(availableCocktails);
2930
}
3031
} catch (err) {
3132
console.error("Failed to fetch cocktails", err);
32-
if (import.meta.env.VITE_MOCK_SERVER === 'true' || window.location.protocol === 'https:') {
33+
if (isSimulationMode()) {
3334
setCocktails(availableCocktails);
3435
}
3536
} finally {

client/src/pages/drinks/hooks/use-drinks-page.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import { useCocktails } from "./use-cocktails";
88
import { usePumpManager } from "./use-pump-manager";
99
import { useSocketSync } from "./use-socket-sync";
1010

11+
import { isSimulationMode } from "@/utils/simulation";
12+
1113
export const useDrinksPage = () => {
1214
const [activeTab, setActiveTab] = useState<TabType>("drinks");
1315
const [selectedCocktailForConfirm, setSelectedCocktailForConfirm] = useState<Cocktail | null>(null);
1416

1517
// Simulation Mode Detection
16-
const isMock = import.meta.env.VITE_MOCK_SERVER === 'true' ||
17-
(window.location.protocol === 'https:' && directionWebDrinks.startsWith('http:'));
18+
const isMock = isSimulationMode();
1819
const {
1920
cocktails,
2021
updateCocktail,

client/src/pages/plant/hooks/use-plant-page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const withTimeout = <T,>(promise: Promise<T>, timeoutMs: number = 10000): Promis
2222
};
2323

2424
import { useTranslation } from "react-i18next";
25+
import { isSimulationMode } from "@/utils/simulation";
2526

2627
export const usePlantPage = () => {
2728
const { t } = useTranslation();
@@ -33,8 +34,7 @@ export const usePlantPage = () => {
3334
const [errorGet, setErrorGet] = useState<string | null>(null);
3435
const [isOpenModalConfig, setIsOpenModalConfig] = useState(false);
3536

36-
const isMock = import.meta.env.VITE_MOCK_SERVER === 'true' ||
37-
(window.location.protocol === 'https:' && directionWebIrrigation.startsWith('http:'));
37+
const isMock = isSimulationMode();
3838

3939
const [days, setDays] = useState<Day[]>([
4040
{ name: "L", state: false },
Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import axios from "axios";
22
import {
3-
directionWeb,
43
directionWebDrinks,
54
handleResponse,
6-
getRequestOptions
75
} from "../config/api.config";
6+
import { isSimulationMode, activateReactiveSimulation } from "../utils/simulation";
7+
import { availableCocktails } from "../pages/drinks/data/cocktails.data";
88

9-
const USE_MOCK = import.meta.env.VITE_MOCK_SERVER === 'true';
9+
const USE_MOCK = isSimulationMode();
1010

1111
export const drinksService = {
1212
/**
@@ -18,22 +18,48 @@ export const drinksService = {
1818
console.log("Mock Control Command:", direction);
1919
return { success: true };
2020
}
21-
const response = await axios.get(`${directionWebDrinks}/drinks/navigation`, { params: { direction } });
22-
return handleResponse(response);
21+
try {
22+
const response = await axios.get(`${directionWebDrinks}/drinks/navigation`, { params: { direction } });
23+
return handleResponse(response);
24+
} catch (error) {
25+
console.error("Drinks navigation error, triggering simulation fallback:", error);
26+
activateReactiveSimulation();
27+
throw error;
28+
}
2329
},
2430

2531
getCocktails: async (): Promise<any> => {
26-
if (USE_MOCK) return [];
27-
const response = await axios.get(`${directionWebDrinks}/drinks/cocktails`);
28-
return handleResponse(response);
32+
if (USE_MOCK) {
33+
return availableCocktails.map(c => ({
34+
name: c.name,
35+
ingredients: (c.recipe || []).map(r => ({
36+
name: r.liquid,
37+
quantity: r.quantity
38+
}))
39+
}));
40+
}
41+
try {
42+
const response = await axios.get(`${directionWebDrinks}/drinks/cocktails`);
43+
return handleResponse(response);
44+
} catch (error) {
45+
console.error("Failed to fetch cocktails, triggering simulation mode:", error);
46+
activateReactiveSimulation();
47+
throw error;
48+
}
2949
},
3050

3151
saveCocktail: async (name: string, ingredients: any[]): Promise<any> => {
3252
if (USE_MOCK) return { success: true };
33-
const response = await axios.post(`${directionWebDrinks}/drinks/save-cocktail`, {
34-
name,
35-
ingredients
36-
});
37-
return handleResponse(response);
53+
try {
54+
const response = await axios.post(`${directionWebDrinks}/drinks/save-cocktail`, {
55+
name,
56+
ingredients
57+
});
58+
return handleResponse(response);
59+
} catch (error) {
60+
console.error("Failed to save cocktail, triggering simulation mode:", error);
61+
activateReactiveSimulation();
62+
throw error;
63+
}
3864
}
3965
};

client/src/services/irrigation.service.ts

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { IWaterPumpStatus, ITemperature, IAddTask } from "../pages/plant/models/plant-model";
2-
import axios, { AxiosResponse } from "axios";
2+
import axios from "axios";
33
import { directionWebIrrigation, handleResponse } from "../config/api.config";
4+
import { activateReactiveSimulation, isSimulationMode } from "../utils/simulation";
45

5-
const USE_MOCK = import.meta.env.VITE_MOCK_SERVER === 'true';
6+
const USE_MOCK = isSimulationMode();
67

78
let mockState = {
89
waterPump1: false,
@@ -28,15 +29,21 @@ export const irrigationService = {
2829

2930
return { status: mockState.waterPump1 };
3031
}
31-
const response = await axios.get(`${directionWebIrrigation}/waterPump1OnOFF`, { params: data });
32-
const resData = handleResponse(response);
33-
let status = false;
34-
if (typeof resData === 'string') {
35-
if (resData === "ON" || resData === "OK") status = true;
36-
} else if (typeof resData === 'object' && resData.status !== undefined) {
37-
status = !!resData.status;
32+
try {
33+
const response = await axios.get(`${directionWebIrrigation}/waterPump1OnOFF`, { params: data });
34+
const resData = handleResponse(response);
35+
let status = false;
36+
if (typeof resData === 'string') {
37+
if (resData === "ON" || resData === "OK") status = true;
38+
} else if (typeof resData === 'object' && resData.status !== undefined) {
39+
status = !!resData.status;
40+
}
41+
return { status };
42+
} catch (error) {
43+
console.error("Irrigation state error, triggering simulation mode:", error);
44+
activateReactiveSimulation();
45+
throw error;
3846
}
39-
return { status };
4047
},
4148

4249
getList: async (): Promise<string> => {
@@ -47,14 +54,20 @@ export const irrigationService = {
4754
).join('/');
4855
return formattedTasks;
4956
}
50-
const response = await axios.get(`${directionWebIrrigation}/getList`);
51-
const data = handleResponse(response);
52-
if (Array.isArray(data)) {
53-
return data.flatMap((t: any) =>
54-
(Array.isArray(t.days) ? t.days : [t.days]).map((d: string) => `${d}-${t.hour}-${t.minutes}`)
55-
).join('/');
57+
try {
58+
const response = await axios.get(`${directionWebIrrigation}/getList`);
59+
const data = handleResponse(response);
60+
if (Array.isArray(data)) {
61+
return data.flatMap((t: any) =>
62+
(Array.isArray(t.days) ? t.days : [t.days]).map((d: string) => `${d}-${t.hour}-${t.minutes}`)
63+
).join('/');
64+
}
65+
return String(data);
66+
} catch (error) {
67+
console.error("Irrigation getList error, triggering simulation mode:", error);
68+
activateReactiveSimulation();
69+
throw error;
5670
}
57-
return String(data);
5871
},
5972

6073
postaddTaskEsp: async (hour: string | number, minutes: string | number, days: string): Promise<IAddTask> => {
@@ -64,10 +77,16 @@ export const irrigationService = {
6477
mockState.tasks.push({ hour: String(hour), minutes: String(minutes), days: newDays as any });
6578
return { success: true, message: "Task added (Mock)" };
6679
}
67-
const response = await axios.get(`${directionWebIrrigation}/addTaskEsp`, {
68-
params: { hour, minutes, days }
69-
});
70-
return handleResponse(response);
80+
try {
81+
const response = await axios.get(`${directionWebIrrigation}/addTaskEsp`, {
82+
params: { hour, minutes, days }
83+
});
84+
return handleResponse(response);
85+
} catch (error) {
86+
console.error("Irrigation addTask error, triggering simulation mode:", error);
87+
activateReactiveSimulation();
88+
throw error;
89+
}
7190
},
7291

7392
getTemperature: async (): Promise<ITemperature> => {
@@ -79,8 +98,14 @@ export const irrigationService = {
7998
humidity: mockState.humidity
8099
};
81100
}
82-
const response = await axios.get(`${directionWebIrrigation}/getTemperature`);
83-
return handleResponse(response);
101+
try {
102+
const response = await axios.get(`${directionWebIrrigation}/getTemperature`);
103+
return handleResponse(response);
104+
} catch (error) {
105+
console.error("Irrigation temperature error, triggering simulation mode:", error);
106+
activateReactiveSimulation();
107+
throw error;
108+
}
84109
},
85110

86111
getClock: async (): Promise<string> => {
@@ -89,7 +114,13 @@ export const irrigationService = {
89114
const now = new Date();
90115
return now.toLocaleTimeString();
91116
}
92-
const response = await axios.get(`${directionWebIrrigation}/getClock`);
93-
return handleResponse(response);
117+
try {
118+
const response = await axios.get(`${directionWebIrrigation}/getClock`);
119+
return handleResponse(response);
120+
} catch (error) {
121+
console.error("Irrigation clock error, triggering simulation mode:", error);
122+
activateReactiveSimulation();
123+
throw error;
124+
}
94125
}
95126
};

client/src/services/robot.service.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@ import { IColorData } from "../pages/car/models/model";
33
import { directionWebRobot, getRequestOptions } from "../config/api.config";
44
import { OutputDataInterface } from "../pages/car/components/card-outputs";
55
import { ColumnInterface } from "../pages/car/components/table-outputs";
6+
import { activateReactiveSimulation, isSimulationMode } from "../utils/simulation";
7+
8+
const USE_MOCK = isSimulationMode();
69

710
const axiosGet = async (params: any, endpoint: string) => {
11+
if (USE_MOCK) return { success: true };
812
try {
913
const response = await axios.get(`${directionWebRobot}/${endpoint}`, {
1014
params,
1115
...getRequestOptions("GET"),
1216
});
1317
return response.data;
1418
} catch (error: any) {
19+
console.error(`Robot service error on ${endpoint}:`, error);
20+
activateReactiveSimulation();
1521
const errorMessage = error.message ?? "Unknown error";
1622
return { type: "error", message: errorMessage };
1723
}
@@ -23,8 +29,15 @@ export const robotService = {
2329
},
2430

2531
toggleLED: async () => {
26-
const response = await axios.get(`${directionWebRobot}/toggleLED`);
27-
return response.data;
32+
if (USE_MOCK) return { success: true };
33+
try {
34+
const response = await axios.get(`${directionWebRobot}/toggleLED`);
35+
return response.data;
36+
} catch (error) {
37+
console.error("Robot toggleLED error:", error);
38+
activateReactiveSimulation();
39+
throw error;
40+
}
2841
},
2942

3043
sendDataOutputSelectedToServer: async (outputSelected: OutputDataInterface) => {
@@ -35,6 +48,10 @@ export const robotService = {
3548
return await axiosGet(rowSelected, "outputsRowTableRobot");
3649
},
3750

51+
sendRowTableOutputsStatusUpdate: async (rowSelected: ColumnInterface) => {
52+
return await axiosGet(rowSelected, "outputsRowTableRobotUpdate");
53+
},
54+
3855
sendOutputRobotUI: async (data: { name: string }) => {
3956
return await axiosGet(data, "outputRobotUI");
4057
},

0 commit comments

Comments
 (0)