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

Refactor/auth architecture pt2 #277

Merged
merged 11 commits into from
Oct 25, 2024
8 changes: 4 additions & 4 deletions src/app/(auth)/AuthProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useEffect } from "react";
import { formatInTimeZone } from "date-fns-tz";
import { clientSignIn, clientSignOut } from "@/store/features/auth/authSlice";
import { clientSignIn } from "@/store/features/auth/authSlice";
import { useAppDispatch } from "@/store/hooks";
import { type User, getUserState } from "@/store/features/user/userSlice";
import { type AppError } from "@/types/types";
Expand Down Expand Up @@ -34,9 +34,9 @@ export default function AuthProvider({ user, error }: AuthProviderProps) {
dispatch(getUserState(userWithDate));
}

if (error) {
dispatch(clientSignOut());
}
// if (error) {
// dispatch(clientSignOut());
// }
}, [dispatch, user, error]);

return null;
Expand Down
3 changes: 2 additions & 1 deletion src/app/(auth)/sign-in/components/SignInFormContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { validateTextInput } from "@/utils/form/validateInput";
import { clientSignIn } from "@/store/features/auth/authSlice";
import { useAppDispatch } from "@/store/hooks";
import routePaths from "@/utils/routePaths";
import { type AuthClientAdapter } from "@/app/(auth)/_adapters/authClientAdapter";
import { type AuthClientAdapter } from "@/modules/auth/adapters/primary/authClientAdapter";
import { TYPES } from "@/di/types";
import { resolve } from "@/di/resolver";

Expand Down Expand Up @@ -48,6 +48,7 @@ function SignInFormContainer({
resolver: zodResolver(validationSchema),
});

// TODO: update error handling
const onSubmit: SubmitHandler<ValidationSchema> = async (data) => {
const { email, password } = data;
const authAdapter = resolve<AuthClientAdapter>(TYPES.AuthClientAdapter);
Expand Down
43 changes: 28 additions & 15 deletions src/components/navbar/DropDown.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,57 @@
"use client";

import "reflect-metadata";
import { ChevronDownIcon } from "@heroicons/react/24/outline";
import Link from "next/link";
import { useRouter } from "next/navigation";
import Button from "@/components/Button";
import { useAppDispatch, useUser } from "@/store/hooks";
import { clientSignOut } from "@/store/features/auth/authSlice";
import { serverSignOut } from "@/app/(auth)/authService";
import { onOpenModal } from "@/store/features/modal/modalSlice";
import { TYPES } from "@/di/types";
import { resolve } from "@/di/resolver";
import { type AuthClientAdapter } from "@/modules/auth/adapters/primary/authClientAdapter";
import routePaths from "@/utils/routePaths";

export default function DropDown({ openState }: { openState?: boolean }) {
const router = useRouter();
const dispatch = useAppDispatch();
const allVoyages = useUser().voyageTeamMembers;
const activeVoyage = allVoyages?.find(
(item) => item.voyageTeam.voyage.status.name === "Active",
);

const currentVoyage = activeVoyage?.voyageTeam.name
? `Team - Tier ${activeVoyage.voyageTeam.name
let currentVoyage;

if (activeVoyage?.voyageTeam.name) {
currentVoyage = `Team - Tier ${activeVoyage.voyageTeam.name
.split("-")[1]
.split("tier")[1]
.toUpperCase()} ${activeVoyage.voyageTeam.name
.split("-")[0]
.toUpperCase()}`
: "Please join a voyage to see your status information.";
.toUpperCase()}`;
} else {
currentVoyage = "Please join a voyage to see your status information.";
}
const closed = "hidden";
const open =
"absolute flex flex-col gap-5 z-[1] w-[250px] p-5 bottom-100 translate-y-[15%] shadow-md bg-base-200 right-0 border border-base-100 rounded-2xl";

// TODO: update error handling
async function handleClick() {
const [res, error] = await serverSignOut();
const authAdapter = resolve<AuthClientAdapter>(TYPES.AuthClientAdapter);
Dan-Y-Ko marked this conversation as resolved.
Show resolved Hide resolved

if (res) {
dispatch(clientSignOut());
}
await authAdapter.logout();
dispatch(clientSignOut());
router.replace(routePaths.signIn());
// if (res) {
// dispatch(clientSignOut());
// }

if (error) {
dispatch(
onOpenModal({ type: "error", content: { message: error.message } }),
);
}
// if (error) {
// dispatch(
// onOpenModal({ type: "error", content: { message: error.message } }),
// );
// }
}

const handleDropDownClick = (event: React.MouseEvent<HTMLDivElement>) => {
Expand Down
4 changes: 3 additions & 1 deletion src/di/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { container } from "tsyringe";
import { TYPES } from "./types";
import { AuthApiAdapter } from "@/modules/auth/adapters/secondary/authApiAdapter";
import { AxiosAdapter } from "@/modules/restApi/adapters/secondary/AxiosAdapter";
import { AuthClientAdapter } from "@/app/(auth)/_adapters/authClientAdapter";
import { AuthClientAdapter } from "@/modules/auth/adapters/primary/authClientAdapter";
import { LoginUsecase } from "@/modules/auth/application/usecases/loginUsecase";
import { LogoutUsecase } from "@/modules/auth/application/usecases/logoutUsecase";

container.register(TYPES.RestApiPort, { useClass: AxiosAdapter });
container.register(TYPES.AuthApiPort, { useClass: AuthApiAdapter });
container.register(TYPES.LoginUsecase, { useClass: LoginUsecase });
container.register(TYPES.LogoutUsecase, { useClass: LogoutUsecase });
container.register(TYPES.AuthClientAdapter, { useClass: AuthClientAdapter });

export default container;
1 change: 1 addition & 0 deletions src/di/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export const TYPES = {

/* UseCases */
LoginUsecase: Symbol.for("LoginUsecase"),
LogoutUsecase: Symbol.for("LogoutUsecase"),
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { inject, injectable } from "tsyringe";
import { type LoginRequestDto } from "@/modules/auth/application/dtos/request.dto";
import { type LoginResponseDto } from "@/modules/auth/application/dtos/response.dto";
import { LoginUsecase } from "@/modules/auth/application/usecases/loginUsecase";
import type {
LogoutResponseDto,
LoginResponseDto,
} from "@/modules/auth/application/dtos/response.dto";
import { type LoginUsecase } from "@/modules/auth/application/usecases/loginUsecase";
import { type LogoutUsecase } from "@/modules/auth/application/usecases/logoutUsecase";
import { type AuthClientPort } from "@/modules/auth/ports/primary/authClientPort";
import { TYPES } from "@/di/types";

Expand All @@ -10,9 +14,16 @@ export class AuthClientAdapter implements AuthClientPort {
constructor(
@inject(TYPES.LoginUsecase)
private readonly loginUsecase: LoginUsecase,

@inject(TYPES.LogoutUsecase)
private readonly logoutUsecase: LogoutUsecase,
) {}

async login({ email, password }: LoginRequestDto): Promise<LoginResponseDto> {
return await this.loginUsecase.execute({ email, password });
}

async logout(): Promise<LogoutResponseDto> {
return await this.logoutUsecase.execute();
}
}
11 changes: 10 additions & 1 deletion src/modules/auth/adapters/secondary/authApiAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { TYPES } from "@/di/types";
import { type AuthApiPort } from "@/modules/auth/ports/secondary/authApiPort";
import { type RestApiPort } from "@/modules/restApi/ports/secondary/restApiPort";
import { type LoginRequestDto } from "@/modules/auth/application/dtos/request.dto";
import { type LoginResponseDto } from "@/modules/auth/application/dtos/response.dto";
import type {
LogoutResponseDto,
LoginResponseDto,
} from "@/modules/auth/application/dtos/response.dto";
import { AuthUrls } from "@/modules/auth/application/constants/authUrls";

@injectable()
Expand All @@ -19,4 +22,10 @@ export class AuthApiAdapter implements AuthApiPort {
payload: { email, password },
});
}

async logout(): Promise<LogoutResponseDto> {
return await this.apiClient.post({
url: AuthUrls.logout,
});
}
}
1 change: 1 addition & 0 deletions src/modules/auth/application/constants/authUrls.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const AuthUrls = {
login: "/api/v1/auth/login",
logout: "/api/v1/auth/logout",
} as const;
16 changes: 16 additions & 0 deletions src/modules/auth/application/usecases/logoutUsecase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { inject, injectable } from "tsyringe";
import { TYPES } from "@/di/types";
import { type AuthApiPort } from "@/modules/auth/ports/secondary/authApiPort";
import { type LogoutResponseDto } from "@/modules/auth/application/dtos/response.dto";

