diff --git a/sigap-website/app/(pages)/(auth)/_components/sign-in-with-credential.tsx b/sigap-website/app/(pages)/(auth)/_components/sign-in-with-credential.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/sigap-website/app/(pages)/(auth)/_components/signin-form.tsx b/sigap-website/app/(pages)/(auth)/_components/signin-form.tsx
index 699755b..95b66d5 100644
--- a/sigap-website/app/(pages)/(auth)/_components/signin-form.tsx
+++ b/sigap-website/app/(pages)/(auth)/_components/signin-form.tsx
@@ -9,7 +9,7 @@ import Link from "next/link";
import { FormField } from "@/app/_components/form-field";
// import { useSignInController } from "@/src/interface-adapters/controllers/auth/sign-in.controller";
import { useState } from "react";
-import { signIn } from "../action";
+
import { useSignInHandler } from "../_handlers/use-sign-in";
export function SignInForm({
@@ -98,7 +98,7 @@ export function SignInForm({
{isPending ? (
<>
- Signing in...
+ Sign in
>
) : (
"Sign in"
diff --git a/sigap-website/app/(pages)/(auth)/_handlers/use-sign-in.ts b/sigap-website/app/(pages)/(auth)/_handlers/use-sign-in.ts
index b35b081..e55e021 100644
--- a/sigap-website/app/(pages)/(auth)/_handlers/use-sign-in.ts
+++ b/sigap-website/app/(pages)/(auth)/_handlers/use-sign-in.ts
@@ -1,5 +1,5 @@
import { useNavigations } from "@/app/_hooks/use-navigations";
-import { useSignInMutation } from "../_queries/mutations";
+import { useSignInPasswordlessMutation } from "../_queries/mutations";
import { toast } from "sonner";
import { useState } from "react";
import { useForm } from "react-hook-form";
@@ -7,7 +7,7 @@ import { ISignInPasswordlessSchema, SignInPasswordlessSchema } from "@/src/entit
import { zodResolver } from "@hookform/resolvers/zod";
export function useSignInHandler() {
- const { mutateAsync: signIn, isPending, error: errors } = useSignInMutation();
+ const { mutateAsync: signIn, isPending, error: errors } = useSignInPasswordlessMutation();
const { router } = useNavigations();
const [error, setError] = useState();
diff --git a/sigap-website/app/(pages)/(auth)/_queries/mutations.ts b/sigap-website/app/(pages)/(auth)/_queries/mutations.ts
index 9d4ee98..7eabde1 100644
--- a/sigap-website/app/(pages)/(auth)/_queries/mutations.ts
+++ b/sigap-website/app/(pages)/(auth)/_queries/mutations.ts
@@ -1,10 +1,17 @@
import { useMutation } from "@tanstack/react-query"
-import { sendMagicLink, sendPasswordRecovery, signIn, signOut, verifyOtp } from "../action"
+import { sendMagicLink, sendPasswordRecovery, signInPasswordless, signInWithPassword, signOut, verifyOtp } from "../action"
-export const useSignInMutation = () => {
+export const useSignInPasswordlessMutation = () => {
return useMutation({
mutationKey: ["signIn"],
- mutationFn: async (formData: FormData) => await signIn(formData),
+ mutationFn: async (formData: FormData) => await signInPasswordless(formData),
+ })
+}
+
+export const useSignInWithPasswordMutation = () => {
+ return useMutation({
+ mutationKey: ["signInWithCredentials"],
+ mutationFn: async (formData: FormData) => await signInWithPassword(formData),
})
}
diff --git a/sigap-website/app/(pages)/(auth)/action.ts b/sigap-website/app/(pages)/(auth)/action.ts
index 00dfc79..7077085 100644
--- a/sigap-website/app/(pages)/(auth)/action.ts
+++ b/sigap-website/app/(pages)/(auth)/action.ts
@@ -8,17 +8,18 @@ import { InputParseError, NotFoundError } from "@/src/entities/errors/common"
import { AuthenticationError, UnauthenticatedError } from "@/src/entities/errors/auth"
import { createClient } from "@/app/_utils/supabase/server"
-export async function signIn(formData: FormData) {
+export async function signInPasswordless(formData: FormData) {
const instrumentationService = getInjection("IInstrumentationService")
return await instrumentationService.instrumentServerAction("signIn", {
recordResponse: true
},
async () => {
- const email = formData.get("email")?.toString()
try {
- const signInController = getInjection("ISignInController")
- return await signInController({ email })
+ const email = formData.get("email")?.toString()
+
+ const signInPasswordlessController = getInjection("ISignInPasswordlessController")
+ return await signInPasswordlessController({ email })
// if (email) {
// redirect(`/verify-otp?email=${encodeURIComponent(email)}`)
@@ -51,6 +52,43 @@ export async function signIn(formData: FormData) {
})
}
+
+export async function signInWithPassword(formData: FormData) {
+ const instrumentationService = getInjection("IInstrumentationService")
+ return await instrumentationService.instrumentServerAction("signInWithPassword", {
+ recordResponse: true
+ }, async () => {
+ try {
+ const email = formData.get("email")?.toString()
+ const password = formData.get("password")?.toString()
+
+ const signInWithPasswordController = getInjection("ISignInWithPasswordController")
+ return await signInWithPasswordController({ email, password })
+ } catch (err) {
+ if (err instanceof InputParseError) {
+ return { error: err.message }
+ }
+
+ if (err instanceof AuthenticationError) {
+ return { error: "Invalid credential. Please try again." }
+ }
+
+ if (err instanceof UnauthenticatedError || err instanceof NotFoundError) {
+ return {
+ error: 'User not found. Please tell your admin to create an account for you.',
+ };
+ }
+
+ const crashReporterService = getInjection('ICrashReporterService');
+ crashReporterService.report(err);
+
+ return {
+ error:
+ 'An error happened. The developers have been notified. Please try again later.',
+ };
+ }
+ })
+}
// export async function signUp(formData: FormData) {
// const instrumentationService = getInjection("IInstrumentationService")
// return await instrumentationService.instrumentServerAction("signUp", { recordResponse: true }, async () => {
diff --git a/sigap-website/app/(pages)/(auth)/handler.tsx b/sigap-website/app/(pages)/(auth)/handler.tsx
new file mode 100644
index 0000000..7817f5a
--- /dev/null
+++ b/sigap-website/app/(pages)/(auth)/handler.tsx
@@ -0,0 +1,161 @@
+// import { AuthenticationError } from "@/src/entities/errors/auth";
+// import { useState } from "react";
+// import { useAuthActions } from './queries';
+// import { useForm } from 'react-hook-form';
+// import { zodResolver } from '@hookform/resolvers/zod';;
+// import { toast } from 'sonner';
+// import { useNavigations } from '@/app/_hooks/use-navigations';
+// import {
+// IVerifyOtpSchema,
+// verifyOtpSchema,
+// } from '@/src/entities/models/auth/verify-otp.model';
+
+// /**
+// * Hook untuk menangani proses sign in
+// *
+// * @returns {Object} Object berisi handler dan state untuk form sign in
+// * @example
+// * const { handleSubmit, isPending, error } = useSignInHandler();
+// *
+// */
+// export function useSignInHandler() {
+// const { signIn } = useAuthActions();
+// const { router } = useNavigations();
+
+// const [error, setError] = useState();
+
+// const handleSubmit = async (event: React.FormEvent) => {
+// event.preventDefault();
+// if (signIn.isPending) return;
+
+// setError(undefined);
+
+// const formData = new FormData(event.currentTarget);
+// const email = formData.get('email')?.toString();
+
+// const res = await signIn.mutateAsync(formData);
+
+// if (!res?.error) {
+// toast('An email has been sent to you. Please check your inbox.');
+// if (email) router.push(`/verify-otp?email=${encodeURIComponent(email)}`);
+// } else {
+// setError(res.error);
+// }
+
+
+// };
+
+// return {
+// // formData,
+// // handleChange,
+// handleSignIn: handleSubmit,
+// error,
+// isPending: signIn.isPending,
+// errors: !!error || signIn.error,
+// clearError: () => setError(undefined),
+// };
+// }
+
+// export function useVerifyOtpHandler(email: string) {
+// const { router } = useNavigations();
+// const { verifyOtp } = useAuthActions();
+// const [error, setError] = useState();
+
+// const {
+// register,
+// handleSubmit: hookFormSubmit,
+// control,
+// formState: { errors },
+// setValue,
+// } = useForm({
+// resolver: zodResolver(verifyOtpSchema),
+// defaultValues: {
+// email,
+// token: '',
+// },
+// });
+
+// const handleOtpChange = (
+// value: string,
+// onChange: (value: string) => void
+// ) => {
+// onChange(value);
+
+// if (value.length === 6) {
+// handleSubmit();
+// }
+
+// // Clear error when user starts typing
+// if (error) {
+// setError(undefined);
+// }
+// };
+
+// const handleSubmit = hookFormSubmit(async (data) => {
+// if (verifyOtp.isPending) return;
+
+// setError(undefined);
+
+// // Create FormData object
+// const formData = new FormData();
+// formData.append('email', data.email);
+// formData.append('token', data.token);
+
+// await verifyOtp.mutateAsync(formData, {
+// onSuccess: () => {
+// toast.success('OTP verified successfully');
+// // Navigate to dashboard on success
+// router.push('/dashboard');
+// },
+// onError: (error) => {
+// setError(error.message);
+// },
+// });
+// });
+
+// return {
+// register,
+// control,
+// handleVerifyOtp: handleSubmit,
+// handleOtpChange,
+// errors: {
+// ...errors,
+// token: error ? { message: error } : errors.token,
+// },
+// isPending: verifyOtp.isPending,
+// clearError: () => setError(undefined),
+// };
+// }
+
+// export function useSignOutHandler() {
+// const { signOut } = useAuthActions();
+// const { router } = useNavigations();
+// const [error, setError] = useState();
+
+// const handleSignOut = async () => {
+// if (signOut.isPending) return;
+
+// setError(undefined);
+
+// await signOut.mutateAsync(undefined, {
+// onSuccess: () => {
+// toast.success('You have been signed out successfully');
+// router.push('/sign-in');
+// },
+// onError: (error) => {
+// if (error instanceof AuthenticationError) {
+// setError(error.message);
+// toast.error(error.message);
+// }
+// },
+// });
+// };
+
+// return {
+// handleSignOut,
+// error,
+// isPending: signOut.isPending,
+// errors: !!error || signOut.error,
+// clearError: () => setError(undefined),
+// };
+// }
diff --git a/sigap-website/app/(pages)/(auth)/sign-in/_components/carousal-quote.tsx b/sigap-website/app/(pages)/(auth)/sign-in/_components/carousal-quote.tsx
new file mode 100644
index 0000000..c943ca2
--- /dev/null
+++ b/sigap-website/app/(pages)/(auth)/sign-in/_components/carousal-quote.tsx
@@ -0,0 +1,50 @@
+import { Carousel, CarouselContent, CarouselItem } from "@/app/_components/ui/carousal"
+import { QuoteIcon } from "lucide-react"
+
+export const CarousalQuotes = () => {
+
+ const items = [
+ {
+ quote: "Tried @supabase for the first time yesterday. Amazing tool! I was able to get my Posgres DB up in no time and their documentation on operating on the DB is super easy! 👏 Can't wait for Cloud functions to arrive! It's gonna be a great Firebase alternative!",
+ author: "@codewithbhargav",
+ image: "https://github.com/shadcn.png",
+ },
+ {
+ quote: "Check out this amazing product @supabase. A must give try #newidea #opportunity",
+ author: "@techenthusiast",
+ image: "https://github.com/shadcn.png",
+ },
+ {
+ quote: "Check out this amazing product @supabase. A must give try #newidea #opportunity",
+ author: "@dataguru",
+ image: "https://github.com/shadcn.png",
+ },
+ ];
+
+ return (
+ <>
+
+
+ {items.map((item, index) => (
+
+
+ {/*
*/}
+
{item.quote}
+
+

+
+
+
+
+ ))}
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/sigap-website/app/(pages)/(auth)/sign-in/page.tsx b/sigap-website/app/(pages)/(auth)/sign-in/page.tsx
index 1f56e08..90a04e6 100644
--- a/sigap-website/app/(pages)/(auth)/sign-in/page.tsx
+++ b/sigap-website/app/(pages)/(auth)/sign-in/page.tsx
@@ -2,25 +2,9 @@ import { SignInForm } from "@/app/(pages)/(auth)/_components/signin-form";
import { Message } from "@/app/_components/form-message";
import { Button } from "@/app/_components/ui/button";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/app/_components/ui/carousal";
+import { IconQuoteFilled } from "@tabler/icons-react";
import { GalleryVerticalEnd, Globe, QuoteIcon } from "lucide-react";
-
-const carouselContent = [
- {
- quote: "Tried @supabase for the first time yesterday. Amazing tool! I was able to get my Posgres DB up in no time and their documentation on operating on the DB is super easy! 👏 Can't wait for Cloud functions to arrive! It's gonna be a great Firebase alternative!",
- author: "@codewithbhargav",
- image: "https://github.com/shadcn.png",
- },
- {
- quote: "Check out this amazing product @supabase. A must give try #newidea #opportunity",
- author: "@techenthusiast",
- image: "https://github.com/shadcn.png",
- },
- {
- quote: "Check out this amazing product @supabase. A must give try #newidea #opportunity",
- author: "@dataguru",
- image: "https://github.com/shadcn.png",
- },
-];
+import { CarousalQuotes } from "./_components/carousal-quote";
export default async function Login(props: { searchParams: Promise }) {
return (
@@ -49,28 +33,7 @@ export default async function Login(props: { searchParams: Promise }) {
Showcase
-
-
- {carouselContent.map((item, index) => (
-
-
-
-
{item.quote}
-
-

-
-
-
-
- ))}
-
-
+
);
diff --git a/sigap-website/di/modules/authentication.module.ts b/sigap-website/di/modules/authentication.module.ts
index 8176ded..52a2d79 100644
--- a/sigap-website/di/modules/authentication.module.ts
+++ b/sigap-website/di/modules/authentication.module.ts
@@ -2,12 +2,12 @@ import { createModule } from '@evyweb/ioctopus';
import { AuthenticationService } from '@/src/infrastructure/services/authentication.service';
-import { signInUseCase } from '@/src/application/use-cases/auth/sign-in.use-case';
+import { signInUseCase } from '@/src/application/use-cases/auth/sign-in-passwordless.use-case';
import { signUpUseCase } from '@/src/application/use-cases/auth/sign-up.use-case';
import { signOutUseCase } from '@/src/application/use-cases/auth/sign-out.use-case';
import { DI_SYMBOLS } from '@/di/types';
-import { signInController } from '@/src/interface-adapters/controllers/auth/sign-in.controller';
+import { signInPasswordlessController } from '@/src/interface-adapters/controllers/auth/sign-in-passwordless.controller';
import { signOutController } from '@/src/interface-adapters/controllers/auth/sign-out.controller';
import { verifyOtpUseCase } from '@/src/application/use-cases/auth/verify-otp.use-case';
import { verifyOtpController } from '@/src/interface-adapters/controllers/auth/verify-otp.controller';
@@ -15,6 +15,8 @@ import { sendMagicLinkUseCase } from '@/src/application/use-cases/auth/send-magi
import { sendPasswordRecoveryUseCase } from '@/src/application/use-cases/auth/send-password-recovery.use-case';
import { sendMagicLinkController } from '@/src/interface-adapters/controllers/auth/send-magic-link.controller';
import { sendPasswordRecoveryController } from '@/src/interface-adapters/controllers/auth/send-password-recovery.controller';
+import { signInWithPasswordUseCase } from '@/src/application/use-cases/auth/sign-in-with-password.use-case';
+import { signInWithPasswordController } from '@/src/interface-adapters/controllers/auth/sign-in-with-password.controller';
export function createAuthenticationModule() {
const authenticationModule = createModule();
@@ -40,13 +42,21 @@ export function createAuthenticationModule() {
// Use Cases
authenticationModule
- .bind(DI_SYMBOLS.ISignInUseCase)
+ .bind(DI_SYMBOLS.ISignInPasswordlessUseCase)
.toHigherOrderFunction(signInUseCase, [
DI_SYMBOLS.IInstrumentationService,
DI_SYMBOLS.IAuthenticationService,
DI_SYMBOLS.IUsersRepository,
]);
+ authenticationModule
+ .bind(DI_SYMBOLS.ISignInWithPasswordUseCase)
+ .toHigherOrderFunction(signInWithPasswordUseCase, [
+ DI_SYMBOLS.IInstrumentationService,
+ DI_SYMBOLS.IAuthenticationService,
+ DI_SYMBOLS.IUsersRepository,
+ ]);
+
authenticationModule
.bind(DI_SYMBOLS.ISignUpUseCase)
.toHigherOrderFunction(signUpUseCase, [
@@ -89,10 +99,17 @@ export function createAuthenticationModule() {
// Controllers
authenticationModule
- .bind(DI_SYMBOLS.ISignInController)
- .toHigherOrderFunction(signInController, [
+ .bind(DI_SYMBOLS.ISignInPasswordlessController)
+ .toHigherOrderFunction(signInPasswordlessController, [
DI_SYMBOLS.IInstrumentationService,
- DI_SYMBOLS.ISignInUseCase,
+ DI_SYMBOLS.ISignInPasswordlessUseCase,
+ ]);
+
+ authenticationModule
+ .bind(DI_SYMBOLS.ISignInWithPasswordController)
+ .toHigherOrderFunction(signInWithPasswordController, [
+ DI_SYMBOLS.IInstrumentationService,
+ DI_SYMBOLS.ISignInWithPasswordUseCase,
]);
authenticationModule
diff --git a/sigap-website/di/types.ts b/sigap-website/di/types.ts
index 7e53b5d..2ed6fdc 100644
--- a/sigap-website/di/types.ts
+++ b/sigap-website/di/types.ts
@@ -3,12 +3,12 @@ import { ITransactionManagerService } from '@/src/application/services/transacti
import { IInstrumentationService } from '@/src/application/services/instrumentation.service.interface';
import { ICrashReporterService } from '@/src/application/services/crash-reporter.service.interface';
-import { ISignInUseCase } from '@/src/application/use-cases/auth/sign-in.use-case';
+import { ISignInPasswordlessUseCase } from '@/src/application/use-cases/auth/sign-in-passwordless.use-case';
import { ISignUpUseCase } from '@/src/application/use-cases/auth/sign-up.use-case';
import { ISignOutUseCase } from '@/src/application/use-cases/auth/sign-out.use-case';
import { IUsersRepository } from '@/src/application/repositories/users.repository.interface';
import { IVerifyOtpUseCase } from '@/src/application/use-cases/auth/verify-otp.use-case';
-import { ISignInController } from '@/src/interface-adapters/controllers/auth/sign-in.controller';
+import { ISignInPasswordlessController } from '@/src/interface-adapters/controllers/auth/sign-in-passwordless.controller';
import { ISignOutController } from '@/src/interface-adapters/controllers/auth/sign-out.controller';
import { IVerifyOtpController } from '@/src/interface-adapters/controllers/auth/verify-otp.controller';
import { IBanUserUseCase } from '@/src/application/use-cases/users/ban-user.use-case';
@@ -39,6 +39,7 @@ import { ISendMagicLinkController } from '@/src/interface-adapters/controllers/a
import { ISendPasswordRecoveryController } from '@/src/interface-adapters/controllers/auth/send-password-recovery.controller';
import { IUploadAvatarController } from '@/src/interface-adapters/controllers/users/upload-avatar.controller';
import { IUploadAvatarUseCase } from '@/src/application/use-cases/users/upload-avatar.use-case';
+import { ISignInWithPasswordController } from '@/src/interface-adapters/controllers/auth/sign-in-with-password.controller';
export const DI_SYMBOLS = {
// Services
@@ -51,7 +52,8 @@ export const DI_SYMBOLS = {
IUsersRepository: Symbol.for('IUsersRepository'),
// Use Cases
- ISignInUseCase: Symbol.for('ISignInUseCase'),
+ ISignInPasswordlessUseCase: Symbol.for('ISignInPasswordlessUseCase'),
+ ISignInWithPasswordUseCase: Symbol.for('ISignInWithPasswordUseCase'),
ISignUpUseCase: Symbol.for('ISignUpUseCase'),
IVerifyOtpUseCase: Symbol.for('IVerifyOtpUseCase'),
ISignOutUseCase: Symbol.for('ISignOutUseCase'),
@@ -72,7 +74,8 @@ export const DI_SYMBOLS = {
IUploadAvatarUseCase: Symbol.for('IUploadAvatarUseCase'),
// Controllers
- ISignInController: Symbol.for('ISignInController'),
+ ISignInPasswordlessController: Symbol.for('ISignInPasswordlessController'),
+ ISignInWithPasswordController: Symbol.for('ISignInWithPasswordController'),
ISignOutController: Symbol.for('ISignOutController'),
IVerifyOtpController: Symbol.for('IVerifyOtpController'),
ISendMagicLinkController: Symbol.for('ISendMagicLinkController'),
@@ -103,7 +106,7 @@ export interface DI_RETURN_TYPES {
IUsersRepository: IUsersRepository;
// Use Cases
- ISignInUseCase: ISignInUseCase;
+ ISignInPasswordlessUseCase: ISignInPasswordlessUseCase;
ISignUpUseCase: ISignUpUseCase;
IVerifyOtpUseCase: IVerifyOtpUseCase;
ISignOutUseCase: ISignOutUseCase;
@@ -124,7 +127,8 @@ export interface DI_RETURN_TYPES {
IUploadAvatarUseCase: IUploadAvatarUseCase;
// Controllers
- ISignInController: ISignInController;
+ ISignInPasswordlessController: ISignInPasswordlessController;
+ ISignInWithPasswordController: ISignInWithPasswordController;
IVerifyOtpController: IVerifyOtpController;
ISignOutController: ISignOutController;
ISendMagicLinkController: ISendMagicLinkController;
diff --git a/sigap-website/src/application/services/authentication.service.interface.ts b/sigap-website/src/application/services/authentication.service.interface.ts
index 7c2d160..41512d1 100644
--- a/sigap-website/src/application/services/authentication.service.interface.ts
+++ b/sigap-website/src/application/services/authentication.service.interface.ts
@@ -9,9 +9,9 @@ import { IUserSchema } from "@/src/entities/models/users/users.model"
export interface IAuthenticationService {
signInPasswordless(credentials: ISignInPasswordlessSchema): Promise
- SignInWithPasswordSchema(credentials: ISignInWithPasswordSchema): Promise
- SignUpWithEmailSchema(credentials: ISignUpWithEmailSchema): Promise
- SignUpWithPhoneSchema(credentials: ISignUpWithPhoneSchema): Promise
+ signInWithPassword(credentials: ISignInWithPasswordSchema): Promise
+ SignUpWithEmail(credentials: ISignUpWithEmailSchema): Promise
+ SignUpWithPhone(credentials: ISignUpWithPhoneSchema): Promise
getSession(): Promise
signOut(): Promise
sendMagicLink(credentials: ISendMagicLinkSchema): Promise
diff --git a/sigap-website/src/application/use-cases/auth/sign-in.use-case.ts b/sigap-website/src/application/use-cases/auth/sign-in-passwordless.use-case.ts
similarity index 95%
rename from sigap-website/src/application/use-cases/auth/sign-in.use-case.ts
rename to sigap-website/src/application/use-cases/auth/sign-in-passwordless.use-case.ts
index d6a7d64..6fe22da 100644
--- a/sigap-website/src/application/use-cases/auth/sign-in.use-case.ts
+++ b/sigap-website/src/application/use-cases/auth/sign-in-passwordless.use-case.ts
@@ -4,7 +4,7 @@ import { type TSignInSchema, ISignInPasswordlessSchema, SignInSchema } from "@/s
import { IAuthenticationService } from "@/src/application/services/authentication.service.interface";
import { IUsersRepository } from "../../repositories/users.repository.interface";
-export type ISignInUseCase = ReturnType
+export type ISignInPasswordlessUseCase = ReturnType
export const signInUseCase =
(
diff --git a/sigap-website/src/application/use-cases/auth/sign-in-with-password.use-case.ts b/sigap-website/src/application/use-cases/auth/sign-in-with-password.use-case.ts
new file mode 100644
index 0000000..7a19537
--- /dev/null
+++ b/sigap-website/src/application/use-cases/auth/sign-in-with-password.use-case.ts
@@ -0,0 +1,27 @@
+import { UnauthenticatedError } from "@/src/entities/errors/auth";
+import { IUsersRepository } from "../../repositories/users.repository.interface";
+import { IAuthenticationService } from "../../services/authentication.service.interface";
+import { IInstrumentationService } from "../../services/instrumentation.service.interface";
+
+export type ISignInWithPasswordUseCase = ReturnType
+
+export const signInWithPasswordUseCase = (
+ instrumentationService: IInstrumentationService,
+ authenticationService: IAuthenticationService,
+ usersRepository: IUsersRepository
+) => async (input: { email: string; password: string }): Promise => {
+ return await instrumentationService.startSpan({ name: "signInWithPassword Use Case", op: "function" },
+ async () => {
+
+ const existingUser = await usersRepository.getUserByEmail({ email: input.email })
+
+ if (!existingUser) {
+ throw new UnauthenticatedError("User not found. Please tell your admin to create an account for you.")
+ }
+
+ await authenticationService.signInWithPassword({ email: input.email, password: input.password })
+
+ return
+ }
+ )
+}
\ No newline at end of file
diff --git a/sigap-website/src/entities/models/auth/sign-in.model.ts b/sigap-website/src/entities/models/auth/sign-in.model.ts
index 55e9e27..da7be1d 100644
--- a/sigap-website/src/entities/models/auth/sign-in.model.ts
+++ b/sigap-website/src/entities/models/auth/sign-in.model.ts
@@ -16,7 +16,6 @@ export type TSignInSchema = z.infer;
export const SignInWithPasswordSchema = SignInSchema.pick({
email: true,
password: true,
- phone: true
})
@@ -26,7 +25,6 @@ export type ISignInWithPasswordSchema = z.infer
export const defaulISignInWithPasswordSchemaValues: ISignInWithPasswordSchema = {
email: "",
password: "",
- phone: ""
};
export const SignInPasswordlessSchema = SignInSchema.pick({
@@ -40,9 +38,13 @@ export const defaulISignInPasswordlessSchemaValues: ISignInPasswordlessSchema =
email: "",
}
+
+
// Define the sign-in response schema using Zod
export const SignInResponseSchema = z.object({
success: z.boolean(),
message: z.string(),
redirectTo: z.string().optional(),
});
+
+
diff --git a/sigap-website/src/infrastructure/services/authentication.service.ts b/sigap-website/src/infrastructure/services/authentication.service.ts
index fb4f9ac..72a3a86 100644
--- a/sigap-website/src/infrastructure/services/authentication.service.ts
+++ b/sigap-website/src/infrastructure/services/authentication.service.ts
@@ -51,7 +51,7 @@ export class AuthenticationService implements IAuthenticationService {
})
}
- async SignInWithPasswordSchema(credentials: ISignInWithPasswordSchema): Promise {
+ async signInWithPassword(credentials: ISignInWithPasswordSchema): Promise {
return await this.instrumentationService.startSpan({
name: "SignInWithPasswordSchema Use Case",
}, async () => {
@@ -79,7 +79,7 @@ export class AuthenticationService implements IAuthenticationService {
})
}
- async SignUpWithEmailSchema(credentials: ISignUpWithEmailSchema): Promise {
+ async SignUpWithEmail(credentials: ISignUpWithEmailSchema): Promise {
return await this.instrumentationService.startSpan({
name: "SignUpWithEmailSchema Use Case",
}, async () => {
@@ -124,7 +124,7 @@ export class AuthenticationService implements IAuthenticationService {
})
}
- async SignUpWithPhoneSchema(credentials: ISignUpWithPhoneSchema): Promise {
+ async SignUpWithPhone(credentials: ISignUpWithPhoneSchema): Promise {
throw new Error("Method not implemented.");
}
diff --git a/sigap-website/src/interface-adapters/controllers/auth/sign-in.controller.ts b/sigap-website/src/interface-adapters/controllers/auth/sign-in-passwordless.controller.ts
similarity index 74%
rename from sigap-website/src/interface-adapters/controllers/auth/sign-in.controller.ts
rename to sigap-website/src/interface-adapters/controllers/auth/sign-in-passwordless.controller.ts
index 1463d61..80131fd 100644
--- a/sigap-website/src/interface-adapters/controllers/auth/sign-in.controller.ts
+++ b/sigap-website/src/interface-adapters/controllers/auth/sign-in-passwordless.controller.ts
@@ -1,5 +1,5 @@
import { z } from "zod";
-import { ISignInUseCase } from "@/src/application/use-cases/auth/sign-in.use-case";
+import { ISignInPasswordlessUseCase } from "@/src/application/use-cases/auth/sign-in-passwordless.use-case";
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
import { InputParseError } from "@/src/entities/errors/common";
@@ -8,12 +8,12 @@ const signInInputSchema = z.object({
email: z.string().min(1, "Email is Required").email("Please enter a valid email address"),
})
-export type ISignInController = ReturnType
+export type ISignInPasswordlessController = ReturnType
-export const signInController =
+export const signInPasswordlessController =
(
instrumentationService: IInstrumentationService,
- signInUseCase: ISignInUseCase
+ signInUseCase: ISignInPasswordlessUseCase
) =>
async (input: Partial>) => {
return await instrumentationService.startSpan({ name: "signIn Controller" }, async () => {
diff --git a/sigap-website/src/interface-adapters/controllers/auth/sign-in-with-password.controller.ts b/sigap-website/src/interface-adapters/controllers/auth/sign-in-with-password.controller.ts
new file mode 100644
index 0000000..33a6417
--- /dev/null
+++ b/sigap-website/src/interface-adapters/controllers/auth/sign-in-with-password.controller.ts
@@ -0,0 +1,34 @@
+import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
+import { ISignInWithPasswordUseCase } from "@/src/application/use-cases/auth/sign-in-with-password.use-case";
+import { InputParseError } from "@/src/entities/errors/common";
+
+import { z } from "zod";
+
+// Sign In Controller
+const signInWithPasswordInputSchema = z.object({
+ email: z.string().min(1, "Email is Required").email("Please enter a valid email address"),
+ password: z.string().min(1, "Password is Required")
+})
+
+export type ISignInWithPasswordController = ReturnType
+
+export const signInWithPasswordController = (
+ instrumentationService: IInstrumentationService,
+ signInWithPasswordUseCase: ISignInWithPasswordUseCase
+) =>
+ async (input: Partial>) => {
+ return await instrumentationService.startSpan({ name: "signInWithPassword Controller" },
+ async () => {
+ const { data, error: inputParseError } = signInWithPasswordInputSchema.safeParse(input)
+
+ if (inputParseError) {
+ throw new InputParseError(inputParseError.errors[0].message)
+ }
+
+ return await signInWithPasswordUseCase({
+ email: data.email,
+ password: data.password
+ })
+ }
+ )
+ }
\ No newline at end of file