Ver código fonte

primera edicion, falta firebase auth

Ruben Romero 3 anos atrás
pai
commit
8a7f5cd14c

+ 10 - 4
README.md

@@ -1,7 +1,13 @@
 # npm pkg ts
+Paquete de npm con hooks y utilidades escrito en Typescript.
 
-Testing package definition for npm module written in Typescript.
+# Cómo construir librería y utilizarla localmente?
+1. ```yarn build```
+2. Genera un directorio con todas las definiciones (./lib/)
+3. ```cd ~/ed-pkg```
+4. ```npm link```
+5. ```cd ~/proyecto_1```
+6. ```npm link ed-pkg```
 
-# how to build
-1. yarn build
-2. outputs -> ./lib
+# Guía para publicar paquete de npm privado
+* https://docs.npmjs.com/creating-and-publishing-private-packages

+ 3 - 0
package.json

@@ -14,7 +14,10 @@
   "author": "Ruben Romero <rubenxrb@gmail.com>",
   "license": "MIT",
   "devDependencies": {
+    "@types/node": "^16.7.8",
     "@types/react": "^17.0.19",
+    "@types/react-router": "^5.1.16",
+    "@types/react-router-dom": "^5.1.8",
     "react": "^17.0.2",
     "typescript": "^4.3.5"
   }

+ 1 - 1
src/constants/index.ts

@@ -1 +1 @@
-export * as httpStatusCodes from "./httpStatusCodes";
+export * as httpStatusCodes from "./httpStatusCodes";

+ 4 - 2
src/hooks/useApp.tsx

@@ -1,7 +1,9 @@
 import React from "react";
 import { AppProviderProps, defaultAppProviderProps } from "../types";
 
-const AppContext = React.createContext<AppProviderProps>(defaultAppProviderProps);
+const AppContext = React.createContext<AppProviderProps>(
+  defaultAppProviderProps
+);
 
 export function AppProvider(props: AppProviderProps) {
   const [type] = React.useState(props.type);
@@ -26,7 +28,7 @@ export function AppProvider(props: AppProviderProps) {
   }, [tokenStorageKey, token]);
 
   const memData = React.useMemo(() => {
-    return {type, token, tokenStorageKey: undefined, setToken};
+    return { type, token, tokenStorageKey: undefined, setToken };
   }, [type, token, tokenStorageKey, setToken]);
 
   return <AppContext.Provider value={memData} {...props} />;

+ 76 - 8
src/hooks/useAuth.tsx

@@ -1,20 +1,88 @@
 import React from "react";
+import { emptyRequest, getRequest, postRequest } from "../utils";
+import { useHttp } from "./useHttp";
+import { useApp } from "./useApp";
 import { AuthProviderProps, defaultAuthProviderProps } from "../types";
 
-const AuthContext = React.createContext<AuthProviderProps>(defaultAuthProviderProps);
+const AuthContext = React.createContext<AuthProviderProps>(
+  defaultAuthProviderProps
+);
 
-// const defaultNotifications = () => [1, 2];
+const empty = emptyRequest();
 
 export function AuthProvider(props: AuthProviderProps) {
-  const [notifications, setNotifications] = React.useState([]);
+  const { token, setToken } = useApp();
+  const [sessionRequest, setSessionRequest] = React.useState(empty);
+  const [session, sessionLoading] = useHttp(sessionRequest);
+  const [agendaRequest, setAgendaRequest] = React.useState(empty);
+  const [agendaResponse, agendaResponseLoading] = useHttp(agendaRequest);
 
-  // COMPONENTE SE MONTÓ
-  React.useEffect(() => {}, []);
+  React.useEffect(() => {
+    if (session && !sessionLoading) {
+      if (session?.resultado?.[0]) {
+        const { token } = session.resultado[0];
+        setToken(token);
+      }
+    }
+  }, [session, sessionLoading, setToken]);
+
+  React.useEffect(() => {
+    if (token) {
+      const agendaReq = getRequest("agenda/cuenta", {
+        expand: "permiso,agenda,consejoElectoral,consejosExtra,usuario",
+      });
+      // agendaReq.alert = true;
+      setAgendaRequest(() => agendaReq);
+    } else {
+      setAgendaRequest(empty);
+    }
+  }, [token]);
+
+  const signIn = React.useCallback(async (email, password) => {
+    try {
+      if (email !== "" && password !== "") {
+        const req = postRequest("login", { correo: email, clave: password });
+        setSessionRequest({ ...req });
+      }
+    } catch (e) {
+      console.log(e);
+    }
+  }, []);
+
+  const signOut = React.useCallback(async () => {
+    try {
+      setToken(null);
+      setSessionRequest(empty);
+    } catch (e) {
+      console.log(e);
+    }
+  }, [setToken]);
 
   const memData = React.useMemo(() => {
-    // AQUI SE PONE TODO LO Q EL HOOK EXPORTA
-    return { notifications, setNotifications };
-  }, [notifications]);
+    return {
+      session,
+      sessionLoading,
+      user:
+        agendaResponse &&
+        agendaResponse.resultado &&
+        agendaResponse.resultado.length > 0
+          ? {
+              ...agendaResponse.resultado[0],
+              permisoExtra: agendaResponse.detalle,
+            }
+          : null,
+      userLoading: agendaResponseLoading,
+      signIn,
+      signOut,
+    };
+  }, [
+    session,
+    sessionLoading,
+    agendaResponse,
+    agendaResponseLoading,
+    signIn,
+    signOut,
+  ]);
 
   return <AuthContext.Provider value={memData} {...props} />;
 }

