282 lines
11 KiB
TypeScript
282 lines
11 KiB
TypeScript
import { ErrorPayload, useApi } from "@/api";
|
||
import { EGender, ESourceAuthorization, ICreateAuthorizePayload, ICreateAuthorizeResponse } from "@/api/resources/User";
|
||
import { useAuth } from "@/auth";
|
||
import { getClientTimezone } from "@/locales";
|
||
import { getDateAsString } from "@/services/date";
|
||
import { filterNullKeysOfObject } from "@/services/filter-object";
|
||
import metricService, { EGoals, EMetrics } from "@/services/metric/metricService";
|
||
import { actions, selectors } from "@/store";
|
||
import moment from "moment";
|
||
import { useCallback, useMemo, useState } from "react";
|
||
import { useTranslations } from "@/hooks/translations";
|
||
import { useDispatch, useSelector } from "react-redux";
|
||
import { Response } from "@/api/resources/Login";
|
||
import { useSession } from "@/hooks/session/useSession";
|
||
|
||
|
||
|
||
export const useAuthentication = () => {
|
||
const api = useApi();
|
||
const feature = useSelector(selectors.selectFeature)
|
||
const { i18n } = useTranslations();
|
||
const dispatch = useDispatch();
|
||
const { updateSession } = useSession();
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
const [error, setError] = useState<string | null>(null);
|
||
const [token, setToken] = useState<string | null>(null);
|
||
const { user, signUp } = useAuth();
|
||
const locale = i18n.language;
|
||
const { username } = useSelector(selectors.selectUser)
|
||
const { name: partnerName, birthDate: partnerBirthdateFromForm } = useSelector(selectors.selectRightUser)
|
||
const {
|
||
gender,
|
||
birthdate: birthdateFromQuestionnaire,
|
||
birthtime: birthtimeFromQuestionnaire,
|
||
birthPlace,
|
||
partnerGender,
|
||
partnerBirthdate: partnerBirthdateFromQuestionnaire,
|
||
partnerBirthPlace,
|
||
partnerBirthtime,
|
||
} = useSelector(selectors.selectQuestionnaire)
|
||
const { checked, dateOfCheck } = useSelector(selectors.selectPrivacyPolicy)
|
||
|
||
const birthdateFromForm = useSelector(selectors.selectBirthdate);
|
||
const birthtimeFromForm = useSelector(selectors.selectBirthtime);
|
||
|
||
const birthdate = useMemo(() => {
|
||
if (birthdateFromQuestionnaire?.length) {
|
||
return birthdateFromQuestionnaire;
|
||
}
|
||
if (birthdateFromForm?.length) {
|
||
return birthdateFromForm;
|
||
}
|
||
}, [birthdateFromForm, birthdateFromQuestionnaire]);
|
||
|
||
const birthtime = useMemo(() => {
|
||
if (birthtimeFromQuestionnaire?.length) {
|
||
return birthtimeFromQuestionnaire;
|
||
}
|
||
if (birthtimeFromForm?.length) {
|
||
return birthtimeFromForm;
|
||
}
|
||
}, [birthtimeFromForm, birthtimeFromQuestionnaire]);
|
||
|
||
const partnerBirthdate = useMemo(() => {
|
||
const fromQuestionnaire = `${partnerBirthdateFromQuestionnaire} ${partnerBirthtime}`
|
||
if (partnerBirthdateFromQuestionnaire?.length) {
|
||
return fromQuestionnaire;
|
||
}
|
||
return getDateAsString(partnerBirthdateFromForm)
|
||
}, [partnerBirthdateFromForm, partnerBirthdateFromQuestionnaire, partnerBirthtime])
|
||
|
||
const formatDate = useCallback((date: string) => {
|
||
const _date = moment(date, "YYYY-MM-DD HH:mm", true).format("YYYY-MM-DD HH:mm");
|
||
if (_date === "Invalid date") {
|
||
return null;
|
||
}
|
||
return _date;
|
||
}, [])
|
||
|
||
// Функция для получения всех куки браузера
|
||
const getAllCookies = useCallback(() => {
|
||
const cookies: Record<string, string> = {};
|
||
document.cookie.split(';').forEach(cookie => {
|
||
const [name, value] = cookie.trim().split('=');
|
||
if (name && value) {
|
||
cookies[name] = decodeURIComponent(value);
|
||
}
|
||
});
|
||
return cookies;
|
||
}, []);
|
||
|
||
const getAuthorizationPayload = useCallback((email: string, source: ESourceAuthorization): ICreateAuthorizePayload => {
|
||
const timezone = getClientTimezone();
|
||
return filterNullKeysOfObject<ICreateAuthorizePayload>({
|
||
timezone,
|
||
locale,
|
||
email,
|
||
source,
|
||
profile: {
|
||
name: username || "",
|
||
gender: EGender[gender as keyof typeof EGender] || null,
|
||
birthdate: formatDate(`${birthdate} ${birthtime}`),
|
||
birthplace: {
|
||
address: birthPlace,
|
||
},
|
||
},
|
||
partner: {
|
||
name: partnerName,
|
||
gender: EGender[partnerGender as keyof typeof EGender] || null,
|
||
birthdate: formatDate(partnerBirthdate),
|
||
birthplace: {
|
||
address: partnerBirthPlace,
|
||
},
|
||
},
|
||
sign: checked,
|
||
signDate: dateOfCheck,
|
||
feature: feature.includes("black") ? "ios" : feature
|
||
})
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
}, [
|
||
birthPlace,
|
||
birthdate,
|
||
gender,
|
||
locale,
|
||
partnerBirthPlace,
|
||
partnerBirthdate,
|
||
partnerGender,
|
||
partnerName,
|
||
username,
|
||
birthtime,
|
||
checked,
|
||
dateOfCheck
|
||
]);
|
||
|
||
const authorizationWithPassword = useCallback(async (email: string, password: string) => {
|
||
try {
|
||
setIsLoading(true);
|
||
setError(null)
|
||
const payload = {
|
||
email,
|
||
locale,
|
||
timezone: getClientTimezone(),
|
||
password
|
||
}
|
||
const loginResult = await api.login(payload);
|
||
const token = "token" in loginResult ? loginResult.token : null;
|
||
const userId = "userId" in loginResult ? loginResult.userId : null;
|
||
const status = "status" in loginResult ? loginResult.status : null;
|
||
const message = "message" in loginResult ? loginResult.message : null;
|
||
if (!token) {
|
||
return {
|
||
status,
|
||
message
|
||
}
|
||
}
|
||
metricService.reachGoal(EGoals.ENTERED_EMAIL, [EMetrics.YANDEX, EMetrics.KLAVIYO]);
|
||
metricService.reachGoal(EGoals.LEAD, [EMetrics.FACEBOOK]);
|
||
const { user: userMe } = await api.getMe({ token });
|
||
if (userId?.length) {
|
||
metricService.userParams({
|
||
email: user?.email,
|
||
UserID: userId
|
||
})
|
||
metricService.setUserID(userId);
|
||
}
|
||
signUp(token, userMe);
|
||
setToken(token);
|
||
dispatch(actions.status.update("registred"));
|
||
} catch (error: unknown) {
|
||
const response = (error as ErrorPayload<Response>).responseData
|
||
setError((!!response && "message" in response && response.message) || (error as Error).message);
|
||
return response
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
}, [api, dispatch, locale, signUp])
|
||
|
||
const authorization = useCallback(async (email: string, source: ESourceAuthorization, isAnonymous = false) => {
|
||
try {
|
||
setIsLoading(true);
|
||
setError(null)
|
||
|
||
// Обновляем сессию с куки перед авторизацией
|
||
try {
|
||
const cookies = getAllCookies();
|
||
await updateSession({ cookies }, source);
|
||
console.log('Session updated with cookies before authorization:', cookies);
|
||
} catch (sessionError) {
|
||
console.warn('Failed to update session with cookies:', sessionError);
|
||
// Продолжаем авторизацию даже если обновление сессии не удалось
|
||
}
|
||
|
||
const payload = getAuthorizationPayload(email, source);
|
||
const { token, userId: userIdFromApi, generatingVideo, videoId, authCode } = isAnonymous ? await api.authorizationAnonymous(payload) : await api.authorization(payload);
|
||
if (!!token && !isAnonymous) {
|
||
metricService.reachGoal(EGoals.ENTERED_EMAIL, [EMetrics.YANDEX, EMetrics.KLAVIYO]);
|
||
metricService.reachGoal(EGoals.LEAD, [EMetrics.FACEBOOK]);
|
||
}
|
||
const { user: userMe } = await api.getMe({ token });
|
||
const userId = userIdFromApi || userMe?._id;
|
||
if (userId?.length) {
|
||
dispatch(actions.userId.update({ userId }));
|
||
metricService.userParams({
|
||
hasPersonalVideo: generatingVideo || false,
|
||
email: user?.email,
|
||
UserID: userId
|
||
})
|
||
metricService.setUserID(userId);
|
||
}
|
||
signUp(token, userMe, isAnonymous);
|
||
setToken(token);
|
||
dispatch(actions.userConfig.setAuthCode(authCode || ""));
|
||
dispatch(actions.personalVideo.updateStatus({ generatingVideo: generatingVideo || false, videoId: videoId || "" }));
|
||
if (generatingVideo) {
|
||
metricService.reachGoal(EGoals.ROSE_VIDEO_CREATION_START, [EMetrics.YANDEX, EMetrics.KLAVIYO]);
|
||
}
|
||
dispatch(actions.status.update("registred"));
|
||
} catch (error) {
|
||
setError((error as Error).message);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
}, [api, dispatch, getAllCookies, getAuthorizationPayload, signUp, updateSession])
|
||
|
||
const anonymousAuthorization = useCallback(async ({
|
||
token,
|
||
userId: userIdFromApi = "",
|
||
generatingVideo = false,
|
||
videoId = "",
|
||
authCode = ""
|
||
}: ICreateAuthorizeResponse) => {
|
||
try {
|
||
setIsLoading(true);
|
||
setError(null)
|
||
const { user: userMe } = await api.getMe({ token });
|
||
const userId = userIdFromApi || userMe?._id;
|
||
if (userId?.length) {
|
||
dispatch(actions.userId.update({ userId }));
|
||
metricService.userParams({
|
||
hasPersonalVideo: generatingVideo || false,
|
||
email: user?.email,
|
||
UserID: userId
|
||
})
|
||
metricService.setUserID(userId);
|
||
}
|
||
signUp(token, userMe, true);
|
||
setToken(token);
|
||
dispatch(actions.userConfig.setAuthCode(authCode || ""));
|
||
dispatch(actions.personalVideo.updateStatus({ generatingVideo: generatingVideo || false, videoId: videoId || "" }));
|
||
if (generatingVideo) {
|
||
metricService.reachGoal(EGoals.ROSE_VIDEO_CREATION_START, [EMetrics.YANDEX, EMetrics.KLAVIYO]);
|
||
}
|
||
dispatch(actions.status.update("registred"));
|
||
} catch (error) {
|
||
setError((error as Error).message);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
}, [api, dispatch, getAuthorizationPayload, signUp])
|
||
|
||
return useMemo(
|
||
() => ({
|
||
isLoading,
|
||
error,
|
||
token,
|
||
user,
|
||
authorization,
|
||
authorizationWithPassword,
|
||
anonymousAuthorization
|
||
}),
|
||
[
|
||
isLoading,
|
||
error,
|
||
token,
|
||
user,
|
||
authorization,
|
||
authorizationWithPassword,
|
||
anonymousAuthorization
|
||
]
|
||
);
|
||
}
|