skip auth
This commit is contained in:
parent
504101b91c
commit
5807e389b4
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue