Преглед изворни кода

Seleccion de fechas en cockpit y validacion

wilitp пре 4 година
родитељ
комит
4a2b321ebb

+ 2 - 2
app/src/api/tables.ts

@@ -32,8 +32,8 @@ export const generalTable = (from: string, to: string, token: string) => {
   };
 
   const qParams = new URLSearchParams();
-  qParams.append("start_datetime", from);
-  qParams.append("end_datetime", to);
+  qParams.append("start_datetime", `${from}T00:00`);
+  qParams.append("end_datetime", `${to}T00:00`);
   return mustFetchJson<Summary[]>(
     `${apiURL}station/all/summary?${qParams.toString()}`,
     config

+ 74 - 25
app/src/components/UI/dashboard/cockpit/index.tsx

@@ -16,11 +16,7 @@ import * as actions from "../../../../context/dashboard/actions";
 import { sectors } from "../../../../api";
 import { UserStateContext } from "../../../../context/auth/AuthProvider";
 import { Station } from "../../../../types";
-
-const campaignList: any[] = ["2018", "2019", "2020", "2021"].map((c) => ({
-  value: c,
-  title: c,
-}));
+import { mustCheckDateOrder } from "../../../../utils";
 
 const Cockpit: FC = () => {
   const dashboardState = useContext(StateContext);
@@ -28,6 +24,18 @@ const Cockpit: FC = () => {
   const userState = useContext(UserStateContext);
   const [sectorList, setSectorList] = useState<Station[]>([]);
 
+  // Opciones para selector de campania
+  const selectedCampaignYear = dashboardState.maxDate.slice(0, 4);
+  const lastCampaignYear = useMemo(
+    () => dashboardState.maxDate.slice(0, 4),
+    []
+  );
+  const campaignListLength = 4;
+  const campaignList = useMemo(
+    () => campList(lastCampaignYear, campaignListLength),
+    []
+  );
+
   // Inicializacion del selector de fincas
   useEffect(() => {
     const token = userState.userToken;
@@ -49,8 +57,24 @@ const Cockpit: FC = () => {
     [sectorList]
   );
 
+  const handleCampChange = (e: ChangeEvent<HTMLInputElement>) => {
+    const camp = campMaxMin(e.target.value);
+    dashboardDispatch(actions.setMinMaxDate(camp.min, camp.max));
+  };
+
+  const handleFromChange = (e: ChangeEvent<HTMLInputElement>) => {
+    mustCheckDateOrder(e.target.value, dashboardState.to);
+    return dashboardDispatch(actions.setFromControl(e.target.value));
+  };
+
+  const handleToChange = (e: ChangeEvent<HTMLInputElement>) => {
+    mustCheckDateOrder(e.target.value, dashboardState.to);
+    return dashboardDispatch(actions.setToControl(e.target.value));
+  };
+
   return (
     <section className="row p-lg-4 p-md-3 p-2">
+      {/* Finca */}
       <div className="col-12 col-lg-4 mb-2 col-xl-3 mb-xl-0">
         <Select
           list={sectorChoices}
@@ -61,40 +85,65 @@ const Cockpit: FC = () => {
           placeholder="Fincas"
         />
       </div>
+
+      {/* Campania */}
       <div className="col-6 col-lg-4 mb-2 col-xl-auto mb-xl-0">
-        <CalendarInput
-          onChange={(e: ChangeEvent<HTMLInputElement>) =>
-            dashboardDispatch(
-              actions.setFromControl(e.target.valueAsDate?.toISOString() ?? "")
-            )
-          }
-          value={dashboardState.from.slice(0, 10)}
+        <Select
+          list={campaignList}
+          onChange={handleCampChange}
+          value={selectedCampaignYear}
           name="Comparación"
+          placeholder="Camapaña"
         />
       </div>
+
+      {/* Desde */}
       <div className="col-6 col-lg-4 mb-2 col-xl-auto mb-xl-0">
         <CalendarInput
-          onChange={(e: ChangeEvent<HTMLInputElement>) =>
-            dashboardDispatch(
-              actions.setToControl(e.target.valueAsDate?.toISOString() ?? "")
-            )
-          }
-          value={dashboardState.to.slice(0, 10)}
+          onChange={handleFromChange}
+          value={dashboardState.from}
           name="Comparación"
+          min={dashboardState.minDate}
+          max={dashboardState.maxDate}
         />
       </div>
+
+      {/* Hasta */}
       <div className="col-6 col-lg-4 mb-2 col-xl-auto mb-xl-0">
-        <Select
-          list={campaignList}
-          onChange={(e: ChangeEvent<HTMLInputElement>) =>
-            dashboardDispatch(actions.setYearControl(e.target.value))
-          }
-          value={dashboardState.year}
+        <CalendarInput
+          onChange={handleToChange}
+          value={dashboardState.to}
           name="Comparación"
-          placeholder="Año historicos"
+          min={dashboardState.minDate}
+          max={dashboardState.maxDate}
         />
       </div>
     </section>
   );
 };
+
+const campMaxMin = (year: string) => {
+  // Las fechas extremas de la temporada de este anio
+  let maxDate = new Date(parseInt(year), 2, 31);
+  let minDate = new Date(parseInt(year) - 1, 9, 1);
+
+  // Conseguimos el string yyyy-mm-dd
+  const max = maxDate.toISOString().slice(0, 10);
+  const min = minDate.toISOString().slice(0, 10);
+
+  return { min, max };
+};
+
+// Computa las campanias para seleccionar
+// a partir de la ultima campania y la cantidad de anios para atras
+const campList = (lastCampaignYear: string, length: number) =>
+  Array.from({
+    length,
+  }).map((_, i) => {
+    const year = parseInt(lastCampaignYear) - length + 1 + i;
+    return {
+      value: year,
+      title: year,
+    };
+  });
 export default Cockpit;

+ 3 - 0
app/src/context/dashboard/actionTypes.ts

@@ -4,6 +4,7 @@ export type ActionType =
   | "SET_YEAR_CONTROL"
   | "SET_MIN_DATE"
   | "SET_MAX_DATE"
+  | "SET_MIN_MAX_DATE"
   | "SET_SECTOR";
 
 export type Action = {
@@ -13,4 +14,6 @@ export type Action = {
   from?: string | null;
   year?: string | null;
   date?: string;
+  minDate?: string;
+  maxDate?: string;
 };

+ 11 - 0
app/src/context/dashboard/actions.ts

@@ -1,4 +1,5 @@
 import { Action } from "./actionTypes";
+import { mustCheckDateOrder } from "../../utils";
 
 export const setYearControl = (year: string): Action => ({
   type: "SET_YEAR_CONTROL",
@@ -30,4 +31,14 @@ export const setMinDate = (date: string): Action => ({
   date,
 });
 
+export const setMinMaxDate = (min: string, max: string): Action => {
+  mustCheckDateOrder(min, max);
+
+  return {
+    type: "SET_MIN_MAX_DATE",
+    minDate: min,
+    maxDate: max,
+  };
+};
+
 export default {};

+ 15 - 11
app/src/context/dashboard/reducer.ts

@@ -9,7 +9,6 @@ export const defaultState = {
 
 export const getInitialState = (): State => {
   const now = new Date();
-  const day = now.toISOString();
 
   // Las fechas extremas de la temporada de este anio
   let maxDate = new Date(now.getFullYear(), 2, 31);
@@ -23,13 +22,13 @@ export const getInitialState = (): State => {
 
   // Conseguimos el string yyyy-mm-dd
   const maxDateString = maxDate.toISOString().slice(0, 10);
-  const minDateString = maxDate.toISOString().slice(0, 10);
+  const minDateString = minDate.toISOString().slice(0, 10);
 
   return {
     sector: null,
     year: now.getFullYear().toString(),
-    from: day,
-    to: day,
+    from: minDateString,
+    to: maxDateString,
     minDate: minDateString,
     maxDate: maxDateString,
   };
@@ -45,9 +44,6 @@ export type State = {
   minDate: string;
 };
 
-const fixYear = (year: string, dateString: string) =>
-  `${year}-${dateString.slice(5)}`;
-
 const reducer: Reducer<State, Action> = (state, action) => {
   switch (action.type) {
     case "SET_SECTOR":
@@ -58,29 +54,37 @@ const reducer: Reducer<State, Action> = (state, action) => {
     case "SET_MIN_DATE":
       return {
         ...state,
+        from: action.date ?? "",
         minDate: action.date ?? "",
       };
     case "SET_MAX_DATE":
       return {
         ...state,
+        to: action.date ?? "",
         maxDate: action.date ?? "",
       };
+    case "SET_MIN_MAX_DATE":
+      return {
+        ...state,
+        to: action.maxDate ?? "",
+        maxDate: action.maxDate ?? "",
+        from: action.minDate ?? "",
+        minDate: action.minDate ?? "",
+      };
     case "SET_TO_CONTROL":
       return {
         ...state,
-        to: fixYear(state.year, action.to!),
+        to: action.to!,
       };
     case "SET_FROM_CONTROL":
       return {
         ...state,
-        from: fixYear(state.year, action.from!),
+        from: action.from!,
       };
     case "SET_YEAR_CONTROL":
       return {
         ...state,
         year: action.year!,
-        to: fixYear(action.year!, state.to),
-        from: fixYear(action.year!, state.from),
       };
     default:
       return state;

+ 12 - 0
app/src/utils.ts

@@ -0,0 +1,12 @@
+export function checkDateOrder(first: string, second: string) {
+  const firstTs = Date.parse(first);
+  const secondTs = Date.parse(second);
+  return firstTs <= secondTs;
+}
+export function mustCheckDateOrder(first: string, second: string) {
+  if (!checkDateOrder(first, second)) {
+    throw new Error(
+      "La fecha inicial no puede ser posterior a la fecha final."
+    );
+  }
+}