fix mobile screen issues

This commit is contained in:
2026-08-24 13:14:22 +05:30
parent dcf9770ada
commit 02eb48af99
34 changed files with 1214 additions and 291 deletions

View File

@@ -4,11 +4,17 @@ import { base44 } from '@/api/base44Client';
/**
* Auth context.
*
* The reference app resolves an identity provider before rendering. The demo
* has no provider, so it resolves the seeded user immediately — but it keeps
* the same context shape (`isLoadingAuth`, `isLoadingPublicSettings`,
* `authError`, `navigateToLogin`, …) so `App.jsx`, `ProtectedRoute` and every
* consumer stay unchanged.
* The single source of truth for "is anyone signed in", and it is not a flag
* this app sets. `checkUserAuth` calls `GET /me`; the server reads its own
* session table and either returns a user or answers 401. Success means there
* is a session, failure means there is not, and there is no third answer this
* code can manufacture.
*
* The context shape is unchanged from the demo's version — `isLoadingAuth`,
* `isLoadingPublicSettings`, `authError`, `navigateToLogin` and the rest — so
* `App.jsx`, `ProtectedRoute` and every consumer stay as they were. What
* changed is where the answer comes from: a real session cookie rather than a
* client that reported the seeded user as permanently signed in.
*/
const AuthContext = createContext(/** @type {any} */ (null));
@@ -27,6 +33,10 @@ export const AuthProvider = ({ children }) => {
setUser(currentUser);
setIsAuthenticated(true);
} catch {
// A 401 is the ordinary state of a signed-out visitor, and it is also
// what an expired session looks like on the first request after it
// lapses. Both mean the same thing here.
setUser(null);
setIsAuthenticated(false);
} finally {
setIsLoadingAuth(false);
@@ -38,10 +48,27 @@ export const AuthProvider = ({ children }) => {
checkUserAuth();
}, []);
const logout = (shouldRedirect = true) => {
/**
* Signs in.
*
* Resolves to the user on success and throws the API's error otherwise. The
* error's message is already the generic one the server chose — it does not
* say whether the address exists — so callers show it as-is rather than
* writing their own.
*/
const login = async ({ email, password, rememberMe = false }) => {
const currentUser = await base44.auth.login({ email, password, rememberMe });
setUser(currentUser);
setIsAuthenticated(true);
setAuthChecked(true);
return currentUser;
};
const logout = async (redirectTo = '/admin/login') => {
setUser(null);
setIsAuthenticated(false);
base44.auth.logout(shouldRedirect ? '/' : undefined);
// Revokes the session server-side, expires the cookie, then redirects.
await base44.auth.logout(redirectTo);
};
const navigateToLogin = () => {
@@ -59,6 +86,7 @@ export const AuthProvider = ({ children }) => {
authError: null,
appPublicSettings: null,
authChecked,
login,
logout,
navigateToLogin,
checkUserAuth,

View File

@@ -1,50 +1,49 @@
/**
* Admin sign-in state.
*
* The demo's data client (`base44.auth`) reports the seeded user as permanently
* signed in — there is no identity provider behind it. That is fine for the
* Employer and Talent demos, but the Admin console is supposed to be reached
* through its own sign-in, and "always authenticated" would mean /admin opened
* straight into the Control Center with the login page never seen.
* This file used to BE the Admin session: a `sessionStorage` flag, set by the
* login page and read by the route guard, standing in for a real one. The
* comment on it said so plainly — "it is not security — a browser flag never
* is — it is the state a real session would occupy … so swapping in a real
* provider later means changing this file and nothing else."
*
* So Admin keeps a session marker of its own. It is deliberately thin: a single
* flag, set by the login page and read by the route guard. It is not security —
* a browser flag never is — it is the state a real session would occupy, put in
* the one place that both the guard and the login screen can agree on, so the
* flow is right now and swapping in a real provider later means changing this
* file and nothing else.
* That swap has happened. The session is now a row in PostgreSQL, addressed by
* an HttpOnly cookie this code cannot read, and the question "is anyone signed
* in" is answered by `GET /me` through `AuthContext` — see `AdminRoute`, which
* now asks the context instead of asking here.
*
* `sessionStorage`, not `localStorage`: closing the tab should end the session,
* which is both the more defensible default for an administrative console and
* what makes the login page the app's actual starting point.
* The three functions survive because `AdminLayout` and the Admin `Profile`
* page call `endAdminSession()` on their sign-out buttons, and those files are
* outside this phase. They are honest about doing nothing that matters: there
* is no local flag left that could disagree with the server, which is the point
* — a browser value that grants access is exactly the thing being removed.
*/
const SESSION_KEY = 'krow_admin_session';
/** True when this tab has signed in to the Admin console. */
/**
* Whether this tab has signed in to the Admin console.
*
* @deprecated The server decides. Use `useAuth().isAuthenticated`, which
* reflects `GET /me`, rather than anything stored in the browser.
* @returns {boolean} always false — no local flag can grant admin access.
*/
export function hasAdminSession() {
try {
return sessionStorage.getItem(SESSION_KEY) === '1';
} catch {
// Private mode with storage denied: fail closed, so the login page shows.
return false;
}
return false;
}
/** Records a successful sign-in. */
export function startAdminSession() {
try {
sessionStorage.setItem(SESSION_KEY, '1');
} catch {
// Nothing to do — the guard will simply ask for sign-in again.
}
}
/**
* Records a successful sign-in.
*
* @deprecated A no-op. Signing in is `POST /api/v1/auth/login`, and what it
* produces is an HttpOnly cookie, not a value in this module.
*/
export function startAdminSession() {}
/** Clears the session. Used by sign-out. */
export function endAdminSession() {
try {
sessionStorage.removeItem(SESSION_KEY);
} catch {
// Ignore.
}
}
/**
* Clears the session.
*
* @deprecated A no-op, kept because the sign-out buttons in `AdminLayout` and
* the Admin `Profile` page still call it before `base44.auth.logout()`. The
* logout call is what ends the session: it revokes the row server-side and
* expires the cookie.
*/
export function endAdminSession() {}

View File

@@ -121,7 +121,10 @@ export function toPositionPayload(draft = {}, { status = 'active' } = {}) {
engine compares it against assignment windows. Null is open-ended. */
duration_months: record.duration_months === '' || record.duration_months == null
? null
: Number(record.duration_months),
: (Number(record.duration_months) || null),
start_date: record.start_date && String(record.start_date).trim() !== ''
? String(record.start_date).trim()
: null,
company: String(record.company || '').trim(),
};
}