feat: Initialize License Tracker Pro v1.2 project

Adds initial project structure, dependencies, and basic configuration for the License Tracker Pro v1.2 application. This includes setting up Vite for the build process, defining core types, and incorporating essential UI components like icons and a timeline. The project is now ready for development.
This commit is contained in:
Philip
2026-01-26 18:55:43 -08:00
parent d4895c6d81
commit e045354892
56 changed files with 3410 additions and 8 deletions
+99
View File
@@ -0,0 +1,99 @@
import { License, User, AuditLog, Contact, NotificationGroup, AppSettings, AIInsight } from './types';
import { GoogleGenAI, Type } from "@google/genai";
const API_URL = 'api.php';
export const DEFAULT_SETTINGS: AppSettings = {
fiscal_start_month: 4, alert_days: 45, smtp_host: '', smtp_port: '465',
smtp_user: '', smtp_pass: '', smtp_from: '', azure_enabled: false,
azure_tenant_id: '', azure_client_id: '', azure_client_secret: '',
ldap_enabled: false, ldap_host: '', ldap_port: '389', ldap_base_dn: '',
ldap_bind_dn: '', ldap_bind_pass: '', ldap_user_filter: '', allow_local_login: true
};
async function handleResponse(response: Response) {
const text = await response.text();
let json;
try {
json = text ? JSON.parse(text) : null;
} catch(e) {
console.error("Failed to parse JSON response. Status:", response.status, "Text:", text.substring(0, 100));
json = null;
}
if (!response.ok) {
const errorMsg = json?.error || `Server Error (${response.status}): ${text.substring(0, 50)}`;
throw new Error(errorMsg);
}
return json;
}
export const checkSession = async () => handleResponse(await fetch(`${API_URL}?action=check_session`));
export const login = async (username: string, password: string, authSource: string = 'local') =>
handleResponse(await fetch(`${API_URL}?action=login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password, authSource })
}));
export const logout = async () => handleResponse(await fetch(`${API_URL}?action=logout`));
export const fetchLicenses = async () => handleResponse(await fetch(`${API_URL}?action=list`));
export const fetchSettings = async () => handleResponse(await fetch(`${API_URL}?action=settings_get`));
export const saveLicense = async (license: any) => {
return handleResponse(await fetch(`${API_URL}?action=save`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(license)
}));
};
export const deleteLicense = async (id: string) => handleResponse(await fetch(`${API_URL}?action=delete&id=${id}`, { method: 'POST' }));
export const saveSettings = async (settings: AppSettings) => handleResponse(await fetch(`${API_URL}?action=settings_save`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(settings) }));
export const fetchUsers = async () => handleResponse(await fetch(`${API_URL}?action=users_list`));
export const createUser = async (u: any) => handleResponse(await fetch(`${API_URL}?action=users_create`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(u) }));
export const updateUser = async (id: number, u: any) => handleResponse(await fetch(`${API_URL}?action=users_update&id=${id}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(u) }));
export const deleteUser = async (id: number) => handleResponse(await fetch(`${API_URL}?action=users_delete&id=${id}`, { method: 'POST' }));
export const fetchGroups = async () => handleResponse(await fetch(`${API_URL}?action=groups_list`));
export const saveGroup = async (g: any) => handleResponse(await fetch(`${API_URL}?action=groups_save`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(g) }));
export const deleteGroup = async (id: number) => handleResponse(await fetch(`${API_URL}?action=groups_delete&id=${id}`, { method: 'POST' }));
export const fetchContacts = async () => handleResponse(await fetch(`${API_URL}?action=contacts_list`));
export const saveContact = async (c: any) => handleResponse(await fetch(`${API_URL}?action=contacts_save`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(c) }));
export const deleteContact = async (id: number) => handleResponse(await fetch(`${API_URL}?action=contacts_delete&id=${id}`, { method: 'POST' }));
export const fetchLogs = async () => handleResponse(await fetch(`${API_URL}?action=logs_list`));
export async function getAIInsights(license: License): Promise<AIInsight> {
try {
const ai = new GoogleGenAI({ apiKey: process.env.API_KEY });
const res = await ai.models.generateContent({
model: 'gemini-3-pro-preview',
contents: `Analyze this license for procurement risks: ${license.licenseName}, Vendor: ${license.vendorName}. Return JSON with status (saving/warning/neutral), advice, and suggested_alternatives.`,
config: {
responseMimeType: 'application/json',
responseSchema: {
type: Type.OBJECT,
properties: {
status: { type: Type.STRING },
advice: { type: Type.STRING },
suggested_alternatives: { type: Type.ARRAY, items: { type: Type.STRING } }
},
required: ["status", "advice", "suggested_alternatives"]
}
}
});
return JSON.parse(res.text || '{}');
} catch (e) {
return { status: 'neutral', advice: "Advice unavailable.", suggested_alternatives: [] };
}
}
export const deleteFile = async (id: number) => handleResponse(await fetch(`${API_URL}?action=file_delete&id=${id}`, { method: 'POST' }));
export const exportDatabase = async () => handleResponse(await fetch(`${API_URL}?action=export`));
export const importDatabase = async (json: string) => handleResponse(await fetch(`${API_URL}?action=import`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: json }));
export const sendTestEmail = async (email: string) => handleResponse(await fetch(`${API_URL}?action=test_email`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email }) }));
export const runNotifications = async () => handleResponse(await fetch(`${API_URL}?action=run_notifications`));
export const getAzureLoginUrl = async () => ({ url: '#' });
export const resetPassword = async (token: string, password: string) => handleResponse(await fetch(`${API_URL}?action=reset_password`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, password }) }));