feat: login_challenge and scope storing, mock api

This commit is contained in:
2025-07-26 14:49:48 +04:00
parent a1a9e0dc93
commit 9a97411bfd
20 changed files with 424 additions and 85 deletions

View File

@ -1,28 +1,63 @@
"use client";
import { FC, useEffect, useState } from "react";
import { redirect } from "next/navigation";
import { useSelector } from "react-redux";
import { Button, Text } from "@mantine/core";
import SERVICES from "@/constants/services";
import { ServiceCode } from "@/enums/ServiceCode";
import SCOPES from "@/constants/scopes";
import { Scopes } from "@/enums/Scopes";
import { notifications } from "@/lib/notifications";
import { RootState } from "@/lib/store";
import ServiceData from "@/types/ServiceData";
import { AuthService } from "@/mocks/authService";
const ConsentButton: FC = () => {
const serviceCode = useSelector(
(state: RootState) => state.targetService.serviceCode
);
const [serviceData, setServiceData] = useState<ServiceData>();
const auth = useSelector((state: RootState) => state.auth);
const [clientName, setClientName] = useState<string>(Scopes.UNDEFINED);
const [serviceRequiredAccess, setServiceRequiredAccess] =
useState<string>("");
const setAccessesForScope = () => {
const accesses: string[] = [];
(auth.scope ?? []).forEach((scopeItem: Scopes) => {
const access = SCOPES[scopeItem];
if (access) accesses.push(access);
});
setServiceRequiredAccess(accesses.join("\n"));
};
const requestConsent = () => {
if (!auth.loginChallenge || auth.scope.length === 0) return;
new AuthService()
.requestConsent(auth.loginChallenge)
.then(response => response.data)
.then(({ clientName }) => {
setClientName(clientName);
})
.catch(error => {
console.error(error);
notifications.error({ message: error.toString() });
});
};
useEffect(() => {
if (serviceCode === ServiceCode.UNDEFINED) {
redirect("services");
}
setServiceData(SERVICES[serviceCode]);
}, [serviceCode]);
setAccessesForScope();
requestConsent();
}, []);
const confirmAccess = () => {};
const confirmAccess = () => {
if (!auth.loginChallenge) return;
new AuthService()
.approveConsent(auth.loginChallenge)
.then(response => response.data)
.then(({ redirectUrl }) => {
window.location.href = redirectUrl;
})
.catch(error => {
console.error(error);
notifications.error({ message: error.toString() });
});
};
return (
<>
@ -34,8 +69,7 @@ const ConsentButton: FC = () => {
<Text
fz={"h4"}
ta="center">
Сервис {serviceData?.name} получит{" "}
{serviceData?.requiredAccesses}
Сервис {clientName} получит {serviceRequiredAccess}
</Text>
</>
);

19
src/app/login/page.tsx Normal file
View File

@ -0,0 +1,19 @@
import LoginForm from "@/components/LoginForm/LoginForm";
import Logo from "@/components/Logo/Logo";
import PageItem from "@/components/PageBlock/PageItem";
import PageContainer from "@/components/PageContainer/PageContainer";
interface LoginPageProps {
searchParams: { login_challenge?: string };
}
export default function LoginPage({ searchParams }: LoginPageProps) {
return (
<PageContainer center>
<PageItem fullScreenMobile>
<Logo title={"Вход"} />
<LoginForm loginChallenge={searchParams.login_challenge} />
</PageItem>
</PageContainer>
);
}

View File

@ -1,15 +1,5 @@
import LoginForm from "@/components/LoginForm/LoginForm";
import Logo from "@/components/Logo/Logo";
import PageItem from "@/components/PageBlock/PageItem";
import PageContainer from "@/components/PageContainer/PageContainer";
import { redirect } from "next/navigation";
export default function MainPage() {
return (
<PageContainer center>
<PageItem fullScreenMobile>
<Logo title={"Вход"} />
<LoginForm />
</PageItem>
</PageContainer>
);
redirect("/login");
}

View File

@ -5,8 +5,8 @@ import { redirect } from "next/navigation";
import { Button, Stack, Title } from "@mantine/core";
import styles from "@/app/services/components/ServicesList/ServicesList.module.css";
import TitleWithLines from "@/components/TitleWithLines/TitleWithLines";
import SERVICES from "@/constants/services";
import { ServiceCode } from "@/enums/ServiceCode";
import SCOPES from "@/constants/scopes";
import { Scopes } from "@/enums/Scopes";
import { setTargetService } from "@/lib/features/targetService/targetServiceSlice";
import { useAppDispatch } from "@/lib/store";
import ServiceData from "@/types/ServiceData";
@ -15,10 +15,10 @@ const ServicesList = () => {
const dispatch = useAppDispatch();
const services = useMemo(
() =>
Object.entries(SERVICES)
.filter(([key]) => key !== ServiceCode.UNDEFINED)
Object.entries(SCOPES)
.filter(([key]) => key !== Scopes.UNDEFINED)
.map(([, value]) => value),
[SERVICES]
[SCOPES]
);
const onServiceClick = (service: ServiceData) => {

View File

@ -2,10 +2,15 @@
import { FC } from "react";
import { redirect } from "next/navigation";
import { useSelector } from "react-redux";
import { Button, PinInput, Stack } from "@mantine/core";
import { useForm } from "@mantine/form";
import ResendVerificationCode from "@/app/verify-phone/components/ResendVerificationCode/ResendVerificationCode";
import style from "@/app/verify-phone/components/VerifyPhoneForm/VerifyPhone.module.css";
import { setScope } from "@/lib/features/auth/authSlice";
import { notifications } from "@/lib/notifications";
import { RootState, useAppDispatch } from "@/lib/store";
import { AuthService } from "@/mocks/authService";
type VerifyNumberForm = {
code: string;
@ -20,11 +25,27 @@ const VerifyPhoneForm: FC = () => {
code: code => code.length !== 6 && "Введите весь код",
},
});
const authState = useSelector((state: RootState) => state.auth);
const dispatch = useAppDispatch();
const handleSubmit = (values: VerifyNumberForm) => {
console.log(values);
if (!authState.phoneNumber || !authState.loginChallenge) return;
redirect("/services");
new AuthService()
.approveLogin(
authState.phoneNumber,
values.code,
authState.loginChallenge
)
.then(response => response.data)
.then(({ redirectUrl, scope }) => {
dispatch(setScope(scope));
window.location.href = redirectUrl;
})
.catch(error => {
console.error(error);
notifications.error({ message: error.toString() });
});
};
const navigateToLogin = () => redirect("/");