Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: minor refactor #10

Merged
merged 2 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions packages/auth-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"files": ["dist"],
"scripts": {
"build:check": "tsc",
"build:js": "vite build",
Expand All @@ -27,8 +25,6 @@
"dev:types": "tsup --watch src",
"dev": "npm-run-all clean --parallel dev:js dev:types",
"lint": "biome lint src",
"start": "static-server dist --port 5173",
"test:watch": "vitest",
"test": "vitest run"
"start": "static-server dist --port 5173"
}
}
4 changes: 4 additions & 0 deletions packages/auth-common/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export const AUTH_TYPES = {
ID_TOKEN: "id_token",
};

export const HEADERS = {
tenantId: "X-Auth-TenantId",
};
4 changes: 1 addition & 3 deletions packages/auth-provider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"files": ["dist"],
"scripts": {
"build:check": "tsc",
"build:js": "vite build",
Expand Down
9 changes: 9 additions & 0 deletions packages/auth-provider/src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const EXPIRED_SESSION =
"Oops! It looks like your session has expired. For your security, please log in again to continue.";
export const AUTH_CONTEXT_ERROR =
"You forgot to wrap your component in <AuthProvider>.";

export const API_ENDPOINT = {
dev: "https://auth.gizmette.local.com:3003",
prod: "https://auth.gizmette.com",
};
29 changes: 29 additions & 0 deletions packages/auth-provider/src/common/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export type ServiceCallProps = {
params: any;
};

export type AuthState = {
isAuthenticated: boolean;
idToken: string;
logoutReason: string;
userId: string;
accessToken?: string;
refreshToken?: string;
};

export type AuthProviderProps = {
children: React.ReactNode;
sessionExpiration?: string;
tenantId: string;
accessType?: string;
};

export type AuthContextProps = {
login: (username: string, password: string) => Promise<boolean>;
logout: () => void;
isAuthenticated: boolean;
accessToken?: string;
refreshToken?: string;
idToken?: string;
logoutReason?: string;
};
45 changes: 45 additions & 0 deletions packages/auth-provider/src/common/utilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { HEADERS } from "@versini/auth-common";
import { v4 as uuidv4 } from "uuid";

import { API_ENDPOINT } from "./constants";
import type { ServiceCallProps } from "./types";

export const isProd = process.env.NODE_ENV === "production";
export const isDev = !isProd;

export const serviceCall = async ({ params = {} }: ServiceCallProps) => {
try {
const nonce = uuidv4();
const response = await fetch(
isDev
? `${API_ENDPOINT.dev}/authenticate`
: `${API_ENDPOINT.prod}/authenticate`,
{
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
[HEADERS.tenantId]: `${params.tenantId}`,
},
body: JSON.stringify({ ...params, nonce }),
},
);

if (response.status !== 200) {
return { status: response.status, data: [] };
}
const { data, errors } = await response.json();
if (data.nonce !== nonce) {
return { status: 500, data: [] };
}

return {
status: response.status,
data,
errors,
};
} catch (_error) {
console.error(_error);
return { status: 500, data: [] };
}
aversini marked this conversation as resolved.
Show resolved Hide resolved
};
16 changes: 4 additions & 12 deletions packages/auth-provider/src/components/AuthProvider/AuthContext.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import { createContext } from "react";

export type AuthContextType = {
login: (username: string, password: string) => Promise<boolean>;
logout: () => void;
isAuthenticated: boolean;
accessToken?: string;
refreshToken?: string;
idToken?: string;
logoutReason?: string;
};
import { AUTH_CONTEXT_ERROR } from "../../common/constants";
import type { AuthContextProps } from "../../common/types";

const stub = (): never => {
throw new Error("You forgot to wrap your component in <AuthProvider>.");
throw new Error(AUTH_CONTEXT_ERROR);
};

export const AuthContext = createContext<AuthContextType>({
export const AuthContext = createContext<AuthContextProps>({
isAuthenticated: false,
login: stub,
logout: stub,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,76 +1,19 @@
import { AUTH_TYPES } from "@versini/auth-common";
import { useLocalStorage } from "@versini/ui-hooks";
import { useEffect, useRef, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { useEffect, useState } from "react";

import { EXPIRED_SESSION } from "../../common/constants";
import type { AuthProviderProps, AuthState } from "../../common/types";
import { serviceCall } from "../../common/utilities";
import { usePrevious } from "../hooks/usePrevious";
import { AuthContext } from "./AuthContext";

type AuthState = {
isAuthenticated: boolean;
idToken: string;
logoutReason: string;
userId: string;
accessToken?: string;
refreshToken?: string;
};

const EXPIRED_SESSION =
"Oops! It looks like your session has expired. For your security, please log in again to continue.";

const serviceCall = async ({ params = {} }: { params?: any }) => {
try {
const nonce = uuidv4();
const response = await fetch(
`${process.env.PUBLIC_AUTH_SERVER_URL}/authenticate`,
{
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Auth-TenantId": `${params.tenantId}`,
},
body: JSON.stringify({ ...params, nonce }),
},
);

if (response.status !== 200) {
return { status: response.status, data: [] };
}
const { data, errors } = await response.json();
if (data.nonce !== nonce) {
return { status: 500, data: [] };
}

return {
status: response.status,
data,
errors,
};
} catch (_error) {
console.error(_error);
return { status: 500, data: [] };
}
};

function usePrevious<T>(state: T): T | undefined {
const ref = useRef<T>();
useEffect(() => {
ref.current = state;
});
return ref.current;
}

export const AuthProvider = ({
children,
sessionExpiration,
tenantId,
accessType,
}: {
children: React.ReactNode;
sessionExpiration?: string;
tenantId: string;
accessType?: string;
}) => {
}: AuthProviderProps) => {
const [accessToken, setAccessToken, removeAccessToken] = useLocalStorage(
`@@auth@@::${tenantId}::@@access@@`,
"",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { render, screen } from "@testing-library/react";
import { AuthProvider } from "../..";

describe("AuthProvider", () => {
it("renders children components", () => {
render(
<AuthProvider tenantId="123">
<div data-testid="child-component">Child Component</div>
</AuthProvider>,
);
const childComponentElement = screen.getByTestId("child-component");
expect(childComponentElement).toBeInTheDocument();
});
});
2 changes: 0 additions & 2 deletions packages/auth-provider/src/components/AuthProvider/index.ts

This file was deleted.

5 changes: 0 additions & 5 deletions packages/auth-provider/src/components/AuthProvider/useAuth.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { renderHook } from "@testing-library/react";

import { useAuth } from "../..";

describe("useAuth tests", () => {
it("should return isAuthenticated false", () => {
const res1 = renderHook(() => useAuth());
expect(res1.result.current.isAuthenticated).toBe(false);
});
});
6 changes: 6 additions & 0 deletions packages/auth-provider/src/components/hooks/useAuth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useContext } from "react";
import type { AuthContextProps } from "../../common/types";
import { AuthContext } from "../AuthProvider/AuthContext";

export const useAuth = (context = AuthContext): AuthContextProps =>
useContext(context) as AuthContextProps;
9 changes: 9 additions & 0 deletions packages/auth-provider/src/components/hooks/usePrevious.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useEffect, useRef } from "react";

export function usePrevious<T>(state: T): T | undefined {
const ref = useRef<T>();
useEffect(() => {
ref.current = state;
});
return ref.current;
}
2 changes: 1 addition & 1 deletion packages/auth-provider/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { AuthProvider } from "./AuthProvider/AuthProvider";
export { useAuth } from "./AuthProvider/useAuth";
export { useAuth } from "./hooks/useAuth";
3 changes: 0 additions & 3 deletions packages/auth-provider/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import path from "node:path";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";

import fs from "fs-extra";
import { glob } from "glob";
import { defineConfig } from "vite";

import { externalDependencies } from "../../configuration/vite.common";
Expand Down
2 changes: 1 addition & 1 deletion packages/auth-provider/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default defineConfig((configEnv) =>
setupFiles: ["./vitest.setup.ts"],
environment: "happy-dom",
coverage: {
include: ["src/**/*.ts", "src/**/*.tsx", "!src/style.ts"],
include: ["src/**/*.ts", "src/**/*.tsx"],
provider: "v8",
thresholds: {
statements: 100,
Expand Down