skip auth

This commit is contained in:
Rama Priyanto 2025-07-22 10:29:28 +07:00
parent 504101b91c
commit 5807e389b4
2 changed files with 220 additions and 206 deletions

View File

@ -13,7 +13,8 @@ type AuthStep = "login" | "email-setup" | "otp";
const AuthPage = ({ params: { locale } }: { params: { locale: string } }) => {
const [currentStep, setCurrentStep] = useState<AuthStep>("login");
const [loginCredentials, setLoginCredentials] = useState<LoginFormData | null>(null);
const [loginCredentials, setLoginCredentials] =
useState<LoginFormData | null>(null);
const { validateEmail } = useEmailValidation();
const { login } = useAuth();
@ -23,6 +24,9 @@ const AuthPage = ({ params: { locale } }: { params: { locale: string } }) => {
try {
const result = await validateEmail(data);
switch (result) {
case "skip":
handleOTPSuccess();
break;
case "setup":
setCurrentStep("email-setup");
break;
@ -112,11 +116,7 @@ const AuthPage = ({ params: { locale } }: { params: { locale: string } }) => {
}
};
return (
<AuthLayout>
{renderCurrentStep()}
</AuthLayout>
);
return <AuthLayout>{renderCurrentStep()}</AuthLayout>;
};
export default AuthPage;

View File

@ -9,7 +9,7 @@ import {
AuthState,
AuthContextType,
EmailValidationData,
OTPData
OTPData,
} from "@/types/auth";
import {
login,
@ -17,7 +17,7 @@ import {
postEmailValidation,
postSetupEmail,
verifyOTPByUsername,
doLogin
doLogin,
} from "@/service/auth";
import {
setAuthCookies,
@ -29,7 +29,7 @@ import {
showAuthError,
showAuthSuccess,
loginRateLimiter,
AUTH_CONSTANTS
AUTH_CONSTANTS,
} from "@/lib/auth-utils";
import { warning } from "@/lib/swal";
@ -46,108 +46,114 @@ export const useAuth = (): AuthContextType => {
useEffect(() => {
const checkAuth = async () => {
try {
setState(prev => ({ ...prev, loading: true }));
setState((prev) => ({ ...prev, loading: true }));
// Add logic to check if user is authenticated
// This could check for valid tokens, etc.
} catch (error) {
setState(prev => ({
setState((prev) => ({
...prev,
isAuthenticated: false,
user: null,
error: "Authentication check failed"
error: "Authentication check failed",
}));
} finally {
setState(prev => ({ ...prev, loading: false }));
setState((prev) => ({ ...prev, loading: false }));
}
};
checkAuth();
}, []);
const login = useCallback(async (credentials: LoginFormData): Promise<void> => {
try {
setState(prev => ({ ...prev, loading: true, error: null }));
const login = useCallback(
async (credentials: LoginFormData): Promise<void> => {
try {
setState((prev) => ({ ...prev, loading: true, error: null }));
// Check rate limiting
if (!loginRateLimiter.canAttempt(credentials.username)) {
const remainingTime = loginRateLimiter.getRemainingTime(credentials.username);
const minutes = Math.ceil(remainingTime / (60 * 1000));
throw new Error(`Too many login attempts. Please try again in ${minutes} minutes.`);
// Check rate limiting
if (!loginRateLimiter.canAttempt(credentials.username)) {
const remainingTime = loginRateLimiter.getRemainingTime(
credentials.username
);
const minutes = Math.ceil(remainingTime / (60 * 1000));
throw new Error(
`Too many login attempts. Please try again in ${minutes} minutes.`
);
}
// Attempt login
const response = await doLogin({
...credentials,
grantType: AUTH_CONSTANTS.GRANT_TYPE,
clientId: AUTH_CONSTANTS.CLIENT_ID,
});
if (response?.error) {
loginRateLimiter.recordAttempt(credentials.username);
throw new Error("Invalid username or password");
}
const { access_token, refresh_token } = response?.data || {};
if (!access_token || !refresh_token) {
throw new Error("Invalid response from server");
}
// Set auth cookies
setAuthCookies(access_token, refresh_token);
// Get user profile
const profileResponse = await getProfile(access_token);
const profile: ProfileData = profileResponse?.data?.data;
if (!profile) {
throw new Error("Failed to fetch user profile");
}
// Validate user eligibility
// if (!isUserEligible(profile)) {
// clearAllCookies();
// warning(
// "Akun Anda tidak dapat digunakan untuk masuk ke MediaHub Polri",
// "/auth"
// );
// return;
// }
// Set profile cookies
setProfileCookies(profile);
// Reset rate limiter on successful login
loginRateLimiter.resetAttempts(credentials.username);
// Navigate based on user role
const navigationPath = getNavigationPath(
profile.roleId,
profile.userLevel?.id,
profile.userLevel?.parentLevelId
);
// Update state
setState({
isAuthenticated: true,
user: profile,
loading: false,
error: null,
});
// Navigate to appropriate dashboard
window.location.href = navigationPath;
} catch (error: any) {
const errorMessage = error?.message || "Login failed";
setState((prev) => ({
...prev,
loading: false,
error: errorMessage,
}));
showAuthError(error, "Login failed");
}
// Attempt login
const response = await doLogin({
...credentials,
grantType: AUTH_CONSTANTS.GRANT_TYPE,
clientId: AUTH_CONSTANTS.CLIENT_ID,
});
if (response?.error) {
loginRateLimiter.recordAttempt(credentials.username);
throw new Error("Invalid username or password");
}
const { access_token, refresh_token } = response?.data || {};
if (!access_token || !refresh_token) {
throw new Error("Invalid response from server");
}
// Set auth cookies
setAuthCookies(access_token, refresh_token);
// Get user profile
const profileResponse = await getProfile(access_token);
const profile: ProfileData = profileResponse?.data?.data;
if (!profile) {
throw new Error("Failed to fetch user profile");
}
// Validate user eligibility
// if (!isUserEligible(profile)) {
// clearAllCookies();
// warning(
// "Akun Anda tidak dapat digunakan untuk masuk ke MediaHub Polri",
// "/auth"
// );
// return;
// }
// Set profile cookies
setProfileCookies(profile);
// Reset rate limiter on successful login
loginRateLimiter.resetAttempts(credentials.username);
// Navigate based on user role
const navigationPath = getNavigationPath(
profile.roleId,
profile.userLevel?.id,
profile.userLevel?.parentLevelId
);
// Update state
setState({
isAuthenticated: true,
user: profile,
loading: false,
error: null,
});
// Navigate to appropriate dashboard
window.location.href = navigationPath;
} catch (error: any) {
const errorMessage = error?.message || "Login failed";
setState(prev => ({
...prev,
loading: false,
error: errorMessage
}));
showAuthError(error, "Login failed");
}
}, [router]);
},
[router]
);
const logout = useCallback((): void => {
clearAllCookies();
@ -162,13 +168,13 @@ export const useAuth = (): AuthContextType => {
const refreshToken = useCallback(async (): Promise<void> => {
try {
setState(prev => ({ ...prev, loading: true }));
setState((prev) => ({ ...prev, loading: true }));
// Add token refresh logic here
// This would typically call an API to refresh the access token
} catch (error) {
logout();
} finally {
setState(prev => ({ ...prev, loading: false }));
setState((prev) => ({ ...prev, loading: false }));
}
}, [logout]);
@ -185,38 +191,43 @@ export const useEmailValidation = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const validateEmail = useCallback(async (credentials: LoginFormData): Promise<string> => {
try {
setLoading(true);
setError(null);
const validateEmail = useCallback(
async (credentials: LoginFormData): Promise<string> => {
try {
setLoading(true);
setError(null);
const response = await postEmailValidation(credentials);
const response = await postEmailValidation(credentials);
if (response?.error) {
throw new Error(response?.message || "Email validation failed");
if (response?.error) {
throw new Error(response?.message || "Email validation failed");
}
const message = response?.data?.message;
switch (message) {
case "Continue to setup email":
return "setup";
case "Email is valid and OTP has been sent":
return "otp";
case "Username & password valid":
return "success";
case "Skip to login":
return "skip";
default:
return "login";
}
} catch (error: any) {
const errorMessage = error?.message || "Email validation failed";
setError(errorMessage);
showAuthError(error, "Email validation failed");
throw error;
} finally {
setLoading(false);
}
const message = response?.data?.message;
switch (message) {
case "Continue to setup email":
return "setup";
case "Email is valid and OTP has been sent":
return "otp";
case "Username & password valid":
return "success";
default:
return "login";
}
} catch (error: any) {
const errorMessage = error?.message || "Email validation failed";
setError(errorMessage);
showAuthError(error, "Email validation failed");
throw error;
} finally {
setLoading(false);
}
}, []);
},
[]
);
return {
validateEmail,
@ -230,46 +241,49 @@ export const useEmailSetup = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const setupEmail = useCallback(async (
credentials: LoginFormData,
emailData: EmailValidationData
): Promise<string> => {
try {
setLoading(true);
setError(null);
const setupEmail = useCallback(
async (
credentials: LoginFormData,
emailData: EmailValidationData
): Promise<string> => {
try {
setLoading(true);
setError(null);
const data = {
username: credentials.username,
password: credentials.password,
oldEmail: emailData.oldEmail,
newEmail: emailData.newEmail,
};
const data = {
username: credentials.username,
password: credentials.password,
oldEmail: emailData.oldEmail,
newEmail: emailData.newEmail,
};
const response = await postSetupEmail(data);
const response = await postSetupEmail(data);
if (response?.error) {
throw new Error(response.message || "Email setup failed");
if (response?.error) {
throw new Error(response.message || "Email setup failed");
}
const message = response?.data?.message;
switch (message) {
case "Email is valid and OTP has been sent":
return "otp";
case "The old email is not same":
throw new Error("Email is invalid");
default:
return "success";
}
} catch (error: any) {
const errorMessage = error?.message || "Email setup failed";
setError(errorMessage);
showAuthError(error, "Email setup failed");
throw error;
} finally {
setLoading(false);
}
const message = response?.data?.message;
switch (message) {
case "Email is valid and OTP has been sent":
return "otp";
case "The old email is not same":
throw new Error("Email is invalid");
default:
return "success";
}
} catch (error: any) {
const errorMessage = error?.message || "Email setup failed";
setError(errorMessage);
showAuthError(error, "Email setup failed");
throw error;
} finally {
setLoading(false);
}
}, []);
},
[]
);
return {
setupEmail,
@ -283,34 +297,34 @@ export const useOTPVerification = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const verifyOTP = useCallback(async (
username: string,
otp: string
): Promise<boolean> => {
try {
setLoading(true);
setError(null);
const verifyOTP = useCallback(
async (username: string, otp: string): Promise<boolean> => {
try {
setLoading(true);
setError(null);
if (otp.length !== 6) {
throw new Error("OTP must be exactly 6 digits");
if (otp.length !== 6) {
throw new Error("OTP must be exactly 6 digits");
}
const response = await verifyOTPByUsername(username, otp);
if (response?.error) {
throw new Error(response.message || "OTP verification failed");
}
return response?.message === "success";
} catch (error: any) {
const errorMessage = error?.message || "OTP verification failed";
setError(errorMessage);
showAuthError(error, "OTP verification failed");
throw error;
} finally {
setLoading(false);
}
const response = await verifyOTPByUsername(username, otp);
if (response?.error) {
throw new Error(response.message || "OTP verification failed");
}
return response?.message === "success";
} catch (error: any) {
const errorMessage = error?.message || "OTP verification failed";
setError(errorMessage);
showAuthError(error, "OTP verification failed");
throw error;
} finally {
setLoading(false);
}
}, []);
},
[]
);
return {
verifyOTP,