Fix organization setup flow: redirect to onboarding for incomplete setup
This commit is contained in:
219
services/demoStorage.ts
Normal file
219
services/demoStorage.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
// Demo mode data persistence using localStorage
|
||||
// This provides a more robust storage solution for demo mode without Firebase
|
||||
|
||||
export interface DemoUser {
|
||||
uid: string;
|
||||
email: string;
|
||||
displayName: string;
|
||||
passwordHash: string; // Simple hash for demo purposes
|
||||
}
|
||||
|
||||
export interface DemoOrganization {
|
||||
orgId: string;
|
||||
name: string;
|
||||
onboardingCompleted: boolean;
|
||||
[key: string]: any; // Additional org data from onboarding
|
||||
}
|
||||
|
||||
export interface DemoEmployee {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
role?: string;
|
||||
department?: string;
|
||||
orgId: string;
|
||||
}
|
||||
|
||||
export interface DemoSubmission {
|
||||
employeeId: string;
|
||||
orgId: string;
|
||||
answers: Record<string, string>;
|
||||
createdAt: number;
|
||||
}
|
||||
|
||||
export interface DemoInvite {
|
||||
code: string;
|
||||
employee: DemoEmployee;
|
||||
used: boolean;
|
||||
createdAt: number;
|
||||
orgId: string;
|
||||
}
|
||||
|
||||
class DemoStorageService {
|
||||
private getKey(key: string): string {
|
||||
return `auditly_demo_${key}`;
|
||||
}
|
||||
|
||||
// User management
|
||||
saveUser(user: DemoUser): void {
|
||||
const users = this.getUsers();
|
||||
users[user.email] = user;
|
||||
localStorage.setItem(this.getKey('users'), JSON.stringify(users));
|
||||
}
|
||||
|
||||
getUsers(): Record<string, DemoUser> {
|
||||
const data = localStorage.getItem(this.getKey('users'));
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
|
||||
getUserByEmail(email: string): DemoUser | null {
|
||||
const users = this.getUsers();
|
||||
return users[email] || null;
|
||||
}
|
||||
|
||||
getUserByUid(uid: string): DemoUser | null {
|
||||
const users = this.getUsers();
|
||||
return Object.values(users).find(user => user.uid === uid) || null;
|
||||
}
|
||||
|
||||
// Simple password hashing for demo (not secure, just for demo purposes)
|
||||
hashPassword(password: string): string {
|
||||
return btoa(password).split('').reverse().join('');
|
||||
}
|
||||
|
||||
verifyPassword(password: string, hash: string): boolean {
|
||||
return this.hashPassword(password) === hash;
|
||||
}
|
||||
|
||||
// Organization management
|
||||
saveOrganization(org: DemoOrganization): void {
|
||||
const orgs = this.getOrganizations();
|
||||
orgs[org.orgId] = org;
|
||||
localStorage.setItem(this.getKey('organizations'), JSON.stringify(orgs));
|
||||
}
|
||||
|
||||
getOrganizations(): Record<string, DemoOrganization> {
|
||||
const data = localStorage.getItem(this.getKey('organizations'));
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
|
||||
getOrganization(orgId: string): DemoOrganization | null {
|
||||
const orgs = this.getOrganizations();
|
||||
return orgs[orgId] || null;
|
||||
}
|
||||
|
||||
// Employee management
|
||||
saveEmployee(employee: DemoEmployee): void {
|
||||
const employees = this.getEmployees();
|
||||
const key = `${employee.orgId}_${employee.id}`;
|
||||
employees[key] = employee;
|
||||
localStorage.setItem(this.getKey('employees'), JSON.stringify(employees));
|
||||
}
|
||||
|
||||
getEmployees(): Record<string, DemoEmployee> {
|
||||
const data = localStorage.getItem(this.getKey('employees'));
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
|
||||
getEmployeesByOrg(orgId: string): DemoEmployee[] {
|
||||
const employees = this.getEmployees();
|
||||
return Object.values(employees).filter(emp => emp.orgId === orgId);
|
||||
}
|
||||
|
||||
// Submission management
|
||||
saveSubmission(submission: DemoSubmission): void {
|
||||
const submissions = this.getSubmissions();
|
||||
const key = `${submission.orgId}_${submission.employeeId}`;
|
||||
submissions[key] = submission;
|
||||
localStorage.setItem(this.getKey('submissions'), JSON.stringify(submissions));
|
||||
}
|
||||
|
||||
getSubmissions(): Record<string, DemoSubmission> {
|
||||
const data = localStorage.getItem(this.getKey('submissions'));
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
|
||||
getSubmissionsByOrg(orgId: string): Record<string, DemoSubmission> {
|
||||
const submissions = this.getSubmissions();
|
||||
const result: Record<string, DemoSubmission> = {};
|
||||
Object.entries(submissions).forEach(([key, sub]) => {
|
||||
if (sub.orgId === orgId) {
|
||||
result[sub.employeeId] = sub;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Invite management
|
||||
saveInvite(invite: DemoInvite): void {
|
||||
const invites = this.getInvites();
|
||||
invites[invite.code] = invite;
|
||||
localStorage.setItem(this.getKey('invites'), JSON.stringify(invites));
|
||||
}
|
||||
|
||||
getInvites(): Record<string, DemoInvite> {
|
||||
const data = localStorage.getItem(this.getKey('invites'));
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
|
||||
getInvite(code: string): DemoInvite | null {
|
||||
const invites = this.getInvites();
|
||||
return invites[code] || null;
|
||||
}
|
||||
|
||||
markInviteUsed(code: string): boolean {
|
||||
const invite = this.getInvite(code);
|
||||
if (invite && !invite.used) {
|
||||
invite.used = true;
|
||||
this.saveInvite(invite);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Company reports (simple storage)
|
||||
saveCompanyReport(orgId: string, report: any): void {
|
||||
const reports = this.getCompanyReports();
|
||||
if (!reports[orgId]) reports[orgId] = [];
|
||||
reports[orgId].push(report);
|
||||
localStorage.setItem(this.getKey('company_reports'), JSON.stringify(reports));
|
||||
}
|
||||
|
||||
getCompanyReports(): Record<string, any[]> {
|
||||
const data = localStorage.getItem(this.getKey('company_reports'));
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
|
||||
getCompanyReportsByOrg(orgId: string): any[] {
|
||||
const reports = this.getCompanyReports();
|
||||
return reports[orgId] || [];
|
||||
}
|
||||
|
||||
// Employee reports
|
||||
saveEmployeeReport(orgId: string, employeeId: string, report: any): void {
|
||||
const reports = this.getEmployeeReports();
|
||||
const key = `${orgId}_${employeeId}`;
|
||||
reports[key] = report;
|
||||
localStorage.setItem(this.getKey('employee_reports'), JSON.stringify(reports));
|
||||
}
|
||||
|
||||
getEmployeeReports(): Record<string, any> {
|
||||
const data = localStorage.getItem(this.getKey('employee_reports'));
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
|
||||
getEmployeeReportsByOrg(orgId: string): Record<string, any> {
|
||||
const reports = this.getEmployeeReports();
|
||||
const result: Record<string, any> = {};
|
||||
Object.entries(reports).forEach(([key, report]) => {
|
||||
if (key.startsWith(`${orgId}_`)) {
|
||||
const employeeId = key.substring(orgId.length + 1);
|
||||
result[employeeId] = report;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Clear all demo data (for testing)
|
||||
clearAllData(): void {
|
||||
const keys = [
|
||||
'users', 'organizations', 'employees', 'submissions',
|
||||
'invites', 'company_reports', 'employee_reports'
|
||||
];
|
||||
keys.forEach(key => {
|
||||
localStorage.removeItem(this.getKey(key));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const demoStorage = new DemoStorageService();
|
||||
41
services/firebase.ts
Normal file
41
services/firebase.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { initializeApp, getApps } from 'firebase/app';
|
||||
import { getAuth, GoogleAuthProvider } from 'firebase/auth';
|
||||
import { getFirestore } from 'firebase/firestore';
|
||||
|
||||
const firebaseConfig = {
|
||||
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
|
||||
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
|
||||
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
|
||||
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
|
||||
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
|
||||
appId: import.meta.env.VITE_FIREBASE_APP_ID,
|
||||
};
|
||||
|
||||
export const isFirebaseConfigured = Boolean(
|
||||
firebaseConfig.apiKey &&
|
||||
firebaseConfig.authDomain &&
|
||||
firebaseConfig.projectId &&
|
||||
firebaseConfig.apiKey !== 'undefined' &&
|
||||
firebaseConfig.authDomain !== 'undefined' &&
|
||||
firebaseConfig.projectId !== 'undefined' &&
|
||||
// Force demo mode on localhost for testing
|
||||
!window.location.hostname.includes('localhost')
|
||||
);
|
||||
|
||||
let app;
|
||||
let auth;
|
||||
let db;
|
||||
let googleProvider;
|
||||
|
||||
if (isFirebaseConfigured) {
|
||||
app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
|
||||
auth = getAuth(app);
|
||||
db = getFirestore(app);
|
||||
googleProvider = new GoogleAuthProvider();
|
||||
} else {
|
||||
auth = null;
|
||||
db = null;
|
||||
googleProvider = null;
|
||||
}
|
||||
|
||||
export { auth, db, googleProvider };
|
||||
BIN
services/geminiService.ts
Normal file
BIN
services/geminiService.ts
Normal file
Binary file not shown.
BIN
services/llmService.ts
Normal file
BIN
services/llmService.ts
Normal file
Binary file not shown.
Reference in New Issue
Block a user