fix: speed up otp login
This commit is contained in:
parent
a5113a2ed5
commit
ffc7f3a97d
|
|
@ -1,13 +1,11 @@
|
||||||
import React, { createContext, useContext, useEffect, useState } from "react";
|
import React, { createContext, useContext, useEffect, useState } from "react";
|
||||||
import { demoUsers } from "../data/mockAppData";
|
import { demoUsers } from "../data/mockAppData";
|
||||||
import { supabase, hasSupabaseConfig } from "../supabaseClient";
|
import { supabase, hasSupabaseConfig } from "../supabaseClient";
|
||||||
import { safeSupabaseCall } from "../services/safeSupabaseCall";
|
|
||||||
|
|
||||||
const AuthContext = createContext(null);
|
const AuthContext = createContext(null);
|
||||||
const STORAGE_KEY = "construction-auth-local-user";
|
const STORAGE_KEY = "construction-auth-local-user";
|
||||||
export const DEMO_LOGIN_EMAIL = "local@local";
|
export const DEMO_LOGIN_EMAIL = "local@local";
|
||||||
export const ROLE_SWITCH_ENTRY_EMAIL = "roles@local";
|
export const ROLE_SWITCH_ENTRY_EMAIL = "roles@local";
|
||||||
export const MISSING_PROFILE_ERROR = "Профиль пользователя не найден. Обратитесь к администратору.";
|
|
||||||
export const PROFILE_LOAD_ERROR = "Не удалось загрузить профиль пользователя.";
|
export const PROFILE_LOAD_ERROR = "Не удалось загрузить профиль пользователя.";
|
||||||
export const UNKNOWN_EMAIL_ERROR = "Email не найден в системе. Обратитесь к администратору.";
|
export const UNKNOWN_EMAIL_ERROR = "Email не найден в системе. Обратитесь к администратору.";
|
||||||
|
|
||||||
|
|
@ -66,6 +64,23 @@ export const mapProfileToAuthUser = (profile) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const mapSessionUserToAuthUser = (sessionUser) => {
|
||||||
|
if (!sessionUser) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userMetadata = sessionUser.user_metadata || {};
|
||||||
|
const appMetadata = sessionUser.app_metadata || {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: sessionUser.id,
|
||||||
|
email: sessionUser.email,
|
||||||
|
name: userMetadata.name || sessionUser.email || "Пользователь",
|
||||||
|
role: userMetadata.role || appMetadata.role || "manager",
|
||||||
|
lastLogin: sessionUser.last_sign_in_at || sessionUser.updated_at || null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const AuthProvider = ({ children }) => {
|
export const AuthProvider = ({ children }) => {
|
||||||
const [user, setUser] = useState(() => {
|
const [user, setUser] = useState(() => {
|
||||||
const stored = localStorage.getItem(STORAGE_KEY);
|
const stored = localStorage.getItem(STORAGE_KEY);
|
||||||
|
|
@ -83,39 +98,15 @@ export const AuthProvider = ({ children }) => {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { subscription },
|
data: { subscription },
|
||||||
} = supabase.auth.onAuthStateChange(async (_event, session) => {
|
} = supabase.auth.onAuthStateChange((_event, session) => {
|
||||||
if (!session?.user) {
|
if (!session?.user) {
|
||||||
setUser(null);
|
setUser(null);
|
||||||
setAuthError("");
|
setAuthError("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data, error } = await safeSupabaseCall(async () => {
|
const nextUser = mapSessionUserToAuthUser(session.user);
|
||||||
const { data: profile, error } = await supabase
|
setUser(nextUser);
|
||||||
.from("users")
|
|
||||||
.select("id, email, name, last_login, role_info:roles(name)")
|
|
||||||
.eq("id", session.user.id)
|
|
||||||
.maybeSingle();
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
return profile;
|
|
||||||
}, "Ошибка загрузки профиля");
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
setUser(null);
|
|
||||||
setAuthError(error?.message || PROFILE_LOAD_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
setUser(null);
|
|
||||||
setAuthError(MISSING_PROFILE_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(mapProfileToAuthUser(data));
|
|
||||||
setAuthError("");
|
setAuthError("");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -171,6 +162,8 @@ export const AuthProvider = ({ children }) => {
|
||||||
throw normalizeOtpError(error);
|
throw normalizeOtpError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setUser(mapSessionUserToAuthUser(data.session?.user));
|
||||||
|
setAuthError("");
|
||||||
return { success: Boolean(data.session) };
|
return { success: Boolean(data.session) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
buildOtpRequestPayload,
|
buildOtpRequestPayload,
|
||||||
isRoleSwitchEntryEmail,
|
isRoleSwitchEntryEmail,
|
||||||
mapProfileToAuthUser,
|
mapProfileToAuthUser,
|
||||||
|
mapSessionUserToAuthUser,
|
||||||
normalizeOtpError,
|
normalizeOtpError,
|
||||||
resolveDemoUser,
|
resolveDemoUser,
|
||||||
resolveLoginEmail,
|
resolveLoginEmail,
|
||||||
|
|
@ -75,6 +76,26 @@ describe("mapProfileToAuthUser", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("mapSessionUserToAuthUser", () => {
|
||||||
|
it("maps session metadata to an immediate app user", () => {
|
||||||
|
expect(
|
||||||
|
mapSessionUserToAuthUser({
|
||||||
|
id: "session-id",
|
||||||
|
email: "driver@company.ru",
|
||||||
|
user_metadata: { name: "Иван Соколов", role: "driver" },
|
||||||
|
app_metadata: { role: "logistician" },
|
||||||
|
last_sign_in_at: "2026-04-15T08:00:00Z",
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
id: "session-id",
|
||||||
|
email: "driver@company.ru",
|
||||||
|
name: "Иван Соколов",
|
||||||
|
role: "driver",
|
||||||
|
lastLogin: "2026-04-15T08:00:00Z",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("normalizeOtpError", () => {
|
describe("normalizeOtpError", () => {
|
||||||
it("maps unknown email errors to the admin hint", () => {
|
it("maps unknown email errors to the admin hint", () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue