feat: initial public release
ConsentOS — a privacy-first cookie consent management platform. Self-hosted, source-available alternative to OneTrust, Cookiebot, and CookieYes. Full standards coverage (IAB TCF v2.2, GPP v1, Google Consent Mode v2, GPC, Shopify Customer Privacy API), multi-tenant architecture with role-based access, configuration cascade (system → org → group → site → region), dark-pattern detection in the scanner, and a tamper-evident consent record audit trail. This is the initial public release. Prior development history is retained internally. See README.md for the feature list, architecture overview, and quick-start instructions. Licensed under the Elastic Licence 2.0 — self-host freely; do not resell as a managed service.
This commit is contained in:
60
apps/admin-ui/src/stores/auth.ts
Normal file
60
apps/admin-ui/src/stores/auth.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { getMe, login as loginApi } from '../api/auth';
|
||||
import { initAnalytics, trackAuthEvent } from '../services/analytics';
|
||||
import type { User } from '../types/api';
|
||||
|
||||
interface AuthState {
|
||||
user: User | null;
|
||||
isAuthenticated: boolean;
|
||||
isLoading: boolean;
|
||||
login: (email: string, password: string) => Promise<void>;
|
||||
logout: () => void;
|
||||
loadUser: () => Promise<void>;
|
||||
}
|
||||
|
||||
export const useAuthStore = create<AuthState>((set) => ({
|
||||
user: null,
|
||||
isAuthenticated: !!localStorage.getItem('access_token'),
|
||||
isLoading: false,
|
||||
|
||||
login: async (email: string, password: string) => {
|
||||
set({ isLoading: true });
|
||||
try {
|
||||
const tokens = await loginApi(email, password);
|
||||
localStorage.setItem('access_token', tokens.access_token);
|
||||
localStorage.setItem('refresh_token', tokens.refresh_token);
|
||||
const user = await getMe();
|
||||
set({ user, isAuthenticated: true, isLoading: false });
|
||||
initAnalytics(user);
|
||||
trackAuthEvent('login', user.id);
|
||||
} catch (error) {
|
||||
set({ isLoading: false });
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
logout: () => {
|
||||
const { user } = useAuthStore.getState();
|
||||
trackAuthEvent('logout', user?.id);
|
||||
localStorage.removeItem('access_token');
|
||||
localStorage.removeItem('refresh_token');
|
||||
set({ user: null, isAuthenticated: false });
|
||||
},
|
||||
|
||||
loadUser: async () => {
|
||||
if (!localStorage.getItem('access_token')) {
|
||||
set({ isAuthenticated: false });
|
||||
return;
|
||||
}
|
||||
set({ isLoading: true });
|
||||
try {
|
||||
const user = await getMe();
|
||||
set({ user, isAuthenticated: true, isLoading: false });
|
||||
initAnalytics(user);
|
||||
} catch {
|
||||
localStorage.removeItem('access_token');
|
||||
set({ user: null, isAuthenticated: false, isLoading: false });
|
||||
}
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user