+ 17 - 16
src/hooks/useHttp.tsx

@@ -1,10 +1,10 @@
 import React from "react";
 import { useAlert } from "./useAlert";
 import { useHistory } from "react-router";
-import { httpCodes } from "../constants";
+import { httpStatusCodes } from "../constants";
 // import { auth } from "../services";
 import { useApp } from "./useApp";
-import { useHttpProps, innerFetch} from '../types'
+import { useHttpProps, innerFetch, useHttpResponse } from "../types";
 
 const { REACT_APP_API_URL: baseUrl } = process.env;
 
@@ -36,18 +36,23 @@ export function useHttp({
   params = null,
   body = null,
   triggerAlert = false,
-}: useHttpProps) {
+}: useHttpProps): [
+  useHttpResponse | null,
+  boolean,
+  string | null,
+  (showAlert: any, inlineParams?: any) => Promise<void>
+] {
   const { showAlert } = useAlert();
   const { token } = useApp();
-  const [response, setResponse] = React.useState(null);
-  const [error, setError] = React.useState(null);
+  const [response, setResponse] = React.useState<useHttpResponse | null>(null);
+  const [error, setError] = React.useState<string | null>(null);
   const [loading, setLoading] = React.useState(true);
   const history = useHistory();
 
   const refresh = React.useCallback(
     async (showAlert, inlineParams = {}) => {
       try {
-        if (!url || !params) {
+        if (!url || !params || !req) {
           setResponse(null);
           setError(null);
           setLoading(true);
@@ -58,17 +63,13 @@ export function useHttp({
         } else {
           setLoading(() => true);
         }
-        // let token = null;
-        // if (auth.currentUser) {
-        //   token = await auth.currentUser.getIdToken();
-        // }
         const fetchReq: innerFetch = {
           method: req,
           headers: makeHeaders(token),
-          body: null
+          body: null,
         };
         if (body) {
-          const serializedBody =  JSON.stringify(body);
+          const serializedBody = JSON.stringify(body);
           fetchReq.body = serializedBody;
         }
         const paramsFinal = { ...params, ...inlineParams };
@@ -80,7 +81,7 @@ export function useHttp({
         const httpRes = await fetch(str, fetchReq);
         const resBody = await httpRes.json();
         switch (httpRes.status) {
-          case httpCodes.OK:
+          case httpStatusCodes.default.OK:
             setResponse(resBody);
             setError(null);
             triggerAlert &&
@@ -91,7 +92,7 @@ export function useHttp({
                   : "Solicitud completada correctamente!",
               });
             break;
-          case httpCodes.BAD_REQUEST:
+          case httpStatusCodes.default.BAD_REQUEST:
             window["scrollTo"]({ top: 0, behavior: "smooth" });
             setError(resBody.errores);
             triggerAlert &&
@@ -102,10 +103,10 @@ export function useHttp({
                   : "Datos erróneos o inválidos.",
               });
             break;
-          case httpCodes.UNAUTHORIZED:
+          case httpStatusCodes.default.UNAUTHORIZED:
             history.push("/no-autorizado");
             break;
-          case httpCodes.SERVER_ERROR:
+          case httpStatusCodes.default.INTERNAL_SERVER_ERROR:
           default:
             triggerAlert &&
               showAlert({

+ 15 - 10
src/hooks/useModel.tsx

@@ -1,8 +1,13 @@
 import React from "react";
 import { useHistory } from "react-router-dom";
-import { emptyRequest, getRequest, postRequest } from "../constants/requests";
-import { capitalizeFirst } from "../utilities";
+import {
+  capitalizeFirst,
+  emptyRequest,
+  getRequest,
+  postRequest,
+} from "../utils";
 import { useHttp } from "./useHttp";
+import { useModelProps } from "../types";
 
 const empty = emptyRequest();
 
@@ -13,8 +18,8 @@ export function useModel({
   expand = null,
   extraParams = null,
   redirectOnPost = false,
-  path = "guardar",
-}) {
+  postPath = "guardar",
+}: useModelProps) {
   const [modelRequest, setProfileRequest] = React.useState(empty);
   const [model, modelLoading, modelError, refreshModel] = useHttp(modelRequest);
 
@@ -30,12 +35,12 @@ export function useModel({
           newModel = { [`id${capitalizeFirst(name)}`]: newModel.id };
           delete newModel.id;
         }
-        const updateReq = postRequest(`${name}/${path}`, newModel);
-        updateReq.alert = alert;
+        const updateReq = postRequest(`${name}/${postPath}`, newModel);
+        updateReq.triggerAlert = alert;
         setUpdateRequest(updateReq);
       }
     },
-    [name, postResultLoading, path]
+    [name, postResultLoading, postPath]
   );
 
   React.useEffect(() => {
@@ -66,9 +71,9 @@ export function useModel({
       modelTmp = model.resultado[0];
       if (model.detalle) modelTmp.detalleExtra = model.detalle;
     }
-    let finalError = {};
-    if (modelError) finalError = { ...modelError };
-    if (postResultError) finalError = { ...finalError, ...postResultError };
+    let finalError: string | null = null;
+    if (modelError) finalError = modelError;
+    if (postResultError) finalError = postResultError;
     return {
       model: modelTmp,
       modelLoading,

+ 11 - 7
src/hooks/useModels.tsx

@@ -1,6 +1,8 @@
 import React from "react";
-import { emptyRequest, getRequest, deleteRequest } from "../constants/requests";
+import { emptyRequest, getRequest, deleteRequest } from "../utils";
+import { useModelsProps } from "../types/useModelsProps";
 import { useHttp } from "./useHttp";
+import { Yii2Pagination } from "../types";
 
 const empty = emptyRequest();
 
@@ -12,9 +14,11 @@ export function useModels({
   limite = null,
   pagina = null,
   extraParams = null,
-}) {
+}: useModelsProps) {
   const [modelRequest, setModelsRequest] = React.useState(empty);
-  const [modelsPage, setModelsPage] = React.useState(null);
+  const [modelsPage, setModelsPage] = React.useState<Yii2Pagination | null>(
+    null
+  );
   const [models, modelsLoading, modelsError, refreshModels] =
     useHttp(modelRequest);
 
@@ -25,7 +29,7 @@ export function useModels({
     async (id) => {
       if (!deleteResultLoading) {
         const deleteReq = deleteRequest(name, id);
-        deleteReq.alert = true;
+        deleteReq.triggerAlert = true;
         setDelRequest(deleteReq);
       }
     },
@@ -51,18 +55,18 @@ export function useModels({
   React.useEffect(() => {
     if (!modelsLoading && !modelsError && models) {
       const { paginacion } = models;
-      setModelsPage(paginacion);
+      if (paginacion) setModelsPage(paginacion);
     }
   }, [models, modelsLoading, modelsError]);
 
   React.useEffect(() => {
     if (!deleteResultLoading && deleteResult) {
-      refreshModels();
+      refreshModels(false, null);
     }
   }, [deleteResult, deleteResultLoading, refreshModels]);
 
   return React.useMemo(() => {
-    let resultado = [];
+    let resultado: Array<any> = [];
     if (models && models.resultado && models.resultado.length > 0) {
       resultado = [...models.resultado];
     }

+ 2 - 8
src/hooks/useNotifications.tsx

@@ -1,17 +1,11 @@
 import React from "react";
 
-const NotificationsContext = React.createContext();
+const NotificationsContext = React.createContext(null);
 
-// const defaultNotifications = () => [1, 2];
-
-export function NotificationsProvider(props) {
+export function NotificationsProvider(props: null) {
   const [notifications, setNotifications] = React.useState([]);
 
-  // COMPONENTE SE MONTÓ
-  React.useEffect(() => {}, []);
-
   const memData = React.useMemo(() => {
-    // AQUI SE PONE TODO LO Q EL HOOK EXPORTA
     return { notifications, setNotifications };
   }, [notifications]);
 

+ 3 - 9
src/types/AlertProviderProps.ts

@@ -1,11 +1,5 @@
+interface AlertProviderProps {}
 
+const defaultAlertProviderProps: AlertProviderProps = {};
 
-interface AlertProviderProps {
-
-}
-
-const defaultAlertProviderProps: AlertProviderProps = {
-
-};
-
-export { AlertProviderProps, defaultAlertProviderProps };
+export { AlertProviderProps, defaultAlertProviderProps };

+ 6 - 7
src/types/AppProviderProps.ts

@@ -1,18 +1,17 @@
-
 type AppProviderType = "regular" | "firebase";
 
 interface AppProviderProps {
-  type: AppProviderType,
-  token: string | null,
-  tokenStorageKey: string | undefined,
-  setToken: (newToken: string) => void
+  type: AppProviderType;
+  token: string | null;
+  tokenStorageKey: string | undefined;
+  setToken: (newToken: string | null) => void;
 }
 
 const defaultAppProviderProps: AppProviderProps = {
   type: "regular",
   token: null,
   tokenStorageKey: undefined,
-  setToken: () => {}
+  setToken: () => {},
 };
 
-export { AppProviderProps, defaultAppProviderProps };
+export { AppProviderProps, defaultAppProviderProps };

+ 3 - 9
src/types/AuthProviderProps.ts

@@ -1,11 +1,5 @@
+interface AuthProviderProps {}
 
+const defaultAuthProviderProps: AuthProviderProps = {};
 
-interface AuthProviderProps {
-
-}
-
-const defaultAuthProviderProps: AuthProviderProps = {
-
-};
-
-export { AuthProviderProps, defaultAuthProviderProps };
+export { AuthProviderProps, defaultAuthProviderProps };

+ 5 - 4
src/types/index.ts

@@ -1,4 +1,5 @@
-export * from './AlertProviderProps';
-export * from './AppProviderProps';
-export * from './AuthProviderProps';
-export * from './useHttpProps';
+export * from "./AlertProviderProps";
+export * from "./AppProviderProps";
+export * from "./AuthProviderProps";
+export * from "./useHttpProps";
+export * from "./useModelProps";

+ 23 - 9
src/types/useHttpProps.ts

@@ -1,17 +1,31 @@
 type httpRequestType = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
 
 interface useHttpProps {
-  req: httpRequestType,
-  url: string,
-  params: any | null,
-  body: any | null,
-  triggerAlert: boolean,
+  req: httpRequestType | null;
+  url: string | null;
+  params: any | null;
+  body: any | null;
+  triggerAlert: boolean;
+}
+
+type Yii2Pagination = {
+  total: number;
+  pagina: number;
+  limite: number;
+};
+
+interface useHttpResponse {
+  resultado: any;
+  mensaje: string | undefined;
+  errores: Array<any>;
+  detalle: any;
+  paginacion?: Yii2Pagination;
 }
 
 interface innerFetch {
-  method: httpRequestType,
-  headers: any,
-  body: string | null
+  method: httpRequestType;
+  headers: any;
+  body: string | null;
 }
 
-export { useHttpProps, innerFetch };
+export { useHttpProps, useHttpResponse, innerFetch, Yii2Pagination };

+ 13 - 0
src/types/useModelProps.ts

@@ -0,0 +1,13 @@
+type postPathStrings = "guardar";
+
+interface useModelProps {
+  name: string;
+  id: string | number;
+  fields: string | null;
+  expand: string | null;
+  extraParams: object | null;
+  redirectOnPost: boolean;
+  postPath: postPathStrings | string;
+}
+
+export { useModelProps };

+ 11 - 0
src/types/useModelsProps.ts

@@ -0,0 +1,11 @@
+interface useModelsProps {
+  name: string;
+  fields: object | null;
+  expand: object | null;
+  ordenar: string | null;
+  limite: number | null;
+  pagina: number | null;
+  extraParams: object | null;
+}
+
+export { useModelsProps };

+ 1 - 1
src/utils/capitalize.ts

@@ -1,3 +1,3 @@
 const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
 
-export default capitalize;
+export default capitalize;

+ 1 - 1
src/utils/capitalizeFirst.ts

@@ -7,4 +7,4 @@ const capitalizeFirst = (str: string) => {
   return palabraUnida;
 };
 
-export default capitalizeFirst;
+export default capitalizeFirst;

+ 4 - 2
src/utils/index.ts

@@ -1,3 +1,5 @@
-export * as capitalize from './capitalize'
-export * as capitalizeFirst from './capitalizeFirst'
+import capitalizeFirst from "./capitalizeFirst";
+import capitalize from "./capitalize";
+
 export * from "./requests";
+export { capitalize, capitalizeFirst };

+ 18 - 4
src/utils/requests.ts

@@ -1,33 +1,47 @@
+import { useHttpProps } from "../types";
 import capitalizeFirst from "./capitalizeFirst";
 
-const emptyRequest = () => ({
+const emptyRequest = (): useHttpProps => ({
   req: null,
   url: null,
   params: null,
   body: null,
+  triggerAlert: false,
 });
 
-const getRequest = (url: string, params = {}) => ({
+const getRequest = (url: string, params = {}): useHttpProps => ({
   req: "GET",
   url,
   params,
   body: null,
+  triggerAlert: false,
 });
 
-const postRequest = (url: string, body: any, params: any = {}) => ({
+const postRequest = (
+  url: string,
+  body: any,
+  params: any = {}
+): useHttpProps => ({
   req: "POST",
   url,
   params,
   body,
+  triggerAlert: false,
 });
 
-const deleteRequest = (url: string, id: number | string, params: any = {}) => ({
+const deleteRequest = (
+  url: string,
+  id: number | string,
+  params: any = {}
+): useHttpProps => ({
   req: "DELETE",
   url: `${url}/eliminar`,
   params: {
     ...params,
     [`id${capitalizeFirst(url)}`]: id,
   },
+  body: null,
+  triggerAlert: false,
 });
 
 export { emptyRequest, getRequest, postRequest, deleteRequest };

+ 28 - 1
yarn.lock

@@ -2,12 +2,39 @@
 # yarn lockfile v1
 
 
+"@types/history@*":
+  version "4.7.9"
+  resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.9.tgz#1cfb6d60ef3822c589f18e70f8b12f9a28ce8724"
+  integrity sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==
+
+"@types/node@^16.7.8":
+  version "16.7.8"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.8.tgz#2448be5f24fe6b77114632b6350fcd219334651e"
+  integrity sha512-8upnoQU0OPzbIkm+ZMM0zCeFCkw2s3mS0IWdx0+AAaWqm4fkBb0UJp8Edl7FVKRamYbpJC/aVsHpKWBIbiC7Zg==
+
 "@types/prop-types@*":
   version "15.7.4"
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
   integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
 
-"@types/react@^17.0.19":
+"@types/react-router-dom@^5.1.8":
+  version "5.1.8"
+  resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.8.tgz#bf3e1c8149b3d62eaa206d58599de82df0241192"
+  integrity sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw==
+  dependencies:
+    "@types/history" "*"
+    "@types/react" "*"
+    "@types/react-router" "*"
+
+"@types/react-router@*", "@types/react-router@^5.1.16":
+  version "5.1.16"
+  resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.16.tgz#f3ba045fb96634e38b21531c482f9aeb37608a99"
+  integrity sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==
+  dependencies:
+    "@types/history" "*"
+    "@types/react" "*"
+
+"@types/react@*", "@types/react@^17.0.19":
   version "17.0.19"
   resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.19.tgz#8f2a85e8180a43b57966b237d26a29481dacc991"
   integrity sha512-sX1HisdB1/ZESixMTGnMxH9TDe8Sk709734fEQZzCV/4lSu9kJCPbo2PbTRoZM+53Pp0P10hYVyReUueGwUi4A==