@injectable()
export class LogoutUsecase {
constructor(
@inject(TYPES.AuthApiPort)
private readonly authApi: AuthApiPort,
) {}

async execute(): Promise<LogoutResponseDto> {
return await this.authApi.logout();
}
}
6 changes: 5 additions & 1 deletion src/modules/auth/ports/primary/authClientPort.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { type LoginRequestDto } from "@/modules/auth/application/dtos/request.dto";
import { type LoginResponseDto } from "@/modules/auth/application/dtos/response.dto";
import type {
LogoutResponseDto,
LoginResponseDto,
} from "@/modules/auth/application/dtos/response.dto";

export interface AuthClientPort {
login: (props: LoginRequestDto) => Promise<LoginResponseDto>;
logout: () => Promise<LogoutResponseDto>;
}
6 changes: 5 additions & 1 deletion src/modules/auth/ports/secondary/authApiPort.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { type LoginRequestDto } from "@/modules/auth/application/dtos/request.dto";
import { type LoginResponseDto } from "@/modules/auth/application/dtos/response.dto";
import type {
LogoutResponseDto,
LoginResponseDto,
} from "@/modules/auth/application/dtos/response.dto";

export interface AuthApiPort {
login: ({ email, password }: LoginRequestDto) => Promise<LoginResponseDto>;
logout: () => Promise<LogoutResponseDto>;
}
10 changes: 5 additions & 5 deletions src/modules/restApi/ports/secondary/restApiPort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import type {
} from "@/modules/restApi/application/entities/restApiParams";

export interface RestApiPort {
get<X>(params: GetParams): Promise<X>;
get: <X>(params: GetParams) => Promise<X>;

post<X, Y>(params: PostParams<X>): Promise<Y>;
post: <X, Y>(params: PostParams<X>) => Promise<Y>;

patch<X, Y>(params: PatchParams<X>): Promise<Y>;
patch: <X, Y>(params: PatchParams<X>) => Promise<Y>;

delete<X>(params: DeleteParams): Promise<X>;
delete: <X>(params: DeleteParams) => Promise<X>;

unauthpost<X, Y>(params: UnauthPostParams<X>): Promise<Y>;
unauthpost: <X, Y>(params: UnauthPostParams<X>) => Promise<Y>;
}
3 changes: 0 additions & 3 deletions src/utils/routePaths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ const routePaths = {
signIn() {
return "/sign-in";
},
signOut() {
return "/sign-out";
},
signUp() {
return "/sign-up";
},
Expand Down
Loading